Iain Buclaw 5fee5ec362 d: Import dmd b8384668f, druntime e6caaab9, phobos 5ab9ad256 (v2.098.0-beta.1)
The D front-end is now itself written in D, in order to build GDC, you
will need a working GDC compiler (GCC version 9.1 or later).

GCC changes:

    - Add support for bootstrapping the D front-end.

These add the required components in order to have a D front-end written
in D itself.  Because the compiler front-end only depends on the core
runtime modules, only libdruntime is built for the bootstrap stages.

D front-end changes:

    - Import dmd v2.098.0-beta.1.

Druntime changes:

    - Import druntime v2.098.0-beta.1.

Phobos changes:

    - Import phobos v2.098.0-beta.1.

The jump from v2.076.1 to v2.098.0 covers nearly 4 years worth of
development on the D programming language and run-time libraries.

ChangeLog:

	* Makefile.def: Add bootstrap to libbacktrace, libphobos, zlib, and
	libatomic.
	* Makefile.in: Regenerate.
	* Makefile.tpl (POSTSTAGE1_HOST_EXPORTS): Fix command for GDC.
	(STAGE1_CONFIGURE_FLAGS): Add --with-libphobos-druntime-only if
	target-libphobos-bootstrap.
	(STAGE2_CONFIGURE_FLAGS): Likewise.
	* configure: Regenerate.
	* configure.ac: Add support for bootstrapping D front-end.

config/ChangeLog:

	* acx.m4 (ACX_PROG_GDC): New m4 function.

gcc/ChangeLog:

	* Makefile.in (GDC): New variable.
	(GDCFLAGS): New variable.
	* configure: Regenerate.
	* configure.ac: Add call to ACX_PROG_GDC.  Substitute GDCFLAGS.

gcc/d/ChangeLog:

	* dmd/MERGE: Merge upstream dmd b8384668f.
	* Make-lang.in (d-warn): Use strict warnings.
	(DMD_WARN_CXXFLAGS): Remove.
	(DMD_COMPILE): Remove.
	(CHECKING_DFLAGS): Define.
	(WARN_DFLAGS): Define.
	(ALL_DFLAGS): Define.
	(DCOMPILE.base): Define.
	(DCOMPILE): Define.
	(DPOSTCOMPILE): Define.
	(DLINKER): Define.
	(DLLINKER): Define.
	(D_FRONTEND_OBJS): Add new dmd front-end objects.
	(D_GENERATED_SRCS): Remove.
	(D_GENERATED_OBJS): Remove.
	(D_ALL_OBJS): Remove D_GENERATED_OBJS.
	(d21$(exeext)): Build using DLLINKER and -static-libphobos.
	(d.tags): Remove dmd/*.c and dmd/root/*.c.
	(d.mostlyclean): Remove D_GENERATED_SRCS, d/idgen$(build_exeext),
	d/impcnvgen$(build_exeext).
	(D_INCLUDES): Include $(srcdir)/d/dmd/res.
	(CFLAGS-d/id.o): Remove.
	(CFLAGS-d/impcnvtab.o): Remove.
	(d/%.o): Build using DCOMPILE and DPOSTCOMPILE.  Update dependencies
	from d/dmd/%.c to d/dmd/%.d.
	(d/idgen$(build_exeext)): Remove.
	(d/impcnvgen$(build_exeext)): Remove.
	(d/id.c): Remove.
	(d/id.h): Remove.
	(d/impcnvtab.c): Remove.
	(d/%.dmdgen.o): Remove.
	(D_SYSTEM_H): Remove.
	(d/idgen.dmdgen.o): Remove.
	(d/impcnvgen.dmdgen.o): Remove.
	* config-lang.in (boot_language): New variable.
	* d-attribs.cc: Include dmd/expression.h.
	* d-builtins.cc: Include d-frontend.h.
	(build_frontend_type): Update for new front-end interface.
	(d_eval_constant_expression): Likewise.
	(d_build_builtins_module): Likewise.
	(maybe_set_builtin_1): Likewise.
	(d_build_d_type_nodes): Likewise.
	* d-codegen.cc (d_decl_context): Likewise.
	(declaration_reference_p): Likewise.
	(declaration_type): Likewise.
	(parameter_reference_p): Likewise.
	(parameter_type): Likewise.
	(get_array_length): Likewise.
	(build_delegate_cst): Likewise.
	(build_typeof_null_value): Likewise.
	(identity_compare_p): Likewise.
	(lower_struct_comparison): Likewise.
	(build_filename_from_loc): Likewise.
	(build_assert_call): Remove LIBCALL_SWITCH_ERROR.
	(build_bounds_index_condition): Call LIBCALL_ARRAYBOUNDS_INDEXP on
	bounds error.
	(build_bounds_slice_condition): Call LIBCALL_ARRAYBOUNDS_SLICEP on
	bounds error.
	(array_bounds_check): Update for new front-end interface.
	(checkaction_trap_p): Handle CHECKACTION_context.
	(get_function_type): Update for new front-end interface.
	(d_build_call): Likewise.
	* d-compiler.cc: Remove include of dmd/scope.h.
	(Compiler::genCmain): Remove.
	(Compiler::paintAsType): Update for new front-end interface.
	(Compiler::onParseModule): Likewise.
	* d-convert.cc (convert_expr): Remove call to LIBCALL_ARRAYCAST.
	(convert_for_rvalue): Update for new front-end interface.
	(convert_for_assignment): Likewise.
	(convert_for_condition): Likewise.
	(d_array_convert): Likewise.
	* d-diagnostic.cc (error): Remove.
	(errorSupplemental): Remove.
	(warning): Remove.
	(warningSupplemental): Remove.
	(deprecation): Remove.
	(deprecationSupplemental): Remove.
	(message): Remove.
	(vtip): New.
	* d-frontend.cc (global): Remove.
	(Global::_init): Remove.
	(Global::startGagging): Remove.
	(Global::endGagging): Remove.
	(Global::increaseErrorCount): Remove.
	(Loc::Loc): Remove.
	(Loc::toChars): Remove.
	(Loc::equals): Remove.
	(isBuiltin): Update for new front-end interface.
	(eval_builtin): Likewise.
	(getTypeInfoType): Likewise.
	(inlineCopy): Remove.
	* d-incpath.cc: Include d-frontend.h.
	(add_globalpaths): Call d_gc_malloc to allocate Strings.
	(add_filepaths): Likewise.
	* d-lang.cc: Include dmd/id.h, dmd/root/file.h, d-frontend.h.  Remove
	include of dmd/mars.h, id.h.
	(entrypoint_module): Remove.
	(entrypoint_root_module): Remove.
	(deps_write_string): Update for new front-end interface.
	(deps_write): Likewise.
	(d_init_options): Call rt_init.  Remove setting global params that are
	default initialized by the front-end.
	(d_handle_option): Handle OPT_fcheckaction_, OPT_fdump_c___spec_,
	OPT_fdump_c___spec_verbose, OPT_fextern_std_, OPT_fpreview,
	OPT_revert, OPT_fsave_mixins_, and OPT_ftransition.
	(d_post_options): Propagate dip1021 and dip1000 preview flags to
	dip25, and flag_diagnostics_show_caret to printErrorContext.
	(d_add_entrypoint_module): Remove.
	(d_parse_file): Update for new front-end interface.
	(d_type_promotes_to): Likewise.
	(d_types_compatible_p): Likewise.
	* d-longdouble.cc (CTFloat::zero): Remove.
	(CTFloat::one): Remove.
	(CTFloat::minusone): Remove.
	(CTFloat::half): Remove.
	* d-system.h (POSIX): Remove.
	(realpath): Remove.
	(isalpha): Remove.
	(isalnum): Remove.
	(isdigit): Remove.
	(islower): Remove.
	(isprint): Remove.
	(isspace): Remove.
	(isupper): Remove.
	(isxdigit): Remove.
	(tolower): Remove.
	(_mkdir): Remove.
	(INT32_MAX): Remove.
	(INT32_MIN): Remove.
	(INT64_MIN): Remove.
	(UINT32_MAX): Remove.
	(UINT64_MAX): Remove.
	* d-target.cc: Include calls.h.
	(target): Remove.
	(define_float_constants): Remove initialization of snan.
	(Target::_init): Update for new front-end interface.
	(Target::isVectorTypeSupported): Likewise.
	(Target::isVectorOpSupported): Remove cases for unordered operators.
	(TargetCPP::typeMangle): Update for new front-end interface.
	(TargetCPP::parameterType): Likewise.
	(Target::systemLinkage): Likewise.
	(Target::isReturnOnStack): Likewise.
	(Target::isCalleeDestroyingArgs): Define.
	(Target::preferPassByRef): Define.
	* d-tree.h (d_add_entrypoint_module): Remove.
	* decl.cc (gcc_attribute_p): Update for new front-end interface.
	(apply_pragma_crt): Define.
	(DeclVisitor::visit(PragmaDeclaration *)): Handle pragmas
	crt_constructor and crt_destructor.
	(DeclVisitor::visit(TemplateDeclaration *)): Update for new front-end
	interface.
	(DeclVisitor::visit): Likewise.
	(DeclVisitor::finish_vtable): Likewise.
	(get_symbol_decl): Error if template has more than one nesting
	context.  Update for new front-end interface.
	(make_thunk): Update for new front-end interface.
	(get_vtable_decl): Likewise.
	* expr.cc (ExprVisitor::visit): Likewise.
	(build_return_dtor): Likewise.
	* imports.cc (ImportVisitor::visit): Likewise.
	* intrinsics.cc: Include dmd/expression.h.  Remove include of
	dmd/mangle.h.
	(maybe_set_intrinsic): Update for new front-end interface.
	* intrinsics.def (INTRINSIC_ROL): Update intrinsic signature.
	(INTRINSIC_ROR): Likewise.
	(INTRINSIC_ROR_TIARG): Likewise.
	(INTRINSIC_TOPREC): Likewise.
	(INTRINSIC_TOPRECL): Likewise.
	(INTRINSIC_TAN): Update intrinsic module and signature.
	(INTRINSIC_ISNAN): Likewise.
	(INTRINSIC_ISFINITE): Likewise.
	(INTRINSIC_COPYSIGN): Define intrinsic.
	(INTRINSIC_COPYSIGNI): Define intrinsic.
	(INTRINSIC_EXP): Update intrinsic module.
	(INTRINSIC_EXPM1): Likewise.
	(INTRINSIC_EXP2): Likewise.
	(INTRINSIC_LOG): Likewise.
	(INTRINSIC_LOG2): Likewise.
	(INTRINSIC_LOG10): Likewise.
	(INTRINSIC_POW): Likewise.
	(INTRINSIC_ROUND): Likewise.
	(INTRINSIC_FLOORF): Likewise.
	(INTRINSIC_FLOOR): Likewise.
	(INTRINSIC_FLOORL): Likewise.
	(INTRINSIC_CEILF): Likewise.
	(INTRINSIC_CEIL): Likewise.
	(INTRINSIC_CEILL): Likewise.
	(INTRINSIC_TRUNC): Likewise.
	(INTRINSIC_FMIN): Likewise.
	(INTRINSIC_FMAX): Likewise.
	(INTRINSIC_FMA): Likewise.
	(INTRINSIC_VA_ARG): Update intrinsic signature.
	(INTRINSIC_VASTART): Likewise.
	* lang.opt (fcheck=): Add alternate aliases for contract switches.
	(fcheckaction=): New option.
	(check_action): New Enum and EnumValue entries.
	(fdump-c++-spec-verbose): New option.
	(fdump-c++-spec=): New option.
	(fextern-std=): New option.
	(extern_stdcpp): New Enum and EnumValue entries
	(fpreview=): New options.
	(frevert=): New options.
	(fsave-mixins): New option.
	(ftransition=): Update options.
	* modules.cc (get_internal_fn): Replace Prot with Visibility.
	(build_internal_fn): Likewise.
	(build_dso_cdtor_fn): Likewise.
	(build_module_tree): Remove check for __entrypoint module.
	* runtime.def (P5): Define.
	(ARRAYBOUNDS_SLICEP): Define.
	(ARRAYBOUNDS_INDEXP): Define.
	(NEWTHROW): Define.
	(ADCMP2): Remove.
	(ARRAYCAST): Remove.
	(SWITCH_STRING): Remove.
	(SWITCH_USTRING): Remove.
	(SWITCH_DSTRING): Remove.
	(SWITCH_ERROR): Remove.
	* toir.cc (IRVisitor::visit): Update for new front-end interface.
	(IRVisitor::check_previous_goto): Remove checks for case and default
	statements.
	(IRVisitor::visit(SwitchStatement *)): Remove handling of string
	switch conditions.
	* typeinfo.cc: Include d-frontend.h.
	(get_typeinfo_kind): Update for new front-end interface.
	(make_frontend_typeinfo): Likewise.
	(TypeInfoVisitor::visit): Likewise.
	(builtin_typeinfo_p): Likewise.
	(get_typeinfo_decl): Likewise.
	(build_typeinfo): Likewise.
	* types.cc (valist_array_p): Likewise.
	(make_array_type): Likewise.
	(merge_aggregate_types): Likewise.
	(TypeVisitor::visit(TypeBasic *)): Likewise.
	(TypeVisitor::visit(TypeFunction *)): Likewise.
	(TypeVisitor::visit(TypeStruct *)): Update comment.
	* verstr.h: Removed.
	* d-frontend.h: New file.

gcc/po/ChangeLog:

	* EXCLUDES: Remove d/dmd sources from list.

gcc/testsuite/ChangeLog:

	* gdc.dg/Wcastresult2.d: Update test.
	* gdc.dg/asm1.d: Likewise.
	* gdc.dg/asm2.d: Likewise.
	* gdc.dg/asm3.d: Likewise.
	* gdc.dg/gdc282.d: Likewise.
	* gdc.dg/imports/gdc170.d: Likewise.
	* gdc.dg/intrinsics.d: Likewise.
	* gdc.dg/pr101672.d: Likewise.
	* gdc.dg/pr90650a.d: Likewise.
	* gdc.dg/pr90650b.d: Likewise.
	* gdc.dg/pr94777a.d: Likewise.
	* gdc.dg/pr95250.d: Likewise.
	* gdc.dg/pr96869.d: Likewise.
	* gdc.dg/pr98277.d: Likewise.
	* gdc.dg/pr98457.d: Likewise.
	* gdc.dg/simd1.d: Likewise.
	* gdc.dg/simd2a.d: Likewise.
	* gdc.dg/simd2b.d: Likewise.
	* gdc.dg/simd2c.d: Likewise.
	* gdc.dg/simd2d.d: Likewise.
	* gdc.dg/simd2e.d: Likewise.
	* gdc.dg/simd2f.d: Likewise.
	* gdc.dg/simd2g.d: Likewise.
	* gdc.dg/simd2h.d: Likewise.
	* gdc.dg/simd2i.d: Likewise.
	* gdc.dg/simd2j.d: Likewise.
	* gdc.dg/simd7951.d: Likewise.
	* gdc.dg/torture/gdc309.d: Likewise.
	* gdc.dg/torture/pr94424.d: Likewise.
	* gdc.dg/torture/pr94777b.d: Likewise.
	* lib/gdc-utils.exp (gdc-convert-args): Handle new compiler options.
	(gdc-convert-test): Handle CXXFLAGS, EXTRA_OBJC_SOURCES, and ARG_SETS
	test directives.
	(gdc-do-test): Only import modules in the test run directory.
	* gdc.dg/pr94777c.d: New test.
	* gdc.dg/pr96156b.d: New test.
	* gdc.dg/pr96157c.d: New test.
	* gdc.dg/simd_ctfe.d: New test.
	* gdc.dg/torture/simd17344.d: New test.
	* gdc.dg/torture/simd20052.d: New test.
	* gdc.dg/torture/simd6.d: New test.
	* gdc.dg/torture/simd7.d: New test.

libphobos/ChangeLog:

	* libdruntime/MERGE: Merge upstream druntime e6caaab9.
	* libdruntime/Makefile.am (D_EXTRA_FLAGS): Build libdruntime with
	-fpreview=dip1000, -fpreview=fieldwise, and -fpreview=dtorfields.
	(ALL_DRUNTIME_SOURCES): Add DRUNTIME_DSOURCES_STDCXX.
	(DRUNTIME_DSOURCES): Update list of C binding modules.
	(DRUNTIME_DSOURCES_STDCXX): Likewise.
	(DRUNTIME_DSOURCES_LINUX): Likewise.
	(DRUNTIME_DSOURCES_OPENBSD): Likewise.
	(DRUNTIME_DISOURCES): Remove __entrypoint.di.
	* libdruntime/Makefile.in: Regenerated.
	* libdruntime/__entrypoint.di: Removed.
	* libdruntime/gcc/deh.d (_d_isbaseof): Update signature.
	(_d_createTrace): Likewise.
	(__gdc_begin_catch): Remove reference to the exception.
	(_d_throw): Increment reference count of thrown object before unwind.
	(__gdc_personality): Chain exceptions with  Throwable.chainTogether.
	* libdruntime/gcc/emutls.d: Update imports.
	* libdruntime/gcc/sections/elf.d: Update imports.
	(DSO.moduleGroup): Update signature.
	* libdruntime/gcc/sections/macho.d: Update imports.
	(DSO.moduleGroup): Update signature.
	* libdruntime/gcc/sections/pecoff.d: Update imports.
	(DSO.moduleGroup): Update signature.
	* src/MERGE: Merge upstream phobos 5ab9ad256.
	* src/Makefile.am (D_EXTRA_DFLAGS): Add -fpreview=dip1000 and
	-fpreview=dtorfields flags.
	(PHOBOS_DSOURCES): Update list of std modules.
	* src/Makefile.in: Regenerate.
	* testsuite/lib/libphobos.exp (libphobos-dg-test): Handle assembly
	compile types.
	(dg-test): Override.
	(additional_prunes): Define.
	(libphobos-dg-prune): Filter any additional_prunes set by tests.
	* testsuite/libphobos.aa/test_aa.d: Update test.
	* testsuite/libphobos.druntime/druntime.exp (version_flags): Add
	-fversion=CoreUnittest.
	* testsuite/libphobos.druntime_shared/druntime_shared.exp
	(version_flags): Add -fversion=CoreUnittest -fversion=Shared.
	* testsuite/libphobos.exceptions/unknown_gc.d: Update test.
	* testsuite/libphobos.hash/test_hash.d: Update test.
	* testsuite/libphobos.phobos/phobos.exp (version_flags): Add
	-fversion=StdUnittest
	* testsuite/libphobos.phobos_shared/phobos_shared.exp (version_flags):
	Likewise.
	* testsuite/libphobos.shared/host.c: Update test.
	* testsuite/libphobos.shared/load.d: Update test.
	* testsuite/libphobos.shared/load_13414.d: Update test.
	* testsuite/libphobos.thread/fiber_guard_page.d: Update test.
	* testsuite/libphobos.thread/tlsgc_sections.d: Update test.
	* testsuite/testsuite_flags.in: Add -fpreview=dip1000 to --gdcflags.
	* testsuite/libphobos.shared/link_mod_collision.d: Removed.
	* testsuite/libphobos.shared/load_mod_collision.d: Removed.
	* testsuite/libphobos.betterc/betterc.exp: New test.
	* testsuite/libphobos.config/config.exp: New test.
	* testsuite/libphobos.gc/gc.exp: New test.
	* testsuite/libphobos.imports/imports.exp: New test.
	* testsuite/libphobos.lifetime/lifetime.exp: New test.
	* testsuite/libphobos.unittest/unittest.exp: New test.
2021-11-30 16:53:28 +01:00

1017 lines
23 KiB
D

/**
* This module contains a collection of bit-level operations.
*
* Copyright: Copyright Don Clugston 2005 - 2013.
* License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
* Authors: Don Clugston, Sean Kelly, Walter Bright, Alex Rønne Petersen, Thomas Stuart Bockman
* Source: $(DRUNTIMESRC core/_bitop.d)
*/
module core.bitop;
nothrow:
@safe:
@nogc:
version (D_InlineAsm_X86_64)
version = AsmX86;
else version (D_InlineAsm_X86)
version = AsmX86;
version (X86_64)
version = AnyX86;
else version (X86)
version = AnyX86;
// Use to implement 64-bit bitops on 32-bit arch.
private union Split64
{
ulong u64;
struct
{
version (LittleEndian)
{
uint lo;
uint hi;
}
else
{
uint hi;
uint lo;
}
}
pragma(inline, true)
this(ulong u64) @safe pure nothrow @nogc
{
if (__ctfe)
{
lo = cast(uint) u64;
hi = cast(uint) (u64 >>> 32);
}
else
this.u64 = u64;
}
}
unittest
{
const rt = Split64(1);
assert((rt.lo == 1) && (rt.hi == 0));
enum ct = Split64(1);
assert((ct.lo == rt.lo) && (ct.hi == rt.hi));
}
/**
* Scans the bits in v starting with bit 0, looking
* for the first set bit.
* Returns:
* The bit number of the first bit set.
* The return value is undefined if v is zero.
*/
int bsf(uint v) pure
{
pragma(inline, false); // so intrinsic detection will work
return softBsf!uint(v);
}
/// ditto
int bsf(ulong v) pure
{
static if (size_t.sizeof == ulong.sizeof) // 64 bit code gen
{
pragma(inline, false); // so intrinsic detection will work
return softBsf!ulong(v);
}
else
{
/* intrinsic not available for 32 bit code,
* make do with 32 bit bsf
*/
const sv = Split64(v);
return (sv.lo == 0)?
bsf(sv.hi) + 32 :
bsf(sv.lo);
}
}
///
unittest
{
assert(bsf(0x21) == 0);
assert(bsf(ulong.max << 39) == 39);
}
unittest
{
// Make sure bsf() is available at CTFE
enum test_ctfe = bsf(ulong.max);
assert(test_ctfe == 0);
}
/**
* Scans the bits in v from the most significant bit
* to the least significant bit, looking
* for the first set bit.
* Returns:
* The bit number of the first bit set.
* The return value is undefined if v is zero.
*/
int bsr(uint v) pure
{
pragma(inline, false); // so intrinsic detection will work
return softBsr!uint(v);
}
/// ditto
int bsr(ulong v) pure
{
static if (size_t.sizeof == ulong.sizeof) // 64 bit code gen
{
pragma(inline, false); // so intrinsic detection will work
return softBsr!ulong(v);
}
else
{
/* intrinsic not available for 32 bit code,
* make do with 32 bit bsr
*/
const sv = Split64(v);
return (sv.hi == 0)?
bsr(sv.lo) :
bsr(sv.hi) + 32;
}
}
///
unittest
{
assert(bsr(0x21) == 5);
assert(bsr((ulong.max >> 15) - 1) == 48);
}
unittest
{
// Make sure bsr() is available at CTFE
enum test_ctfe = bsr(ulong.max);
assert(test_ctfe == 63);
}
private alias softBsf(N) = softScan!(N, true);
private alias softBsr(N) = softScan!(N, false);
/* Shared software fallback implementation for bit scan foward and reverse.
If forward is true, bsf is computed (the index of the first set bit).
If forward is false, bsr is computed (the index of the last set bit).
-1 is returned if no bits are set (v == 0).
*/
private int softScan(N, bool forward)(N v) pure
if (is(N == uint) || is(N == ulong))
{
// bsf() and bsr() are officially undefined for v == 0.
if (!v)
return -1;
// This is essentially an unrolled binary search:
enum mask(ulong lo) = forward ? cast(N) lo : cast(N)~lo;
enum inc(int up) = forward ? up : -up;
N x;
int ret;
static if (is(N == ulong))
{
x = v & mask!0x0000_0000_FFFF_FFFFL;
if (x)
{
v = x;
ret = forward ? 0 : 63;
}
else
ret = forward ? 32 : 31;
x = v & mask!0x0000_FFFF_0000_FFFFL;
if (x)
v = x;
else
ret += inc!16;
}
else static if (is(N == uint))
{
x = v & mask!0x0000_FFFF;
if (x)
{
v = x;
ret = forward ? 0 : 31;
}
else
ret = forward ? 16 : 15;
}
else
static assert(false);
x = v & mask!0x00FF_00FF_00FF_00FFL;
if (x)
v = x;
else
ret += inc!8;
x = v & mask!0x0F0F_0F0F_0F0F_0F0FL;
if (x)
v = x;
else
ret += inc!4;
x = v & mask!0x3333_3333_3333_3333L;
if (x)
v = x;
else
ret += inc!2;
x = v & mask!0x5555_5555_5555_5555L;
if (!x)
ret += inc!1;
return ret;
}
unittest
{
assert(softBsf!uint(0u) == -1);
assert(softBsr!uint(0u) == -1);
assert(softBsf!ulong(0uL) == -1);
assert(softBsr!ulong(0uL) == -1);
assert(softBsf!uint(0x0031_A000) == 13);
assert(softBsr!uint(0x0031_A000) == 21);
assert(softBsf!ulong(0x0000_0001_8000_0000L) == 31);
assert(softBsr!ulong(0x0000_0001_8000_0000L) == 32);
foreach (b; 0 .. 64)
{
if (b < 32)
{
assert(softBsf!uint(1u << b) == b);
assert(softBsr!uint(1u << b) == b);
}
assert(softBsf!ulong(1uL << b) == b);
assert(softBsr!ulong(1uL << b) == b);
}
}
/**
* Tests the bit.
* (No longer an intrisic - the compiler recognizes the patterns
* in the body.)
*/
int bt(const scope size_t* p, size_t bitnum) pure @system
{
static if (size_t.sizeof == 8)
return ((p[bitnum >> 6] & (1L << (bitnum & 63)))) != 0;
else static if (size_t.sizeof == 4)
return ((p[bitnum >> 5] & (1 << (bitnum & 31)))) != 0;
else
static assert(0);
}
///
@system pure unittest
{
size_t[2] array;
array[0] = 2;
array[1] = 0x100;
assert(bt(array.ptr, 1));
assert(array[0] == 2);
assert(array[1] == 0x100);
}
/**
* Tests and complements the bit.
*/
int btc(size_t* p, size_t bitnum) pure @system;
/**
* Tests and resets (sets to 0) the bit.
*/
int btr(size_t* p, size_t bitnum) pure @system;
/**
* Tests and sets the bit.
* Params:
* p = a non-NULL pointer to an array of size_ts.
* bitnum = a bit number, starting with bit 0 of p[0],
* and progressing. It addresses bits like the expression:
---
p[index / (size_t.sizeof*8)] & (1 << (index & ((size_t.sizeof*8) - 1)))
---
* Returns:
* A non-zero value if the bit was set, and a zero
* if it was clear.
*/
int bts(size_t* p, size_t bitnum) pure @system;
///
@system pure unittest
{
size_t[2] array;
array[0] = 2;
array[1] = 0x100;
assert(btc(array.ptr, 35) == 0);
if (size_t.sizeof == 8)
{
assert(array[0] == 0x8_0000_0002);
assert(array[1] == 0x100);
}
else
{
assert(array[0] == 2);
assert(array[1] == 0x108);
}
assert(btc(array.ptr, 35));
assert(array[0] == 2);
assert(array[1] == 0x100);
assert(bts(array.ptr, 35) == 0);
if (size_t.sizeof == 8)
{
assert(array[0] == 0x8_0000_0002);
assert(array[1] == 0x100);
}
else
{
assert(array[0] == 2);
assert(array[1] == 0x108);
}
assert(btr(array.ptr, 35));
assert(array[0] == 2);
assert(array[1] == 0x100);
}
/**
* Range over bit set. Each element is the bit number that is set.
*
* This is more efficient than testing each bit in a sparsely populated bit
* set. Note that the first bit in the bit set would be bit 0.
*/
struct BitRange
{
/// Number of bits in each size_t
enum bitsPerWord = size_t.sizeof * 8;
private
{
const(size_t)*bits; // points at next word of bits to check
size_t cur; // needed to allow searching bits using bsf
size_t idx; // index of current set bit
size_t len; // number of bits in the bit set.
}
@nogc nothrow pure:
/**
* Construct a BitRange.
*
* Params:
* bitarr = The array of bits to iterate over
* numBits = The total number of valid bits in the given bit array
*/
this(const(size_t)* bitarr, size_t numBits) @system
{
bits = bitarr;
len = numBits;
if (len)
{
// prime the first bit
cur = *bits++ ^ 1;
popFront();
}
}
/// Range functions
size_t front()
{
assert(!empty);
return idx;
}
/// ditto
bool empty() const
{
return idx >= len;
}
/// ditto
void popFront() @system
{
// clear the current bit
auto curbit = idx % bitsPerWord;
cur ^= size_t(1) << curbit;
if (!cur)
{
// find next size_t with set bit
idx -= curbit;
while (!cur)
{
if ((idx += bitsPerWord) >= len)
// now empty
return;
cur = *bits++;
}
idx += bsf(cur);
}
else
{
idx += bsf(cur) - curbit;
}
}
}
///
@system unittest
{
import core.stdc.stdlib : malloc, free;
import core.stdc.string : memset;
// initialize a bit array
enum nBytes = (100 + BitRange.bitsPerWord - 1) / 8;
size_t *bitArr = cast(size_t *)malloc(nBytes);
scope(exit) free(bitArr);
memset(bitArr, 0, nBytes);
// set some bits
bts(bitArr, 48);
bts(bitArr, 24);
bts(bitArr, 95);
bts(bitArr, 78);
enum sum = 48 + 24 + 95 + 78;
// iterate
size_t testSum;
size_t nBits;
foreach (b; BitRange(bitArr, 100))
{
testSum += b;
++nBits;
}
assert(testSum == sum);
assert(nBits == 4);
}
@system unittest
{
void testIt(size_t numBits, size_t[] bitsToTest...)
{
import core.stdc.stdlib : malloc, free;
import core.stdc.string : memset;
immutable numBytes = (numBits + size_t.sizeof * 8 - 1) / 8;
size_t* bitArr = cast(size_t *)malloc(numBytes);
scope(exit) free(bitArr);
memset(bitArr, 0, numBytes);
foreach (b; bitsToTest)
bts(bitArr, b);
auto br = BitRange(bitArr, numBits);
foreach (b; bitsToTest)
{
assert(!br.empty);
assert(b == br.front);
br.popFront();
}
assert(br.empty);
}
testIt(100, 0, 1, 31, 63, 85);
testIt(100, 6, 45, 89, 92, 99);
}
/**
* Swaps bytes in a 2 byte ushort.
* Params:
* x = value
* Returns:
* `x` with bytes swapped
*/
pragma(inline, false)
ushort byteswap(ushort x) pure
{
/* Calling it bswap(ushort) would break existing code that calls bswap(uint).
*
* This pattern is meant to be recognized by the dmd code generator.
* Don't change it without checking that an XCH instruction is still
* used to implement it.
* Inlining may also throw it off.
*/
return cast(ushort) (((x >> 8) & 0xFF) | ((x << 8) & 0xFF00u));
}
///
unittest
{
assert(byteswap(cast(ushort)0xF234) == 0x34F2);
static ushort xx = 0xF234;
assert(byteswap(xx) == 0x34F2);
}
/**
* Swaps bytes in a 4 byte uint end-to-end, i.e. byte 0 becomes
* byte 3, byte 1 becomes byte 2, byte 2 becomes byte 1, byte 3
* becomes byte 0.
*/
uint bswap(uint v) pure;
///
unittest
{
assert(bswap(0x01020304u) == 0x04030201u);
static uint xx = 0x10203040u;
assert(bswap(xx) == 0x40302010u);
}
/**
* Swaps bytes in an 8 byte ulong end-to-end, i.e. byte 0 becomes
* byte 7, byte 1 becomes byte 6, etc.
* This is meant to be recognized by the compiler as an intrinsic.
*/
ulong bswap(ulong v) pure;
///
unittest
{
assert(bswap(0x01020304_05060708uL) == 0x08070605_04030201uL);
static ulong xx = 0x10203040_50607080uL;
assert(bswap(xx) == 0x80706050_40302010uL);
}
version (DigitalMars) version (AnyX86) @system // not pure
{
/**
* Reads I/O port at port_address.
*/
ubyte inp(uint port_address);
/**
* ditto
*/
ushort inpw(uint port_address);
/**
* ditto
*/
uint inpl(uint port_address);
/**
* Writes and returns value to I/O port at port_address.
*/
ubyte outp(uint port_address, ubyte value);
/**
* ditto
*/
ushort outpw(uint port_address, ushort value);
/**
* ditto
*/
uint outpl(uint port_address, uint value);
}
/**
* Calculates the number of set bits in an integer.
*/
int popcnt(uint x) pure
{
// Select the fastest method depending on the compiler and CPU architecture
version (DigitalMars)
{
static if (is(typeof(_popcnt(uint.max))))
{
import core.cpuid;
if (!__ctfe && hasPopcnt)
return _popcnt(x);
}
}
return softPopcnt!uint(x);
}
unittest
{
assert( popcnt( 0 ) == 0 );
assert( popcnt( 7 ) == 3 );
assert( popcnt( 0xAA )== 4 );
assert( popcnt( 0x8421_1248 ) == 8 );
assert( popcnt( 0xFFFF_FFFF ) == 32 );
assert( popcnt( 0xCCCC_CCCC ) == 16 );
assert( popcnt( 0x7777_7777 ) == 24 );
// Make sure popcnt() is available at CTFE
enum test_ctfe = popcnt(uint.max);
assert(test_ctfe == 32);
}
/// ditto
int popcnt(ulong x) pure
{
// Select the fastest method depending on the compiler and CPU architecture
import core.cpuid;
static if (size_t.sizeof == uint.sizeof)
{
const sx = Split64(x);
version (DigitalMars)
{
static if (is(typeof(_popcnt(uint.max))))
{
if (!__ctfe && hasPopcnt)
return _popcnt(sx.lo) + _popcnt(sx.hi);
}
}
return softPopcnt!uint(sx.lo) + softPopcnt!uint(sx.hi);
}
else static if (size_t.sizeof == ulong.sizeof)
{
version (DigitalMars)
{
static if (is(typeof(_popcnt(ulong.max))))
{
if (!__ctfe && hasPopcnt)
return _popcnt(x);
}
}
return softPopcnt!ulong(x);
}
else
static assert(false);
}
unittest
{
assert(popcnt(0uL) == 0);
assert(popcnt(1uL) == 1);
assert(popcnt((1uL << 32) - 1) == 32);
assert(popcnt(0x48_65_6C_6C_6F_3F_21_00uL) == 28);
assert(popcnt(ulong.max) == 64);
// Make sure popcnt() is available at CTFE
enum test_ctfe = popcnt(ulong.max);
assert(test_ctfe == 64);
}
private int softPopcnt(N)(N x) pure
if (is(N == uint) || is(N == ulong))
{
// Avoid branches, and the potential for cache misses which
// could be incurred with a table lookup.
// We need to mask alternate bits to prevent the
// sum from overflowing.
// add neighbouring bits. Each bit is 0 or 1.
enum mask1 = cast(N) 0x5555_5555_5555_5555L;
x = x - ((x>>1) & mask1);
// now each two bits of x is a number 00,01 or 10.
// now add neighbouring pairs
enum mask2a = cast(N) 0xCCCC_CCCC_CCCC_CCCCL;
enum mask2b = cast(N) 0x3333_3333_3333_3333L;
x = ((x & mask2a)>>2) + (x & mask2b);
// now each nibble holds 0000-0100. Adding them won't
// overflow any more, so we don't need to mask any more
enum mask4 = cast(N) 0x0F0F_0F0F_0F0F_0F0FL;
x = (x + (x >> 4)) & mask4;
enum shiftbits = is(N == uint)? 24 : 56;
enum maskMul = cast(N) 0x0101_0101_0101_0101L;
x = (x * maskMul) >> shiftbits;
return cast(int) x;
}
version (DigitalMars) version (AnyX86)
{
/**
* Calculates the number of set bits in an integer
* using the X86 SSE4 POPCNT instruction.
* POPCNT is not available on all X86 CPUs.
*/
ushort _popcnt( ushort x ) pure;
/// ditto
int _popcnt( uint x ) pure;
version (X86_64)
{
/// ditto
int _popcnt( ulong x ) pure;
}
unittest
{
// Not everyone has SSE4 instructions
import core.cpuid;
if (!hasPopcnt)
return;
static int popcnt_x(ulong u) nothrow @nogc
{
int c;
while (u)
{
c += u & 1;
u >>= 1;
}
return c;
}
for (uint u = 0; u < 0x1_0000; ++u)
{
//writefln("%x %x %x", u, _popcnt(cast(ushort)u), popcnt_x(cast(ushort)u));
assert(_popcnt(cast(ushort)u) == popcnt_x(cast(ushort)u));
assert(_popcnt(cast(uint)u) == popcnt_x(cast(uint)u));
uint ui = u * 0x3_0001;
assert(_popcnt(ui) == popcnt_x(ui));
version (X86_64)
{
assert(_popcnt(cast(ulong)u) == popcnt_x(cast(ulong)u));
ulong ul = u * 0x3_0003_0001;
assert(_popcnt(ul) == popcnt_x(ul));
}
}
}
}
// @@@DEPRECATED_2.099@@@
deprecated("volatileLoad has been moved to core.volatile. Use core.volatile.volatileLoad instead.")
{
public import core.volatile : volatileLoad;
}
// @@@DEPRECATED_2.099@@@
deprecated("volatileStore has been moved to core.volatile. Use core.volatile.volatileStore instead.")
{
public import core.volatile : volatileStore;
}
/**
* Reverses the order of bits in a 32-bit integer.
*/
pragma(inline, true)
uint bitswap( uint x ) pure
{
if (!__ctfe)
{
static if (is(typeof(asmBitswap32(x))))
return asmBitswap32(x);
}
return softBitswap!uint(x);
}
unittest
{
static void test(alias impl)()
{
assert (impl( 0x8000_0100 ) == 0x0080_0001);
foreach (i; 0 .. 32)
assert (impl(1 << i) == 1 << 32 - i - 1);
}
test!(bitswap)();
test!(softBitswap!uint)();
static if (is(typeof(asmBitswap32(0u))))
test!(asmBitswap32)();
// Make sure bitswap() is available at CTFE
enum test_ctfe = bitswap(1U);
assert(test_ctfe == (1U << 31));
}
/**
* Reverses the order of bits in a 64-bit integer.
*/
pragma(inline, true)
ulong bitswap ( ulong x ) pure
{
if (!__ctfe)
{
static if (is(typeof(asmBitswap64(x))))
return asmBitswap64(x);
}
return softBitswap!ulong(x);
}
unittest
{
static void test(alias impl)()
{
assert (impl( 0b1000000000000000000000010000000000000000100000000000000000000001)
== 0b1000000000000000000000010000000000000000100000000000000000000001);
assert (impl( 0b1110000000000000000000010000000000000000100000000000000000000001)
== 0b1000000000000000000000010000000000000000100000000000000000000111);
foreach (i; 0 .. 64)
assert (impl(1UL << i) == 1UL << 64 - i - 1);
}
test!(bitswap)();
test!(softBitswap!ulong)();
static if (is(typeof(asmBitswap64(0uL))))
test!(asmBitswap64)();
// Make sure bitswap() is available at CTFE
enum test_ctfe = bitswap(1UL);
assert(test_ctfe == (1UL << 63));
}
private N softBitswap(N)(N x) pure
if (is(N == uint) || is(N == ulong))
{
// swap 1-bit pairs:
enum mask1 = cast(N) 0x5555_5555_5555_5555L;
x = ((x >> 1) & mask1) | ((x & mask1) << 1);
// swap 2-bit pairs:
enum mask2 = cast(N) 0x3333_3333_3333_3333L;
x = ((x >> 2) & mask2) | ((x & mask2) << 2);
// swap 4-bit pairs:
enum mask4 = cast(N) 0x0F0F_0F0F_0F0F_0F0FL;
x = ((x >> 4) & mask4) | ((x & mask4) << 4);
// reverse the order of all bytes:
x = bswap(x);
return x;
}
version (AsmX86)
{
private uint asmBitswap32(uint x) @trusted pure
{
asm pure nothrow @nogc { naked; }
version (D_InlineAsm_X86_64)
{
version (Win64)
asm pure nothrow @nogc { mov EAX, ECX; }
else
asm pure nothrow @nogc { mov EAX, EDI; }
}
asm pure nothrow @nogc
{
// Author: Tiago Gasiba.
mov EDX, EAX;
shr EAX, 1;
and EDX, 0x5555_5555;
and EAX, 0x5555_5555;
shl EDX, 1;
or EAX, EDX;
mov EDX, EAX;
shr EAX, 2;
and EDX, 0x3333_3333;
and EAX, 0x3333_3333;
shl EDX, 2;
or EAX, EDX;
mov EDX, EAX;
shr EAX, 4;
and EDX, 0x0f0f_0f0f;
and EAX, 0x0f0f_0f0f;
shl EDX, 4;
or EAX, EDX;
bswap EAX;
ret;
}
}
}
version (D_InlineAsm_X86_64)
{
private ulong asmBitswap64(ulong x) @trusted pure
{
asm pure nothrow @nogc { naked; }
version (Win64)
asm pure nothrow @nogc { mov RAX, RCX; }
else
asm pure nothrow @nogc { mov RAX, RDI; }
asm pure nothrow @nogc
{
// Author: Tiago Gasiba.
mov RDX, RAX;
shr RAX, 1;
mov RCX, 0x5555_5555_5555_5555L;
and RDX, RCX;
and RAX, RCX;
shl RDX, 1;
or RAX, RDX;
mov RDX, RAX;
shr RAX, 2;
mov RCX, 0x3333_3333_3333_3333L;
and RDX, RCX;
and RAX, RCX;
shl RDX, 2;
or RAX, RDX;
mov RDX, RAX;
shr RAX, 4;
mov RCX, 0x0f0f_0f0f_0f0f_0f0fL;
and RDX, RCX;
and RAX, RCX;
shl RDX, 4;
or RAX, RDX;
bswap RAX;
ret;
}
}
}
/**
* Bitwise rotate `value` left (`rol`) or right (`ror`) by
* `count` bit positions.
*/
pure T rol(T)(const T value, const uint count)
if (__traits(isIntegral, T) && __traits(isUnsigned, T))
{
assert(count < 8 * T.sizeof);
if (count == 0)
return cast(T) value;
return cast(T) ((value << count) | (value >> (T.sizeof * 8 - count)));
}
/// ditto
pure T ror(T)(const T value, const uint count)
if (__traits(isIntegral, T) && __traits(isUnsigned, T))
{
assert(count < 8 * T.sizeof);
if (count == 0)
return cast(T) value;
return cast(T) ((value >> count) | (value << (T.sizeof * 8 - count)));
}
/// ditto
pure T rol(uint count, T)(const T value)
if (__traits(isIntegral, T) && __traits(isUnsigned, T))
{
static assert(count < 8 * T.sizeof);
static if (count == 0)
return cast(T) value;
return cast(T) ((value << count) | (value >> (T.sizeof * 8 - count)));
}
/// ditto
pure T ror(uint count, T)(const T value)
if (__traits(isIntegral, T) && __traits(isUnsigned, T))
{
static assert(count < 8 * T.sizeof);
static if (count == 0)
return cast(T) value;
return cast(T) ((value >> count) | (value << (T.sizeof * 8 - count)));
}
///
unittest
{
ubyte a = 0b11110000U;
ulong b = ~1UL;
assert(rol(a, 1) == 0b11100001);
assert(ror(a, 1) == 0b01111000);
assert(rol(a, 3) == 0b10000111);
assert(ror(a, 3) == 0b00011110);
assert(rol(a, 0) == a);
assert(ror(a, 0) == a);
assert(rol(b, 63) == ~(1UL << 63));
assert(ror(b, 63) == ~2UL);
assert(rol!3(a) == 0b10000111);
assert(ror!3(a) == 0b00011110);
enum c = rol(uint(1), 0);
enum d = ror(uint(1), 0);
assert(c == uint(1));
assert(d == uint(1));
}