diff --git a/CMakeLists.txt b/CMakeLists.txt index 015832913fd1..1c03faf1e911 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,11 +1,5 @@ cmake_minimum_required(VERSION 2.8.12) -# Use ccache if possible -FIND_PROGRAM(CCACHE_PROGRAM ccache) -IF(CCACHE_PROGRAM) - MESSAGE(STATUS "Found ccache ${CCACHE_PROGRAM}") -ENDIF() - if(NOT CMAKE_BUILD_TYPE) set(CMAKE_BUILD_TYPE "Debug" CACHE STRING "Choose the type of build, options are: None Debug Release RelWithDebInfo MinSizeRel." FORCE) @@ -98,10 +92,15 @@ set(ZIG_SHARED_LLVM off CACHE BOOL "Prefer linking against shared LLVM libraries set(ZIG_STATIC_LLVM off CACHE BOOL "Prefer linking against static LLVM libraries") set(ZIG_STATIC_ZLIB off CACHE BOOL "Prefer linking against static zlib") set(ZIG_STATIC_ZSTD off CACHE BOOL "Prefer linking against static zstd") -set(ZIG_USE_CCACHE off CACHE BOOL "Use ccache if available") +set(ZIG_USE_CCACHE off CACHE BOOL "Use ccache") -if(CCACHE_PROGRAM AND ZIG_USE_CCACHE) - SET_PROPERTY(GLOBAL PROPERTY RULE_LAUNCH_COMPILE "${CCACHE_PROGRAM}") +if(ZIG_USE_CCACHE) + find_program(CCACHE_PROGRAM ccache) + if(CCACHE_PROGRAM) + set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE "${CCACHE_PROGRAM}") + else() + message(SEND_ERROR "ccache requested but not found") + endif() endif() if(ZIG_STATIC) @@ -118,19 +117,9 @@ string(REGEX REPLACE "\\\\" "\\\\\\\\" ZIG_LIBC_LIB_DIR_ESCAPED "${ZIG_LIBC_LIB_ string(REGEX REPLACE "\\\\" "\\\\\\\\" ZIG_LIBC_STATIC_LIB_DIR_ESCAPED "${ZIG_LIBC_STATIC_LIB_DIR}") string(REGEX REPLACE "\\\\" "\\\\\\\\" ZIG_LIBC_INCLUDE_DIR_ESCAPED "${ZIG_LIBC_INCLUDE_DIR}") -option(ZIG_TEST_COVERAGE "Build Zig with test coverage instrumentation" OFF) - set(ZIG_TARGET_TRIPLE "native" CACHE STRING "arch-os-abi to output binaries for") set(ZIG_TARGET_MCPU "native" CACHE STRING "-mcpu parameter to output binaries for") -set(ZIG_EXECUTABLE "" CACHE STRING "(when cross compiling) path to already-built zig binary") set(ZIG_SINGLE_THREADED off CACHE BOOL "limit the zig compiler to use only 1 thread") -set(ZIG_OMIT_STAGE2 off CACHE BOOL "omit the stage2 backend from stage1") - -if("${CMAKE_BUILD_TYPE}" STREQUAL "Debug") - set(ZIG_ENABLE_LOGGING ON CACHE BOOL "enable logging") -else() - set(ZIG_ENABLE_LOGGING OFF CACHE BOOL "enable logging") -endif() if("${ZIG_TARGET_TRIPLE}" STREQUAL "native") set(ZIG_USE_LLVM_CONFIG ON CACHE BOOL "use llvm-config to find LLVM libraries") @@ -179,190 +168,6 @@ include_directories(${LLVM_INCLUDE_DIRS}) include_directories(${LLD_INCLUDE_DIRS}) include_directories(${CLANG_INCLUDE_DIRS}) -# No patches have been applied to SoftFloat-3e -set(EMBEDDED_SOFTFLOAT_SOURCES - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/8086/f128M_isSignalingNaN.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/8086/extF80M_isSignalingNaN.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/8086/s_commonNaNToF128M.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/8086/s_commonNaNToExtF80M.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/8086/s_commonNaNToF16UI.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/8086/s_commonNaNToF32UI.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/8086/s_commonNaNToF64UI.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/8086/s_f128MToCommonNaN.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/8086/s_extF80MToCommonNaN.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/8086/s_f16UIToCommonNaN.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/8086/s_f32UIToCommonNaN.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/8086/s_f64UIToCommonNaN.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/8086/s_propagateNaNF128M.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/8086/s_propagateNaNExtF80M.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/8086/s_propagateNaNF16UI.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/8086/softfloat_raiseFlags.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f128M_add.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f128M_div.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f128M_eq.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f128M_eq_signaling.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f128M_le.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f128M_le_quiet.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f128M_lt.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f128M_lt_quiet.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f128M_mul.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f128M_mulAdd.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f128M_rem.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f128M_roundToInt.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f128M_sqrt.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f128M_sub.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f128M_to_f16.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f128M_to_f32.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f128M_to_f64.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f128M_to_extF80M.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f128M_to_i32.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f128M_to_i32_r_minMag.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f128M_to_i64.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f128M_to_i64_r_minMag.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f128M_to_ui32.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f128M_to_ui32_r_minMag.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f128M_to_ui64.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f128M_to_ui64_r_minMag.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/extF80M_add.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/extF80M_div.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/extF80M_eq.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/extF80M_le.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/extF80M_lt.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/extF80M_mul.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/extF80M_rem.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/extF80M_roundToInt.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/extF80M_sqrt.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/extF80M_sub.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/extF80M_to_f16.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/extF80M_to_f32.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/extF80M_to_f64.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/extF80M_to_f128M.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f16_add.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f16_div.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f16_eq.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f16_isSignalingNaN.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f16_lt.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f16_mul.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f16_rem.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f16_roundToInt.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f16_sqrt.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f16_sub.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f16_to_extF80M.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f16_to_f128M.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f16_to_f64.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f32_to_extF80M.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f32_to_f128M.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f64_to_extF80M.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f64_to_f128M.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f64_to_f16.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/i32_to_f128M.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_add256M.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_addCarryM.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_addComplCarryM.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_addF128M.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_addExtF80M.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_addM.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_addMagsF16.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_addMagsF32.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_addMagsF64.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_approxRecip32_1.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_approxRecipSqrt32_1.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_approxRecipSqrt_1Ks.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_approxRecip_1Ks.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_compare128M.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_compare96M.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_compareNonnormExtF80M.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_countLeadingZeros16.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_countLeadingZeros32.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_countLeadingZeros64.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_countLeadingZeros8.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_eq128.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_invalidF128M.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_invalidExtF80M.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_isNaNF128M.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_le128.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_lt128.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_mul128MTo256M.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_mul64To128M.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_mulAddF128M.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_mulAddF16.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_mulAddF32.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_mulAddF64.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_negXM.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_normExtF80SigM.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_normRoundPackMToF128M.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_normRoundPackMToExtF80M.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_normRoundPackToF16.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_normRoundPackToF32.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_normRoundPackToF64.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_normSubnormalF128SigM.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_normSubnormalF16Sig.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_normSubnormalF32Sig.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_normSubnormalF64Sig.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_remStepMBy32.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_roundMToI64.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_roundMToUI64.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_roundPackMToExtF80M.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_roundPackMToF128M.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_roundPackToF16.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_roundPackToF32.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_roundPackToF64.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_roundToI32.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_roundToI64.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_roundToUI32.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_roundToUI64.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_shiftLeftM.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_shiftNormSigF128M.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_shiftRightJam256M.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_shiftRightJam32.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_shiftRightJam64.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_shiftRightJamM.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_shiftRightM.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_shortShiftLeft64To96M.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_shortShiftLeftM.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_shortShiftRightExtendM.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_shortShiftRightJam64.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_shortShiftRightJamM.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_shortShiftRightM.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_sub1XM.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_sub256M.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_subM.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_subMagsF16.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_subMagsF32.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_subMagsF64.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_tryPropagateNaNF128M.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_tryPropagateNaNExtF80M.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f16_mulAdd.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f128M_mulAdd.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/softfloat_state.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/ui32_to_f128M.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/ui64_to_f128M.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/ui32_to_extF80M.c" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/ui64_to_extF80M.c" -) -add_library(embedded_softfloat STATIC ${EMBEDDED_SOFTFLOAT_SOURCES}) -if(MSVC) - set(SOFTFLOAT_CFLAGS "/w") - - if(NOT "${CMAKE_BUILD_TYPE}" STREQUAL "Debug") - set(SOFTFLOAT_CFLAGS "${SOFTFLOAT_CFLAGS} /O2") - endif() - - set_target_properties(embedded_softfloat PROPERTIES - COMPILE_FLAGS ${SOFTFLOAT_CFLAGS} - ) -else() - set_target_properties(embedded_softfloat PROPERTIES - COMPILE_FLAGS "-std=c99 -O3" - ) -endif() -target_include_directories(embedded_softfloat PUBLIC - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e-prebuilt" - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/8086" -) -include_directories("${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/include") -set(SOFTFLOAT_LIBRARIES embedded_softfloat) - find_package(Threads) set(ZIG_LIB_DIR "lib/zig") @@ -374,35 +179,18 @@ set(ZIG_STD_DEST "${ZIG_LIB_DIR}/std") set(ZIG_CONFIG_H_OUT "${CMAKE_BINARY_DIR}/config.h") set(ZIG_CONFIG_ZIG_OUT "${CMAKE_BINARY_DIR}/config.zig") -# This is our shim which will be replaced by stage1.zig. -set(ZIG1_SOURCES - "${CMAKE_SOURCE_DIR}/src/stage1/zig0.cpp" -) - -set(STAGE1_SOURCES - "${CMAKE_SOURCE_DIR}/src/stage1/analyze.cpp" - "${CMAKE_SOURCE_DIR}/src/stage1/astgen.cpp" - "${CMAKE_SOURCE_DIR}/src/stage1/bigfloat.cpp" - "${CMAKE_SOURCE_DIR}/src/stage1/bigint.cpp" - "${CMAKE_SOURCE_DIR}/src/stage1/buffer.cpp" - "${CMAKE_SOURCE_DIR}/src/stage1/codegen.cpp" - "${CMAKE_SOURCE_DIR}/src/stage1/errmsg.cpp" - "${CMAKE_SOURCE_DIR}/src/stage1/error.cpp" - "${CMAKE_SOURCE_DIR}/src/stage1/heap.cpp" - "${CMAKE_SOURCE_DIR}/src/stage1/ir.cpp" - "${CMAKE_SOURCE_DIR}/src/stage1/ir_print.cpp" - "${CMAKE_SOURCE_DIR}/src/stage1/mem.cpp" - "${CMAKE_SOURCE_DIR}/src/stage1/os.cpp" - "${CMAKE_SOURCE_DIR}/src/stage1/parser.cpp" - "${CMAKE_SOURCE_DIR}/src/stage1/range_set.cpp" - "${CMAKE_SOURCE_DIR}/src/stage1/softfloat_ext.cpp" - "${CMAKE_SOURCE_DIR}/src/stage1/stage1.cpp" - "${CMAKE_SOURCE_DIR}/src/stage1/target.cpp" - "${CMAKE_SOURCE_DIR}/src/stage1/tokenizer.cpp" - "${CMAKE_SOURCE_DIR}/src/stage1/util.cpp" -) -set(OPTIMIZED_C_SOURCES - "${CMAKE_SOURCE_DIR}/src/stage1/parse_f128.c" +set(ZIG_WASM2C_SOURCES + "${CMAKE_SOURCE_DIR}/stage1/wasm2c.c" + "${CMAKE_SOURCE_DIR}/stage1/zstd/lib/decompress/huf_decompress.c" + "${CMAKE_SOURCE_DIR}/stage1/zstd/lib/decompress/zstd_ddict.c" + "${CMAKE_SOURCE_DIR}/stage1/zstd/lib/decompress/zstd_decompress.c" + "${CMAKE_SOURCE_DIR}/stage1/zstd/lib/decompress/zstd_decompress_block.c" + "${CMAKE_SOURCE_DIR}/stage1/zstd/lib/common/entropy_common.c" + "${CMAKE_SOURCE_DIR}/stage1/zstd/lib/common/error_private.c" + "${CMAKE_SOURCE_DIR}/stage1/zstd/lib/common/fse_decompress.c" + "${CMAKE_SOURCE_DIR}/stage1/zstd/lib/common/pool.c" + "${CMAKE_SOURCE_DIR}/stage1/zstd/lib/common/xxhash.c" + "${CMAKE_SOURCE_DIR}/stage1/zstd/lib/common/zstd_common.c" ) set(ZIG_CPP_SOURCES # These are planned to stay even when we are self-hosted. @@ -416,9 +204,6 @@ set(ZIG_CPP_SOURCES "${CMAKE_SOURCE_DIR}/src/windows_sdk.cpp" ) # Needed because we use cmake, not the zig build system, to build zig2.o. -# This list is generated by building zig and then clearing the zig-cache directory, -# then manually running the build-obj command (see BUILD_ZIG2_ARGS), and then looking -# in the zig-cache directory for the compiler-generated list of zig file dependencies. set(ZIG_STAGE2_SOURCES "${ZIG_CONFIG_ZIG_OUT}" "${CMAKE_SOURCE_DIR}/lib/std/array_hash_map.zig" @@ -828,7 +613,6 @@ set(ZIG_STAGE2_SOURCES "${CMAKE_SOURCE_DIR}/src/print_targets.zig" "${CMAKE_SOURCE_DIR}/src/print_zir.zig" "${CMAKE_SOURCE_DIR}/src/register_manager.zig" - "${CMAKE_SOURCE_DIR}/src/stage1.zig" "${CMAKE_SOURCE_DIR}/src/target.zig" "${CMAKE_SOURCE_DIR}/src/tracy.zig" "${CMAKE_SOURCE_DIR}/src/translate_c.zig" @@ -847,24 +631,12 @@ if(MSVC) endif() endif() -if(ZIG_OMIT_STAGE2) - set(ZIG_OMIT_STAGE2_BOOL "true") -else() - set(ZIG_OMIT_STAGE2_BOOL "false") -endif() - -if(ZIG_ENABLE_LOGGING) - set(ZIG_ENABLE_LOGGING_BOOL "true") -else() - set(ZIG_ENABLE_LOGGING_BOOL "false") -endif() - configure_file ( - "${CMAKE_SOURCE_DIR}/src/stage1/config.h.in" + "${CMAKE_SOURCE_DIR}/stage1/config.h.in" "${ZIG_CONFIG_H_OUT}" ) configure_file ( - "${CMAKE_SOURCE_DIR}/src/config.zig.in" + "${CMAKE_SOURCE_DIR}/stage1/config.zig.in" "${ZIG_CONFIG_ZIG_OUT}" ) @@ -872,55 +644,40 @@ include_directories( ${CMAKE_SOURCE_DIR} ${CMAKE_BINARY_DIR} "${CMAKE_SOURCE_DIR}/src" - "${CMAKE_SOURCE_DIR}/src/stage1" ) # These have to go before the -Wno- flags if(MSVC) - set(EXE_CFLAGS "/std:c++14") + set(EXE_CXX_FLAGS "/std:c++14") else(MSVC) - set(EXE_CFLAGS "-std=c++14") + set(EXE_CXX_FLAGS "-std=c++14") endif(MSVC) -if(ZIG_STATIC) - set(EXE_CFLAGS "${EXE_CFLAGS} -DZIG_LINK_MODE=Static") -else() - set(EXE_CFLAGS "${EXE_CFLAGS} -DZIG_LINK_MODE=Dynamic") -endif() - if("${CMAKE_BUILD_TYPE}" STREQUAL "Debug") if(MSVC) - set(EXE_CFLAGS "${EXE_CFLAGS} /w") + set(EXE_CXX_FLAGS "${EXE_CXX_FLAGS} /w") else() - set(EXE_CFLAGS "${EXE_CFLAGS} -Werror -Wall") + set(EXE_CXX_FLAGS "${EXE_CXX_FLAGS} -Werror -Wall") # fallthrough support was added in GCC 7.0 if(NOT CMAKE_CXX_COMPILER_ID STREQUAL "GNU" OR CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 7.0) - set(EXE_CFLAGS "${EXE_CFLAGS} -Werror=implicit-fallthrough") + set(EXE_CXX_FLAGS "${EXE_CXX_FLAGS} -Werror=implicit-fallthrough") endif() # GCC 9.2 and older are unable to detect valid variable initialization in some cases if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS_EQUAL 9.2) - set(EXE_CFLAGS "${EXE_CFLAGS} -Wno-maybe-uninitialized") + set(EXE_CXX_FLAGS "${EXE_CXX_FLAGS} -Wno-maybe-uninitialized") endif() endif() endif() if(MSVC) - set(EXE_CFLAGS "${EXE_CFLAGS}") + set(EXE_CXX_FLAGS "${EXE_CXX_FLAGS}") else() - set(EXE_CFLAGS "${EXE_CFLAGS} -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -D_GNU_SOURCE -fvisibility-inlines-hidden -fno-exceptions -fno-rtti -Werror=type-limits -Wno-missing-braces -Wno-comment") + set(EXE_CXX_FLAGS "${EXE_CXX_FLAGS} -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -D_GNU_SOURCE -fvisibility-inlines-hidden -fno-exceptions -fno-rtti -Werror=type-limits -Wno-missing-braces -Wno-comment") if(MINGW) - set(EXE_CFLAGS "${EXE_CFLAGS} -Wno-format") + set(EXE_CXX_FLAGS "${EXE_CXX_FLAGS} -Wno-format") endif() endif() -if(MSVC) - if(NOT "${CMAKE_BUILD_TYPE}" STREQUAL "Debug") - set(OPTIMIZED_C_FLAGS "/O2") - endif() -else(MSVC) - set(OPTIMIZED_C_FLAGS "-std=c99 -O3") -endif(MSVC) - set(EXE_LDFLAGS " ") if(MSVC) set(EXE_LDFLAGS "${EXE_LDFLAGS} /STACK:16777216") @@ -939,21 +696,10 @@ if(ZIG_STATIC) elseif(NOT MSVC) set(EXE_LDFLAGS "${EXE_LDFLAGS} -static") endif() -else() - if(MINGW) - set(EXE_LDFLAGS "${EXE_LDFLAGS}") - endif() -endif() - -if(ZIG_TEST_COVERAGE) - set(EXE_CFLAGS "${EXE_CFLAGS} -fprofile-arcs -ftest-coverage") - set(EXE_LDFLAGS "${EXE_LDFLAGS} -fprofile-arcs -ftest-coverage") endif() add_library(zigcpp STATIC ${ZIG_CPP_SOURCES}) -set_target_properties(zigcpp PROPERTIES - COMPILE_FLAGS ${EXE_CFLAGS} -) +set_target_properties(zigcpp PROPERTIES COMPILE_FLAGS ${EXE_CXX_FLAGS}) target_link_libraries(zigcpp LINK_PUBLIC ${CLANG_LIBRARIES} @@ -962,50 +708,120 @@ target_link_libraries(zigcpp LINK_PUBLIC ${CMAKE_THREAD_LIBS_INIT} ) -add_library(opt_c_util STATIC ${OPTIMIZED_C_SOURCES}) -set_target_properties(opt_c_util PROPERTIES - COMPILE_FLAGS "${OPTIMIZED_C_FLAGS}" +if(CMAKE_HOST_SYSTEM_PROCESSOR STREQUAL "AMD64") + set(HOST_TARGET_ARCH "x86_64") +elseif(CMAKE_HOST_SYSTEM_PROCESSOR STREQUAL "arm64") + set(HOST_TARGET_ARCH "aarch64") +else() + string(TOLOWER "${CMAKE_HOST_SYSTEM_PROCESSOR}" HOST_TARGET_ARCH) +endif() +if(CMAKE_HOST_SYSTEM_NAME STREQUAL "Darwin") + set(HOST_TARGET_OS "macos") +else() + string(TOLOWER "${CMAKE_HOST_SYSTEM_NAME}" HOST_TARGET_OS) +endif() +set(HOST_TARGET_TRIPLE "${HOST_TARGET_ARCH}-${HOST_TARGET_OS}") + +if(MSVC) + set(ZIG_WASM2C_COMPILE_FLAGS "/std:c99 /O2") + set(ZIG1_COMPILE_FLAGS "/std:c99 /Os") + set(ZIG2_COMPILE_FLAGS "/std:c99 /O0") + set(ZIG2_LINK_FLAGS "/STACK:16777216") +else() + set(ZIG_WASM2C_COMPILE_FLAGS "-std=c99 -O2") + set(ZIG1_COMPILE_FLAGS "-std=c99 -Os") + set(ZIG2_COMPILE_FLAGS "-std=c99 -O0 -fno-stack-protector") + if(APPLE) + set(ZIG2_LINK_FLAGS "-Wl,-stack_size,0x10000000") + else() + set(ZIG2_LINK_FLAGS "-Wl,-z,stack-size=0x10000000") + endif() +endif() + +set(ZIG1_WASM_ZST_SOURCE "${CMAKE_SOURCE_DIR}/stage1/zig1.wasm.zst") +set(ZIG1_C_SOURCE "${CMAKE_BINARY_DIR}/zig1.c") +set(ZIG2_C_SOURCE "${CMAKE_BINARY_DIR}/zig2.c") +set(ZIG_COMPILER_RT_C_SOURCE "${CMAKE_BINARY_DIR}/compiler_rt.c") + +add_executable(zig-wasm2c ${ZIG_WASM2C_SOURCES}) +set_target_properties(zig-wasm2c PROPERTIES COMPILE_FLAGS ${ZIG_WASM2C_COMPILE_FLAGS}) +target_include_directories(zig-wasm2c PUBLIC "${CMAKE_SOURCE_DIR}/stage1/zstd/lib") +target_compile_definitions(zig-wasm2c PRIVATE ZSTD_DISABLE_ASM) + +add_custom_command( + OUTPUT "${ZIG1_C_SOURCE}" + COMMAND zig-wasm2c "${ZIG1_WASM_ZST_SOURCE}" "${ZIG1_C_SOURCE}" + DEPENDS zig-wasm2c "${ZIG1_WASM_ZST_SOURCE}" + COMMENT STATUS "Converting ${ZIG1_WASM_ZST_SOURCE} to ${ZIG1_C_SOURCE}" + WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}" +) + +add_executable(zig1 ${ZIG1_C_SOURCE} "${CMAKE_SOURCE_DIR}/stage1/wasi.c") +set_target_properties(zig1 PROPERTIES COMPILE_FLAGS ${ZIG1_COMPILE_FLAGS}) +target_link_libraries(zig1 LINK_PUBLIC m) +target_include_directories(zig1 PUBLIC "${CMAKE_SOURCE_DIR}/stage1/zstd/lib") +target_compile_definitions(zig1 PRIVATE ZSTD_DISABLE_ASM) + +set(BUILD_ZIG2_ARGS + "${CMAKE_SOURCE_DIR}/lib" + build-exe src/main.zig -ofmt=c -lc + -OReleaseSmall + --name zig2 -femit-bin="${ZIG2_C_SOURCE}" + --pkg-begin build_options "${ZIG_CONFIG_ZIG_OUT}" --pkg-end + -target "${HOST_TARGET_TRIPLE}" ) -target_include_directories(opt_c_util PRIVATE - "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e-prebuilt" + +add_custom_command( + OUTPUT "${ZIG2_C_SOURCE}" + COMMAND zig1 ${BUILD_ZIG2_ARGS} + DEPENDS zig1 "${ZIG_STAGE2_SOURCES}" + COMMENT STATUS "Running zig1.wasm to produce ${ZIG2_C_SOURCE}" + WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}" ) -add_library(zigstage1 STATIC ${STAGE1_SOURCES}) -set_target_properties(zigstage1 PROPERTIES - COMPILE_FLAGS ${EXE_CFLAGS} - LINK_FLAGS ${EXE_LDFLAGS} +set(BUILD_COMPILER_RT_ARGS + "${CMAKE_SOURCE_DIR}/lib" + build-obj lib/compiler_rt.zig -ofmt=c + -OReleaseSmall + --name compiler_rt -femit-bin="${ZIG_COMPILER_RT_C_SOURCE}" + --pkg-begin build_options "${ZIG_CONFIG_ZIG_OUT}" --pkg-end + -target "${HOST_TARGET_TRIPLE}" +) + +add_custom_command( + OUTPUT "${ZIG_COMPILER_RT_C_SOURCE}" + COMMAND zig1 ${BUILD_COMPILER_RT_ARGS} + DEPENDS zig1 "${ZIG_STAGE2_SOURCES}" + COMMENT STATUS "Running zig1.wasm to produce ${ZIG_COMPILER_RT_C_SOURCE}" + WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}" ) -target_link_libraries(zigstage1 LINK_PUBLIC - opt_c_util - ${SOFTFLOAT_LIBRARIES} - zigcpp + +add_executable(zig2 ${ZIG2_C_SOURCE} ${ZIG_COMPILER_RT_C_SOURCE}) +set_target_properties(zig2 PROPERTIES + COMPILE_FLAGS ${ZIG2_COMPILE_FLAGS} + LINK_FLAGS ${ZIG2_LINK_FLAGS} ) +target_include_directories(zig2 PUBLIC "${CMAKE_SOURCE_DIR}/lib") +target_link_libraries(zig2 LINK_PUBLIC zigcpp) + +if(MSVC) + target_link_libraries(zig2 LINK_PUBLIC ntdll.lib) +elseif(MINGW) + target_link_libraries(zig2 LINK_PUBLIC ntdll) +endif() + if(NOT MSVC) - target_link_libraries(zigstage1 LINK_PUBLIC ${LIBXML2}) + target_link_libraries(zig2 LINK_PUBLIC ${LIBXML2}) endif() if(ZIG_DIA_GUIDS_LIB) - target_link_libraries(zigstage1 LINK_PUBLIC ${ZIG_DIA_GUIDS_LIB}) + target_link_libraries(zig2 LINK_PUBLIC ${ZIG_DIA_GUIDS_LIB}) endif() if(MSVC OR MINGW) - target_link_libraries(zigstage1 LINK_PUBLIC version) -endif() - -if("${ZIG_EXECUTABLE}" STREQUAL "") - add_executable(zig1 ${ZIG1_SOURCES}) - set_target_properties(zig1 PROPERTIES - COMPILE_FLAGS ${EXE_CFLAGS} - LINK_FLAGS ${EXE_LDFLAGS} - ) - target_link_libraries(zig1 zigstage1) + target_link_libraries(zig2 LINK_PUBLIC version) endif() -if(MSVC) - set(ZIG2_OBJECT "${CMAKE_BINARY_DIR}/zig2.obj") -else() - set(ZIG2_OBJECT "${CMAKE_BINARY_DIR}/zig2.o") -endif() if("${CMAKE_BUILD_TYPE}" STREQUAL "Debug") set(ZIG_RELEASE_ARG "") elseif("${CMAKE_BUILD_TYPE}" STREQUAL "RelWithDebInfo") @@ -1029,78 +845,32 @@ else() set(ZIG_STATIC_ARG "") endif() -set(BUILD_ZIG2_ARGS - "src/stage1.zig" - --name zig2 - --zig-lib-dir "${CMAKE_SOURCE_DIR}/lib" - "-femit-bin=${ZIG2_OBJECT}" - -fcompiler-rt - ${ZIG_SINGLE_THREADED_ARG} - -target native - -mcpu native - -lc - --pkg-begin build_options "${ZIG_CONFIG_ZIG_OUT}" - --pkg-end -) - -if("${ZIG_EXECUTABLE}" STREQUAL "") - add_custom_command( - OUTPUT "${ZIG2_OBJECT}" - COMMAND zig1 ${BUILD_ZIG2_ARGS} - DEPENDS zig1 "${ZIG_STAGE2_SOURCES}" - COMMENT STATUS "Building stage2 object ${ZIG2_OBJECT}" - WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}" - ) - if (WIN32) - set(ZIG_EXECUTABLE "${CMAKE_BINARY_DIR}/zig2.exe") - else() - set(ZIG_EXECUTABLE "${CMAKE_BINARY_DIR}/zig2") - endif() -else() - add_custom_command( - OUTPUT "${ZIG2_OBJECT}" - COMMAND "${ZIG_EXECUTABLE}" "build-obj" ${BUILD_ZIG2_ARGS} - DEPENDS ${ZIG_STAGE2_SOURCES} - COMMENT STATUS "Building stage2 component ${ZIG2_OBJECT}" - WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}" - ) -endif() - -# cmake won't let us configure an executable without C sources. -add_executable(zig2 "${CMAKE_SOURCE_DIR}/src/stage1/empty.cpp" "${ZIG2_OBJECT}") - -set_target_properties(zig2 PROPERTIES - COMPILE_FLAGS ${EXE_CFLAGS} - LINK_FLAGS ${EXE_LDFLAGS} -) -target_link_libraries(zig2 zigstage1) -if(MSVC) - target_link_libraries(zig2 ntdll.lib) -elseif(MINGW) - target_link_libraries(zig2 ntdll) -endif() - set(ZIG_BUILD_ARGS - --zig-lib-dir "${CMAKE_SOURCE_DIR}/lib" - "-Dconfig_h=${ZIG_CONFIG_H_OUT}" - "-Denable-llvm" - "-Denable-stage1" - ${ZIG_RELEASE_ARG} - ${ZIG_STATIC_ARG} - ${ZIG_NO_LIB_ARG} - ${ZIG_SINGLE_THREADED_ARG} - "-Dtarget=${ZIG_TARGET_TRIPLE}" - "-Dcpu=${ZIG_TARGET_MCPU}" - "-Dversion-string=${RESOLVED_ZIG_VERSION}" + --zig-lib-dir "${CMAKE_SOURCE_DIR}/lib" + "-Dconfig_h=${ZIG_CONFIG_H_OUT}" + "-Denable-llvm" + ${ZIG_RELEASE_ARG} + ${ZIG_STATIC_ARG} + ${ZIG_NO_LIB_ARG} + ${ZIG_SINGLE_THREADED_ARG} + "-Dtarget=${ZIG_TARGET_TRIPLE}" + "-Dcpu=${ZIG_TARGET_MCPU}" + "-Dversion-string=${RESOLVED_ZIG_VERSION}" ) add_custom_target(stage3 ALL - COMMAND zig2 build compile ${ZIG_BUILD_ARGS} - DEPENDS zig2 - COMMENT STATUS "Building stage3" - WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}" + COMMAND zig2 build compile ${ZIG_BUILD_ARGS} + DEPENDS zig2 + COMMENT STATUS "Building stage3" + WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}" ) +if(WIN32) + set(ZIG_EXECUTABLE "${CMAKE_BINARY_DIR}/zig2.exe") +else() + set(ZIG_EXECUTABLE "${CMAKE_BINARY_DIR}/zig2") +endif() + install(CODE "set(ZIG_EXECUTABLE \"${ZIG_EXECUTABLE}\")") install(CODE "set(ZIG_BUILD_ARGS \"${ZIG_BUILD_ARGS}\")") install(CODE "set(CMAKE_INSTALL_PREFIX \"${CMAKE_INSTALL_PREFIX}\")") diff --git a/build.zig b/build.zig index 69f65d2a5939..f37fa9b2685d 100644 --- a/build.zig +++ b/build.zig @@ -14,13 +14,25 @@ const zig_version = std.builtin.Version{ .major = 0, .minor = 11, .patch = 0 }; const stack_size = 32 * 1024 * 1024; pub fn build(b: *Builder) !void { - b.setPreferredReleaseMode(.ReleaseFast); - const test_step = b.step("test", "Run all the tests"); - const mode = b.standardReleaseOptions(); - var target = b.standardTargetOptions(.{}); + const release = b.option(bool, "release", "Build in release mode") orelse false; + const only_c = b.option(bool, "only-c", "Translate the Zig compiler to C code, with only the C backend enabled") orelse false; + const target = t: { + var default_target: std.zig.CrossTarget = .{}; + if (only_c) { + default_target.ofmt = .c; + } + break :t b.standardTargetOptions(.{ .default_target = default_target }); + }; + const mode: std.builtin.Mode = if (release) switch (target.getCpuArch()) { + .wasm32 => .ReleaseSmall, + else => .ReleaseFast, + } else .Debug; + const single_threaded = b.option(bool, "single-threaded", "Build artifacts that run in single threaded mode"); const use_zig_libcxx = b.option(bool, "use-zig-libcxx", "If libc++ is needed, use zig's bundled version, don't try to integrate with the system") orelse false; + const test_step = b.step("test", "Run all the tests"); + const docgen_exe = b.addExecutable("docgen", "doc/docgen.zig"); docgen_exe.single_threaded = single_threaded; @@ -48,8 +60,6 @@ pub fn build(b: *Builder) !void { const fmt_build_zig = b.addFmt(&[_][]const u8{"build.zig"}); - const only_c = b.option(bool, "only-c", "Translate the Zig compiler to C code, with only the C backend enabled") orelse false; - const skip_debug = b.option(bool, "skip-debug", "Main test suite skips debug builds") orelse false; const skip_release = b.option(bool, "skip-release", "Main test suite skips release builds") orelse false; const skip_release_small = b.option(bool, "skip-release-small", "Main test suite skips release-small builds") orelse skip_release; @@ -69,9 +79,8 @@ pub fn build(b: *Builder) !void { const only_install_lib_files = b.option(bool, "lib-files-only", "Only install library files") orelse false; - const have_stage1 = b.option(bool, "enable-stage1", "Include the stage1 compiler behind a feature flag") orelse false; const static_llvm = b.option(bool, "static-llvm", "Disable integration with system-installed LLVM, Clang, LLD, and libc++") orelse false; - const enable_llvm = b.option(bool, "enable-llvm", "Build self-hosted compiler with LLVM backend enabled") orelse (have_stage1 or static_llvm); + const enable_llvm = b.option(bool, "enable-llvm", "Build self-hosted compiler with LLVM backend enabled") orelse static_llvm; const llvm_has_m68k = b.option( bool, "llvm-has-m68k", @@ -132,38 +141,26 @@ pub fn build(b: *Builder) !void { const force_gpa = b.option(bool, "force-gpa", "Force the compiler to use GeneralPurposeAllocator") orelse false; const link_libc = b.option(bool, "force-link-libc", "Force self-hosted compiler to link libc") orelse (enable_llvm or only_c); const sanitize_thread = b.option(bool, "sanitize-thread", "Enable thread-sanitization") orelse false; - const strip = b.option(bool, "strip", "Omit debug information") orelse false; - const use_zig0 = b.option(bool, "zig0", "Bootstrap using zig0") orelse false; + const strip = b.option(bool, "strip", "Omit debug information"); const value_tracing = b.option(bool, "value-tracing", "Enable extra state tracking to help troubleshoot bugs in the compiler (using the std.debug.Trace API)") orelse false; const mem_leak_frames: u32 = b.option(u32, "mem-leak-frames", "How many stack frames to print when a memory leak occurs. Tests get 2x this amount.") orelse blk: { - if (strip) break :blk @as(u32, 0); + if (strip == true) break :blk @as(u32, 0); if (mode != .Debug) break :blk 0; break :blk 4; }; - if (only_c) { - target.ofmt = .c; - } - - const main_file: ?[]const u8 = mf: { - if (!have_stage1) break :mf "src/main.zig"; - if (use_zig0) break :mf null; - break :mf "src/stage1.zig"; - }; - - const exe = b.addExecutable("zig", main_file); - - const compile_step = b.step("compile", "Build the self-hosted compiler"); - compile_step.dependOn(&exe.step); - - exe.stack_size = stack_size; + const exe = addCompilerStep(b); exe.strip = strip; exe.sanitize_thread = sanitize_thread; exe.build_id = b.option(bool, "build-id", "Include a build id note") orelse false; exe.install(); exe.setBuildMode(mode); exe.setTarget(target); + + const compile_step = b.step("compile", "Build the self-hosted compiler"); + compile_step.dependOn(&exe.step); + if (!skip_stage2_tests) { test_step.dependOn(&exe.step); } @@ -199,7 +196,7 @@ pub fn build(b: *Builder) !void { const enable_link_snapshots = b.option(bool, "link-snapshot", "Whether to enable linker state snapshots") orelse false; const opt_version_string = b.option([]const u8, "version-string", "Override Zig version string. Default is to find out with git."); - const version = if (opt_version_string) |version| version else v: { + const version_slice = if (opt_version_string) |version| version else v: { if (!std.process.can_spawn) { std.debug.print("error: version info cannot be retrieved from git. Zig version must be provided using -Dversion-string\n", .{}); std.process.exit(1); @@ -251,7 +248,8 @@ pub fn build(b: *Builder) !void { }, } }; - exe_options.addOption([:0]const u8, "version", try b.allocator.dupeZ(u8, version)); + const version = try b.allocator.dupeZ(u8, version_slice); + exe_options.addOption([:0]const u8, "version", version); if (enable_llvm) { const cmake_cfg = if (static_llvm) null else blk: { @@ -264,92 +262,6 @@ pub fn build(b: *Builder) !void { } }; - if (have_stage1) { - const softfloat = b.addStaticLibrary("softfloat", null); - softfloat.setBuildMode(.ReleaseFast); - softfloat.setTarget(target); - softfloat.addIncludePath("deps/SoftFloat-3e-prebuilt"); - softfloat.addIncludePath("deps/SoftFloat-3e/source/8086"); - softfloat.addIncludePath("deps/SoftFloat-3e/source/include"); - softfloat.addCSourceFiles(&softfloat_sources, &[_][]const u8{ "-std=c99", "-O3" }); - softfloat.single_threaded = single_threaded; - - const zig0 = b.addExecutable("zig0", null); - zig0.addCSourceFiles(&.{"src/stage1/zig0.cpp"}, &exe_cflags); - zig0.addIncludePath("zig-cache/tmp"); // for config.h - zig0.defineCMacro("ZIG_VERSION_MAJOR", b.fmt("{d}", .{zig_version.major})); - zig0.defineCMacro("ZIG_VERSION_MINOR", b.fmt("{d}", .{zig_version.minor})); - zig0.defineCMacro("ZIG_VERSION_PATCH", b.fmt("{d}", .{zig_version.patch})); - zig0.defineCMacro("ZIG_VERSION_STRING", b.fmt("\"{s}\"", .{version})); - - for ([_]*std.build.LibExeObjStep{ zig0, exe, test_cases }) |artifact| { - artifact.addIncludePath("src"); - artifact.addIncludePath("deps/SoftFloat-3e/source/include"); - artifact.addIncludePath("deps/SoftFloat-3e-prebuilt"); - - artifact.defineCMacro("ZIG_LINK_MODE", "Static"); - - artifact.addCSourceFiles(&stage1_sources, &exe_cflags); - artifact.addCSourceFiles(&optimized_c_sources, &[_][]const u8{ "-std=c99", "-O3" }); - - artifact.linkLibrary(softfloat); - artifact.linkLibCpp(); - } - - try addStaticLlvmOptionsToExe(zig0); - - const zig1_obj_ext = target.getObjectFormat().fileExt(target.getCpuArch()); - const zig1_obj_path = b.pathJoin(&.{ "zig-cache", "tmp", b.fmt("zig1{s}", .{zig1_obj_ext}) }); - const zig1_compiler_rt_path = b.pathJoin(&.{ b.pathFromRoot("lib"), "std", "special", "compiler_rt.zig" }); - - const zig1_obj = zig0.run(); - zig1_obj.addArgs(&.{ - "src/stage1.zig", - "-target", - try target.zigTriple(b.allocator), - "-mcpu=baseline", - "--name", - "zig1", - "--zig-lib-dir", - b.pathFromRoot("lib"), - b.fmt("-femit-bin={s}", .{b.pathFromRoot(zig1_obj_path)}), - "-fcompiler-rt", - "-lc", - }); - { - zig1_obj.addArgs(&.{ "--pkg-begin", "build_options" }); - zig1_obj.addFileSourceArg(exe_options.getSource()); - zig1_obj.addArgs(&.{ "--pkg-end", "--pkg-begin", "compiler_rt", zig1_compiler_rt_path, "--pkg-end" }); - } - switch (mode) { - .Debug => {}, - .ReleaseFast => { - zig1_obj.addArg("-OReleaseFast"); - zig1_obj.addArg("-fstrip"); - }, - .ReleaseSafe => { - zig1_obj.addArg("-OReleaseSafe"); - zig1_obj.addArg("-fstrip"); - }, - .ReleaseSmall => { - zig1_obj.addArg("-OReleaseSmall"); - zig1_obj.addArg("-fstrip"); - }, - } - if (single_threaded orelse false) { - zig1_obj.addArg("-fsingle-threaded"); - } - - if (use_zig0) { - exe.step.dependOn(&zig1_obj.step); - exe.addObjectFile(zig1_obj_path); - } - - // This is intentionally a dummy path. stage1.zig tries to @import("compiler_rt") in case - // of being built by cmake. But when built by zig it's gonna get a compiler_rt so that - // is pointless. - exe.addPackagePath("compiler_rt", "src/empty.zig"); - } if (cmake_cfg) |cfg| { // Inside this code path, we have to coordinate with system packaged LLVM, Clang, and LLD. // That means we also have to rely on stage1 compiled c++ files. We parse config.h to find @@ -379,7 +291,6 @@ pub fn build(b: *Builder) !void { exe_options.addOption(bool, "enable_tracy_callstack", tracy_callstack); exe_options.addOption(bool, "enable_tracy_allocation", tracy_allocation); exe_options.addOption(bool, "value_tracing", value_tracing); - exe_options.addOption(bool, "have_stage1", have_stage1); if (tracy) |tracy_path| { const client_cpp = fs.path.join( b.allocator, @@ -414,7 +325,6 @@ pub fn build(b: *Builder) !void { test_cases_options.addOption(bool, "enable_link_snapshots", enable_link_snapshots); test_cases_options.addOption(bool, "skip_non_native", skip_non_native); test_cases_options.addOption(bool, "skip_stage1", skip_stage1); - test_cases_options.addOption(bool, "have_stage1", have_stage1); test_cases_options.addOption(bool, "have_llvm", enable_llvm); test_cases_options.addOption(bool, "llvm_has_m68k", llvm_has_m68k); test_cases_options.addOption(bool, "llvm_has_csky", llvm_has_csky); @@ -429,7 +339,7 @@ pub fn build(b: *Builder) !void { test_cases_options.addOption(u32, "mem_leak_frames", mem_leak_frames * 2); test_cases_options.addOption(bool, "value_tracing", value_tracing); test_cases_options.addOption(?[]const u8, "glibc_runtimes_dir", b.glibc_runtimes_dir); - test_cases_options.addOption([:0]const u8, "version", try b.allocator.dupeZ(u8, version)); + test_cases_options.addOption([:0]const u8, "version", version); test_cases_options.addOption(std.SemanticVersion, "semver", semver); test_cases_options.addOption(?[]const u8, "test_filter", test_filter); @@ -547,6 +457,61 @@ pub fn build(b: *Builder) !void { skip_stage1, true, // TODO get these all passing )); + + try addWasiUpdateStep(b, version); +} + +fn addWasiUpdateStep(b: *Builder, version: [:0]const u8) !void { + const semver = try std.SemanticVersion.parse(version); + + var target: std.zig.CrossTarget = .{ + .cpu_arch = .wasm32, + .os_tag = .wasi, + }; + target.cpu_features_add.addFeature(@enumToInt(std.Target.wasm.Feature.bulk_memory)); + + const exe = addCompilerStep(b); + exe.setBuildMode(.ReleaseSmall); + exe.setTarget(target); + + const exe_options = b.addOptions(); + exe.addOptions("build_options", exe_options); + + exe_options.addOption(u32, "mem_leak_frames", 0); + exe_options.addOption(bool, "have_llvm", false); + exe_options.addOption(bool, "force_gpa", false); + exe_options.addOption(bool, "only_c", true); + exe_options.addOption([:0]const u8, "version", version); + exe_options.addOption(std.SemanticVersion, "semver", semver); + exe_options.addOption(bool, "enable_logging", false); + exe_options.addOption(bool, "enable_link_snapshots", false); + exe_options.addOption(bool, "enable_tracy", false); + exe_options.addOption(bool, "enable_tracy_callstack", false); + exe_options.addOption(bool, "enable_tracy_allocation", false); + exe_options.addOption(bool, "value_tracing", false); + + const run_opt = b.addSystemCommand(&.{ "wasm-opt", "-Oz", "--enable-bulk-memory" }); + run_opt.addArtifactArg(exe); + run_opt.addArg("-o"); + run_opt.addFileSourceArg(.{ .path = "stage1/zig1.wasm" }); + + const run_zstd = b.addSystemCommand(&.{ "zstd", "-19", "-f" }); + run_zstd.step.dependOn(&run_opt.step); + run_zstd.addFileSourceArg(.{ .path = "stage1/zig1.wasm" }); + run_zstd.addArg("-o"); + run_zstd.addFileSourceArg(.{ .path = "stage1/zig1.wasm.zst" }); + + const cleanup = b.addRemoveDirTree("stage1/zig1.wasm"); + cleanup.step.dependOn(&run_zstd.step); + + const update_zig1_step = b.step("update-zig1", "Update stage1/zig1.wasm.zst"); + update_zig1_step.dependOn(&cleanup.step); +} + +fn addCompilerStep(b: *Builder) *std.build.LibExeObjStep { + const exe = b.addExecutable("zig", "src/main.zig"); + exe.stack_size = stack_size; + return exe; } const exe_cflags = [_][]const u8{ @@ -1010,31 +975,6 @@ const softfloat_sources = [_][]const u8{ "deps/SoftFloat-3e/source/ui64_to_extF80M.c", }; -const stage1_sources = [_][]const u8{ - "src/stage1/analyze.cpp", - "src/stage1/astgen.cpp", - "src/stage1/bigfloat.cpp", - "src/stage1/bigint.cpp", - "src/stage1/buffer.cpp", - "src/stage1/codegen.cpp", - "src/stage1/errmsg.cpp", - "src/stage1/error.cpp", - "src/stage1/heap.cpp", - "src/stage1/ir.cpp", - "src/stage1/ir_print.cpp", - "src/stage1/mem.cpp", - "src/stage1/os.cpp", - "src/stage1/parser.cpp", - "src/stage1/range_set.cpp", - "src/stage1/stage1.cpp", - "src/stage1/target.cpp", - "src/stage1/tokenizer.cpp", - "src/stage1/util.cpp", - "src/stage1/softfloat_ext.cpp", -}; -const optimized_c_sources = [_][]const u8{ - "src/stage1/parse_f128.c", -}; const zig_cpp_sources = [_][]const u8{ // These are planned to stay even when we are self-hosted. "src/zig_llvm.cpp", diff --git a/ci/aarch64-linux-debug.sh b/ci/aarch64-linux-debug.sh index b49c47967c98..05cdcdd0787a 100644 --- a/ci/aarch64-linux-debug.sh +++ b/ci/aarch64-linux-debug.sh @@ -8,7 +8,7 @@ set -e ARCH="$(uname -m)" TARGET="$ARCH-linux-musl" MCPU="baseline" -CACHE_BASENAME="zig+llvm+lld+clang-$TARGET-0.11.0-dev.448+e6e459e9e" +CACHE_BASENAME="zig+llvm+lld+clang-$TARGET-0.11.0-dev.534+b0b1cc356" PREFIX="$HOME/deps/$CACHE_BASENAME" ZIG="$PREFIX/bin/zig" diff --git a/ci/aarch64-linux-release.sh b/ci/aarch64-linux-release.sh index 394361269d77..b74ce134501a 100644 --- a/ci/aarch64-linux-release.sh +++ b/ci/aarch64-linux-release.sh @@ -8,7 +8,7 @@ set -e ARCH="$(uname -m)" TARGET="$ARCH-linux-musl" MCPU="baseline" -CACHE_BASENAME="zig+llvm+lld+clang-$TARGET-0.11.0-dev.448+e6e459e9e" +CACHE_BASENAME="zig+llvm+lld+clang-$TARGET-0.11.0-dev.534+b0b1cc356" PREFIX="$HOME/deps/$CACHE_BASENAME" ZIG="$PREFIX/bin/zig" diff --git a/ci/aarch64-macos.sh b/ci/aarch64-macos.sh index c520dbbec237..337c2bfa8e70 100755 --- a/ci/aarch64-macos.sh +++ b/ci/aarch64-macos.sh @@ -9,7 +9,7 @@ set -e ZIGDIR="$(pwd)" TARGET="$ARCH-macos-none" MCPU="baseline" -CACHE_BASENAME="zig+llvm+lld+clang-$TARGET-0.11.0-dev.448+e6e459e9e" +CACHE_BASENAME="zig+llvm+lld+clang-$TARGET-0.11.0-dev.534+b0b1cc356-1" PREFIX="$HOME/$CACHE_BASENAME" ZIG="$PREFIX/bin/zig" diff --git a/ci/x86_64-linux-release.sh b/ci/x86_64-linux-release.sh index b1b5cc380d50..c87a3cb32b0f 100755 --- a/ci/x86_64-linux-release.sh +++ b/ci/x86_64-linux-release.sh @@ -75,7 +75,6 @@ stage3-release/bin/zig test ../lib/std/std.zig -femit-docs -fno-emit-bin --zig-l stage3-release/bin/zig build \ --prefix stage4-release \ -Denable-llvm \ - -Denable-stage1 \ -Dno-lib \ -Drelease \ -Dstrip \ diff --git a/ci/x86_64-macos.sh b/ci/x86_64-macos.sh index 15769e31dd16..f09121ccd0d1 100755 --- a/ci/x86_64-macos.sh +++ b/ci/x86_64-macos.sh @@ -9,7 +9,7 @@ set -e ZIGDIR="$(pwd)" TARGET="$ARCH-macos-none" MCPU="baseline" -CACHE_BASENAME="zig+llvm+lld+clang-$TARGET-0.11.0-dev.448+e6e459e9e" +CACHE_BASENAME="zig+llvm+lld+clang-$TARGET-0.11.0-dev.534+b0b1cc356" PREFIX="$HOME/$CACHE_BASENAME" JOBS="-j3" diff --git a/ci/x86_64-windows.ps1 b/ci/x86_64-windows.ps1 index 85195a85c3b8..c5907b47b249 100644 --- a/ci/x86_64-windows.ps1 +++ b/ci/x86_64-windows.ps1 @@ -8,13 +8,13 @@ Invoke-WebRequest -Uri "$ZIG_LLVM_CLANG_LLD_URL" -OutFile "$ZIG_LLVM_CLANG_LLD_N Write-Output "Extracting..." -Add-Type -AssemblyName System.IO.Compression.FileSystem ; +Add-Type -AssemblyName System.IO.Compression.FileSystem ; [System.IO.Compression.ZipFile]::ExtractToDirectory("$PWD/$ZIG_LLVM_CLANG_LLD_NAME.zip", "$PWD") Set-Variable -Name ZIGLIBDIR -Value "$(Get-Location)\lib" Set-Variable -Name ZIGINSTALLDIR -Value "$(Get-Location)\stage3-release" Set-Variable -Name ZIGPREFIXPATH -Value "$(Get-Location)\$ZIG_LLVM_CLANG_LLD_NAME" - + function CheckLastExitCode { if (!$?) { exit 1 @@ -37,7 +37,6 @@ Write-Output "Building Zig..." --prefix "$ZIGINSTALLDIR" ` --search-prefix "$ZIGPREFIXPATH" ` --zig-lib-dir "$ZIGLIBDIR" ` - -Denable-stage1 ` -Dstatic-llvm ` -Drelease ` -Duse-zig-libcxx ` diff --git a/deps/SoftFloat-3e-prebuilt/platform.h b/deps/SoftFloat-3e-prebuilt/platform.h deleted file mode 100644 index 2c4a0ec88ec3..000000000000 --- a/deps/SoftFloat-3e-prebuilt/platform.h +++ /dev/null @@ -1,99 +0,0 @@ -#ifndef ZIG_DEP_SOFTFLOAT_PLATFORM_H -#define ZIG_DEP_SOFTFLOAT_PLATFORM_H - -#if defined(__BIG_ENDIAN__) -#define BIGENDIAN 1 -#elif defined(_BIG_ENDIAN) && (_BIG_ENDIAN == 1) -#define BIGENDIAN 1 -#elif defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) -#define BIGENDIAN 1 -#elif defined(__ARMEB__) -#define BIGENDIAN 1 -#elif defined(__THUMBEB__) -#define BIGENDIAN 1 -#elif defined(__AARCH64EB__) -#define BIGENDIAN 1 -#elif defined(_MIPSEB) -#define BIGENDIAN 1 -#elif defined(__MIPSEB) -#define BIGENDIAN 1 -#elif defined(__MIPSEB__) -#define BIGENDIAN 1 -#elif defined(__sparc) -#define BIGENDIAN 1 -#elif defined(__sparc__) -#define BIGENDIAN 1 -#elif defined(_POWER) -#define BIGENDIAN 1 -#elif defined(__hpux) -#define BIGENDIAN 1 -#elif defined(__hppa) -#define BIGENDIAN 1 -#elif defined(_POWER) -#define BIGENDIAN 1 -#elif defined(__s390__) -#define BIGENDIAN 1 -#endif - -#if defined(__LITTLE_ENDIAN__) -#define LITTLEENDIAN 1 -#elif defined(_LITTLE_ENDIAN) && (_LITTLE_ENDIAN == 1) -#define LITTLEENDIAN 1 -#elif defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) -#define LITTLEENDIAN 1 -#elif defined(__ARMEL__) -#define LITTLEENDIAN 1 -#elif defined(__THUMBEL__) -#define LITTLEENDIAN 1 -#elif defined(__AARCH64EL__) -#define LITTLEENDIAN 1 -#elif defined(_MIPSEL) -#define LITTLEENDIAN 1 -#elif defined(__MIPSEL) -#define LITTLEENDIAN 1 -#elif defined(__MIPSEL__) -#define LITTLEENDIAN 1 -#elif defined(__i386__) -#define LITTLEENDIAN 1 -#elif defined(__alpha__) -#define LITTLEENDIAN 1 -#elif defined(__ia64) -#define LITTLEENDIAN 1 -#elif defined(__ia64__) -#define LITTLEENDIAN 1 -#elif defined(_M_IX86) -#define LITTLEENDIAN 1 -#elif defined(_M_IA64) -#define LITTLEENDIAN 1 -#elif defined(_M_ALPHA) -#define LITTLEENDIAN 1 -#elif defined(__amd64) -#define LITTLEENDIAN 1 -#elif defined(__amd64__) -#define LITTLEENDIAN 1 -#elif defined(_M_AMD64) -#define LITTLEENDIAN 1 -#elif defined(__x86_64) -#define LITTLEENDIAN 1 -#elif defined(__x86_64__) -#define LITTLEENDIAN 1 -#elif defined(_M_X64) -#define LITTLEENDIAN 1 -#elif defined(__bfin__) -#define LITTLEENDIAN 1 -#endif - -#if defined(LITTLEENDIAN) && defined(BIGENDIAN) -#error unable to detect endianness -#elif !defined(LITTLEENDIAN) && !defined(BIGENDIAN) -#error unable to detect endianness -#endif - -#define INLINE inline -#if _MSC_VER -#define THREAD_LOCAL __declspec(thread) -#else -#define THREAD_LOCAL __thread -#endif - -#endif diff --git a/deps/SoftFloat-3e/COPYING.txt b/deps/SoftFloat-3e/COPYING.txt deleted file mode 100644 index b5690face082..000000000000 --- a/deps/SoftFloat-3e/COPYING.txt +++ /dev/null @@ -1,37 +0,0 @@ - -License for Berkeley SoftFloat Release 3e - -John R. Hauser -2018 January 20 - -The following applies to the whole of SoftFloat Release 3e as well as to -each source file individually. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the -University of California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions, and the following disclaimer in the - documentation and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors - may be used to endorse or promote products derived from this software - without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF -THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - diff --git a/deps/SoftFloat-3e/README.html b/deps/SoftFloat-3e/README.html deleted file mode 100644 index 7989e0c2602e..000000000000 --- a/deps/SoftFloat-3e/README.html +++ /dev/null @@ -1,49 +0,0 @@ - - - - -Berkeley SoftFloat Package Overview - - - - -

Package Overview for Berkeley SoftFloat Release 3e

- -

-John R. Hauser
-2018 January 20
-

- -

-Berkeley SoftFloat is a software implementation of binary floating-point that -conforms to the IEEE Standard for Floating-Point Arithmetic. -SoftFloat is distributed in the form of C source code. -Building the SoftFloat sources generates a library file (typically -softfloat.a or libsoftfloat.a) containing the -floating-point subroutines. -

- -

-The SoftFloat package is documented in the following files in the -doc subdirectory: -

- - - - - - - - - - - - - -
SoftFloat.htmlDocumentation for using the SoftFloat functions.
SoftFloat-source.htmlDocumentation for building SoftFloat.
SoftFloat-history.html   History of the major changes to SoftFloat.
-
-Other files in the package comprise the source code for SoftFloat. -

- - - diff --git a/deps/SoftFloat-3e/README.txt b/deps/SoftFloat-3e/README.txt deleted file mode 100644 index 1613c7671800..000000000000 --- a/deps/SoftFloat-3e/README.txt +++ /dev/null @@ -1,21 +0,0 @@ - -Package Overview for Berkeley SoftFloat Release 3e - -John R. Hauser -2018 January 20 - -Berkeley SoftFloat is a software implementation of binary floating-point -that conforms to the IEEE Standard for Floating-Point Arithmetic. SoftFloat -is distributed in the form of C source code. Building the SoftFloat sources -generates a library file (typically "softfloat.a" or "libsoftfloat.a") -containing the floating-point subroutines. - -The SoftFloat package is documented in the following files in the "doc" -subdirectory: - - SoftFloat.html Documentation for using the SoftFloat functions. - SoftFloat-source.html Documentation for building SoftFloat. - SoftFloat-history.html History of the major changes to SoftFloat. - -Other files in the package comprise the source code for SoftFloat. - diff --git a/deps/SoftFloat-3e/doc/SoftFloat-history.html b/deps/SoftFloat-3e/doc/SoftFloat-history.html deleted file mode 100644 index daa48ca3b374..000000000000 --- a/deps/SoftFloat-3e/doc/SoftFloat-history.html +++ /dev/null @@ -1,258 +0,0 @@ - - - - -Berkeley SoftFloat History - - - - -

History of Berkeley SoftFloat, to Release 3e

- -

-John R. Hauser
-2018 January 20
-

- - -

Release 3e (2018 January)

- - - - -

Release 3d (2017 August)

- - - - -

Release 3c (2017 February)

- - - - -

Release 3b (2016 July)

- - - - -

Release 3a (2015 October)

- - - - -

Release 3 (2015 February)

- - - - -

Release 2c (2015 January)

- - - - -

Release 2b (2002 May)

- - - - -

Release 2a (1998 December)

- - - - -

Release 2 (1997 June)

- - - - -

Release 1a (1996 July)

- - - - -

Release 1 (1996 July)

- - - - - - diff --git a/deps/SoftFloat-3e/doc/SoftFloat-source.html b/deps/SoftFloat-3e/doc/SoftFloat-source.html deleted file mode 100644 index d4b85f7b092f..000000000000 --- a/deps/SoftFloat-3e/doc/SoftFloat-source.html +++ /dev/null @@ -1,686 +0,0 @@ - - - - -Berkeley SoftFloat Source Documentation - - - - -

Berkeley SoftFloat Release 3e: Source Documentation

- -

-John R. Hauser
-2018 January 20
-

- - -

Contents

- -
- --- - - - - - - - - - - - - - - - - - - - -
1. Introduction
2. Limitations
3. Acknowledgments and License
4. SoftFloat Package Directory Structure
5. Issues for Porting SoftFloat to a New Target
5.1. Standard Headers <stdbool.h> and - <stdint.h>
5.2. Specializing Floating-Point Behavior
5.3. Macros for Build Options
5.4. Adapting a Template Target Directory
5.5. Target-Specific Optimization of Primitive Functions
6. Testing SoftFloat
7. Providing SoftFloat as a Common Library for Applications
8. Contact Information
-
- - -

1. Introduction

- -

-This document gives information needed for compiling and/or porting Berkeley -SoftFloat, a library of C functions implementing binary floating-point -conforming to the IEEE Standard for Floating-Point Arithmetic. -For basic documentation about SoftFloat refer to -SoftFloat.html. -

- -

-The source code for SoftFloat is intended to be relatively machine-independent -and should be compilable with any ISO-Standard C compiler that also supports -64-bit integers. -SoftFloat has been successfully compiled with the GNU C Compiler -(gcc) for several platforms. -

- -

-Release 3 of SoftFloat was a complete rewrite relative to -Release 2 or earlier. -Changes to the interface of SoftFloat functions are documented in -SoftFloat.html. -The current version of SoftFloat is Release 3e. -

- - -

2. Limitations

- -

-SoftFloat assumes the computer has an addressable byte size of either 8 or -16 bits. -(Nearly all computers in use today have 8-bit bytes.) -

- -

-SoftFloat is written in C and is designed to work with other C code. -The C compiler used must conform at a minimum to the 1989 ANSI standard for the -C language (same as the 1990 ISO standard) and must in addition support basic -arithmetic on 64-bit integers. -Earlier releases of SoftFloat included implementations of 32-bit -single-precision and 64-bit double-precision floating-point that -did not require 64-bit integers, but this option is not supported -starting with Release 3. -Since 1999, ISO standards for C have mandated compiler support for -64-bit integers. -A compiler conforming to the 1999 C Standard or later is recommended but not -strictly required. -

- -

-C Standard header files <stdbool.h> and -<stdint.h> are required for defining standard Boolean and -integer types. -If these headers are not supplied with the C compiler, minimal substitutes must -be provided. -SoftFloat’s dependence on these headers is detailed later in -section 5.1, Standard Headers <stdbool.h> -and <stdint.h>. -

- - -

3. Acknowledgments and License

- -

-The SoftFloat package was written by me, John R. Hauser. -Release 3 of SoftFloat was a completely new implementation -supplanting earlier releases. -The project to create Release 3 (now through 3e) was -done in the employ of the University of California, Berkeley, within the -Department of Electrical Engineering and Computer Sciences, first for the -Parallel Computing Laboratory (Par Lab) and then for the ASPIRE Lab. -The work was officially overseen by Prof. Krste Asanovic, with funding provided -by these sources: -

- ---- - - - - - - - - - -
Par Lab: -Microsoft (Award #024263), Intel (Award #024894), and U.C. Discovery -(Award #DIG07-10227), with additional support from Par Lab affiliates Nokia, -NVIDIA, Oracle, and Samsung. -
ASPIRE Lab: -DARPA PERFECT program (Award #HR0011-12-2-0016), with additional support from -ASPIRE industrial sponsor Intel and ASPIRE affiliates Google, Nokia, NVIDIA, -Oracle, and Samsung. -
-
-

- -

-The following applies to the whole of SoftFloat Release 3e as well -as to each source file individually. -

- -

-Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the -University of California. -All rights reserved. -

- -

-Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: -

    - -
  1. -

    -Redistributions of source code must retain the above copyright notice, this -list of conditions, and the following disclaimer. -

    - -
  2. -

    -Redistributions in binary form must reproduce the above copyright notice, this -list of conditions, and the following disclaimer in the documentation and/or -other materials provided with the distribution. -

    - -
  3. -

    -Neither the name of the University nor the names of its contributors may be -used to endorse or promote products derived from this software without specific -prior written permission. -

    - -
-

- -

-THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS “AS IS”, -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. -IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, -INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE -OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF -ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -

- - -

4. SoftFloat Package Directory Structure

- -

-Because SoftFloat is targeted to multiple platforms, its source code is -slightly scattered between target-specific and target-independent directories -and files. -The supplied directory structure is as follows: -

-
-doc
-source
-    include
-    8086
-    8086-SSE
-    ARM-VFPv2
-    ARM-VFPv2-defaultNaN
-build
-    template-FAST_INT64
-    template-not-FAST_INT64
-    Linux-386-GCC
-    Linux-386-SSE2-GCC
-    Linux-x86_64-GCC
-    Linux-ARM-VFPv2-GCC
-    Win32-MinGW
-    Win32-SSE2-MinGW
-    Win64-MinGW-w64
-
-
-The majority of the SoftFloat sources are provided in the source -directory. -The include subdirectory contains several header files -(unsurprisingly), while the other subdirectories of source contain -source files that specialize the floating-point behavior to match particular -processor families: -
-
-
8086
-
-Intel’s older, 8087-derived floating-point, extended to all supported -floating-point types -
-
8086-SSE
-
-Intel’s x86 processors with Streaming SIMD Extensions (SSE) and later -compatible extensions, having 8087 behavior for 80-bit -double-extended-precision (extFloat80_t) and SSE behavior for -other floating-point types -
-
ARM-VFPv2
-
-ARM’s VFPv2 or later floating-point, with NaN payload propagation -
-
ARM-VFPv2-defaultNaN
-
-ARM’s VFPv2 or later floating-point, with the “default NaN” -option -
-
-
-If other specializations are attempted, these would be expected to be other -subdirectories of source alongside the ones listed above. -Specialization is covered later, in section 5.2, Specializing -Floating-Point Behavior. -

- -

-The build directory is intended to contain a subdirectory for each -target platform for which a build of the SoftFloat library may be created. -For each build target, the target’s subdirectory is where all derived -object files and the completed SoftFloat library (typically -softfloat.a or libsoftfloat.a) are created. -The two template subdirectories are not actual build targets but -contain sample files for creating new target directories. -(The meaning of FAST_INT64 will be explained later.) -

- -

-Ignoring the template directories, the supplied target directories -are intended to follow a naming system of -<execution-environment>-<compiler>. -For the example targets, -<execution-environment> is -Linux-386, Linux-386-SSE2, -Linux-x86_64, -Linux-ARM-VFPv2, Win32, -Win32-SSE2, or Win64, and -<compiler> is GCC, -MinGW, or MinGW-w64. -

- -

-All of the supplied target directories are merely examples that may or may not -be correct for compiling on any particular system. -Despite requests, there are currently no plans to include and maintain in the -SoftFloat package the build files needed for a great many users’ -compilation environments, which can span a huge range of operating systems, -compilers, and other tools. -

- -

-As supplied, each target directory contains two files: -

-
-Makefile
-platform.h
-
-
-The provided Makefile is written for GNU make. -A build of SoftFloat for the specific target is begun by executing the -make command with the target directory as the current directory. -A completely different build tool can be used if an appropriate -Makefile equivalent is created. -

- -

-The platform.h header file exists to provide a location for -additional C declarations specific to the build target. -Every C source file of SoftFloat contains a #include for -platform.h. -In many cases, the contents of platform.h can be as simple as one -or two lines of code. -At the other extreme, to get maximal performance from SoftFloat, it may be -desirable to include in header platform.h (directly or via -#include) declarations for numerous target-specific optimizations. -Such possibilities are discussed in the next section, Issues for Porting -SoftFloat to a New Target. -If the target’s compiler or library has bugs or other shortcomings, -workarounds for these issues may also be possible with target-specific -declarations in platform.h, avoiding the need to modify the main -SoftFloat sources. -

- - -

5. Issues for Porting SoftFloat to a New Target

- -

5.1. Standard Headers <stdbool.h> and <stdint.h>

- -

-The SoftFloat sources make use of standard headers -<stdbool.h> and <stdint.h>, which have -been part of the ISO C Standard Library since 1999. -With any recent compiler, these standard headers are likely to be supported, -even if the compiler does not claim complete conformance to the latest ISO C -Standard. -For older or nonstandard compilers, substitutes for -<stdbool.h> and <stdint.h> may need to be -created. -SoftFloat depends on these names from <stdbool.h>: -

-
-bool
-true
-false
-
-
-and on these names from <stdint.h>: -
-
-uint16_t
-uint32_t
-uint64_t
-int32_t
-int64_t
-UINT64_C
-INT64_C
-uint_least8_t
-uint_fast8_t
-uint_fast16_t
-uint_fast32_t
-uint_fast64_t
-int_fast8_t
-int_fast16_t
-int_fast32_t
-int_fast64_t
-
-
-

- - -

5.2. Specializing Floating-Point Behavior

- -

-The IEEE Floating-Point Standard allows for some flexibility in a conforming -implementation, particularly concerning NaNs. -The SoftFloat source directory is supplied with some -specialization subdirectories containing possible definitions for this -implementation-specific behavior. -For example, the 8086 and 8086-SSE -subdirectories have source files that specialize SoftFloat’s behavior to -match that of Intel’s x86 line of processors. -The files in a specialization subdirectory must determine: -

-

- -

-As provided, the build process for a target expects to involve exactly -one specialization directory that defines all of these -implementation-specific details for the target. -A specialization directory such as 8086 is expected to contain a -header file called specialize.h, together with whatever other -source files are needed to complete the specialization. -

- -

-A new build target may use an existing specialization, such as the ones -provided by the 8086 and 8086-SSE -subdirectories. -If a build target needs a new specialization, different from any existing ones, -it is recommended that a new specialization directory be created for this -purpose. -The specialize.h header file from any of the provided -specialization subdirectories can be used as a model for what definitions are -needed. -

- - -

5.3. Macros for Build Options

- -

-The SoftFloat source files adapt the floating-point implementation according to -several C preprocessor macros: -

-
-
LITTLEENDIAN -
-Must be defined for little-endian machines; must not be defined for big-endian -machines. -
INLINE -
-Specifies the sequence of tokens used to indicate that a C function should be -inlined. -If macro INLINE_LEVEL is defined with a value of 1 or higher, this -macro must be defined; otherwise, this macro is ignored and need not be -defined. -For compilers that conform to the C Standard’s rules for inline -functions, this macro can be defined as the single keyword inline. -For other compilers that follow a convention pre-dating the standardization of -inline, this macro may need to be defined to extern -inline. -
THREAD_LOCAL -
-Can be defined to a sequence of tokens that, when appearing at the start of a -variable declaration, indicates to the C compiler that the variable is -per-thread, meaning that each execution thread gets its own separate -instance of the variable. -This macro is used in header softfloat.h in the declarations of -variables softfloat_roundingMode, -softfloat_detectTininess, extF80_roundingPrecision, -and softfloat_exceptionFlags. -If macro THREAD_LOCAL is left undefined, these variables will -default to being ordinary global variables. -Depending on the compiler, possible valid definitions of this macro include -_Thread_local and __thread. -
-
-
SOFTFLOAT_ROUND_ODD -
-Can be defined to enable support for optional rounding mode -softfloat_round_odd. -
-
-
INLINE_LEVEL -
-Can be defined to an integer to determine the degree of inlining requested of -the compiler. -Larger numbers request that more inlining be done. -If this macro is not defined or is defined to a value less than 1 -(zero or negative), no inlining is requested. -The maximum effective value is no higher than 5. -Defining this macro to a value greater than 5 is the same as defining it -to 5. -
SOFTFLOAT_FAST_INT64 -
-Can be defined to indicate that the build target’s implementation of -64-bit arithmetic is efficient. -For newer 64-bit processors, this macro should usually be defined. -For very small microprocessors whose buses and registers are 8-bit -or 16-bit in size, this macro should usually not be defined. -Whether this macro should be defined for a 32-bit processor may -depend on the target machine and the applications that will use SoftFloat. -
SOFTFLOAT_FAST_DIV32TO16 -
-Can be defined to indicate that the target’s division operator -in C (written as /) is reasonably efficient for -dividing a 32-bit unsigned integer by a 16-bit -unsigned integer. -Setting this macro may affect the performance of function f16_div. -
SOFTFLOAT_FAST_DIV64TO32 -
-Can be defined to indicate that the target’s division operator -in C (written as /) is reasonably efficient for -dividing a 64-bit unsigned integer by a 32-bit -unsigned integer. -Setting this macro may affect the performance of division, remainder, and -square root operations other than f16_div. -
-
-

- -

-Following the usual custom for C, for most of these macros (all -except INLINE, THREAD_LOCAL, and -INLINE_LEVEL), the content of any definition is irrelevant; -what matters is a macro’s effect on #ifdef directives. -

- -

-It is recommended that any definitions of macros LITTLEENDIAN, -INLINE, and THREAD_LOCAL be made in a build -target’s platform.h header file, because these macros are -expected to be determined inflexibly by the target machine and compiler. -The other five macros select options and control optimization, and thus might -be better located in the target’s Makefile (or its equivalent). -

- - -

5.4. Adapting a Template Target Directory

- -

-In the build directory, two template subdirectories -provide models for new target directories. -Two different templates exist because different functions are needed in the -SoftFloat library depending on whether macro SOFTFLOAT_FAST_INT64 -is defined. -If macro SOFTFLOAT_FAST_INT64 will be defined, -template-FAST_INT64 is the template to use; -otherwise, template-not-FAST_INT64 is the appropriate -template. -A new target directory can be created by copying the correct template directory -and editing the files inside. -To avoid confusion, it would be wise to refrain from editing the files within a -template directory directly. -

- - -

5.5. Target-Specific Optimization of Primitive Functions

- -

-Header file primitives.h (in directory -source/include) declares macros and functions for numerous -underlying arithmetic operations upon which many of SoftFloat’s -floating-point functions are ultimately built. -The SoftFloat sources include implementations of all of these functions/macros, -written as standard C code, so a complete and correct SoftFloat library can be -created using only the supplied code for all functions. -However, for many targets, SoftFloat’s performance can be improved by -substituting target-specific implementations of some of the functions/macros -declared in primitives.h. -

- -

-For example, primitives.h declares a function called -softfloat_countLeadingZeros32 that takes an unsigned -32-bit integer as an argument and returns the number of the -integer’s most-significant bits that are zeros. -While the SoftFloat sources include an implementation of this function written -in standard C, many processors can perform this same function -directly in only one or two machine instructions. -An alternative, target-specific implementation that maps to those instructions -is likely to be more efficient than the generic C code from the SoftFloat -package. -

- -

-A build target can replace the supplied version of any function or macro of -primitives.h by defining a macro with the same name in the -target’s platform.h header file. -For this purpose, it may be helpful for platform.h to -#include header file primitiveTypes.h, which defines -types used for arguments and results of functions declared in -primitives.h. -When a desired replacement implementation is a function, not a macro, it is -sufficient for platform.h to include the line -

-
-#define <function-name> <function-name>
-
-
-where <function-name> is the name of the -function. -This technically defines <function-name> -as a macro, but one that resolves to the same name, which may then be a -function. -(A preprocessor that conforms to the C Standard is required to limit recursive -macro expansion from being applied more than once.) -

- -

-The supplied header file opts-GCC.h (in directory -source/include) provides an example of target-specific -optimization for the GCC compiler. -Each GCC target example in the build directory has -

-#include "opts-GCC.h" -
-in its platform.h header file. -Before opts-GCC.h is included, the following macros must be -defined (or not) to control which features are invoked: -
-
-
SOFTFLOAT_BUILTIN_CLZ
-
-If defined, SoftFloat’s internal -‘countLeadingZeros’ functions use intrinsics -__builtin_clz and __builtin_clzll. -
-
SOFTFLOAT_INTRINSIC_INT128
-
-If defined, SoftFloat makes use of GCC’s nonstandard 128-bit -integer type __int128. -
-
-
-On some machines, these improvements are observed to increase the speeds of -f64_mul and f128_mul by around 20 to 25%, although -other functions receive less dramatic boosts, or none at all. -Results can vary greatly across different platforms. -

- - -

6. Testing SoftFloat

- -

-SoftFloat can be tested using the testsoftfloat program by the -same author. -This program is part of the Berkeley TestFloat package available at the Web -page -http://www.jhauser.us/arithmetic/TestFloat.html. -The TestFloat package also has a program called timesoftfloat that -measures the speed of SoftFloat’s floating-point functions. -

- - -

7. Providing SoftFloat as a Common Library for Applications

- -

-Header file softfloat.h defines the SoftFloat interface as seen by -clients. -If the SoftFloat library will be made a common library for programs on a -system, the supplied softfloat.h has a couple of deficiencies for -this purpose: -

-In the situation that new programs may regularly #include header -file softfloat.h, it is recommended that a custom, self-contained -version of this header file be created that eliminates these issues. -

- - -

8. Contact Information

- -

-At the time of this writing, the most up-to-date information about SoftFloat -and the latest release can be found at the Web page -http://www.jhauser.us/arithmetic/SoftFloat.html. -

- - - - diff --git a/deps/SoftFloat-3e/doc/SoftFloat.html b/deps/SoftFloat-3e/doc/SoftFloat.html deleted file mode 100644 index bb41770ec521..000000000000 --- a/deps/SoftFloat-3e/doc/SoftFloat.html +++ /dev/null @@ -1,1527 +0,0 @@ - - - - -Berkeley SoftFloat Library Interface - - - - -

Berkeley SoftFloat Release 3e: Library Interface

- -

-John R. Hauser
-2018 January 20
-

- - -

Contents

- -
- --- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1. Introduction
2. Limitations
3. Acknowledgments and License
4. Types and Functions
4.1. Boolean and Integer Types
4.2. Floating-Point Types
4.3. Supported Floating-Point Functions
4.4. Non-canonical Representations in extFloat80_t
4.5. Conventions for Passing Arguments and Results
5. Reserved Names
6. Mode Variables
6.1. Rounding Mode
6.2. Underflow Detection
6.3. Rounding Precision for the 80-Bit Extended Format
7. Exceptions and Exception Flags
8. Function Details
8.1. Conversions from Integer to Floating-Point
8.2. Conversions from Floating-Point to Integer
8.3. Conversions Among Floating-Point Types
8.4. Basic Arithmetic Functions
8.5. Fused Multiply-Add Functions
8.6. Remainder Functions
8.7. Round-to-Integer Functions
8.8. Comparison Functions
8.9. Signaling NaN Test Functions
8.10. Raise-Exception Function
9. Changes from SoftFloat Release 2
9.1. Name Changes
9.2. Changes to Function Arguments
9.3. Added Capabilities
9.4. Better Compatibility with the C Language
9.5. New Organization as a Library
9.6. Optimization Gains (and Losses)
10. Future Directions
11. Contact Information
-
- - -

1. Introduction

- -

-Berkeley SoftFloat is a software implementation of binary floating-point that -conforms to the IEEE Standard for Floating-Point Arithmetic. -The current release supports five binary formats: 16-bit -half-precision, 32-bit single-precision, 64-bit -double-precision, 80-bit double-extended-precision, and -128-bit quadruple-precision. -The following functions are supported for each format: -

-All operations required by the original 1985 version of the IEEE Floating-Point -Standard are implemented, except for conversions to and from decimal. -

- -

-This document gives information about the types defined and the routines -implemented by SoftFloat. -It does not attempt to define or explain the IEEE Floating-Point Standard. -Information about the standard is available elsewhere. -

- -

-The current version of SoftFloat is Release 3e. -This release modifies the behavior of the rarely used odd rounding mode -(round to odd, also known as jamming), and also adds some new -specialization and optimization examples for those compiling SoftFloat. -

- -

-The previous Release 3d fixed bugs that were found in the square -root functions for the 64-bit, 80-bit, and -128-bit floating-point formats. -(Thanks to Alexei Sibidanov at the University of Victoria for reporting an -incorrect result.) -The bugs affected all prior Release-3 versions of SoftFloat -through 3c. -The flaw in the 64-bit floating-point square root function was of -very minor impact, causing a 1-ulp error (1 unit in -the last place) a few times out of a billion. -The bugs in the 80-bit and 128-bit square root -functions were more serious. -Although incorrect results again occurred only a few times out of a billion, -when they did occur a large portion of the less-significant bits could be -wrong. -

- -

-Among earlier releases, 3b was notable for adding support for the -16-bit half-precision format. -For more about the evolution of SoftFloat releases, see -SoftFloat-history.html. -

- -

-The functional interface of SoftFloat Release 3 and later differs -in many details from the releases that came before. -For specifics of these differences, see section 9 below, -Changes from SoftFloat Release 2. -

- - -

2. Limitations

- -

-SoftFloat assumes the computer has an addressable byte size of 8 or -16 bits. -(Nearly all computers in use today have 8-bit bytes.) -

- -

-SoftFloat is written in C and is designed to work with other C code. -The C compiler used must conform at a minimum to the 1989 ANSI standard for the -C language (same as the 1990 ISO standard) and must in addition support basic -arithmetic on 64-bit integers. -Earlier releases of SoftFloat included implementations of 32-bit -single-precision and 64-bit double-precision floating-point that -did not require 64-bit integers, but this option is not supported -starting with Release 3. -Since 1999, ISO standards for C have mandated compiler support for -64-bit integers. -A compiler conforming to the 1999 C Standard or later is recommended but not -strictly required. -

- -

-Most operations not required by the original 1985 version of the IEEE -Floating-Point Standard but added in the 2008 version are not yet supported in -SoftFloat Release 3e. -

- - -

3. Acknowledgments and License

- -

-The SoftFloat package was written by me, John R. Hauser. -Release 3 of SoftFloat was a completely new implementation -supplanting earlier releases. -The project to create Release 3 (now through 3e) was -done in the employ of the University of California, Berkeley, within the -Department of Electrical Engineering and Computer Sciences, first for the -Parallel Computing Laboratory (Par Lab) and then for the ASPIRE Lab. -The work was officially overseen by Prof. Krste Asanovic, with funding provided -by these sources: -

- ---- - - - - - - - - - -
Par Lab: -Microsoft (Award #024263), Intel (Award #024894), and U.C. Discovery -(Award #DIG07-10227), with additional support from Par Lab affiliates Nokia, -NVIDIA, Oracle, and Samsung. -
ASPIRE Lab: -DARPA PERFECT program (Award #HR0011-12-2-0016), with additional support from -ASPIRE industrial sponsor Intel and ASPIRE affiliates Google, Nokia, NVIDIA, -Oracle, and Samsung. -
-
-

- -

-The following applies to the whole of SoftFloat Release 3e as well -as to each source file individually. -

- -

-Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the -University of California. -All rights reserved. -

- -

-Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: -

    - -
  1. -

    -Redistributions of source code must retain the above copyright notice, this -list of conditions, and the following disclaimer. -

    - -
  2. -

    -Redistributions in binary form must reproduce the above copyright notice, this -list of conditions, and the following disclaimer in the documentation and/or -other materials provided with the distribution. -

    - -
  3. -

    -Neither the name of the University nor the names of its contributors may be -used to endorse or promote products derived from this software without specific -prior written permission. -

    - -
-

- -

-THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS “AS IS”, -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. -IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, -INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE -OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF -ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -

- - -

4. Types and Functions

- -

-The types and functions of SoftFloat are declared in header file -softfloat.h. -

- -

4.1. Boolean and Integer Types

- -

-Header file softfloat.h depends on standard headers -<stdbool.h> and <stdint.h> to define type -bool and several integer types. -These standard headers have been part of the ISO C Standard Library since 1999. -With any recent compiler, they are likely to be supported, even if the compiler -does not claim complete conformance to the latest ISO C Standard. -For older or nonstandard compilers, a port of SoftFloat may have substitutes -for these headers. -Header softfloat.h depends only on the name bool from -<stdbool.h> and on these type names from -<stdint.h>: -

-
-uint16_t
-uint32_t
-uint64_t
-int32_t
-int64_t
-uint_fast8_t
-uint_fast32_t
-uint_fast64_t
-int_fast32_t
-int_fast64_t
-
-
-

- - -

4.2. Floating-Point Types

- -

-The softfloat.h header defines five floating-point types: -

- - - - - - - - - - - - - - - - - - - - - -
float16_t16-bit half-precision binary format
float32_t32-bit single-precision binary format
float64_t64-bit double-precision binary format
extFloat80_t   80-bit double-extended-precision binary format (old Intel or -Motorola format)
float128_t128-bit quadruple-precision binary format
-
-The non-extended types are each exactly the size specified: -16 bits for float16_t, 32 bits for -float32_t, 64 bits for float64_t, and -128 bits for float128_t. -Aside from these size requirements, the definitions of all these types may -differ for different ports of SoftFloat to specific systems. -A given port of SoftFloat may or may not define some of the floating-point -types as aliases for the C standard types float, -double, and long double. -

- -

-Header file softfloat.h also defines a structure, -struct extFloat80M, for the representation of -80-bit double-extended-precision floating-point values in memory. -This structure is the same size as type extFloat80_t and contains -at least these two fields (not necessarily in this order): -

-
-uint16_t signExp;
-uint64_t signif;
-
-
-Field signExp contains the sign and exponent of the floating-point -value, with the sign in the most significant bit (bit 15) and the -encoded exponent in the other 15 bits. -Field signif is the complete 64-bit significand of -the floating-point value. -(In the usual encoding for 80-bit extended floating-point, the -leading 1 bit of normalized numbers is not implicit but is stored -in the most significant bit of the significand.) -

- -

4.3. Supported Floating-Point Functions

- -

-SoftFloat implements these arithmetic operations for its floating-point types: -

-

- -

-The following operations required by the 2008 IEEE Floating-Point Standard are -not supported in SoftFloat Release 3e: -

-

- -

4.4. Non-canonical Representations in extFloat80_t

- -

-Because the 80-bit double-extended-precision format, -extFloat80_t, stores an explicit leading significand bit, many -finite floating-point numbers are encodable in this type in multiple equivalent -forms. -Of these multiple encodings, there is always a unique one with the least -encoded exponent value, and this encoding is considered the canonical -representation of the floating-point number. -Any other equivalent representations (having a higher encoded exponent value) -are non-canonical. -For a value in the subnormal range (including zero), the canonical -representation always has an encoded exponent of zero and a leading significand -bit of 0. -For finite values outside the subnormal range, the canonical representation -always has an encoded exponent that is nonzero and a leading significand bit -of 1. -

- -

-For an infinity or NaN, the leading significand bit is similarly expected to -be 1. -An infinity or NaN with a leading significand bit of 0 is again -considered non-canonical. -Hence, altogether, to be canonical, a value of type extFloat80_t -must have a leading significand bit of 1, unless the value is -subnormal or zero, in which case the leading significand bit and the encoded -exponent must both be zero. -

- -

-SoftFloat’s functions are not guaranteed to operate as expected when -inputs of type extFloat80_t are non-canonical. -Assuming all of a function’s extFloat80_t inputs (if any) -are canonical, function outputs of type extFloat80_t will always -be canonical. -

- -

4.5. Conventions for Passing Arguments and Results

- -

-Values that are at most 64 bits in size (i.e., not the -80-bit or 128-bit floating-point formats) are in all -cases passed as function arguments by value. -Likewise, when an output of a function is no more than 64 bits, it -is always returned directly as the function result. -Thus, for example, the SoftFloat function for adding two 64-bit -floating-point values has this simple signature: -

-float64_t f64_add( float64_t, float64_t ); -
-

- -

-The story is more complex when function inputs and outputs are -80-bit and 128-bit floating-point. -For these types, SoftFloat always provides a function that passes these larger -values into or out of the function indirectly, via pointers. -For example, for adding two 128-bit floating-point values, -SoftFloat supplies this function: -

-void f128M_add( const float128_t *, const float128_t *, float128_t * ); -
-The first two arguments point to the values to be added, and the last argument -points to the location where the sum will be stored. -The M in the name f128M_add is mnemonic for the fact -that the 128-bit inputs and outputs are “in memory”, -pointed to by pointer arguments. -

- -

-All ports of SoftFloat implement these pass-by-pointer functions for -types extFloat80_t and float128_t. -At the same time, SoftFloat ports may also implement alternate versions of -these same functions that pass extFloat80_t and -float128_t by value, like the smaller formats. -Thus, besides the function with name f128M_add shown above, a -SoftFloat port may also supply an equivalent function with this signature: -

-float128_t f128_add( float128_t, float128_t ); -
-

- -

-As a general rule, on computers where the machine word size is -32 bits or smaller, only the pass-by-pointer versions of functions -(e.g., f128M_add) are provided for types extFloat80_t -and float128_t, because passing such large types directly can have -significant extra cost. -On computers where the word size is 64 bits or larger, both -function versions (f128M_add and f128_add) are -provided, because the cost of passing by value is then more reasonable. -Applications that must be portable accross both classes of computers must use -the pointer-based functions, as these are always implemented. -However, if it is known that SoftFloat includes the by-value functions for all -platforms of interest, programmers can use whichever version they prefer. -

- - -

5. Reserved Names

- -

-In addition to the variables and functions documented here, SoftFloat defines -some symbol names for its own private use. -These private names always begin with the prefix -‘softfloat_’. -When a program includes header softfloat.h or links with the -SoftFloat library, all names with prefix ‘softfloat_’ -are reserved for possible use by SoftFloat. -Applications that use SoftFloat should not define their own names with this -prefix, and should reference only such names as are documented. -

- - -

6. Mode Variables

- -

-The following global variables control rounding mode, underflow detection, and -the 80-bit extended format’s rounding precision: -

-softfloat_roundingMode
-softfloat_detectTininess
-extF80_roundingPrecision -
-These mode variables are covered in the next several subsections. -For some SoftFloat ports, these variables may be per-thread (declared -thread_local), meaning that different execution threads have their -own separate copies of the variables. -

- -

6.1. Rounding Mode

- -

-All five rounding modes defined by the 2008 IEEE Floating-Point Standard are -implemented for all operations that require rounding. -Some ports of SoftFloat may also implement the round-to-odd mode. -

- -

-The rounding mode is selected by the global variable -

-uint_fast8_t softfloat_roundingMode; -
-This variable may be set to one of the values -
- - - - - - - - - - - - - - - - - - - - - - - - - -
softfloat_round_near_evenround to nearest, with ties to even
softfloat_round_near_maxMag  round to nearest, with ties to maximum magnitude (away from zero)
softfloat_round_minMaground to minimum magnitude (toward zero)
softfloat_round_minround to minimum (down)
softfloat_round_maxround to maximum (up)
softfloat_round_oddround to odd (jamming), if supported by the SoftFloat port
-
-Variable softfloat_roundingMode is initialized to -softfloat_round_near_even. -

- -

-When softfloat_round_odd is the rounding mode for a function that -rounds to an integer value (either conversion to an integer format or a -‘roundToInt’ function), if the input is not already an -integer, the rounded result is the closest odd integer. -For other operations, this rounding mode acts as though the floating-point -result is first rounded to minimum magnitude, the same as -softfloat_round_minMag, and then, if the result is inexact, the -least-significant bit of the result is set to 1. -Rounding to odd is also known as jamming. -

- -

6.2. Underflow Detection

- -

-In the terminology of the IEEE Standard, SoftFloat can detect tininess for -underflow either before or after rounding. -The choice is made by the global variable -

-uint_fast8_t softfloat_detectTininess; -
-which can be set to either -
-softfloat_tininess_beforeRounding
-softfloat_tininess_afterRounding -
-Detecting tininess after rounding is usually better because it results in fewer -spurious underflow signals. -The other option is provided for compatibility with some systems. -Like most systems (and as required by the newer 2008 IEEE Standard), SoftFloat -always detects loss of accuracy for underflow as an inexact result. -

- -

6.3. Rounding Precision for the 80-Bit Extended Format

- -

-For extFloat80_t only, the rounding precision of the basic -arithmetic operations is controlled by the global variable -

-uint_fast8_t extF80_roundingPrecision; -
-The operations affected are: -
-extF80_add
-extF80_sub
-extF80_mul
-extF80_div
-extF80_sqrt -
-When extF80_roundingPrecision is set to its default value of 80, -these operations are rounded to the full precision of the 80-bit -double-extended-precision format, like occurs for other formats. -Setting extF80_roundingPrecision to 32 or to 64 causes the -operations listed to be rounded to 32-bit precision (equivalent to -float32_t) or to 64-bit precision (equivalent to -float64_t), respectively. -When rounding to reduced precision, additional bits in the result significand -beyond the rounding point are set to zero. -The consequences of setting extF80_roundingPrecision to a value -other than 32, 64, or 80 is not specified. -Operations other than the ones listed above are not affected by -extF80_roundingPrecision. -

- - -

7. Exceptions and Exception Flags

- -

-All five exception flags required by the IEEE Floating-Point Standard are -implemented. -Each flag is stored as a separate bit in the global variable -

-uint_fast8_t softfloat_exceptionFlags; -
-The positions of the exception flag bits within this variable are determined by -the bit masks -
-softfloat_flag_inexact
-softfloat_flag_underflow
-softfloat_flag_overflow
-softfloat_flag_infinite
-softfloat_flag_invalid -
-Variable softfloat_exceptionFlags is initialized to all zeros, -meaning no exceptions. -

- -

-For some SoftFloat ports, softfloat_exceptionFlags may be -per-thread (declared thread_local), meaning that different -execution threads have their own separate instances of it. -

- -

-An individual exception flag can be cleared with the statement -

-softfloat_exceptionFlags &= ~softfloat_flag_<exception>; -
-where <exception> is the appropriate name. -To raise a floating-point exception, function softfloat_raiseFlags -should normally be used. -

- -

-When SoftFloat detects an exception other than inexact, it calls -softfloat_raiseFlags. -The default version of this function simply raises the corresponding exception -flags. -Particular ports of SoftFloat may support alternate behavior, such as exception -traps, by modifying the default softfloat_raiseFlags. -A program may also supply its own softfloat_raiseFlags function to -override the one from the SoftFloat library. -

- -

-Because inexact results occur frequently under most circumstances (and thus are -hardly exceptional), SoftFloat does not ordinarily call -softfloat_raiseFlags for inexact exceptions. -It does always raise the inexact exception flag as required. -

- - -

8. Function Details

- -

-In this section, <float> appears in function names as -a substitute for one of these abbreviations: -

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
f16indicates float16_t, passed by value
f32indicates float32_t, passed by value
f64indicates float64_t, passed by value
extF80M   indicates extFloat80_t, passed indirectly via pointers
extF80indicates extFloat80_t, passed by value
f128Mindicates float128_t, passed indirectly via pointers
f128indicates float128_t, passed by value
-
-The circumstances under which values of floating-point types -extFloat80_t and float128_t may be passed either by -value or indirectly via pointers was discussed earlier in -section 4.5, Conventions for Passing Arguments and Results. -

- -

8.1. Conversions from Integer to Floating-Point

- -

-All conversions from a 32-bit or 64-bit integer, -signed or unsigned, to a floating-point format are supported. -Functions performing these conversions have these names: -

-ui32_to_<float>
-ui64_to_<float>
-i32_to_<float>
-i64_to_<float> -
-Conversions from 32-bit integers to 64-bit -double-precision and larger formats are always exact, and likewise conversions -from 64-bit integers to 80-bit -double-extended-precision and 128-bit quadruple-precision are also -always exact. -

- -

-Each conversion function takes one input of the appropriate type and generates -one output. -The following illustrates the signatures of these functions in cases when the -floating-point result is passed either by value or via pointers: -

-
-float64_t i32_to_f64( int32_t a );
-
-
-void i32_to_f128M( int32_t a, float128_t *destPtr );
-
-
-

- -

8.2. Conversions from Floating-Point to Integer

- -

-Conversions from a floating-point format to a 32-bit or -64-bit integer, signed or unsigned, are supported with these -functions: -

-<float>_to_ui32
-<float>_to_ui64
-<float>_to_i32
-<float>_to_i64 -
-The functions have signatures as follows, depending on whether the -floating-point input is passed by value or via pointers: -
-
-int_fast32_t f64_to_i32( float64_t a, uint_fast8_t roundingMode, bool exact );
-
-
-int_fast32_t
- f128M_to_i32( const float128_t *aPtr, uint_fast8_t roundingMode, bool exact );
-
-
-

- -

-The roundingMode argument specifies the rounding mode for -the conversion. -The variable that usually indicates rounding mode, -softfloat_roundingMode, is ignored. -Argument exact determines whether the inexact -exception flag is raised if the conversion is not exact. -If exact is true, the inexact flag may -be raised; -otherwise, it will not be, even if the conversion is inexact. -

- -

-A conversion from floating-point to integer format raises the invalid -exception if the source value cannot be rounded to a representable integer of -the desired size (32 or 64 bits). -In such circumstances, the integer result returned is determined by the -particular port of SoftFloat, although typically this value will be either the -maximum or minimum value of the integer format. -The functions that convert to integer types never raise the floating-point -overflow exception. -

- -

-Because languages such as C require that conversions to integers -be rounded toward zero, the following functions are provided for improved speed -and convenience: -

-<float>_to_ui32_r_minMag
-<float>_to_ui64_r_minMag
-<float>_to_i32_r_minMag
-<float>_to_i64_r_minMag -
-These functions round only toward zero (to minimum magnitude). -The signatures for these functions are the same as above without the redundant -roundingMode argument: -
-
-int_fast32_t f64_to_i32_r_minMag( float64_t a, bool exact );
-
-
-int_fast32_t f128M_to_i32_r_minMag( const float128_t *aPtr, bool exact );
-
-
-

- -

8.3. Conversions Among Floating-Point Types

- -

-Conversions between floating-point formats are done by functions with these -names: -

-<float>_to_<float> -
-All combinations of source and result type are supported where the source and -result are different formats. -There are four different styles of signature for these functions, depending on -whether the input and the output floating-point values are passed by value or -via pointers: -
-
-float32_t f64_to_f32( float64_t a );
-
-
-float32_t f128M_to_f32( const float128_t *aPtr );
-
-
-void f32_to_f128M( float32_t a, float128_t *destPtr );
-
-
-void extF80M_to_f128M( const extFloat80_t *aPtr, float128_t *destPtr );
-
-
-

- -

-Conversions from a smaller to a larger floating-point format are always exact -and so require no rounding. -

- -

8.4. Basic Arithmetic Functions

- -

-The following basic arithmetic functions are provided: -

-<float>_add
-<float>_sub
-<float>_mul
-<float>_div
-<float>_sqrt -
-Each floating-point operation takes two operands, except for sqrt -(square root) which takes only one. -The operands and result are all of the same floating-point format. -Signatures for these functions take the following forms: -
-
-float64_t f64_add( float64_t a, float64_t b );
-
-
-void
- f128M_add(
-     const float128_t *aPtr, const float128_t *bPtr, float128_t *destPtr );
-
-
-float64_t f64_sqrt( float64_t a );
-
-
-void f128M_sqrt( const float128_t *aPtr, float128_t *destPtr );
-
-
-When floating-point values are passed indirectly through pointers, arguments -aPtr and bPtr point to the input -operands, and the last argument, destPtr, points to the -location where the result is stored. -

- -

-Rounding of the 80-bit double-extended-precision -(extFloat80_t) functions is affected by variable -extF80_roundingPrecision, as explained earlier in -section 6.3, -Rounding Precision for the 80-Bit Extended Format. -

- -

8.5. Fused Multiply-Add Functions

- -

-The 2008 version of the IEEE Floating-Point Standard defines a fused -multiply-add operation that does a combined multiplication and addition -with only a single rounding. -SoftFloat implements fused multiply-add with functions -

-<float>_mulAdd -
-Unlike other operations, fused multiple-add is not supported for the -80-bit double-extended-precision format, -extFloat80_t. -

- -

-Depending on whether floating-point values are passed by value or via pointers, -the fused multiply-add functions have signatures of these forms: -

-
-float64_t f64_mulAdd( float64_t a, float64_t b, float64_t c );
-
-
-void
- f128M_mulAdd(
-     const float128_t *aPtr,
-     const float128_t *bPtr,
-     const float128_t *cPtr,
-     float128_t *destPtr
- );
-
-
-The functions compute -(a × b) - + c -with a single rounding. -When floating-point values are passed indirectly through pointers, arguments -aPtr, bPtr, and -cPtr point to operands a, -b, and c respectively, and -destPtr points to the location where the result is stored. -

- -

-If one of the multiplication operands a and -b is infinite and the other is zero, these functions raise -the invalid exception even if operand c is a quiet NaN. -

- -

8.6. Remainder Functions

- -

-For each format, SoftFloat implements the remainder operation defined by the -IEEE Floating-Point Standard. -The remainder functions have names -

-<float>_rem -
-Each remainder operation takes two floating-point operands of the same format -and returns a result in the same format. -Depending on whether floating-point values are passed by value or via pointers, -the remainder functions have signatures of these forms: -
-
-float64_t f64_rem( float64_t a, float64_t b );
-
-
-void
- f128M_rem(
-     const float128_t *aPtr, const float128_t *bPtr, float128_t *destPtr );
-
-
-When floating-point values are passed indirectly through pointers, arguments -aPtr and bPtr point to operands -a and b respectively, and -destPtr points to the location where the result is stored. -

- -

-The IEEE Standard remainder operation computes the value -a - − n × b, -where n is the integer closest to -a ÷ b. -If a ÷ b is exactly -halfway between two integers, n is the even integer closest to -a ÷ b. -The IEEE Standard’s remainder operation is always exact and so requires -no rounding. -

- -

-Depending on the relative magnitudes of the operands, the remainder -functions can take considerably longer to execute than the other SoftFloat -functions. -This is an inherent characteristic of the remainder operation itself and is not -a flaw in the SoftFloat implementation. -

- -

8.7. Round-to-Integer Functions

- -

-For each format, SoftFloat implements the round-to-integer operation specified -by the IEEE Floating-Point Standard. -These functions are named -

-<float>_roundToInt -
-Each round-to-integer operation takes a single floating-point operand. -This operand is rounded to an integer according to a specified rounding mode, -and the resulting integer value is returned in the same floating-point format. -(Note that the result is not an integer type.) -

- -

-The signatures of the round-to-integer functions are similar to those for -conversions to an integer type: -

-
-float64_t f64_roundToInt( float64_t a, uint_fast8_t roundingMode, bool exact );
-
-
-void
- f128M_roundToInt(
-     const float128_t *aPtr,
-     uint_fast8_t roundingMode,
-     bool exact,
-     float128_t *destPtr
- );
-
-
-When floating-point values are passed indirectly through pointers, -aPtr points to the input operand and -destPtr points to the location where the result is stored. -

- -

-The roundingMode argument specifies the rounding mode to -apply. -The variable that usually indicates rounding mode, -softfloat_roundingMode, is ignored. -Argument exact determines whether the inexact -exception flag is raised if the conversion is not exact. -If exact is true, the inexact flag may -be raised; -otherwise, it will not be, even if the conversion is inexact. -

- -

8.8. Comparison Functions

- -

-For each format, the following floating-point comparison functions are -provided: -

-<float>_eq
-<float>_le
-<float>_lt -
-Each comparison takes two operands of the same type and returns a Boolean. -The abbreviation eq stands for “equal” (=); -le stands for “less than or equal” (≤); -and lt stands for “less than” (<). -Depending on whether the floating-point operands are passed by value or via -pointers, the comparison functions have signatures of these forms: -
-
-bool f64_eq( float64_t a, float64_t b );
-
-
-bool f128M_eq( const float128_t *aPtr, const float128_t *bPtr );
-
-
-

- -

-The usual greater-than (>), greater-than-or-equal (≥), and not-equal -(≠) comparisons are easily obtained from the functions provided. -The not-equal function is just the logical complement of the equal function. -The greater-than-or-equal function is identical to the less-than-or-equal -function with the arguments in reverse order, and likewise the greater-than -function is identical to the less-than function with the arguments reversed. -

- -

-The IEEE Floating-Point Standard specifies that the less-than-or-equal and -less-than comparisons by default raise the invalid exception if either -operand is any kind of NaN. -Equality comparisons, on the other hand, are defined by default to raise the -invalid exception only for signaling NaNs, not quiet NaNs. -For completeness, SoftFloat provides these complementary functions: -

-<float>_eq_signaling
-<float>_le_quiet
-<float>_lt_quiet -
-The signaling equality comparisons are identical to the default -equality comparisons except that the invalid exception is raised for any -NaN input, not just for signaling NaNs. -Similarly, the quiet comparison functions are identical to their -default counterparts except that the invalid exception is not raised for -quiet NaNs. -

- -

8.9. Signaling NaN Test Functions

- -

-Functions for testing whether a floating-point value is a signaling NaN are -provided with these names: -

-<float>_isSignalingNaN -
-The functions take one floating-point operand and return a Boolean indicating -whether the operand is a signaling NaN. -Accordingly, the functions have the forms -
-
-bool f64_isSignalingNaN( float64_t a );
-
-
-bool f128M_isSignalingNaN( const float128_t *aPtr );
-
-
-

- -

8.10. Raise-Exception Function

- -

-SoftFloat provides a single function for raising floating-point exceptions: -

-
-void softfloat_raiseFlags( uint_fast8_t exceptions );
-
-
-The exceptions argument is a mask indicating the set of -exceptions to raise. -(See earlier section 7, Exceptions and Exception Flags.) -In addition to setting the specified exception flags in variable -softfloat_exceptionFlags, the softfloat_raiseFlags -function may cause a trap or abort appropriate for the current system. -

- - -

9. Changes from SoftFloat Release 2

- -

-Apart from a change in the legal use license, Release 3 of -SoftFloat introduced numerous technical differences compared to earlier -releases. -

- -

9.1. Name Changes

- -

-The most obvious and pervasive difference compared to Release 2 -is that the names of most functions and variables have changed, even when the -behavior has not. -First, the floating-point types, the mode variables, the exception flags -variable, the function to raise exceptions, and various associated constants -have been renamed as follows: -

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
old name, Release 2:new name, Release 3:
float32float32_t
float64float64_t
floatx80extFloat80_t
float128float128_t
float_rounding_modesoftfloat_roundingMode
float_round_nearest_evensoftfloat_round_near_even
float_round_to_zerosoftfloat_round_minMag
float_round_downsoftfloat_round_min
float_round_upsoftfloat_round_max
float_detect_tininesssoftfloat_detectTininess
float_tininess_before_rounding    softfloat_tininess_beforeRounding
float_tininess_after_roundingsoftfloat_tininess_afterRounding
floatx80_rounding_precisionextF80_roundingPrecision
float_exception_flagssoftfloat_exceptionFlags
float_flag_inexactsoftfloat_flag_inexact
float_flag_underflowsoftfloat_flag_underflow
float_flag_overflowsoftfloat_flag_overflow
float_flag_divbyzerosoftfloat_flag_infinite
float_flag_invalidsoftfloat_flag_invalid
float_raisesoftfloat_raiseFlags
-
-

- -

-Furthermore, Release 3 adopted the following new abbreviations for -function names: -

- - - - - - - - - - - -
used in names in Release 2:    used in names in Release 3:
int32 i32
int64 i64
float32 f32
float64 f64
floatx80 extF80
float128 f128
-
-Thus, for example, the function to add two 32-bit floating-point -numbers, previously called float32_add in Release 2, -is now f32_add. -Lastly, there have been a few other changes to function names: -
- - - - - - - - - - - - - - - - - - - - - -
used in names in Release 2:   used in names in Release 3:   relevant functions:
_round_to_zero_r_minMagconversions from floating-point to integer (section 8.2)
round_to_introundToIntround-to-integer functions (section 8.7)
is_signaling_nan    isSignalingNaNsignaling NaN test functions (section 8.9)
-
-

- -

9.2. Changes to Function Arguments

- -

-Besides simple name changes, some operations were given a different interface -in Release 3 than they had in Release 2: -

-

- -

9.3. Added Capabilities

- -

-With Release 3, some new features have been added that were not -present in Release 2: -

-

- -

9.4. Better Compatibility with the C Language

- -

-Release 3 of SoftFloat was written to conform better to the ISO C -Standard’s rules for portability. -For example, older releases of SoftFloat employed type conversions in ways -that, while commonly practiced, are not fully defined by the C Standard. -Such problematic type conversions have generally been replaced by the use of -unions, the behavior around which is more strictly regulated these days. -

- -

9.5. New Organization as a Library

- -

-Starting with Release 3, SoftFloat now builds as a library. -Previously, SoftFloat compiled into a single, monolithic object file containing -all the SoftFloat functions, with the consequence that a program linking with -SoftFloat would get every SoftFloat function in its binary file even if only a -few functions were actually used. -With SoftFloat in the form of a library, a program that is linked by a standard -linker will include only those functions of SoftFloat that it needs and no -others. -

- -

9.6. Optimization Gains (and Losses)

- -

-Individual SoftFloat functions have been variously improved in -Release 3 compared to earlier releases. -In particular, better, faster algorithms have been deployed for the operations -of division, square root, and remainder. -For functions operating on the larger 80-bit and -128-bit formats, extFloat80_t and -float128_t, code size has also generally been reduced. -

- -

-However, because Release 2 compiled all of SoftFloat together as a -single object file, compilers could make optimizations across function calls -when one SoftFloat function calls another. -Now that the functions of SoftFloat are compiled separately and only afterward -linked together into a program, there is not usually the same opportunity to -optimize across function calls. -Some loss of speed has been observed due to this change. -

- - -

10. Future Directions

- -

-The following improvements are anticipated for future releases of SoftFloat: -

-

- - -

11. Contact Information

- -

-At the time of this writing, the most up-to-date information about SoftFloat -and the latest release can be found at the Web page -http://www.jhauser.us/arithmetic/SoftFloat.html. -

- - - - diff --git a/deps/SoftFloat-3e/source/8086-SSE/extF80M_isSignalingNaN.c b/deps/SoftFloat-3e/source/8086-SSE/extF80M_isSignalingNaN.c deleted file mode 100644 index 85ee211c28d7..000000000000 --- a/deps/SoftFloat-3e/source/8086-SSE/extF80M_isSignalingNaN.c +++ /dev/null @@ -1,57 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "softfloat.h" - -/*---------------------------------------------------------------------------- -*----------------------------------------------------------------------------*/ -bool extF80M_isSignalingNaN( const extFloat80_t *aPtr ) -{ - const struct extFloat80M *aSPtr; - uint64_t uiA0; - - aSPtr = (const struct extFloat80M *) aPtr; - if ( (aSPtr->signExp & 0x7FFF) != 0x7FFF ) return false; - uiA0 = aSPtr->signif; - return - ! (uiA0 & UINT64_C( 0x4000000000000000 )) - && (uiA0 & UINT64_C( 0x3FFFFFFFFFFFFFFF)); - -} - diff --git a/deps/SoftFloat-3e/source/8086-SSE/f128M_isSignalingNaN.c b/deps/SoftFloat-3e/source/8086-SSE/f128M_isSignalingNaN.c deleted file mode 100644 index 79a707771672..000000000000 --- a/deps/SoftFloat-3e/source/8086-SSE/f128M_isSignalingNaN.c +++ /dev/null @@ -1,60 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "primitives.h" -#include "softfloat.h" - -/*---------------------------------------------------------------------------- -*----------------------------------------------------------------------------*/ -bool f128M_isSignalingNaN( const float128_t *aPtr ) -{ - const uint32_t *aWPtr; - uint32_t uiA96; - - aWPtr = (const uint32_t *) aPtr; - uiA96 = aWPtr[indexWordHi( 4 )]; - if ( (uiA96 & 0x7FFF8000) != 0x7FFF0000 ) return false; - return - ((uiA96 & 0x00007FFF) != 0) - || ((aWPtr[indexWord( 4, 2 )] | aWPtr[indexWord( 4, 1 )] - | aWPtr[indexWord( 4, 0 )]) - != 0); - -} - diff --git a/deps/SoftFloat-3e/source/8086-SSE/s_commonNaNToExtF80M.c b/deps/SoftFloat-3e/source/8086-SSE/s_commonNaNToExtF80M.c deleted file mode 100644 index 3405b3ba4efb..000000000000 --- a/deps/SoftFloat-3e/source/8086-SSE/s_commonNaNToExtF80M.c +++ /dev/null @@ -1,56 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" - -/*---------------------------------------------------------------------------- -| Converts the common NaN pointed to by `aPtr' into an 80-bit extended -| floating-point NaN, and stores this NaN at the location pointed to by -| `zSPtr'. -*----------------------------------------------------------------------------*/ -void - softfloat_commonNaNToExtF80M( - const struct commonNaN *aPtr, struct extFloat80M *zSPtr ) -{ - - zSPtr->signExp = packToExtF80UI64( aPtr->sign, 0x7FFF ); - zSPtr->signif = UINT64_C( 0xC000000000000000 ) | aPtr->v64>>1; - -} - diff --git a/deps/SoftFloat-3e/source/8086-SSE/s_commonNaNToExtF80UI.c b/deps/SoftFloat-3e/source/8086-SSE/s_commonNaNToExtF80UI.c deleted file mode 100644 index cb7424f430c9..000000000000 --- a/deps/SoftFloat-3e/source/8086-SSE/s_commonNaNToExtF80UI.c +++ /dev/null @@ -1,56 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "primitives.h" -#include "specialize.h" - -/*---------------------------------------------------------------------------- -| Converts the common NaN pointed to by `aPtr' into an 80-bit extended -| floating-point NaN, and returns the bit pattern of this value as an unsigned -| integer. -*----------------------------------------------------------------------------*/ -struct uint128 softfloat_commonNaNToExtF80UI( const struct commonNaN *aPtr ) -{ - struct uint128 uiZ; - - uiZ.v64 = (uint_fast16_t) aPtr->sign<<15 | 0x7FFF; - uiZ.v0 = UINT64_C( 0xC000000000000000 ) | aPtr->v64>>1; - return uiZ; - -} - diff --git a/deps/SoftFloat-3e/source/8086-SSE/s_commonNaNToF128M.c b/deps/SoftFloat-3e/source/8086-SSE/s_commonNaNToF128M.c deleted file mode 100644 index e7ea80258916..000000000000 --- a/deps/SoftFloat-3e/source/8086-SSE/s_commonNaNToF128M.c +++ /dev/null @@ -1,56 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "primitives.h" -#include "specialize.h" - -/*---------------------------------------------------------------------------- -| Converts the common NaN pointed to by `aPtr' into a 128-bit floating-point -| NaN, and stores this NaN at the location pointed to by `zWPtr'. Argument -| `zWPtr' points to an array of four 32-bit elements that concatenate in the -| platform's normal endian order to form a 128-bit floating-point value. -*----------------------------------------------------------------------------*/ -void - softfloat_commonNaNToF128M( const struct commonNaN *aPtr, uint32_t *zWPtr ) -{ - - softfloat_shortShiftRight128M( (const uint32_t *) &aPtr->v0, 16, zWPtr ); - zWPtr[indexWordHi( 4 )] |= (uint32_t) aPtr->sign<<31 | 0x7FFF8000; - -} - diff --git a/deps/SoftFloat-3e/source/8086-SSE/s_commonNaNToF128UI.c b/deps/SoftFloat-3e/source/8086-SSE/s_commonNaNToF128UI.c deleted file mode 100644 index 7a9423bea290..000000000000 --- a/deps/SoftFloat-3e/source/8086-SSE/s_commonNaNToF128UI.c +++ /dev/null @@ -1,55 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "primitives.h" -#include "specialize.h" - -/*---------------------------------------------------------------------------- -| Converts the common NaN pointed to by `aPtr' into a 128-bit floating-point -| NaN, and returns the bit pattern of this value as an unsigned integer. -*----------------------------------------------------------------------------*/ -struct uint128 softfloat_commonNaNToF128UI( const struct commonNaN *aPtr ) -{ - struct uint128 uiZ; - - uiZ = softfloat_shortShiftRight128( aPtr->v64, aPtr->v0, 16 ); - uiZ.v64 |= (uint_fast64_t) aPtr->sign<<63 | UINT64_C( 0x7FFF800000000000 ); - return uiZ; - -} - diff --git a/deps/SoftFloat-3e/source/8086-SSE/s_commonNaNToF16UI.c b/deps/SoftFloat-3e/source/8086-SSE/s_commonNaNToF16UI.c deleted file mode 100644 index d4e458a94143..000000000000 --- a/deps/SoftFloat-3e/source/8086-SSE/s_commonNaNToF16UI.c +++ /dev/null @@ -1,51 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "specialize.h" - -/*---------------------------------------------------------------------------- -| Converts the common NaN pointed to by `aPtr' into a 16-bit floating-point -| NaN, and returns the bit pattern of this value as an unsigned integer. -*----------------------------------------------------------------------------*/ -uint_fast16_t softfloat_commonNaNToF16UI( const struct commonNaN *aPtr ) -{ - - return (uint_fast16_t) aPtr->sign<<15 | 0x7E00 | aPtr->v64>>54; - -} - diff --git a/deps/SoftFloat-3e/source/8086-SSE/s_commonNaNToF32UI.c b/deps/SoftFloat-3e/source/8086-SSE/s_commonNaNToF32UI.c deleted file mode 100644 index ed6c2268f31f..000000000000 --- a/deps/SoftFloat-3e/source/8086-SSE/s_commonNaNToF32UI.c +++ /dev/null @@ -1,51 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "specialize.h" - -/*---------------------------------------------------------------------------- -| Converts the common NaN pointed to by `aPtr' into a 32-bit floating-point -| NaN, and returns the bit pattern of this value as an unsigned integer. -*----------------------------------------------------------------------------*/ -uint_fast32_t softfloat_commonNaNToF32UI( const struct commonNaN *aPtr ) -{ - - return (uint_fast32_t) aPtr->sign<<31 | 0x7FC00000 | aPtr->v64>>41; - -} - diff --git a/deps/SoftFloat-3e/source/8086-SSE/s_commonNaNToF64UI.c b/deps/SoftFloat-3e/source/8086-SSE/s_commonNaNToF64UI.c deleted file mode 100644 index 1182be3c9cdf..000000000000 --- a/deps/SoftFloat-3e/source/8086-SSE/s_commonNaNToF64UI.c +++ /dev/null @@ -1,53 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "specialize.h" - -/*---------------------------------------------------------------------------- -| Converts the common NaN pointed to by `aPtr' into a 64-bit floating-point -| NaN, and returns the bit pattern of this value as an unsigned integer. -*----------------------------------------------------------------------------*/ -uint_fast64_t softfloat_commonNaNToF64UI( const struct commonNaN *aPtr ) -{ - - return - (uint_fast64_t) aPtr->sign<<63 | UINT64_C( 0x7FF8000000000000 ) - | aPtr->v64>>12; - -} - diff --git a/deps/SoftFloat-3e/source/8086-SSE/s_extF80MToCommonNaN.c b/deps/SoftFloat-3e/source/8086-SSE/s_extF80MToCommonNaN.c deleted file mode 100644 index 00baf35f893a..000000000000 --- a/deps/SoftFloat-3e/source/8086-SSE/s_extF80MToCommonNaN.c +++ /dev/null @@ -1,62 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -/*---------------------------------------------------------------------------- -| Assuming the 80-bit extended floating-point value pointed to by `aSPtr' is -| a NaN, converts this NaN to the common NaN form, and stores the resulting -| common NaN at the location pointed to by `zPtr'. If the NaN is a signaling -| NaN, the invalid exception is raised. -*----------------------------------------------------------------------------*/ -void - softfloat_extF80MToCommonNaN( - const struct extFloat80M *aSPtr, struct commonNaN *zPtr ) -{ - - if ( extF80M_isSignalingNaN( (const extFloat80_t *) aSPtr ) ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - } - zPtr->sign = signExtF80UI64( aSPtr->signExp ); - zPtr->v64 = aSPtr->signif<<1; - zPtr->v0 = 0; - -} - diff --git a/deps/SoftFloat-3e/source/8086-SSE/s_extF80UIToCommonNaN.c b/deps/SoftFloat-3e/source/8086-SSE/s_extF80UIToCommonNaN.c deleted file mode 100644 index ab6311ef2906..000000000000 --- a/deps/SoftFloat-3e/source/8086-SSE/s_extF80UIToCommonNaN.c +++ /dev/null @@ -1,62 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "specialize.h" -#include "softfloat.h" - -/*---------------------------------------------------------------------------- -| Assuming the unsigned integer formed from concatenating `uiA64' and `uiA0' -| has the bit pattern of an 80-bit extended floating-point NaN, converts -| this NaN to the common NaN form, and stores the resulting common NaN at the -| location pointed to by `zPtr'. If the NaN is a signaling NaN, the invalid -| exception is raised. -*----------------------------------------------------------------------------*/ -void - softfloat_extF80UIToCommonNaN( - uint_fast16_t uiA64, uint_fast64_t uiA0, struct commonNaN *zPtr ) -{ - - if ( softfloat_isSigNaNExtF80UI( uiA64, uiA0 ) ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - } - zPtr->sign = uiA64>>15; - zPtr->v64 = uiA0<<1; - zPtr->v0 = 0; - -} - diff --git a/deps/SoftFloat-3e/source/8086-SSE/s_f128MToCommonNaN.c b/deps/SoftFloat-3e/source/8086-SSE/s_f128MToCommonNaN.c deleted file mode 100644 index 55ec25b58c8d..000000000000 --- a/deps/SoftFloat-3e/source/8086-SSE/s_f128MToCommonNaN.c +++ /dev/null @@ -1,62 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "primitives.h" -#include "specialize.h" -#include "softfloat.h" - -/*---------------------------------------------------------------------------- -| Assuming the 128-bit floating-point value pointed to by `aWPtr' is a NaN, -| converts this NaN to the common NaN form, and stores the resulting common -| NaN at the location pointed to by `zPtr'. If the NaN is a signaling NaN, -| the invalid exception is raised. Argument `aWPtr' points to an array of -| four 32-bit elements that concatenate in the platform's normal endian order -| to form a 128-bit floating-point value. -*----------------------------------------------------------------------------*/ -void - softfloat_f128MToCommonNaN( const uint32_t *aWPtr, struct commonNaN *zPtr ) -{ - - if ( f128M_isSignalingNaN( (const float128_t *) aWPtr ) ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - } - zPtr->sign = aWPtr[indexWordHi( 4 )]>>31; - softfloat_shortShiftLeft128M( aWPtr, 16, (uint32_t *) &zPtr->v0 ); - -} - diff --git a/deps/SoftFloat-3e/source/8086-SSE/s_f128UIToCommonNaN.c b/deps/SoftFloat-3e/source/8086-SSE/s_f128UIToCommonNaN.c deleted file mode 100644 index f838f02aaf1f..000000000000 --- a/deps/SoftFloat-3e/source/8086-SSE/s_f128UIToCommonNaN.c +++ /dev/null @@ -1,65 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "primitives.h" -#include "specialize.h" -#include "softfloat.h" - -/*---------------------------------------------------------------------------- -| Assuming the unsigned integer formed from concatenating `uiA64' and `uiA0' -| has the bit pattern of a 128-bit floating-point NaN, converts this NaN to -| the common NaN form, and stores the resulting common NaN at the location -| pointed to by `zPtr'. If the NaN is a signaling NaN, the invalid exception -| is raised. -*----------------------------------------------------------------------------*/ -void - softfloat_f128UIToCommonNaN( - uint_fast64_t uiA64, uint_fast64_t uiA0, struct commonNaN *zPtr ) -{ - struct uint128 NaNSig; - - if ( softfloat_isSigNaNF128UI( uiA64, uiA0 ) ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - } - NaNSig = softfloat_shortShiftLeft128( uiA64, uiA0, 16 ); - zPtr->sign = uiA64>>63; - zPtr->v64 = NaNSig.v64; - zPtr->v0 = NaNSig.v0; - -} - diff --git a/deps/SoftFloat-3e/source/8086-SSE/s_f16UIToCommonNaN.c b/deps/SoftFloat-3e/source/8086-SSE/s_f16UIToCommonNaN.c deleted file mode 100644 index c1e242d23684..000000000000 --- a/deps/SoftFloat-3e/source/8086-SSE/s_f16UIToCommonNaN.c +++ /dev/null @@ -1,59 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "specialize.h" -#include "softfloat.h" - -/*---------------------------------------------------------------------------- -| Assuming `uiA' has the bit pattern of a 16-bit floating-point NaN, converts -| this NaN to the common NaN form, and stores the resulting common NaN at the -| location pointed to by `zPtr'. If the NaN is a signaling NaN, the invalid -| exception is raised. -*----------------------------------------------------------------------------*/ -void softfloat_f16UIToCommonNaN( uint_fast16_t uiA, struct commonNaN *zPtr ) -{ - - if ( softfloat_isSigNaNF16UI( uiA ) ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - } - zPtr->sign = uiA>>15; - zPtr->v64 = (uint_fast64_t) uiA<<54; - zPtr->v0 = 0; - -} - diff --git a/deps/SoftFloat-3e/source/8086-SSE/s_f32UIToCommonNaN.c b/deps/SoftFloat-3e/source/8086-SSE/s_f32UIToCommonNaN.c deleted file mode 100644 index b21ba660398d..000000000000 --- a/deps/SoftFloat-3e/source/8086-SSE/s_f32UIToCommonNaN.c +++ /dev/null @@ -1,59 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "specialize.h" -#include "softfloat.h" - -/*---------------------------------------------------------------------------- -| Assuming `uiA' has the bit pattern of a 32-bit floating-point NaN, converts -| this NaN to the common NaN form, and stores the resulting common NaN at the -| location pointed to by `zPtr'. If the NaN is a signaling NaN, the invalid -| exception is raised. -*----------------------------------------------------------------------------*/ -void softfloat_f32UIToCommonNaN( uint_fast32_t uiA, struct commonNaN *zPtr ) -{ - - if ( softfloat_isSigNaNF32UI( uiA ) ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - } - zPtr->sign = uiA>>31; - zPtr->v64 = (uint_fast64_t) uiA<<41; - zPtr->v0 = 0; - -} - diff --git a/deps/SoftFloat-3e/source/8086-SSE/s_f64UIToCommonNaN.c b/deps/SoftFloat-3e/source/8086-SSE/s_f64UIToCommonNaN.c deleted file mode 100644 index 6529d2ee5fd1..000000000000 --- a/deps/SoftFloat-3e/source/8086-SSE/s_f64UIToCommonNaN.c +++ /dev/null @@ -1,59 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "specialize.h" -#include "softfloat.h" - -/*---------------------------------------------------------------------------- -| Assuming `uiA' has the bit pattern of a 64-bit floating-point NaN, converts -| this NaN to the common NaN form, and stores the resulting common NaN at the -| location pointed to by `zPtr'. If the NaN is a signaling NaN, the invalid -| exception is raised. -*----------------------------------------------------------------------------*/ -void softfloat_f64UIToCommonNaN( uint_fast64_t uiA, struct commonNaN *zPtr ) -{ - - if ( softfloat_isSigNaNF64UI( uiA ) ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - } - zPtr->sign = uiA>>63; - zPtr->v64 = uiA<<12; - zPtr->v0 = 0; - -} - diff --git a/deps/SoftFloat-3e/source/8086-SSE/s_propagateNaNExtF80M.c b/deps/SoftFloat-3e/source/8086-SSE/s_propagateNaNExtF80M.c deleted file mode 100644 index ea1d57a78814..000000000000 --- a/deps/SoftFloat-3e/source/8086-SSE/s_propagateNaNExtF80M.c +++ /dev/null @@ -1,107 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -/*---------------------------------------------------------------------------- -| Assuming at least one of the two 80-bit extended floating-point values -| pointed to by `aSPtr' and `bSPtr' is a NaN, stores the combined NaN result -| at the location pointed to by `zSPtr'. If either original floating-point -| value is a signaling NaN, the invalid exception is raised. -*----------------------------------------------------------------------------*/ -void - softfloat_propagateNaNExtF80M( - const struct extFloat80M *aSPtr, - const struct extFloat80M *bSPtr, - struct extFloat80M *zSPtr - ) -{ - bool isSigNaNA; - const struct extFloat80M *sPtr; - bool isSigNaNB; - uint_fast16_t uiB64; - uint64_t uiB0; - uint_fast16_t uiA64; - uint64_t uiA0; - uint_fast16_t uiMagA64, uiMagB64; - - isSigNaNA = extF80M_isSignalingNaN( (const extFloat80_t *) aSPtr ); - sPtr = aSPtr; - if ( ! bSPtr ) { - if ( isSigNaNA ) softfloat_raiseFlags( softfloat_flag_invalid ); - goto copy; - } - isSigNaNB = extF80M_isSignalingNaN( (const extFloat80_t *) bSPtr ); - if ( isSigNaNA | isSigNaNB ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - if ( isSigNaNA ) { - uiB64 = bSPtr->signExp; - if ( isSigNaNB ) goto returnLargerUIMag; - uiB0 = bSPtr->signif; - if ( isNaNExtF80UI( uiB64, uiB0 ) ) goto copyB; - goto copy; - } else { - uiA64 = aSPtr->signExp; - uiA0 = aSPtr->signif; - if ( isNaNExtF80UI( uiA64, uiA0 ) ) goto copy; - goto copyB; - } - } - uiB64 = bSPtr->signExp; - returnLargerUIMag: - uiA64 = aSPtr->signExp; - uiMagA64 = uiA64 & 0x7FFF; - uiMagB64 = uiB64 & 0x7FFF; - if ( uiMagA64 < uiMagB64 ) goto copyB; - if ( uiMagB64 < uiMagA64 ) goto copy; - uiA0 = aSPtr->signif; - uiB0 = bSPtr->signif; - if ( uiA0 < uiB0 ) goto copyB; - if ( uiB0 < uiA0 ) goto copy; - if ( uiA64 < uiB64 ) goto copy; - copyB: - sPtr = bSPtr; - copy: - zSPtr->signExp = sPtr->signExp; - zSPtr->signif = sPtr->signif | UINT64_C( 0xC000000000000000 ); - -} - diff --git a/deps/SoftFloat-3e/source/8086-SSE/s_propagateNaNExtF80UI.c b/deps/SoftFloat-3e/source/8086-SSE/s_propagateNaNExtF80UI.c deleted file mode 100644 index cc3f0f42c55d..000000000000 --- a/deps/SoftFloat-3e/source/8086-SSE/s_propagateNaNExtF80UI.c +++ /dev/null @@ -1,106 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2018 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -/*---------------------------------------------------------------------------- -| Interpreting the unsigned integer formed from concatenating 'uiA64' and -| 'uiA0' as an 80-bit extended floating-point value, and likewise interpreting -| the unsigned integer formed from concatenating 'uiB64' and 'uiB0' as another -| 80-bit extended floating-point value, and assuming at least on of these -| floating-point values is a NaN, returns the bit pattern of the combined NaN -| result. If either original floating-point value is a signaling NaN, the -| invalid exception is raised. -*----------------------------------------------------------------------------*/ -struct uint128 - softfloat_propagateNaNExtF80UI( - uint_fast16_t uiA64, - uint_fast64_t uiA0, - uint_fast16_t uiB64, - uint_fast64_t uiB0 - ) -{ - bool isSigNaNA, isSigNaNB; - uint_fast64_t uiNonsigA0, uiNonsigB0; - uint_fast16_t uiMagA64, uiMagB64; - struct uint128 uiZ; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - isSigNaNA = softfloat_isSigNaNExtF80UI( uiA64, uiA0 ); - isSigNaNB = softfloat_isSigNaNExtF80UI( uiB64, uiB0 ); - /*------------------------------------------------------------------------ - | Make NaNs non-signaling. - *------------------------------------------------------------------------*/ - uiNonsigA0 = uiA0 | UINT64_C( 0xC000000000000000 ); - uiNonsigB0 = uiB0 | UINT64_C( 0xC000000000000000 ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( isSigNaNA | isSigNaNB ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - if ( isSigNaNA ) { - if ( isSigNaNB ) goto returnLargerMag; - if ( isNaNExtF80UI( uiB64, uiB0 ) ) goto returnB; - goto returnA; - } else { - if ( isNaNExtF80UI( uiA64, uiA0 ) ) goto returnA; - goto returnB; - } - } - returnLargerMag: - uiMagA64 = uiA64 & 0x7FFF; - uiMagB64 = uiB64 & 0x7FFF; - if ( uiMagA64 < uiMagB64 ) goto returnB; - if ( uiMagB64 < uiMagA64 ) goto returnA; - if ( uiA0 < uiB0 ) goto returnB; - if ( uiB0 < uiA0 ) goto returnA; - if ( uiA64 < uiB64 ) goto returnA; - returnB: - uiZ.v64 = uiB64; - uiZ.v0 = uiNonsigB0; - return uiZ; - returnA: - uiZ.v64 = uiA64; - uiZ.v0 = uiNonsigA0; - return uiZ; - -} - diff --git a/deps/SoftFloat-3e/source/8086-SSE/s_propagateNaNF128M.c b/deps/SoftFloat-3e/source/8086-SSE/s_propagateNaNF128M.c deleted file mode 100644 index aa903bf80909..000000000000 --- a/deps/SoftFloat-3e/source/8086-SSE/s_propagateNaNF128M.c +++ /dev/null @@ -1,76 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -/*---------------------------------------------------------------------------- -| Assuming at least one of the two 128-bit floating-point values pointed to by -| `aWPtr' and `bWPtr' is a NaN, stores the combined NaN result at the location -| pointed to by `zWPtr'. If either original floating-point value is a -| signaling NaN, the invalid exception is raised. Each of `aWPtr', `bWPtr', -| and `zWPtr' points to an array of four 32-bit elements that concatenate in -| the platform's normal endian order to form a 128-bit floating-point value. -*----------------------------------------------------------------------------*/ -void - softfloat_propagateNaNF128M( - const uint32_t *aWPtr, const uint32_t *bWPtr, uint32_t *zWPtr ) -{ - bool isSigNaNA; - const uint32_t *ptr; - - ptr = aWPtr; - isSigNaNA = f128M_isSignalingNaN( (const float128_t *) aWPtr ); - if ( - isSigNaNA - || (bWPtr && f128M_isSignalingNaN( (const float128_t *) bWPtr )) - ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - if ( isSigNaNA ) goto copy; - } - if ( ! softfloat_isNaNF128M( aWPtr ) ) ptr = bWPtr; - copy: - zWPtr[indexWordHi( 4 )] = ptr[indexWordHi( 4 )] | 0x00008000; - zWPtr[indexWord( 4, 2 )] = ptr[indexWord( 4, 2 )]; - zWPtr[indexWord( 4, 1 )] = ptr[indexWord( 4, 1 )]; - zWPtr[indexWord( 4, 0 )] = ptr[indexWord( 4, 0 )]; - -} - diff --git a/deps/SoftFloat-3e/source/8086-SSE/s_propagateNaNF128UI.c b/deps/SoftFloat-3e/source/8086-SSE/s_propagateNaNF128UI.c deleted file mode 100644 index 1c1c2f4a0983..000000000000 --- a/deps/SoftFloat-3e/source/8086-SSE/s_propagateNaNF128UI.c +++ /dev/null @@ -1,81 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -/*---------------------------------------------------------------------------- -| Interpreting the unsigned integer formed from concatenating `uiA64' and -| `uiA0' as a 128-bit floating-point value, and likewise interpreting the -| unsigned integer formed from concatenating `uiB64' and `uiB0' as another -| 128-bit floating-point value, and assuming at least on of these floating- -| point values is a NaN, returns the bit pattern of the combined NaN result. -| If either original floating-point value is a signaling NaN, the invalid -| exception is raised. -*----------------------------------------------------------------------------*/ -struct uint128 - softfloat_propagateNaNF128UI( - uint_fast64_t uiA64, - uint_fast64_t uiA0, - uint_fast64_t uiB64, - uint_fast64_t uiB0 - ) -{ - bool isSigNaNA; - struct uint128 uiZ; - - isSigNaNA = softfloat_isSigNaNF128UI( uiA64, uiA0 ); - if ( isSigNaNA || softfloat_isSigNaNF128UI( uiB64, uiB0 ) ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - if ( isSigNaNA ) goto returnNonsigA; - } - if ( isNaNF128UI( uiA64, uiA0 ) ) { - returnNonsigA: - uiZ.v64 = uiA64; - uiZ.v0 = uiA0; - } else { - uiZ.v64 = uiB64; - uiZ.v0 = uiB0; - } - uiZ.v64 |= UINT64_C( 0x0000800000000000 ); - return uiZ; - -} - diff --git a/deps/SoftFloat-3e/source/8086-SSE/s_propagateNaNF16UI.c b/deps/SoftFloat-3e/source/8086-SSE/s_propagateNaNF16UI.c deleted file mode 100644 index 4e87ff41f806..000000000000 --- a/deps/SoftFloat-3e/source/8086-SSE/s_propagateNaNF16UI.c +++ /dev/null @@ -1,63 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -/*---------------------------------------------------------------------------- -| Interpreting `uiA' and `uiB' as the bit patterns of two 16-bit floating- -| point values, at least one of which is a NaN, returns the bit pattern of -| the combined NaN result. If either `uiA' or `uiB' has the pattern of a -| signaling NaN, the invalid exception is raised. -*----------------------------------------------------------------------------*/ -uint_fast16_t - softfloat_propagateNaNF16UI( uint_fast16_t uiA, uint_fast16_t uiB ) -{ - bool isSigNaNA; - - isSigNaNA = softfloat_isSigNaNF16UI( uiA ); - if ( isSigNaNA || softfloat_isSigNaNF16UI( uiB ) ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - if ( isSigNaNA ) return uiA | 0x0200; - } - return (isNaNF16UI( uiA ) ? uiA : uiB) | 0x0200; - -} - diff --git a/deps/SoftFloat-3e/source/8086-SSE/s_propagateNaNF32UI.c b/deps/SoftFloat-3e/source/8086-SSE/s_propagateNaNF32UI.c deleted file mode 100644 index e1a87552506f..000000000000 --- a/deps/SoftFloat-3e/source/8086-SSE/s_propagateNaNF32UI.c +++ /dev/null @@ -1,63 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -/*---------------------------------------------------------------------------- -| Interpreting `uiA' and `uiB' as the bit patterns of two 32-bit floating- -| point values, at least one of which is a NaN, returns the bit pattern of -| the combined NaN result. If either `uiA' or `uiB' has the pattern of a -| signaling NaN, the invalid exception is raised. -*----------------------------------------------------------------------------*/ -uint_fast32_t - softfloat_propagateNaNF32UI( uint_fast32_t uiA, uint_fast32_t uiB ) -{ - bool isSigNaNA; - - isSigNaNA = softfloat_isSigNaNF32UI( uiA ); - if ( isSigNaNA || softfloat_isSigNaNF32UI( uiB ) ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - if ( isSigNaNA ) return uiA | 0x00400000; - } - return (isNaNF32UI( uiA ) ? uiA : uiB) | 0x00400000; - -} - diff --git a/deps/SoftFloat-3e/source/8086-SSE/s_propagateNaNF64UI.c b/deps/SoftFloat-3e/source/8086-SSE/s_propagateNaNF64UI.c deleted file mode 100644 index 1af349f3e324..000000000000 --- a/deps/SoftFloat-3e/source/8086-SSE/s_propagateNaNF64UI.c +++ /dev/null @@ -1,63 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -/*---------------------------------------------------------------------------- -| Interpreting `uiA' and `uiB' as the bit patterns of two 64-bit floating- -| point values, at least one of which is a NaN, returns the bit pattern of -| the combined NaN result. If either `uiA' or `uiB' has the pattern of a -| signaling NaN, the invalid exception is raised. -*----------------------------------------------------------------------------*/ -uint_fast64_t - softfloat_propagateNaNF64UI( uint_fast64_t uiA, uint_fast64_t uiB ) -{ - bool isSigNaNA; - - isSigNaNA = softfloat_isSigNaNF64UI( uiA ); - if ( isSigNaNA || softfloat_isSigNaNF64UI( uiB ) ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - if ( isSigNaNA ) return uiA | UINT64_C( 0x0008000000000000 ); - } - return (isNaNF64UI( uiA ) ? uiA : uiB) | UINT64_C( 0x0008000000000000 ); - -} - diff --git a/deps/SoftFloat-3e/source/8086-SSE/softfloat_raiseFlags.c b/deps/SoftFloat-3e/source/8086-SSE/softfloat_raiseFlags.c deleted file mode 100644 index 3115306beedd..000000000000 --- a/deps/SoftFloat-3e/source/8086-SSE/softfloat_raiseFlags.c +++ /dev/null @@ -1,52 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include "platform.h" -#include "softfloat.h" - -/*---------------------------------------------------------------------------- -| Raises the exceptions specified by `flags'. Floating-point traps can be -| defined here if desired. It is currently not possible for such a trap -| to substitute a result value. If traps are not implemented, this routine -| should be simply `softfloat_exceptionFlags |= flags;'. -*----------------------------------------------------------------------------*/ -void softfloat_raiseFlags( uint_fast8_t flags ) -{ - - softfloat_exceptionFlags |= flags; - -} - diff --git a/deps/SoftFloat-3e/source/8086-SSE/specialize.h b/deps/SoftFloat-3e/source/8086-SSE/specialize.h deleted file mode 100644 index 5fe119a1e1f1..000000000000 --- a/deps/SoftFloat-3e/source/8086-SSE/specialize.h +++ /dev/null @@ -1,376 +0,0 @@ - -/*============================================================================ - -This C header file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2018 The Regents of the -University of California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#ifndef specialize_h -#define specialize_h 1 - -#include -#include -#include "primitiveTypes.h" -#include "softfloat.h" - -/*---------------------------------------------------------------------------- -| Default value for 'softfloat_detectTininess'. -*----------------------------------------------------------------------------*/ -#define init_detectTininess softfloat_tininess_afterRounding - -/*---------------------------------------------------------------------------- -| The values to return on conversions to 32-bit integer formats that raise an -| invalid exception. -*----------------------------------------------------------------------------*/ -#define ui32_fromPosOverflow 0xFFFFFFFF -#define ui32_fromNegOverflow 0xFFFFFFFF -#define ui32_fromNaN 0xFFFFFFFF -#define i32_fromPosOverflow (-0x7FFFFFFF - 1) -#define i32_fromNegOverflow (-0x7FFFFFFF - 1) -#define i32_fromNaN (-0x7FFFFFFF - 1) - -/*---------------------------------------------------------------------------- -| The values to return on conversions to 64-bit integer formats that raise an -| invalid exception. -*----------------------------------------------------------------------------*/ -#define ui64_fromPosOverflow UINT64_C( 0xFFFFFFFFFFFFFFFF ) -#define ui64_fromNegOverflow UINT64_C( 0xFFFFFFFFFFFFFFFF ) -#define ui64_fromNaN UINT64_C( 0xFFFFFFFFFFFFFFFF ) -#define i64_fromPosOverflow (-INT64_C( 0x7FFFFFFFFFFFFFFF ) - 1) -#define i64_fromNegOverflow (-INT64_C( 0x7FFFFFFFFFFFFFFF ) - 1) -#define i64_fromNaN (-INT64_C( 0x7FFFFFFFFFFFFFFF ) - 1) - -/*---------------------------------------------------------------------------- -| "Common NaN" structure, used to transfer NaN representations from one format -| to another. -*----------------------------------------------------------------------------*/ -struct commonNaN { - bool sign; -#ifdef LITTLEENDIAN - uint64_t v0, v64; -#else - uint64_t v64, v0; -#endif -}; - -/*---------------------------------------------------------------------------- -| The bit pattern for a default generated 16-bit floating-point NaN. -*----------------------------------------------------------------------------*/ -#define defaultNaNF16UI 0xFE00 - -/*---------------------------------------------------------------------------- -| Returns true when 16-bit unsigned integer 'uiA' has the bit pattern of a -| 16-bit floating-point signaling NaN. -| Note: This macro evaluates its argument more than once. -*----------------------------------------------------------------------------*/ -#define softfloat_isSigNaNF16UI( uiA ) ((((uiA) & 0x7E00) == 0x7C00) && ((uiA) & 0x01FF)) - -/*---------------------------------------------------------------------------- -| Assuming 'uiA' has the bit pattern of a 16-bit floating-point NaN, converts -| this NaN to the common NaN form, and stores the resulting common NaN at the -| location pointed to by 'zPtr'. If the NaN is a signaling NaN, the invalid -| exception is raised. -*----------------------------------------------------------------------------*/ -void softfloat_f16UIToCommonNaN( uint_fast16_t uiA, struct commonNaN *zPtr ); - -/*---------------------------------------------------------------------------- -| Converts the common NaN pointed to by 'aPtr' into a 16-bit floating-point -| NaN, and returns the bit pattern of this value as an unsigned integer. -*----------------------------------------------------------------------------*/ -uint_fast16_t softfloat_commonNaNToF16UI( const struct commonNaN *aPtr ); - -/*---------------------------------------------------------------------------- -| Interpreting 'uiA' and 'uiB' as the bit patterns of two 16-bit floating- -| point values, at least one of which is a NaN, returns the bit pattern of -| the combined NaN result. If either 'uiA' or 'uiB' has the pattern of a -| signaling NaN, the invalid exception is raised. -*----------------------------------------------------------------------------*/ -uint_fast16_t - softfloat_propagateNaNF16UI( uint_fast16_t uiA, uint_fast16_t uiB ); - -/*---------------------------------------------------------------------------- -| The bit pattern for a default generated 32-bit floating-point NaN. -*----------------------------------------------------------------------------*/ -#define defaultNaNF32UI 0xFFC00000 - -/*---------------------------------------------------------------------------- -| Returns true when 32-bit unsigned integer 'uiA' has the bit pattern of a -| 32-bit floating-point signaling NaN. -| Note: This macro evaluates its argument more than once. -*----------------------------------------------------------------------------*/ -#define softfloat_isSigNaNF32UI( uiA ) ((((uiA) & 0x7FC00000) == 0x7F800000) && ((uiA) & 0x003FFFFF)) - -/*---------------------------------------------------------------------------- -| Assuming 'uiA' has the bit pattern of a 32-bit floating-point NaN, converts -| this NaN to the common NaN form, and stores the resulting common NaN at the -| location pointed to by 'zPtr'. If the NaN is a signaling NaN, the invalid -| exception is raised. -*----------------------------------------------------------------------------*/ -void softfloat_f32UIToCommonNaN( uint_fast32_t uiA, struct commonNaN *zPtr ); - -/*---------------------------------------------------------------------------- -| Converts the common NaN pointed to by 'aPtr' into a 32-bit floating-point -| NaN, and returns the bit pattern of this value as an unsigned integer. -*----------------------------------------------------------------------------*/ -uint_fast32_t softfloat_commonNaNToF32UI( const struct commonNaN *aPtr ); - -/*---------------------------------------------------------------------------- -| Interpreting 'uiA' and 'uiB' as the bit patterns of two 32-bit floating- -| point values, at least one of which is a NaN, returns the bit pattern of -| the combined NaN result. If either 'uiA' or 'uiB' has the pattern of a -| signaling NaN, the invalid exception is raised. -*----------------------------------------------------------------------------*/ -uint_fast32_t - softfloat_propagateNaNF32UI( uint_fast32_t uiA, uint_fast32_t uiB ); - -/*---------------------------------------------------------------------------- -| The bit pattern for a default generated 64-bit floating-point NaN. -*----------------------------------------------------------------------------*/ -#define defaultNaNF64UI UINT64_C( 0xFFF8000000000000 ) - -/*---------------------------------------------------------------------------- -| Returns true when 64-bit unsigned integer 'uiA' has the bit pattern of a -| 64-bit floating-point signaling NaN. -| Note: This macro evaluates its argument more than once. -*----------------------------------------------------------------------------*/ -#define softfloat_isSigNaNF64UI( uiA ) ((((uiA) & UINT64_C( 0x7FF8000000000000 )) == UINT64_C( 0x7FF0000000000000 )) && ((uiA) & UINT64_C( 0x0007FFFFFFFFFFFF ))) - -/*---------------------------------------------------------------------------- -| Assuming 'uiA' has the bit pattern of a 64-bit floating-point NaN, converts -| this NaN to the common NaN form, and stores the resulting common NaN at the -| location pointed to by 'zPtr'. If the NaN is a signaling NaN, the invalid -| exception is raised. -*----------------------------------------------------------------------------*/ -void softfloat_f64UIToCommonNaN( uint_fast64_t uiA, struct commonNaN *zPtr ); - -/*---------------------------------------------------------------------------- -| Converts the common NaN pointed to by 'aPtr' into a 64-bit floating-point -| NaN, and returns the bit pattern of this value as an unsigned integer. -*----------------------------------------------------------------------------*/ -uint_fast64_t softfloat_commonNaNToF64UI( const struct commonNaN *aPtr ); - -/*---------------------------------------------------------------------------- -| Interpreting 'uiA' and 'uiB' as the bit patterns of two 64-bit floating- -| point values, at least one of which is a NaN, returns the bit pattern of -| the combined NaN result. If either 'uiA' or 'uiB' has the pattern of a -| signaling NaN, the invalid exception is raised. -*----------------------------------------------------------------------------*/ -uint_fast64_t - softfloat_propagateNaNF64UI( uint_fast64_t uiA, uint_fast64_t uiB ); - -/*---------------------------------------------------------------------------- -| The bit pattern for a default generated 80-bit extended floating-point NaN. -*----------------------------------------------------------------------------*/ -#define defaultNaNExtF80UI64 0xFFFF -#define defaultNaNExtF80UI0 UINT64_C( 0xC000000000000000 ) - -/*---------------------------------------------------------------------------- -| Returns true when the 80-bit unsigned integer formed from concatenating -| 16-bit 'uiA64' and 64-bit 'uiA0' has the bit pattern of an 80-bit extended -| floating-point signaling NaN. -| Note: This macro evaluates its arguments more than once. -*----------------------------------------------------------------------------*/ -#define softfloat_isSigNaNExtF80UI( uiA64, uiA0 ) ((((uiA64) & 0x7FFF) == 0x7FFF) && ! ((uiA0) & UINT64_C( 0x4000000000000000 )) && ((uiA0) & UINT64_C( 0x3FFFFFFFFFFFFFFF ))) - -#ifdef SOFTFLOAT_FAST_INT64 - -/*---------------------------------------------------------------------------- -| The following functions are needed only when 'SOFTFLOAT_FAST_INT64' is -| defined. -*----------------------------------------------------------------------------*/ - -/*---------------------------------------------------------------------------- -| Assuming the unsigned integer formed from concatenating 'uiA64' and 'uiA0' -| has the bit pattern of an 80-bit extended floating-point NaN, converts -| this NaN to the common NaN form, and stores the resulting common NaN at the -| location pointed to by 'zPtr'. If the NaN is a signaling NaN, the invalid -| exception is raised. -*----------------------------------------------------------------------------*/ -void - softfloat_extF80UIToCommonNaN( - uint_fast16_t uiA64, uint_fast64_t uiA0, struct commonNaN *zPtr ); - -/*---------------------------------------------------------------------------- -| Converts the common NaN pointed to by 'aPtr' into an 80-bit extended -| floating-point NaN, and returns the bit pattern of this value as an unsigned -| integer. -*----------------------------------------------------------------------------*/ -struct uint128 softfloat_commonNaNToExtF80UI( const struct commonNaN *aPtr ); - -/*---------------------------------------------------------------------------- -| Interpreting the unsigned integer formed from concatenating 'uiA64' and -| 'uiA0' as an 80-bit extended floating-point value, and likewise interpreting -| the unsigned integer formed from concatenating 'uiB64' and 'uiB0' as another -| 80-bit extended floating-point value, and assuming at least on of these -| floating-point values is a NaN, returns the bit pattern of the combined NaN -| result. If either original floating-point value is a signaling NaN, the -| invalid exception is raised. -*----------------------------------------------------------------------------*/ -struct uint128 - softfloat_propagateNaNExtF80UI( - uint_fast16_t uiA64, - uint_fast64_t uiA0, - uint_fast16_t uiB64, - uint_fast64_t uiB0 - ); - -/*---------------------------------------------------------------------------- -| The bit pattern for a default generated 128-bit floating-point NaN. -*----------------------------------------------------------------------------*/ -#define defaultNaNF128UI64 UINT64_C( 0xFFFF800000000000 ) -#define defaultNaNF128UI0 UINT64_C( 0 ) - -/*---------------------------------------------------------------------------- -| Returns true when the 128-bit unsigned integer formed from concatenating -| 64-bit 'uiA64' and 64-bit 'uiA0' has the bit pattern of a 128-bit floating- -| point signaling NaN. -| Note: This macro evaluates its arguments more than once. -*----------------------------------------------------------------------------*/ -#define softfloat_isSigNaNF128UI( uiA64, uiA0 ) ((((uiA64) & UINT64_C( 0x7FFF800000000000 )) == UINT64_C( 0x7FFF000000000000 )) && ((uiA0) || ((uiA64) & UINT64_C( 0x00007FFFFFFFFFFF )))) - -/*---------------------------------------------------------------------------- -| Assuming the unsigned integer formed from concatenating 'uiA64' and 'uiA0' -| has the bit pattern of a 128-bit floating-point NaN, converts this NaN to -| the common NaN form, and stores the resulting common NaN at the location -| pointed to by 'zPtr'. If the NaN is a signaling NaN, the invalid exception -| is raised. -*----------------------------------------------------------------------------*/ -void - softfloat_f128UIToCommonNaN( - uint_fast64_t uiA64, uint_fast64_t uiA0, struct commonNaN *zPtr ); - -/*---------------------------------------------------------------------------- -| Converts the common NaN pointed to by 'aPtr' into a 128-bit floating-point -| NaN, and returns the bit pattern of this value as an unsigned integer. -*----------------------------------------------------------------------------*/ -struct uint128 softfloat_commonNaNToF128UI( const struct commonNaN * ); - -/*---------------------------------------------------------------------------- -| Interpreting the unsigned integer formed from concatenating 'uiA64' and -| 'uiA0' as a 128-bit floating-point value, and likewise interpreting the -| unsigned integer formed from concatenating 'uiB64' and 'uiB0' as another -| 128-bit floating-point value, and assuming at least on of these floating- -| point values is a NaN, returns the bit pattern of the combined NaN result. -| If either original floating-point value is a signaling NaN, the invalid -| exception is raised. -*----------------------------------------------------------------------------*/ -struct uint128 - softfloat_propagateNaNF128UI( - uint_fast64_t uiA64, - uint_fast64_t uiA0, - uint_fast64_t uiB64, - uint_fast64_t uiB0 - ); - -#else - -/*---------------------------------------------------------------------------- -| The following functions are needed only when 'SOFTFLOAT_FAST_INT64' is not -| defined. -*----------------------------------------------------------------------------*/ - -/*---------------------------------------------------------------------------- -| Assuming the 80-bit extended floating-point value pointed to by 'aSPtr' is -| a NaN, converts this NaN to the common NaN form, and stores the resulting -| common NaN at the location pointed to by 'zPtr'. If the NaN is a signaling -| NaN, the invalid exception is raised. -*----------------------------------------------------------------------------*/ -void - softfloat_extF80MToCommonNaN( - const struct extFloat80M *aSPtr, struct commonNaN *zPtr ); - -/*---------------------------------------------------------------------------- -| Converts the common NaN pointed to by 'aPtr' into an 80-bit extended -| floating-point NaN, and stores this NaN at the location pointed to by -| 'zSPtr'. -*----------------------------------------------------------------------------*/ -void - softfloat_commonNaNToExtF80M( - const struct commonNaN *aPtr, struct extFloat80M *zSPtr ); - -/*---------------------------------------------------------------------------- -| Assuming at least one of the two 80-bit extended floating-point values -| pointed to by 'aSPtr' and 'bSPtr' is a NaN, stores the combined NaN result -| at the location pointed to by 'zSPtr'. If either original floating-point -| value is a signaling NaN, the invalid exception is raised. -*----------------------------------------------------------------------------*/ -void - softfloat_propagateNaNExtF80M( - const struct extFloat80M *aSPtr, - const struct extFloat80M *bSPtr, - struct extFloat80M *zSPtr - ); - -/*---------------------------------------------------------------------------- -| The bit pattern for a default generated 128-bit floating-point NaN. -*----------------------------------------------------------------------------*/ -#define defaultNaNF128UI96 0xFFFF8000 -#define defaultNaNF128UI64 0 -#define defaultNaNF128UI32 0 -#define defaultNaNF128UI0 0 - -/*---------------------------------------------------------------------------- -| Assuming the 128-bit floating-point value pointed to by 'aWPtr' is a NaN, -| converts this NaN to the common NaN form, and stores the resulting common -| NaN at the location pointed to by 'zPtr'. If the NaN is a signaling NaN, -| the invalid exception is raised. Argument 'aWPtr' points to an array of -| four 32-bit elements that concatenate in the platform's normal endian order -| to form a 128-bit floating-point value. -*----------------------------------------------------------------------------*/ -void - softfloat_f128MToCommonNaN( const uint32_t *aWPtr, struct commonNaN *zPtr ); - -/*---------------------------------------------------------------------------- -| Converts the common NaN pointed to by 'aPtr' into a 128-bit floating-point -| NaN, and stores this NaN at the location pointed to by 'zWPtr'. Argument -| 'zWPtr' points to an array of four 32-bit elements that concatenate in the -| platform's normal endian order to form a 128-bit floating-point value. -*----------------------------------------------------------------------------*/ -void - softfloat_commonNaNToF128M( const struct commonNaN *aPtr, uint32_t *zWPtr ); - -/*---------------------------------------------------------------------------- -| Assuming at least one of the two 128-bit floating-point values pointed to by -| 'aWPtr' and 'bWPtr' is a NaN, stores the combined NaN result at the location -| pointed to by 'zWPtr'. If either original floating-point value is a -| signaling NaN, the invalid exception is raised. Each of 'aWPtr', 'bWPtr', -| and 'zWPtr' points to an array of four 32-bit elements that concatenate in -| the platform's normal endian order to form a 128-bit floating-point value. -*----------------------------------------------------------------------------*/ -void - softfloat_propagateNaNF128M( - const uint32_t *aWPtr, const uint32_t *bWPtr, uint32_t *zWPtr ); - -#endif - -#endif - diff --git a/deps/SoftFloat-3e/source/8086/extF80M_isSignalingNaN.c b/deps/SoftFloat-3e/source/8086/extF80M_isSignalingNaN.c deleted file mode 100644 index 85ee211c28d7..000000000000 --- a/deps/SoftFloat-3e/source/8086/extF80M_isSignalingNaN.c +++ /dev/null @@ -1,57 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "softfloat.h" - -/*---------------------------------------------------------------------------- -*----------------------------------------------------------------------------*/ -bool extF80M_isSignalingNaN( const extFloat80_t *aPtr ) -{ - const struct extFloat80M *aSPtr; - uint64_t uiA0; - - aSPtr = (const struct extFloat80M *) aPtr; - if ( (aSPtr->signExp & 0x7FFF) != 0x7FFF ) return false; - uiA0 = aSPtr->signif; - return - ! (uiA0 & UINT64_C( 0x4000000000000000 )) - && (uiA0 & UINT64_C( 0x3FFFFFFFFFFFFFFF)); - -} - diff --git a/deps/SoftFloat-3e/source/8086/f128M_isSignalingNaN.c b/deps/SoftFloat-3e/source/8086/f128M_isSignalingNaN.c deleted file mode 100644 index 79a707771672..000000000000 --- a/deps/SoftFloat-3e/source/8086/f128M_isSignalingNaN.c +++ /dev/null @@ -1,60 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "primitives.h" -#include "softfloat.h" - -/*---------------------------------------------------------------------------- -*----------------------------------------------------------------------------*/ -bool f128M_isSignalingNaN( const float128_t *aPtr ) -{ - const uint32_t *aWPtr; - uint32_t uiA96; - - aWPtr = (const uint32_t *) aPtr; - uiA96 = aWPtr[indexWordHi( 4 )]; - if ( (uiA96 & 0x7FFF8000) != 0x7FFF0000 ) return false; - return - ((uiA96 & 0x00007FFF) != 0) - || ((aWPtr[indexWord( 4, 2 )] | aWPtr[indexWord( 4, 1 )] - | aWPtr[indexWord( 4, 0 )]) - != 0); - -} - diff --git a/deps/SoftFloat-3e/source/8086/s_commonNaNToExtF80M.c b/deps/SoftFloat-3e/source/8086/s_commonNaNToExtF80M.c deleted file mode 100644 index 3405b3ba4efb..000000000000 --- a/deps/SoftFloat-3e/source/8086/s_commonNaNToExtF80M.c +++ /dev/null @@ -1,56 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" - -/*---------------------------------------------------------------------------- -| Converts the common NaN pointed to by `aPtr' into an 80-bit extended -| floating-point NaN, and stores this NaN at the location pointed to by -| `zSPtr'. -*----------------------------------------------------------------------------*/ -void - softfloat_commonNaNToExtF80M( - const struct commonNaN *aPtr, struct extFloat80M *zSPtr ) -{ - - zSPtr->signExp = packToExtF80UI64( aPtr->sign, 0x7FFF ); - zSPtr->signif = UINT64_C( 0xC000000000000000 ) | aPtr->v64>>1; - -} - diff --git a/deps/SoftFloat-3e/source/8086/s_commonNaNToExtF80UI.c b/deps/SoftFloat-3e/source/8086/s_commonNaNToExtF80UI.c deleted file mode 100644 index cb7424f430c9..000000000000 --- a/deps/SoftFloat-3e/source/8086/s_commonNaNToExtF80UI.c +++ /dev/null @@ -1,56 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "primitives.h" -#include "specialize.h" - -/*---------------------------------------------------------------------------- -| Converts the common NaN pointed to by `aPtr' into an 80-bit extended -| floating-point NaN, and returns the bit pattern of this value as an unsigned -| integer. -*----------------------------------------------------------------------------*/ -struct uint128 softfloat_commonNaNToExtF80UI( const struct commonNaN *aPtr ) -{ - struct uint128 uiZ; - - uiZ.v64 = (uint_fast16_t) aPtr->sign<<15 | 0x7FFF; - uiZ.v0 = UINT64_C( 0xC000000000000000 ) | aPtr->v64>>1; - return uiZ; - -} - diff --git a/deps/SoftFloat-3e/source/8086/s_commonNaNToF128M.c b/deps/SoftFloat-3e/source/8086/s_commonNaNToF128M.c deleted file mode 100644 index e7ea80258916..000000000000 --- a/deps/SoftFloat-3e/source/8086/s_commonNaNToF128M.c +++ /dev/null @@ -1,56 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "primitives.h" -#include "specialize.h" - -/*---------------------------------------------------------------------------- -| Converts the common NaN pointed to by `aPtr' into a 128-bit floating-point -| NaN, and stores this NaN at the location pointed to by `zWPtr'. Argument -| `zWPtr' points to an array of four 32-bit elements that concatenate in the -| platform's normal endian order to form a 128-bit floating-point value. -*----------------------------------------------------------------------------*/ -void - softfloat_commonNaNToF128M( const struct commonNaN *aPtr, uint32_t *zWPtr ) -{ - - softfloat_shortShiftRight128M( (const uint32_t *) &aPtr->v0, 16, zWPtr ); - zWPtr[indexWordHi( 4 )] |= (uint32_t) aPtr->sign<<31 | 0x7FFF8000; - -} - diff --git a/deps/SoftFloat-3e/source/8086/s_commonNaNToF128UI.c b/deps/SoftFloat-3e/source/8086/s_commonNaNToF128UI.c deleted file mode 100644 index 7a9423bea290..000000000000 --- a/deps/SoftFloat-3e/source/8086/s_commonNaNToF128UI.c +++ /dev/null @@ -1,55 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "primitives.h" -#include "specialize.h" - -/*---------------------------------------------------------------------------- -| Converts the common NaN pointed to by `aPtr' into a 128-bit floating-point -| NaN, and returns the bit pattern of this value as an unsigned integer. -*----------------------------------------------------------------------------*/ -struct uint128 softfloat_commonNaNToF128UI( const struct commonNaN *aPtr ) -{ - struct uint128 uiZ; - - uiZ = softfloat_shortShiftRight128( aPtr->v64, aPtr->v0, 16 ); - uiZ.v64 |= (uint_fast64_t) aPtr->sign<<63 | UINT64_C( 0x7FFF800000000000 ); - return uiZ; - -} - diff --git a/deps/SoftFloat-3e/source/8086/s_commonNaNToF16UI.c b/deps/SoftFloat-3e/source/8086/s_commonNaNToF16UI.c deleted file mode 100644 index d4e458a94143..000000000000 --- a/deps/SoftFloat-3e/source/8086/s_commonNaNToF16UI.c +++ /dev/null @@ -1,51 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "specialize.h" - -/*---------------------------------------------------------------------------- -| Converts the common NaN pointed to by `aPtr' into a 16-bit floating-point -| NaN, and returns the bit pattern of this value as an unsigned integer. -*----------------------------------------------------------------------------*/ -uint_fast16_t softfloat_commonNaNToF16UI( const struct commonNaN *aPtr ) -{ - - return (uint_fast16_t) aPtr->sign<<15 | 0x7E00 | aPtr->v64>>54; - -} - diff --git a/deps/SoftFloat-3e/source/8086/s_commonNaNToF32UI.c b/deps/SoftFloat-3e/source/8086/s_commonNaNToF32UI.c deleted file mode 100644 index ed6c2268f31f..000000000000 --- a/deps/SoftFloat-3e/source/8086/s_commonNaNToF32UI.c +++ /dev/null @@ -1,51 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "specialize.h" - -/*---------------------------------------------------------------------------- -| Converts the common NaN pointed to by `aPtr' into a 32-bit floating-point -| NaN, and returns the bit pattern of this value as an unsigned integer. -*----------------------------------------------------------------------------*/ -uint_fast32_t softfloat_commonNaNToF32UI( const struct commonNaN *aPtr ) -{ - - return (uint_fast32_t) aPtr->sign<<31 | 0x7FC00000 | aPtr->v64>>41; - -} - diff --git a/deps/SoftFloat-3e/source/8086/s_commonNaNToF64UI.c b/deps/SoftFloat-3e/source/8086/s_commonNaNToF64UI.c deleted file mode 100644 index 1182be3c9cdf..000000000000 --- a/deps/SoftFloat-3e/source/8086/s_commonNaNToF64UI.c +++ /dev/null @@ -1,53 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "specialize.h" - -/*---------------------------------------------------------------------------- -| Converts the common NaN pointed to by `aPtr' into a 64-bit floating-point -| NaN, and returns the bit pattern of this value as an unsigned integer. -*----------------------------------------------------------------------------*/ -uint_fast64_t softfloat_commonNaNToF64UI( const struct commonNaN *aPtr ) -{ - - return - (uint_fast64_t) aPtr->sign<<63 | UINT64_C( 0x7FF8000000000000 ) - | aPtr->v64>>12; - -} - diff --git a/deps/SoftFloat-3e/source/8086/s_extF80MToCommonNaN.c b/deps/SoftFloat-3e/source/8086/s_extF80MToCommonNaN.c deleted file mode 100644 index 00baf35f893a..000000000000 --- a/deps/SoftFloat-3e/source/8086/s_extF80MToCommonNaN.c +++ /dev/null @@ -1,62 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -/*---------------------------------------------------------------------------- -| Assuming the 80-bit extended floating-point value pointed to by `aSPtr' is -| a NaN, converts this NaN to the common NaN form, and stores the resulting -| common NaN at the location pointed to by `zPtr'. If the NaN is a signaling -| NaN, the invalid exception is raised. -*----------------------------------------------------------------------------*/ -void - softfloat_extF80MToCommonNaN( - const struct extFloat80M *aSPtr, struct commonNaN *zPtr ) -{ - - if ( extF80M_isSignalingNaN( (const extFloat80_t *) aSPtr ) ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - } - zPtr->sign = signExtF80UI64( aSPtr->signExp ); - zPtr->v64 = aSPtr->signif<<1; - zPtr->v0 = 0; - -} - diff --git a/deps/SoftFloat-3e/source/8086/s_extF80UIToCommonNaN.c b/deps/SoftFloat-3e/source/8086/s_extF80UIToCommonNaN.c deleted file mode 100644 index ab6311ef2906..000000000000 --- a/deps/SoftFloat-3e/source/8086/s_extF80UIToCommonNaN.c +++ /dev/null @@ -1,62 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "specialize.h" -#include "softfloat.h" - -/*---------------------------------------------------------------------------- -| Assuming the unsigned integer formed from concatenating `uiA64' and `uiA0' -| has the bit pattern of an 80-bit extended floating-point NaN, converts -| this NaN to the common NaN form, and stores the resulting common NaN at the -| location pointed to by `zPtr'. If the NaN is a signaling NaN, the invalid -| exception is raised. -*----------------------------------------------------------------------------*/ -void - softfloat_extF80UIToCommonNaN( - uint_fast16_t uiA64, uint_fast64_t uiA0, struct commonNaN *zPtr ) -{ - - if ( softfloat_isSigNaNExtF80UI( uiA64, uiA0 ) ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - } - zPtr->sign = uiA64>>15; - zPtr->v64 = uiA0<<1; - zPtr->v0 = 0; - -} - diff --git a/deps/SoftFloat-3e/source/8086/s_f128MToCommonNaN.c b/deps/SoftFloat-3e/source/8086/s_f128MToCommonNaN.c deleted file mode 100644 index 55ec25b58c8d..000000000000 --- a/deps/SoftFloat-3e/source/8086/s_f128MToCommonNaN.c +++ /dev/null @@ -1,62 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "primitives.h" -#include "specialize.h" -#include "softfloat.h" - -/*---------------------------------------------------------------------------- -| Assuming the 128-bit floating-point value pointed to by `aWPtr' is a NaN, -| converts this NaN to the common NaN form, and stores the resulting common -| NaN at the location pointed to by `zPtr'. If the NaN is a signaling NaN, -| the invalid exception is raised. Argument `aWPtr' points to an array of -| four 32-bit elements that concatenate in the platform's normal endian order -| to form a 128-bit floating-point value. -*----------------------------------------------------------------------------*/ -void - softfloat_f128MToCommonNaN( const uint32_t *aWPtr, struct commonNaN *zPtr ) -{ - - if ( f128M_isSignalingNaN( (const float128_t *) aWPtr ) ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - } - zPtr->sign = aWPtr[indexWordHi( 4 )]>>31; - softfloat_shortShiftLeft128M( aWPtr, 16, (uint32_t *) &zPtr->v0 ); - -} - diff --git a/deps/SoftFloat-3e/source/8086/s_f128UIToCommonNaN.c b/deps/SoftFloat-3e/source/8086/s_f128UIToCommonNaN.c deleted file mode 100644 index f838f02aaf1f..000000000000 --- a/deps/SoftFloat-3e/source/8086/s_f128UIToCommonNaN.c +++ /dev/null @@ -1,65 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "primitives.h" -#include "specialize.h" -#include "softfloat.h" - -/*---------------------------------------------------------------------------- -| Assuming the unsigned integer formed from concatenating `uiA64' and `uiA0' -| has the bit pattern of a 128-bit floating-point NaN, converts this NaN to -| the common NaN form, and stores the resulting common NaN at the location -| pointed to by `zPtr'. If the NaN is a signaling NaN, the invalid exception -| is raised. -*----------------------------------------------------------------------------*/ -void - softfloat_f128UIToCommonNaN( - uint_fast64_t uiA64, uint_fast64_t uiA0, struct commonNaN *zPtr ) -{ - struct uint128 NaNSig; - - if ( softfloat_isSigNaNF128UI( uiA64, uiA0 ) ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - } - NaNSig = softfloat_shortShiftLeft128( uiA64, uiA0, 16 ); - zPtr->sign = uiA64>>63; - zPtr->v64 = NaNSig.v64; - zPtr->v0 = NaNSig.v0; - -} - diff --git a/deps/SoftFloat-3e/source/8086/s_f16UIToCommonNaN.c b/deps/SoftFloat-3e/source/8086/s_f16UIToCommonNaN.c deleted file mode 100644 index c1e242d23684..000000000000 --- a/deps/SoftFloat-3e/source/8086/s_f16UIToCommonNaN.c +++ /dev/null @@ -1,59 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "specialize.h" -#include "softfloat.h" - -/*---------------------------------------------------------------------------- -| Assuming `uiA' has the bit pattern of a 16-bit floating-point NaN, converts -| this NaN to the common NaN form, and stores the resulting common NaN at the -| location pointed to by `zPtr'. If the NaN is a signaling NaN, the invalid -| exception is raised. -*----------------------------------------------------------------------------*/ -void softfloat_f16UIToCommonNaN( uint_fast16_t uiA, struct commonNaN *zPtr ) -{ - - if ( softfloat_isSigNaNF16UI( uiA ) ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - } - zPtr->sign = uiA>>15; - zPtr->v64 = (uint_fast64_t) uiA<<54; - zPtr->v0 = 0; - -} - diff --git a/deps/SoftFloat-3e/source/8086/s_f32UIToCommonNaN.c b/deps/SoftFloat-3e/source/8086/s_f32UIToCommonNaN.c deleted file mode 100644 index b21ba660398d..000000000000 --- a/deps/SoftFloat-3e/source/8086/s_f32UIToCommonNaN.c +++ /dev/null @@ -1,59 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "specialize.h" -#include "softfloat.h" - -/*---------------------------------------------------------------------------- -| Assuming `uiA' has the bit pattern of a 32-bit floating-point NaN, converts -| this NaN to the common NaN form, and stores the resulting common NaN at the -| location pointed to by `zPtr'. If the NaN is a signaling NaN, the invalid -| exception is raised. -*----------------------------------------------------------------------------*/ -void softfloat_f32UIToCommonNaN( uint_fast32_t uiA, struct commonNaN *zPtr ) -{ - - if ( softfloat_isSigNaNF32UI( uiA ) ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - } - zPtr->sign = uiA>>31; - zPtr->v64 = (uint_fast64_t) uiA<<41; - zPtr->v0 = 0; - -} - diff --git a/deps/SoftFloat-3e/source/8086/s_f64UIToCommonNaN.c b/deps/SoftFloat-3e/source/8086/s_f64UIToCommonNaN.c deleted file mode 100644 index 6529d2ee5fd1..000000000000 --- a/deps/SoftFloat-3e/source/8086/s_f64UIToCommonNaN.c +++ /dev/null @@ -1,59 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "specialize.h" -#include "softfloat.h" - -/*---------------------------------------------------------------------------- -| Assuming `uiA' has the bit pattern of a 64-bit floating-point NaN, converts -| this NaN to the common NaN form, and stores the resulting common NaN at the -| location pointed to by `zPtr'. If the NaN is a signaling NaN, the invalid -| exception is raised. -*----------------------------------------------------------------------------*/ -void softfloat_f64UIToCommonNaN( uint_fast64_t uiA, struct commonNaN *zPtr ) -{ - - if ( softfloat_isSigNaNF64UI( uiA ) ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - } - zPtr->sign = uiA>>63; - zPtr->v64 = uiA<<12; - zPtr->v0 = 0; - -} - diff --git a/deps/SoftFloat-3e/source/8086/s_propagateNaNExtF80M.c b/deps/SoftFloat-3e/source/8086/s_propagateNaNExtF80M.c deleted file mode 100644 index ea1d57a78814..000000000000 --- a/deps/SoftFloat-3e/source/8086/s_propagateNaNExtF80M.c +++ /dev/null @@ -1,107 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -/*---------------------------------------------------------------------------- -| Assuming at least one of the two 80-bit extended floating-point values -| pointed to by `aSPtr' and `bSPtr' is a NaN, stores the combined NaN result -| at the location pointed to by `zSPtr'. If either original floating-point -| value is a signaling NaN, the invalid exception is raised. -*----------------------------------------------------------------------------*/ -void - softfloat_propagateNaNExtF80M( - const struct extFloat80M *aSPtr, - const struct extFloat80M *bSPtr, - struct extFloat80M *zSPtr - ) -{ - bool isSigNaNA; - const struct extFloat80M *sPtr; - bool isSigNaNB; - uint_fast16_t uiB64; - uint64_t uiB0; - uint_fast16_t uiA64; - uint64_t uiA0; - uint_fast16_t uiMagA64, uiMagB64; - - isSigNaNA = extF80M_isSignalingNaN( (const extFloat80_t *) aSPtr ); - sPtr = aSPtr; - if ( ! bSPtr ) { - if ( isSigNaNA ) softfloat_raiseFlags( softfloat_flag_invalid ); - goto copy; - } - isSigNaNB = extF80M_isSignalingNaN( (const extFloat80_t *) bSPtr ); - if ( isSigNaNA | isSigNaNB ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - if ( isSigNaNA ) { - uiB64 = bSPtr->signExp; - if ( isSigNaNB ) goto returnLargerUIMag; - uiB0 = bSPtr->signif; - if ( isNaNExtF80UI( uiB64, uiB0 ) ) goto copyB; - goto copy; - } else { - uiA64 = aSPtr->signExp; - uiA0 = aSPtr->signif; - if ( isNaNExtF80UI( uiA64, uiA0 ) ) goto copy; - goto copyB; - } - } - uiB64 = bSPtr->signExp; - returnLargerUIMag: - uiA64 = aSPtr->signExp; - uiMagA64 = uiA64 & 0x7FFF; - uiMagB64 = uiB64 & 0x7FFF; - if ( uiMagA64 < uiMagB64 ) goto copyB; - if ( uiMagB64 < uiMagA64 ) goto copy; - uiA0 = aSPtr->signif; - uiB0 = bSPtr->signif; - if ( uiA0 < uiB0 ) goto copyB; - if ( uiB0 < uiA0 ) goto copy; - if ( uiA64 < uiB64 ) goto copy; - copyB: - sPtr = bSPtr; - copy: - zSPtr->signExp = sPtr->signExp; - zSPtr->signif = sPtr->signif | UINT64_C( 0xC000000000000000 ); - -} - diff --git a/deps/SoftFloat-3e/source/8086/s_propagateNaNExtF80UI.c b/deps/SoftFloat-3e/source/8086/s_propagateNaNExtF80UI.c deleted file mode 100644 index cc3f0f42c55d..000000000000 --- a/deps/SoftFloat-3e/source/8086/s_propagateNaNExtF80UI.c +++ /dev/null @@ -1,106 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2018 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -/*---------------------------------------------------------------------------- -| Interpreting the unsigned integer formed from concatenating 'uiA64' and -| 'uiA0' as an 80-bit extended floating-point value, and likewise interpreting -| the unsigned integer formed from concatenating 'uiB64' and 'uiB0' as another -| 80-bit extended floating-point value, and assuming at least on of these -| floating-point values is a NaN, returns the bit pattern of the combined NaN -| result. If either original floating-point value is a signaling NaN, the -| invalid exception is raised. -*----------------------------------------------------------------------------*/ -struct uint128 - softfloat_propagateNaNExtF80UI( - uint_fast16_t uiA64, - uint_fast64_t uiA0, - uint_fast16_t uiB64, - uint_fast64_t uiB0 - ) -{ - bool isSigNaNA, isSigNaNB; - uint_fast64_t uiNonsigA0, uiNonsigB0; - uint_fast16_t uiMagA64, uiMagB64; - struct uint128 uiZ; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - isSigNaNA = softfloat_isSigNaNExtF80UI( uiA64, uiA0 ); - isSigNaNB = softfloat_isSigNaNExtF80UI( uiB64, uiB0 ); - /*------------------------------------------------------------------------ - | Make NaNs non-signaling. - *------------------------------------------------------------------------*/ - uiNonsigA0 = uiA0 | UINT64_C( 0xC000000000000000 ); - uiNonsigB0 = uiB0 | UINT64_C( 0xC000000000000000 ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( isSigNaNA | isSigNaNB ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - if ( isSigNaNA ) { - if ( isSigNaNB ) goto returnLargerMag; - if ( isNaNExtF80UI( uiB64, uiB0 ) ) goto returnB; - goto returnA; - } else { - if ( isNaNExtF80UI( uiA64, uiA0 ) ) goto returnA; - goto returnB; - } - } - returnLargerMag: - uiMagA64 = uiA64 & 0x7FFF; - uiMagB64 = uiB64 & 0x7FFF; - if ( uiMagA64 < uiMagB64 ) goto returnB; - if ( uiMagB64 < uiMagA64 ) goto returnA; - if ( uiA0 < uiB0 ) goto returnB; - if ( uiB0 < uiA0 ) goto returnA; - if ( uiA64 < uiB64 ) goto returnA; - returnB: - uiZ.v64 = uiB64; - uiZ.v0 = uiNonsigB0; - return uiZ; - returnA: - uiZ.v64 = uiA64; - uiZ.v0 = uiNonsigA0; - return uiZ; - -} - diff --git a/deps/SoftFloat-3e/source/8086/s_propagateNaNF128M.c b/deps/SoftFloat-3e/source/8086/s_propagateNaNF128M.c deleted file mode 100644 index 06554fbfe1ec..000000000000 --- a/deps/SoftFloat-3e/source/8086/s_propagateNaNF128M.c +++ /dev/null @@ -1,108 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -/*---------------------------------------------------------------------------- -| Assuming at least one of the two 128-bit floating-point values pointed to by -| `aWPtr' and `bWPtr' is a NaN, stores the combined NaN result at the location -| pointed to by `zWPtr'. If either original floating-point value is a -| signaling NaN, the invalid exception is raised. Each of `aWPtr', `bWPtr', -| and `zWPtr' points to an array of four 32-bit elements that concatenate in -| the platform's normal endian order to form a 128-bit floating-point value. -*----------------------------------------------------------------------------*/ -void - softfloat_propagateNaNF128M( - const uint32_t *aWPtr, const uint32_t *bWPtr, uint32_t *zWPtr ) -{ - bool isSigNaNA; - const uint32_t *ptr; - bool isSigNaNB; - uint32_t uiA96, uiB96, wordMagA, wordMagB; - - isSigNaNA = f128M_isSignalingNaN( (const float128_t *) aWPtr ); - ptr = aWPtr; - if ( ! bWPtr ) { - if ( isSigNaNA ) softfloat_raiseFlags( softfloat_flag_invalid ); - goto copy; - } - isSigNaNB = f128M_isSignalingNaN( (const float128_t *) bWPtr ); - if ( isSigNaNA | isSigNaNB ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - if ( isSigNaNA ) { - if ( isSigNaNB ) goto returnLargerUIMag; - if ( softfloat_isNaNF128M( bWPtr ) ) goto copyB; - goto copy; - } else { - if ( softfloat_isNaNF128M( aWPtr ) ) goto copy; - goto copyB; - } - } - returnLargerUIMag: - uiA96 = aWPtr[indexWordHi( 4 )]; - uiB96 = bWPtr[indexWordHi( 4 )]; - wordMagA = uiA96 & 0x7FFFFFFF; - wordMagB = uiB96 & 0x7FFFFFFF; - if ( wordMagA < wordMagB ) goto copyB; - if ( wordMagB < wordMagA ) goto copy; - wordMagA = aWPtr[indexWord( 4, 2 )]; - wordMagB = bWPtr[indexWord( 4, 2 )]; - if ( wordMagA < wordMagB ) goto copyB; - if ( wordMagB < wordMagA ) goto copy; - wordMagA = aWPtr[indexWord( 4, 1 )]; - wordMagB = bWPtr[indexWord( 4, 1 )]; - if ( wordMagA < wordMagB ) goto copyB; - if ( wordMagB < wordMagA ) goto copy; - wordMagA = aWPtr[indexWord( 4, 0 )]; - wordMagB = bWPtr[indexWord( 4, 0 )]; - if ( wordMagA < wordMagB ) goto copyB; - if ( wordMagB < wordMagA ) goto copy; - if ( uiA96 < uiB96 ) goto copy; - copyB: - ptr = bWPtr; - copy: - zWPtr[indexWordHi( 4 )] = ptr[indexWordHi( 4 )] | 0x00008000; - zWPtr[indexWord( 4, 2 )] = ptr[indexWord( 4, 2 )]; - zWPtr[indexWord( 4, 1 )] = ptr[indexWord( 4, 1 )]; - zWPtr[indexWord( 4, 0 )] = ptr[indexWord( 4, 0 )]; - -} - diff --git a/deps/SoftFloat-3e/source/8086/s_propagateNaNF128UI.c b/deps/SoftFloat-3e/source/8086/s_propagateNaNF128UI.c deleted file mode 100644 index 46b9f5f2c25a..000000000000 --- a/deps/SoftFloat-3e/source/8086/s_propagateNaNF128UI.c +++ /dev/null @@ -1,105 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2018 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -/*---------------------------------------------------------------------------- -| Interpreting the unsigned integer formed from concatenating 'uiA64' and -| 'uiA0' as a 128-bit floating-point value, and likewise interpreting the -| unsigned integer formed from concatenating 'uiB64' and 'uiB0' as another -| 128-bit floating-point value, and assuming at least on of these floating- -| point values is a NaN, returns the bit pattern of the combined NaN result. -| If either original floating-point value is a signaling NaN, the invalid -| exception is raised. -*----------------------------------------------------------------------------*/ -struct uint128 - softfloat_propagateNaNF128UI( - uint_fast64_t uiA64, - uint_fast64_t uiA0, - uint_fast64_t uiB64, - uint_fast64_t uiB0 - ) -{ - bool isSigNaNA, isSigNaNB; - uint_fast64_t uiNonsigA64, uiNonsigB64, uiMagA64, uiMagB64; - struct uint128 uiZ; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - isSigNaNA = softfloat_isSigNaNF128UI( uiA64, uiA0 ); - isSigNaNB = softfloat_isSigNaNF128UI( uiB64, uiB0 ); - /*------------------------------------------------------------------------ - | Make NaNs non-signaling. - *------------------------------------------------------------------------*/ - uiNonsigA64 = uiA64 | UINT64_C( 0x0000800000000000 ); - uiNonsigB64 = uiB64 | UINT64_C( 0x0000800000000000 ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( isSigNaNA | isSigNaNB ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - if ( isSigNaNA ) { - if ( isSigNaNB ) goto returnLargerMag; - if ( isNaNF128UI( uiB64, uiB0 ) ) goto returnB; - goto returnA; - } else { - if ( isNaNF128UI( uiA64, uiA0 ) ) goto returnA; - goto returnB; - } - } - returnLargerMag: - uiMagA64 = uiA64 & UINT64_C( 0x7FFFFFFFFFFFFFFF ); - uiMagB64 = uiB64 & UINT64_C( 0x7FFFFFFFFFFFFFFF ); - if ( uiMagA64 < uiMagB64 ) goto returnB; - if ( uiMagB64 < uiMagA64 ) goto returnA; - if ( uiA0 < uiB0 ) goto returnB; - if ( uiB0 < uiA0 ) goto returnA; - if ( uiNonsigA64 < uiNonsigB64 ) goto returnA; - returnB: - uiZ.v64 = uiNonsigB64; - uiZ.v0 = uiB0; - return uiZ; - returnA: - uiZ.v64 = uiNonsigA64; - uiZ.v0 = uiA0; - return uiZ; - -} - diff --git a/deps/SoftFloat-3e/source/8086/s_propagateNaNF16UI.c b/deps/SoftFloat-3e/source/8086/s_propagateNaNF16UI.c deleted file mode 100644 index 89cc0fe97ea2..000000000000 --- a/deps/SoftFloat-3e/source/8086/s_propagateNaNF16UI.c +++ /dev/null @@ -1,84 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2018 The Regents of the -University of California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -/*---------------------------------------------------------------------------- -| Interpreting 'uiA' and 'uiB' as the bit patterns of two 16-bit floating- -| point values, at least one of which is a NaN, returns the bit pattern of -| the combined NaN result. If either 'uiA' or 'uiB' has the pattern of a -| signaling NaN, the invalid exception is raised. -*----------------------------------------------------------------------------*/ -uint_fast16_t - softfloat_propagateNaNF16UI( uint_fast16_t uiA, uint_fast16_t uiB ) -{ - bool isSigNaNA, isSigNaNB; - uint_fast16_t uiNonsigA, uiNonsigB, uiMagA, uiMagB; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - isSigNaNA = softfloat_isSigNaNF16UI( uiA ); - isSigNaNB = softfloat_isSigNaNF16UI( uiB ); - /*------------------------------------------------------------------------ - | Make NaNs non-signaling. - *------------------------------------------------------------------------*/ - uiNonsigA = uiA | 0x0200; - uiNonsigB = uiB | 0x0200; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( isSigNaNA | isSigNaNB ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - if ( isSigNaNA ) { - if ( isSigNaNB ) goto returnLargerMag; - return isNaNF16UI( uiB ) ? uiNonsigB : uiNonsigA; - } else { - return isNaNF16UI( uiA ) ? uiNonsigA : uiNonsigB; - } - } - returnLargerMag: - uiMagA = uiA & 0x7FFF; - uiMagB = uiB & 0x7FFF; - if ( uiMagA < uiMagB ) return uiNonsigB; - if ( uiMagB < uiMagA ) return uiNonsigA; - return (uiNonsigA < uiNonsigB) ? uiNonsigA : uiNonsigB; - -} - diff --git a/deps/SoftFloat-3e/source/8086/s_propagateNaNF32UI.c b/deps/SoftFloat-3e/source/8086/s_propagateNaNF32UI.c deleted file mode 100644 index aeb6024acf96..000000000000 --- a/deps/SoftFloat-3e/source/8086/s_propagateNaNF32UI.c +++ /dev/null @@ -1,84 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2018 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -/*---------------------------------------------------------------------------- -| Interpreting 'uiA' and 'uiB' as the bit patterns of two 32-bit floating- -| point values, at least one of which is a NaN, returns the bit pattern of -| the combined NaN result. If either 'uiA' or 'uiB' has the pattern of a -| signaling NaN, the invalid exception is raised. -*----------------------------------------------------------------------------*/ -uint_fast32_t - softfloat_propagateNaNF32UI( uint_fast32_t uiA, uint_fast32_t uiB ) -{ - bool isSigNaNA, isSigNaNB; - uint_fast32_t uiNonsigA, uiNonsigB, uiMagA, uiMagB; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - isSigNaNA = softfloat_isSigNaNF32UI( uiA ); - isSigNaNB = softfloat_isSigNaNF32UI( uiB ); - /*------------------------------------------------------------------------ - | Make NaNs non-signaling. - *------------------------------------------------------------------------*/ - uiNonsigA = uiA | 0x00400000; - uiNonsigB = uiB | 0x00400000; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( isSigNaNA | isSigNaNB ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - if ( isSigNaNA ) { - if ( isSigNaNB ) goto returnLargerMag; - return isNaNF32UI( uiB ) ? uiNonsigB : uiNonsigA; - } else { - return isNaNF32UI( uiA ) ? uiNonsigA : uiNonsigB; - } - } - returnLargerMag: - uiMagA = uiA & 0x7FFFFFFF; - uiMagB = uiB & 0x7FFFFFFF; - if ( uiMagA < uiMagB ) return uiNonsigB; - if ( uiMagB < uiMagA ) return uiNonsigA; - return (uiNonsigA < uiNonsigB) ? uiNonsigA : uiNonsigB; - -} - diff --git a/deps/SoftFloat-3e/source/8086/s_propagateNaNF64UI.c b/deps/SoftFloat-3e/source/8086/s_propagateNaNF64UI.c deleted file mode 100644 index dabad402482a..000000000000 --- a/deps/SoftFloat-3e/source/8086/s_propagateNaNF64UI.c +++ /dev/null @@ -1,84 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2018 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -/*---------------------------------------------------------------------------- -| Interpreting 'uiA' and 'uiB' as the bit patterns of two 64-bit floating- -| point values, at least one of which is a NaN, returns the bit pattern of -| the combined NaN result. If either 'uiA' or 'uiB' has the pattern of a -| signaling NaN, the invalid exception is raised. -*----------------------------------------------------------------------------*/ -uint_fast64_t - softfloat_propagateNaNF64UI( uint_fast64_t uiA, uint_fast64_t uiB ) -{ - bool isSigNaNA, isSigNaNB; - uint_fast64_t uiNonsigA, uiNonsigB, uiMagA, uiMagB; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - isSigNaNA = softfloat_isSigNaNF64UI( uiA ); - isSigNaNB = softfloat_isSigNaNF64UI( uiB ); - /*------------------------------------------------------------------------ - | Make NaNs non-signaling. - *------------------------------------------------------------------------*/ - uiNonsigA = uiA | UINT64_C( 0x0008000000000000 ); - uiNonsigB = uiB | UINT64_C( 0x0008000000000000 ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( isSigNaNA | isSigNaNB ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - if ( isSigNaNA ) { - if ( isSigNaNB ) goto returnLargerMag; - return isNaNF64UI( uiB ) ? uiNonsigB : uiNonsigA; - } else { - return isNaNF64UI( uiA ) ? uiNonsigA : uiNonsigB; - } - } - returnLargerMag: - uiMagA = uiA & UINT64_C( 0x7FFFFFFFFFFFFFFF ); - uiMagB = uiB & UINT64_C( 0x7FFFFFFFFFFFFFFF ); - if ( uiMagA < uiMagB ) return uiNonsigB; - if ( uiMagB < uiMagA ) return uiNonsigA; - return (uiNonsigA < uiNonsigB) ? uiNonsigA : uiNonsigB; - -} - diff --git a/deps/SoftFloat-3e/source/8086/softfloat_raiseFlags.c b/deps/SoftFloat-3e/source/8086/softfloat_raiseFlags.c deleted file mode 100644 index 3115306beedd..000000000000 --- a/deps/SoftFloat-3e/source/8086/softfloat_raiseFlags.c +++ /dev/null @@ -1,52 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include "platform.h" -#include "softfloat.h" - -/*---------------------------------------------------------------------------- -| Raises the exceptions specified by `flags'. Floating-point traps can be -| defined here if desired. It is currently not possible for such a trap -| to substitute a result value. If traps are not implemented, this routine -| should be simply `softfloat_exceptionFlags |= flags;'. -*----------------------------------------------------------------------------*/ -void softfloat_raiseFlags( uint_fast8_t flags ) -{ - - softfloat_exceptionFlags |= flags; - -} - diff --git a/deps/SoftFloat-3e/source/8086/specialize.h b/deps/SoftFloat-3e/source/8086/specialize.h deleted file mode 100644 index 5fe119a1e1f1..000000000000 --- a/deps/SoftFloat-3e/source/8086/specialize.h +++ /dev/null @@ -1,376 +0,0 @@ - -/*============================================================================ - -This C header file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2018 The Regents of the -University of California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#ifndef specialize_h -#define specialize_h 1 - -#include -#include -#include "primitiveTypes.h" -#include "softfloat.h" - -/*---------------------------------------------------------------------------- -| Default value for 'softfloat_detectTininess'. -*----------------------------------------------------------------------------*/ -#define init_detectTininess softfloat_tininess_afterRounding - -/*---------------------------------------------------------------------------- -| The values to return on conversions to 32-bit integer formats that raise an -| invalid exception. -*----------------------------------------------------------------------------*/ -#define ui32_fromPosOverflow 0xFFFFFFFF -#define ui32_fromNegOverflow 0xFFFFFFFF -#define ui32_fromNaN 0xFFFFFFFF -#define i32_fromPosOverflow (-0x7FFFFFFF - 1) -#define i32_fromNegOverflow (-0x7FFFFFFF - 1) -#define i32_fromNaN (-0x7FFFFFFF - 1) - -/*---------------------------------------------------------------------------- -| The values to return on conversions to 64-bit integer formats that raise an -| invalid exception. -*----------------------------------------------------------------------------*/ -#define ui64_fromPosOverflow UINT64_C( 0xFFFFFFFFFFFFFFFF ) -#define ui64_fromNegOverflow UINT64_C( 0xFFFFFFFFFFFFFFFF ) -#define ui64_fromNaN UINT64_C( 0xFFFFFFFFFFFFFFFF ) -#define i64_fromPosOverflow (-INT64_C( 0x7FFFFFFFFFFFFFFF ) - 1) -#define i64_fromNegOverflow (-INT64_C( 0x7FFFFFFFFFFFFFFF ) - 1) -#define i64_fromNaN (-INT64_C( 0x7FFFFFFFFFFFFFFF ) - 1) - -/*---------------------------------------------------------------------------- -| "Common NaN" structure, used to transfer NaN representations from one format -| to another. -*----------------------------------------------------------------------------*/ -struct commonNaN { - bool sign; -#ifdef LITTLEENDIAN - uint64_t v0, v64; -#else - uint64_t v64, v0; -#endif -}; - -/*---------------------------------------------------------------------------- -| The bit pattern for a default generated 16-bit floating-point NaN. -*----------------------------------------------------------------------------*/ -#define defaultNaNF16UI 0xFE00 - -/*---------------------------------------------------------------------------- -| Returns true when 16-bit unsigned integer 'uiA' has the bit pattern of a -| 16-bit floating-point signaling NaN. -| Note: This macro evaluates its argument more than once. -*----------------------------------------------------------------------------*/ -#define softfloat_isSigNaNF16UI( uiA ) ((((uiA) & 0x7E00) == 0x7C00) && ((uiA) & 0x01FF)) - -/*---------------------------------------------------------------------------- -| Assuming 'uiA' has the bit pattern of a 16-bit floating-point NaN, converts -| this NaN to the common NaN form, and stores the resulting common NaN at the -| location pointed to by 'zPtr'. If the NaN is a signaling NaN, the invalid -| exception is raised. -*----------------------------------------------------------------------------*/ -void softfloat_f16UIToCommonNaN( uint_fast16_t uiA, struct commonNaN *zPtr ); - -/*---------------------------------------------------------------------------- -| Converts the common NaN pointed to by 'aPtr' into a 16-bit floating-point -| NaN, and returns the bit pattern of this value as an unsigned integer. -*----------------------------------------------------------------------------*/ -uint_fast16_t softfloat_commonNaNToF16UI( const struct commonNaN *aPtr ); - -/*---------------------------------------------------------------------------- -| Interpreting 'uiA' and 'uiB' as the bit patterns of two 16-bit floating- -| point values, at least one of which is a NaN, returns the bit pattern of -| the combined NaN result. If either 'uiA' or 'uiB' has the pattern of a -| signaling NaN, the invalid exception is raised. -*----------------------------------------------------------------------------*/ -uint_fast16_t - softfloat_propagateNaNF16UI( uint_fast16_t uiA, uint_fast16_t uiB ); - -/*---------------------------------------------------------------------------- -| The bit pattern for a default generated 32-bit floating-point NaN. -*----------------------------------------------------------------------------*/ -#define defaultNaNF32UI 0xFFC00000 - -/*---------------------------------------------------------------------------- -| Returns true when 32-bit unsigned integer 'uiA' has the bit pattern of a -| 32-bit floating-point signaling NaN. -| Note: This macro evaluates its argument more than once. -*----------------------------------------------------------------------------*/ -#define softfloat_isSigNaNF32UI( uiA ) ((((uiA) & 0x7FC00000) == 0x7F800000) && ((uiA) & 0x003FFFFF)) - -/*---------------------------------------------------------------------------- -| Assuming 'uiA' has the bit pattern of a 32-bit floating-point NaN, converts -| this NaN to the common NaN form, and stores the resulting common NaN at the -| location pointed to by 'zPtr'. If the NaN is a signaling NaN, the invalid -| exception is raised. -*----------------------------------------------------------------------------*/ -void softfloat_f32UIToCommonNaN( uint_fast32_t uiA, struct commonNaN *zPtr ); - -/*---------------------------------------------------------------------------- -| Converts the common NaN pointed to by 'aPtr' into a 32-bit floating-point -| NaN, and returns the bit pattern of this value as an unsigned integer. -*----------------------------------------------------------------------------*/ -uint_fast32_t softfloat_commonNaNToF32UI( const struct commonNaN *aPtr ); - -/*---------------------------------------------------------------------------- -| Interpreting 'uiA' and 'uiB' as the bit patterns of two 32-bit floating- -| point values, at least one of which is a NaN, returns the bit pattern of -| the combined NaN result. If either 'uiA' or 'uiB' has the pattern of a -| signaling NaN, the invalid exception is raised. -*----------------------------------------------------------------------------*/ -uint_fast32_t - softfloat_propagateNaNF32UI( uint_fast32_t uiA, uint_fast32_t uiB ); - -/*---------------------------------------------------------------------------- -| The bit pattern for a default generated 64-bit floating-point NaN. -*----------------------------------------------------------------------------*/ -#define defaultNaNF64UI UINT64_C( 0xFFF8000000000000 ) - -/*---------------------------------------------------------------------------- -| Returns true when 64-bit unsigned integer 'uiA' has the bit pattern of a -| 64-bit floating-point signaling NaN. -| Note: This macro evaluates its argument more than once. -*----------------------------------------------------------------------------*/ -#define softfloat_isSigNaNF64UI( uiA ) ((((uiA) & UINT64_C( 0x7FF8000000000000 )) == UINT64_C( 0x7FF0000000000000 )) && ((uiA) & UINT64_C( 0x0007FFFFFFFFFFFF ))) - -/*---------------------------------------------------------------------------- -| Assuming 'uiA' has the bit pattern of a 64-bit floating-point NaN, converts -| this NaN to the common NaN form, and stores the resulting common NaN at the -| location pointed to by 'zPtr'. If the NaN is a signaling NaN, the invalid -| exception is raised. -*----------------------------------------------------------------------------*/ -void softfloat_f64UIToCommonNaN( uint_fast64_t uiA, struct commonNaN *zPtr ); - -/*---------------------------------------------------------------------------- -| Converts the common NaN pointed to by 'aPtr' into a 64-bit floating-point -| NaN, and returns the bit pattern of this value as an unsigned integer. -*----------------------------------------------------------------------------*/ -uint_fast64_t softfloat_commonNaNToF64UI( const struct commonNaN *aPtr ); - -/*---------------------------------------------------------------------------- -| Interpreting 'uiA' and 'uiB' as the bit patterns of two 64-bit floating- -| point values, at least one of which is a NaN, returns the bit pattern of -| the combined NaN result. If either 'uiA' or 'uiB' has the pattern of a -| signaling NaN, the invalid exception is raised. -*----------------------------------------------------------------------------*/ -uint_fast64_t - softfloat_propagateNaNF64UI( uint_fast64_t uiA, uint_fast64_t uiB ); - -/*---------------------------------------------------------------------------- -| The bit pattern for a default generated 80-bit extended floating-point NaN. -*----------------------------------------------------------------------------*/ -#define defaultNaNExtF80UI64 0xFFFF -#define defaultNaNExtF80UI0 UINT64_C( 0xC000000000000000 ) - -/*---------------------------------------------------------------------------- -| Returns true when the 80-bit unsigned integer formed from concatenating -| 16-bit 'uiA64' and 64-bit 'uiA0' has the bit pattern of an 80-bit extended -| floating-point signaling NaN. -| Note: This macro evaluates its arguments more than once. -*----------------------------------------------------------------------------*/ -#define softfloat_isSigNaNExtF80UI( uiA64, uiA0 ) ((((uiA64) & 0x7FFF) == 0x7FFF) && ! ((uiA0) & UINT64_C( 0x4000000000000000 )) && ((uiA0) & UINT64_C( 0x3FFFFFFFFFFFFFFF ))) - -#ifdef SOFTFLOAT_FAST_INT64 - -/*---------------------------------------------------------------------------- -| The following functions are needed only when 'SOFTFLOAT_FAST_INT64' is -| defined. -*----------------------------------------------------------------------------*/ - -/*---------------------------------------------------------------------------- -| Assuming the unsigned integer formed from concatenating 'uiA64' and 'uiA0' -| has the bit pattern of an 80-bit extended floating-point NaN, converts -| this NaN to the common NaN form, and stores the resulting common NaN at the -| location pointed to by 'zPtr'. If the NaN is a signaling NaN, the invalid -| exception is raised. -*----------------------------------------------------------------------------*/ -void - softfloat_extF80UIToCommonNaN( - uint_fast16_t uiA64, uint_fast64_t uiA0, struct commonNaN *zPtr ); - -/*---------------------------------------------------------------------------- -| Converts the common NaN pointed to by 'aPtr' into an 80-bit extended -| floating-point NaN, and returns the bit pattern of this value as an unsigned -| integer. -*----------------------------------------------------------------------------*/ -struct uint128 softfloat_commonNaNToExtF80UI( const struct commonNaN *aPtr ); - -/*---------------------------------------------------------------------------- -| Interpreting the unsigned integer formed from concatenating 'uiA64' and -| 'uiA0' as an 80-bit extended floating-point value, and likewise interpreting -| the unsigned integer formed from concatenating 'uiB64' and 'uiB0' as another -| 80-bit extended floating-point value, and assuming at least on of these -| floating-point values is a NaN, returns the bit pattern of the combined NaN -| result. If either original floating-point value is a signaling NaN, the -| invalid exception is raised. -*----------------------------------------------------------------------------*/ -struct uint128 - softfloat_propagateNaNExtF80UI( - uint_fast16_t uiA64, - uint_fast64_t uiA0, - uint_fast16_t uiB64, - uint_fast64_t uiB0 - ); - -/*---------------------------------------------------------------------------- -| The bit pattern for a default generated 128-bit floating-point NaN. -*----------------------------------------------------------------------------*/ -#define defaultNaNF128UI64 UINT64_C( 0xFFFF800000000000 ) -#define defaultNaNF128UI0 UINT64_C( 0 ) - -/*---------------------------------------------------------------------------- -| Returns true when the 128-bit unsigned integer formed from concatenating -| 64-bit 'uiA64' and 64-bit 'uiA0' has the bit pattern of a 128-bit floating- -| point signaling NaN. -| Note: This macro evaluates its arguments more than once. -*----------------------------------------------------------------------------*/ -#define softfloat_isSigNaNF128UI( uiA64, uiA0 ) ((((uiA64) & UINT64_C( 0x7FFF800000000000 )) == UINT64_C( 0x7FFF000000000000 )) && ((uiA0) || ((uiA64) & UINT64_C( 0x00007FFFFFFFFFFF )))) - -/*---------------------------------------------------------------------------- -| Assuming the unsigned integer formed from concatenating 'uiA64' and 'uiA0' -| has the bit pattern of a 128-bit floating-point NaN, converts this NaN to -| the common NaN form, and stores the resulting common NaN at the location -| pointed to by 'zPtr'. If the NaN is a signaling NaN, the invalid exception -| is raised. -*----------------------------------------------------------------------------*/ -void - softfloat_f128UIToCommonNaN( - uint_fast64_t uiA64, uint_fast64_t uiA0, struct commonNaN *zPtr ); - -/*---------------------------------------------------------------------------- -| Converts the common NaN pointed to by 'aPtr' into a 128-bit floating-point -| NaN, and returns the bit pattern of this value as an unsigned integer. -*----------------------------------------------------------------------------*/ -struct uint128 softfloat_commonNaNToF128UI( const struct commonNaN * ); - -/*---------------------------------------------------------------------------- -| Interpreting the unsigned integer formed from concatenating 'uiA64' and -| 'uiA0' as a 128-bit floating-point value, and likewise interpreting the -| unsigned integer formed from concatenating 'uiB64' and 'uiB0' as another -| 128-bit floating-point value, and assuming at least on of these floating- -| point values is a NaN, returns the bit pattern of the combined NaN result. -| If either original floating-point value is a signaling NaN, the invalid -| exception is raised. -*----------------------------------------------------------------------------*/ -struct uint128 - softfloat_propagateNaNF128UI( - uint_fast64_t uiA64, - uint_fast64_t uiA0, - uint_fast64_t uiB64, - uint_fast64_t uiB0 - ); - -#else - -/*---------------------------------------------------------------------------- -| The following functions are needed only when 'SOFTFLOAT_FAST_INT64' is not -| defined. -*----------------------------------------------------------------------------*/ - -/*---------------------------------------------------------------------------- -| Assuming the 80-bit extended floating-point value pointed to by 'aSPtr' is -| a NaN, converts this NaN to the common NaN form, and stores the resulting -| common NaN at the location pointed to by 'zPtr'. If the NaN is a signaling -| NaN, the invalid exception is raised. -*----------------------------------------------------------------------------*/ -void - softfloat_extF80MToCommonNaN( - const struct extFloat80M *aSPtr, struct commonNaN *zPtr ); - -/*---------------------------------------------------------------------------- -| Converts the common NaN pointed to by 'aPtr' into an 80-bit extended -| floating-point NaN, and stores this NaN at the location pointed to by -| 'zSPtr'. -*----------------------------------------------------------------------------*/ -void - softfloat_commonNaNToExtF80M( - const struct commonNaN *aPtr, struct extFloat80M *zSPtr ); - -/*---------------------------------------------------------------------------- -| Assuming at least one of the two 80-bit extended floating-point values -| pointed to by 'aSPtr' and 'bSPtr' is a NaN, stores the combined NaN result -| at the location pointed to by 'zSPtr'. If either original floating-point -| value is a signaling NaN, the invalid exception is raised. -*----------------------------------------------------------------------------*/ -void - softfloat_propagateNaNExtF80M( - const struct extFloat80M *aSPtr, - const struct extFloat80M *bSPtr, - struct extFloat80M *zSPtr - ); - -/*---------------------------------------------------------------------------- -| The bit pattern for a default generated 128-bit floating-point NaN. -*----------------------------------------------------------------------------*/ -#define defaultNaNF128UI96 0xFFFF8000 -#define defaultNaNF128UI64 0 -#define defaultNaNF128UI32 0 -#define defaultNaNF128UI0 0 - -/*---------------------------------------------------------------------------- -| Assuming the 128-bit floating-point value pointed to by 'aWPtr' is a NaN, -| converts this NaN to the common NaN form, and stores the resulting common -| NaN at the location pointed to by 'zPtr'. If the NaN is a signaling NaN, -| the invalid exception is raised. Argument 'aWPtr' points to an array of -| four 32-bit elements that concatenate in the platform's normal endian order -| to form a 128-bit floating-point value. -*----------------------------------------------------------------------------*/ -void - softfloat_f128MToCommonNaN( const uint32_t *aWPtr, struct commonNaN *zPtr ); - -/*---------------------------------------------------------------------------- -| Converts the common NaN pointed to by 'aPtr' into a 128-bit floating-point -| NaN, and stores this NaN at the location pointed to by 'zWPtr'. Argument -| 'zWPtr' points to an array of four 32-bit elements that concatenate in the -| platform's normal endian order to form a 128-bit floating-point value. -*----------------------------------------------------------------------------*/ -void - softfloat_commonNaNToF128M( const struct commonNaN *aPtr, uint32_t *zWPtr ); - -/*---------------------------------------------------------------------------- -| Assuming at least one of the two 128-bit floating-point values pointed to by -| 'aWPtr' and 'bWPtr' is a NaN, stores the combined NaN result at the location -| pointed to by 'zWPtr'. If either original floating-point value is a -| signaling NaN, the invalid exception is raised. Each of 'aWPtr', 'bWPtr', -| and 'zWPtr' points to an array of four 32-bit elements that concatenate in -| the platform's normal endian order to form a 128-bit floating-point value. -*----------------------------------------------------------------------------*/ -void - softfloat_propagateNaNF128M( - const uint32_t *aWPtr, const uint32_t *bWPtr, uint32_t *zWPtr ); - -#endif - -#endif - diff --git a/deps/SoftFloat-3e/source/ARM-VFPv2-defaultNaN/extF80M_isSignalingNaN.c b/deps/SoftFloat-3e/source/ARM-VFPv2-defaultNaN/extF80M_isSignalingNaN.c deleted file mode 100644 index 85ee211c28d7..000000000000 --- a/deps/SoftFloat-3e/source/ARM-VFPv2-defaultNaN/extF80M_isSignalingNaN.c +++ /dev/null @@ -1,57 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "softfloat.h" - -/*---------------------------------------------------------------------------- -*----------------------------------------------------------------------------*/ -bool extF80M_isSignalingNaN( const extFloat80_t *aPtr ) -{ - const struct extFloat80M *aSPtr; - uint64_t uiA0; - - aSPtr = (const struct extFloat80M *) aPtr; - if ( (aSPtr->signExp & 0x7FFF) != 0x7FFF ) return false; - uiA0 = aSPtr->signif; - return - ! (uiA0 & UINT64_C( 0x4000000000000000 )) - && (uiA0 & UINT64_C( 0x3FFFFFFFFFFFFFFF)); - -} - diff --git a/deps/SoftFloat-3e/source/ARM-VFPv2-defaultNaN/f128M_isSignalingNaN.c b/deps/SoftFloat-3e/source/ARM-VFPv2-defaultNaN/f128M_isSignalingNaN.c deleted file mode 100644 index 79a707771672..000000000000 --- a/deps/SoftFloat-3e/source/ARM-VFPv2-defaultNaN/f128M_isSignalingNaN.c +++ /dev/null @@ -1,60 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "primitives.h" -#include "softfloat.h" - -/*---------------------------------------------------------------------------- -*----------------------------------------------------------------------------*/ -bool f128M_isSignalingNaN( const float128_t *aPtr ) -{ - const uint32_t *aWPtr; - uint32_t uiA96; - - aWPtr = (const uint32_t *) aPtr; - uiA96 = aWPtr[indexWordHi( 4 )]; - if ( (uiA96 & 0x7FFF8000) != 0x7FFF0000 ) return false; - return - ((uiA96 & 0x00007FFF) != 0) - || ((aWPtr[indexWord( 4, 2 )] | aWPtr[indexWord( 4, 1 )] - | aWPtr[indexWord( 4, 0 )]) - != 0); - -} - diff --git a/deps/SoftFloat-3e/source/ARM-VFPv2-defaultNaN/s_commonNaNToExtF80M.c b/deps/SoftFloat-3e/source/ARM-VFPv2-defaultNaN/s_commonNaNToExtF80M.c deleted file mode 100644 index 54a50dc3575b..000000000000 --- a/deps/SoftFloat-3e/source/ARM-VFPv2-defaultNaN/s_commonNaNToExtF80M.c +++ /dev/null @@ -1,57 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2017 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include "platform.h" -#include "softfloat_types.h" - -#define softfloat_commonNaNToExtF80M softfloat_commonNaNToExtF80M -#include "specialize.h" - -/*---------------------------------------------------------------------------- -| Converts the common NaN pointed to by 'aPtr' into an 80-bit extended -| floating-point NaN, and stores this NaN at the location pointed to by -| 'zSPtr'. -*----------------------------------------------------------------------------*/ -void - softfloat_commonNaNToExtF80M( - const struct commonNaN *aPtr, struct extFloat80M *zSPtr ) -{ - - zSPtr->signExp = defaultNaNExtF80UI64; - zSPtr->signif = defaultNaNExtF80UI0; - -} - diff --git a/deps/SoftFloat-3e/source/ARM-VFPv2-defaultNaN/s_commonNaNToExtF80UI.c b/deps/SoftFloat-3e/source/ARM-VFPv2-defaultNaN/s_commonNaNToExtF80UI.c deleted file mode 100644 index 5b698f6645ad..000000000000 --- a/deps/SoftFloat-3e/source/ARM-VFPv2-defaultNaN/s_commonNaNToExtF80UI.c +++ /dev/null @@ -1,57 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2017 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include "platform.h" -#include "primitiveTypes.h" - -#define softfloat_commonNaNToExtF80UI softfloat_commonNaNToExtF80UI -#include "specialize.h" - -/*---------------------------------------------------------------------------- -| Converts the common NaN pointed to by 'aPtr' into an 80-bit extended -| floating-point NaN, and returns the bit pattern of this value as an unsigned -| integer. -*----------------------------------------------------------------------------*/ -struct uint128 softfloat_commonNaNToExtF80UI( const struct commonNaN *aPtr ) -{ - struct uint128 uiZ; - - uiZ.v64 = defaultNaNExtF80UI64; - uiZ.v0 = defaultNaNExtF80UI0; - return uiZ; - -} - diff --git a/deps/SoftFloat-3e/source/ARM-VFPv2-defaultNaN/s_commonNaNToF128M.c b/deps/SoftFloat-3e/source/ARM-VFPv2-defaultNaN/s_commonNaNToF128M.c deleted file mode 100644 index b22baa816be0..000000000000 --- a/deps/SoftFloat-3e/source/ARM-VFPv2-defaultNaN/s_commonNaNToF128M.c +++ /dev/null @@ -1,60 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2017 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "primitiveTypes.h" - -#define softfloat_commonNaNToF128M softfloat_commonNaNToF128M -#include "specialize.h" - -/*---------------------------------------------------------------------------- -| Converts the common NaN pointed to by 'aPtr' into a 128-bit floating-point -| NaN, and stores this NaN at the location pointed to by 'zWPtr'. Argument -| 'zWPtr' points to an array of four 32-bit elements that concatenate in the -| platform's normal endian order to form a 128-bit floating-point value. -*----------------------------------------------------------------------------*/ -void - softfloat_commonNaNToF128M( const struct commonNaN *aPtr, uint32_t *zWPtr ) -{ - - zWPtr[indexWord( 4, 3 )] = defaultNaNF128UI96; - zWPtr[indexWord( 4, 2 )] = defaultNaNF128UI64; - zWPtr[indexWord( 4, 1 )] = defaultNaNF128UI32; - zWPtr[indexWord( 4, 0 )] = defaultNaNF128UI0; - -} - diff --git a/deps/SoftFloat-3e/source/ARM-VFPv2-defaultNaN/s_commonNaNToF128UI.c b/deps/SoftFloat-3e/source/ARM-VFPv2-defaultNaN/s_commonNaNToF128UI.c deleted file mode 100644 index 70f0cf1c6cfc..000000000000 --- a/deps/SoftFloat-3e/source/ARM-VFPv2-defaultNaN/s_commonNaNToF128UI.c +++ /dev/null @@ -1,56 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2017 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include "platform.h" -#include "primitiveTypes.h" - -#define softfloat_commonNaNToF128UI softfloat_commonNaNToF128UI -#include "specialize.h" - -/*---------------------------------------------------------------------------- -| Converts the common NaN pointed to by 'aPtr' into a 128-bit floating-point -| NaN, and returns the bit pattern of this value as an unsigned integer. -*----------------------------------------------------------------------------*/ -struct uint128 softfloat_commonNaNToF128UI( const struct commonNaN *aPtr ) -{ - struct uint128 uiZ; - - uiZ.v64 = defaultNaNF128UI64; - uiZ.v0 = defaultNaNF128UI0; - return uiZ; - -} - diff --git a/deps/SoftFloat-3e/source/ARM-VFPv2-defaultNaN/s_commonNaNToF16UI.c b/deps/SoftFloat-3e/source/ARM-VFPv2-defaultNaN/s_commonNaNToF16UI.c deleted file mode 100644 index 7c7d5c82e9da..000000000000 --- a/deps/SoftFloat-3e/source/ARM-VFPv2-defaultNaN/s_commonNaNToF16UI.c +++ /dev/null @@ -1,5 +0,0 @@ - -/*---------------------------------------------------------------------------- -| This file intentionally contains no code. -*----------------------------------------------------------------------------*/ - diff --git a/deps/SoftFloat-3e/source/ARM-VFPv2-defaultNaN/s_commonNaNToF32UI.c b/deps/SoftFloat-3e/source/ARM-VFPv2-defaultNaN/s_commonNaNToF32UI.c deleted file mode 100644 index 7c7d5c82e9da..000000000000 --- a/deps/SoftFloat-3e/source/ARM-VFPv2-defaultNaN/s_commonNaNToF32UI.c +++ /dev/null @@ -1,5 +0,0 @@ - -/*---------------------------------------------------------------------------- -| This file intentionally contains no code. -*----------------------------------------------------------------------------*/ - diff --git a/deps/SoftFloat-3e/source/ARM-VFPv2-defaultNaN/s_commonNaNToF64UI.c b/deps/SoftFloat-3e/source/ARM-VFPv2-defaultNaN/s_commonNaNToF64UI.c deleted file mode 100644 index 7c7d5c82e9da..000000000000 --- a/deps/SoftFloat-3e/source/ARM-VFPv2-defaultNaN/s_commonNaNToF64UI.c +++ /dev/null @@ -1,5 +0,0 @@ - -/*---------------------------------------------------------------------------- -| This file intentionally contains no code. -*----------------------------------------------------------------------------*/ - diff --git a/deps/SoftFloat-3e/source/ARM-VFPv2-defaultNaN/s_extF80MToCommonNaN.c b/deps/SoftFloat-3e/source/ARM-VFPv2-defaultNaN/s_extF80MToCommonNaN.c deleted file mode 100644 index 7c7d5c82e9da..000000000000 --- a/deps/SoftFloat-3e/source/ARM-VFPv2-defaultNaN/s_extF80MToCommonNaN.c +++ /dev/null @@ -1,5 +0,0 @@ - -/*---------------------------------------------------------------------------- -| This file intentionally contains no code. -*----------------------------------------------------------------------------*/ - diff --git a/deps/SoftFloat-3e/source/ARM-VFPv2-defaultNaN/s_extF80UIToCommonNaN.c b/deps/SoftFloat-3e/source/ARM-VFPv2-defaultNaN/s_extF80UIToCommonNaN.c deleted file mode 100644 index 7c7d5c82e9da..000000000000 --- a/deps/SoftFloat-3e/source/ARM-VFPv2-defaultNaN/s_extF80UIToCommonNaN.c +++ /dev/null @@ -1,5 +0,0 @@ - -/*---------------------------------------------------------------------------- -| This file intentionally contains no code. -*----------------------------------------------------------------------------*/ - diff --git a/deps/SoftFloat-3e/source/ARM-VFPv2-defaultNaN/s_f128MToCommonNaN.c b/deps/SoftFloat-3e/source/ARM-VFPv2-defaultNaN/s_f128MToCommonNaN.c deleted file mode 100644 index 7c7d5c82e9da..000000000000 --- a/deps/SoftFloat-3e/source/ARM-VFPv2-defaultNaN/s_f128MToCommonNaN.c +++ /dev/null @@ -1,5 +0,0 @@ - -/*---------------------------------------------------------------------------- -| This file intentionally contains no code. -*----------------------------------------------------------------------------*/ - diff --git a/deps/SoftFloat-3e/source/ARM-VFPv2-defaultNaN/s_f128UIToCommonNaN.c b/deps/SoftFloat-3e/source/ARM-VFPv2-defaultNaN/s_f128UIToCommonNaN.c deleted file mode 100644 index 7c7d5c82e9da..000000000000 --- a/deps/SoftFloat-3e/source/ARM-VFPv2-defaultNaN/s_f128UIToCommonNaN.c +++ /dev/null @@ -1,5 +0,0 @@ - -/*---------------------------------------------------------------------------- -| This file intentionally contains no code. -*----------------------------------------------------------------------------*/ - diff --git a/deps/SoftFloat-3e/source/ARM-VFPv2-defaultNaN/s_f16UIToCommonNaN.c b/deps/SoftFloat-3e/source/ARM-VFPv2-defaultNaN/s_f16UIToCommonNaN.c deleted file mode 100644 index 7c7d5c82e9da..000000000000 --- a/deps/SoftFloat-3e/source/ARM-VFPv2-defaultNaN/s_f16UIToCommonNaN.c +++ /dev/null @@ -1,5 +0,0 @@ - -/*---------------------------------------------------------------------------- -| This file intentionally contains no code. -*----------------------------------------------------------------------------*/ - diff --git a/deps/SoftFloat-3e/source/ARM-VFPv2-defaultNaN/s_f32UIToCommonNaN.c b/deps/SoftFloat-3e/source/ARM-VFPv2-defaultNaN/s_f32UIToCommonNaN.c deleted file mode 100644 index 7c7d5c82e9da..000000000000 --- a/deps/SoftFloat-3e/source/ARM-VFPv2-defaultNaN/s_f32UIToCommonNaN.c +++ /dev/null @@ -1,5 +0,0 @@ - -/*---------------------------------------------------------------------------- -| This file intentionally contains no code. -*----------------------------------------------------------------------------*/ - diff --git a/deps/SoftFloat-3e/source/ARM-VFPv2-defaultNaN/s_f64UIToCommonNaN.c b/deps/SoftFloat-3e/source/ARM-VFPv2-defaultNaN/s_f64UIToCommonNaN.c deleted file mode 100644 index 7c7d5c82e9da..000000000000 --- a/deps/SoftFloat-3e/source/ARM-VFPv2-defaultNaN/s_f64UIToCommonNaN.c +++ /dev/null @@ -1,5 +0,0 @@ - -/*---------------------------------------------------------------------------- -| This file intentionally contains no code. -*----------------------------------------------------------------------------*/ - diff --git a/deps/SoftFloat-3e/source/ARM-VFPv2-defaultNaN/s_propagateNaNExtF80M.c b/deps/SoftFloat-3e/source/ARM-VFPv2-defaultNaN/s_propagateNaNExtF80M.c deleted file mode 100644 index 1c6510c7e3c5..000000000000 --- a/deps/SoftFloat-3e/source/ARM-VFPv2-defaultNaN/s_propagateNaNExtF80M.c +++ /dev/null @@ -1,74 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2017 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "primitiveTypes.h" -#include "specialize.h" -#include "softfloat.h" - -/*---------------------------------------------------------------------------- -| Assuming at least one of the two 80-bit extended floating-point values -| pointed to by 'aSPtr' and 'bSPtr' is a NaN, stores the combined NaN result -| at the location pointed to by 'zSPtr'. If either original floating-point -| value is a signaling NaN, the invalid exception is raised. -*----------------------------------------------------------------------------*/ -void - softfloat_propagateNaNExtF80M( - const struct extFloat80M *aSPtr, - const struct extFloat80M *bSPtr, - struct extFloat80M *zSPtr - ) -{ - uint_fast16_t ui64; - uint_fast64_t ui0; - - ui64 = aSPtr->signExp; - ui0 = aSPtr->signif; - if ( - softfloat_isSigNaNExtF80UI( ui64, ui0 ) - || (bSPtr - && (ui64 = bSPtr->signExp, - ui0 = bSPtr->signif, - softfloat_isSigNaNExtF80UI( ui64, ui0 ))) - ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - } - zSPtr->signExp = defaultNaNExtF80UI64; - zSPtr->signif = defaultNaNExtF80UI0; - -} - diff --git a/deps/SoftFloat-3e/source/ARM-VFPv2-defaultNaN/s_propagateNaNExtF80UI.c b/deps/SoftFloat-3e/source/ARM-VFPv2-defaultNaN/s_propagateNaNExtF80UI.c deleted file mode 100644 index e1bb1555aa73..000000000000 --- a/deps/SoftFloat-3e/source/ARM-VFPv2-defaultNaN/s_propagateNaNExtF80UI.c +++ /dev/null @@ -1,73 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2017 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "primitiveTypes.h" -#include "specialize.h" -#include "softfloat.h" - -/*---------------------------------------------------------------------------- -| Interpreting the unsigned integer formed from concatenating 'uiA64' and -| 'uiA0' as an 80-bit extended floating-point value, and likewise interpreting -| the unsigned integer formed from concatenating 'uiB64' and 'uiB0' as another -| 80-bit extended floating-point value, and assuming at least on of these -| floating-point values is a NaN, returns the bit pattern of the combined NaN -| result. If either original floating-point value is a signaling NaN, the -| invalid exception is raised. -*----------------------------------------------------------------------------*/ -struct uint128 - softfloat_propagateNaNExtF80UI( - uint_fast16_t uiA64, - uint_fast64_t uiA0, - uint_fast16_t uiB64, - uint_fast64_t uiB0 - ) -{ - struct uint128 uiZ; - - if ( - softfloat_isSigNaNExtF80UI( uiA64, uiA0 ) - || softfloat_isSigNaNExtF80UI( uiB64, uiB0 ) - ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - } - uiZ.v64 = defaultNaNExtF80UI64; - uiZ.v0 = defaultNaNExtF80UI0; - return uiZ; - -} - diff --git a/deps/SoftFloat-3e/source/ARM-VFPv2-defaultNaN/s_propagateNaNF128M.c b/deps/SoftFloat-3e/source/ARM-VFPv2-defaultNaN/s_propagateNaNF128M.c deleted file mode 100644 index 9bddee955d56..000000000000 --- a/deps/SoftFloat-3e/source/ARM-VFPv2-defaultNaN/s_propagateNaNF128M.c +++ /dev/null @@ -1,68 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2017 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "primitiveTypes.h" -#include "specialize.h" -#include "softfloat.h" - -/*---------------------------------------------------------------------------- -| Assuming at least one of the two 128-bit floating-point values pointed to by -| 'aWPtr' and 'bWPtr' is a NaN, stores the combined NaN result at the location -| pointed to by 'zWPtr'. If either original floating-point value is a -| signaling NaN, the invalid exception is raised. Each of 'aWPtr', 'bWPtr', -| and 'zWPtr' points to an array of four 32-bit elements that concatenate in -| the platform's normal endian order to form a 128-bit floating-point value. -*----------------------------------------------------------------------------*/ -void - softfloat_propagateNaNF128M( - const uint32_t *aWPtr, const uint32_t *bWPtr, uint32_t *zWPtr ) -{ - - if ( - f128M_isSignalingNaN( (const float128_t *) aWPtr ); - || (bWPtr && f128M_isSignalingNaN( (const float128_t *) bWPtr )) - ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - } - zWPtr[indexWord( 4, 3 )] = defaultNaNF128UI96; - zWPtr[indexWord( 4, 2 )] = defaultNaNF128UI64; - zWPtr[indexWord( 4, 1 )] = defaultNaNF128UI32; - zWPtr[indexWord( 4, 0 )] = defaultNaNF128UI0; - -} - diff --git a/deps/SoftFloat-3e/source/ARM-VFPv2-defaultNaN/s_propagateNaNF128UI.c b/deps/SoftFloat-3e/source/ARM-VFPv2-defaultNaN/s_propagateNaNF128UI.c deleted file mode 100644 index 57fddd158adc..000000000000 --- a/deps/SoftFloat-3e/source/ARM-VFPv2-defaultNaN/s_propagateNaNF128UI.c +++ /dev/null @@ -1,73 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2017 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "primitiveTypes.h" -#include "specialize.h" -#include "softfloat.h" - -/*---------------------------------------------------------------------------- -| Interpreting the unsigned integer formed from concatenating 'uiA64' and -| 'uiA0' as a 128-bit floating-point value, and likewise interpreting the -| unsigned integer formed from concatenating 'uiB64' and 'uiB0' as another -| 128-bit floating-point value, and assuming at least on of these floating- -| point values is a NaN, returns the bit pattern of the combined NaN result. -| If either original floating-point value is a signaling NaN, the invalid -| exception is raised. -*----------------------------------------------------------------------------*/ -struct uint128 - softfloat_propagateNaNF128UI( - uint_fast64_t uiA64, - uint_fast64_t uiA0, - uint_fast64_t uiB64, - uint_fast64_t uiB0 - ) -{ - struct uint128 uiZ; - - if ( - softfloat_isSigNaNF128UI( uiA64, uiA0 ) - || softfloat_isSigNaNF128UI( uiB64, uiB0 ) - ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - } - uiZ.v64 = defaultNaNF128UI64; - uiZ.v0 = defaultNaNF128UI0; - return uiZ; - -} - diff --git a/deps/SoftFloat-3e/source/ARM-VFPv2-defaultNaN/s_propagateNaNF16UI.c b/deps/SoftFloat-3e/source/ARM-VFPv2-defaultNaN/s_propagateNaNF16UI.c deleted file mode 100644 index 0b08e003967b..000000000000 --- a/deps/SoftFloat-3e/source/ARM-VFPv2-defaultNaN/s_propagateNaNF16UI.c +++ /dev/null @@ -1,58 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017 The Regents of the -University of California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "specialize.h" -#include "softfloat.h" - -/*---------------------------------------------------------------------------- -| Interpreting 'uiA' and 'uiB' as the bit patterns of two 16-bit floating- -| point values, at least one of which is a NaN, returns the bit pattern of -| the combined NaN result. If either 'uiA' or 'uiB' has the pattern of a -| signaling NaN, the invalid exception is raised. -*----------------------------------------------------------------------------*/ -uint_fast16_t - softfloat_propagateNaNF16UI( uint_fast16_t uiA, uint_fast16_t uiB ) -{ - - if ( softfloat_isSigNaNF16UI( uiA ) || softfloat_isSigNaNF16UI( uiB ) ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - } - return defaultNaNF16UI; - -} - diff --git a/deps/SoftFloat-3e/source/ARM-VFPv2-defaultNaN/s_propagateNaNF32UI.c b/deps/SoftFloat-3e/source/ARM-VFPv2-defaultNaN/s_propagateNaNF32UI.c deleted file mode 100644 index cab740358e3b..000000000000 --- a/deps/SoftFloat-3e/source/ARM-VFPv2-defaultNaN/s_propagateNaNF32UI.c +++ /dev/null @@ -1,58 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2017 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "specialize.h" -#include "softfloat.h" - -/*---------------------------------------------------------------------------- -| Interpreting 'uiA' and 'uiB' as the bit patterns of two 32-bit floating- -| point values, at least one of which is a NaN, returns the bit pattern of -| the combined NaN result. If either 'uiA' or 'uiB' has the pattern of a -| signaling NaN, the invalid exception is raised. -*----------------------------------------------------------------------------*/ -uint_fast32_t - softfloat_propagateNaNF32UI( uint_fast32_t uiA, uint_fast32_t uiB ) -{ - - if ( softfloat_isSigNaNF32UI( uiA ) || softfloat_isSigNaNF32UI( uiB ) ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - } - return defaultNaNF32UI; - -} - diff --git a/deps/SoftFloat-3e/source/ARM-VFPv2-defaultNaN/s_propagateNaNF64UI.c b/deps/SoftFloat-3e/source/ARM-VFPv2-defaultNaN/s_propagateNaNF64UI.c deleted file mode 100644 index 83b91d3a9d96..000000000000 --- a/deps/SoftFloat-3e/source/ARM-VFPv2-defaultNaN/s_propagateNaNF64UI.c +++ /dev/null @@ -1,58 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2017 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "specialize.h" -#include "softfloat.h" - -/*---------------------------------------------------------------------------- -| Interpreting 'uiA' and 'uiB' as the bit patterns of two 64-bit floating- -| point values, at least one of which is a NaN, returns the bit pattern of -| the combined NaN result. If either 'uiA' or 'uiB' has the pattern of a -| signaling NaN, the invalid exception is raised. -*----------------------------------------------------------------------------*/ -uint_fast64_t - softfloat_propagateNaNF64UI( uint_fast64_t uiA, uint_fast64_t uiB ) -{ - - if ( softfloat_isSigNaNF64UI( uiA ) || softfloat_isSigNaNF64UI( uiB ) ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - } - return defaultNaNF64UI; - -} - diff --git a/deps/SoftFloat-3e/source/ARM-VFPv2-defaultNaN/softfloat_raiseFlags.c b/deps/SoftFloat-3e/source/ARM-VFPv2-defaultNaN/softfloat_raiseFlags.c deleted file mode 100644 index 61046da3c05e..000000000000 --- a/deps/SoftFloat-3e/source/ARM-VFPv2-defaultNaN/softfloat_raiseFlags.c +++ /dev/null @@ -1,52 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2017 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include "platform.h" -#include "softfloat.h" - -/*---------------------------------------------------------------------------- -| Raises the exceptions specified by 'flags'. Floating-point traps can be -| defined here if desired. It is currently not possible for such a trap -| to substitute a result value. If traps are not implemented, this routine -| should be simply 'softfloat_exceptionFlags |= flags;'. -*----------------------------------------------------------------------------*/ -void softfloat_raiseFlags( uint_fast8_t flags ) -{ - - softfloat_exceptionFlags |= flags; - -} - diff --git a/deps/SoftFloat-3e/source/ARM-VFPv2-defaultNaN/specialize.h b/deps/SoftFloat-3e/source/ARM-VFPv2-defaultNaN/specialize.h deleted file mode 100644 index 2c481a259675..000000000000 --- a/deps/SoftFloat-3e/source/ARM-VFPv2-defaultNaN/specialize.h +++ /dev/null @@ -1,407 +0,0 @@ - -/*============================================================================ - -This C header file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the -University of California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#ifndef specialize_h -#define specialize_h 1 - -#include -#include -#include "primitiveTypes.h" -#include "softfloat.h" - -/*---------------------------------------------------------------------------- -| Default value for 'softfloat_detectTininess'. -*----------------------------------------------------------------------------*/ -#define init_detectTininess softfloat_tininess_beforeRounding - -/*---------------------------------------------------------------------------- -| The values to return on conversions to 32-bit integer formats that raise an -| invalid exception. -*----------------------------------------------------------------------------*/ -#define ui32_fromPosOverflow 0xFFFFFFFF -#define ui32_fromNegOverflow 0 -#define ui32_fromNaN 0 -#define i32_fromPosOverflow 0x7FFFFFFF -#define i32_fromNegOverflow (-0x7FFFFFFF - 1) -#define i32_fromNaN 0 - -/*---------------------------------------------------------------------------- -| The values to return on conversions to 64-bit integer formats that raise an -| invalid exception. -*----------------------------------------------------------------------------*/ -#define ui64_fromPosOverflow UINT64_C( 0xFFFFFFFFFFFFFFFF ) -#define ui64_fromNegOverflow 0 -#define ui64_fromNaN 0 -#define i64_fromPosOverflow INT64_C( 0x7FFFFFFFFFFFFFFF ) -#define i64_fromNegOverflow (-INT64_C( 0x7FFFFFFFFFFFFFFF ) - 1) -#define i64_fromNaN 0 - -/*---------------------------------------------------------------------------- -| "Common NaN" structure, used to transfer NaN representations from one format -| to another. -*----------------------------------------------------------------------------*/ -struct commonNaN { char _unused; }; - -/*---------------------------------------------------------------------------- -| The bit pattern for a default generated 16-bit floating-point NaN. -*----------------------------------------------------------------------------*/ -#define defaultNaNF16UI 0x7E00 - -/*---------------------------------------------------------------------------- -| Returns true when 16-bit unsigned integer 'uiA' has the bit pattern of a -| 16-bit floating-point signaling NaN. -| Note: This macro evaluates its argument more than once. -*----------------------------------------------------------------------------*/ -#define softfloat_isSigNaNF16UI( uiA ) ((((uiA) & 0x7E00) == 0x7C00) && ((uiA) & 0x01FF)) - -/*---------------------------------------------------------------------------- -| Assuming 'uiA' has the bit pattern of a 16-bit floating-point NaN, converts -| this NaN to the common NaN form, and stores the resulting common NaN at the -| location pointed to by 'zPtr'. If the NaN is a signaling NaN, the invalid -| exception is raised. -*----------------------------------------------------------------------------*/ -#define softfloat_f16UIToCommonNaN( uiA, zPtr ) if ( ! ((uiA) & 0x0200) ) softfloat_raiseFlags( softfloat_flag_invalid ) - -/*---------------------------------------------------------------------------- -| Converts the common NaN pointed to by 'aPtr' into a 16-bit floating-point -| NaN, and returns the bit pattern of this value as an unsigned integer. -*----------------------------------------------------------------------------*/ -#define softfloat_commonNaNToF16UI( aPtr ) ((uint_fast16_t) defaultNaNF16UI) - -/*---------------------------------------------------------------------------- -| Interpreting 'uiA' and 'uiB' as the bit patterns of two 16-bit floating- -| point values, at least one of which is a NaN, returns the bit pattern of -| the combined NaN result. If either 'uiA' or 'uiB' has the pattern of a -| signaling NaN, the invalid exception is raised. -*----------------------------------------------------------------------------*/ -uint_fast16_t - softfloat_propagateNaNF16UI( uint_fast16_t uiA, uint_fast16_t uiB ); - -/*---------------------------------------------------------------------------- -| The bit pattern for a default generated 32-bit floating-point NaN. -*----------------------------------------------------------------------------*/ -#define defaultNaNF32UI 0x7FC00000 - -/*---------------------------------------------------------------------------- -| Returns true when 32-bit unsigned integer 'uiA' has the bit pattern of a -| 32-bit floating-point signaling NaN. -| Note: This macro evaluates its argument more than once. -*----------------------------------------------------------------------------*/ -#define softfloat_isSigNaNF32UI( uiA ) ((((uiA) & 0x7FC00000) == 0x7F800000) && ((uiA) & 0x003FFFFF)) - -/*---------------------------------------------------------------------------- -| Assuming 'uiA' has the bit pattern of a 32-bit floating-point NaN, converts -| this NaN to the common NaN form, and stores the resulting common NaN at the -| location pointed to by 'zPtr'. If the NaN is a signaling NaN, the invalid -| exception is raised. -*----------------------------------------------------------------------------*/ -#define softfloat_f32UIToCommonNaN( uiA, zPtr ) if ( ! ((uiA) & 0x00400000) ) softfloat_raiseFlags( softfloat_flag_invalid ) - -/*---------------------------------------------------------------------------- -| Converts the common NaN pointed to by 'aPtr' into a 32-bit floating-point -| NaN, and returns the bit pattern of this value as an unsigned integer. -*----------------------------------------------------------------------------*/ -#define softfloat_commonNaNToF32UI( aPtr ) ((uint_fast32_t) defaultNaNF32UI) - -/*---------------------------------------------------------------------------- -| Interpreting 'uiA' and 'uiB' as the bit patterns of two 32-bit floating- -| point values, at least one of which is a NaN, returns the bit pattern of -| the combined NaN result. If either 'uiA' or 'uiB' has the pattern of a -| signaling NaN, the invalid exception is raised. -*----------------------------------------------------------------------------*/ -uint_fast32_t - softfloat_propagateNaNF32UI( uint_fast32_t uiA, uint_fast32_t uiB ); - -/*---------------------------------------------------------------------------- -| The bit pattern for a default generated 64-bit floating-point NaN. -*----------------------------------------------------------------------------*/ -#define defaultNaNF64UI UINT64_C( 0x7FF8000000000000 ) - -/*---------------------------------------------------------------------------- -| Returns true when 64-bit unsigned integer 'uiA' has the bit pattern of a -| 64-bit floating-point signaling NaN. -| Note: This macro evaluates its argument more than once. -*----------------------------------------------------------------------------*/ -#define softfloat_isSigNaNF64UI( uiA ) ((((uiA) & UINT64_C( 0x7FF8000000000000 )) == UINT64_C( 0x7FF0000000000000 )) && ((uiA) & UINT64_C( 0x0007FFFFFFFFFFFF ))) - -/*---------------------------------------------------------------------------- -| Assuming 'uiA' has the bit pattern of a 64-bit floating-point NaN, converts -| this NaN to the common NaN form, and stores the resulting common NaN at the -| location pointed to by 'zPtr'. If the NaN is a signaling NaN, the invalid -| exception is raised. -*----------------------------------------------------------------------------*/ -#define softfloat_f64UIToCommonNaN( uiA, zPtr ) if ( ! ((uiA) & UINT64_C( 0x0008000000000000 )) ) softfloat_raiseFlags( softfloat_flag_invalid ) - -/*---------------------------------------------------------------------------- -| Converts the common NaN pointed to by 'aPtr' into a 64-bit floating-point -| NaN, and returns the bit pattern of this value as an unsigned integer. -*----------------------------------------------------------------------------*/ -#define softfloat_commonNaNToF64UI( aPtr ) ((uint_fast64_t) defaultNaNF64UI) - -/*---------------------------------------------------------------------------- -| Interpreting 'uiA' and 'uiB' as the bit patterns of two 64-bit floating- -| point values, at least one of which is a NaN, returns the bit pattern of -| the combined NaN result. If either 'uiA' or 'uiB' has the pattern of a -| signaling NaN, the invalid exception is raised. -*----------------------------------------------------------------------------*/ -uint_fast64_t - softfloat_propagateNaNF64UI( uint_fast64_t uiA, uint_fast64_t uiB ); - -/*---------------------------------------------------------------------------- -| The bit pattern for a default generated 80-bit extended floating-point NaN. -*----------------------------------------------------------------------------*/ -#define defaultNaNExtF80UI64 0x7FFF -#define defaultNaNExtF80UI0 UINT64_C( 0xC000000000000000 ) - -/*---------------------------------------------------------------------------- -| Returns true when the 80-bit unsigned integer formed from concatenating -| 16-bit 'uiA64' and 64-bit 'uiA0' has the bit pattern of an 80-bit extended -| floating-point signaling NaN. -| Note: This macro evaluates its arguments more than once. -*----------------------------------------------------------------------------*/ -#define softfloat_isSigNaNExtF80UI( uiA64, uiA0 ) ((((uiA64) & 0x7FFF) == 0x7FFF) && ! ((uiA0) & UINT64_C( 0x4000000000000000 )) && ((uiA0) & UINT64_C( 0x3FFFFFFFFFFFFFFF ))) - -#ifdef SOFTFLOAT_FAST_INT64 - -/*---------------------------------------------------------------------------- -| The following functions are needed only when 'SOFTFLOAT_FAST_INT64' is -| defined. -*----------------------------------------------------------------------------*/ - -/*---------------------------------------------------------------------------- -| Assuming the unsigned integer formed from concatenating 'uiA64' and 'uiA0' -| has the bit pattern of an 80-bit extended floating-point NaN, converts -| this NaN to the common NaN form, and stores the resulting common NaN at the -| location pointed to by 'zPtr'. If the NaN is a signaling NaN, the invalid -| exception is raised. -*----------------------------------------------------------------------------*/ -#define softfloat_extF80UIToCommonNaN( uiA64, uiA0, zPtr ) if ( ! ((uiA0) & UINT64_C( 0x4000000000000000 )) ) softfloat_raiseFlags( softfloat_flag_invalid ) - -/*---------------------------------------------------------------------------- -| Converts the common NaN pointed to by 'aPtr' into an 80-bit extended -| floating-point NaN, and returns the bit pattern of this value as an unsigned -| integer. -*----------------------------------------------------------------------------*/ -#if defined INLINE && ! defined softfloat_commonNaNToExtF80UI -INLINE -struct uint128 softfloat_commonNaNToExtF80UI( const struct commonNaN *aPtr ) -{ - struct uint128 uiZ; - uiZ.v64 = defaultNaNExtF80UI64; - uiZ.v0 = defaultNaNExtF80UI0; - return uiZ; -} -#else -struct uint128 softfloat_commonNaNToExtF80UI( const struct commonNaN *aPtr ); -#endif - -/*---------------------------------------------------------------------------- -| Interpreting the unsigned integer formed from concatenating 'uiA64' and -| 'uiA0' as an 80-bit extended floating-point value, and likewise interpreting -| the unsigned integer formed from concatenating 'uiB64' and 'uiB0' as another -| 80-bit extended floating-point value, and assuming at least on of these -| floating-point values is a NaN, returns the bit pattern of the combined NaN -| result. If either original floating-point value is a signaling NaN, the -| invalid exception is raised. -*----------------------------------------------------------------------------*/ -struct uint128 - softfloat_propagateNaNExtF80UI( - uint_fast16_t uiA64, - uint_fast64_t uiA0, - uint_fast16_t uiB64, - uint_fast64_t uiB0 - ); - -/*---------------------------------------------------------------------------- -| The bit pattern for a default generated 128-bit floating-point NaN. -*----------------------------------------------------------------------------*/ -#define defaultNaNF128UI64 UINT64_C( 0x7FFF800000000000 ) -#define defaultNaNF128UI0 UINT64_C( 0 ) - -/*---------------------------------------------------------------------------- -| Returns true when the 128-bit unsigned integer formed from concatenating -| 64-bit 'uiA64' and 64-bit 'uiA0' has the bit pattern of a 128-bit floating- -| point signaling NaN. -| Note: This macro evaluates its arguments more than once. -*----------------------------------------------------------------------------*/ -#define softfloat_isSigNaNF128UI( uiA64, uiA0 ) ((((uiA64) & UINT64_C( 0x7FFF800000000000 )) == UINT64_C( 0x7FFF000000000000 )) && ((uiA0) || ((uiA64) & UINT64_C( 0x00007FFFFFFFFFFF )))) - -/*---------------------------------------------------------------------------- -| Assuming the unsigned integer formed from concatenating 'uiA64' and 'uiA0' -| has the bit pattern of a 128-bit floating-point NaN, converts this NaN to -| the common NaN form, and stores the resulting common NaN at the location -| pointed to by 'zPtr'. If the NaN is a signaling NaN, the invalid exception -| is raised. -*----------------------------------------------------------------------------*/ -#define softfloat_f128UIToCommonNaN( uiA64, uiA0, zPtr ) if ( ! ((uiA64) & UINT64_C( 0x0000800000000000 )) ) softfloat_raiseFlags( softfloat_flag_invalid ) - -/*---------------------------------------------------------------------------- -| Converts the common NaN pointed to by 'aPtr' into a 128-bit floating-point -| NaN, and returns the bit pattern of this value as an unsigned integer. -*----------------------------------------------------------------------------*/ -#if defined INLINE && ! defined softfloat_commonNaNToF128UI -INLINE -struct uint128 softfloat_commonNaNToF128UI( const struct commonNaN *aPtr ) -{ - struct uint128 uiZ; - uiZ.v64 = defaultNaNF128UI64; - uiZ.v0 = defaultNaNF128UI0; - return uiZ; -} -#else -struct uint128 softfloat_commonNaNToF128UI( const struct commonNaN * ); -#endif - -/*---------------------------------------------------------------------------- -| Interpreting the unsigned integer formed from concatenating 'uiA64' and -| 'uiA0' as a 128-bit floating-point value, and likewise interpreting the -| unsigned integer formed from concatenating 'uiB64' and 'uiB0' as another -| 128-bit floating-point value, and assuming at least on of these floating- -| point values is a NaN, returns the bit pattern of the combined NaN result. -| If either original floating-point value is a signaling NaN, the invalid -| exception is raised. -*----------------------------------------------------------------------------*/ -struct uint128 - softfloat_propagateNaNF128UI( - uint_fast64_t uiA64, - uint_fast64_t uiA0, - uint_fast64_t uiB64, - uint_fast64_t uiB0 - ); - -#else - -/*---------------------------------------------------------------------------- -| The following functions are needed only when 'SOFTFLOAT_FAST_INT64' is not -| defined. -*----------------------------------------------------------------------------*/ - -/*---------------------------------------------------------------------------- -| Assuming the 80-bit extended floating-point value pointed to by 'aSPtr' is -| a NaN, converts this NaN to the common NaN form, and stores the resulting -| common NaN at the location pointed to by 'zPtr'. If the NaN is a signaling -| NaN, the invalid exception is raised. -*----------------------------------------------------------------------------*/ -#define softfloat_extF80MToCommonNaN( aSPtr, zPtr ) if ( ! ((aSPtr)->signif & UINT64_C( 0x4000000000000000 )) ) softfloat_raiseFlags( softfloat_flag_invalid ) - -/*---------------------------------------------------------------------------- -| Converts the common NaN pointed to by 'aPtr' into an 80-bit extended -| floating-point NaN, and stores this NaN at the location pointed to by -| 'zSPtr'. -*----------------------------------------------------------------------------*/ -#if defined INLINE && ! defined softfloat_commonNaNToExtF80M -INLINE -void - softfloat_commonNaNToExtF80M( - const struct commonNaN *aPtr, struct extFloat80M *zSPtr ) -{ - zSPtr->signExp = defaultNaNExtF80UI64; - zSPtr->signif = defaultNaNExtF80UI0; -} -#else -void - softfloat_commonNaNToExtF80M( - const struct commonNaN *aPtr, struct extFloat80M *zSPtr ); -#endif - -/*---------------------------------------------------------------------------- -| Assuming at least one of the two 80-bit extended floating-point values -| pointed to by 'aSPtr' and 'bSPtr' is a NaN, stores the combined NaN result -| at the location pointed to by 'zSPtr'. If either original floating-point -| value is a signaling NaN, the invalid exception is raised. -*----------------------------------------------------------------------------*/ -void - softfloat_propagateNaNExtF80M( - const struct extFloat80M *aSPtr, - const struct extFloat80M *bSPtr, - struct extFloat80M *zSPtr - ); - -/*---------------------------------------------------------------------------- -| The bit pattern for a default generated 128-bit floating-point NaN. -*----------------------------------------------------------------------------*/ -#define defaultNaNF128UI96 0x7FFF8000 -#define defaultNaNF128UI64 0 -#define defaultNaNF128UI32 0 -#define defaultNaNF128UI0 0 - -/*---------------------------------------------------------------------------- -| Assuming the 128-bit floating-point value pointed to by 'aWPtr' is a NaN, -| converts this NaN to the common NaN form, and stores the resulting common -| NaN at the location pointed to by 'zPtr'. If the NaN is a signaling NaN, -| the invalid exception is raised. Argument 'aWPtr' points to an array of -| four 32-bit elements that concatenate in the platform's normal endian order -| to form a 128-bit floating-point value. -*----------------------------------------------------------------------------*/ -#define softfloat_f128MToCommonNaN( aWPtr, zPtr ) if ( ! ((aWPtr)[indexWordHi( 4 )] & UINT64_C( 0x0000800000000000 )) ) softfloat_raiseFlags( softfloat_flag_invalid ) - -/*---------------------------------------------------------------------------- -| Converts the common NaN pointed to by 'aPtr' into a 128-bit floating-point -| NaN, and stores this NaN at the location pointed to by 'zWPtr'. Argument -| 'zWPtr' points to an array of four 32-bit elements that concatenate in the -| platform's normal endian order to form a 128-bit floating-point value. -*----------------------------------------------------------------------------*/ -#if defined INLINE && ! defined softfloat_commonNaNToF128M -INLINE -void - softfloat_commonNaNToF128M( const struct commonNaN *aPtr, uint32_t *zWPtr ) -{ - zWPtr[indexWord( 4, 3 )] = defaultNaNF128UI96; - zWPtr[indexWord( 4, 2 )] = defaultNaNF128UI64; - zWPtr[indexWord( 4, 1 )] = defaultNaNF128UI32; - zWPtr[indexWord( 4, 0 )] = defaultNaNF128UI0; -} -#else -void - softfloat_commonNaNToF128M( const struct commonNaN *aPtr, uint32_t *zWPtr ); -#endif - -/*---------------------------------------------------------------------------- -| Assuming at least one of the two 128-bit floating-point values pointed to by -| 'aWPtr' and 'bWPtr' is a NaN, stores the combined NaN result at the location -| pointed to by 'zWPtr'. If either original floating-point value is a -| signaling NaN, the invalid exception is raised. Each of 'aWPtr', 'bWPtr', -| and 'zWPtr' points to an array of four 32-bit elements that concatenate in -| the platform's normal endian order to form a 128-bit floating-point value. -*----------------------------------------------------------------------------*/ -void - softfloat_propagateNaNF128M( - const uint32_t *aWPtr, const uint32_t *bWPtr, uint32_t *zWPtr ); - -#endif - -#endif - diff --git a/deps/SoftFloat-3e/source/ARM-VFPv2/extF80M_isSignalingNaN.c b/deps/SoftFloat-3e/source/ARM-VFPv2/extF80M_isSignalingNaN.c deleted file mode 100644 index 85ee211c28d7..000000000000 --- a/deps/SoftFloat-3e/source/ARM-VFPv2/extF80M_isSignalingNaN.c +++ /dev/null @@ -1,57 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "softfloat.h" - -/*---------------------------------------------------------------------------- -*----------------------------------------------------------------------------*/ -bool extF80M_isSignalingNaN( const extFloat80_t *aPtr ) -{ - const struct extFloat80M *aSPtr; - uint64_t uiA0; - - aSPtr = (const struct extFloat80M *) aPtr; - if ( (aSPtr->signExp & 0x7FFF) != 0x7FFF ) return false; - uiA0 = aSPtr->signif; - return - ! (uiA0 & UINT64_C( 0x4000000000000000 )) - && (uiA0 & UINT64_C( 0x3FFFFFFFFFFFFFFF)); - -} - diff --git a/deps/SoftFloat-3e/source/ARM-VFPv2/f128M_isSignalingNaN.c b/deps/SoftFloat-3e/source/ARM-VFPv2/f128M_isSignalingNaN.c deleted file mode 100644 index 79a707771672..000000000000 --- a/deps/SoftFloat-3e/source/ARM-VFPv2/f128M_isSignalingNaN.c +++ /dev/null @@ -1,60 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "primitives.h" -#include "softfloat.h" - -/*---------------------------------------------------------------------------- -*----------------------------------------------------------------------------*/ -bool f128M_isSignalingNaN( const float128_t *aPtr ) -{ - const uint32_t *aWPtr; - uint32_t uiA96; - - aWPtr = (const uint32_t *) aPtr; - uiA96 = aWPtr[indexWordHi( 4 )]; - if ( (uiA96 & 0x7FFF8000) != 0x7FFF0000 ) return false; - return - ((uiA96 & 0x00007FFF) != 0) - || ((aWPtr[indexWord( 4, 2 )] | aWPtr[indexWord( 4, 1 )] - | aWPtr[indexWord( 4, 0 )]) - != 0); - -} - diff --git a/deps/SoftFloat-3e/source/ARM-VFPv2/s_commonNaNToExtF80M.c b/deps/SoftFloat-3e/source/ARM-VFPv2/s_commonNaNToExtF80M.c deleted file mode 100644 index 543400bc1a92..000000000000 --- a/deps/SoftFloat-3e/source/ARM-VFPv2/s_commonNaNToExtF80M.c +++ /dev/null @@ -1,56 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2017 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" - -/*---------------------------------------------------------------------------- -| Converts the common NaN pointed to by 'aPtr' into an 80-bit extended -| floating-point NaN, and stores this NaN at the location pointed to by -| 'zSPtr'. -*----------------------------------------------------------------------------*/ -void - softfloat_commonNaNToExtF80M( - const struct commonNaN *aPtr, struct extFloat80M *zSPtr ) -{ - - zSPtr->signExp = packToExtF80UI64( aPtr->sign, 0x7FFF ); - zSPtr->signif = UINT64_C( 0xC000000000000000 ) | aPtr->v64>>1; - -} - diff --git a/deps/SoftFloat-3e/source/ARM-VFPv2/s_commonNaNToExtF80UI.c b/deps/SoftFloat-3e/source/ARM-VFPv2/s_commonNaNToExtF80UI.c deleted file mode 100644 index 6cf1d119186e..000000000000 --- a/deps/SoftFloat-3e/source/ARM-VFPv2/s_commonNaNToExtF80UI.c +++ /dev/null @@ -1,56 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2017 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "primitives.h" -#include "specialize.h" - -/*---------------------------------------------------------------------------- -| Converts the common NaN pointed to by 'aPtr' into an 80-bit extended -| floating-point NaN, and returns the bit pattern of this value as an unsigned -| integer. -*----------------------------------------------------------------------------*/ -struct uint128 softfloat_commonNaNToExtF80UI( const struct commonNaN *aPtr ) -{ - struct uint128 uiZ; - - uiZ.v64 = (uint_fast16_t) aPtr->sign<<15 | 0x7FFF; - uiZ.v0 = UINT64_C( 0xC000000000000000 ) | aPtr->v64>>1; - return uiZ; - -} - diff --git a/deps/SoftFloat-3e/source/ARM-VFPv2/s_commonNaNToF128M.c b/deps/SoftFloat-3e/source/ARM-VFPv2/s_commonNaNToF128M.c deleted file mode 100644 index 4e8ede07fd01..000000000000 --- a/deps/SoftFloat-3e/source/ARM-VFPv2/s_commonNaNToF128M.c +++ /dev/null @@ -1,56 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2017 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "primitives.h" -#include "specialize.h" - -/*---------------------------------------------------------------------------- -| Converts the common NaN pointed to by 'aPtr' into a 128-bit floating-point -| NaN, and stores this NaN at the location pointed to by 'zWPtr'. Argument -| 'zWPtr' points to an array of four 32-bit elements that concatenate in the -| platform's normal endian order to form a 128-bit floating-point value. -*----------------------------------------------------------------------------*/ -void - softfloat_commonNaNToF128M( const struct commonNaN *aPtr, uint32_t *zWPtr ) -{ - - softfloat_shortShiftRight128M( (const uint32_t *) &aPtr->v0, 16, zWPtr ); - zWPtr[indexWordHi( 4 )] |= (uint32_t) aPtr->sign<<31 | 0x7FFF8000; - -} - diff --git a/deps/SoftFloat-3e/source/ARM-VFPv2/s_commonNaNToF128UI.c b/deps/SoftFloat-3e/source/ARM-VFPv2/s_commonNaNToF128UI.c deleted file mode 100644 index f938c3f2d37e..000000000000 --- a/deps/SoftFloat-3e/source/ARM-VFPv2/s_commonNaNToF128UI.c +++ /dev/null @@ -1,55 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2017 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "primitives.h" -#include "specialize.h" - -/*---------------------------------------------------------------------------- -| Converts the common NaN pointed to by 'aPtr' into a 128-bit floating-point -| NaN, and returns the bit pattern of this value as an unsigned integer. -*----------------------------------------------------------------------------*/ -struct uint128 softfloat_commonNaNToF128UI( const struct commonNaN *aPtr ) -{ - struct uint128 uiZ; - - uiZ = softfloat_shortShiftRight128( aPtr->v64, aPtr->v0, 16 ); - uiZ.v64 |= (uint_fast64_t) aPtr->sign<<63 | UINT64_C( 0x7FFF800000000000 ); - return uiZ; - -} - diff --git a/deps/SoftFloat-3e/source/ARM-VFPv2/s_commonNaNToF16UI.c b/deps/SoftFloat-3e/source/ARM-VFPv2/s_commonNaNToF16UI.c deleted file mode 100644 index 6cd4fc192c2d..000000000000 --- a/deps/SoftFloat-3e/source/ARM-VFPv2/s_commonNaNToF16UI.c +++ /dev/null @@ -1,51 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2017 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "specialize.h" - -/*---------------------------------------------------------------------------- -| Converts the common NaN pointed to by 'aPtr' into a 16-bit floating-point -| NaN, and returns the bit pattern of this value as an unsigned integer. -*----------------------------------------------------------------------------*/ -uint_fast16_t softfloat_commonNaNToF16UI( const struct commonNaN *aPtr ) -{ - - return (uint_fast16_t) aPtr->sign<<15 | 0x7E00 | aPtr->v64>>54; - -} - diff --git a/deps/SoftFloat-3e/source/ARM-VFPv2/s_commonNaNToF32UI.c b/deps/SoftFloat-3e/source/ARM-VFPv2/s_commonNaNToF32UI.c deleted file mode 100644 index 7b38167f0022..000000000000 --- a/deps/SoftFloat-3e/source/ARM-VFPv2/s_commonNaNToF32UI.c +++ /dev/null @@ -1,51 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2017 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "specialize.h" - -/*---------------------------------------------------------------------------- -| Converts the common NaN pointed to by 'aPtr' into a 32-bit floating-point -| NaN, and returns the bit pattern of this value as an unsigned integer. -*----------------------------------------------------------------------------*/ -uint_fast32_t softfloat_commonNaNToF32UI( const struct commonNaN *aPtr ) -{ - - return (uint_fast32_t) aPtr->sign<<31 | 0x7FC00000 | aPtr->v64>>41; - -} - diff --git a/deps/SoftFloat-3e/source/ARM-VFPv2/s_commonNaNToF64UI.c b/deps/SoftFloat-3e/source/ARM-VFPv2/s_commonNaNToF64UI.c deleted file mode 100644 index 14847029d28a..000000000000 --- a/deps/SoftFloat-3e/source/ARM-VFPv2/s_commonNaNToF64UI.c +++ /dev/null @@ -1,53 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2017 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "specialize.h" - -/*---------------------------------------------------------------------------- -| Converts the common NaN pointed to by 'aPtr' into a 64-bit floating-point -| NaN, and returns the bit pattern of this value as an unsigned integer. -*----------------------------------------------------------------------------*/ -uint_fast64_t softfloat_commonNaNToF64UI( const struct commonNaN *aPtr ) -{ - - return - (uint_fast64_t) aPtr->sign<<63 | UINT64_C( 0x7FF8000000000000 ) - | aPtr->v64>>12; - -} - diff --git a/deps/SoftFloat-3e/source/ARM-VFPv2/s_extF80MToCommonNaN.c b/deps/SoftFloat-3e/source/ARM-VFPv2/s_extF80MToCommonNaN.c deleted file mode 100644 index 82216cf4111d..000000000000 --- a/deps/SoftFloat-3e/source/ARM-VFPv2/s_extF80MToCommonNaN.c +++ /dev/null @@ -1,62 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2017 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -/*---------------------------------------------------------------------------- -| Assuming the 80-bit extended floating-point value pointed to by 'aSPtr' is -| a NaN, converts this NaN to the common NaN form, and stores the resulting -| common NaN at the location pointed to by 'zPtr'. If the NaN is a signaling -| NaN, the invalid exception is raised. -*----------------------------------------------------------------------------*/ -void - softfloat_extF80MToCommonNaN( - const struct extFloat80M *aSPtr, struct commonNaN *zPtr ) -{ - - if ( extF80M_isSignalingNaN( (const extFloat80_t *) aSPtr ) ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - } - zPtr->sign = signExtF80UI64( aSPtr->signExp ); - zPtr->v64 = aSPtr->signif<<1; - zPtr->v0 = 0; - -} - diff --git a/deps/SoftFloat-3e/source/ARM-VFPv2/s_extF80UIToCommonNaN.c b/deps/SoftFloat-3e/source/ARM-VFPv2/s_extF80UIToCommonNaN.c deleted file mode 100644 index 2559fb6d2c3b..000000000000 --- a/deps/SoftFloat-3e/source/ARM-VFPv2/s_extF80UIToCommonNaN.c +++ /dev/null @@ -1,62 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2017 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "specialize.h" -#include "softfloat.h" - -/*---------------------------------------------------------------------------- -| Assuming the unsigned integer formed from concatenating 'uiA64' and 'uiA0' -| has the bit pattern of an 80-bit extended floating-point NaN, converts -| this NaN to the common NaN form, and stores the resulting common NaN at the -| location pointed to by 'zPtr'. If the NaN is a signaling NaN, the invalid -| exception is raised. -*----------------------------------------------------------------------------*/ -void - softfloat_extF80UIToCommonNaN( - uint_fast16_t uiA64, uint_fast64_t uiA0, struct commonNaN *zPtr ) -{ - - if ( softfloat_isSigNaNExtF80UI( uiA64, uiA0 ) ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - } - zPtr->sign = uiA64>>15; - zPtr->v64 = uiA0<<1; - zPtr->v0 = 0; - -} - diff --git a/deps/SoftFloat-3e/source/ARM-VFPv2/s_f128MToCommonNaN.c b/deps/SoftFloat-3e/source/ARM-VFPv2/s_f128MToCommonNaN.c deleted file mode 100644 index 322d25ab1e53..000000000000 --- a/deps/SoftFloat-3e/source/ARM-VFPv2/s_f128MToCommonNaN.c +++ /dev/null @@ -1,62 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2017 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "primitives.h" -#include "specialize.h" -#include "softfloat.h" - -/*---------------------------------------------------------------------------- -| Assuming the 128-bit floating-point value pointed to by 'aWPtr' is a NaN, -| converts this NaN to the common NaN form, and stores the resulting common -| NaN at the location pointed to by 'zPtr'. If the NaN is a signaling NaN, -| the invalid exception is raised. Argument 'aWPtr' points to an array of -| four 32-bit elements that concatenate in the platform's normal endian order -| to form a 128-bit floating-point value. -*----------------------------------------------------------------------------*/ -void - softfloat_f128MToCommonNaN( const uint32_t *aWPtr, struct commonNaN *zPtr ) -{ - - if ( f128M_isSignalingNaN( (const float128_t *) aWPtr ) ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - } - zPtr->sign = aWPtr[indexWordHi( 4 )]>>31; - softfloat_shortShiftLeft128M( aWPtr, 16, (uint32_t *) &zPtr->v0 ); - -} - diff --git a/deps/SoftFloat-3e/source/ARM-VFPv2/s_f128UIToCommonNaN.c b/deps/SoftFloat-3e/source/ARM-VFPv2/s_f128UIToCommonNaN.c deleted file mode 100644 index 843c187a7da1..000000000000 --- a/deps/SoftFloat-3e/source/ARM-VFPv2/s_f128UIToCommonNaN.c +++ /dev/null @@ -1,65 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2017 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "primitives.h" -#include "specialize.h" -#include "softfloat.h" - -/*---------------------------------------------------------------------------- -| Assuming the unsigned integer formed from concatenating 'uiA64' and 'uiA0' -| has the bit pattern of a 128-bit floating-point NaN, converts this NaN to -| the common NaN form, and stores the resulting common NaN at the location -| pointed to by 'zPtr'. If the NaN is a signaling NaN, the invalid exception -| is raised. -*----------------------------------------------------------------------------*/ -void - softfloat_f128UIToCommonNaN( - uint_fast64_t uiA64, uint_fast64_t uiA0, struct commonNaN *zPtr ) -{ - struct uint128 NaNSig; - - if ( softfloat_isSigNaNF128UI( uiA64, uiA0 ) ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - } - NaNSig = softfloat_shortShiftLeft128( uiA64, uiA0, 16 ); - zPtr->sign = uiA64>>63; - zPtr->v64 = NaNSig.v64; - zPtr->v0 = NaNSig.v0; - -} - diff --git a/deps/SoftFloat-3e/source/ARM-VFPv2/s_f16UIToCommonNaN.c b/deps/SoftFloat-3e/source/ARM-VFPv2/s_f16UIToCommonNaN.c deleted file mode 100644 index f5fe58770d20..000000000000 --- a/deps/SoftFloat-3e/source/ARM-VFPv2/s_f16UIToCommonNaN.c +++ /dev/null @@ -1,59 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2017 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "specialize.h" -#include "softfloat.h" - -/*---------------------------------------------------------------------------- -| Assuming 'uiA' has the bit pattern of a 16-bit floating-point NaN, converts -| this NaN to the common NaN form, and stores the resulting common NaN at the -| location pointed to by 'zPtr'. If the NaN is a signaling NaN, the invalid -| exception is raised. -*----------------------------------------------------------------------------*/ -void softfloat_f16UIToCommonNaN( uint_fast16_t uiA, struct commonNaN *zPtr ) -{ - - if ( softfloat_isSigNaNF16UI( uiA ) ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - } - zPtr->sign = uiA>>15; - zPtr->v64 = (uint_fast64_t) uiA<<54; - zPtr->v0 = 0; - -} - diff --git a/deps/SoftFloat-3e/source/ARM-VFPv2/s_f32UIToCommonNaN.c b/deps/SoftFloat-3e/source/ARM-VFPv2/s_f32UIToCommonNaN.c deleted file mode 100644 index 58726a357166..000000000000 --- a/deps/SoftFloat-3e/source/ARM-VFPv2/s_f32UIToCommonNaN.c +++ /dev/null @@ -1,59 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2017 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "specialize.h" -#include "softfloat.h" - -/*---------------------------------------------------------------------------- -| Assuming 'uiA' has the bit pattern of a 32-bit floating-point NaN, converts -| this NaN to the common NaN form, and stores the resulting common NaN at the -| location pointed to by 'zPtr'. If the NaN is a signaling NaN, the invalid -| exception is raised. -*----------------------------------------------------------------------------*/ -void softfloat_f32UIToCommonNaN( uint_fast32_t uiA, struct commonNaN *zPtr ) -{ - - if ( softfloat_isSigNaNF32UI( uiA ) ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - } - zPtr->sign = uiA>>31; - zPtr->v64 = (uint_fast64_t) uiA<<41; - zPtr->v0 = 0; - -} - diff --git a/deps/SoftFloat-3e/source/ARM-VFPv2/s_f64UIToCommonNaN.c b/deps/SoftFloat-3e/source/ARM-VFPv2/s_f64UIToCommonNaN.c deleted file mode 100644 index 03761e4331c6..000000000000 --- a/deps/SoftFloat-3e/source/ARM-VFPv2/s_f64UIToCommonNaN.c +++ /dev/null @@ -1,59 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2017 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "specialize.h" -#include "softfloat.h" - -/*---------------------------------------------------------------------------- -| Assuming 'uiA' has the bit pattern of a 64-bit floating-point NaN, converts -| this NaN to the common NaN form, and stores the resulting common NaN at the -| location pointed to by 'zPtr'. If the NaN is a signaling NaN, the invalid -| exception is raised. -*----------------------------------------------------------------------------*/ -void softfloat_f64UIToCommonNaN( uint_fast64_t uiA, struct commonNaN *zPtr ) -{ - - if ( softfloat_isSigNaNF64UI( uiA ) ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - } - zPtr->sign = uiA>>63; - zPtr->v64 = uiA<<12; - zPtr->v0 = 0; - -} - diff --git a/deps/SoftFloat-3e/source/ARM-VFPv2/s_propagateNaNExtF80M.c b/deps/SoftFloat-3e/source/ARM-VFPv2/s_propagateNaNExtF80M.c deleted file mode 100644 index f10ed0b62f11..000000000000 --- a/deps/SoftFloat-3e/source/ARM-VFPv2/s_propagateNaNExtF80M.c +++ /dev/null @@ -1,86 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2017 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -/*---------------------------------------------------------------------------- -| Assuming at least one of the two 80-bit extended floating-point values -| pointed to by 'aSPtr' and 'bSPtr' is a NaN, stores the combined NaN result -| at the location pointed to by 'zSPtr'. If either original floating-point -| value is a signaling NaN, the invalid exception is raised. -*----------------------------------------------------------------------------*/ -void - softfloat_propagateNaNExtF80M( - const struct extFloat80M *aSPtr, - const struct extFloat80M *bSPtr, - struct extFloat80M *zSPtr - ) -{ - const struct extFloat80M *sPtr; - bool isSigNaNA; - uint_fast16_t uiZ64; - uint_fast64_t uiZ0; - - sPtr = aSPtr; - isSigNaNA = extF80M_isSignalingNaN( (const extFloat80_t *) aSPtr ); - if ( - isSigNaNA - || (bSPtr - && extF80M_isSignalingNaN( (const extFloat80_t *) bSPtr )) - ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - if ( isSigNaNA ) goto copyNonsig; - goto copyNonsigB; - } - uiZ64 = sPtr->signExp; - uiZ0 = sPtr->signif; - if ( isNaNExtF80UI( uiZ64, uiZ0 ) ) goto returnNonsig; - copyNonsigB: - sPtr = bSPtr; - copyNonsig: - uiZ64 = sPtr->signExp; - uiZ0 = sPtr->signif; - returnNonsig: - zSPtr->signExp = uiZ64; - zSPtr->signif = uiZ0 | UINT64_C( 0xC000000000000000 ); - -} - diff --git a/deps/SoftFloat-3e/source/ARM-VFPv2/s_propagateNaNExtF80UI.c b/deps/SoftFloat-3e/source/ARM-VFPv2/s_propagateNaNExtF80UI.c deleted file mode 100644 index bd23c2473658..000000000000 --- a/deps/SoftFloat-3e/source/ARM-VFPv2/s_propagateNaNExtF80UI.c +++ /dev/null @@ -1,83 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2017 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -/*---------------------------------------------------------------------------- -| Interpreting the unsigned integer formed from concatenating 'uiA64' and -| 'uiA0' as an 80-bit extended floating-point value, and likewise interpreting -| the unsigned integer formed from concatenating 'uiB64' and 'uiB0' as another -| 80-bit extended floating-point value, and assuming at least on of these -| floating-point values is a NaN, returns the bit pattern of the combined NaN -| result. If either original floating-point value is a signaling NaN, the -| invalid exception is raised. -*----------------------------------------------------------------------------*/ -struct uint128 - softfloat_propagateNaNExtF80UI( - uint_fast16_t uiA64, - uint_fast64_t uiA0, - uint_fast16_t uiB64, - uint_fast64_t uiB0 - ) -{ - bool isSigNaNA; - struct uint128 uiZ; - - isSigNaNA = softfloat_isSigNaNExtF80UI( uiA64, uiA0 ); - if ( isSigNaNA || softfloat_isSigNaNExtF80UI( uiB64, uiB0 ) ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - if ( isSigNaNA ) goto returnNonsigA; - goto returnNonsigB; - } - if ( isNaNExtF80UI( uiA64, uiA0 ) ) { - returnNonsigA: - uiZ.v64 = uiA64; - uiZ.v0 = uiA0; - } else { - returnNonsigB: - uiZ.v64 = uiB64; - uiZ.v0 = uiB0; - } - uiZ.v0 | UINT64_C( 0xC000000000000000 ); - return uiZ; - -} - diff --git a/deps/SoftFloat-3e/source/ARM-VFPv2/s_propagateNaNF128M.c b/deps/SoftFloat-3e/source/ARM-VFPv2/s_propagateNaNF128M.c deleted file mode 100644 index 23e766a1937f..000000000000 --- a/deps/SoftFloat-3e/source/ARM-VFPv2/s_propagateNaNF128M.c +++ /dev/null @@ -1,77 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2017 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -/*---------------------------------------------------------------------------- -| Assuming at least one of the two 128-bit floating-point values pointed to by -| 'aWPtr' and 'bWPtr' is a NaN, stores the combined NaN result at the location -| pointed to by 'zWPtr'. If either original floating-point value is a -| signaling NaN, the invalid exception is raised. Each of 'aWPtr', 'bWPtr', -| and 'zWPtr' points to an array of four 32-bit elements that concatenate in -| the platform's normal endian order to form a 128-bit floating-point value. -*----------------------------------------------------------------------------*/ -void - softfloat_propagateNaNF128M( - const uint32_t *aWPtr, const uint32_t *bWPtr, uint32_t *zWPtr ) -{ - const uint32_t *ptr; - bool isSigNaNA; - - ptr = aWPtr; - isSigNaNA = f128M_isSignalingNaN( (const float128_t *) aWPtr ); - if ( - isSigNaNA - || (bWPtr && f128M_isSignalingNaN( (const float128_t *) bWPtr )) - ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - if ( ! isSigNaNA ) ptr = bWPtr; - goto copyNonsig; - } - if ( ! softfloat_isNaNF128M( aWPtr ) ) ptr = bWPtr; - copyNonsig: - zWPtr[indexWordHi( 4 )] = ptr[indexWordHi( 4 )] | 0x00008000; - zWPtr[indexWord( 4, 2 )] = ptr[indexWord( 4, 2 )]; - zWPtr[indexWord( 4, 1 )] = ptr[indexWord( 4, 1 )]; - zWPtr[indexWord( 4, 0 )] = ptr[indexWord( 4, 0 )]; - -} - diff --git a/deps/SoftFloat-3e/source/ARM-VFPv2/s_propagateNaNF128UI.c b/deps/SoftFloat-3e/source/ARM-VFPv2/s_propagateNaNF128UI.c deleted file mode 100644 index b8882d77cfba..000000000000 --- a/deps/SoftFloat-3e/source/ARM-VFPv2/s_propagateNaNF128UI.c +++ /dev/null @@ -1,83 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2017 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -/*---------------------------------------------------------------------------- -| Interpreting the unsigned integer formed from concatenating 'uiA64' and -| 'uiA0' as a 128-bit floating-point value, and likewise interpreting the -| unsigned integer formed from concatenating 'uiB64' and 'uiB0' as another -| 128-bit floating-point value, and assuming at least on of these floating- -| point values is a NaN, returns the bit pattern of the combined NaN result. -| If either original floating-point value is a signaling NaN, the invalid -| exception is raised. -*----------------------------------------------------------------------------*/ -struct uint128 - softfloat_propagateNaNF128UI( - uint_fast64_t uiA64, - uint_fast64_t uiA0, - uint_fast64_t uiB64, - uint_fast64_t uiB0 - ) -{ - bool isSigNaNA; - struct uint128 uiZ; - - isSigNaNA = softfloat_isSigNaNF128UI( uiA64, uiA0 ); - if ( isSigNaNA || softfloat_isSigNaNF128UI( uiB64, uiB0 ) ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - if ( isSigNaNA ) goto returnNonsigA; - goto returnNonsigB; - } - if ( isNaNF128UI( uiA64, uiA0 ) ) { - returnNonsigA: - uiZ.v64 = uiA64; - uiZ.v0 = uiA0; - } else { - returnNonsigB: - uiZ.v64 = uiB64; - uiZ.v0 = uiB0; - } - uiZ.v64 |= UINT64_C( 0x0000800000000000 ); - return uiZ; - -} - diff --git a/deps/SoftFloat-3e/source/ARM-VFPv2/s_propagateNaNF16UI.c b/deps/SoftFloat-3e/source/ARM-VFPv2/s_propagateNaNF16UI.c deleted file mode 100644 index e333328746e6..000000000000 --- a/deps/SoftFloat-3e/source/ARM-VFPv2/s_propagateNaNF16UI.c +++ /dev/null @@ -1,63 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2017 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -/*---------------------------------------------------------------------------- -| Interpreting 'uiA' and 'uiB' as the bit patterns of two 16-bit floating- -| point values, at least one of which is a NaN, returns the bit pattern of -| the combined NaN result. If either 'uiA' or 'uiB' has the pattern of a -| signaling NaN, the invalid exception is raised. -*----------------------------------------------------------------------------*/ -uint_fast16_t - softfloat_propagateNaNF16UI( uint_fast16_t uiA, uint_fast16_t uiB ) -{ - bool isSigNaNA; - - isSigNaNA = softfloat_isSigNaNF16UI( uiA ); - if ( isSigNaNA || softfloat_isSigNaNF16UI( uiB ) ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - return (isSigNaNA ? uiA : uiB) | 0x0200; - } - return isNaNF16UI( uiA ) ? uiA : uiB; - -} - diff --git a/deps/SoftFloat-3e/source/ARM-VFPv2/s_propagateNaNF32UI.c b/deps/SoftFloat-3e/source/ARM-VFPv2/s_propagateNaNF32UI.c deleted file mode 100644 index c7508ae7cd1d..000000000000 --- a/deps/SoftFloat-3e/source/ARM-VFPv2/s_propagateNaNF32UI.c +++ /dev/null @@ -1,63 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2017 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -/*---------------------------------------------------------------------------- -| Interpreting 'uiA' and 'uiB' as the bit patterns of two 32-bit floating- -| point values, at least one of which is a NaN, returns the bit pattern of -| the combined NaN result. If either 'uiA' or 'uiB' has the pattern of a -| signaling NaN, the invalid exception is raised. -*----------------------------------------------------------------------------*/ -uint_fast32_t - softfloat_propagateNaNF32UI( uint_fast32_t uiA, uint_fast32_t uiB ) -{ - bool isSigNaNA; - - isSigNaNA = softfloat_isSigNaNF32UI( uiA ); - if ( isSigNaNA || softfloat_isSigNaNF32UI( uiB ) ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - return (isSigNaNA ? uiA : uiB) | 0x00400000; - } - return isNaNF32UI( uiA ) ? uiA : uiB; - -} - diff --git a/deps/SoftFloat-3e/source/ARM-VFPv2/s_propagateNaNF64UI.c b/deps/SoftFloat-3e/source/ARM-VFPv2/s_propagateNaNF64UI.c deleted file mode 100644 index 8c67763818a1..000000000000 --- a/deps/SoftFloat-3e/source/ARM-VFPv2/s_propagateNaNF64UI.c +++ /dev/null @@ -1,63 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2017 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -/*---------------------------------------------------------------------------- -| Interpreting 'uiA' and 'uiB' as the bit patterns of two 64-bit floating- -| point values, at least one of which is a NaN, returns the bit pattern of -| the combined NaN result. If either 'uiA' or 'uiB' has the pattern of a -| signaling NaN, the invalid exception is raised. -*----------------------------------------------------------------------------*/ -uint_fast64_t - softfloat_propagateNaNF64UI( uint_fast64_t uiA, uint_fast64_t uiB ) -{ - bool isSigNaNA; - - isSigNaNA = softfloat_isSigNaNF64UI( uiA ); - if ( isSigNaNA || softfloat_isSigNaNF64UI( uiB ) ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - return (isSigNaNA ? uiA : uiB) | UINT64_C( 0x0008000000000000 ); - } - return isNaNF64UI( uiA ) ? uiA : uiB; - -} - diff --git a/deps/SoftFloat-3e/source/ARM-VFPv2/softfloat_raiseFlags.c b/deps/SoftFloat-3e/source/ARM-VFPv2/softfloat_raiseFlags.c deleted file mode 100644 index 61046da3c05e..000000000000 --- a/deps/SoftFloat-3e/source/ARM-VFPv2/softfloat_raiseFlags.c +++ /dev/null @@ -1,52 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2017 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include "platform.h" -#include "softfloat.h" - -/*---------------------------------------------------------------------------- -| Raises the exceptions specified by 'flags'. Floating-point traps can be -| defined here if desired. It is currently not possible for such a trap -| to substitute a result value. If traps are not implemented, this routine -| should be simply 'softfloat_exceptionFlags |= flags;'. -*----------------------------------------------------------------------------*/ -void softfloat_raiseFlags( uint_fast8_t flags ) -{ - - softfloat_exceptionFlags |= flags; - -} - diff --git a/deps/SoftFloat-3e/source/ARM-VFPv2/specialize.h b/deps/SoftFloat-3e/source/ARM-VFPv2/specialize.h deleted file mode 100644 index 5321f33bcaad..000000000000 --- a/deps/SoftFloat-3e/source/ARM-VFPv2/specialize.h +++ /dev/null @@ -1,376 +0,0 @@ - -/*============================================================================ - -This C header file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the -University of California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#ifndef specialize_h -#define specialize_h 1 - -#include -#include -#include "primitiveTypes.h" -#include "softfloat.h" - -/*---------------------------------------------------------------------------- -| Default value for 'softfloat_detectTininess'. -*----------------------------------------------------------------------------*/ -#define init_detectTininess softfloat_tininess_beforeRounding - -/*---------------------------------------------------------------------------- -| The values to return on conversions to 32-bit integer formats that raise an -| invalid exception. -*----------------------------------------------------------------------------*/ -#define ui32_fromPosOverflow 0xFFFFFFFF -#define ui32_fromNegOverflow 0 -#define ui32_fromNaN 0 -#define i32_fromPosOverflow 0x7FFFFFFF -#define i32_fromNegOverflow (-0x7FFFFFFF - 1) -#define i32_fromNaN 0 - -/*---------------------------------------------------------------------------- -| The values to return on conversions to 64-bit integer formats that raise an -| invalid exception. -*----------------------------------------------------------------------------*/ -#define ui64_fromPosOverflow UINT64_C( 0xFFFFFFFFFFFFFFFF ) -#define ui64_fromNegOverflow 0 -#define ui64_fromNaN 0 -#define i64_fromPosOverflow INT64_C( 0x7FFFFFFFFFFFFFFF ) -#define i64_fromNegOverflow (-INT64_C( 0x7FFFFFFFFFFFFFFF ) - 1) -#define i64_fromNaN 0 - -/*---------------------------------------------------------------------------- -| "Common NaN" structure, used to transfer NaN representations from one format -| to another. -*----------------------------------------------------------------------------*/ -struct commonNaN { - bool sign; -#ifdef LITTLEENDIAN - uint64_t v0, v64; -#else - uint64_t v64, v0; -#endif -}; - -/*---------------------------------------------------------------------------- -| The bit pattern for a default generated 16-bit floating-point NaN. -*----------------------------------------------------------------------------*/ -#define defaultNaNF16UI 0x7E00 - -/*---------------------------------------------------------------------------- -| Returns true when 16-bit unsigned integer 'uiA' has the bit pattern of a -| 16-bit floating-point signaling NaN. -| Note: This macro evaluates its argument more than once. -*----------------------------------------------------------------------------*/ -#define softfloat_isSigNaNF16UI( uiA ) ((((uiA) & 0x7E00) == 0x7C00) && ((uiA) & 0x01FF)) - -/*---------------------------------------------------------------------------- -| Assuming 'uiA' has the bit pattern of a 16-bit floating-point NaN, converts -| this NaN to the common NaN form, and stores the resulting common NaN at the -| location pointed to by 'zPtr'. If the NaN is a signaling NaN, the invalid -| exception is raised. -*----------------------------------------------------------------------------*/ -void softfloat_f16UIToCommonNaN( uint_fast16_t uiA, struct commonNaN *zPtr ); - -/*---------------------------------------------------------------------------- -| Converts the common NaN pointed to by 'aPtr' into a 16-bit floating-point -| NaN, and returns the bit pattern of this value as an unsigned integer. -*----------------------------------------------------------------------------*/ -uint_fast16_t softfloat_commonNaNToF16UI( const struct commonNaN *aPtr ); - -/*---------------------------------------------------------------------------- -| Interpreting 'uiA' and 'uiB' as the bit patterns of two 16-bit floating- -| point values, at least one of which is a NaN, returns the bit pattern of -| the combined NaN result. If either 'uiA' or 'uiB' has the pattern of a -| signaling NaN, the invalid exception is raised. -*----------------------------------------------------------------------------*/ -uint_fast16_t - softfloat_propagateNaNF16UI( uint_fast16_t uiA, uint_fast16_t uiB ); - -/*---------------------------------------------------------------------------- -| The bit pattern for a default generated 32-bit floating-point NaN. -*----------------------------------------------------------------------------*/ -#define defaultNaNF32UI 0x7FC00000 - -/*---------------------------------------------------------------------------- -| Returns true when 32-bit unsigned integer 'uiA' has the bit pattern of a -| 32-bit floating-point signaling NaN. -| Note: This macro evaluates its argument more than once. -*----------------------------------------------------------------------------*/ -#define softfloat_isSigNaNF32UI( uiA ) ((((uiA) & 0x7FC00000) == 0x7F800000) && ((uiA) & 0x003FFFFF)) - -/*---------------------------------------------------------------------------- -| Assuming 'uiA' has the bit pattern of a 32-bit floating-point NaN, converts -| this NaN to the common NaN form, and stores the resulting common NaN at the -| location pointed to by 'zPtr'. If the NaN is a signaling NaN, the invalid -| exception is raised. -*----------------------------------------------------------------------------*/ -void softfloat_f32UIToCommonNaN( uint_fast32_t uiA, struct commonNaN *zPtr ); - -/*---------------------------------------------------------------------------- -| Converts the common NaN pointed to by 'aPtr' into a 32-bit floating-point -| NaN, and returns the bit pattern of this value as an unsigned integer. -*----------------------------------------------------------------------------*/ -uint_fast32_t softfloat_commonNaNToF32UI( const struct commonNaN *aPtr ); - -/*---------------------------------------------------------------------------- -| Interpreting 'uiA' and 'uiB' as the bit patterns of two 32-bit floating- -| point values, at least one of which is a NaN, returns the bit pattern of -| the combined NaN result. If either 'uiA' or 'uiB' has the pattern of a -| signaling NaN, the invalid exception is raised. -*----------------------------------------------------------------------------*/ -uint_fast32_t - softfloat_propagateNaNF32UI( uint_fast32_t uiA, uint_fast32_t uiB ); - -/*---------------------------------------------------------------------------- -| The bit pattern for a default generated 64-bit floating-point NaN. -*----------------------------------------------------------------------------*/ -#define defaultNaNF64UI UINT64_C( 0x7FF8000000000000 ) - -/*---------------------------------------------------------------------------- -| Returns true when 64-bit unsigned integer 'uiA' has the bit pattern of a -| 64-bit floating-point signaling NaN. -| Note: This macro evaluates its argument more than once. -*----------------------------------------------------------------------------*/ -#define softfloat_isSigNaNF64UI( uiA ) ((((uiA) & UINT64_C( 0x7FF8000000000000 )) == UINT64_C( 0x7FF0000000000000 )) && ((uiA) & UINT64_C( 0x0007FFFFFFFFFFFF ))) - -/*---------------------------------------------------------------------------- -| Assuming 'uiA' has the bit pattern of a 64-bit floating-point NaN, converts -| this NaN to the common NaN form, and stores the resulting common NaN at the -| location pointed to by 'zPtr'. If the NaN is a signaling NaN, the invalid -| exception is raised. -*----------------------------------------------------------------------------*/ -void softfloat_f64UIToCommonNaN( uint_fast64_t uiA, struct commonNaN *zPtr ); - -/*---------------------------------------------------------------------------- -| Converts the common NaN pointed to by 'aPtr' into a 64-bit floating-point -| NaN, and returns the bit pattern of this value as an unsigned integer. -*----------------------------------------------------------------------------*/ -uint_fast64_t softfloat_commonNaNToF64UI( const struct commonNaN *aPtr ); - -/*---------------------------------------------------------------------------- -| Interpreting 'uiA' and 'uiB' as the bit patterns of two 64-bit floating- -| point values, at least one of which is a NaN, returns the bit pattern of -| the combined NaN result. If either 'uiA' or 'uiB' has the pattern of a -| signaling NaN, the invalid exception is raised. -*----------------------------------------------------------------------------*/ -uint_fast64_t - softfloat_propagateNaNF64UI( uint_fast64_t uiA, uint_fast64_t uiB ); - -/*---------------------------------------------------------------------------- -| The bit pattern for a default generated 80-bit extended floating-point NaN. -*----------------------------------------------------------------------------*/ -#define defaultNaNExtF80UI64 0x7FFF -#define defaultNaNExtF80UI0 UINT64_C( 0xC000000000000000 ) - -/*---------------------------------------------------------------------------- -| Returns true when the 80-bit unsigned integer formed from concatenating -| 16-bit 'uiA64' and 64-bit 'uiA0' has the bit pattern of an 80-bit extended -| floating-point signaling NaN. -| Note: This macro evaluates its arguments more than once. -*----------------------------------------------------------------------------*/ -#define softfloat_isSigNaNExtF80UI( uiA64, uiA0 ) ((((uiA64) & 0x7FFF) == 0x7FFF) && ! ((uiA0) & UINT64_C( 0x4000000000000000 )) && ((uiA0) & UINT64_C( 0x3FFFFFFFFFFFFFFF ))) - -#ifdef SOFTFLOAT_FAST_INT64 - -/*---------------------------------------------------------------------------- -| The following functions are needed only when 'SOFTFLOAT_FAST_INT64' is -| defined. -*----------------------------------------------------------------------------*/ - -/*---------------------------------------------------------------------------- -| Assuming the unsigned integer formed from concatenating 'uiA64' and 'uiA0' -| has the bit pattern of an 80-bit extended floating-point NaN, converts -| this NaN to the common NaN form, and stores the resulting common NaN at the -| location pointed to by 'zPtr'. If the NaN is a signaling NaN, the invalid -| exception is raised. -*----------------------------------------------------------------------------*/ -void - softfloat_extF80UIToCommonNaN( - uint_fast16_t uiA64, uint_fast64_t uiA0, struct commonNaN *zPtr ); - -/*---------------------------------------------------------------------------- -| Converts the common NaN pointed to by 'aPtr' into an 80-bit extended -| floating-point NaN, and returns the bit pattern of this value as an unsigned -| integer. -*----------------------------------------------------------------------------*/ -struct uint128 softfloat_commonNaNToExtF80UI( const struct commonNaN *aPtr ); - -/*---------------------------------------------------------------------------- -| Interpreting the unsigned integer formed from concatenating 'uiA64' and -| 'uiA0' as an 80-bit extended floating-point value, and likewise interpreting -| the unsigned integer formed from concatenating 'uiB64' and 'uiB0' as another -| 80-bit extended floating-point value, and assuming at least on of these -| floating-point values is a NaN, returns the bit pattern of the combined NaN -| result. If either original floating-point value is a signaling NaN, the -| invalid exception is raised. -*----------------------------------------------------------------------------*/ -struct uint128 - softfloat_propagateNaNExtF80UI( - uint_fast16_t uiA64, - uint_fast64_t uiA0, - uint_fast16_t uiB64, - uint_fast64_t uiB0 - ); - -/*---------------------------------------------------------------------------- -| The bit pattern for a default generated 128-bit floating-point NaN. -*----------------------------------------------------------------------------*/ -#define defaultNaNF128UI64 UINT64_C( 0x7FFF800000000000 ) -#define defaultNaNF128UI0 UINT64_C( 0 ) - -/*---------------------------------------------------------------------------- -| Returns true when the 128-bit unsigned integer formed from concatenating -| 64-bit 'uiA64' and 64-bit 'uiA0' has the bit pattern of a 128-bit floating- -| point signaling NaN. -| Note: This macro evaluates its arguments more than once. -*----------------------------------------------------------------------------*/ -#define softfloat_isSigNaNF128UI( uiA64, uiA0 ) ((((uiA64) & UINT64_C( 0x7FFF800000000000 )) == UINT64_C( 0x7FFF000000000000 )) && ((uiA0) || ((uiA64) & UINT64_C( 0x00007FFFFFFFFFFF )))) - -/*---------------------------------------------------------------------------- -| Assuming the unsigned integer formed from concatenating 'uiA64' and 'uiA0' -| has the bit pattern of a 128-bit floating-point NaN, converts this NaN to -| the common NaN form, and stores the resulting common NaN at the location -| pointed to by 'zPtr'. If the NaN is a signaling NaN, the invalid exception -| is raised. -*----------------------------------------------------------------------------*/ -void - softfloat_f128UIToCommonNaN( - uint_fast64_t uiA64, uint_fast64_t uiA0, struct commonNaN *zPtr ); - -/*---------------------------------------------------------------------------- -| Converts the common NaN pointed to by 'aPtr' into a 128-bit floating-point -| NaN, and returns the bit pattern of this value as an unsigned integer. -*----------------------------------------------------------------------------*/ -struct uint128 softfloat_commonNaNToF128UI( const struct commonNaN * ); - -/*---------------------------------------------------------------------------- -| Interpreting the unsigned integer formed from concatenating 'uiA64' and -| 'uiA0' as a 128-bit floating-point value, and likewise interpreting the -| unsigned integer formed from concatenating 'uiB64' and 'uiB0' as another -| 128-bit floating-point value, and assuming at least on of these floating- -| point values is a NaN, returns the bit pattern of the combined NaN result. -| If either original floating-point value is a signaling NaN, the invalid -| exception is raised. -*----------------------------------------------------------------------------*/ -struct uint128 - softfloat_propagateNaNF128UI( - uint_fast64_t uiA64, - uint_fast64_t uiA0, - uint_fast64_t uiB64, - uint_fast64_t uiB0 - ); - -#else - -/*---------------------------------------------------------------------------- -| The following functions are needed only when 'SOFTFLOAT_FAST_INT64' is not -| defined. -*----------------------------------------------------------------------------*/ - -/*---------------------------------------------------------------------------- -| Assuming the 80-bit extended floating-point value pointed to by 'aSPtr' is -| a NaN, converts this NaN to the common NaN form, and stores the resulting -| common NaN at the location pointed to by 'zPtr'. If the NaN is a signaling -| NaN, the invalid exception is raised. -*----------------------------------------------------------------------------*/ -void - softfloat_extF80MToCommonNaN( - const struct extFloat80M *aSPtr, struct commonNaN *zPtr ); - -/*---------------------------------------------------------------------------- -| Converts the common NaN pointed to by 'aPtr' into an 80-bit extended -| floating-point NaN, and stores this NaN at the location pointed to by -| 'zSPtr'. -*----------------------------------------------------------------------------*/ -void - softfloat_commonNaNToExtF80M( - const struct commonNaN *aPtr, struct extFloat80M *zSPtr ); - -/*---------------------------------------------------------------------------- -| Assuming at least one of the two 80-bit extended floating-point values -| pointed to by 'aSPtr' and 'bSPtr' is a NaN, stores the combined NaN result -| at the location pointed to by 'zSPtr'. If either original floating-point -| value is a signaling NaN, the invalid exception is raised. -*----------------------------------------------------------------------------*/ -void - softfloat_propagateNaNExtF80M( - const struct extFloat80M *aSPtr, - const struct extFloat80M *bSPtr, - struct extFloat80M *zSPtr - ); - -/*---------------------------------------------------------------------------- -| The bit pattern for a default generated 128-bit floating-point NaN. -*----------------------------------------------------------------------------*/ -#define defaultNaNF128UI96 0x7FFF8000 -#define defaultNaNF128UI64 0 -#define defaultNaNF128UI32 0 -#define defaultNaNF128UI0 0 - -/*---------------------------------------------------------------------------- -| Assuming the 128-bit floating-point value pointed to by 'aWPtr' is a NaN, -| converts this NaN to the common NaN form, and stores the resulting common -| NaN at the location pointed to by 'zPtr'. If the NaN is a signaling NaN, -| the invalid exception is raised. Argument 'aWPtr' points to an array of -| four 32-bit elements that concatenate in the platform's normal endian order -| to form a 128-bit floating-point value. -*----------------------------------------------------------------------------*/ -void - softfloat_f128MToCommonNaN( const uint32_t *aWPtr, struct commonNaN *zPtr ); - -/*---------------------------------------------------------------------------- -| Converts the common NaN pointed to by 'aPtr' into a 128-bit floating-point -| NaN, and stores this NaN at the location pointed to by 'zWPtr'. Argument -| 'zWPtr' points to an array of four 32-bit elements that concatenate in the -| platform's normal endian order to form a 128-bit floating-point value. -*----------------------------------------------------------------------------*/ -void - softfloat_commonNaNToF128M( const struct commonNaN *aPtr, uint32_t *zWPtr ); - -/*---------------------------------------------------------------------------- -| Assuming at least one of the two 128-bit floating-point values pointed to by -| 'aWPtr' and 'bWPtr' is a NaN, stores the combined NaN result at the location -| pointed to by 'zWPtr'. If either original floating-point value is a -| signaling NaN, the invalid exception is raised. Each of 'aWPtr', 'bWPtr', -| and 'zWPtr' points to an array of four 32-bit elements that concatenate in -| the platform's normal endian order to form a 128-bit floating-point value. -*----------------------------------------------------------------------------*/ -void - softfloat_propagateNaNF128M( - const uint32_t *aWPtr, const uint32_t *bWPtr, uint32_t *zWPtr ); - -#endif - -#endif - diff --git a/deps/SoftFloat-3e/source/extF80M_add.c b/deps/SoftFloat-3e/source/extF80M_add.c deleted file mode 100644 index 02e415fcc133..000000000000 --- a/deps/SoftFloat-3e/source/extF80M_add.c +++ /dev/null @@ -1,100 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "internals.h" -#include "softfloat.h" - -#ifdef SOFTFLOAT_FAST_INT64 - -void - extF80M_add( - const extFloat80_t *aPtr, const extFloat80_t *bPtr, extFloat80_t *zPtr ) -{ - const struct extFloat80M *aSPtr, *bSPtr; - uint_fast16_t uiA64; - uint_fast64_t uiA0; - bool signA; - uint_fast16_t uiB64; - uint_fast64_t uiB0; - bool signB; -#if ! defined INLINE_LEVEL || (INLINE_LEVEL < 2) - extFloat80_t - (*magsFuncPtr)( - uint_fast16_t, uint_fast64_t, uint_fast16_t, uint_fast64_t, bool ); -#endif - - aSPtr = (const struct extFloat80M *) aPtr; - bSPtr = (const struct extFloat80M *) bPtr; - uiA64 = aSPtr->signExp; - uiA0 = aSPtr->signif; - signA = signExtF80UI64( uiA64 ); - uiB64 = bSPtr->signExp; - uiB0 = bSPtr->signif; - signB = signExtF80UI64( uiB64 ); -#if defined INLINE_LEVEL && (2 <= INLINE_LEVEL) - if ( signA == signB ) { - *zPtr = softfloat_addMagsExtF80( uiA64, uiA0, uiB64, uiB0, signA ); - } else { - *zPtr = softfloat_subMagsExtF80( uiA64, uiA0, uiB64, uiB0, signA ); - } -#else - magsFuncPtr = - (signA == signB) ? softfloat_addMagsExtF80 : softfloat_subMagsExtF80; - *zPtr = (*magsFuncPtr)( uiA64, uiA0, uiB64, uiB0, signA ); -#endif - -} - -#else - -void - extF80M_add( - const extFloat80_t *aPtr, const extFloat80_t *bPtr, extFloat80_t *zPtr ) -{ - - softfloat_addExtF80M( - (const struct extFloat80M *) aPtr, - (const struct extFloat80M *) bPtr, - (struct extFloat80M *) zPtr, - false - ); - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/extF80M_div.c b/deps/SoftFloat-3e/source/extF80M_div.c deleted file mode 100644 index 4d543ce9e510..000000000000 --- a/deps/SoftFloat-3e/source/extF80M_div.c +++ /dev/null @@ -1,194 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -#ifdef SOFTFLOAT_FAST_INT64 - -void - extF80M_div( - const extFloat80_t *aPtr, const extFloat80_t *bPtr, extFloat80_t *zPtr ) -{ - - *zPtr = extF80_div( *aPtr, *bPtr ); - -} - -#else - -void - extF80M_div( - const extFloat80_t *aPtr, const extFloat80_t *bPtr, extFloat80_t *zPtr ) -{ - const struct extFloat80M *aSPtr, *bSPtr; - struct extFloat80M *zSPtr; - uint_fast16_t uiA64; - int32_t expA; - uint_fast16_t uiB64; - int32_t expB; - bool signZ; - uint64_t sigA, x64; - int32_t expZ; - int shiftDist; - uint32_t y[3], recip32, sigB[3]; - int ix; - uint32_t q, qs[2]; - uint_fast16_t uiZ64; - uint64_t uiZ0; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - aSPtr = (const struct extFloat80M *) aPtr; - bSPtr = (const struct extFloat80M *) bPtr; - zSPtr = (struct extFloat80M *) zPtr; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uiA64 = aSPtr->signExp; - expA = expExtF80UI64( uiA64 ); - uiB64 = bSPtr->signExp; - expB = expExtF80UI64( uiB64 ); - signZ = signExtF80UI64( uiA64 ) ^ signExtF80UI64( uiB64 ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( (expA == 0x7FFF) || (expB == 0x7FFF) ) { - if ( softfloat_tryPropagateNaNExtF80M( aSPtr, bSPtr, zSPtr ) ) return; - if ( expA == 0x7FFF ) { - if ( expB == 0x7FFF ) goto invalid; - goto infinity; - } - goto zero; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - sigA = aSPtr->signif; - x64 = bSPtr->signif; - if ( ! expB ) expB = 1; - if ( ! (x64 & UINT64_C( 0x8000000000000000 )) ) { - if ( ! x64 ) { - if ( ! sigA ) goto invalid; - softfloat_raiseFlags( softfloat_flag_infinite ); - goto infinity; - } - expB += softfloat_normExtF80SigM( &x64 ); - } - if ( ! expA ) expA = 1; - if ( ! (sigA & UINT64_C( 0x8000000000000000 )) ) { - if ( ! sigA ) goto zero; - expA += softfloat_normExtF80SigM( &sigA ); - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - expZ = expA - expB + 0x3FFF; - shiftDist = 29; - if ( sigA < x64 ) { - --expZ; - shiftDist = 30; - } - softfloat_shortShiftLeft64To96M( sigA, shiftDist, y ); - recip32 = softfloat_approxRecip32_1( x64>>32 ); - sigB[indexWord( 3, 0 )] = (uint32_t) x64<<30; - x64 >>= 2; - sigB[indexWord( 3, 2 )] = x64>>32; - sigB[indexWord( 3, 1 )] = x64; - ix = 2; - for (;;) { - x64 = (uint64_t) y[indexWordHi( 3 )] * recip32; - q = (x64 + 0x80000000)>>32; - --ix; - if ( ix < 0 ) break; - softfloat_remStep96MBy32( y, 29, sigB, q, y ); - if ( y[indexWordHi( 3 )] & 0x80000000 ) { - --q; - softfloat_add96M( y, sigB, y ); - } - qs[ix] = q; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( ((q + 1) & 0x3FFFFF) < 2 ) { - softfloat_remStep96MBy32( y, 29, sigB, q, y ); - if ( y[indexWordHi( 3 )] & 0x80000000 ) { - --q; - softfloat_add96M( y, sigB, y ); - } else if ( softfloat_compare96M( sigB, y ) <= 0 ) { - ++q; - softfloat_sub96M( y, sigB, y ); - } - if ( - y[indexWordLo( 3 )] || y[indexWord( 3, 1 )] || y[indexWord( 3, 2 )] - ) { - q |= 1; - } - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - x64 = (uint64_t) q<<9; - y[indexWord( 3, 0 )] = x64; - x64 = ((uint64_t) qs[0]<<6) + (x64>>32); - y[indexWord( 3, 1 )] = x64; - y[indexWord( 3, 2 )] = (qs[1]<<3) + (x64>>32); - softfloat_roundPackMToExtF80M( - signZ, expZ, y, extF80_roundingPrecision, zSPtr ); - return; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - invalid: - softfloat_invalidExtF80M( zSPtr ); - return; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - infinity: - uiZ64 = packToExtF80UI64( signZ, 0x7FFF ); - uiZ0 = UINT64_C( 0x8000000000000000 ); - goto uiZ; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - zero: - uiZ64 = packToExtF80UI64( signZ, 0 ); - uiZ0 = 0; - uiZ: - zSPtr->signExp = uiZ64; - zSPtr->signif = uiZ0; - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/extF80M_eq.c b/deps/SoftFloat-3e/source/extF80M_eq.c deleted file mode 100644 index e17aa24351e9..000000000000 --- a/deps/SoftFloat-3e/source/extF80M_eq.c +++ /dev/null @@ -1,98 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -#ifdef SOFTFLOAT_FAST_INT64 - -bool extF80M_eq( const extFloat80_t *aPtr, const extFloat80_t *bPtr ) -{ - - return extF80_eq( *aPtr, *bPtr ); - -} - -#else - -bool extF80M_eq( const extFloat80_t *aPtr, const extFloat80_t *bPtr ) -{ - const struct extFloat80M *aSPtr, *bSPtr; - uint_fast16_t uiA64; - uint64_t uiA0; - uint_fast16_t uiB64; - uint64_t uiB0; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - aSPtr = (const struct extFloat80M *) aPtr; - bSPtr = (const struct extFloat80M *) bPtr; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uiA64 = aSPtr->signExp; - uiA0 = aSPtr->signif; - uiB64 = bSPtr->signExp; - uiB0 = bSPtr->signif; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( isNaNExtF80UI( uiA64, uiA0 ) || isNaNExtF80UI( uiB64, uiB0 ) ) { - if ( - softfloat_isSigNaNExtF80UI( uiA64, uiA0 ) - || softfloat_isSigNaNExtF80UI( uiB64, uiB0 ) - ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - } - return false; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( uiA0 == uiB0 ) { - return (uiA64 == uiB64) || ! uiA0; - } else { - if ( ! ((uiA0 & uiB0) & UINT64_C( 0x8000000000000000 )) ) { - return ! softfloat_compareNonnormExtF80M( aSPtr, bSPtr ); - } - return false; - } - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/extF80M_eq_signaling.c b/deps/SoftFloat-3e/source/extF80M_eq_signaling.c deleted file mode 100644 index c4a7322393ad..000000000000 --- a/deps/SoftFloat-3e/source/extF80M_eq_signaling.c +++ /dev/null @@ -1,92 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "softfloat.h" - -#ifdef SOFTFLOAT_FAST_INT64 - -bool extF80M_eq_signaling( const extFloat80_t *aPtr, const extFloat80_t *bPtr ) -{ - - return extF80_eq_signaling( *aPtr, *bPtr ); - -} - -#else - -bool extF80M_eq_signaling( const extFloat80_t *aPtr, const extFloat80_t *bPtr ) -{ - const struct extFloat80M *aSPtr, *bSPtr; - uint_fast16_t uiA64; - uint64_t uiA0; - uint_fast16_t uiB64; - uint64_t uiB0; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - aSPtr = (const struct extFloat80M *) aPtr; - bSPtr = (const struct extFloat80M *) bPtr; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uiA64 = aSPtr->signExp; - uiA0 = aSPtr->signif; - uiB64 = bSPtr->signExp; - uiB0 = bSPtr->signif; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( isNaNExtF80UI( uiA64, uiA0 ) || isNaNExtF80UI( uiB64, uiB0 ) ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - return false; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( uiA0 == uiB0 ) { - return (uiA64 == uiB64) || ! uiA0; - } else { - if ( ! ((uiA0 & uiB0) & UINT64_C( 0x8000000000000000 )) ) { - return ! softfloat_compareNonnormExtF80M( aSPtr, bSPtr ); - } - return false; - } - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/extF80M_le.c b/deps/SoftFloat-3e/source/extF80M_le.c deleted file mode 100644 index e54eb9eea095..000000000000 --- a/deps/SoftFloat-3e/source/extF80M_le.c +++ /dev/null @@ -1,106 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "softfloat.h" - -#ifdef SOFTFLOAT_FAST_INT64 - -bool extF80M_le( const extFloat80_t *aPtr, const extFloat80_t *bPtr ) -{ - - return extF80_le( *aPtr, *bPtr ); - -} - -#else - -bool extF80M_le( const extFloat80_t *aPtr, const extFloat80_t *bPtr ) -{ - const struct extFloat80M *aSPtr, *bSPtr; - uint_fast16_t uiA64; - uint64_t uiA0; - uint_fast16_t uiB64; - uint64_t uiB0; - bool signA, ltMags; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - aSPtr = (const struct extFloat80M *) aPtr; - bSPtr = (const struct extFloat80M *) bPtr; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uiA64 = aSPtr->signExp; - uiA0 = aSPtr->signif; - uiB64 = bSPtr->signExp; - uiB0 = bSPtr->signif; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( isNaNExtF80UI( uiA64, uiA0 ) || isNaNExtF80UI( uiB64, uiB0 ) ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - return false; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - signA = signExtF80UI64( uiA64 ); - if ( (uiA64 ^ uiB64) & 0x8000 ) { - /*-------------------------------------------------------------------- - | Signs are different. - *--------------------------------------------------------------------*/ - return signA || ! (uiA0 | uiB0); - } else { - /*-------------------------------------------------------------------- - | Signs are the same. - *--------------------------------------------------------------------*/ - if ( ! ((uiA0 & uiB0) & UINT64_C( 0x8000000000000000 )) ) { - return (softfloat_compareNonnormExtF80M( aSPtr, bSPtr ) <= 0); - } - if ( uiA64 == uiB64 ) { - if ( uiA0 == uiB0 ) return true; - ltMags = (uiA0 < uiB0); - } else { - ltMags = (uiA64 < uiB64); - } - return signA ^ ltMags; - } - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/extF80M_le_quiet.c b/deps/SoftFloat-3e/source/extF80M_le_quiet.c deleted file mode 100644 index 943f262061bf..000000000000 --- a/deps/SoftFloat-3e/source/extF80M_le_quiet.c +++ /dev/null @@ -1,112 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -#ifdef SOFTFLOAT_FAST_INT64 - -bool extF80M_le_quiet( const extFloat80_t *aPtr, const extFloat80_t *bPtr ) -{ - - return extF80_le_quiet( *aPtr, *bPtr ); - -} - -#else - -bool extF80M_le_quiet( const extFloat80_t *aPtr, const extFloat80_t *bPtr ) -{ - const struct extFloat80M *aSPtr, *bSPtr; - uint_fast16_t uiA64; - uint64_t uiA0; - uint_fast16_t uiB64; - uint64_t uiB0; - bool signA, ltMags; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - aSPtr = (const struct extFloat80M *) aPtr; - bSPtr = (const struct extFloat80M *) bPtr; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uiA64 = aSPtr->signExp; - uiA0 = aSPtr->signif; - uiB64 = bSPtr->signExp; - uiB0 = bSPtr->signif; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( isNaNExtF80UI( uiA64, uiA0 ) || isNaNExtF80UI( uiB64, uiB0 ) ) { - if ( - softfloat_isSigNaNExtF80UI( uiA64, uiA0 ) - || softfloat_isSigNaNExtF80UI( uiB64, uiB0 ) - ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - } - return false; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - signA = signExtF80UI64( uiA64 ); - if ( (uiA64 ^ uiB64) & 0x8000 ) { - /*-------------------------------------------------------------------- - | Signs are different. - *--------------------------------------------------------------------*/ - return signA || ! (uiA0 | uiB0); - } else { - /*-------------------------------------------------------------------- - | Signs are the same. - *--------------------------------------------------------------------*/ - if ( ! ((uiA0 & uiB0) & UINT64_C( 0x8000000000000000 )) ) { - return (softfloat_compareNonnormExtF80M( aSPtr, bSPtr ) <= 0); - } - if ( uiA64 == uiB64 ) { - if ( uiA0 == uiB0 ) return true; - ltMags = (uiA0 < uiB0); - } else { - ltMags = (uiA64 < uiB64); - } - return signA ^ ltMags; - } - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/extF80M_lt.c b/deps/SoftFloat-3e/source/extF80M_lt.c deleted file mode 100644 index cbc562f64d7c..000000000000 --- a/deps/SoftFloat-3e/source/extF80M_lt.c +++ /dev/null @@ -1,106 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "softfloat.h" - -#ifdef SOFTFLOAT_FAST_INT64 - -bool extF80M_lt( const extFloat80_t *aPtr, const extFloat80_t *bPtr ) -{ - - return extF80_lt( *aPtr, *bPtr ); - -} - -#else - -bool extF80M_lt( const extFloat80_t *aPtr, const extFloat80_t *bPtr ) -{ - const struct extFloat80M *aSPtr, *bSPtr; - uint_fast16_t uiA64; - uint64_t uiA0; - uint_fast16_t uiB64; - uint64_t uiB0; - bool signA, ltMags; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - aSPtr = (const struct extFloat80M *) aPtr; - bSPtr = (const struct extFloat80M *) bPtr; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uiA64 = aSPtr->signExp; - uiA0 = aSPtr->signif; - uiB64 = bSPtr->signExp; - uiB0 = bSPtr->signif; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( isNaNExtF80UI( uiA64, uiA0 ) || isNaNExtF80UI( uiB64, uiB0 ) ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - return false; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - signA = signExtF80UI64( uiA64 ); - if ( (uiA64 ^ uiB64) & 0x8000 ) { - /*-------------------------------------------------------------------- - | Signs are different. - *--------------------------------------------------------------------*/ - return signA && ((uiA0 | uiB0) != 0); - } else { - /*-------------------------------------------------------------------- - | Signs are the same. - *--------------------------------------------------------------------*/ - if ( ! ((uiA0 & uiB0) & UINT64_C( 0x8000000000000000 )) ) { - return (softfloat_compareNonnormExtF80M( aSPtr, bSPtr ) < 0); - } - if ( uiA64 == uiB64 ) { - if ( uiA0 == uiB0 ) return false; - ltMags = (uiA0 < uiB0); - } else { - ltMags = (uiA64 < uiB64); - } - return signA ^ ltMags; - } - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/extF80M_lt_quiet.c b/deps/SoftFloat-3e/source/extF80M_lt_quiet.c deleted file mode 100644 index 650586d025a9..000000000000 --- a/deps/SoftFloat-3e/source/extF80M_lt_quiet.c +++ /dev/null @@ -1,112 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -#ifdef SOFTFLOAT_FAST_INT64 - -bool extF80M_lt_quiet( const extFloat80_t *aPtr, const extFloat80_t *bPtr ) -{ - - return extF80_lt_quiet( *aPtr, *bPtr ); - -} - -#else - -bool extF80M_lt_quiet( const extFloat80_t *aPtr, const extFloat80_t *bPtr ) -{ - const struct extFloat80M *aSPtr, *bSPtr; - uint_fast16_t uiA64; - uint64_t uiA0; - uint_fast16_t uiB64; - uint64_t uiB0; - bool signA, ltMags; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - aSPtr = (const struct extFloat80M *) aPtr; - bSPtr = (const struct extFloat80M *) bPtr; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uiA64 = aSPtr->signExp; - uiA0 = aSPtr->signif; - uiB64 = bSPtr->signExp; - uiB0 = bSPtr->signif; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( isNaNExtF80UI( uiA64, uiA0 ) || isNaNExtF80UI( uiB64, uiB0 ) ) { - if ( - softfloat_isSigNaNExtF80UI( uiA64, uiA0 ) - || softfloat_isSigNaNExtF80UI( uiB64, uiB0 ) - ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - } - return false; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - signA = signExtF80UI64( uiA64 ); - if ( (uiA64 ^ uiB64) & 0x8000 ) { - /*-------------------------------------------------------------------- - | Signs are different. - *--------------------------------------------------------------------*/ - return signA && ((uiA0 | uiB0) != 0); - } else { - /*-------------------------------------------------------------------- - | Signs are the same. - *--------------------------------------------------------------------*/ - if ( ! ((uiA0 & uiB0) & UINT64_C( 0x8000000000000000 )) ) { - return (softfloat_compareNonnormExtF80M( aSPtr, bSPtr ) < 0); - } - if ( uiA64 == uiB64 ) { - if ( uiA0 == uiB0 ) return false; - ltMags = (uiA0 < uiB0); - } else { - ltMags = (uiA64 < uiB64); - } - return signA ^ ltMags; - } - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/extF80M_mul.c b/deps/SoftFloat-3e/source/extF80M_mul.c deleted file mode 100644 index 281394f713f5..000000000000 --- a/deps/SoftFloat-3e/source/extF80M_mul.c +++ /dev/null @@ -1,139 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -#ifdef SOFTFLOAT_FAST_INT64 - -void - extF80M_mul( - const extFloat80_t *aPtr, const extFloat80_t *bPtr, extFloat80_t *zPtr ) -{ - - *zPtr = extF80_mul( *aPtr, *bPtr ); - -} - -#else - -void - extF80M_mul( - const extFloat80_t *aPtr, const extFloat80_t *bPtr, extFloat80_t *zPtr ) -{ - const struct extFloat80M *aSPtr, *bSPtr; - struct extFloat80M *zSPtr; - uint_fast16_t uiA64; - int32_t expA; - uint_fast16_t uiB64; - int32_t expB; - bool signZ; - uint_fast16_t exp, uiZ64; - uint64_t uiZ0, sigA, sigB; - int32_t expZ; - uint32_t sigProd[4], *extSigZPtr; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - aSPtr = (const struct extFloat80M *) aPtr; - bSPtr = (const struct extFloat80M *) bPtr; - zSPtr = (struct extFloat80M *) zPtr; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uiA64 = aSPtr->signExp; - expA = expExtF80UI64( uiA64 ); - uiB64 = bSPtr->signExp; - expB = expExtF80UI64( uiB64 ); - signZ = signExtF80UI64( uiA64 ) ^ signExtF80UI64( uiB64 ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( (expA == 0x7FFF) || (expB == 0x7FFF) ) { - if ( softfloat_tryPropagateNaNExtF80M( aSPtr, bSPtr, zSPtr ) ) return; - if ( - (! aSPtr->signif && (expA != 0x7FFF)) - || (! bSPtr->signif && (expB != 0x7FFF)) - ) { - softfloat_invalidExtF80M( zSPtr ); - return; - } - uiZ64 = packToExtF80UI64( signZ, 0x7FFF ); - uiZ0 = UINT64_C( 0x8000000000000000 ); - goto uiZ; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( ! expA ) expA = 1; - sigA = aSPtr->signif; - if ( ! (sigA & UINT64_C( 0x8000000000000000 )) ) { - if ( ! sigA ) goto zero; - expA += softfloat_normExtF80SigM( &sigA ); - } - if ( ! expB ) expB = 1; - sigB = bSPtr->signif; - if ( ! (sigB & UINT64_C( 0x8000000000000000 )) ) { - if ( ! sigB ) goto zero; - expB += softfloat_normExtF80SigM( &sigB ); - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - expZ = expA + expB - 0x3FFE; - softfloat_mul64To128M( sigA, sigB, sigProd ); - if ( sigProd[indexWordLo( 4 )] ) sigProd[indexWord( 4, 1 )] |= 1; - extSigZPtr = &sigProd[indexMultiwordHi( 4, 3 )]; - if ( sigProd[indexWordHi( 4 )] < 0x80000000 ) { - --expZ; - softfloat_add96M( extSigZPtr, extSigZPtr, extSigZPtr ); - } - softfloat_roundPackMToExtF80M( - signZ, expZ, extSigZPtr, extF80_roundingPrecision, zSPtr ); - return; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - zero: - uiZ64 = packToExtF80UI64( signZ, 0 ); - uiZ0 = 0; - uiZ: - zSPtr->signExp = uiZ64; - zSPtr->signif = uiZ0; - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/extF80M_rem.c b/deps/SoftFloat-3e/source/extF80M_rem.c deleted file mode 100644 index 4aff18ae9791..000000000000 --- a/deps/SoftFloat-3e/source/extF80M_rem.c +++ /dev/null @@ -1,204 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -#ifdef SOFTFLOAT_FAST_INT64 - -void - extF80M_rem( - const extFloat80_t *aPtr, const extFloat80_t *bPtr, extFloat80_t *zPtr ) -{ - - *zPtr = extF80_rem( *aPtr, *bPtr ); - -} - -#else - -void - extF80M_rem( - const extFloat80_t *aPtr, const extFloat80_t *bPtr, extFloat80_t *zPtr ) -{ - const struct extFloat80M *aSPtr, *bSPtr; - struct extFloat80M *zSPtr; - uint_fast16_t uiA64; - int32_t expA, expB; - uint64_t x64; - bool signRem; - uint64_t sigA; - int32_t expDiff; - uint32_t rem[3], x[3], sig32B, q, recip32, rem2[3], *remPtr, *altRemPtr; - uint32_t *newRemPtr, wordMeanRem; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - aSPtr = (const struct extFloat80M *) aPtr; - bSPtr = (const struct extFloat80M *) bPtr; - zSPtr = (struct extFloat80M *) zPtr; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uiA64 = aSPtr->signExp; - expA = expExtF80UI64( uiA64 ); - expB = expExtF80UI64( bSPtr->signExp ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( (expA == 0x7FFF) || (expB == 0x7FFF) ) { - if ( softfloat_tryPropagateNaNExtF80M( aSPtr, bSPtr, zSPtr ) ) return; - if ( expA == 0x7FFF ) goto invalid; - /*-------------------------------------------------------------------- - | If we get here, then argument b is an infinity and `expB' is 0x7FFF; - | Doubling `expB' is an easy way to ensure that `expDiff' later is - | less than -1, which will result in returning a canonicalized version - | of argument a. - *--------------------------------------------------------------------*/ - expB += expB; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( ! expB ) expB = 1; - x64 = bSPtr->signif; - if ( ! (x64 & UINT64_C( 0x8000000000000000 )) ) { - if ( ! x64 ) goto invalid; - expB += softfloat_normExtF80SigM( &x64 ); - } - signRem = signExtF80UI64( uiA64 ); - if ( ! expA ) expA = 1; - sigA = aSPtr->signif; - if ( ! (sigA & UINT64_C( 0x8000000000000000 )) ) { - if ( ! sigA ) { - expA = 0; - goto copyA; - } - expA += softfloat_normExtF80SigM( &sigA ); - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - expDiff = expA - expB; - if ( expDiff < -1 ) goto copyA; - rem[indexWord( 3, 2 )] = sigA>>34; - rem[indexWord( 3, 1 )] = sigA>>2; - rem[indexWord( 3, 0 )] = (uint32_t) sigA<<30; - x[indexWord( 3, 0 )] = (uint32_t) x64<<30; - sig32B = x64>>32; - x64 >>= 2; - x[indexWord( 3, 2 )] = x64>>32; - x[indexWord( 3, 1 )] = x64; - if ( expDiff < 1 ) { - if ( expDiff ) { - --expB; - softfloat_add96M( x, x, x ); - q = 0; - } else { - q = (softfloat_compare96M( x, rem ) <= 0); - if ( q ) softfloat_sub96M( rem, x, rem ); - } - } else { - recip32 = softfloat_approxRecip32_1( sig32B ); - expDiff -= 30; - for (;;) { - x64 = (uint64_t) rem[indexWordHi( 3 )] * recip32; - if ( expDiff < 0 ) break; - q = (x64 + 0x80000000)>>32; - softfloat_remStep96MBy32( rem, 29, x, q, rem ); - if ( rem[indexWordHi( 3 )] & 0x80000000 ) { - softfloat_add96M( rem, x, rem ); - } - expDiff -= 29; - } - /*-------------------------------------------------------------------- - | (`expDiff' cannot be less than -29 here.) - *--------------------------------------------------------------------*/ - q = (uint32_t) (x64>>32)>>(~expDiff & 31); - softfloat_remStep96MBy32( rem, expDiff + 30, x, q, rem ); - if ( rem[indexWordHi( 3 )] & 0x80000000 ) { - remPtr = rem; - altRemPtr = rem2; - softfloat_add96M( remPtr, x, altRemPtr ); - goto selectRem; - } - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - remPtr = rem; - altRemPtr = rem2; - do { - ++q; - newRemPtr = altRemPtr; - softfloat_sub96M( remPtr, x, newRemPtr ); - altRemPtr = remPtr; - remPtr = newRemPtr; - } while ( ! (remPtr[indexWordHi( 3 )] & 0x80000000) ); - selectRem: - softfloat_add96M( remPtr, altRemPtr, x ); - wordMeanRem = x[indexWordHi( 3 )]; - if ( - (wordMeanRem & 0x80000000) - || (! wordMeanRem && (q & 1) && ! x[indexWord( 3, 0 )] - && ! x[indexWord( 3, 1 )]) - ) { - remPtr = altRemPtr; - } - if ( remPtr[indexWordHi( 3 )] & 0x80000000 ) { - signRem = ! signRem; - softfloat_negX96M( remPtr ); - } - softfloat_normRoundPackMToExtF80M( signRem, expB + 2, remPtr, 80, zSPtr ); - return; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - invalid: - softfloat_invalidExtF80M( zSPtr ); - return; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - copyA: - if ( expA < 1 ) { - sigA >>= 1 - expA; - expA = 0; - } - zSPtr->signExp = packToExtF80UI64( signRem, expA ); - zSPtr->signif = sigA; - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/extF80M_roundToInt.c b/deps/SoftFloat-3e/source/extF80M_roundToInt.c deleted file mode 100644 index 2e8572957110..000000000000 --- a/deps/SoftFloat-3e/source/extF80M_roundToInt.c +++ /dev/null @@ -1,176 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2017 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -#ifdef SOFTFLOAT_FAST_INT64 - -void - extF80M_roundToInt( - const extFloat80_t *aPtr, - uint_fast8_t roundingMode, - bool exact, - extFloat80_t *zPtr - ) -{ - - *zPtr = extF80_roundToInt( *aPtr, roundingMode, exact ); - -} - -#else - -void - extF80M_roundToInt( - const extFloat80_t *aPtr, - uint_fast8_t roundingMode, - bool exact, - extFloat80_t *zPtr - ) -{ - const struct extFloat80M *aSPtr; - struct extFloat80M *zSPtr; - uint_fast16_t uiA64, signUI64; - int32_t exp; - uint64_t sigA; - uint_fast16_t uiZ64; - uint64_t sigZ, lastBitMask, roundBitsMask; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - aSPtr = (const struct extFloat80M *) aPtr; - zSPtr = (struct extFloat80M *) zPtr; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uiA64 = aSPtr->signExp; - signUI64 = uiA64 & packToExtF80UI64( 1, 0 ); - exp = expExtF80UI64( uiA64 ); - sigA = aSPtr->signif; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( !(sigA & UINT64_C( 0x8000000000000000 )) && (exp != 0x7FFF) ) { - if ( !sigA ) { - uiZ64 = signUI64; - sigZ = 0; - goto uiZ; - } - exp += softfloat_normExtF80SigM( &sigA ); - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( exp <= 0x3FFE ) { - if ( exact ) softfloat_exceptionFlags |= softfloat_flag_inexact; - switch ( roundingMode ) { - case softfloat_round_near_even: - if ( !(sigA & UINT64_C( 0x7FFFFFFFFFFFFFFF )) ) break; - case softfloat_round_near_maxMag: - if ( exp == 0x3FFE ) goto mag1; - break; - case softfloat_round_min: - if ( signUI64 ) goto mag1; - break; - case softfloat_round_max: - if ( !signUI64 ) goto mag1; - break; -#ifdef SOFTFLOAT_ROUND_ODD - case softfloat_round_odd: - goto mag1; -#endif - } - uiZ64 = signUI64; - sigZ = 0; - goto uiZ; - mag1: - uiZ64 = signUI64 | 0x3FFF; - sigZ = UINT64_C( 0x8000000000000000 ); - goto uiZ; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( 0x403E <= exp ) { - if ( exp == 0x7FFF ) { - if ( sigA & UINT64_C( 0x7FFFFFFFFFFFFFFF ) ) { - softfloat_propagateNaNExtF80M( aSPtr, 0, zSPtr ); - return; - } - sigZ = UINT64_C( 0x8000000000000000 ); - } else { - sigZ = sigA; - } - uiZ64 = signUI64 | exp; - goto uiZ; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uiZ64 = signUI64 | exp; - lastBitMask = (uint64_t) 1<<(0x403E - exp); - roundBitsMask = lastBitMask - 1; - sigZ = sigA; - if ( roundingMode == softfloat_round_near_maxMag ) { - sigZ += lastBitMask>>1; - } else if ( roundingMode == softfloat_round_near_even ) { - sigZ += lastBitMask>>1; - if ( !(sigZ & roundBitsMask) ) sigZ &= ~lastBitMask; - } else if ( - roundingMode == (signUI64 ? softfloat_round_min : softfloat_round_max) - ) { - sigZ += roundBitsMask; - } - sigZ &= ~roundBitsMask; - if ( !sigZ ) { - ++uiZ64; - sigZ = UINT64_C( 0x8000000000000000 ); - } - if ( sigZ != sigA ) { -#ifdef SOFTFLOAT_ROUND_ODD - if ( roundingMode == softfloat_round_odd ) sigZ |= lastBitMask; -#endif - if ( exact ) softfloat_exceptionFlags |= softfloat_flag_inexact; - } - uiZ: - zSPtr->signExp = uiZ64; - zSPtr->signif = sigZ; - return; - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/extF80M_sqrt.c b/deps/SoftFloat-3e/source/extF80M_sqrt.c deleted file mode 100644 index 7ee91e0e5765..000000000000 --- a/deps/SoftFloat-3e/source/extF80M_sqrt.c +++ /dev/null @@ -1,180 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2017 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -#ifdef SOFTFLOAT_FAST_INT64 - -void extF80M_sqrt( const extFloat80_t *aPtr, extFloat80_t *zPtr ) -{ - - *zPtr = extF80_sqrt( *aPtr ); - -} - -#else - -void extF80M_sqrt( const extFloat80_t *aPtr, extFloat80_t *zPtr ) -{ - const struct extFloat80M *aSPtr; - struct extFloat80M *zSPtr; - uint_fast16_t uiA64, signUI64; - int32_t expA; - uint64_t rem64; - int32_t expZ; - uint32_t rem96[3], sig32A, recipSqrt32, sig32Z, q; - uint64_t sig64Z, x64; - uint32_t rem32, term[4], rem[4], extSigZ[3]; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - aSPtr = (const struct extFloat80M *) aPtr; - zSPtr = (struct extFloat80M *) zPtr; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uiA64 = aSPtr->signExp; - signUI64 = uiA64 & packToExtF80UI64( 1, 0 ); - expA = expExtF80UI64( uiA64 ); - rem64 = aSPtr->signif; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( expA == 0x7FFF ) { - if ( rem64 & UINT64_C( 0x7FFFFFFFFFFFFFFF ) ) { - softfloat_propagateNaNExtF80M( aSPtr, 0, zSPtr ); - return; - } - if ( signUI64 ) goto invalid; - rem64 = UINT64_C( 0x8000000000000000 ); - goto copyA; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( ! expA ) expA = 1; - if ( ! (rem64 & UINT64_C( 0x8000000000000000 )) ) { - if ( ! rem64 ) { - uiA64 = signUI64; - goto copyA; - } - expA += softfloat_normExtF80SigM( &rem64 ); - } - if ( signUI64 ) goto invalid; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - expZ = ((expA - 0x3FFF)>>1) + 0x3FFF; - expA &= 1; - softfloat_shortShiftLeft64To96M( rem64, 30 - expA, rem96 ); - sig32A = rem64>>32; - recipSqrt32 = softfloat_approxRecipSqrt32_1( expA, sig32A ); - sig32Z = ((uint64_t) sig32A * recipSqrt32)>>32; - if ( expA ) sig32Z >>= 1; - rem64 = - ((uint64_t) rem96[indexWord( 3, 2 )]<<32 | rem96[indexWord( 3, 1 )]) - - (uint64_t) sig32Z * sig32Z; - rem96[indexWord( 3, 2 )] = rem64>>32; - rem96[indexWord( 3, 1 )] = rem64; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - q = ((uint32_t) (rem64>>2) * (uint64_t) recipSqrt32)>>32; - sig64Z = ((uint64_t) sig32Z<<32) + ((uint64_t) q<<3); - term[indexWord( 3, 2 )] = 0; - /*------------------------------------------------------------------------ - | (Repeating this loop is a rare occurrence.) - *------------------------------------------------------------------------*/ - for (;;) { - x64 = ((uint64_t) sig32Z<<32) + sig64Z; - term[indexWord( 3, 1 )] = x64>>32; - term[indexWord( 3, 0 )] = x64; - softfloat_remStep96MBy32( - rem96, 29, term, q, &rem[indexMultiwordHi( 4, 3 )] ); - rem32 = rem[indexWord( 4, 3 )]; - if ( ! (rem32 & 0x80000000) ) break; - --q; - sig64Z -= 1<<3; - } - rem64 = (uint64_t) rem32<<32 | rem[indexWord( 4, 2 )]; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - q = (((uint32_t) (rem64>>2) * (uint64_t) recipSqrt32)>>32) + 2; - if ( rem64>>34 ) q += recipSqrt32; - x64 = (uint64_t) q<<7; - extSigZ[indexWord( 3, 0 )] = x64; - x64 = (sig64Z<<1) + (x64>>32); - extSigZ[indexWord( 3, 2 )] = x64>>32; - extSigZ[indexWord( 3, 1 )] = x64; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( (q & 0xFFFFFF) <= 2 ) { - q &= ~(uint32_t) 0xFFFF; - extSigZ[indexWordLo( 3 )] = q<<7; - x64 = sig64Z + (q>>27); - term[indexWord( 4, 3 )] = 0; - term[indexWord( 4, 2 )] = x64>>32; - term[indexWord( 4, 1 )] = x64; - term[indexWord( 4, 0 )] = q<<5; - rem[indexWord( 4, 0 )] = 0; - softfloat_remStep128MBy32( rem, 28, term, q, rem ); - q = rem[indexWordHi( 4 )]; - if ( q & 0x80000000 ) { - softfloat_sub1X96M( extSigZ ); - } else { - if ( q || rem[indexWord( 4, 1 )] || rem[indexWord( 4, 2 )] ) { - extSigZ[indexWordLo( 3 )] |= 1; - } - } - } - softfloat_roundPackMToExtF80M( - 0, expZ, extSigZ, extF80_roundingPrecision, zSPtr ); - return; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - invalid: - softfloat_invalidExtF80M( zSPtr ); - return; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - copyA: - zSPtr->signExp = uiA64; - zSPtr->signif = rem64; - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/extF80M_sub.c b/deps/SoftFloat-3e/source/extF80M_sub.c deleted file mode 100644 index 5d1895c7a028..000000000000 --- a/deps/SoftFloat-3e/source/extF80M_sub.c +++ /dev/null @@ -1,100 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "internals.h" -#include "softfloat.h" - -#ifdef SOFTFLOAT_FAST_INT64 - -void - extF80M_sub( - const extFloat80_t *aPtr, const extFloat80_t *bPtr, extFloat80_t *zPtr ) -{ - const struct extFloat80M *aSPtr, *bSPtr; - uint_fast16_t uiA64; - uint_fast64_t uiA0; - bool signA; - uint_fast16_t uiB64; - uint_fast64_t uiB0; - bool signB; -#if ! defined INLINE_LEVEL || (INLINE_LEVEL < 2) - extFloat80_t - (*magsFuncPtr)( - uint_fast16_t, uint_fast64_t, uint_fast16_t, uint_fast64_t, bool ); -#endif - - aSPtr = (const struct extFloat80M *) aPtr; - bSPtr = (const struct extFloat80M *) bPtr; - uiA64 = aSPtr->signExp; - uiA0 = aSPtr->signif; - signA = signExtF80UI64( uiA64 ); - uiB64 = bSPtr->signExp; - uiB0 = bSPtr->signif; - signB = signExtF80UI64( uiB64 ); -#if defined INLINE_LEVEL && (2 <= INLINE_LEVEL) - if ( signA == signB ) { - *zPtr = softfloat_subMagsExtF80( uiA64, uiA0, uiB64, uiB0, signA ); - } else { - *zPtr = softfloat_addMagsExtF80( uiA64, uiA0, uiB64, uiB0, signA ); - } -#else - magsFuncPtr = - (signA == signB) ? softfloat_subMagsExtF80 : softfloat_addMagsExtF80; - *zPtr = (*magsFuncPtr)( uiA64, uiA0, uiB64, uiB0, signA ); -#endif - -} - -#else - -void - extF80M_sub( - const extFloat80_t *aPtr, const extFloat80_t *bPtr, extFloat80_t *zPtr ) -{ - - softfloat_addExtF80M( - (const struct extFloat80M *) aPtr, - (const struct extFloat80M *) bPtr, - (struct extFloat80M *) zPtr, - true - ); - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/extF80M_to_f128M.c b/deps/SoftFloat-3e/source/extF80M_to_f128M.c deleted file mode 100644 index da81e8d6b326..000000000000 --- a/deps/SoftFloat-3e/source/extF80M_to_f128M.c +++ /dev/null @@ -1,125 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -#ifdef SOFTFLOAT_FAST_INT64 - -void extF80M_to_f128M( const extFloat80_t *aPtr, float128_t *zPtr ) -{ - - *zPtr = extF80_to_f128( *aPtr ); - -} - -#else - -void extF80M_to_f128M( const extFloat80_t *aPtr, float128_t *zPtr ) -{ - const struct extFloat80M *aSPtr; - uint32_t *zWPtr; - uint_fast16_t uiA64; - bool sign; - int32_t exp; - uint64_t sig; - struct commonNaN commonNaN; - uint32_t uiZ96; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - aSPtr = (const struct extFloat80M *) aPtr; - zWPtr = (uint32_t *) zPtr; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uiA64 = aSPtr->signExp; - sign = signExtF80UI64( uiA64 ); - exp = expExtF80UI64( uiA64 ); - sig = aSPtr->signif; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - zWPtr[indexWord( 4, 0 )] = 0; - if ( exp == 0x7FFF ) { - if ( sig & UINT64_C( 0x7FFFFFFFFFFFFFFF ) ) { - softfloat_extF80MToCommonNaN( aSPtr, &commonNaN ); - softfloat_commonNaNToF128M( &commonNaN, zWPtr ); - return; - } - uiZ96 = packToF128UI96( sign, 0x7FFF, 0 ); - goto uiZ; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( exp ) --exp; - if ( ! (sig & UINT64_C( 0x8000000000000000 )) ) { - if ( ! sig ) { - uiZ96 = packToF128UI96( sign, 0, 0 ); - goto uiZ; - } - exp += softfloat_normExtF80SigM( &sig ); - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - zWPtr[indexWord( 4, 1 )] = (uint32_t) sig<<17; - sig >>= 15; - zWPtr[indexWord( 4, 2 )] = sig; - if ( exp < 0 ) { - zWPtr[indexWordHi( 4 )] = sig>>32; - softfloat_shiftRight96M( - &zWPtr[indexMultiwordHi( 4, 3 )], - -exp, - &zWPtr[indexMultiwordHi( 4, 3 )] - ); - exp = 0; - sig = (uint64_t) zWPtr[indexWordHi( 4 )]<<32; - } - zWPtr[indexWordHi( 4 )] = packToF128UI96( sign, exp, sig>>32 ); - return; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uiZ: - zWPtr[indexWord( 4, 3 )] = uiZ96; - zWPtr[indexWord( 4, 2 )] = 0; - zWPtr[indexWord( 4, 1 )] = 0; - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/extF80M_to_f16.c b/deps/SoftFloat-3e/source/extF80M_to_f16.c deleted file mode 100644 index 5ae38d0c4b8a..000000000000 --- a/deps/SoftFloat-3e/source/extF80M_to_f16.c +++ /dev/null @@ -1,112 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -#ifdef SOFTFLOAT_FAST_INT64 - -float16_t extF80M_to_f16( const extFloat80_t *aPtr ) -{ - - return extF80_to_f16( *aPtr ); - -} - -#else - -float16_t extF80M_to_f16( const extFloat80_t *aPtr ) -{ - const struct extFloat80M *aSPtr; - uint_fast16_t uiA64; - bool sign; - int32_t exp; - uint64_t sig; - struct commonNaN commonNaN; - uint16_t uiZ, sig16; - union ui16_f16 uZ; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - aSPtr = (const struct extFloat80M *) aPtr; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uiA64 = aSPtr->signExp; - sign = signExtF80UI64( uiA64 ); - exp = expExtF80UI64( uiA64 ); - sig = aSPtr->signif; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( exp == 0x7FFF ) { - if ( sig & UINT64_C( 0x7FFFFFFFFFFFFFFF ) ) { - softfloat_extF80MToCommonNaN( aSPtr, &commonNaN ); - uiZ = softfloat_commonNaNToF16UI( &commonNaN ); - } else { - uiZ = packToF16UI( sign, 0x1F, 0 ); - } - goto uiZ; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( ! (sig & UINT64_C( 0x8000000000000000 )) ) { - if ( ! sig ) { - uiZ = packToF16UI( sign, 0, 0 ); - goto uiZ; - } - exp += softfloat_normExtF80SigM( &sig ); - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - sig16 = softfloat_shortShiftRightJam64( sig, 49 ); - exp -= 0x3FF1; - if ( sizeof (int_fast16_t) < sizeof (int32_t) ) { - if ( exp < -0x40 ) exp = -0x40; - } - return softfloat_roundPackToF16( sign, exp, sig16 ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uiZ: - uZ.ui = uiZ; - return uZ.f; - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/extF80M_to_f32.c b/deps/SoftFloat-3e/source/extF80M_to_f32.c deleted file mode 100644 index 47cf224dc1f8..000000000000 --- a/deps/SoftFloat-3e/source/extF80M_to_f32.c +++ /dev/null @@ -1,112 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -#ifdef SOFTFLOAT_FAST_INT64 - -float32_t extF80M_to_f32( const extFloat80_t *aPtr ) -{ - - return extF80_to_f32( *aPtr ); - -} - -#else - -float32_t extF80M_to_f32( const extFloat80_t *aPtr ) -{ - const struct extFloat80M *aSPtr; - uint_fast16_t uiA64; - bool sign; - int32_t exp; - uint64_t sig; - struct commonNaN commonNaN; - uint32_t uiZ, sig32; - union ui32_f32 uZ; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - aSPtr = (const struct extFloat80M *) aPtr; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uiA64 = aSPtr->signExp; - sign = signExtF80UI64( uiA64 ); - exp = expExtF80UI64( uiA64 ); - sig = aSPtr->signif; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( exp == 0x7FFF ) { - if ( sig & UINT64_C( 0x7FFFFFFFFFFFFFFF ) ) { - softfloat_extF80MToCommonNaN( aSPtr, &commonNaN ); - uiZ = softfloat_commonNaNToF32UI( &commonNaN ); - } else { - uiZ = packToF32UI( sign, 0xFF, 0 ); - } - goto uiZ; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( ! (sig & UINT64_C( 0x8000000000000000 )) ) { - if ( ! sig ) { - uiZ = packToF32UI( sign, 0, 0 ); - goto uiZ; - } - exp += softfloat_normExtF80SigM( &sig ); - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - sig32 = softfloat_shortShiftRightJam64( sig, 33 ); - exp -= 0x3F81; - if ( sizeof (int_fast16_t) < sizeof (int32_t) ) { - if ( exp < -0x1000 ) exp = -0x1000; - } - return softfloat_roundPackToF32( sign, exp, sig32 ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uiZ: - uZ.ui = uiZ; - return uZ.f; - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/extF80M_to_f64.c b/deps/SoftFloat-3e/source/extF80M_to_f64.c deleted file mode 100644 index 5f8f4aa2998b..000000000000 --- a/deps/SoftFloat-3e/source/extF80M_to_f64.c +++ /dev/null @@ -1,112 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -#ifdef SOFTFLOAT_FAST_INT64 - -float64_t extF80M_to_f64( const extFloat80_t *aPtr ) -{ - - return extF80_to_f64( *aPtr ); - -} - -#else - -float64_t extF80M_to_f64( const extFloat80_t *aPtr ) -{ - const struct extFloat80M *aSPtr; - uint_fast16_t uiA64; - bool sign; - int32_t exp; - uint64_t sig; - struct commonNaN commonNaN; - uint64_t uiZ; - union ui64_f64 uZ; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - aSPtr = (const struct extFloat80M *) aPtr; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uiA64 = aSPtr->signExp; - sign = signExtF80UI64( uiA64 ); - exp = expExtF80UI64( uiA64 ); - sig = aSPtr->signif; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( exp == 0x7FFF ) { - if ( sig & UINT64_C( 0x7FFFFFFFFFFFFFFF ) ) { - softfloat_extF80MToCommonNaN( aSPtr, &commonNaN ); - uiZ = softfloat_commonNaNToF64UI( &commonNaN ); - } else { - uiZ = packToF64UI( sign, 0x7FF, 0 ); - } - goto uiZ; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( ! (sig & UINT64_C( 0x8000000000000000 )) ) { - if ( ! sig ) { - uiZ = packToF64UI( sign, 0, 0 ); - goto uiZ; - } - exp += softfloat_normExtF80SigM( &sig ); - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - sig = softfloat_shortShiftRightJam64( sig, 1 ); - exp -= 0x3C01; - if ( sizeof (int_fast16_t) < sizeof (int32_t) ) { - if ( exp < -0x1000 ) exp = -0x1000; - } - return softfloat_roundPackToF64( sign, exp, sig ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uiZ: - uZ.ui = uiZ; - return uZ.f; - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/extF80M_to_i32.c b/deps/SoftFloat-3e/source/extF80M_to_i32.c deleted file mode 100644 index 06394e34181f..000000000000 --- a/deps/SoftFloat-3e/source/extF80M_to_i32.c +++ /dev/null @@ -1,100 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017 The Regents of the -University of California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -#ifdef SOFTFLOAT_FAST_INT64 - -int_fast32_t - extF80M_to_i32( - const extFloat80_t *aPtr, uint_fast8_t roundingMode, bool exact ) -{ - - return extF80_to_i32( *aPtr, roundingMode, exact ); - -} - -#else - -int_fast32_t - extF80M_to_i32( - const extFloat80_t *aPtr, uint_fast8_t roundingMode, bool exact ) -{ - const struct extFloat80M *aSPtr; - uint_fast16_t uiA64; - bool sign; - int32_t exp; - uint64_t sig; - int32_t shiftDist; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - aSPtr = (const struct extFloat80M *) aPtr; - uiA64 = aSPtr->signExp; - sign = signExtF80UI64( uiA64 ); - exp = expExtF80UI64( uiA64 ); - sig = aSPtr->signif; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - shiftDist = 0x4032 - exp; - if ( shiftDist <= 0 ) { - if ( sig>>32 ) goto invalid; - if ( -32 < shiftDist ) { - sig <<= -shiftDist; - } else { - if ( (uint32_t) sig ) goto invalid; - } - } else { - sig = softfloat_shiftRightJam64( sig, shiftDist ); - } - return softfloat_roundToI32( sign, sig, roundingMode, exact ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - invalid: - softfloat_raiseFlags( softfloat_flag_invalid ); - return - (exp == 0x7FFF) && (sig & UINT64_C( 0x7FFFFFFFFFFFFFFF )) ? i32_fromNaN - : sign ? i32_fromNegOverflow : i32_fromPosOverflow; - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/extF80M_to_i32_r_minMag.c b/deps/SoftFloat-3e/source/extF80M_to_i32_r_minMag.c deleted file mode 100644 index 5f5cf599df94..000000000000 --- a/deps/SoftFloat-3e/source/extF80M_to_i32_r_minMag.c +++ /dev/null @@ -1,120 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -#ifdef SOFTFLOAT_FAST_INT64 - -int_fast32_t extF80M_to_i32_r_minMag( const extFloat80_t *aPtr, bool exact ) -{ - - return extF80_to_i32_r_minMag( *aPtr, exact ); - -} - -#else - -int_fast32_t extF80M_to_i32_r_minMag( const extFloat80_t *aPtr, bool exact ) -{ - const struct extFloat80M *aSPtr; - uint_fast16_t uiA64; - int32_t exp; - uint64_t sig; - int32_t shiftDist; - bool sign, raiseInexact; - int32_t z; - uint64_t shiftedSig; - uint32_t absZ; - union { uint32_t ui; int32_t i; } u; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - aSPtr = (const struct extFloat80M *) aPtr; - uiA64 = aSPtr->signExp; - exp = expExtF80UI64( uiA64 ); - sig = aSPtr->signif; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( ! sig && (exp != 0x7FFF) ) return 0; - shiftDist = 0x403E - exp; - if ( 64 <= shiftDist ) { - raiseInexact = exact; - z = 0; - } else { - sign = signExtF80UI64( uiA64 ); - raiseInexact = false; - if ( shiftDist < 0 ) { - if ( sig>>32 || (shiftDist <= -31) ) goto invalid; - shiftedSig = (uint64_t) (uint32_t) sig<<-shiftDist; - if ( shiftedSig>>32 ) goto invalid; - absZ = shiftedSig; - } else { - shiftedSig = sig; - if ( shiftDist ) shiftedSig >>= shiftDist; - if ( shiftedSig>>32 ) goto invalid; - absZ = shiftedSig; - if ( exact && shiftDist ) { - raiseInexact = ((uint64_t) absZ< -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -#ifdef SOFTFLOAT_FAST_INT64 - -int_fast64_t - extF80M_to_i64( - const extFloat80_t *aPtr, uint_fast8_t roundingMode, bool exact ) -{ - - return extF80_to_i64( *aPtr, roundingMode, exact ); - -} - -#else - -int_fast64_t - extF80M_to_i64( - const extFloat80_t *aPtr, uint_fast8_t roundingMode, bool exact ) -{ - const struct extFloat80M *aSPtr; - uint_fast16_t uiA64; - bool sign; - int32_t exp; - uint64_t sig; - int32_t shiftDist; - uint32_t extSig[3]; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - aSPtr = (const struct extFloat80M *) aPtr; - uiA64 = aSPtr->signExp; - sign = signExtF80UI64( uiA64 ); - exp = expExtF80UI64( uiA64 ); - sig = aSPtr->signif; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - shiftDist = 0x403E - exp; - if ( shiftDist < 0 ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - return - (exp == 0x7FFF) && (sig & UINT64_C( 0x7FFFFFFFFFFFFFFF )) - ? i64_fromNaN - : sign ? i64_fromNegOverflow : i64_fromPosOverflow; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - extSig[indexWord( 3, 2 )] = sig>>32; - extSig[indexWord( 3, 1 )] = sig; - extSig[indexWord( 3, 0 )] = 0; - if ( shiftDist ) softfloat_shiftRightJam96M( extSig, shiftDist, extSig ); - return softfloat_roundMToI64( sign, extSig, roundingMode, exact ); - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/extF80M_to_i64_r_minMag.c b/deps/SoftFloat-3e/source/extF80M_to_i64_r_minMag.c deleted file mode 100644 index ec9b92844c97..000000000000 --- a/deps/SoftFloat-3e/source/extF80M_to_i64_r_minMag.c +++ /dev/null @@ -1,115 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -#ifdef SOFTFLOAT_FAST_INT64 - -int_fast64_t extF80M_to_i64_r_minMag( const extFloat80_t *aPtr, bool exact ) -{ - - return extF80_to_i64_r_minMag( *aPtr, exact ); - -} - -#else - -int_fast64_t extF80M_to_i64_r_minMag( const extFloat80_t *aPtr, bool exact ) -{ - const struct extFloat80M *aSPtr; - uint_fast16_t uiA64; - int32_t exp; - uint64_t sig; - int32_t shiftDist; - bool sign, raiseInexact; - int64_t z; - uint64_t absZ; - union { uint64_t ui; int64_t i; } u; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - aSPtr = (const struct extFloat80M *) aPtr; - uiA64 = aSPtr->signExp; - exp = expExtF80UI64( uiA64 ); - sig = aSPtr->signif; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( ! sig && (exp != 0x7FFF) ) return 0; - shiftDist = 0x403E - exp; - if ( 64 <= shiftDist ) { - raiseInexact = exact; - z = 0; - } else { - sign = signExtF80UI64( uiA64 ); - raiseInexact = false; - if ( shiftDist < 0 ) { - if ( shiftDist <= -63 ) goto invalid; - shiftDist = -shiftDist; - absZ = sig<>shiftDist != sig ) goto invalid; - } else { - absZ = sig; - if ( shiftDist ) absZ >>= shiftDist; - if ( exact && shiftDist ) raiseInexact = (absZ< -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -#ifdef SOFTFLOAT_FAST_INT64 - -uint_fast32_t - extF80M_to_ui32( - const extFloat80_t *aPtr, uint_fast8_t roundingMode, bool exact ) -{ - - return extF80_to_ui32( *aPtr, roundingMode, exact ); - -} - -#else - -uint_fast32_t - extF80M_to_ui32( - const extFloat80_t *aPtr, uint_fast8_t roundingMode, bool exact ) -{ - const struct extFloat80M *aSPtr; - uint_fast16_t uiA64; - bool sign; - int32_t exp; - uint64_t sig; - int32_t shiftDist; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - aSPtr = (const struct extFloat80M *) aPtr; - uiA64 = aSPtr->signExp; - sign = signExtF80UI64( uiA64 ); - exp = expExtF80UI64( uiA64 ); - sig = aSPtr->signif; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - shiftDist = 0x4032 - exp; - if ( shiftDist <= 0 ) { - if ( sig>>32 ) goto invalid; - if ( -32 < shiftDist ) { - sig <<= -shiftDist; - } else { - if ( (uint32_t) sig ) goto invalid; - } - } else { - sig = softfloat_shiftRightJam64( sig, shiftDist ); - } - return softfloat_roundToUI32( sign, sig, roundingMode, exact ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - invalid: - softfloat_raiseFlags( softfloat_flag_invalid ); - return - (exp == 0x7FFF) && (sig & UINT64_C( 0x7FFFFFFFFFFFFFFF )) - ? ui32_fromNaN - : sign ? ui32_fromNegOverflow : ui32_fromPosOverflow; - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/extF80M_to_ui32_r_minMag.c b/deps/SoftFloat-3e/source/extF80M_to_ui32_r_minMag.c deleted file mode 100644 index e28b08d70d2a..000000000000 --- a/deps/SoftFloat-3e/source/extF80M_to_ui32_r_minMag.c +++ /dev/null @@ -1,111 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -#ifdef SOFTFLOAT_FAST_INT64 - -uint_fast32_t extF80M_to_ui32_r_minMag( const extFloat80_t *aPtr, bool exact ) -{ - - return extF80_to_ui32_r_minMag( *aPtr, exact ); - -} - -#else - -uint_fast32_t extF80M_to_ui32_r_minMag( const extFloat80_t *aPtr, bool exact ) -{ - const struct extFloat80M *aSPtr; - uint_fast16_t uiA64; - int32_t exp; - uint64_t sig; - int32_t shiftDist; - bool sign; - uint64_t shiftedSig; - uint32_t z; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - aSPtr = (const struct extFloat80M *) aPtr; - uiA64 = aSPtr->signExp; - exp = expExtF80UI64( uiA64 ); - sig = aSPtr->signif; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( ! sig && (exp != 0x7FFF) ) return 0; - shiftDist = 0x403E - exp; - if ( 64 <= shiftDist ) { - if ( exact ) softfloat_exceptionFlags |= softfloat_flag_inexact; - return 0; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - sign = signExtF80UI64( uiA64 ); - if ( shiftDist < 0 ) { - if ( sign || sig>>32 || (shiftDist <= -31) ) goto invalid; - shiftedSig = (uint64_t) (uint32_t) sig<<-shiftDist; - if ( shiftedSig>>32 ) goto invalid; - z = shiftedSig; - } else { - shiftedSig = sig; - if ( shiftDist ) shiftedSig >>= shiftDist; - if ( shiftedSig>>32 ) goto invalid; - z = shiftedSig; - if ( sign && z ) goto invalid; - if ( exact && shiftDist && ((uint64_t) z< -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -#ifdef SOFTFLOAT_FAST_INT64 - -uint_fast64_t - extF80M_to_ui64( - const extFloat80_t *aPtr, uint_fast8_t roundingMode, bool exact ) -{ - - return extF80_to_ui64( *aPtr, roundingMode, exact ); - -} - -#else - -uint_fast64_t - extF80M_to_ui64( - const extFloat80_t *aPtr, uint_fast8_t roundingMode, bool exact ) -{ - const struct extFloat80M *aSPtr; - uint_fast16_t uiA64; - bool sign; - int32_t exp; - uint64_t sig; - int32_t shiftDist; - uint32_t extSig[3]; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - aSPtr = (const struct extFloat80M *) aPtr; - uiA64 = aSPtr->signExp; - sign = signExtF80UI64( uiA64 ); - exp = expExtF80UI64( uiA64 ); - sig = aSPtr->signif; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - shiftDist = 0x403E - exp; - if ( shiftDist < 0 ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - return - (exp == 0x7FFF) && (sig & UINT64_C( 0x7FFFFFFFFFFFFFFF )) - ? ui64_fromNaN - : sign ? ui64_fromNegOverflow : ui64_fromPosOverflow; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - extSig[indexWord( 3, 2 )] = sig>>32; - extSig[indexWord( 3, 1 )] = sig; - extSig[indexWord( 3, 0 )] = 0; - if ( shiftDist ) softfloat_shiftRightJam96M( extSig, shiftDist, extSig ); - return softfloat_roundMToUI64( sign, extSig, roundingMode, exact ); - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/extF80M_to_ui64_r_minMag.c b/deps/SoftFloat-3e/source/extF80M_to_ui64_r_minMag.c deleted file mode 100644 index 87d80897b782..000000000000 --- a/deps/SoftFloat-3e/source/extF80M_to_ui64_r_minMag.c +++ /dev/null @@ -1,108 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -#ifdef SOFTFLOAT_FAST_INT64 - -uint_fast64_t extF80M_to_ui64_r_minMag( const extFloat80_t *aPtr, bool exact ) -{ - - return extF80_to_ui64_r_minMag( *aPtr, exact ); - -} - -#else - -uint_fast64_t extF80M_to_ui64_r_minMag( const extFloat80_t *aPtr, bool exact ) -{ - const struct extFloat80M *aSPtr; - uint_fast16_t uiA64; - int32_t exp; - uint64_t sig; - int32_t shiftDist; - bool sign; - uint64_t z; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - aSPtr = (const struct extFloat80M *) aPtr; - uiA64 = aSPtr->signExp; - exp = expExtF80UI64( uiA64 ); - sig = aSPtr->signif; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( ! sig && (exp != 0x7FFF) ) return 0; - shiftDist = 0x403E - exp; - if ( 64 <= shiftDist ) { - if ( exact ) softfloat_exceptionFlags |= softfloat_flag_inexact; - return 0; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - sign = signExtF80UI64( uiA64 ); - if ( shiftDist < 0 ) { - if ( sign || (shiftDist <= -63) ) goto invalid; - shiftDist = -shiftDist; - z = sig<>shiftDist != sig ) goto invalid; - } else { - z = sig; - if ( shiftDist ) z >>= shiftDist; - if ( sign && z ) goto invalid; - if ( exact && shiftDist && (z< -#include -#include "platform.h" -#include "internals.h" -#include "softfloat.h" - -extFloat80_t extF80_add( extFloat80_t a, extFloat80_t b ) -{ - union { struct extFloat80M s; extFloat80_t f; } uA; - uint_fast16_t uiA64; - uint_fast64_t uiA0; - bool signA; - union { struct extFloat80M s; extFloat80_t f; } uB; - uint_fast16_t uiB64; - uint_fast64_t uiB0; - bool signB; -#if ! defined INLINE_LEVEL || (INLINE_LEVEL < 2) - extFloat80_t - (*magsFuncPtr)( - uint_fast16_t, uint_fast64_t, uint_fast16_t, uint_fast64_t, bool ); -#endif - - uA.f = a; - uiA64 = uA.s.signExp; - uiA0 = uA.s.signif; - signA = signExtF80UI64( uiA64 ); - uB.f = b; - uiB64 = uB.s.signExp; - uiB0 = uB.s.signif; - signB = signExtF80UI64( uiB64 ); -#if defined INLINE_LEVEL && (2 <= INLINE_LEVEL) - if ( signA == signB ) { - return softfloat_addMagsExtF80( uiA64, uiA0, uiB64, uiB0, signA ); - } else { - return softfloat_subMagsExtF80( uiA64, uiA0, uiB64, uiB0, signA ); - } -#else - magsFuncPtr = - (signA == signB) ? softfloat_addMagsExtF80 : softfloat_subMagsExtF80; - return (*magsFuncPtr)( uiA64, uiA0, uiB64, uiB0, signA ); -#endif - -} - diff --git a/deps/SoftFloat-3e/source/extF80_div.c b/deps/SoftFloat-3e/source/extF80_div.c deleted file mode 100644 index 28dfb13de8e2..000000000000 --- a/deps/SoftFloat-3e/source/extF80_div.c +++ /dev/null @@ -1,203 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -extFloat80_t extF80_div( extFloat80_t a, extFloat80_t b ) -{ - union { struct extFloat80M s; extFloat80_t f; } uA; - uint_fast16_t uiA64; - uint_fast64_t uiA0; - bool signA; - int_fast32_t expA; - uint_fast64_t sigA; - union { struct extFloat80M s; extFloat80_t f; } uB; - uint_fast16_t uiB64; - uint_fast64_t uiB0; - bool signB; - int_fast32_t expB; - uint_fast64_t sigB; - bool signZ; - struct exp32_sig64 normExpSig; - int_fast32_t expZ; - struct uint128 rem; - uint_fast32_t recip32; - uint_fast64_t sigZ; - int ix; - uint_fast64_t q64; - uint_fast32_t q; - struct uint128 term; - uint_fast64_t sigZExtra; - struct uint128 uiZ; - uint_fast16_t uiZ64; - uint_fast64_t uiZ0; - union { struct extFloat80M s; extFloat80_t f; } uZ; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uA.f = a; - uiA64 = uA.s.signExp; - uiA0 = uA.s.signif; - signA = signExtF80UI64( uiA64 ); - expA = expExtF80UI64( uiA64 ); - sigA = uiA0; - uB.f = b; - uiB64 = uB.s.signExp; - uiB0 = uB.s.signif; - signB = signExtF80UI64( uiB64 ); - expB = expExtF80UI64( uiB64 ); - sigB = uiB0; - signZ = signA ^ signB; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( expA == 0x7FFF ) { - if ( sigA & UINT64_C( 0x7FFFFFFFFFFFFFFF ) ) goto propagateNaN; - if ( expB == 0x7FFF ) { - if ( sigB & UINT64_C( 0x7FFFFFFFFFFFFFFF ) ) goto propagateNaN; - goto invalid; - } - goto infinity; - } - if ( expB == 0x7FFF ) { - if ( sigB & UINT64_C( 0x7FFFFFFFFFFFFFFF ) ) goto propagateNaN; - goto zero; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( ! expB ) expB = 1; - if ( ! (sigB & UINT64_C( 0x8000000000000000 )) ) { - if ( ! sigB ) { - if ( ! sigA ) goto invalid; - softfloat_raiseFlags( softfloat_flag_infinite ); - goto infinity; - } - normExpSig = softfloat_normSubnormalExtF80Sig( sigB ); - expB += normExpSig.exp; - sigB = normExpSig.sig; - } - if ( ! expA ) expA = 1; - if ( ! (sigA & UINT64_C( 0x8000000000000000 )) ) { - if ( ! sigA ) goto zero; - normExpSig = softfloat_normSubnormalExtF80Sig( sigA ); - expA += normExpSig.exp; - sigA = normExpSig.sig; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - expZ = expA - expB + 0x3FFF; - if ( sigA < sigB ) { - --expZ; - rem = softfloat_shortShiftLeft128( 0, sigA, 32 ); - } else { - rem = softfloat_shortShiftLeft128( 0, sigA, 31 ); - } - recip32 = softfloat_approxRecip32_1( sigB>>32 ); - sigZ = 0; - ix = 2; - for (;;) { - q64 = (uint_fast64_t) (uint32_t) (rem.v64>>2) * recip32; - q = (q64 + 0x80000000)>>32; - --ix; - if ( ix < 0 ) break; - rem = softfloat_shortShiftLeft128( rem.v64, rem.v0, 29 ); - term = softfloat_mul64ByShifted32To128( sigB, q ); - rem = softfloat_sub128( rem.v64, rem.v0, term.v64, term.v0 ); - if ( rem.v64 & UINT64_C( 0x8000000000000000 ) ) { - --q; - rem = softfloat_add128( rem.v64, rem.v0, sigB>>32, sigB<<32 ); - } - sigZ = (sigZ<<29) + q; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( ((q + 1) & 0x3FFFFF) < 2 ) { - rem = softfloat_shortShiftLeft128( rem.v64, rem.v0, 29 ); - term = softfloat_mul64ByShifted32To128( sigB, q ); - rem = softfloat_sub128( rem.v64, rem.v0, term.v64, term.v0 ); - term = softfloat_shortShiftLeft128( 0, sigB, 32 ); - if ( rem.v64 & UINT64_C( 0x8000000000000000 ) ) { - --q; - rem = softfloat_add128( rem.v64, rem.v0, term.v64, term.v0 ); - } else if ( softfloat_le128( term.v64, term.v0, rem.v64, rem.v0 ) ) { - ++q; - rem = softfloat_sub128( rem.v64, rem.v0, term.v64, term.v0 ); - } - if ( rem.v64 | rem.v0 ) q |= 1; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - sigZ = (sigZ<<6) + (q>>23); - sigZExtra = (uint64_t) ((uint_fast64_t) q<<41); - return - softfloat_roundPackToExtF80( - signZ, expZ, sigZ, sigZExtra, extF80_roundingPrecision ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - propagateNaN: - uiZ = softfloat_propagateNaNExtF80UI( uiA64, uiA0, uiB64, uiB0 ); - uiZ64 = uiZ.v64; - uiZ0 = uiZ.v0; - goto uiZ; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - invalid: - softfloat_raiseFlags( softfloat_flag_invalid ); - uiZ64 = defaultNaNExtF80UI64; - uiZ0 = defaultNaNExtF80UI0; - goto uiZ; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - infinity: - uiZ64 = packToExtF80UI64( signZ, 0x7FFF ); - uiZ0 = UINT64_C( 0x8000000000000000 ); - goto uiZ; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - zero: - uiZ64 = packToExtF80UI64( signZ, 0 ); - uiZ0 = 0; - uiZ: - uZ.s.signExp = uiZ64; - uZ.s.signif = uiZ0; - return uZ.f; - -} - diff --git a/deps/SoftFloat-3e/source/extF80_eq.c b/deps/SoftFloat-3e/source/extF80_eq.c deleted file mode 100644 index efcbc37143c5..000000000000 --- a/deps/SoftFloat-3e/source/extF80_eq.c +++ /dev/null @@ -1,73 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -bool extF80_eq( extFloat80_t a, extFloat80_t b ) -{ - union { struct extFloat80M s; extFloat80_t f; } uA; - uint_fast16_t uiA64; - uint_fast64_t uiA0; - union { struct extFloat80M s; extFloat80_t f; } uB; - uint_fast16_t uiB64; - uint_fast64_t uiB0; - - uA.f = a; - uiA64 = uA.s.signExp; - uiA0 = uA.s.signif; - uB.f = b; - uiB64 = uB.s.signExp; - uiB0 = uB.s.signif; - if ( isNaNExtF80UI( uiA64, uiA0 ) || isNaNExtF80UI( uiB64, uiB0 ) ) { - if ( - softfloat_isSigNaNExtF80UI( uiA64, uiA0 ) - || softfloat_isSigNaNExtF80UI( uiB64, uiB0 ) - ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - } - return false; - } - return - (uiA0 == uiB0) - && ((uiA64 == uiB64) || (! uiA0 && ! ((uiA64 | uiB64) & 0x7FFF))); - -} - diff --git a/deps/SoftFloat-3e/source/extF80_eq_signaling.c b/deps/SoftFloat-3e/source/extF80_eq_signaling.c deleted file mode 100644 index 193b191e6cf8..000000000000 --- a/deps/SoftFloat-3e/source/extF80_eq_signaling.c +++ /dev/null @@ -1,67 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "softfloat.h" - -bool extF80_eq_signaling( extFloat80_t a, extFloat80_t b ) -{ - union { struct extFloat80M s; extFloat80_t f; } uA; - uint_fast16_t uiA64; - uint_fast64_t uiA0; - union { struct extFloat80M s; extFloat80_t f; } uB; - uint_fast16_t uiB64; - uint_fast64_t uiB0; - - uA.f = a; - uiA64 = uA.s.signExp; - uiA0 = uA.s.signif; - uB.f = b; - uiB64 = uB.s.signExp; - uiB0 = uB.s.signif; - if ( isNaNExtF80UI( uiA64, uiA0 ) || isNaNExtF80UI( uiB64, uiB0 ) ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - return false; - } - return - (uiA0 == uiB0) - && ((uiA64 == uiB64) || (! uiA0 && ! ((uiA64 | uiB64) & 0x7FFF))); - -} - diff --git a/deps/SoftFloat-3e/source/extF80_isSignalingNaN.c b/deps/SoftFloat-3e/source/extF80_isSignalingNaN.c deleted file mode 100644 index 33d2abd7e9bf..000000000000 --- a/deps/SoftFloat-3e/source/extF80_isSignalingNaN.c +++ /dev/null @@ -1,51 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -bool extF80_isSignalingNaN( extFloat80_t a ) -{ - union { struct extFloat80M s; extFloat80_t f; } uA; - - uA.f = a; - return softfloat_isSigNaNExtF80UI( uA.s.signExp, uA.s.signif ); - -} - diff --git a/deps/SoftFloat-3e/source/extF80_le.c b/deps/SoftFloat-3e/source/extF80_le.c deleted file mode 100644 index 4e23c5142007..000000000000 --- a/deps/SoftFloat-3e/source/extF80_le.c +++ /dev/null @@ -1,73 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -bool extF80_le( extFloat80_t a, extFloat80_t b ) -{ - union { struct extFloat80M s; extFloat80_t f; } uA; - uint_fast16_t uiA64; - uint_fast64_t uiA0; - union { struct extFloat80M s; extFloat80_t f; } uB; - uint_fast16_t uiB64; - uint_fast64_t uiB0; - bool signA, signB; - - uA.f = a; - uiA64 = uA.s.signExp; - uiA0 = uA.s.signif; - uB.f = b; - uiB64 = uB.s.signExp; - uiB0 = uB.s.signif; - if ( isNaNExtF80UI( uiA64, uiA0 ) || isNaNExtF80UI( uiB64, uiB0 ) ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - return false; - } - signA = signExtF80UI64( uiA64 ); - signB = signExtF80UI64( uiB64 ); - return - (signA != signB) - ? signA || ! (((uiA64 | uiB64) & 0x7FFF) | uiA0 | uiB0) - : ((uiA64 == uiB64) && (uiA0 == uiB0)) - || (signA ^ softfloat_lt128( uiA64, uiA0, uiB64, uiB0 )); - -} - diff --git a/deps/SoftFloat-3e/source/extF80_le_quiet.c b/deps/SoftFloat-3e/source/extF80_le_quiet.c deleted file mode 100644 index 9839e47f9e01..000000000000 --- a/deps/SoftFloat-3e/source/extF80_le_quiet.c +++ /dev/null @@ -1,78 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -bool extF80_le_quiet( extFloat80_t a, extFloat80_t b ) -{ - union { struct extFloat80M s; extFloat80_t f; } uA; - uint_fast16_t uiA64; - uint_fast64_t uiA0; - union { struct extFloat80M s; extFloat80_t f; } uB; - uint_fast16_t uiB64; - uint_fast64_t uiB0; - bool signA, signB; - - uA.f = a; - uiA64 = uA.s.signExp; - uiA0 = uA.s.signif; - uB.f = b; - uiB64 = uB.s.signExp; - uiB0 = uB.s.signif; - if ( isNaNExtF80UI( uiA64, uiA0 ) || isNaNExtF80UI( uiB64, uiB0 ) ) { - if ( - softfloat_isSigNaNExtF80UI( uiA64, uiA0 ) - || softfloat_isSigNaNExtF80UI( uiB64, uiB0 ) - ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - } - return false; - } - signA = signExtF80UI64( uiA64 ); - signB = signExtF80UI64( uiB64 ); - return - (signA != signB) - ? signA || ! (((uiA64 | uiB64) & 0x7FFF) | uiA0 | uiB0) - : ((uiA64 == uiB64) && (uiA0 == uiB0)) - || (signA ^ softfloat_lt128( uiA64, uiA0, uiB64, uiB0 )); - -} - diff --git a/deps/SoftFloat-3e/source/extF80_lt.c b/deps/SoftFloat-3e/source/extF80_lt.c deleted file mode 100644 index a4ac69fa6c23..000000000000 --- a/deps/SoftFloat-3e/source/extF80_lt.c +++ /dev/null @@ -1,73 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -bool extF80_lt( extFloat80_t a, extFloat80_t b ) -{ - union { struct extFloat80M s; extFloat80_t f; } uA; - uint_fast16_t uiA64; - uint_fast64_t uiA0; - union { struct extFloat80M s; extFloat80_t f; } uB; - uint_fast16_t uiB64; - uint_fast64_t uiB0; - bool signA, signB; - - uA.f = a; - uiA64 = uA.s.signExp; - uiA0 = uA.s.signif; - uB.f = b; - uiB64 = uB.s.signExp; - uiB0 = uB.s.signif; - if ( isNaNExtF80UI( uiA64, uiA0 ) || isNaNExtF80UI( uiB64, uiB0 ) ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - return false; - } - signA = signExtF80UI64( uiA64 ); - signB = signExtF80UI64( uiB64 ); - return - (signA != signB) - ? signA && (((uiA64 | uiB64) & 0x7FFF) | uiA0 | uiB0) - : ((uiA64 != uiB64) || (uiA0 != uiB0)) - && (signA ^ softfloat_lt128( uiA64, uiA0, uiB64, uiB0 )); - -} - diff --git a/deps/SoftFloat-3e/source/extF80_lt_quiet.c b/deps/SoftFloat-3e/source/extF80_lt_quiet.c deleted file mode 100644 index 00f4d4768771..000000000000 --- a/deps/SoftFloat-3e/source/extF80_lt_quiet.c +++ /dev/null @@ -1,78 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -bool extF80_lt_quiet( extFloat80_t a, extFloat80_t b ) -{ - union { struct extFloat80M s; extFloat80_t f; } uA; - uint_fast16_t uiA64; - uint_fast64_t uiA0; - union { struct extFloat80M s; extFloat80_t f; } uB; - uint_fast16_t uiB64; - uint_fast64_t uiB0; - bool signA, signB; - - uA.f = a; - uiA64 = uA.s.signExp; - uiA0 = uA.s.signif; - uB.f = b; - uiB64 = uB.s.signExp; - uiB0 = uB.s.signif; - if ( isNaNExtF80UI( uiA64, uiA0 ) || isNaNExtF80UI( uiB64, uiB0 ) ) { - if ( - softfloat_isSigNaNExtF80UI( uiA64, uiA0 ) - || softfloat_isSigNaNExtF80UI( uiB64, uiB0 ) - ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - } - return false; - } - signA = signExtF80UI64( uiA64 ); - signB = signExtF80UI64( uiB64 ); - return - (signA != signB) - ? signA && (((uiA64 | uiB64) & 0x7FFF) | uiA0 | uiB0) - : ((uiA64 != uiB64) || (uiA0 != uiB0)) - && (signA ^ softfloat_lt128( uiA64, uiA0, uiB64, uiB0 )); - -} - diff --git a/deps/SoftFloat-3e/source/extF80_mul.c b/deps/SoftFloat-3e/source/extF80_mul.c deleted file mode 100644 index 39ce4012c454..000000000000 --- a/deps/SoftFloat-3e/source/extF80_mul.c +++ /dev/null @@ -1,158 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -extFloat80_t extF80_mul( extFloat80_t a, extFloat80_t b ) -{ - union { struct extFloat80M s; extFloat80_t f; } uA; - uint_fast16_t uiA64; - uint_fast64_t uiA0; - bool signA; - int_fast32_t expA; - uint_fast64_t sigA; - union { struct extFloat80M s; extFloat80_t f; } uB; - uint_fast16_t uiB64; - uint_fast64_t uiB0; - bool signB; - int_fast32_t expB; - uint_fast64_t sigB; - bool signZ; - uint_fast64_t magBits; - struct exp32_sig64 normExpSig; - int_fast32_t expZ; - struct uint128 sig128Z, uiZ; - uint_fast16_t uiZ64; - uint_fast64_t uiZ0; - union { struct extFloat80M s; extFloat80_t f; } uZ; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uA.f = a; - uiA64 = uA.s.signExp; - uiA0 = uA.s.signif; - signA = signExtF80UI64( uiA64 ); - expA = expExtF80UI64( uiA64 ); - sigA = uiA0; - uB.f = b; - uiB64 = uB.s.signExp; - uiB0 = uB.s.signif; - signB = signExtF80UI64( uiB64 ); - expB = expExtF80UI64( uiB64 ); - sigB = uiB0; - signZ = signA ^ signB; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( expA == 0x7FFF ) { - if ( - (sigA & UINT64_C( 0x7FFFFFFFFFFFFFFF )) - || ((expB == 0x7FFF) && (sigB & UINT64_C( 0x7FFFFFFFFFFFFFFF ))) - ) { - goto propagateNaN; - } - magBits = expB | sigB; - goto infArg; - } - if ( expB == 0x7FFF ) { - if ( sigB & UINT64_C( 0x7FFFFFFFFFFFFFFF ) ) goto propagateNaN; - magBits = expA | sigA; - goto infArg; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( ! expA ) expA = 1; - if ( ! (sigA & UINT64_C( 0x8000000000000000 )) ) { - if ( ! sigA ) goto zero; - normExpSig = softfloat_normSubnormalExtF80Sig( sigA ); - expA += normExpSig.exp; - sigA = normExpSig.sig; - } - if ( ! expB ) expB = 1; - if ( ! (sigB & UINT64_C( 0x8000000000000000 )) ) { - if ( ! sigB ) goto zero; - normExpSig = softfloat_normSubnormalExtF80Sig( sigB ); - expB += normExpSig.exp; - sigB = normExpSig.sig; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - expZ = expA + expB - 0x3FFE; - sig128Z = softfloat_mul64To128( sigA, sigB ); - if ( sig128Z.v64 < UINT64_C( 0x8000000000000000 ) ) { - --expZ; - sig128Z = - softfloat_add128( - sig128Z.v64, sig128Z.v0, sig128Z.v64, sig128Z.v0 ); - } - return - softfloat_roundPackToExtF80( - signZ, expZ, sig128Z.v64, sig128Z.v0, extF80_roundingPrecision ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - propagateNaN: - uiZ = softfloat_propagateNaNExtF80UI( uiA64, uiA0, uiB64, uiB0 ); - uiZ64 = uiZ.v64; - uiZ0 = uiZ.v0; - goto uiZ; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - infArg: - if ( ! magBits ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - uiZ64 = defaultNaNExtF80UI64; - uiZ0 = defaultNaNExtF80UI0; - } else { - uiZ64 = packToExtF80UI64( signZ, 0x7FFF ); - uiZ0 = UINT64_C( 0x8000000000000000 ); - } - goto uiZ; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - zero: - uiZ64 = packToExtF80UI64( signZ, 0 ); - uiZ0 = 0; - uiZ: - uZ.s.signExp = uiZ64; - uZ.s.signif = uiZ0; - return uZ.f; - -} - diff --git a/deps/SoftFloat-3e/source/extF80_rem.c b/deps/SoftFloat-3e/source/extF80_rem.c deleted file mode 100644 index 5ad977526241..000000000000 --- a/deps/SoftFloat-3e/source/extF80_rem.c +++ /dev/null @@ -1,225 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017 The Regents of the -University of California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -extFloat80_t extF80_rem( extFloat80_t a, extFloat80_t b ) -{ - union { struct extFloat80M s; extFloat80_t f; } uA; - uint_fast16_t uiA64; - uint_fast64_t uiA0; - bool signA; - int_fast32_t expA; - uint_fast64_t sigA; - union { struct extFloat80M s; extFloat80_t f; } uB; - uint_fast16_t uiB64; - uint_fast64_t uiB0; - int_fast32_t expB; - uint_fast64_t sigB; - struct exp32_sig64 normExpSig; - int_fast32_t expDiff; - struct uint128 rem, shiftedSigB; - uint_fast32_t q, recip32; - uint_fast64_t q64; - struct uint128 term, altRem, meanRem; - bool signRem; - struct uint128 uiZ; - uint_fast16_t uiZ64; - uint_fast64_t uiZ0; - union { struct extFloat80M s; extFloat80_t f; } uZ; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uA.f = a; - uiA64 = uA.s.signExp; - uiA0 = uA.s.signif; - signA = signExtF80UI64( uiA64 ); - expA = expExtF80UI64( uiA64 ); - sigA = uiA0; - uB.f = b; - uiB64 = uB.s.signExp; - uiB0 = uB.s.signif; - expB = expExtF80UI64( uiB64 ); - sigB = uiB0; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( expA == 0x7FFF ) { - if ( - (sigA & UINT64_C( 0x7FFFFFFFFFFFFFFF )) - || ((expB == 0x7FFF) && (sigB & UINT64_C( 0x7FFFFFFFFFFFFFFF ))) - ) { - goto propagateNaN; - } - goto invalid; - } - if ( expB == 0x7FFF ) { - if ( sigB & UINT64_C( 0x7FFFFFFFFFFFFFFF ) ) goto propagateNaN; - /*-------------------------------------------------------------------- - | Argument b is an infinity. Doubling `expB' is an easy way to ensure - | that `expDiff' later is less than -1, which will result in returning - | a canonicalized version of argument a. - *--------------------------------------------------------------------*/ - expB += expB; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( ! expB ) expB = 1; - if ( ! (sigB & UINT64_C( 0x8000000000000000 )) ) { - if ( ! sigB ) goto invalid; - normExpSig = softfloat_normSubnormalExtF80Sig( sigB ); - expB += normExpSig.exp; - sigB = normExpSig.sig; - } - if ( ! expA ) expA = 1; - if ( ! (sigA & UINT64_C( 0x8000000000000000 )) ) { - if ( ! sigA ) { - expA = 0; - goto copyA; - } - normExpSig = softfloat_normSubnormalExtF80Sig( sigA ); - expA += normExpSig.exp; - sigA = normExpSig.sig; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - expDiff = expA - expB; - if ( expDiff < -1 ) goto copyA; - rem = softfloat_shortShiftLeft128( 0, sigA, 32 ); - shiftedSigB = softfloat_shortShiftLeft128( 0, sigB, 32 ); - if ( expDiff < 1 ) { - if ( expDiff ) { - --expB; - shiftedSigB = softfloat_shortShiftLeft128( 0, sigB, 33 ); - q = 0; - } else { - q = (sigB <= sigA); - if ( q ) { - rem = - softfloat_sub128( - rem.v64, rem.v0, shiftedSigB.v64, shiftedSigB.v0 ); - } - } - } else { - recip32 = softfloat_approxRecip32_1( sigB>>32 ); - expDiff -= 30; - for (;;) { - q64 = (uint_fast64_t) (uint32_t) (rem.v64>>2) * recip32; - if ( expDiff < 0 ) break; - q = (q64 + 0x80000000)>>32; - rem = softfloat_shortShiftLeft128( rem.v64, rem.v0, 29 ); - term = softfloat_mul64ByShifted32To128( sigB, q ); - rem = softfloat_sub128( rem.v64, rem.v0, term.v64, term.v0 ); - if ( rem.v64 & UINT64_C( 0x8000000000000000 ) ) { - rem = - softfloat_add128( - rem.v64, rem.v0, shiftedSigB.v64, shiftedSigB.v0 ); - } - expDiff -= 29; - } - /*-------------------------------------------------------------------- - | (`expDiff' cannot be less than -29 here.) - *--------------------------------------------------------------------*/ - q = (uint32_t) (q64>>32)>>(~expDiff & 31); - rem = softfloat_shortShiftLeft128( rem.v64, rem.v0, expDiff + 30 ); - term = softfloat_mul64ByShifted32To128( sigB, q ); - rem = softfloat_sub128( rem.v64, rem.v0, term.v64, term.v0 ); - if ( rem.v64 & UINT64_C( 0x8000000000000000 ) ) { - altRem = - softfloat_add128( - rem.v64, rem.v0, shiftedSigB.v64, shiftedSigB.v0 ); - goto selectRem; - } - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - do { - altRem = rem; - ++q; - rem = - softfloat_sub128( - rem.v64, rem.v0, shiftedSigB.v64, shiftedSigB.v0 ); - } while ( ! (rem.v64 & UINT64_C( 0x8000000000000000 )) ); - selectRem: - meanRem = softfloat_add128( rem.v64, rem.v0, altRem.v64, altRem.v0 ); - if ( - (meanRem.v64 & UINT64_C( 0x8000000000000000 )) - || (! (meanRem.v64 | meanRem.v0) && (q & 1)) - ) { - rem = altRem; - } - signRem = signA; - if ( rem.v64 & UINT64_C( 0x8000000000000000 ) ) { - signRem = ! signRem; - rem = softfloat_sub128( 0, 0, rem.v64, rem.v0 ); - } - return - softfloat_normRoundPackToExtF80( - signRem, rem.v64 | rem.v0 ? expB + 32 : 0, rem.v64, rem.v0, 80 ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - propagateNaN: - uiZ = softfloat_propagateNaNExtF80UI( uiA64, uiA0, uiB64, uiB0 ); - uiZ64 = uiZ.v64; - uiZ0 = uiZ.v0; - goto uiZ; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - invalid: - softfloat_raiseFlags( softfloat_flag_invalid ); - uiZ64 = defaultNaNExtF80UI64; - uiZ0 = defaultNaNExtF80UI0; - goto uiZ; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - copyA: - if ( expA < 1 ) { - sigA >>= 1 - expA; - expA = 0; - } - uiZ64 = packToExtF80UI64( signA, expA ); - uiZ0 = sigA; - uiZ: - uZ.s.signExp = uiZ64; - uZ.s.signif = uiZ0; - return uZ.f; - -} - diff --git a/deps/SoftFloat-3e/source/extF80_roundToInt.c b/deps/SoftFloat-3e/source/extF80_roundToInt.c deleted file mode 100644 index 6c12d84c9e9f..000000000000 --- a/deps/SoftFloat-3e/source/extF80_roundToInt.c +++ /dev/null @@ -1,154 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2017 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -extFloat80_t - extF80_roundToInt( extFloat80_t a, uint_fast8_t roundingMode, bool exact ) -{ - union { struct extFloat80M s; extFloat80_t f; } uA; - uint_fast16_t uiA64, signUI64; - int_fast32_t exp; - uint_fast64_t sigA; - uint_fast16_t uiZ64; - uint_fast64_t sigZ; - struct exp32_sig64 normExpSig; - struct uint128 uiZ; - uint_fast64_t lastBitMask, roundBitsMask; - union { struct extFloat80M s; extFloat80_t f; } uZ; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uA.f = a; - uiA64 = uA.s.signExp; - signUI64 = uiA64 & packToExtF80UI64( 1, 0 ); - exp = expExtF80UI64( uiA64 ); - sigA = uA.s.signif; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( !(sigA & UINT64_C( 0x8000000000000000 )) && (exp != 0x7FFF) ) { - if ( !sigA ) { - uiZ64 = signUI64; - sigZ = 0; - goto uiZ; - } - normExpSig = softfloat_normSubnormalExtF80Sig( sigA ); - exp += normExpSig.exp; - sigA = normExpSig.sig; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( 0x403E <= exp ) { - if ( exp == 0x7FFF ) { - if ( sigA & UINT64_C( 0x7FFFFFFFFFFFFFFF ) ) { - uiZ = softfloat_propagateNaNExtF80UI( uiA64, sigA, 0, 0 ); - uiZ64 = uiZ.v64; - sigZ = uiZ.v0; - goto uiZ; - } - sigZ = UINT64_C( 0x8000000000000000 ); - } else { - sigZ = sigA; - } - uiZ64 = signUI64 | exp; - goto uiZ; - } - if ( exp <= 0x3FFE ) { - if ( exact ) softfloat_exceptionFlags |= softfloat_flag_inexact; - switch ( roundingMode ) { - case softfloat_round_near_even: - if ( !(sigA & UINT64_C( 0x7FFFFFFFFFFFFFFF )) ) break; - case softfloat_round_near_maxMag: - if ( exp == 0x3FFE ) goto mag1; - break; - case softfloat_round_min: - if ( signUI64 ) goto mag1; - break; - case softfloat_round_max: - if ( !signUI64 ) goto mag1; - break; -#ifdef SOFTFLOAT_ROUND_ODD - case softfloat_round_odd: - goto mag1; -#endif - } - uiZ64 = signUI64; - sigZ = 0; - goto uiZ; - mag1: - uiZ64 = signUI64 | 0x3FFF; - sigZ = UINT64_C( 0x8000000000000000 ); - goto uiZ; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uiZ64 = signUI64 | exp; - lastBitMask = (uint_fast64_t) 1<<(0x403E - exp); - roundBitsMask = lastBitMask - 1; - sigZ = sigA; - if ( roundingMode == softfloat_round_near_maxMag ) { - sigZ += lastBitMask>>1; - } else if ( roundingMode == softfloat_round_near_even ) { - sigZ += lastBitMask>>1; - if ( !(sigZ & roundBitsMask) ) sigZ &= ~lastBitMask; - } else if ( - roundingMode == (signUI64 ? softfloat_round_min : softfloat_round_max) - ) { - sigZ += roundBitsMask; - } - sigZ &= ~roundBitsMask; - if ( !sigZ ) { - ++uiZ64; - sigZ = UINT64_C( 0x8000000000000000 ); - } - if ( sigZ != sigA ) { -#ifdef SOFTFLOAT_ROUND_ODD - if ( roundingMode == softfloat_round_odd ) sigZ |= lastBitMask; -#endif - if ( exact ) softfloat_exceptionFlags |= softfloat_flag_inexact; - } - uiZ: - uZ.s.signExp = uiZ64; - uZ.s.signif = sigZ; - return uZ.f; - -} - diff --git a/deps/SoftFloat-3e/source/extF80_sqrt.c b/deps/SoftFloat-3e/source/extF80_sqrt.c deleted file mode 100644 index af8c496e1432..000000000000 --- a/deps/SoftFloat-3e/source/extF80_sqrt.c +++ /dev/null @@ -1,176 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017 The Regents of the -University of California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -extFloat80_t extF80_sqrt( extFloat80_t a ) -{ - union { struct extFloat80M s; extFloat80_t f; } uA; - uint_fast16_t uiA64; - uint_fast64_t uiA0; - bool signA; - int_fast32_t expA; - uint_fast64_t sigA; - struct uint128 uiZ; - uint_fast16_t uiZ64; - uint_fast64_t uiZ0; - struct exp32_sig64 normExpSig; - int_fast32_t expZ; - uint_fast32_t sig32A, recipSqrt32, sig32Z; - struct uint128 rem; - uint_fast64_t q, x64, sigZ; - struct uint128 y, term; - uint_fast64_t sigZExtra; - union { struct extFloat80M s; extFloat80_t f; } uZ; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uA.f = a; - uiA64 = uA.s.signExp; - uiA0 = uA.s.signif; - signA = signExtF80UI64( uiA64 ); - expA = expExtF80UI64( uiA64 ); - sigA = uiA0; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( expA == 0x7FFF ) { - if ( sigA & UINT64_C( 0x7FFFFFFFFFFFFFFF ) ) { - uiZ = softfloat_propagateNaNExtF80UI( uiA64, uiA0, 0, 0 ); - uiZ64 = uiZ.v64; - uiZ0 = uiZ.v0; - goto uiZ; - } - if ( ! signA ) return a; - goto invalid; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( signA ) { - if ( ! sigA ) goto zero; - goto invalid; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( ! expA ) expA = 1; - if ( ! (sigA & UINT64_C( 0x8000000000000000 )) ) { - if ( ! sigA ) goto zero; - normExpSig = softfloat_normSubnormalExtF80Sig( sigA ); - expA += normExpSig.exp; - sigA = normExpSig.sig; - } - /*------------------------------------------------------------------------ - | (`sig32Z' is guaranteed to be a lower bound on the square root of - | `sig32A', which makes `sig32Z' also a lower bound on the square root of - | `sigA'.) - *------------------------------------------------------------------------*/ - expZ = ((expA - 0x3FFF)>>1) + 0x3FFF; - expA &= 1; - sig32A = sigA>>32; - recipSqrt32 = softfloat_approxRecipSqrt32_1( expA, sig32A ); - sig32Z = ((uint_fast64_t) sig32A * recipSqrt32)>>32; - if ( expA ) { - sig32Z >>= 1; - rem = softfloat_shortShiftLeft128( 0, sigA, 61 ); - } else { - rem = softfloat_shortShiftLeft128( 0, sigA, 62 ); - } - rem.v64 -= (uint_fast64_t) sig32Z * sig32Z; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - q = ((uint32_t) (rem.v64>>2) * (uint_fast64_t) recipSqrt32)>>32; - x64 = (uint_fast64_t) sig32Z<<32; - sigZ = x64 + (q<<3); - y = softfloat_shortShiftLeft128( rem.v64, rem.v0, 29 ); - /*------------------------------------------------------------------------ - | (Repeating this loop is a rare occurrence.) - *------------------------------------------------------------------------*/ - for (;;) { - term = softfloat_mul64ByShifted32To128( x64 + sigZ, q ); - rem = softfloat_sub128( y.v64, y.v0, term.v64, term.v0 ); - if ( ! (rem.v64 & UINT64_C( 0x8000000000000000 )) ) break; - --q; - sigZ -= 1<<3; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - q = (((rem.v64>>2) * recipSqrt32)>>32) + 2; - x64 = sigZ; - sigZ = (sigZ<<1) + (q>>25); - sigZExtra = (uint64_t) (q<<39); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( (q & 0xFFFFFF) <= 2 ) { - q &= ~(uint_fast64_t) 0xFFFF; - sigZExtra = (uint64_t) (q<<39); - term = softfloat_mul64ByShifted32To128( x64 + (q>>27), q ); - x64 = (uint32_t) (q<<5) * (uint_fast64_t) (uint32_t) q; - term = softfloat_add128( term.v64, term.v0, 0, x64 ); - rem = softfloat_shortShiftLeft128( rem.v64, rem.v0, 28 ); - rem = softfloat_sub128( rem.v64, rem.v0, term.v64, term.v0 ); - if ( rem.v64 & UINT64_C( 0x8000000000000000 ) ) { - if ( ! sigZExtra ) --sigZ; - --sigZExtra; - } else { - if ( rem.v64 | rem.v0 ) sigZExtra |= 1; - } - } - return - softfloat_roundPackToExtF80( - 0, expZ, sigZ, sigZExtra, extF80_roundingPrecision ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - invalid: - softfloat_raiseFlags( softfloat_flag_invalid ); - uiZ64 = defaultNaNExtF80UI64; - uiZ0 = defaultNaNExtF80UI0; - goto uiZ; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - zero: - uiZ64 = packToExtF80UI64( signA, 0 ); - uiZ0 = 0; - uiZ: - uZ.s.signExp = uiZ64; - uZ.s.signif = uiZ0; - return uZ.f; - -} - diff --git a/deps/SoftFloat-3e/source/extF80_sub.c b/deps/SoftFloat-3e/source/extF80_sub.c deleted file mode 100644 index 770c7563a248..000000000000 --- a/deps/SoftFloat-3e/source/extF80_sub.c +++ /dev/null @@ -1,80 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "softfloat.h" - -extFloat80_t extF80_sub( extFloat80_t a, extFloat80_t b ) -{ - union { struct extFloat80M s; extFloat80_t f; } uA; - uint_fast16_t uiA64; - uint_fast64_t uiA0; - bool signA; - union { struct extFloat80M s; extFloat80_t f; } uB; - uint_fast16_t uiB64; - uint_fast64_t uiB0; - bool signB; -#if ! defined INLINE_LEVEL || (INLINE_LEVEL < 2) - extFloat80_t - (*magsFuncPtr)( - uint_fast16_t, uint_fast64_t, uint_fast16_t, uint_fast64_t, bool ); -#endif - - uA.f = a; - uiA64 = uA.s.signExp; - uiA0 = uA.s.signif; - signA = signExtF80UI64( uiA64 ); - uB.f = b; - uiB64 = uB.s.signExp; - uiB0 = uB.s.signif; - signB = signExtF80UI64( uiB64 ); -#if defined INLINE_LEVEL && (2 <= INLINE_LEVEL) - if ( signA == signB ) { - return softfloat_subMagsExtF80( uiA64, uiA0, uiB64, uiB0, signA ); - } else { - return softfloat_addMagsExtF80( uiA64, uiA0, uiB64, uiB0, signA ); - } -#else - magsFuncPtr = - (signA == signB) ? softfloat_subMagsExtF80 : softfloat_addMagsExtF80; - return (*magsFuncPtr)( uiA64, uiA0, uiB64, uiB0, signA ); -#endif - -} - diff --git a/deps/SoftFloat-3e/source/extF80_to_f128.c b/deps/SoftFloat-3e/source/extF80_to_f128.c deleted file mode 100644 index 4de90ae3166a..000000000000 --- a/deps/SoftFloat-3e/source/extF80_to_f128.c +++ /dev/null @@ -1,75 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -float128_t extF80_to_f128( extFloat80_t a ) -{ - union { struct extFloat80M s; extFloat80_t f; } uA; - uint_fast16_t uiA64; - uint_fast64_t uiA0; - uint_fast16_t exp; - uint_fast64_t frac; - struct commonNaN commonNaN; - struct uint128 uiZ; - bool sign; - struct uint128 frac128; - union ui128_f128 uZ; - - uA.f = a; - uiA64 = uA.s.signExp; - uiA0 = uA.s.signif; - exp = expExtF80UI64( uiA64 ); - frac = uiA0 & UINT64_C( 0x7FFFFFFFFFFFFFFF ); - if ( (exp == 0x7FFF) && frac ) { - softfloat_extF80UIToCommonNaN( uiA64, uiA0, &commonNaN ); - uiZ = softfloat_commonNaNToF128UI( &commonNaN ); - } else { - sign = signExtF80UI64( uiA64 ); - frac128 = softfloat_shortShiftLeft128( 0, frac, 49 ); - uiZ.v64 = packToF128UI64( sign, exp, frac128.v64 ); - uiZ.v0 = frac128.v0; - } - uZ.ui = uiZ; - return uZ.f; - -} - diff --git a/deps/SoftFloat-3e/source/extF80_to_f16.c b/deps/SoftFloat-3e/source/extF80_to_f16.c deleted file mode 100644 index 5919403fb9c4..000000000000 --- a/deps/SoftFloat-3e/source/extF80_to_f16.c +++ /dev/null @@ -1,96 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -float16_t extF80_to_f16( extFloat80_t a ) -{ - union { struct extFloat80M s; extFloat80_t f; } uA; - uint_fast16_t uiA64; - uint_fast64_t uiA0; - bool sign; - int_fast32_t exp; - uint_fast64_t sig; - struct commonNaN commonNaN; - uint_fast16_t uiZ, sig16; - union ui16_f16 uZ; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uA.f = a; - uiA64 = uA.s.signExp; - uiA0 = uA.s.signif; - sign = signExtF80UI64( uiA64 ); - exp = expExtF80UI64( uiA64 ); - sig = uiA0; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( exp == 0x7FFF ) { - if ( sig & UINT64_C( 0x7FFFFFFFFFFFFFFF ) ) { - softfloat_extF80UIToCommonNaN( uiA64, uiA0, &commonNaN ); - uiZ = softfloat_commonNaNToF16UI( &commonNaN ); - } else { - uiZ = packToF16UI( sign, 0x1F, 0 ); - } - goto uiZ; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - sig16 = softfloat_shortShiftRightJam64( sig, 49 ); - if ( ! (exp | sig16) ) { - uiZ = packToF16UI( sign, 0, 0 ); - goto uiZ; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - exp -= 0x3FF1; - if ( sizeof (int_fast16_t) < sizeof (int_fast32_t) ) { - if ( exp < -0x40 ) exp = -0x40; - } - return softfloat_roundPackToF16( sign, exp, sig16 ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uiZ: - uZ.ui = uiZ; - return uZ.f; - -} - diff --git a/deps/SoftFloat-3e/source/extF80_to_f32.c b/deps/SoftFloat-3e/source/extF80_to_f32.c deleted file mode 100644 index 77fcfdc112ec..000000000000 --- a/deps/SoftFloat-3e/source/extF80_to_f32.c +++ /dev/null @@ -1,96 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -float32_t extF80_to_f32( extFloat80_t a ) -{ - union { struct extFloat80M s; extFloat80_t f; } uA; - uint_fast16_t uiA64; - uint_fast64_t uiA0; - bool sign; - int_fast32_t exp; - uint_fast64_t sig; - struct commonNaN commonNaN; - uint_fast32_t uiZ, sig32; - union ui32_f32 uZ; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uA.f = a; - uiA64 = uA.s.signExp; - uiA0 = uA.s.signif; - sign = signExtF80UI64( uiA64 ); - exp = expExtF80UI64( uiA64 ); - sig = uiA0; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( exp == 0x7FFF ) { - if ( sig & UINT64_C( 0x7FFFFFFFFFFFFFFF ) ) { - softfloat_extF80UIToCommonNaN( uiA64, uiA0, &commonNaN ); - uiZ = softfloat_commonNaNToF32UI( &commonNaN ); - } else { - uiZ = packToF32UI( sign, 0xFF, 0 ); - } - goto uiZ; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - sig32 = softfloat_shortShiftRightJam64( sig, 33 ); - if ( ! (exp | sig32) ) { - uiZ = packToF32UI( sign, 0, 0 ); - goto uiZ; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - exp -= 0x3F81; - if ( sizeof (int_fast16_t) < sizeof (int_fast32_t) ) { - if ( exp < -0x1000 ) exp = -0x1000; - } - return softfloat_roundPackToF32( sign, exp, sig32 ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uiZ: - uZ.ui = uiZ; - return uZ.f; - -} - diff --git a/deps/SoftFloat-3e/source/extF80_to_f64.c b/deps/SoftFloat-3e/source/extF80_to_f64.c deleted file mode 100644 index 410d6622c4f0..000000000000 --- a/deps/SoftFloat-3e/source/extF80_to_f64.c +++ /dev/null @@ -1,96 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -float64_t extF80_to_f64( extFloat80_t a ) -{ - union { struct extFloat80M s; extFloat80_t f; } uA; - uint_fast16_t uiA64; - uint_fast64_t uiA0; - bool sign; - int_fast32_t exp; - uint_fast64_t sig; - struct commonNaN commonNaN; - uint_fast64_t uiZ; - union ui64_f64 uZ; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uA.f = a; - uiA64 = uA.s.signExp; - uiA0 = uA.s.signif; - sign = signExtF80UI64( uiA64 ); - exp = expExtF80UI64( uiA64 ); - sig = uiA0; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( ! (exp | sig) ) { - uiZ = packToF64UI( sign, 0, 0 ); - goto uiZ; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( exp == 0x7FFF ) { - if ( sig & UINT64_C( 0x7FFFFFFFFFFFFFFF ) ) { - softfloat_extF80UIToCommonNaN( uiA64, uiA0, &commonNaN ); - uiZ = softfloat_commonNaNToF64UI( &commonNaN ); - } else { - uiZ = packToF64UI( sign, 0x7FF, 0 ); - } - goto uiZ; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - sig = softfloat_shortShiftRightJam64( sig, 1 ); - exp -= 0x3C01; - if ( sizeof (int_fast16_t) < sizeof (int_fast32_t) ) { - if ( exp < -0x1000 ) exp = -0x1000; - } - return softfloat_roundPackToF64( sign, exp, sig ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uiZ: - uZ.ui = uiZ; - return uZ.f; - -} - diff --git a/deps/SoftFloat-3e/source/extF80_to_i32.c b/deps/SoftFloat-3e/source/extF80_to_i32.c deleted file mode 100644 index 9acdc3c9bc73..000000000000 --- a/deps/SoftFloat-3e/source/extF80_to_i32.c +++ /dev/null @@ -1,83 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017 The Regents of the -University of California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -int_fast32_t - extF80_to_i32( extFloat80_t a, uint_fast8_t roundingMode, bool exact ) -{ - union { struct extFloat80M s; extFloat80_t f; } uA; - uint_fast16_t uiA64; - bool sign; - int_fast32_t exp; - uint_fast64_t sig; - int_fast32_t shiftDist; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uA.f = a; - uiA64 = uA.s.signExp; - sign = signExtF80UI64( uiA64 ); - exp = expExtF80UI64( uiA64 ); - sig = uA.s.signif; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ -#if (i32_fromNaN != i32_fromPosOverflow) || (i32_fromNaN != i32_fromNegOverflow) - if ( (exp == 0x7FFF) && (sig & UINT64_C( 0x7FFFFFFFFFFFFFFF )) ) { -#if (i32_fromNaN == i32_fromPosOverflow) - sign = 0; -#elif (i32_fromNaN == i32_fromNegOverflow) - sign = 1; -#else - softfloat_raiseFlags( softfloat_flag_invalid ); - return i32_fromNaN; -#endif - } -#endif - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - shiftDist = 0x4032 - exp; - if ( shiftDist <= 0 ) shiftDist = 1; - sig = softfloat_shiftRightJam64( sig, shiftDist ); - return softfloat_roundToI32( sign, sig, roundingMode, exact ); - -} - diff --git a/deps/SoftFloat-3e/source/extF80_to_i32_r_minMag.c b/deps/SoftFloat-3e/source/extF80_to_i32_r_minMag.c deleted file mode 100644 index 03224678a183..000000000000 --- a/deps/SoftFloat-3e/source/extF80_to_i32_r_minMag.c +++ /dev/null @@ -1,97 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -int_fast32_t extF80_to_i32_r_minMag( extFloat80_t a, bool exact ) -{ - union { struct extFloat80M s; extFloat80_t f; } uA; - uint_fast16_t uiA64; - int_fast32_t exp; - uint_fast64_t sig; - int_fast32_t shiftDist; - bool sign; - int_fast32_t absZ; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uA.f = a; - uiA64 = uA.s.signExp; - exp = expExtF80UI64( uiA64 ); - sig = uA.s.signif; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - shiftDist = 0x403E - exp; - if ( 64 <= shiftDist ) { - if ( exact && (exp | sig) ) { - softfloat_exceptionFlags |= softfloat_flag_inexact; - } - return 0; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - sign = signExtF80UI64( uiA64 ); - if ( shiftDist < 33 ) { - if ( - (uiA64 == packToExtF80UI64( 1, 0x401E )) - && (sig < UINT64_C( 0x8000000100000000 )) - ) { - if ( exact && (sig & UINT64_C( 0x00000000FFFFFFFF )) ) { - softfloat_exceptionFlags |= softfloat_flag_inexact; - } - return -0x7FFFFFFF - 1; - } - softfloat_raiseFlags( softfloat_flag_invalid ); - return - (exp == 0x7FFF) && (sig & UINT64_C( 0x7FFFFFFFFFFFFFFF )) - ? i32_fromNaN - : sign ? i32_fromNegOverflow : i32_fromPosOverflow; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - absZ = sig>>shiftDist; - if ( exact && ((uint_fast64_t) (uint_fast32_t) absZ< -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -int_fast64_t - extF80_to_i64( extFloat80_t a, uint_fast8_t roundingMode, bool exact ) -{ - union { struct extFloat80M s; extFloat80_t f; } uA; - uint_fast16_t uiA64; - bool sign; - int_fast32_t exp; - uint_fast64_t sig; - int_fast32_t shiftDist; - uint_fast64_t sigExtra; - struct uint64_extra sig64Extra; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uA.f = a; - uiA64 = uA.s.signExp; - sign = signExtF80UI64( uiA64 ); - exp = expExtF80UI64( uiA64 ); - sig = uA.s.signif; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - shiftDist = 0x403E - exp; - if ( shiftDist <= 0 ) { - /*-------------------------------------------------------------------- - *--------------------------------------------------------------------*/ - if ( shiftDist ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - return - (exp == 0x7FFF) && (sig & UINT64_C( 0x7FFFFFFFFFFFFFFF )) - ? i64_fromNaN - : sign ? i64_fromNegOverflow : i64_fromPosOverflow; - } - /*-------------------------------------------------------------------- - *--------------------------------------------------------------------*/ - sigExtra = 0; - } else { - /*-------------------------------------------------------------------- - *--------------------------------------------------------------------*/ - sig64Extra = softfloat_shiftRightJam64Extra( sig, 0, shiftDist ); - sig = sig64Extra.v; - sigExtra = sig64Extra.extra; - } - return softfloat_roundToI64( sign, sig, sigExtra, roundingMode, exact ); - -} - diff --git a/deps/SoftFloat-3e/source/extF80_to_i64_r_minMag.c b/deps/SoftFloat-3e/source/extF80_to_i64_r_minMag.c deleted file mode 100644 index 8871d01d107e..000000000000 --- a/deps/SoftFloat-3e/source/extF80_to_i64_r_minMag.c +++ /dev/null @@ -1,94 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -int_fast64_t extF80_to_i64_r_minMag( extFloat80_t a, bool exact ) -{ - union { struct extFloat80M s; extFloat80_t f; } uA; - uint_fast16_t uiA64; - int_fast32_t exp; - uint_fast64_t sig; - int_fast32_t shiftDist; - bool sign; - int_fast64_t absZ; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uA.f = a; - uiA64 = uA.s.signExp; - exp = expExtF80UI64( uiA64 ); - sig = uA.s.signif; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - shiftDist = 0x403E - exp; - if ( 64 <= shiftDist ) { - if ( exact && (exp | sig) ) { - softfloat_exceptionFlags |= softfloat_flag_inexact; - } - return 0; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - sign = signExtF80UI64( uiA64 ); - if ( shiftDist <= 0 ) { - if ( - (uiA64 == packToExtF80UI64( 1, 0x403E )) - && (sig == UINT64_C( 0x8000000000000000 )) - ) { - return -INT64_C( 0x7FFFFFFFFFFFFFFF ) - 1; - } - softfloat_raiseFlags( softfloat_flag_invalid ); - return - (exp == 0x7FFF) && (sig & UINT64_C( 0x7FFFFFFFFFFFFFFF )) - ? i64_fromNaN - : sign ? i64_fromNegOverflow : i64_fromPosOverflow; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - absZ = sig>>shiftDist; - if ( exact && (uint64_t) (sig<<(-shiftDist & 63)) ) { - softfloat_exceptionFlags |= softfloat_flag_inexact; - } - return sign ? -absZ : absZ; - -} - diff --git a/deps/SoftFloat-3e/source/extF80_to_ui32.c b/deps/SoftFloat-3e/source/extF80_to_ui32.c deleted file mode 100644 index 581297731d7c..000000000000 --- a/deps/SoftFloat-3e/source/extF80_to_ui32.c +++ /dev/null @@ -1,83 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017 The Regents of the -University of California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -uint_fast32_t - extF80_to_ui32( extFloat80_t a, uint_fast8_t roundingMode, bool exact ) -{ - union { struct extFloat80M s; extFloat80_t f; } uA; - uint_fast16_t uiA64; - bool sign; - int_fast32_t exp; - uint_fast64_t sig; - int_fast32_t shiftDist; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uA.f = a; - uiA64 = uA.s.signExp; - sign = signExtF80UI64( uiA64 ); - exp = expExtF80UI64( uiA64 ); - sig = uA.s.signif; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ -#if (ui32_fromNaN != ui32_fromPosOverflow) || (ui32_fromNaN != ui32_fromNegOverflow) - if ( (exp == 0x7FFF) && (sig & UINT64_C( 0x7FFFFFFFFFFFFFFF )) ) { -#if (ui32_fromNaN == ui32_fromPosOverflow) - sign = 0; -#elif (ui32_fromNaN == ui32_fromNegOverflow) - sign = 1; -#else - softfloat_raiseFlags( softfloat_flag_invalid ); - return ui32_fromNaN; -#endif - } -#endif - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - shiftDist = 0x4032 - exp; - if ( shiftDist <= 0 ) shiftDist = 1; - sig = softfloat_shiftRightJam64( sig, shiftDist ); - return softfloat_roundToUI32( sign, sig, roundingMode, exact ); - -} - diff --git a/deps/SoftFloat-3e/source/extF80_to_ui32_r_minMag.c b/deps/SoftFloat-3e/source/extF80_to_ui32_r_minMag.c deleted file mode 100644 index be2c53b1d20d..000000000000 --- a/deps/SoftFloat-3e/source/extF80_to_ui32_r_minMag.c +++ /dev/null @@ -1,88 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -uint_fast32_t extF80_to_ui32_r_minMag( extFloat80_t a, bool exact ) -{ - union { struct extFloat80M s; extFloat80_t f; } uA; - uint_fast16_t uiA64; - int_fast32_t exp; - uint_fast64_t sig; - int_fast32_t shiftDist; - bool sign; - uint_fast32_t z; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uA.f = a; - uiA64 = uA.s.signExp; - exp = expExtF80UI64( uiA64 ); - sig = uA.s.signif; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - shiftDist = 0x403E - exp; - if ( 64 <= shiftDist ) { - if ( exact && (exp | sig) ) { - softfloat_exceptionFlags |= softfloat_flag_inexact; - } - return 0; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - sign = signExtF80UI64( uiA64 ); - if ( sign || (shiftDist < 32) ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - return - (exp == 0x7FFF) && (sig & UINT64_C( 0x7FFFFFFFFFFFFFFF )) - ? ui32_fromNaN - : sign ? ui32_fromNegOverflow : ui32_fromPosOverflow; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - z = sig>>shiftDist; - if ( exact && ((uint_fast64_t) z< -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -uint_fast64_t - extF80_to_ui64( extFloat80_t a, uint_fast8_t roundingMode, bool exact ) -{ - union { struct extFloat80M s; extFloat80_t f; } uA; - uint_fast16_t uiA64; - bool sign; - int_fast32_t exp; - uint_fast64_t sig; - int_fast32_t shiftDist; - uint_fast64_t sigExtra; - struct uint64_extra sig64Extra; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uA.f = a; - uiA64 = uA.s.signExp; - sign = signExtF80UI64( uiA64 ); - exp = expExtF80UI64( uiA64 ); - sig = uA.s.signif; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - shiftDist = 0x403E - exp; - if ( shiftDist < 0 ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - return - (exp == 0x7FFF) && (sig & UINT64_C( 0x7FFFFFFFFFFFFFFF )) - ? ui64_fromNaN - : sign ? ui64_fromNegOverflow : ui64_fromPosOverflow; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - sigExtra = 0; - if ( shiftDist ) { - sig64Extra = softfloat_shiftRightJam64Extra( sig, 0, shiftDist ); - sig = sig64Extra.v; - sigExtra = sig64Extra.extra; - } - return softfloat_roundToUI64( sign, sig, sigExtra, roundingMode, exact ); - -} - diff --git a/deps/SoftFloat-3e/source/extF80_to_ui64_r_minMag.c b/deps/SoftFloat-3e/source/extF80_to_ui64_r_minMag.c deleted file mode 100644 index eca688c65236..000000000000 --- a/deps/SoftFloat-3e/source/extF80_to_ui64_r_minMag.c +++ /dev/null @@ -1,88 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -uint_fast64_t extF80_to_ui64_r_minMag( extFloat80_t a, bool exact ) -{ - union { struct extFloat80M s; extFloat80_t f; } uA; - uint_fast16_t uiA64; - int_fast32_t exp; - uint_fast64_t sig; - int_fast32_t shiftDist; - bool sign; - uint_fast64_t z; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uA.f = a; - uiA64 = uA.s.signExp; - exp = expExtF80UI64( uiA64 ); - sig = uA.s.signif; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - shiftDist = 0x403E - exp; - if ( 64 <= shiftDist ) { - if ( exact && (exp | sig) ) { - softfloat_exceptionFlags |= softfloat_flag_inexact; - } - return 0; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - sign = signExtF80UI64( uiA64 ); - if ( sign || (shiftDist < 0) ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - return - (exp == 0x7FFF) && (sig & UINT64_C( 0x7FFFFFFFFFFFFFFF )) - ? ui64_fromNaN - : sign ? ui64_fromNegOverflow : ui64_fromPosOverflow; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - z = sig>>shiftDist; - if ( exact && (z< -#include -#include "platform.h" -#include "internals.h" -#include "softfloat.h" - -#ifdef SOFTFLOAT_FAST_INT64 - -void - f128M_add( const float128_t *aPtr, const float128_t *bPtr, float128_t *zPtr ) -{ - const uint64_t *aWPtr, *bWPtr; - uint_fast64_t uiA64, uiA0; - bool signA; - uint_fast64_t uiB64, uiB0; - bool signB; -#if ! defined INLINE_LEVEL || (INLINE_LEVEL < 2) - float128_t - (*magsFuncPtr)( - uint_fast64_t, uint_fast64_t, uint_fast64_t, uint_fast64_t, bool ); -#endif - - aWPtr = (const uint64_t *) aPtr; - bWPtr = (const uint64_t *) bPtr; - uiA64 = aWPtr[indexWord( 2, 1 )]; - uiA0 = aWPtr[indexWord( 2, 0 )]; - signA = signF128UI64( uiA64 ); - uiB64 = bWPtr[indexWord( 2, 1 )]; - uiB0 = bWPtr[indexWord( 2, 0 )]; - signB = signF128UI64( uiB64 ); -#if defined INLINE_LEVEL && (2 <= INLINE_LEVEL) - if ( signA == signB ) { - *zPtr = softfloat_addMagsF128( uiA64, uiA0, uiB64, uiB0, signA ); - } else { - *zPtr = softfloat_subMagsF128( uiA64, uiA0, uiB64, uiB0, signA ); - } -#else - magsFuncPtr = - (signA == signB) ? softfloat_addMagsF128 : softfloat_subMagsF128; - *zPtr = (*magsFuncPtr)( uiA64, uiA0, uiB64, uiB0, signA ); -#endif - -} - -#else - -void - f128M_add( const float128_t *aPtr, const float128_t *bPtr, float128_t *zPtr ) -{ - - softfloat_addF128M( - (const uint32_t *) aPtr, - (const uint32_t *) bPtr, - (uint32_t *) zPtr, - false - ); - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/f128M_div.c b/deps/SoftFloat-3e/source/f128M_div.c deleted file mode 100644 index b443548f5286..000000000000 --- a/deps/SoftFloat-3e/source/f128M_div.c +++ /dev/null @@ -1,187 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -#ifdef SOFTFLOAT_FAST_INT64 - -void - f128M_div( const float128_t *aPtr, const float128_t *bPtr, float128_t *zPtr ) -{ - - *zPtr = f128_div( *aPtr, *bPtr ); - -} - -#else - -void - f128M_div( const float128_t *aPtr, const float128_t *bPtr, float128_t *zPtr ) -{ - const uint32_t *aWPtr, *bWPtr; - uint32_t *zWPtr, uiA96; - bool signA; - int32_t expA; - uint32_t uiB96; - bool signB; - int32_t expB; - bool signZ; - uint32_t y[5], sigB[4]; - int32_t expZ; - uint32_t recip32; - int ix; - uint64_t q64; - uint32_t q, qs[3], uiZ96; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - aWPtr = (const uint32_t *) aPtr; - bWPtr = (const uint32_t *) bPtr; - zWPtr = (uint32_t *) zPtr; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uiA96 = aWPtr[indexWordHi( 4 )]; - signA = signF128UI96( uiA96 ); - expA = expF128UI96( uiA96 ); - uiB96 = bWPtr[indexWordHi( 4 )]; - signB = signF128UI96( uiB96 ); - expB = expF128UI96( uiB96 ); - signZ = signA ^ signB; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( (expA == 0x7FFF) || (expB == 0x7FFF) ) { - if ( softfloat_tryPropagateNaNF128M( aWPtr, bWPtr, zWPtr ) ) return; - if ( expA == 0x7FFF ) { - if ( expB == 0x7FFF ) goto invalid; - goto infinity; - } - goto zero; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - expA = softfloat_shiftNormSigF128M( aWPtr, 13, y ); - expB = softfloat_shiftNormSigF128M( bWPtr, 13, sigB ); - if ( expA == -128 ) { - if ( expB == -128 ) goto invalid; - goto zero; - } - if ( expB == -128 ) { - softfloat_raiseFlags( softfloat_flag_infinite ); - goto infinity; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - expZ = expA - expB + 0x3FFE; - if ( softfloat_compare128M( y, sigB ) < 0 ) { - --expZ; - softfloat_add128M( y, y, y ); - } - recip32 = - softfloat_approxRecip32_1( - ((uint64_t) sigB[indexWord( 4, 3 )]<<32 | sigB[indexWord( 4, 2 )]) - >>30 - ); - ix = 3; - for (;;) { - q64 = (uint64_t) y[indexWordHi( 4 )] * recip32; - q = (q64 + 0x80000000)>>32; - --ix; - if ( ix < 0 ) break; - softfloat_remStep128MBy32( y, 29, sigB, q, y ); - if ( y[indexWordHi( 4 )] & 0x80000000 ) { - --q; - softfloat_add128M( y, sigB, y ); - } - qs[ix] = q; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( ((q + 1) & 7) < 2 ) { - softfloat_remStep128MBy32( y, 29, sigB, q, y ); - if ( y[indexWordHi( 4 )] & 0x80000000 ) { - --q; - softfloat_add128M( y, sigB, y ); - } else if ( softfloat_compare128M( sigB, y ) <= 0 ) { - ++q; - softfloat_sub128M( y, sigB, y ); - } - if ( - y[indexWordLo( 4 )] || y[indexWord( 4, 1 )] - || (y[indexWord( 4, 2 )] | y[indexWord( 4, 3 )]) - ) { - q |= 1; - } - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - q64 = (uint64_t) q<<28; - y[indexWord( 5, 0 )] = q64; - q64 = ((uint64_t) qs[0]<<25) + (q64>>32); - y[indexWord( 5, 1 )] = q64; - q64 = ((uint64_t) qs[1]<<22) + (q64>>32); - y[indexWord( 5, 2 )] = q64; - q64 = ((uint64_t) qs[2]<<19) + (q64>>32); - y[indexWord( 5, 3 )] = q64; - y[indexWord( 5, 4 )] = q64>>32; - softfloat_roundPackMToF128M( signZ, expZ, y, zWPtr ); - return; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - invalid: - softfloat_invalidF128M( zWPtr ); - return; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - infinity: - uiZ96 = packToF128UI96( signZ, 0x7FFF, 0 ); - goto uiZ96; - zero: - uiZ96 = packToF128UI96( signZ, 0, 0 ); - uiZ96: - zWPtr[indexWordHi( 4 )] = uiZ96; - zWPtr[indexWord( 4, 2 )] = 0; - zWPtr[indexWord( 4, 1 )] = 0; - zWPtr[indexWord( 4, 0 )] = 0; - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/f128M_eq.c b/deps/SoftFloat-3e/source/f128M_eq.c deleted file mode 100644 index 497fdbf6f037..000000000000 --- a/deps/SoftFloat-3e/source/f128M_eq.c +++ /dev/null @@ -1,100 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -#ifdef SOFTFLOAT_FAST_INT64 - -bool f128M_eq( const float128_t *aPtr, const float128_t *bPtr ) -{ - - return f128_eq( *aPtr, *bPtr ); - -} - -#else - -bool f128M_eq( const float128_t *aPtr, const float128_t *bPtr ) -{ - const uint32_t *aWPtr, *bWPtr; - uint32_t wordA, wordB, uiA96, uiB96; - bool possibleOppositeZeros; - uint32_t mashWord; - - aWPtr = (const uint32_t *) aPtr; - bWPtr = (const uint32_t *) bPtr; - wordA = aWPtr[indexWord( 4, 2 )]; - wordB = bWPtr[indexWord( 4, 2 )]; - if ( wordA != wordB ) goto false_checkSigNaNs; - uiA96 = aWPtr[indexWordHi( 4 )]; - uiB96 = bWPtr[indexWordHi( 4 )]; - possibleOppositeZeros = false; - if ( uiA96 != uiB96 ) { - possibleOppositeZeros = (((uiA96 | uiB96) & 0x7FFFFFFF) == 0); - if ( ! possibleOppositeZeros ) goto false_checkSigNaNs; - } - mashWord = wordA | wordB; - wordA = aWPtr[indexWord( 4, 1 )]; - wordB = bWPtr[indexWord( 4, 1 )]; - if ( wordA != wordB ) goto false_checkSigNaNs; - mashWord |= wordA | wordB; - wordA = aWPtr[indexWord( 4, 0 )]; - wordB = bWPtr[indexWord( 4, 0 )]; - if ( wordA != wordB ) goto false_checkSigNaNs; - if ( possibleOppositeZeros && ((mashWord | wordA | wordB) != 0) ) { - goto false_checkSigNaNs; - } - if ( ! softfloat_isNaNF128M( aWPtr ) && ! softfloat_isNaNF128M( bWPtr ) ) { - return true; - } - false_checkSigNaNs: - if ( - f128M_isSignalingNaN( (const float128_t *) aWPtr ) - || f128M_isSignalingNaN( (const float128_t *) bWPtr ) - ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - } - return false; - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/f128M_eq_signaling.c b/deps/SoftFloat-3e/source/f128M_eq_signaling.c deleted file mode 100644 index a9fa4d5101fb..000000000000 --- a/deps/SoftFloat-3e/source/f128M_eq_signaling.c +++ /dev/null @@ -1,92 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -#ifdef SOFTFLOAT_FAST_INT64 - -bool f128M_eq_signaling( const float128_t *aPtr, const float128_t *bPtr ) -{ - - return f128_eq_signaling( *aPtr, *bPtr ); - -} - -#else - -bool f128M_eq_signaling( const float128_t *aPtr, const float128_t *bPtr ) -{ - const uint32_t *aWPtr, *bWPtr; - uint32_t wordA, wordB, uiA96, uiB96; - bool possibleOppositeZeros; - uint32_t mashWord; - - aWPtr = (const uint32_t *) aPtr; - bWPtr = (const uint32_t *) bPtr; - if ( softfloat_isNaNF128M( aWPtr ) || softfloat_isNaNF128M( bWPtr ) ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - return false; - } - wordA = aWPtr[indexWord( 4, 2 )]; - wordB = bWPtr[indexWord( 4, 2 )]; - if ( wordA != wordB ) return false; - uiA96 = aWPtr[indexWordHi( 4 )]; - uiB96 = bWPtr[indexWordHi( 4 )]; - possibleOppositeZeros = false; - if ( uiA96 != uiB96 ) { - possibleOppositeZeros = (((uiA96 | uiB96) & 0x7FFFFFFF) == 0); - if ( ! possibleOppositeZeros ) return false; - } - mashWord = wordA | wordB; - wordA = aWPtr[indexWord( 4, 1 )]; - wordB = bWPtr[indexWord( 4, 1 )]; - if ( wordA != wordB ) return false; - mashWord |= wordA | wordB; - wordA = aWPtr[indexWord( 4, 0 )]; - wordB = bWPtr[indexWord( 4, 0 )]; - return - (wordA == wordB) - && (! possibleOppositeZeros || ((mashWord | wordA | wordB) == 0)); - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/f128M_le.c b/deps/SoftFloat-3e/source/f128M_le.c deleted file mode 100644 index 7306e45c363c..000000000000 --- a/deps/SoftFloat-3e/source/f128M_le.c +++ /dev/null @@ -1,93 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "softfloat.h" - -#ifdef SOFTFLOAT_FAST_INT64 - -bool f128M_le( const float128_t *aPtr, const float128_t *bPtr ) -{ - - return f128_le( *aPtr, *bPtr ); - -} - -#else - -bool f128M_le( const float128_t *aPtr, const float128_t *bPtr ) -{ - const uint32_t *aWPtr, *bWPtr; - uint32_t uiA96, uiB96; - bool signA, signB; - uint32_t wordA, wordB; - - aWPtr = (const uint32_t *) aPtr; - bWPtr = (const uint32_t *) bPtr; - if ( softfloat_isNaNF128M( aWPtr ) || softfloat_isNaNF128M( bWPtr ) ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - return false; - } - uiA96 = aWPtr[indexWordHi( 4 )]; - uiB96 = bWPtr[indexWordHi( 4 )]; - signA = signF128UI96( uiA96 ); - signB = signF128UI96( uiB96 ); - if ( signA != signB ) { - if ( signA ) return true; - if ( (uiA96 | uiB96) & 0x7FFFFFFF ) return false; - wordA = aWPtr[indexWord( 4, 2 )]; - wordB = bWPtr[indexWord( 4, 2 )]; - if ( wordA | wordB ) return false; - wordA = aWPtr[indexWord( 4, 1 )]; - wordB = bWPtr[indexWord( 4, 1 )]; - if ( wordA | wordB ) return false; - wordA = aWPtr[indexWord( 4, 0 )]; - wordB = bWPtr[indexWord( 4, 0 )]; - return ((wordA | wordB) == 0); - } - if ( signA ) { - aWPtr = (const uint32_t *) bPtr; - bWPtr = (const uint32_t *) aPtr; - } - return (softfloat_compare128M( aWPtr, bWPtr ) <= 0); - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/f128M_le_quiet.c b/deps/SoftFloat-3e/source/f128M_le_quiet.c deleted file mode 100644 index d9e442942d62..000000000000 --- a/deps/SoftFloat-3e/source/f128M_le_quiet.c +++ /dev/null @@ -1,96 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -#ifdef SOFTFLOAT_FAST_INT64 - -bool f128M_le_quiet( const float128_t *aPtr, const float128_t *bPtr ) -{ - - return f128_le_quiet( *aPtr, *bPtr ); - -} - -#else - -bool f128M_le_quiet( const float128_t *aPtr, const float128_t *bPtr ) -{ - const uint32_t *aWPtr, *bWPtr; - uint32_t uiA96, uiB96; - bool signA, signB; - uint32_t wordA, wordB; - - aWPtr = (const uint32_t *) aPtr; - bWPtr = (const uint32_t *) bPtr; - if ( softfloat_isNaNF128M( aWPtr ) || softfloat_isNaNF128M( bWPtr ) ) { - if ( f128M_isSignalingNaN( aPtr ) || f128M_isSignalingNaN( bPtr ) ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - } - return false; - } - uiA96 = aWPtr[indexWordHi( 4 )]; - uiB96 = bWPtr[indexWordHi( 4 )]; - signA = signF128UI96( uiA96 ); - signB = signF128UI96( uiB96 ); - if ( signA != signB ) { - if ( signA ) return true; - if ( (uiA96 | uiB96) & 0x7FFFFFFF ) return false; - wordA = aWPtr[indexWord( 4, 2 )]; - wordB = bWPtr[indexWord( 4, 2 )]; - if ( wordA | wordB ) return false; - wordA = aWPtr[indexWord( 4, 1 )]; - wordB = bWPtr[indexWord( 4, 1 )]; - if ( wordA | wordB ) return false; - wordA = aWPtr[indexWord( 4, 0 )]; - wordB = bWPtr[indexWord( 4, 0 )]; - return ((wordA | wordB) == 0); - } - if ( signA ) { - aWPtr = (const uint32_t *) bPtr; - bWPtr = (const uint32_t *) aPtr; - } - return (softfloat_compare128M( aWPtr, bWPtr ) <= 0); - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/f128M_lt.c b/deps/SoftFloat-3e/source/f128M_lt.c deleted file mode 100644 index d2f797feaff3..000000000000 --- a/deps/SoftFloat-3e/source/f128M_lt.c +++ /dev/null @@ -1,93 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "softfloat.h" - -#ifdef SOFTFLOAT_FAST_INT64 - -bool f128M_lt( const float128_t *aPtr, const float128_t *bPtr ) -{ - - return f128_lt( *aPtr, *bPtr ); - -} - -#else - -bool f128M_lt( const float128_t *aPtr, const float128_t *bPtr ) -{ - const uint32_t *aWPtr, *bWPtr; - uint32_t uiA96, uiB96; - bool signA, signB; - uint32_t wordA, wordB; - - aWPtr = (const uint32_t *) aPtr; - bWPtr = (const uint32_t *) bPtr; - if ( softfloat_isNaNF128M( aWPtr ) || softfloat_isNaNF128M( bWPtr ) ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - return false; - } - uiA96 = aWPtr[indexWordHi( 4 )]; - uiB96 = bWPtr[indexWordHi( 4 )]; - signA = signF128UI96( uiA96 ); - signB = signF128UI96( uiB96 ); - if ( signA != signB ) { - if ( signB ) return false; - if ( (uiA96 | uiB96) & 0x7FFFFFFF ) return true; - wordA = aWPtr[indexWord( 4, 2 )]; - wordB = bWPtr[indexWord( 4, 2 )]; - if ( wordA | wordB ) return true; - wordA = aWPtr[indexWord( 4, 1 )]; - wordB = bWPtr[indexWord( 4, 1 )]; - if ( wordA | wordB ) return true; - wordA = aWPtr[indexWord( 4, 0 )]; - wordB = bWPtr[indexWord( 4, 0 )]; - return ((wordA | wordB) != 0); - } - if ( signA ) { - aWPtr = (const uint32_t *) bPtr; - bWPtr = (const uint32_t *) aPtr; - } - return (softfloat_compare128M( aWPtr, bWPtr ) < 0); - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/f128M_lt_quiet.c b/deps/SoftFloat-3e/source/f128M_lt_quiet.c deleted file mode 100644 index adbddea71caf..000000000000 --- a/deps/SoftFloat-3e/source/f128M_lt_quiet.c +++ /dev/null @@ -1,96 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -#ifdef SOFTFLOAT_FAST_INT64 - -bool f128M_lt_quiet( const float128_t *aPtr, const float128_t *bPtr ) -{ - - return f128_lt_quiet( *aPtr, *bPtr ); - -} - -#else - -bool f128M_lt_quiet( const float128_t *aPtr, const float128_t *bPtr ) -{ - const uint32_t *aWPtr, *bWPtr; - uint32_t uiA96, uiB96; - bool signA, signB; - uint32_t wordA, wordB; - - aWPtr = (const uint32_t *) aPtr; - bWPtr = (const uint32_t *) bPtr; - if ( softfloat_isNaNF128M( aWPtr ) || softfloat_isNaNF128M( bWPtr ) ) { - if ( f128M_isSignalingNaN( aPtr ) || f128M_isSignalingNaN( bPtr ) ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - } - return false; - } - uiA96 = aWPtr[indexWordHi( 4 )]; - uiB96 = bWPtr[indexWordHi( 4 )]; - signA = signF128UI96( uiA96 ); - signB = signF128UI96( uiB96 ); - if ( signA != signB ) { - if ( signB ) return false; - if ( (uiA96 | uiB96) & 0x7FFFFFFF ) return true; - wordA = aWPtr[indexWord( 4, 2 )]; - wordB = bWPtr[indexWord( 4, 2 )]; - if ( wordA | wordB ) return true; - wordA = aWPtr[indexWord( 4, 1 )]; - wordB = bWPtr[indexWord( 4, 1 )]; - if ( wordA | wordB ) return true; - wordA = aWPtr[indexWord( 4, 0 )]; - wordB = bWPtr[indexWord( 4, 0 )]; - return ((wordA | wordB) != 0); - } - if ( signA ) { - aWPtr = (const uint32_t *) bPtr; - bWPtr = (const uint32_t *) aPtr; - } - return (softfloat_compare128M( aWPtr, bWPtr ) < 0); - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/f128M_mul.c b/deps/SoftFloat-3e/source/f128M_mul.c deleted file mode 100644 index 4b8292a27a72..000000000000 --- a/deps/SoftFloat-3e/source/f128M_mul.c +++ /dev/null @@ -1,158 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -#ifdef SOFTFLOAT_FAST_INT64 - -void - f128M_mul( const float128_t *aPtr, const float128_t *bPtr, float128_t *zPtr ) -{ - - *zPtr = f128_mul( *aPtr, *bPtr ); - -} - -#else - -void - f128M_mul( const float128_t *aPtr, const float128_t *bPtr, float128_t *zPtr ) -{ - const uint32_t *aWPtr, *bWPtr; - uint32_t *zWPtr; - uint32_t uiA96; - int32_t expA; - uint32_t uiB96; - int32_t expB; - bool signZ; - const uint32_t *ptr; - uint32_t uiZ96, sigA[4]; - uint_fast8_t shiftDist; - uint32_t sigB[4]; - int32_t expZ; - uint32_t sigProd[8], *extSigZPtr; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - aWPtr = (const uint32_t *) aPtr; - bWPtr = (const uint32_t *) bPtr; - zWPtr = (uint32_t *) zPtr; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uiA96 = aWPtr[indexWordHi( 4 )]; - expA = expF128UI96( uiA96 ); - uiB96 = bWPtr[indexWordHi( 4 )]; - expB = expF128UI96( uiB96 ); - signZ = signF128UI96( uiA96 ) ^ signF128UI96( uiB96 ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( (expA == 0x7FFF) || (expB == 0x7FFF) ) { - if ( softfloat_tryPropagateNaNF128M( aWPtr, bWPtr, zWPtr ) ) return; - ptr = aWPtr; - if ( ! expA ) goto possiblyInvalid; - if ( ! expB ) { - ptr = bWPtr; - possiblyInvalid: - if ( - ! fracF128UI96( ptr[indexWordHi( 4 )] ) - && ! (ptr[indexWord( 4, 2 )] | ptr[indexWord( 4, 1 )] - | ptr[indexWord( 4, 0 )]) - ) { - softfloat_invalidF128M( zWPtr ); - return; - } - } - uiZ96 = packToF128UI96( signZ, 0x7FFF, 0 ); - goto uiZ96; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( expA ) { - sigA[indexWordHi( 4 )] = fracF128UI96( uiA96 ) | 0x00010000; - sigA[indexWord( 4, 2 )] = aWPtr[indexWord( 4, 2 )]; - sigA[indexWord( 4, 1 )] = aWPtr[indexWord( 4, 1 )]; - sigA[indexWord( 4, 0 )] = aWPtr[indexWord( 4, 0 )]; - } else { - expA = softfloat_shiftNormSigF128M( aWPtr, 0, sigA ); - if ( expA == -128 ) goto zero; - } - if ( expB ) { - sigB[indexWordHi( 4 )] = fracF128UI96( uiB96 ) | 0x00010000; - sigB[indexWord( 4, 2 )] = bWPtr[indexWord( 4, 2 )]; - sigB[indexWord( 4, 1 )] = bWPtr[indexWord( 4, 1 )]; - sigB[indexWord( 4, 0 )] = bWPtr[indexWord( 4, 0 )]; - } else { - expB = softfloat_shiftNormSigF128M( bWPtr, 0, sigB ); - if ( expB == -128 ) goto zero; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - expZ = expA + expB - 0x4000; - softfloat_mul128MTo256M( sigA, sigB, sigProd ); - if ( - sigProd[indexWord( 8, 2 )] - || (sigProd[indexWord( 8, 1 )] | sigProd[indexWord( 8, 0 )]) - ) { - sigProd[indexWord( 8, 3 )] |= 1; - } - extSigZPtr = &sigProd[indexMultiwordHi( 8, 5 )]; - shiftDist = 16; - if ( extSigZPtr[indexWordHi( 5 )] & 2 ) { - ++expZ; - shiftDist = 15; - } - softfloat_shortShiftLeft160M( extSigZPtr, shiftDist, extSigZPtr ); - softfloat_roundPackMToF128M( signZ, expZ, extSigZPtr, zWPtr ); - return; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - zero: - uiZ96 = packToF128UI96( signZ, 0, 0 ); - uiZ96: - zWPtr[indexWordHi( 4 )] = uiZ96; - zWPtr[indexWord( 4, 2 )] = 0; - zWPtr[indexWord( 4, 1 )] = 0; - zWPtr[indexWord( 4, 0 )] = 0; - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/f128M_mulAdd.c b/deps/SoftFloat-3e/source/f128M_mulAdd.c deleted file mode 100644 index 2b0b7fe26e69..000000000000 --- a/deps/SoftFloat-3e/source/f128M_mulAdd.c +++ /dev/null @@ -1,92 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "internals.h" -#include "softfloat.h" - -#ifdef SOFTFLOAT_FAST_INT64 - -void - f128M_mulAdd( - const float128_t *aPtr, - const float128_t *bPtr, - const float128_t *cPtr, - float128_t *zPtr - ) -{ - const uint64_t *aWPtr, *bWPtr, *cWPtr; - uint_fast64_t uiA64, uiA0; - uint_fast64_t uiB64, uiB0; - uint_fast64_t uiC64, uiC0; - - aWPtr = (const uint64_t *) aPtr; - bWPtr = (const uint64_t *) bPtr; - cWPtr = (const uint64_t *) cPtr; - uiA64 = aWPtr[indexWord( 2, 1 )]; - uiA0 = aWPtr[indexWord( 2, 0 )]; - uiB64 = bWPtr[indexWord( 2, 1 )]; - uiB0 = bWPtr[indexWord( 2, 0 )]; - uiC64 = cWPtr[indexWord( 2, 1 )]; - uiC0 = cWPtr[indexWord( 2, 0 )]; - *zPtr = softfloat_mulAddF128( uiA64, uiA0, uiB64, uiB0, uiC64, uiC0, 0 ); - -} - -#else - -void - f128M_mulAdd( - const float128_t *aPtr, - const float128_t *bPtr, - const float128_t *cPtr, - float128_t *zPtr - ) -{ - - softfloat_mulAddF128M( - (const uint32_t *) aPtr, - (const uint32_t *) bPtr, - (const uint32_t *) cPtr, - (uint32_t *) zPtr, - 0 - ); - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/f128M_rem.c b/deps/SoftFloat-3e/source/f128M_rem.c deleted file mode 100644 index 39aafdd6ad5c..000000000000 --- a/deps/SoftFloat-3e/source/f128M_rem.c +++ /dev/null @@ -1,182 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -#ifdef SOFTFLOAT_FAST_INT64 - -void - f128M_rem( const float128_t *aPtr, const float128_t *bPtr, float128_t *zPtr ) -{ - - *zPtr = f128_rem( *aPtr, *bPtr ); - -} - -#else - -void - f128M_rem( const float128_t *aPtr, const float128_t *bPtr, float128_t *zPtr ) -{ - const uint32_t *aWPtr, *bWPtr; - uint32_t *zWPtr, uiA96; - int32_t expA, expB; - uint32_t x[4], rem1[5], *remPtr; - bool signRem; - int32_t expDiff; - uint32_t q, recip32; - uint64_t q64; - uint32_t rem2[5], *altRemPtr, *newRemPtr, wordMeanRem; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - aWPtr = (const uint32_t *) aPtr; - bWPtr = (const uint32_t *) bPtr; - zWPtr = (uint32_t *) zPtr; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uiA96 = aWPtr[indexWordHi( 4 )]; - expA = expF128UI96( uiA96 ); - expB = expF128UI96( bWPtr[indexWordHi( 4 )] ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( (expA == 0x7FFF) || (expB == 0x7FFF) ) { - if ( softfloat_tryPropagateNaNF128M( aWPtr, bWPtr, zWPtr ) ) return; - if ( expA == 0x7FFF ) goto invalid; - goto copyA; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( expA < expB - 1 ) goto copyA; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - expB = softfloat_shiftNormSigF128M( bWPtr, 13, x ); - if ( expB == -128 ) goto invalid; - remPtr = &rem1[indexMultiwordLo( 5, 4 )]; - expA = softfloat_shiftNormSigF128M( aWPtr, 13, remPtr ); - if ( expA == -128 ) goto copyA; - signRem = signF128UI96( uiA96 ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - expDiff = expA - expB; - if ( expDiff < 1 ) { - if ( expDiff < -1 ) goto copyA; - if ( expDiff ) { - --expB; - softfloat_add128M( x, x, x ); - q = 0; - } else { - q = (softfloat_compare128M( x, remPtr ) <= 0); - if ( q ) softfloat_sub128M( remPtr, x, remPtr ); - } - } else { - recip32 = - softfloat_approxRecip32_1( - ((uint64_t) x[indexWord( 4, 3 )]<<32 | x[indexWord( 4, 2 )]) - >>30 - ); - expDiff -= 30; - for (;;) { - q64 = (uint64_t) remPtr[indexWordHi( 4 )] * recip32; - if ( expDiff < 0 ) break; - q = (q64 + 0x80000000)>>32; - softfloat_remStep128MBy32( remPtr, 29, x, q, remPtr ); - if ( remPtr[indexWordHi( 4 )] & 0x80000000 ) { - softfloat_add128M( remPtr, x, remPtr ); - } - expDiff -= 29; - } - /*-------------------------------------------------------------------- - | (`expDiff' cannot be less than -29 here.) - *--------------------------------------------------------------------*/ - q = (uint32_t) (q64>>32)>>(~expDiff & 31); - softfloat_remStep128MBy32( remPtr, expDiff + 30, x, q, remPtr ); - if ( remPtr[indexWordHi( 4 )] & 0x80000000 ) { - altRemPtr = &rem2[indexMultiwordLo( 5, 4 )]; - softfloat_add128M( remPtr, x, altRemPtr ); - goto selectRem; - } - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - altRemPtr = &rem2[indexMultiwordLo( 5, 4 )]; - do { - ++q; - newRemPtr = altRemPtr; - softfloat_sub128M( remPtr, x, newRemPtr ); - altRemPtr = remPtr; - remPtr = newRemPtr; - } while ( ! (remPtr[indexWordHi( 4 )] & 0x80000000) ); - selectRem: - softfloat_add128M( remPtr, altRemPtr, x ); - wordMeanRem = x[indexWordHi( 4 )]; - if ( - (wordMeanRem & 0x80000000) - || (! wordMeanRem && (q & 1) && ! x[indexWord( 4, 0 )] - && ! (x[indexWord( 4, 2 )] | x[indexWord( 4, 1 )])) - ) { - remPtr = altRemPtr; - } - if ( remPtr[indexWordHi( 4 )] & 0x80000000 ) { - signRem = ! signRem; - softfloat_negX128M( remPtr ); - } - remPtr -= indexMultiwordLo( 5, 4 ); - remPtr[indexWordHi( 5 )] = 0; - softfloat_normRoundPackMToF128M( signRem, expB + 18, remPtr, zWPtr ); - return; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - invalid: - softfloat_invalidF128M( zWPtr ); - return; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - copyA: - zWPtr[indexWordHi( 4 )] = uiA96; - zWPtr[indexWord( 4, 2 )] = aWPtr[indexWord( 4, 2 )]; - zWPtr[indexWord( 4, 1 )] = aWPtr[indexWord( 4, 1 )]; - zWPtr[indexWord( 4, 0 )] = aWPtr[indexWord( 4, 0 )]; - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/f128M_roundToInt.c b/deps/SoftFloat-3e/source/f128M_roundToInt.c deleted file mode 100644 index b96d742b214b..000000000000 --- a/deps/SoftFloat-3e/source/f128M_roundToInt.c +++ /dev/null @@ -1,223 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2017 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -#ifdef SOFTFLOAT_FAST_INT64 - -void - f128M_roundToInt( - const float128_t *aPtr, - uint_fast8_t roundingMode, - bool exact, - float128_t *zPtr - ) -{ - - *zPtr = f128_roundToInt( *aPtr, roundingMode, exact ); - -} - -#else - -void - f128M_roundToInt( - const float128_t *aPtr, - uint_fast8_t roundingMode, - bool exact, - float128_t *zPtr - ) -{ - const uint32_t *aWPtr; - uint32_t *zWPtr; - uint32_t ui96; - int32_t exp; - uint32_t sigExtra; - bool sign; - uint_fast8_t bitPos; - bool roundNear; - unsigned int index, lastIndex; - bool extra; - uint32_t wordA, bit, wordZ; - uint_fast8_t carry; - uint32_t extrasMask; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - aWPtr = (const uint32_t *) aPtr; - zWPtr = (uint32_t *) zPtr; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - ui96 = aWPtr[indexWordHi( 4 )]; - exp = expF128UI96( ui96 ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( exp < 0x3FFF ) { - zWPtr[indexWord( 4, 2 )] = 0; - zWPtr[indexWord( 4, 1 )] = 0; - zWPtr[indexWord( 4, 0 )] = 0; - sigExtra = aWPtr[indexWord( 4, 2 )]; - if ( !sigExtra ) { - sigExtra = aWPtr[indexWord( 4, 1 )] | aWPtr[indexWord( 4, 0 )]; - } - if ( !sigExtra && !(ui96 & 0x7FFFFFFF) ) goto ui96; - if ( exact ) softfloat_exceptionFlags |= softfloat_flag_inexact; - sign = signF128UI96( ui96 ); - switch ( roundingMode ) { - case softfloat_round_near_even: - if ( !fracF128UI96( ui96 ) && !sigExtra ) break; - case softfloat_round_near_maxMag: - if ( exp == 0x3FFE ) goto mag1; - break; - case softfloat_round_min: - if ( sign ) goto mag1; - break; - case softfloat_round_max: - if ( !sign ) goto mag1; - break; -#ifdef SOFTFLOAT_ROUND_ODD - case softfloat_round_odd: - goto mag1; -#endif - } - ui96 = packToF128UI96( sign, 0, 0 ); - goto ui96; - mag1: - ui96 = packToF128UI96( sign, 0x3FFF, 0 ); - goto ui96; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( 0x406F <= exp ) { - if ( - (exp == 0x7FFF) - && (fracF128UI96( ui96 ) - || (aWPtr[indexWord( 4, 2 )] | aWPtr[indexWord( 4, 1 )] - | aWPtr[indexWord( 4, 0 )])) - ) { - softfloat_propagateNaNF128M( aWPtr, 0, zWPtr ); - return; - } - zWPtr[indexWord( 4, 2 )] = aWPtr[indexWord( 4, 2 )]; - zWPtr[indexWord( 4, 1 )] = aWPtr[indexWord( 4, 1 )]; - zWPtr[indexWord( 4, 0 )] = aWPtr[indexWord( 4, 0 )]; - goto ui96; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - bitPos = 0x406F - exp; - roundNear = - (roundingMode == softfloat_round_near_maxMag) - || (roundingMode == softfloat_round_near_even); - bitPos -= roundNear; - index = indexWordLo( 4 ); - lastIndex = indexWordHi( 4 ); - extra = 0; - for (;;) { - wordA = aWPtr[index]; - if ( bitPos < 32 ) break; - if ( wordA ) extra = 1; - zWPtr[index] = 0; - index += wordIncr; - bitPos -= 32; - } - bit = (uint32_t) 1< -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -#ifdef SOFTFLOAT_FAST_INT64 - -void f128M_sqrt( const float128_t *aPtr, float128_t *zPtr ) -{ - - *zPtr = f128_sqrt( *aPtr ); - -} - -#else - -void f128M_sqrt( const float128_t *aPtr, float128_t *zPtr ) -{ - const uint32_t *aWPtr; - uint32_t *zWPtr; - uint32_t uiA96; - bool signA; - int32_t rawExpA; - uint32_t rem[6]; - int32_t expA, expZ; - uint64_t rem64; - uint32_t sig32A, recipSqrt32, sig32Z, qs[3], q; - uint64_t sig64Z; - uint32_t term[5]; - uint64_t x64; - uint32_t y[5], rem32; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - aWPtr = (const uint32_t *) aPtr; - zWPtr = (uint32_t *) zPtr; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uiA96 = aWPtr[indexWordHi( 4 )]; - signA = signF128UI96( uiA96 ); - rawExpA = expF128UI96( uiA96 ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( rawExpA == 0x7FFF ) { - if ( - fracF128UI96( uiA96 ) - || (aWPtr[indexWord( 4, 2 )] | aWPtr[indexWord( 4, 1 )] - | aWPtr[indexWord( 4, 0 )]) - ) { - softfloat_propagateNaNF128M( aWPtr, 0, zWPtr ); - return; - } - if ( ! signA ) goto copyA; - goto invalid; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - expA = softfloat_shiftNormSigF128M( aWPtr, 13 - (rawExpA & 1), rem ); - if ( expA == -128 ) goto copyA; - if ( signA ) goto invalid; - /*------------------------------------------------------------------------ - | (`sig32Z' is guaranteed to be a lower bound on the square root of - | `sig32A', which makes `sig32Z' also a lower bound on the square root of - | `sigA'.) - *------------------------------------------------------------------------*/ - expZ = ((expA - 0x3FFF)>>1) + 0x3FFE; - expA &= 1; - rem64 = (uint64_t) rem[indexWord( 4, 3 )]<<32 | rem[indexWord( 4, 2 )]; - if ( expA ) { - if ( ! rawExpA ) { - softfloat_shortShiftRight128M( rem, 1, rem ); - rem64 >>= 1; - } - sig32A = rem64>>29; - } else { - sig32A = rem64>>30; - } - recipSqrt32 = softfloat_approxRecipSqrt32_1( expA, sig32A ); - sig32Z = ((uint64_t) sig32A * recipSqrt32)>>32; - if ( expA ) sig32Z >>= 1; - qs[2] = sig32Z; - rem64 -= (uint64_t) sig32Z * sig32Z; - rem[indexWord( 4, 3 )] = rem64>>32; - rem[indexWord( 4, 2 )] = rem64; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - q = ((uint32_t) (rem64>>2) * (uint64_t) recipSqrt32)>>32; - sig64Z = ((uint64_t) sig32Z<<32) + ((uint64_t) q<<3); - term[indexWord( 4, 3 )] = 0; - term[indexWord( 4, 0 )] = 0; - /*------------------------------------------------------------------------ - | (Repeating this loop is a rare occurrence.) - *------------------------------------------------------------------------*/ - for (;;) { - x64 = ((uint64_t) sig32Z<<32) + sig64Z; - term[indexWord( 4, 2 )] = x64>>32; - term[indexWord( 4, 1 )] = x64; - softfloat_remStep128MBy32( rem, 29, term, q, y ); - rem32 = y[indexWord( 4, 3 )]; - if ( ! (rem32 & 0x80000000) ) break; - --q; - sig64Z -= 1<<3; - } - qs[1] = q; - rem64 = (uint64_t) rem32<<32 | y[indexWord( 4, 2 )]; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - q = ((uint32_t) (rem64>>2) * (uint64_t) recipSqrt32)>>32; - if ( rem64>>34 ) q += recipSqrt32; - sig64Z <<= 1; - /*------------------------------------------------------------------------ - | (Repeating this loop is a rare occurrence.) - *------------------------------------------------------------------------*/ - for (;;) { - x64 = sig64Z + (q>>26); - term[indexWord( 4, 2 )] = x64>>32; - term[indexWord( 4, 1 )] = x64; - term[indexWord( 4, 0 )] = q<<6; - softfloat_remStep128MBy32( - y, 29, term, q, &rem[indexMultiwordHi( 6, 4 )] ); - rem32 = rem[indexWordHi( 6 )]; - if ( ! (rem32 & 0x80000000) ) break; - --q; - } - qs[0] = q; - rem64 = (uint64_t) rem32<<32 | rem[indexWord( 6, 4 )]; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - q = (((uint32_t) (rem64>>2) * (uint64_t) recipSqrt32)>>32) + 2; - if ( rem64>>34 ) q += recipSqrt32; - x64 = (uint64_t) q<<27; - y[indexWord( 5, 0 )] = x64; - x64 = ((uint64_t) qs[0]<<24) + (x64>>32); - y[indexWord( 5, 1 )] = x64; - x64 = ((uint64_t) qs[1]<<21) + (x64>>32); - y[indexWord( 5, 2 )] = x64; - x64 = ((uint64_t) qs[2]<<18) + (x64>>32); - y[indexWord( 5, 3 )] = x64; - y[indexWord( 5, 4 )] = x64>>32; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( (q & 0xF) <= 2 ) { - q &= ~3; - y[indexWordLo( 5 )] = q<<27; - term[indexWord( 5, 4 )] = 0; - term[indexWord( 5, 3 )] = 0; - term[indexWord( 5, 2 )] = 0; - term[indexWord( 5, 1 )] = q>>6; - term[indexWord( 5, 0 )] = q<<26; - softfloat_sub160M( y, term, term ); - rem[indexWord( 6, 1 )] = 0; - rem[indexWord( 6, 0 )] = 0; - softfloat_remStep160MBy32( - &rem[indexMultiwordLo( 6, 5 )], - 14, - term, - q, - &rem[indexMultiwordLo( 6, 5 )] - ); - rem32 = rem[indexWord( 6, 4 )]; - if ( rem32 & 0x80000000 ) { - softfloat_sub1X160M( y ); - } else { - if ( - rem32 || rem[indexWord( 6, 0 )] || rem[indexWord( 6, 1 )] - || (rem[indexWord( 6, 3 )] | rem[indexWord( 6, 2 )]) - ) { - y[indexWordLo( 5 )] |= 1; - } - } - } - softfloat_roundPackMToF128M( 0, expZ, y, zWPtr ); - return; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - invalid: - softfloat_invalidF128M( zWPtr ); - return; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - copyA: - zWPtr[indexWordHi( 4 )] = uiA96; - zWPtr[indexWord( 4, 2 )] = aWPtr[indexWord( 4, 2 )]; - zWPtr[indexWord( 4, 1 )] = aWPtr[indexWord( 4, 1 )]; - zWPtr[indexWord( 4, 0 )] = aWPtr[indexWord( 4, 0 )]; - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/f128M_sub.c b/deps/SoftFloat-3e/source/f128M_sub.c deleted file mode 100644 index 5d65c799f31f..000000000000 --- a/deps/SoftFloat-3e/source/f128M_sub.c +++ /dev/null @@ -1,97 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "softfloat.h" - -#ifdef SOFTFLOAT_FAST_INT64 - -void - f128M_sub( const float128_t *aPtr, const float128_t *bPtr, float128_t *zPtr ) -{ - const uint64_t *aWPtr, *bWPtr; - uint_fast64_t uiA64, uiA0; - bool signA; - uint_fast64_t uiB64, uiB0; - bool signB; -#if ! defined INLINE_LEVEL || (INLINE_LEVEL < 2) - float128_t - (*magsFuncPtr)( - uint_fast64_t, uint_fast64_t, uint_fast64_t, uint_fast64_t, bool ); -#endif - - aWPtr = (const uint64_t *) aPtr; - bWPtr = (const uint64_t *) bPtr; - uiA64 = aWPtr[indexWord( 2, 1 )]; - uiA0 = aWPtr[indexWord( 2, 0 )]; - signA = signF128UI64( uiA64 ); - uiB64 = bWPtr[indexWord( 2, 1 )]; - uiB0 = bWPtr[indexWord( 2, 0 )]; - signB = signF128UI64( uiB64 ); -#if defined INLINE_LEVEL && (2 <= INLINE_LEVEL) - if ( signA == signB ) { - *zPtr = softfloat_subMagsF128( uiA64, uiA0, uiB64, uiB0, signA ); - } else { - *zPtr = softfloat_addMagsF128( uiA64, uiA0, uiB64, uiB0, signA ); - } -#else - magsFuncPtr = - (signA == signB) ? softfloat_subMagsF128 : softfloat_addMagsF128; - *zPtr = (*magsFuncPtr)( uiA64, uiA0, uiB64, uiB0, signA ); -#endif - -} - -#else - -void - f128M_sub( const float128_t *aPtr, const float128_t *bPtr, float128_t *zPtr ) -{ - - softfloat_addF128M( - (const uint32_t *) aPtr, - (const uint32_t *) bPtr, - (uint32_t *) zPtr, - true - ); - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/f128M_to_extF80M.c b/deps/SoftFloat-3e/source/f128M_to_extF80M.c deleted file mode 100644 index b0340c794854..000000000000 --- a/deps/SoftFloat-3e/source/f128M_to_extF80M.c +++ /dev/null @@ -1,101 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -#ifdef SOFTFLOAT_FAST_INT64 - -void f128M_to_extF80M( const float128_t *aPtr, extFloat80_t *zPtr ) -{ - - *zPtr = f128_to_extF80( *aPtr ); - -} - -#else - -void f128M_to_extF80M( const float128_t *aPtr, extFloat80_t *zPtr ) -{ - const uint32_t *aWPtr; - struct extFloat80M *zSPtr; - uint32_t uiA96; - bool sign; - int32_t exp; - struct commonNaN commonNaN; - uint32_t sig[4]; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - aWPtr = (const uint32_t *) aPtr; - zSPtr = (struct extFloat80M *) zPtr; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uiA96 = aWPtr[indexWordHi( 4 )]; - sign = signF128UI96( uiA96 ); - exp = expF128UI96( uiA96 ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( exp == 0x7FFF ) { - if ( softfloat_isNaNF128M( aWPtr ) ) { - softfloat_f128MToCommonNaN( aWPtr, &commonNaN ); - softfloat_commonNaNToExtF80M( &commonNaN, zSPtr ); - return; - } - zSPtr->signExp = packToExtF80UI64( sign, 0x7FFF ); - zSPtr->signif = UINT64_C( 0x8000000000000000 ); - return; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - exp = softfloat_shiftNormSigF128M( aWPtr, 15, sig ); - if ( exp == -128 ) { - zSPtr->signExp = packToExtF80UI64( sign, 0 ); - zSPtr->signif = 0; - return; - } - if ( sig[indexWord( 4, 0 )] ) sig[indexWord( 4, 1 )] |= 1; - softfloat_roundPackMToExtF80M( - sign, exp, &sig[indexMultiwordHi( 4, 3 )], 80, zSPtr ); - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/f128M_to_f16.c b/deps/SoftFloat-3e/source/f128M_to_f16.c deleted file mode 100644 index 95109a771d70..000000000000 --- a/deps/SoftFloat-3e/source/f128M_to_f16.c +++ /dev/null @@ -1,113 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -#ifdef SOFTFLOAT_FAST_INT64 - -float16_t f128M_to_f16( const float128_t *aPtr ) -{ - - return f128_to_f16( *aPtr ); - -} - -#else - -float16_t f128M_to_f16( const float128_t *aPtr ) -{ - const uint32_t *aWPtr; - uint32_t uiA96; - bool sign; - int32_t exp; - uint32_t frac32; - struct commonNaN commonNaN; - uint16_t uiZ, frac16; - union ui16_f16 uZ; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - aWPtr = (const uint32_t *) aPtr; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uiA96 = aWPtr[indexWordHi( 4 )]; - sign = signF128UI96( uiA96 ); - exp = expF128UI96( uiA96 ); - frac32 = - fracF128UI96( uiA96 ) - | ((aWPtr[indexWord( 4, 2 )] | aWPtr[indexWord( 4, 1 )] - | aWPtr[indexWord( 4, 0 )]) - != 0); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( exp == 0x7FFF ) { - if ( frac32 ) { - softfloat_f128MToCommonNaN( aWPtr, &commonNaN ); - uiZ = softfloat_commonNaNToF16UI( &commonNaN ); - } else { - uiZ = packToF16UI( sign, 0x1F, 0 ); - } - goto uiZ; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - frac16 = frac32>>2 | (frac32 & 3); - if ( ! (exp | frac16) ) { - uiZ = packToF16UI( sign, 0, 0 ); - goto uiZ; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - exp -= 0x3FF1; - if ( sizeof (int_fast16_t) < sizeof (int32_t) ) { - if ( exp < -0x40 ) exp = -0x40; - } - return softfloat_roundPackToF16( sign, exp, frac16 | 0x4000 ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uiZ: - uZ.ui = uiZ; - return uZ.f; - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/f128M_to_f32.c b/deps/SoftFloat-3e/source/f128M_to_f32.c deleted file mode 100644 index 4542deb0c384..000000000000 --- a/deps/SoftFloat-3e/source/f128M_to_f32.c +++ /dev/null @@ -1,109 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -#ifdef SOFTFLOAT_FAST_INT64 - -float32_t f128M_to_f32( const float128_t *aPtr ) -{ - - return f128_to_f32( *aPtr ); - -} - -#else - -float32_t f128M_to_f32( const float128_t *aPtr ) -{ - const uint32_t *aWPtr; - uint32_t uiA96; - bool sign; - int32_t exp; - uint64_t frac64; - struct commonNaN commonNaN; - uint32_t uiZ, frac32; - union ui32_f32 uZ; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - aWPtr = (const uint32_t *) aPtr; - uiA96 = aWPtr[indexWordHi( 4 )]; - sign = signF128UI96( uiA96 ); - exp = expF128UI96( uiA96 ); - frac64 = - (uint64_t) fracF128UI96( uiA96 )<<32 | aWPtr[indexWord( 4, 2 )] - | ((aWPtr[indexWord( 4, 1 )] | aWPtr[indexWord( 4, 0 )]) != 0); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( exp == 0x7FFF ) { - if ( frac64 ) { - softfloat_f128MToCommonNaN( aWPtr, &commonNaN ); - uiZ = softfloat_commonNaNToF32UI( &commonNaN ); - } else { - uiZ = packToF32UI( sign, 0xFF, 0 ); - } - goto uiZ; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - frac32 = softfloat_shortShiftRightJam64( frac64, 18 ); - if ( ! (exp | frac32) ) { - uiZ = packToF32UI( sign, 0, 0 ); - goto uiZ; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - exp -= 0x3F81; - if ( sizeof (int_fast16_t) < sizeof (int32_t) ) { - if ( exp < -0x1000 ) exp = -0x1000; - } - return softfloat_roundPackToF32( sign, exp, frac32 | 0x40000000 ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uiZ: - uZ.ui = uiZ; - return uZ.f; - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/f128M_to_f64.c b/deps/SoftFloat-3e/source/f128M_to_f64.c deleted file mode 100644 index 6213bb7f50a2..000000000000 --- a/deps/SoftFloat-3e/source/f128M_to_f64.c +++ /dev/null @@ -1,112 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -#ifdef SOFTFLOAT_FAST_INT64 - -float64_t f128M_to_f64( const float128_t *aPtr ) -{ - - return f128_to_f64( *aPtr ); - -} - -#else - -float64_t f128M_to_f64( const float128_t *aPtr ) -{ - const uint32_t *aWPtr; - uint32_t uiA96; - bool sign; - int32_t exp; - uint64_t frac64; - struct commonNaN commonNaN; - uint64_t uiZ; - uint32_t frac32; - union ui64_f64 uZ; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - aWPtr = (const uint32_t *) aPtr; - uiA96 = aWPtr[indexWordHi( 4 )]; - sign = signF128UI96( uiA96 ); - exp = expF128UI96( uiA96 ); - frac64 = (uint64_t) fracF128UI96( uiA96 )<<32 | aWPtr[indexWord( 4, 2 )]; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( exp == 0x7FFF ) { - if ( frac64 || aWPtr[indexWord( 4, 1 )] | aWPtr[indexWord( 4, 0 )] ) { - softfloat_f128MToCommonNaN( aWPtr, &commonNaN ); - uiZ = softfloat_commonNaNToF64UI( &commonNaN ); - } else { - uiZ = packToF64UI( sign, 0x7FF, 0 ); - } - goto uiZ; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - frac32 = aWPtr[indexWord( 4, 1 )]; - frac64 = frac64<<14 | frac32>>18; - if ( (frac32 & 0x0003FFFF) || aWPtr[indexWord( 4, 0 )] ) frac64 |= 1; - if ( ! (exp | frac64) ) { - uiZ = packToF64UI( sign, 0, 0 ); - goto uiZ; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - exp -= 0x3C01; - if ( sizeof (int_fast16_t) < sizeof (int32_t) ) { - if ( exp < -0x1000 ) exp = -0x1000; - } - return - softfloat_roundPackToF64( - sign, exp, frac64 | UINT64_C( 0x4000000000000000 ) ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uiZ: - uZ.ui = uiZ; - return uZ.f; - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/f128M_to_i32.c b/deps/SoftFloat-3e/source/f128M_to_i32.c deleted file mode 100644 index 54cc6f603737..000000000000 --- a/deps/SoftFloat-3e/source/f128M_to_i32.c +++ /dev/null @@ -1,98 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017 The Regents of the -University of California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -#ifdef SOFTFLOAT_FAST_INT64 - -int_fast32_t - f128M_to_i32( const float128_t *aPtr, uint_fast8_t roundingMode, bool exact ) -{ - - return f128_to_i32( *aPtr, roundingMode, exact ); - -} - -#else - -int_fast32_t - f128M_to_i32( const float128_t *aPtr, uint_fast8_t roundingMode, bool exact ) -{ - const uint32_t *aWPtr; - uint32_t uiA96; - bool sign; - int32_t exp; - uint64_t sig64; - int32_t shiftDist; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - aWPtr = (const uint32_t *) aPtr; - uiA96 = aWPtr[indexWordHi( 4 )]; - sign = signF128UI96( uiA96 ); - exp = expF128UI96( uiA96 ); - sig64 = (uint64_t) fracF128UI96( uiA96 )<<32 | aWPtr[indexWord( 4, 2 )]; - if ( aWPtr[indexWord( 4, 1 )] | aWPtr[indexWord( 4, 0 )] ) sig64 |= 1; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ -#if (i32_fromNaN != i32_fromPosOverflow) || (i32_fromNaN != i32_fromNegOverflow) - if ( (exp == 0x7FFF) && sig64 ) { -#if (i32_fromNaN == i32_fromPosOverflow) - sign = 0; -#elif (i32_fromNaN == i32_fromNegOverflow) - sign = 1; -#else - softfloat_raiseFlags( softfloat_flag_invalid ); - return i32_fromNaN; -#endif - } -#endif - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( exp ) sig64 |= UINT64_C( 0x0001000000000000 ); - shiftDist = 0x4023 - exp; - if ( 0 < shiftDist ) sig64 = softfloat_shiftRightJam64( sig64, shiftDist ); - return softfloat_roundToI32( sign, sig64, roundingMode, exact ); - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/f128M_to_i32_r_minMag.c b/deps/SoftFloat-3e/source/f128M_to_i32_r_minMag.c deleted file mode 100644 index 1f22039dedb3..000000000000 --- a/deps/SoftFloat-3e/source/f128M_to_i32_r_minMag.c +++ /dev/null @@ -1,106 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -#ifdef SOFTFLOAT_FAST_INT64 - -int_fast32_t f128M_to_i32_r_minMag( const float128_t *aPtr, bool exact ) -{ - - return f128_to_i32_r_minMag( *aPtr, exact ); - -} - -#else - -int_fast32_t f128M_to_i32_r_minMag( const float128_t *aPtr, bool exact ) -{ - const uint32_t *aWPtr; - uint32_t uiA96; - bool sign; - int32_t exp; - uint64_t sig64; - int32_t shiftDist; - uint32_t absZ, uiZ; - union { uint32_t ui; int32_t i; } uZ; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - aWPtr = (const uint32_t *) aPtr; - uiA96 = aWPtr[indexWordHi( 4 )]; - sign = signF128UI96( uiA96 ); - exp = expF128UI96( uiA96 ); - sig64 = (uint64_t) fracF128UI96( uiA96 )<<32 | aWPtr[indexWord( 4, 2 )]; - if ( aWPtr[indexWord( 4, 1 )] | aWPtr[indexWord( 4, 0 )] ) sig64 |= 1; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( exp < 0x3FFF ) { - if ( exact && (exp | sig64) ) { - softfloat_exceptionFlags |= softfloat_flag_inexact; - } - return 0; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( 0x401F <= exp ) goto invalid; - shiftDist = 0x402F - exp; - sig64 |= UINT64_C( 0x0001000000000000 ); - absZ = sig64>>shiftDist; - uiZ = sign ? -absZ : absZ; - if ( uiZ>>31 != sign ) goto invalid; - if ( exact && ((uint64_t) absZ< -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -#ifdef SOFTFLOAT_FAST_INT64 - -int_fast64_t - f128M_to_i64( const float128_t *aPtr, uint_fast8_t roundingMode, bool exact ) -{ - - return f128_to_i64( *aPtr, roundingMode, exact ); - -} - -#else - -int_fast64_t - f128M_to_i64( const float128_t *aPtr, uint_fast8_t roundingMode, bool exact ) -{ - const uint32_t *aWPtr; - uint32_t uiA96; - bool sign; - int32_t exp; - uint32_t sig96; - int32_t shiftDist; - uint32_t sig[4]; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - aWPtr = (const uint32_t *) aPtr; - uiA96 = aWPtr[indexWordHi( 4 )]; - sign = signF128UI96( uiA96 ); - exp = expF128UI96( uiA96 ); - sig96 = fracF128UI96( uiA96 ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - shiftDist = 0x404F - exp; - if ( shiftDist < 17 ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - return - (exp == 0x7FFF) - && (sig96 - || (aWPtr[indexWord( 4, 2 )] | aWPtr[indexWord( 4, 1 )] - | aWPtr[indexWord( 4, 0 )])) - ? i64_fromNaN - : sign ? i64_fromNegOverflow : i64_fromPosOverflow; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( exp ) sig96 |= 0x00010000; - sig[indexWord( 4, 3 )] = sig96; - sig[indexWord( 4, 2 )] = aWPtr[indexWord( 4, 2 )]; - sig[indexWord( 4, 1 )] = aWPtr[indexWord( 4, 1 )]; - sig[indexWord( 4, 0 )] = aWPtr[indexWord( 4, 0 )]; - softfloat_shiftRightJam128M( sig, shiftDist, sig ); - return - softfloat_roundMToI64( - sign, sig + indexMultiwordLo( 4, 3 ), roundingMode, exact ); - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/f128M_to_i64_r_minMag.c b/deps/SoftFloat-3e/source/f128M_to_i64_r_minMag.c deleted file mode 100644 index da3d28ad0b93..000000000000 --- a/deps/SoftFloat-3e/source/f128M_to_i64_r_minMag.c +++ /dev/null @@ -1,124 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -#ifdef SOFTFLOAT_FAST_INT64 - -int_fast64_t f128M_to_i64_r_minMag( const float128_t *aPtr, bool exact ) -{ - - return f128_to_i64_r_minMag( *aPtr, exact ); - -} - -#else - -int_fast64_t f128M_to_i64_r_minMag( const float128_t *aPtr, bool exact ) -{ - const uint32_t *aWPtr; - uint32_t uiA96; - bool sign; - int32_t exp; - uint32_t sig96; - int32_t shiftDist; - uint32_t sig[4]; - uint64_t uiZ; - union { uint64_t ui; int64_t i; } uZ; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - aWPtr = (const uint32_t *) aPtr; - uiA96 = aWPtr[indexWordHi( 4 )]; - sign = signF128UI96( uiA96 ); - exp = expF128UI96( uiA96 ); - sig96 = fracF128UI96( uiA96 ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - shiftDist = 0x403E - exp; - if ( shiftDist < 0 ) goto invalid; - if ( exact ) { - if ( exp ) sig96 |= 0x00010000; - sig[indexWord( 4, 3 )] = sig96; - sig[indexWord( 4, 2 )] = aWPtr[indexWord( 4, 2 )]; - sig[indexWord( 4, 1 )] = aWPtr[indexWord( 4, 1 )]; - sig[indexWord( 4, 0 )] = aWPtr[indexWord( 4, 0 )]; - softfloat_shiftRightJam128M( sig, shiftDist + 17, sig ); - uiZ = (uint64_t) sig[indexWord( 4, 2 )]<<32 | sig[indexWord( 4, 1 )]; - if ( uiZ>>63 && (! sign || (uiZ != UINT64_C( 0x8000000000000000 ))) ) { - goto invalid; - } - if ( sig[indexWordLo( 4 )] ) { - softfloat_exceptionFlags |= softfloat_flag_inexact; - } - } else { - if ( 64 <= shiftDist ) return 0; - uiZ = - (uint64_t) sig96<<47 - | (uint64_t) aWPtr[indexWord( 4, 2 )]<<15 - | aWPtr[indexWord( 4, 1 )]>>17; - if ( shiftDist ) { - uiZ |= UINT64_C( 0x8000000000000000 ); - uiZ >>= shiftDist; - } else { - if ( uiZ || ! sign ) goto invalid; - uiZ |= UINT64_C( 0x8000000000000000 ); - } - } - if ( sign ) uiZ = -uiZ; - uZ.ui = uiZ; - return uZ.i; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - invalid: - softfloat_raiseFlags( softfloat_flag_invalid ); - return - (exp == 0x7FFF) - && (sig96 - || (aWPtr[indexWord( 4, 2 )] | aWPtr[indexWord( 4, 1 )] - | aWPtr[indexWord( 4, 0 )])) - ? i64_fromNaN - : sign ? i64_fromNegOverflow : i64_fromPosOverflow; - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/f128M_to_ui32.c b/deps/SoftFloat-3e/source/f128M_to_ui32.c deleted file mode 100644 index c1baa063a6dc..000000000000 --- a/deps/SoftFloat-3e/source/f128M_to_ui32.c +++ /dev/null @@ -1,98 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017 The Regents of the -University of California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -#ifdef SOFTFLOAT_FAST_INT64 - -uint_fast32_t - f128M_to_ui32( const float128_t *aPtr, uint_fast8_t roundingMode, bool exact ) -{ - - return f128_to_ui32( *aPtr, roundingMode, exact ); - -} - -#else - -uint_fast32_t - f128M_to_ui32( const float128_t *aPtr, uint_fast8_t roundingMode, bool exact ) -{ - const uint32_t *aWPtr; - uint32_t uiA96; - bool sign; - int32_t exp; - uint64_t sig64; - int32_t shiftDist; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - aWPtr = (const uint32_t *) aPtr; - uiA96 = aWPtr[indexWordHi( 4 )]; - sign = signF128UI96( uiA96 ); - exp = expF128UI96( uiA96 ); - sig64 = (uint64_t) fracF128UI96( uiA96 )<<32 | aWPtr[indexWord( 4, 2 )]; - if ( aWPtr[indexWord( 4, 1 )] | aWPtr[indexWord( 4, 0 )] ) sig64 |= 1; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ -#if (ui32_fromNaN != ui32_fromPosOverflow) || (ui32_fromNaN != ui32_fromNegOverflow) - if ( (exp == 0x7FFF) && sig64 ) { -#if (ui32_fromNaN == ui32_fromPosOverflow) - sign = 0; -#elif (ui32_fromNaN == ui32_fromNegOverflow) - sign = 1; -#else - softfloat_raiseFlags( softfloat_flag_invalid ); - return ui32_fromNaN; -#endif - } -#endif - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( exp ) sig64 |= UINT64_C( 0x0001000000000000 ); - shiftDist = 0x4023 - exp; - if ( 0 < shiftDist ) sig64 = softfloat_shiftRightJam64( sig64, shiftDist ); - return softfloat_roundToUI32( sign, sig64, roundingMode, exact ); - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/f128M_to_ui32_r_minMag.c b/deps/SoftFloat-3e/source/f128M_to_ui32_r_minMag.c deleted file mode 100644 index a1aca621ab38..000000000000 --- a/deps/SoftFloat-3e/source/f128M_to_ui32_r_minMag.c +++ /dev/null @@ -1,102 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -#ifdef SOFTFLOAT_FAST_INT64 - -uint_fast32_t f128M_to_ui32_r_minMag( const float128_t *aPtr, bool exact ) -{ - - return f128_to_ui32_r_minMag( *aPtr, exact ); - -} - -#else - -uint_fast32_t f128M_to_ui32_r_minMag( const float128_t *aPtr, bool exact ) -{ - const uint32_t *aWPtr; - uint32_t uiA96; - int32_t exp; - uint64_t sig64; - int32_t shiftDist; - bool sign; - uint32_t z; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - aWPtr = (const uint32_t *) aPtr; - uiA96 = aWPtr[indexWordHi( 4 )]; - exp = expF128UI96( uiA96 ); - sig64 = (uint64_t) fracF128UI96( uiA96 )<<32 | aWPtr[indexWord( 4, 2 )]; - if ( aWPtr[indexWord( 4, 1 )] | aWPtr[indexWord( 4, 0 )] ) sig64 |= 1; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - shiftDist = 0x402F - exp; - if ( 49 <= shiftDist ) { - if ( exact && (exp | sig64) ) { - softfloat_exceptionFlags |= softfloat_flag_inexact; - } - return 0; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - sign = signF128UI96( uiA96 ); - if ( sign || (shiftDist < 17) ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - return - (exp == 0x7FFF) && sig64 ? ui32_fromNaN - : sign ? ui32_fromNegOverflow : ui32_fromPosOverflow; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - sig64 |= UINT64_C( 0x0001000000000000 ); - z = sig64>>shiftDist; - if ( exact && ((uint64_t) z< -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -#ifdef SOFTFLOAT_FAST_INT64 - -uint_fast64_t - f128M_to_ui64( const float128_t *aPtr, uint_fast8_t roundingMode, bool exact ) -{ - - return f128_to_ui64( *aPtr, roundingMode, exact ); - -} - -#else - -uint_fast64_t - f128M_to_ui64( const float128_t *aPtr, uint_fast8_t roundingMode, bool exact ) -{ - const uint32_t *aWPtr; - uint32_t uiA96; - bool sign; - int32_t exp; - uint32_t sig96; - int32_t shiftDist; - uint32_t sig[4]; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - aWPtr = (const uint32_t *) aPtr; - uiA96 = aWPtr[indexWordHi( 4 )]; - sign = signF128UI96( uiA96 ); - exp = expF128UI96( uiA96 ); - sig96 = fracF128UI96( uiA96 ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - shiftDist = 0x404F - exp; - if ( shiftDist < 17 ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - return - (exp == 0x7FFF) - && (sig96 - || (aWPtr[indexWord( 4, 2 )] | aWPtr[indexWord( 4, 1 )] - | aWPtr[indexWord( 4, 0 )])) - ? ui64_fromNaN - : sign ? ui64_fromNegOverflow : ui64_fromPosOverflow; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( exp ) sig96 |= 0x00010000; - sig[indexWord( 4, 3 )] = sig96; - sig[indexWord( 4, 2 )] = aWPtr[indexWord( 4, 2 )]; - sig[indexWord( 4, 1 )] = aWPtr[indexWord( 4, 1 )]; - sig[indexWord( 4, 0 )] = aWPtr[indexWord( 4, 0 )]; - softfloat_shiftRightJam128M( sig, shiftDist, sig ); - return - softfloat_roundMToUI64( - sign, sig + indexMultiwordLo( 4, 3 ), roundingMode, exact ); - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/f128M_to_ui64_r_minMag.c b/deps/SoftFloat-3e/source/f128M_to_ui64_r_minMag.c deleted file mode 100644 index 7a1b602959c1..000000000000 --- a/deps/SoftFloat-3e/source/f128M_to_ui64_r_minMag.c +++ /dev/null @@ -1,114 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -#ifdef SOFTFLOAT_FAST_INT64 - -uint_fast64_t f128M_to_ui64_r_minMag( const float128_t *aPtr, bool exact ) -{ - - return f128_to_ui64_r_minMag( *aPtr, exact ); - -} - -#else - -uint_fast64_t f128M_to_ui64_r_minMag( const float128_t *aPtr, bool exact ) -{ - const uint32_t *aWPtr; - uint32_t uiA96; - bool sign; - int32_t exp; - uint32_t sig96; - int32_t shiftDist; - uint32_t sig[4]; - uint64_t z; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - aWPtr = (const uint32_t *) aPtr; - uiA96 = aWPtr[indexWordHi( 4 )]; - sign = signF128UI96( uiA96 ); - exp = expF128UI96( uiA96 ); - sig96 = fracF128UI96( uiA96 ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - shiftDist = 0x403E - exp; - if ( shiftDist < 0 ) goto invalid; - if ( exact ) { - if ( exp ) sig96 |= 0x00010000; - sig[indexWord( 4, 3 )] = sig96; - sig[indexWord( 4, 2 )] = aWPtr[indexWord( 4, 2 )]; - sig[indexWord( 4, 1 )] = aWPtr[indexWord( 4, 1 )]; - sig[indexWord( 4, 0 )] = aWPtr[indexWord( 4, 0 )]; - softfloat_shiftRightJam128M( sig, shiftDist + 17, sig ); - z = (uint64_t) sig[indexWord( 4, 2 )]<<32 | sig[indexWord( 4, 1 )]; - if ( sign && z ) goto invalid; - if ( sig[indexWordLo( 4 )] ) { - softfloat_exceptionFlags |= softfloat_flag_inexact; - } - } else { - if ( 64 <= shiftDist ) return 0; - if ( sign ) goto invalid; - z = UINT64_C( 0x8000000000000000 ) - | (uint64_t) sig96<<47 - | (uint64_t) aWPtr[indexWord( 4, 2 )]<<15 - | aWPtr[indexWord( 4, 1 )]>>17; - z >>= shiftDist; - } - return z; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - invalid: - softfloat_raiseFlags( softfloat_flag_invalid ); - return - (exp == 0x7FFF) - && (sig96 - || (aWPtr[indexWord( 4, 2 )] | aWPtr[indexWord( 4, 1 )] - | aWPtr[indexWord( 4, 0 )])) - ? ui64_fromNaN - : sign ? ui64_fromNegOverflow : ui64_fromPosOverflow; - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/f128_add.c b/deps/SoftFloat-3e/source/f128_add.c deleted file mode 100644 index e9caba682593..000000000000 --- a/deps/SoftFloat-3e/source/f128_add.c +++ /dev/null @@ -1,78 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "softfloat.h" - -float128_t f128_add( float128_t a, float128_t b ) -{ - union ui128_f128 uA; - uint_fast64_t uiA64, uiA0; - bool signA; - union ui128_f128 uB; - uint_fast64_t uiB64, uiB0; - bool signB; -#if ! defined INLINE_LEVEL || (INLINE_LEVEL < 2) - float128_t - (*magsFuncPtr)( - uint_fast64_t, uint_fast64_t, uint_fast64_t, uint_fast64_t, bool ); -#endif - - uA.f = a; - uiA64 = uA.ui.v64; - uiA0 = uA.ui.v0; - signA = signF128UI64( uiA64 ); - uB.f = b; - uiB64 = uB.ui.v64; - uiB0 = uB.ui.v0; - signB = signF128UI64( uiB64 ); -#if defined INLINE_LEVEL && (2 <= INLINE_LEVEL) - if ( signA == signB ) { - return softfloat_addMagsF128( uiA64, uiA0, uiB64, uiB0, signA ); - } else { - return softfloat_subMagsF128( uiA64, uiA0, uiB64, uiB0, signA ); - } -#else - magsFuncPtr = - (signA == signB) ? softfloat_addMagsF128 : softfloat_subMagsF128; - return (*magsFuncPtr)( uiA64, uiA0, uiB64, uiB0, signA ); -#endif - -} - diff --git a/deps/SoftFloat-3e/source/f128_div.c b/deps/SoftFloat-3e/source/f128_div.c deleted file mode 100644 index 0693db754a60..000000000000 --- a/deps/SoftFloat-3e/source/f128_div.c +++ /dev/null @@ -1,199 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -float128_t f128_div( float128_t a, float128_t b ) -{ - union ui128_f128 uA; - uint_fast64_t uiA64, uiA0; - bool signA; - int_fast32_t expA; - struct uint128 sigA; - union ui128_f128 uB; - uint_fast64_t uiB64, uiB0; - bool signB; - int_fast32_t expB; - struct uint128 sigB; - bool signZ; - struct exp32_sig128 normExpSig; - int_fast32_t expZ; - struct uint128 rem; - uint_fast32_t recip32; - int ix; - uint_fast64_t q64; - uint_fast32_t q; - struct uint128 term; - uint_fast32_t qs[3]; - uint_fast64_t sigZExtra; - struct uint128 sigZ, uiZ; - union ui128_f128 uZ; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uA.f = a; - uiA64 = uA.ui.v64; - uiA0 = uA.ui.v0; - signA = signF128UI64( uiA64 ); - expA = expF128UI64( uiA64 ); - sigA.v64 = fracF128UI64( uiA64 ); - sigA.v0 = uiA0; - uB.f = b; - uiB64 = uB.ui.v64; - uiB0 = uB.ui.v0; - signB = signF128UI64( uiB64 ); - expB = expF128UI64( uiB64 ); - sigB.v64 = fracF128UI64( uiB64 ); - sigB.v0 = uiB0; - signZ = signA ^ signB; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( expA == 0x7FFF ) { - if ( sigA.v64 | sigA.v0 ) goto propagateNaN; - if ( expB == 0x7FFF ) { - if ( sigB.v64 | sigB.v0 ) goto propagateNaN; - goto invalid; - } - goto infinity; - } - if ( expB == 0x7FFF ) { - if ( sigB.v64 | sigB.v0 ) goto propagateNaN; - goto zero; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( ! expB ) { - if ( ! (sigB.v64 | sigB.v0) ) { - if ( ! (expA | sigA.v64 | sigA.v0) ) goto invalid; - softfloat_raiseFlags( softfloat_flag_infinite ); - goto infinity; - } - normExpSig = softfloat_normSubnormalF128Sig( sigB.v64, sigB.v0 ); - expB = normExpSig.exp; - sigB = normExpSig.sig; - } - if ( ! expA ) { - if ( ! (sigA.v64 | sigA.v0) ) goto zero; - normExpSig = softfloat_normSubnormalF128Sig( sigA.v64, sigA.v0 ); - expA = normExpSig.exp; - sigA = normExpSig.sig; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - expZ = expA - expB + 0x3FFE; - sigA.v64 |= UINT64_C( 0x0001000000000000 ); - sigB.v64 |= UINT64_C( 0x0001000000000000 ); - rem = sigA; - if ( softfloat_lt128( sigA.v64, sigA.v0, sigB.v64, sigB.v0 ) ) { - --expZ; - rem = softfloat_add128( sigA.v64, sigA.v0, sigA.v64, sigA.v0 ); - } - recip32 = softfloat_approxRecip32_1( sigB.v64>>17 ); - ix = 3; - for (;;) { - q64 = (uint_fast64_t) (uint32_t) (rem.v64>>19) * recip32; - q = (q64 + 0x80000000)>>32; - --ix; - if ( ix < 0 ) break; - rem = softfloat_shortShiftLeft128( rem.v64, rem.v0, 29 ); - term = softfloat_mul128By32( sigB.v64, sigB.v0, q ); - rem = softfloat_sub128( rem.v64, rem.v0, term.v64, term.v0 ); - if ( rem.v64 & UINT64_C( 0x8000000000000000 ) ) { - --q; - rem = softfloat_add128( rem.v64, rem.v0, sigB.v64, sigB.v0 ); - } - qs[ix] = q; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( ((q + 1) & 7) < 2 ) { - rem = softfloat_shortShiftLeft128( rem.v64, rem.v0, 29 ); - term = softfloat_mul128By32( sigB.v64, sigB.v0, q ); - rem = softfloat_sub128( rem.v64, rem.v0, term.v64, term.v0 ); - if ( rem.v64 & UINT64_C( 0x8000000000000000 ) ) { - --q; - rem = softfloat_add128( rem.v64, rem.v0, sigB.v64, sigB.v0 ); - } else if ( softfloat_le128( sigB.v64, sigB.v0, rem.v64, rem.v0 ) ) { - ++q; - rem = softfloat_sub128( rem.v64, rem.v0, sigB.v64, sigB.v0 ); - } - if ( rem.v64 | rem.v0 ) q |= 1; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - sigZExtra = (uint64_t) ((uint_fast64_t) q<<60); - term = softfloat_shortShiftLeft128( 0, qs[1], 54 ); - sigZ = - softfloat_add128( - (uint_fast64_t) qs[2]<<19, ((uint_fast64_t) qs[0]<<25) + (q>>4), - term.v64, term.v0 - ); - return - softfloat_roundPackToF128( signZ, expZ, sigZ.v64, sigZ.v0, sigZExtra ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - propagateNaN: - uiZ = softfloat_propagateNaNF128UI( uiA64, uiA0, uiB64, uiB0 ); - goto uiZ; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - invalid: - softfloat_raiseFlags( softfloat_flag_invalid ); - uiZ.v64 = defaultNaNF128UI64; - uiZ.v0 = defaultNaNF128UI0; - goto uiZ; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - infinity: - uiZ.v64 = packToF128UI64( signZ, 0x7FFF, 0 ); - goto uiZ0; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - zero: - uiZ.v64 = packToF128UI64( signZ, 0, 0 ); - uiZ0: - uiZ.v0 = 0; - uiZ: - uZ.ui = uiZ; - return uZ.f; - -} - diff --git a/deps/SoftFloat-3e/source/f128_eq.c b/deps/SoftFloat-3e/source/f128_eq.c deleted file mode 100644 index 9462fc2abd06..000000000000 --- a/deps/SoftFloat-3e/source/f128_eq.c +++ /dev/null @@ -1,73 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -bool f128_eq( float128_t a, float128_t b ) -{ - union ui128_f128 uA; - uint_fast64_t uiA64, uiA0; - union ui128_f128 uB; - uint_fast64_t uiB64, uiB0; - - uA.f = a; - uiA64 = uA.ui.v64; - uiA0 = uA.ui.v0; - uB.f = b; - uiB64 = uB.ui.v64; - uiB0 = uB.ui.v0; - if ( isNaNF128UI( uiA64, uiA0 ) || isNaNF128UI( uiB64, uiB0 ) ) { - if ( - softfloat_isSigNaNF128UI( uiA64, uiA0 ) - || softfloat_isSigNaNF128UI( uiB64, uiB0 ) - ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - } - return false; - } - return - (uiA0 == uiB0) - && ( (uiA64 == uiB64) - || (! uiA0 && ! ((uiA64 | uiB64) & UINT64_C( 0x7FFFFFFFFFFFFFFF ))) - ); - -} - diff --git a/deps/SoftFloat-3e/source/f128_eq_signaling.c b/deps/SoftFloat-3e/source/f128_eq_signaling.c deleted file mode 100644 index 5d0819d291b9..000000000000 --- a/deps/SoftFloat-3e/source/f128_eq_signaling.c +++ /dev/null @@ -1,67 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "softfloat.h" - -bool f128_eq_signaling( float128_t a, float128_t b ) -{ - union ui128_f128 uA; - uint_fast64_t uiA64, uiA0; - union ui128_f128 uB; - uint_fast64_t uiB64, uiB0; - - uA.f = a; - uiA64 = uA.ui.v64; - uiA0 = uA.ui.v0; - uB.f = b; - uiB64 = uB.ui.v64; - uiB0 = uB.ui.v0; - if ( isNaNF128UI( uiA64, uiA0 ) || isNaNF128UI( uiB64, uiB0 ) ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - return false; - } - return - (uiA0 == uiB0) - && ( (uiA64 == uiB64) - || (! uiA0 && ! ((uiA64 | uiB64) & UINT64_C( 0x7FFFFFFFFFFFFFFF ))) - ); - -} - diff --git a/deps/SoftFloat-3e/source/f128_isSignalingNaN.c b/deps/SoftFloat-3e/source/f128_isSignalingNaN.c deleted file mode 100644 index a764ff6bfebc..000000000000 --- a/deps/SoftFloat-3e/source/f128_isSignalingNaN.c +++ /dev/null @@ -1,51 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -bool f128_isSignalingNaN( float128_t a ) -{ - union ui128_f128 uA; - - uA.f = a; - return softfloat_isSigNaNF128UI( uA.ui.v64, uA.ui.v0 ); - -} - diff --git a/deps/SoftFloat-3e/source/f128_le.c b/deps/SoftFloat-3e/source/f128_le.c deleted file mode 100644 index 521a1cb03725..000000000000 --- a/deps/SoftFloat-3e/source/f128_le.c +++ /dev/null @@ -1,72 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "softfloat.h" - -bool f128_le( float128_t a, float128_t b ) -{ - union ui128_f128 uA; - uint_fast64_t uiA64, uiA0; - union ui128_f128 uB; - uint_fast64_t uiB64, uiB0; - bool signA, signB; - - uA.f = a; - uiA64 = uA.ui.v64; - uiA0 = uA.ui.v0; - uB.f = b; - uiB64 = uB.ui.v64; - uiB0 = uB.ui.v0; - if ( isNaNF128UI( uiA64, uiA0 ) || isNaNF128UI( uiB64, uiB0 ) ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - return false; - } - signA = signF128UI64( uiA64 ); - signB = signF128UI64( uiB64 ); - return - (signA != signB) - ? signA - || ! (((uiA64 | uiB64) & UINT64_C( 0x7FFFFFFFFFFFFFFF )) - | uiA0 | uiB0) - : ((uiA64 == uiB64) && (uiA0 == uiB0)) - || (signA ^ softfloat_lt128( uiA64, uiA0, uiB64, uiB0 )); - -} - diff --git a/deps/SoftFloat-3e/source/f128_le_quiet.c b/deps/SoftFloat-3e/source/f128_le_quiet.c deleted file mode 100644 index 820b28b810a1..000000000000 --- a/deps/SoftFloat-3e/source/f128_le_quiet.c +++ /dev/null @@ -1,78 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -bool f128_le_quiet( float128_t a, float128_t b ) -{ - union ui128_f128 uA; - uint_fast64_t uiA64, uiA0; - union ui128_f128 uB; - uint_fast64_t uiB64, uiB0; - bool signA, signB; - - uA.f = a; - uiA64 = uA.ui.v64; - uiA0 = uA.ui.v0; - uB.f = b; - uiB64 = uB.ui.v64; - uiB0 = uB.ui.v0; - if ( isNaNF128UI( uiA64, uiA0 ) || isNaNF128UI( uiB64, uiB0 ) ) { - if ( - softfloat_isSigNaNF128UI( uiA64, uiA0 ) - || softfloat_isSigNaNF128UI( uiB64, uiB0 ) - ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - } - return false; - } - signA = signF128UI64( uiA64 ); - signB = signF128UI64( uiB64 ); - return - (signA != signB) - ? signA - || ! (((uiA64 | uiB64) & UINT64_C( 0x7FFFFFFFFFFFFFFF )) - | uiA0 | uiB0) - : ((uiA64 == uiB64) && (uiA0 == uiB0)) - || (signA ^ softfloat_lt128( uiA64, uiA0, uiB64, uiB0 )); - -} - diff --git a/deps/SoftFloat-3e/source/f128_lt.c b/deps/SoftFloat-3e/source/f128_lt.c deleted file mode 100644 index fa46ae2bce69..000000000000 --- a/deps/SoftFloat-3e/source/f128_lt.c +++ /dev/null @@ -1,72 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "softfloat.h" - -bool f128_lt( float128_t a, float128_t b ) -{ - union ui128_f128 uA; - uint_fast64_t uiA64, uiA0; - union ui128_f128 uB; - uint_fast64_t uiB64, uiB0; - bool signA, signB; - - uA.f = a; - uiA64 = uA.ui.v64; - uiA0 = uA.ui.v0; - uB.f = b; - uiB64 = uB.ui.v64; - uiB0 = uB.ui.v0; - if ( isNaNF128UI( uiA64, uiA0 ) || isNaNF128UI( uiB64, uiB0 ) ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - return false; - } - signA = signF128UI64( uiA64 ); - signB = signF128UI64( uiB64 ); - return - (signA != signB) - ? signA - && (((uiA64 | uiB64) & UINT64_C( 0x7FFFFFFFFFFFFFFF )) - | uiA0 | uiB0) - : ((uiA64 != uiB64) || (uiA0 != uiB0)) - && (signA ^ softfloat_lt128( uiA64, uiA0, uiB64, uiB0 )); - -} - diff --git a/deps/SoftFloat-3e/source/f128_lt_quiet.c b/deps/SoftFloat-3e/source/f128_lt_quiet.c deleted file mode 100644 index d491de2f2d02..000000000000 --- a/deps/SoftFloat-3e/source/f128_lt_quiet.c +++ /dev/null @@ -1,78 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -bool f128_lt_quiet( float128_t a, float128_t b ) -{ - union ui128_f128 uA; - uint_fast64_t uiA64, uiA0; - union ui128_f128 uB; - uint_fast64_t uiB64, uiB0; - bool signA, signB; - - uA.f = a; - uiA64 = uA.ui.v64; - uiA0 = uA.ui.v0; - uB.f = b; - uiB64 = uB.ui.v64; - uiB0 = uB.ui.v0; - if ( isNaNF128UI( uiA64, uiA0 ) || isNaNF128UI( uiB64, uiB0 ) ) { - if ( - softfloat_isSigNaNF128UI( uiA64, uiA0 ) - || softfloat_isSigNaNF128UI( uiB64, uiB0 ) - ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - } - return false; - } - signA = signF128UI64( uiA64 ); - signB = signF128UI64( uiB64 ); - return - (signA != signB) - ? signA - && (((uiA64 | uiB64) & UINT64_C( 0x7FFFFFFFFFFFFFFF )) - | uiA0 | uiB0) - : ((uiA64 != uiB64) || (uiA0 != uiB0)) - && (signA ^ softfloat_lt128( uiA64, uiA0, uiB64, uiB0 )); - -} - diff --git a/deps/SoftFloat-3e/source/f128_mul.c b/deps/SoftFloat-3e/source/f128_mul.c deleted file mode 100644 index 24af86a245d2..000000000000 --- a/deps/SoftFloat-3e/source/f128_mul.c +++ /dev/null @@ -1,163 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -float128_t f128_mul( float128_t a, float128_t b ) -{ - union ui128_f128 uA; - uint_fast64_t uiA64, uiA0; - bool signA; - int_fast32_t expA; - struct uint128 sigA; - union ui128_f128 uB; - uint_fast64_t uiB64, uiB0; - bool signB; - int_fast32_t expB; - struct uint128 sigB; - bool signZ; - uint_fast64_t magBits; - struct exp32_sig128 normExpSig; - int_fast32_t expZ; - uint64_t sig256Z[4]; - uint_fast64_t sigZExtra; - struct uint128 sigZ; - struct uint128_extra sig128Extra; - struct uint128 uiZ; - union ui128_f128 uZ; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uA.f = a; - uiA64 = uA.ui.v64; - uiA0 = uA.ui.v0; - signA = signF128UI64( uiA64 ); - expA = expF128UI64( uiA64 ); - sigA.v64 = fracF128UI64( uiA64 ); - sigA.v0 = uiA0; - uB.f = b; - uiB64 = uB.ui.v64; - uiB0 = uB.ui.v0; - signB = signF128UI64( uiB64 ); - expB = expF128UI64( uiB64 ); - sigB.v64 = fracF128UI64( uiB64 ); - sigB.v0 = uiB0; - signZ = signA ^ signB; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( expA == 0x7FFF ) { - if ( - (sigA.v64 | sigA.v0) || ((expB == 0x7FFF) && (sigB.v64 | sigB.v0)) - ) { - goto propagateNaN; - } - magBits = expB | sigB.v64 | sigB.v0; - goto infArg; - } - if ( expB == 0x7FFF ) { - if ( sigB.v64 | sigB.v0 ) goto propagateNaN; - magBits = expA | sigA.v64 | sigA.v0; - goto infArg; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( ! expA ) { - if ( ! (sigA.v64 | sigA.v0) ) goto zero; - normExpSig = softfloat_normSubnormalF128Sig( sigA.v64, sigA.v0 ); - expA = normExpSig.exp; - sigA = normExpSig.sig; - } - if ( ! expB ) { - if ( ! (sigB.v64 | sigB.v0) ) goto zero; - normExpSig = softfloat_normSubnormalF128Sig( sigB.v64, sigB.v0 ); - expB = normExpSig.exp; - sigB = normExpSig.sig; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - expZ = expA + expB - 0x4000; - sigA.v64 |= UINT64_C( 0x0001000000000000 ); - sigB = softfloat_shortShiftLeft128( sigB.v64, sigB.v0, 16 ); - softfloat_mul128To256M( sigA.v64, sigA.v0, sigB.v64, sigB.v0, sig256Z ); - sigZExtra = sig256Z[indexWord( 4, 1 )] | (sig256Z[indexWord( 4, 0 )] != 0); - sigZ = - softfloat_add128( - sig256Z[indexWord( 4, 3 )], sig256Z[indexWord( 4, 2 )], - sigA.v64, sigA.v0 - ); - if ( UINT64_C( 0x0002000000000000 ) <= sigZ.v64 ) { - ++expZ; - sig128Extra = - softfloat_shortShiftRightJam128Extra( - sigZ.v64, sigZ.v0, sigZExtra, 1 ); - sigZ = sig128Extra.v; - sigZExtra = sig128Extra.extra; - } - return - softfloat_roundPackToF128( signZ, expZ, sigZ.v64, sigZ.v0, sigZExtra ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - propagateNaN: - uiZ = softfloat_propagateNaNF128UI( uiA64, uiA0, uiB64, uiB0 ); - goto uiZ; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - infArg: - if ( ! magBits ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - uiZ.v64 = defaultNaNF128UI64; - uiZ.v0 = defaultNaNF128UI0; - goto uiZ; - } - uiZ.v64 = packToF128UI64( signZ, 0x7FFF, 0 ); - goto uiZ0; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - zero: - uiZ.v64 = packToF128UI64( signZ, 0, 0 ); - uiZ0: - uiZ.v0 = 0; - uiZ: - uZ.ui = uiZ; - return uZ.f; - -} - diff --git a/deps/SoftFloat-3e/source/f128_mulAdd.c b/deps/SoftFloat-3e/source/f128_mulAdd.c deleted file mode 100644 index c7272d4e0e9f..000000000000 --- a/deps/SoftFloat-3e/source/f128_mulAdd.c +++ /dev/null @@ -1,63 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "internals.h" -#include "softfloat.h" - -float128_t f128_mulAdd( float128_t a, float128_t b, float128_t c ) -{ - union ui128_f128 uA; - uint_fast64_t uiA64, uiA0; - union ui128_f128 uB; - uint_fast64_t uiB64, uiB0; - union ui128_f128 uC; - uint_fast64_t uiC64, uiC0; - - uA.f = a; - uiA64 = uA.ui.v64; - uiA0 = uA.ui.v0; - uB.f = b; - uiB64 = uB.ui.v64; - uiB0 = uB.ui.v0; - uC.f = c; - uiC64 = uC.ui.v64; - uiC0 = uC.ui.v0; - return softfloat_mulAddF128( uiA64, uiA0, uiB64, uiB0, uiC64, uiC0, 0 ); - -} - diff --git a/deps/SoftFloat-3e/source/f128_rem.c b/deps/SoftFloat-3e/source/f128_rem.c deleted file mode 100644 index f525f697a58c..000000000000 --- a/deps/SoftFloat-3e/source/f128_rem.c +++ /dev/null @@ -1,190 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -float128_t f128_rem( float128_t a, float128_t b ) -{ - union ui128_f128 uA; - uint_fast64_t uiA64, uiA0; - bool signA; - int_fast32_t expA; - struct uint128 sigA; - union ui128_f128 uB; - uint_fast64_t uiB64, uiB0; - int_fast32_t expB; - struct uint128 sigB; - struct exp32_sig128 normExpSig; - struct uint128 rem; - int_fast32_t expDiff; - uint_fast32_t q, recip32; - uint_fast64_t q64; - struct uint128 term, altRem, meanRem; - bool signRem; - struct uint128 uiZ; - union ui128_f128 uZ; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uA.f = a; - uiA64 = uA.ui.v64; - uiA0 = uA.ui.v0; - signA = signF128UI64( uiA64 ); - expA = expF128UI64( uiA64 ); - sigA.v64 = fracF128UI64( uiA64 ); - sigA.v0 = uiA0; - uB.f = b; - uiB64 = uB.ui.v64; - uiB0 = uB.ui.v0; - expB = expF128UI64( uiB64 ); - sigB.v64 = fracF128UI64( uiB64 ); - sigB.v0 = uiB0; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( expA == 0x7FFF ) { - if ( - (sigA.v64 | sigA.v0) || ((expB == 0x7FFF) && (sigB.v64 | sigB.v0)) - ) { - goto propagateNaN; - } - goto invalid; - } - if ( expB == 0x7FFF ) { - if ( sigB.v64 | sigB.v0 ) goto propagateNaN; - return a; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( ! expB ) { - if ( ! (sigB.v64 | sigB.v0) ) goto invalid; - normExpSig = softfloat_normSubnormalF128Sig( sigB.v64, sigB.v0 ); - expB = normExpSig.exp; - sigB = normExpSig.sig; - } - if ( ! expA ) { - if ( ! (sigA.v64 | sigA.v0) ) return a; - normExpSig = softfloat_normSubnormalF128Sig( sigA.v64, sigA.v0 ); - expA = normExpSig.exp; - sigA = normExpSig.sig; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - sigA.v64 |= UINT64_C( 0x0001000000000000 ); - sigB.v64 |= UINT64_C( 0x0001000000000000 ); - rem = sigA; - expDiff = expA - expB; - if ( expDiff < 1 ) { - if ( expDiff < -1 ) return a; - if ( expDiff ) { - --expB; - sigB = softfloat_add128( sigB.v64, sigB.v0, sigB.v64, sigB.v0 ); - q = 0; - } else { - q = softfloat_le128( sigB.v64, sigB.v0, rem.v64, rem.v0 ); - if ( q ) { - rem = softfloat_sub128( rem.v64, rem.v0, sigB.v64, sigB.v0 ); - } - } - } else { - recip32 = softfloat_approxRecip32_1( sigB.v64>>17 ); - expDiff -= 30; - for (;;) { - q64 = (uint_fast64_t) (uint32_t) (rem.v64>>19) * recip32; - if ( expDiff < 0 ) break; - q = (q64 + 0x80000000)>>32; - rem = softfloat_shortShiftLeft128( rem.v64, rem.v0, 29 ); - term = softfloat_mul128By32( sigB.v64, sigB.v0, q ); - rem = softfloat_sub128( rem.v64, rem.v0, term.v64, term.v0 ); - if ( rem.v64 & UINT64_C( 0x8000000000000000 ) ) { - rem = softfloat_add128( rem.v64, rem.v0, sigB.v64, sigB.v0 ); - } - expDiff -= 29; - } - /*-------------------------------------------------------------------- - | (`expDiff' cannot be less than -29 here.) - *--------------------------------------------------------------------*/ - q = (uint32_t) (q64>>32)>>(~expDiff & 31); - rem = softfloat_shortShiftLeft128( rem.v64, rem.v0, expDiff + 30 ); - term = softfloat_mul128By32( sigB.v64, sigB.v0, q ); - rem = softfloat_sub128( rem.v64, rem.v0, term.v64, term.v0 ); - if ( rem.v64 & UINT64_C( 0x8000000000000000 ) ) { - altRem = softfloat_add128( rem.v64, rem.v0, sigB.v64, sigB.v0 ); - goto selectRem; - } - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - do { - altRem = rem; - ++q; - rem = softfloat_sub128( rem.v64, rem.v0, sigB.v64, sigB.v0 ); - } while ( ! (rem.v64 & UINT64_C( 0x8000000000000000 )) ); - selectRem: - meanRem = softfloat_add128( rem.v64, rem.v0, altRem.v64, altRem.v0 ); - if ( - (meanRem.v64 & UINT64_C( 0x8000000000000000 )) - || (! (meanRem.v64 | meanRem.v0) && (q & 1)) - ) { - rem = altRem; - } - signRem = signA; - if ( rem.v64 & UINT64_C( 0x8000000000000000 ) ) { - signRem = ! signRem; - rem = softfloat_sub128( 0, 0, rem.v64, rem.v0 ); - } - return softfloat_normRoundPackToF128( signRem, expB - 1, rem.v64, rem.v0 ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - propagateNaN: - uiZ = softfloat_propagateNaNF128UI( uiA64, uiA0, uiB64, uiB0 ); - goto uiZ; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - invalid: - softfloat_raiseFlags( softfloat_flag_invalid ); - uiZ.v64 = defaultNaNF128UI64; - uiZ.v0 = defaultNaNF128UI0; - uiZ: - uZ.ui = uiZ; - return uZ.f; - -} - diff --git a/deps/SoftFloat-3e/source/f128_roundToInt.c b/deps/SoftFloat-3e/source/f128_roundToInt.c deleted file mode 100644 index 69185d6efa69..000000000000 --- a/deps/SoftFloat-3e/source/f128_roundToInt.c +++ /dev/null @@ -1,172 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2017 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -float128_t - f128_roundToInt( float128_t a, uint_fast8_t roundingMode, bool exact ) -{ - union ui128_f128 uA; - uint_fast64_t uiA64, uiA0; - int_fast32_t exp; - struct uint128 uiZ; - uint_fast64_t lastBitMask0, roundBitsMask; - bool roundNearEven; - uint_fast64_t lastBitMask64; - union ui128_f128 uZ; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uA.f = a; - uiA64 = uA.ui.v64; - uiA0 = uA.ui.v0; - exp = expF128UI64( uiA64 ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( 0x402F <= exp ) { - /*-------------------------------------------------------------------- - *--------------------------------------------------------------------*/ - if ( 0x406F <= exp ) { - if ( (exp == 0x7FFF) && (fracF128UI64( uiA64 ) | uiA0) ) { - uiZ = softfloat_propagateNaNF128UI( uiA64, uiA0, 0, 0 ); - goto uiZ; - } - return a; - } - /*-------------------------------------------------------------------- - *--------------------------------------------------------------------*/ - lastBitMask0 = (uint_fast64_t) 2<<(0x406E - exp); - roundBitsMask = lastBitMask0 - 1; - uiZ.v64 = uiA64; - uiZ.v0 = uiA0; - roundNearEven = (roundingMode == softfloat_round_near_even); - if ( roundNearEven || (roundingMode == softfloat_round_near_maxMag) ) { - if ( exp == 0x402F ) { - if ( UINT64_C( 0x8000000000000000 ) <= uiZ.v0 ) { - ++uiZ.v64; - if ( - roundNearEven - && (uiZ.v0 == UINT64_C( 0x8000000000000000 )) - ) { - uiZ.v64 &= ~1; - } - } - } else { - uiZ = softfloat_add128( uiZ.v64, uiZ.v0, 0, lastBitMask0>>1 ); - if ( roundNearEven && !(uiZ.v0 & roundBitsMask) ) { - uiZ.v0 &= ~lastBitMask0; - } - } - } else if ( - roundingMode - == (signF128UI64( uiZ.v64 ) ? softfloat_round_min - : softfloat_round_max) - ) { - uiZ = softfloat_add128( uiZ.v64, uiZ.v0, 0, roundBitsMask ); - } - uiZ.v0 &= ~roundBitsMask; - lastBitMask64 = !lastBitMask0; - } else { - /*-------------------------------------------------------------------- - *--------------------------------------------------------------------*/ - if ( exp < 0x3FFF ) { - if ( !((uiA64 & UINT64_C( 0x7FFFFFFFFFFFFFFF )) | uiA0) ) return a; - if ( exact ) softfloat_exceptionFlags |= softfloat_flag_inexact; - uiZ.v64 = uiA64 & packToF128UI64( 1, 0, 0 ); - uiZ.v0 = 0; - switch ( roundingMode ) { - case softfloat_round_near_even: - if ( !(fracF128UI64( uiA64 ) | uiA0) ) break; - case softfloat_round_near_maxMag: - if ( exp == 0x3FFE ) uiZ.v64 |= packToF128UI64( 0, 0x3FFF, 0 ); - break; - case softfloat_round_min: - if ( uiZ.v64 ) uiZ.v64 = packToF128UI64( 1, 0x3FFF, 0 ); - break; - case softfloat_round_max: - if ( !uiZ.v64 ) uiZ.v64 = packToF128UI64( 0, 0x3FFF, 0 ); - break; -#ifdef SOFTFLOAT_ROUND_ODD - case softfloat_round_odd: - uiZ.v64 |= packToF128UI64( 0, 0x3FFF, 0 ); - break; -#endif - } - goto uiZ; - } - /*-------------------------------------------------------------------- - *--------------------------------------------------------------------*/ - uiZ.v64 = uiA64; - uiZ.v0 = 0; - lastBitMask64 = (uint_fast64_t) 1<<(0x402F - exp); - roundBitsMask = lastBitMask64 - 1; - if ( roundingMode == softfloat_round_near_maxMag ) { - uiZ.v64 += lastBitMask64>>1; - } else if ( roundingMode == softfloat_round_near_even ) { - uiZ.v64 += lastBitMask64>>1; - if ( !((uiZ.v64 & roundBitsMask) | uiA0) ) { - uiZ.v64 &= ~lastBitMask64; - } - } else if ( - roundingMode - == (signF128UI64( uiZ.v64 ) ? softfloat_round_min - : softfloat_round_max) - ) { - uiZ.v64 = (uiZ.v64 | (uiA0 != 0)) + roundBitsMask; - } - uiZ.v64 &= ~roundBitsMask; - lastBitMask0 = 0; - } - if ( (uiZ.v64 != uiA64) || (uiZ.v0 != uiA0) ) { -#ifdef SOFTFLOAT_ROUND_ODD - if ( roundingMode == softfloat_round_odd ) { - uiZ.v64 |= lastBitMask64; - uiZ.v0 |= lastBitMask0; - } -#endif - if ( exact ) softfloat_exceptionFlags |= softfloat_flag_inexact; - } - uiZ: - uZ.ui = uiZ; - return uZ.f; - -} - diff --git a/deps/SoftFloat-3e/source/f128_sqrt.c b/deps/SoftFloat-3e/source/f128_sqrt.c deleted file mode 100644 index f1d9bac79287..000000000000 --- a/deps/SoftFloat-3e/source/f128_sqrt.c +++ /dev/null @@ -1,201 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017 The Regents of the -University of California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -float128_t f128_sqrt( float128_t a ) -{ - union ui128_f128 uA; - uint_fast64_t uiA64, uiA0; - bool signA; - int_fast32_t expA; - struct uint128 sigA, uiZ; - struct exp32_sig128 normExpSig; - int_fast32_t expZ; - uint_fast32_t sig32A, recipSqrt32, sig32Z; - struct uint128 rem; - uint32_t qs[3]; - uint_fast32_t q; - uint_fast64_t x64, sig64Z; - struct uint128 y, term; - uint_fast64_t sigZExtra; - struct uint128 sigZ; - union ui128_f128 uZ; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uA.f = a; - uiA64 = uA.ui.v64; - uiA0 = uA.ui.v0; - signA = signF128UI64( uiA64 ); - expA = expF128UI64( uiA64 ); - sigA.v64 = fracF128UI64( uiA64 ); - sigA.v0 = uiA0; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( expA == 0x7FFF ) { - if ( sigA.v64 | sigA.v0 ) { - uiZ = softfloat_propagateNaNF128UI( uiA64, uiA0, 0, 0 ); - goto uiZ; - } - if ( ! signA ) return a; - goto invalid; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( signA ) { - if ( ! (expA | sigA.v64 | sigA.v0) ) return a; - goto invalid; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( ! expA ) { - if ( ! (sigA.v64 | sigA.v0) ) return a; - normExpSig = softfloat_normSubnormalF128Sig( sigA.v64, sigA.v0 ); - expA = normExpSig.exp; - sigA = normExpSig.sig; - } - /*------------------------------------------------------------------------ - | (`sig32Z' is guaranteed to be a lower bound on the square root of - | `sig32A', which makes `sig32Z' also a lower bound on the square root of - | `sigA'.) - *------------------------------------------------------------------------*/ - expZ = ((expA - 0x3FFF)>>1) + 0x3FFE; - expA &= 1; - sigA.v64 |= UINT64_C( 0x0001000000000000 ); - sig32A = sigA.v64>>17; - recipSqrt32 = softfloat_approxRecipSqrt32_1( expA, sig32A ); - sig32Z = ((uint_fast64_t) sig32A * recipSqrt32)>>32; - if ( expA ) { - sig32Z >>= 1; - rem = softfloat_shortShiftLeft128( sigA.v64, sigA.v0, 12 ); - } else { - rem = softfloat_shortShiftLeft128( sigA.v64, sigA.v0, 13 ); - } - qs[2] = sig32Z; - rem.v64 -= (uint_fast64_t) sig32Z * sig32Z; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - q = ((uint32_t) (rem.v64>>2) * (uint_fast64_t) recipSqrt32)>>32; - x64 = (uint_fast64_t) sig32Z<<32; - sig64Z = x64 + ((uint_fast64_t) q<<3); - y = softfloat_shortShiftLeft128( rem.v64, rem.v0, 29 ); - /*------------------------------------------------------------------------ - | (Repeating this loop is a rare occurrence.) - *------------------------------------------------------------------------*/ - for (;;) { - term = softfloat_mul64ByShifted32To128( x64 + sig64Z, q ); - rem = softfloat_sub128( y.v64, y.v0, term.v64, term.v0 ); - if ( ! (rem.v64 & UINT64_C( 0x8000000000000000 )) ) break; - --q; - sig64Z -= 1<<3; - } - qs[1] = q; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - q = ((rem.v64>>2) * recipSqrt32)>>32; - y = softfloat_shortShiftLeft128( rem.v64, rem.v0, 29 ); - sig64Z <<= 1; - /*------------------------------------------------------------------------ - | (Repeating this loop is a rare occurrence.) - *------------------------------------------------------------------------*/ - for (;;) { - term = softfloat_shortShiftLeft128( 0, sig64Z, 32 ); - term = softfloat_add128( term.v64, term.v0, 0, (uint_fast64_t) q<<6 ); - term = softfloat_mul128By32( term.v64, term.v0, q ); - rem = softfloat_sub128( y.v64, y.v0, term.v64, term.v0 ); - if ( ! (rem.v64 & UINT64_C( 0x8000000000000000 )) ) break; - --q; - } - qs[0] = q; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - q = (((rem.v64>>2) * recipSqrt32)>>32) + 2; - sigZExtra = (uint64_t) ((uint_fast64_t) q<<59); - term = softfloat_shortShiftLeft128( 0, qs[1], 53 ); - sigZ = - softfloat_add128( - (uint_fast64_t) qs[2]<<18, ((uint_fast64_t) qs[0]<<24) + (q>>5), - term.v64, term.v0 - ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( (q & 0xF) <= 2 ) { - q &= ~3; - sigZExtra = (uint64_t) ((uint_fast64_t) q<<59); - y = softfloat_shortShiftLeft128( sigZ.v64, sigZ.v0, 6 ); - y.v0 |= sigZExtra>>58; - term = softfloat_sub128( y.v64, y.v0, 0, q ); - y = softfloat_mul64ByShifted32To128( term.v0, q ); - term = softfloat_mul64ByShifted32To128( term.v64, q ); - term = softfloat_add128( term.v64, term.v0, 0, y.v64 ); - rem = softfloat_shortShiftLeft128( rem.v64, rem.v0, 20 ); - term = softfloat_sub128( term.v64, term.v0, rem.v64, rem.v0 ); - /*-------------------------------------------------------------------- - | The concatenation of `term' and `y.v0' is now the negative remainder - | (3 words altogether). - *--------------------------------------------------------------------*/ - if ( term.v64 & UINT64_C( 0x8000000000000000 ) ) { - sigZExtra |= 1; - } else { - if ( term.v64 | term.v0 | y.v0 ) { - if ( sigZExtra ) { - --sigZExtra; - } else { - sigZ = softfloat_sub128( sigZ.v64, sigZ.v0, 0, 1 ); - sigZExtra = ~0; - } - } - } - } - return softfloat_roundPackToF128( 0, expZ, sigZ.v64, sigZ.v0, sigZExtra ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - invalid: - softfloat_raiseFlags( softfloat_flag_invalid ); - uiZ.v64 = defaultNaNF128UI64; - uiZ.v0 = defaultNaNF128UI0; - uiZ: - uZ.ui = uiZ; - return uZ.f; - -} - diff --git a/deps/SoftFloat-3e/source/f128_sub.c b/deps/SoftFloat-3e/source/f128_sub.c deleted file mode 100644 index 5181cc5ecd1f..000000000000 --- a/deps/SoftFloat-3e/source/f128_sub.c +++ /dev/null @@ -1,78 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "softfloat.h" - -float128_t f128_sub( float128_t a, float128_t b ) -{ - union ui128_f128 uA; - uint_fast64_t uiA64, uiA0; - bool signA; - union ui128_f128 uB; - uint_fast64_t uiB64, uiB0; - bool signB; -#if ! defined INLINE_LEVEL || (INLINE_LEVEL < 2) - float128_t - (*magsFuncPtr)( - uint_fast64_t, uint_fast64_t, uint_fast64_t, uint_fast64_t, bool ); -#endif - - uA.f = a; - uiA64 = uA.ui.v64; - uiA0 = uA.ui.v0; - signA = signF128UI64( uiA64 ); - uB.f = b; - uiB64 = uB.ui.v64; - uiB0 = uB.ui.v0; - signB = signF128UI64( uiB64 ); -#if defined INLINE_LEVEL && (2 <= INLINE_LEVEL) - if ( signA == signB ) { - return softfloat_subMagsF128( uiA64, uiA0, uiB64, uiB0, signA ); - } else { - return softfloat_addMagsF128( uiA64, uiA0, uiB64, uiB0, signA ); - } -#else - magsFuncPtr = - (signA == signB) ? softfloat_subMagsF128 : softfloat_addMagsF128; - return (*magsFuncPtr)( uiA64, uiA0, uiB64, uiB0, signA ); -#endif - -} - diff --git a/deps/SoftFloat-3e/source/f128_to_extF80.c b/deps/SoftFloat-3e/source/f128_to_extF80.c deleted file mode 100644 index ec169c0ffaea..000000000000 --- a/deps/SoftFloat-3e/source/f128_to_extF80.c +++ /dev/null @@ -1,109 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -extFloat80_t f128_to_extF80( float128_t a ) -{ - union ui128_f128 uA; - uint_fast64_t uiA64, uiA0; - bool sign; - int_fast32_t exp; - uint_fast64_t frac64, frac0; - struct commonNaN commonNaN; - struct uint128 uiZ; - uint_fast16_t uiZ64; - uint_fast64_t uiZ0; - struct exp32_sig128 normExpSig; - struct uint128 sig128; - union { struct extFloat80M s; extFloat80_t f; } uZ; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uA.f = a; - uiA64 = uA.ui.v64; - uiA0 = uA.ui.v0; - sign = signF128UI64( uiA64 ); - exp = expF128UI64( uiA64 ); - frac64 = fracF128UI64( uiA64 ); - frac0 = uiA0; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( exp == 0x7FFF ) { - if ( frac64 | frac0 ) { - softfloat_f128UIToCommonNaN( uiA64, uiA0, &commonNaN ); - uiZ = softfloat_commonNaNToExtF80UI( &commonNaN ); - uiZ64 = uiZ.v64; - uiZ0 = uiZ.v0; - } else { - uiZ64 = packToExtF80UI64( sign, 0x7FFF ); - uiZ0 = UINT64_C( 0x8000000000000000 ); - } - goto uiZ; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( ! exp ) { - if ( ! (frac64 | frac0) ) { - uiZ64 = packToExtF80UI64( sign, 0 ); - uiZ0 = 0; - goto uiZ; - } - normExpSig = softfloat_normSubnormalF128Sig( frac64, frac0 ); - exp = normExpSig.exp; - frac64 = normExpSig.sig.v64; - frac0 = normExpSig.sig.v0; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - sig128 = - softfloat_shortShiftLeft128( - frac64 | UINT64_C( 0x0001000000000000 ), frac0, 15 ); - return softfloat_roundPackToExtF80( sign, exp, sig128.v64, sig128.v0, 80 ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uiZ: - uZ.s.signExp = uiZ64; - uZ.s.signif = uiZ0; - return uZ.f; - -} - diff --git a/deps/SoftFloat-3e/source/f128_to_f16.c b/deps/SoftFloat-3e/source/f128_to_f16.c deleted file mode 100644 index 5a8ee721297b..000000000000 --- a/deps/SoftFloat-3e/source/f128_to_f16.c +++ /dev/null @@ -1,95 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -float16_t f128_to_f16( float128_t a ) -{ - union ui128_f128 uA; - uint_fast64_t uiA64, uiA0; - bool sign; - int_fast32_t exp; - uint_fast64_t frac64; - struct commonNaN commonNaN; - uint_fast16_t uiZ, frac16; - union ui16_f16 uZ; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uA.f = a; - uiA64 = uA.ui.v64; - uiA0 = uA.ui.v0; - sign = signF128UI64( uiA64 ); - exp = expF128UI64( uiA64 ); - frac64 = fracF128UI64( uiA64 ) | (uiA0 != 0); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( exp == 0x7FFF ) { - if ( frac64 ) { - softfloat_f128UIToCommonNaN( uiA64, uiA0, &commonNaN ); - uiZ = softfloat_commonNaNToF16UI( &commonNaN ); - } else { - uiZ = packToF16UI( sign, 0x1F, 0 ); - } - goto uiZ; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - frac16 = softfloat_shortShiftRightJam64( frac64, 34 ); - if ( ! (exp | frac16) ) { - uiZ = packToF16UI( sign, 0, 0 ); - goto uiZ; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - exp -= 0x3FF1; - if ( sizeof (int_fast16_t) < sizeof (int_fast32_t) ) { - if ( exp < -0x40 ) exp = -0x40; - } - return softfloat_roundPackToF16( sign, exp, frac16 | 0x4000 ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uiZ: - uZ.ui = uiZ; - return uZ.f; - -} - diff --git a/deps/SoftFloat-3e/source/f128_to_f32.c b/deps/SoftFloat-3e/source/f128_to_f32.c deleted file mode 100644 index 07e4a80df65d..000000000000 --- a/deps/SoftFloat-3e/source/f128_to_f32.c +++ /dev/null @@ -1,95 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -float32_t f128_to_f32( float128_t a ) -{ - union ui128_f128 uA; - uint_fast64_t uiA64, uiA0; - bool sign; - int_fast32_t exp; - uint_fast64_t frac64; - struct commonNaN commonNaN; - uint_fast32_t uiZ, frac32; - union ui32_f32 uZ; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uA.f = a; - uiA64 = uA.ui.v64; - uiA0 = uA.ui.v0; - sign = signF128UI64( uiA64 ); - exp = expF128UI64( uiA64 ); - frac64 = fracF128UI64( uiA64 ) | (uiA0 != 0); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( exp == 0x7FFF ) { - if ( frac64 ) { - softfloat_f128UIToCommonNaN( uiA64, uiA0, &commonNaN ); - uiZ = softfloat_commonNaNToF32UI( &commonNaN ); - } else { - uiZ = packToF32UI( sign, 0xFF, 0 ); - } - goto uiZ; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - frac32 = softfloat_shortShiftRightJam64( frac64, 18 ); - if ( ! (exp | frac32) ) { - uiZ = packToF32UI( sign, 0, 0 ); - goto uiZ; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - exp -= 0x3F81; - if ( sizeof (int_fast16_t) < sizeof (int_fast32_t) ) { - if ( exp < -0x1000 ) exp = -0x1000; - } - return softfloat_roundPackToF32( sign, exp, frac32 | 0x40000000 ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uiZ: - uZ.ui = uiZ; - return uZ.f; - -} - diff --git a/deps/SoftFloat-3e/source/f128_to_f64.c b/deps/SoftFloat-3e/source/f128_to_f64.c deleted file mode 100644 index f791938b4190..000000000000 --- a/deps/SoftFloat-3e/source/f128_to_f64.c +++ /dev/null @@ -1,100 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -float64_t f128_to_f64( float128_t a ) -{ - union ui128_f128 uA; - uint_fast64_t uiA64, uiA0; - bool sign; - int_fast32_t exp; - uint_fast64_t frac64, frac0; - struct commonNaN commonNaN; - uint_fast64_t uiZ; - struct uint128 frac128; - union ui64_f64 uZ; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uA.f = a; - uiA64 = uA.ui.v64; - uiA0 = uA.ui.v0; - sign = signF128UI64( uiA64 ); - exp = expF128UI64( uiA64 ); - frac64 = fracF128UI64( uiA64 ); - frac0 = uiA0; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( exp == 0x7FFF ) { - if ( frac64 | frac0 ) { - softfloat_f128UIToCommonNaN( uiA64, uiA0, &commonNaN ); - uiZ = softfloat_commonNaNToF64UI( &commonNaN ); - } else { - uiZ = packToF64UI( sign, 0x7FF, 0 ); - } - goto uiZ; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - frac128 = softfloat_shortShiftLeft128( frac64, frac0, 14 ); - frac64 = frac128.v64 | (frac128.v0 != 0); - if ( ! (exp | frac64) ) { - uiZ = packToF64UI( sign, 0, 0 ); - goto uiZ; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - exp -= 0x3C01; - if ( sizeof (int_fast16_t) < sizeof (int_fast32_t) ) { - if ( exp < -0x1000 ) exp = -0x1000; - } - return - softfloat_roundPackToF64( - sign, exp, frac64 | UINT64_C( 0x4000000000000000 ) ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uiZ: - uZ.ui = uiZ; - return uZ.f; - -} - diff --git a/deps/SoftFloat-3e/source/f128_to_i32.c b/deps/SoftFloat-3e/source/f128_to_i32.c deleted file mode 100644 index 16c4a3ccdace..000000000000 --- a/deps/SoftFloat-3e/source/f128_to_i32.c +++ /dev/null @@ -1,85 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017 The Regents of the -University of California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -int_fast32_t f128_to_i32( float128_t a, uint_fast8_t roundingMode, bool exact ) -{ - union ui128_f128 uA; - uint_fast64_t uiA64, uiA0; - bool sign; - int_fast32_t exp; - uint_fast64_t sig64, sig0; - int_fast32_t shiftDist; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uA.f = a; - uiA64 = uA.ui.v64; - uiA0 = uA.ui.v0; - sign = signF128UI64( uiA64 ); - exp = expF128UI64( uiA64 ); - sig64 = fracF128UI64( uiA64 ); - sig0 = uiA0; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ -#if (i32_fromNaN != i32_fromPosOverflow) || (i32_fromNaN != i32_fromNegOverflow) - if ( (exp == 0x7FFF) && (sig64 | sig0) ) { -#if (i32_fromNaN == i32_fromPosOverflow) - sign = 0; -#elif (i32_fromNaN == i32_fromNegOverflow) - sign = 1; -#else - softfloat_raiseFlags( softfloat_flag_invalid ); - return i32_fromNaN; -#endif - } -#endif - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( exp ) sig64 |= UINT64_C( 0x0001000000000000 ); - sig64 |= (sig0 != 0); - shiftDist = 0x4023 - exp; - if ( 0 < shiftDist ) sig64 = softfloat_shiftRightJam64( sig64, shiftDist ); - return softfloat_roundToI32( sign, sig64, roundingMode, exact ); - -} - diff --git a/deps/SoftFloat-3e/source/f128_to_i32_r_minMag.c b/deps/SoftFloat-3e/source/f128_to_i32_r_minMag.c deleted file mode 100644 index 18cfeaee5442..000000000000 --- a/deps/SoftFloat-3e/source/f128_to_i32_r_minMag.c +++ /dev/null @@ -1,100 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -int_fast32_t f128_to_i32_r_minMag( float128_t a, bool exact ) -{ - union ui128_f128 uA; - uint_fast64_t uiA64, uiA0; - int_fast32_t exp; - uint_fast64_t sig64; - int_fast32_t shiftDist; - bool sign; - int_fast32_t absZ; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uA.f = a; - uiA64 = uA.ui.v64; - uiA0 = uA.ui.v0; - exp = expF128UI64( uiA64 ); - sig64 = fracF128UI64( uiA64 ) | (uiA0 != 0); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - shiftDist = 0x402F - exp; - if ( 49 <= shiftDist ) { - if ( exact && (exp | sig64) ) { - softfloat_exceptionFlags |= softfloat_flag_inexact; - } - return 0; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - sign = signF128UI64( uiA64 ); - if ( shiftDist < 18 ) { - if ( - sign && (shiftDist == 17) - && (sig64 < UINT64_C( 0x0000000000020000 )) - ) { - if ( exact && sig64 ) { - softfloat_exceptionFlags |= softfloat_flag_inexact; - } - return -0x7FFFFFFF - 1; - } - softfloat_raiseFlags( softfloat_flag_invalid ); - return - (exp == 0x7FFF) && sig64 ? i32_fromNaN - : sign ? i32_fromNegOverflow : i32_fromPosOverflow; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - sig64 |= UINT64_C( 0x0001000000000000 ); - absZ = sig64>>shiftDist; - if ( - exact && ((uint_fast64_t) (uint_fast32_t) absZ< -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -int_fast64_t f128_to_i64( float128_t a, uint_fast8_t roundingMode, bool exact ) -{ - union ui128_f128 uA; - uint_fast64_t uiA64, uiA0; - bool sign; - int_fast32_t exp; - uint_fast64_t sig64, sig0; - int_fast32_t shiftDist; - struct uint128 sig128; - struct uint64_extra sigExtra; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uA.f = a; - uiA64 = uA.ui.v64; - uiA0 = uA.ui.v0; - sign = signF128UI64( uiA64 ); - exp = expF128UI64( uiA64 ); - sig64 = fracF128UI64( uiA64 ); - sig0 = uiA0; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - shiftDist = 0x402F - exp; - if ( shiftDist <= 0 ) { - /*-------------------------------------------------------------------- - *--------------------------------------------------------------------*/ - if ( shiftDist < -15 ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - return - (exp == 0x7FFF) && (sig64 | sig0) ? i64_fromNaN - : sign ? i64_fromNegOverflow : i64_fromPosOverflow; - } - /*-------------------------------------------------------------------- - *--------------------------------------------------------------------*/ - sig64 |= UINT64_C( 0x0001000000000000 ); - if ( shiftDist ) { - sig128 = softfloat_shortShiftLeft128( sig64, sig0, -shiftDist ); - sig64 = sig128.v64; - sig0 = sig128.v0; - } - } else { - /*-------------------------------------------------------------------- - *--------------------------------------------------------------------*/ - if ( exp ) sig64 |= UINT64_C( 0x0001000000000000 ); - sigExtra = softfloat_shiftRightJam64Extra( sig64, sig0, shiftDist ); - sig64 = sigExtra.v; - sig0 = sigExtra.extra; - } - return softfloat_roundToI64( sign, sig64, sig0, roundingMode, exact ); - -} - diff --git a/deps/SoftFloat-3e/source/f128_to_i64_r_minMag.c b/deps/SoftFloat-3e/source/f128_to_i64_r_minMag.c deleted file mode 100644 index e2cc62e27ebe..000000000000 --- a/deps/SoftFloat-3e/source/f128_to_i64_r_minMag.c +++ /dev/null @@ -1,113 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -int_fast64_t f128_to_i64_r_minMag( float128_t a, bool exact ) -{ - union ui128_f128 uA; - uint_fast64_t uiA64, uiA0; - bool sign; - int_fast32_t exp; - uint_fast64_t sig64, sig0; - int_fast32_t shiftDist; - int_fast8_t negShiftDist; - int_fast64_t absZ; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uA.f = a; - uiA64 = uA.ui.v64; - uiA0 = uA.ui.v0; - sign = signF128UI64( uiA64 ); - exp = expF128UI64( uiA64 ); - sig64 = fracF128UI64( uiA64 ); - sig0 = uiA0; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - shiftDist = 0x402F - exp; - if ( shiftDist < 0 ) { - /*-------------------------------------------------------------------- - *--------------------------------------------------------------------*/ - if ( shiftDist < -14 ) { - if ( - (uiA64 == UINT64_C( 0xC03E000000000000 )) - && (sig0 < UINT64_C( 0x0002000000000000 )) - ) { - if ( exact && sig0 ) { - softfloat_exceptionFlags |= softfloat_flag_inexact; - } - return -INT64_C( 0x7FFFFFFFFFFFFFFF ) - 1; - } - softfloat_raiseFlags( softfloat_flag_invalid ); - return - (exp == 0x7FFF) && (sig64 | sig0) ? i64_fromNaN - : sign ? i64_fromNegOverflow : i64_fromPosOverflow; - } - /*-------------------------------------------------------------------- - *--------------------------------------------------------------------*/ - sig64 |= UINT64_C( 0x0001000000000000 ); - negShiftDist = -shiftDist; - absZ = sig64<>(shiftDist & 63); - if ( exact && (uint64_t) (sig0<>shiftDist; - if ( exact && (sig0 || (absZ< -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -uint_fast32_t - f128_to_ui32( float128_t a, uint_fast8_t roundingMode, bool exact ) -{ - union ui128_f128 uA; - uint_fast64_t uiA64, uiA0; - bool sign; - int_fast32_t exp; - uint_fast64_t sig64; - int_fast32_t shiftDist; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uA.f = a; - uiA64 = uA.ui.v64; - uiA0 = uA.ui.v0; - sign = signF128UI64( uiA64 ); - exp = expF128UI64( uiA64 ); - sig64 = fracF128UI64( uiA64 ) | (uiA0 != 0); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ -#if (ui32_fromNaN != ui32_fromPosOverflow) || (ui32_fromNaN != ui32_fromNegOverflow) - if ( (exp == 0x7FFF) && sig64 ) { -#if (ui32_fromNaN == ui32_fromPosOverflow) - sign = 0; -#elif (ui32_fromNaN == ui32_fromNegOverflow) - sign = 1; -#else - softfloat_raiseFlags( softfloat_flag_invalid ); - return ui32_fromNaN; -#endif - } -#endif - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( exp ) sig64 |= UINT64_C( 0x0001000000000000 ); - shiftDist = 0x4023 - exp; - if ( 0 < shiftDist ) { - sig64 = softfloat_shiftRightJam64( sig64, shiftDist ); - } - return softfloat_roundToUI32( sign, sig64, roundingMode, exact ); - -} - diff --git a/deps/SoftFloat-3e/source/f128_to_ui32_r_minMag.c b/deps/SoftFloat-3e/source/f128_to_ui32_r_minMag.c deleted file mode 100644 index 92facd517819..000000000000 --- a/deps/SoftFloat-3e/source/f128_to_ui32_r_minMag.c +++ /dev/null @@ -1,89 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -uint_fast32_t f128_to_ui32_r_minMag( float128_t a, bool exact ) -{ - union ui128_f128 uA; - uint_fast64_t uiA64, uiA0; - int_fast32_t exp; - uint_fast64_t sig64; - int_fast32_t shiftDist; - bool sign; - uint_fast32_t z; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uA.f = a; - uiA64 = uA.ui.v64; - uiA0 = uA.ui.v0; - exp = expF128UI64( uiA64 ); - sig64 = fracF128UI64( uiA64 ) | (uiA0 != 0); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - shiftDist = 0x402F - exp; - if ( 49 <= shiftDist ) { - if ( exact && (exp | sig64) ) { - softfloat_exceptionFlags |= softfloat_flag_inexact; - } - return 0; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - sign = signF128UI64( uiA64 ); - if ( sign || (shiftDist < 17) ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - return - (exp == 0x7FFF) && sig64 ? ui32_fromNaN - : sign ? ui32_fromNegOverflow : ui32_fromPosOverflow; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - sig64 |= UINT64_C( 0x0001000000000000 ); - z = sig64>>shiftDist; - if ( exact && ((uint_fast64_t) z< -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -uint_fast64_t - f128_to_ui64( float128_t a, uint_fast8_t roundingMode, bool exact ) -{ - union ui128_f128 uA; - uint_fast64_t uiA64, uiA0; - bool sign; - int_fast32_t exp; - uint_fast64_t sig64, sig0; - int_fast32_t shiftDist; - struct uint128 sig128; - struct uint64_extra sigExtra; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uA.f = a; - uiA64 = uA.ui.v64; - uiA0 = uA.ui.v0; - sign = signF128UI64( uiA64 ); - exp = expF128UI64( uiA64 ); - sig64 = fracF128UI64( uiA64 ); - sig0 = uiA0; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - shiftDist = 0x402F - exp; - if ( shiftDist <= 0 ) { - /*-------------------------------------------------------------------- - *--------------------------------------------------------------------*/ - if ( shiftDist < -15 ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - return - (exp == 0x7FFF) && (sig64 | sig0) ? ui64_fromNaN - : sign ? ui64_fromNegOverflow : ui64_fromPosOverflow; - } - /*-------------------------------------------------------------------- - *--------------------------------------------------------------------*/ - sig64 |= UINT64_C( 0x0001000000000000 ); - if ( shiftDist ) { - sig128 = softfloat_shortShiftLeft128( sig64, sig0, -shiftDist ); - sig64 = sig128.v64; - sig0 = sig128.v0; - } - } else { - /*-------------------------------------------------------------------- - *--------------------------------------------------------------------*/ - if ( exp ) sig64 |= UINT64_C( 0x0001000000000000 ); - sigExtra = softfloat_shiftRightJam64Extra( sig64, sig0, shiftDist ); - sig64 = sigExtra.v; - sig0 = sigExtra.extra; - } - return softfloat_roundToUI64( sign, sig64, sig0, roundingMode, exact ); - -} - diff --git a/deps/SoftFloat-3e/source/f128_to_ui64_r_minMag.c b/deps/SoftFloat-3e/source/f128_to_ui64_r_minMag.c deleted file mode 100644 index edeafd3c814b..000000000000 --- a/deps/SoftFloat-3e/source/f128_to_ui64_r_minMag.c +++ /dev/null @@ -1,105 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -uint_fast64_t f128_to_ui64_r_minMag( float128_t a, bool exact ) -{ - union ui128_f128 uA; - uint_fast64_t uiA64, uiA0; - bool sign; - int_fast32_t exp; - uint_fast64_t sig64, sig0; - int_fast32_t shiftDist; - int_fast8_t negShiftDist; - uint_fast64_t z; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uA.f = a; - uiA64 = uA.ui.v64; - uiA0 = uA.ui.v0; - sign = signF128UI64( uiA64 ); - exp = expF128UI64( uiA64 ); - sig64 = fracF128UI64( uiA64 ); - sig0 = uiA0; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - shiftDist = 0x402F - exp; - if ( shiftDist < 0 ) { - /*-------------------------------------------------------------------- - *--------------------------------------------------------------------*/ - if ( sign || (shiftDist < -15) ) goto invalid; - sig64 |= UINT64_C( 0x0001000000000000 ); - negShiftDist = -shiftDist; - z = sig64<>(shiftDist & 63); - if ( exact && (uint64_t) (sig0<>shiftDist; - if ( exact && (sig0 || (z< -#include -#include "platform.h" -#include "internals.h" -#include "softfloat.h" - -float16_t f16_add( float16_t a, float16_t b ) -{ - union ui16_f16 uA; - uint_fast16_t uiA; - union ui16_f16 uB; - uint_fast16_t uiB; -#if ! defined INLINE_LEVEL || (INLINE_LEVEL < 1) - float16_t (*magsFuncPtr)( uint_fast16_t, uint_fast16_t ); -#endif - - uA.f = a; - uiA = uA.ui; - uB.f = b; - uiB = uB.ui; -#if defined INLINE_LEVEL && (1 <= INLINE_LEVEL) - if ( signF16UI( uiA ^ uiB ) ) { - return softfloat_subMagsF16( uiA, uiB ); - } else { - return softfloat_addMagsF16( uiA, uiB ); - } -#else - magsFuncPtr = - signF16UI( uiA ^ uiB ) ? softfloat_subMagsF16 : softfloat_addMagsF16; - return (*magsFuncPtr)( uiA, uiB ); -#endif - -} - diff --git a/deps/SoftFloat-3e/source/f16_div.c b/deps/SoftFloat-3e/source/f16_div.c deleted file mode 100644 index 77f9a2cd2b89..000000000000 --- a/deps/SoftFloat-3e/source/f16_div.c +++ /dev/null @@ -1,186 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -extern const uint16_t softfloat_approxRecip_1k0s[]; -extern const uint16_t softfloat_approxRecip_1k1s[]; - -float16_t f16_div( float16_t a, float16_t b ) -{ - union ui16_f16 uA; - uint_fast16_t uiA; - bool signA; - int_fast8_t expA; - uint_fast16_t sigA; - union ui16_f16 uB; - uint_fast16_t uiB; - bool signB; - int_fast8_t expB; - uint_fast16_t sigB; - bool signZ; - struct exp8_sig16 normExpSig; - int_fast8_t expZ; -#ifdef SOFTFLOAT_FAST_DIV32TO16 - uint_fast32_t sig32A; - uint_fast16_t sigZ; -#else - int index; - uint16_t r0; - uint_fast16_t sigZ, rem; -#endif - uint_fast16_t uiZ; - union ui16_f16 uZ; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uA.f = a; - uiA = uA.ui; - signA = signF16UI( uiA ); - expA = expF16UI( uiA ); - sigA = fracF16UI( uiA ); - uB.f = b; - uiB = uB.ui; - signB = signF16UI( uiB ); - expB = expF16UI( uiB ); - sigB = fracF16UI( uiB ); - signZ = signA ^ signB; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( expA == 0x1F ) { - if ( sigA ) goto propagateNaN; - if ( expB == 0x1F ) { - if ( sigB ) goto propagateNaN; - goto invalid; - } - goto infinity; - } - if ( expB == 0x1F ) { - if ( sigB ) goto propagateNaN; - goto zero; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( ! expB ) { - if ( ! sigB ) { - if ( ! (expA | sigA) ) goto invalid; - softfloat_raiseFlags( softfloat_flag_infinite ); - goto infinity; - } - normExpSig = softfloat_normSubnormalF16Sig( sigB ); - expB = normExpSig.exp; - sigB = normExpSig.sig; - } - if ( ! expA ) { - if ( ! sigA ) goto zero; - normExpSig = softfloat_normSubnormalF16Sig( sigA ); - expA = normExpSig.exp; - sigA = normExpSig.sig; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - expZ = expA - expB + 0xE; - sigA |= 0x0400; - sigB |= 0x0400; -#ifdef SOFTFLOAT_FAST_DIV32TO16 - if ( sigA < sigB ) { - --expZ; - sig32A = (uint_fast32_t) sigA<<15; - } else { - sig32A = (uint_fast32_t) sigA<<14; - } - sigZ = sig32A / sigB; - if ( ! (sigZ & 7) ) sigZ |= ((uint_fast32_t) sigB * sigZ != sig32A); -#else - if ( sigA < sigB ) { - --expZ; - sigA <<= 5; - } else { - sigA <<= 4; - } - index = sigB>>6 & 0xF; - r0 = softfloat_approxRecip_1k0s[index] - - (((uint_fast32_t) softfloat_approxRecip_1k1s[index] - * (sigB & 0x3F)) - >>10); - sigZ = ((uint_fast32_t) sigA * r0)>>16; - rem = (sigA<<10) - sigZ * sigB; - sigZ += (rem * (uint_fast32_t) r0)>>26; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - ++sigZ; - if ( ! (sigZ & 7) ) { - sigZ &= ~1; - rem = (sigA<<10) - sigZ * sigB; - if ( rem & 0x8000 ) { - sigZ -= 2; - } else { - if ( rem ) sigZ |= 1; - } - } -#endif - return softfloat_roundPackToF16( signZ, expZ, sigZ ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - propagateNaN: - uiZ = softfloat_propagateNaNF16UI( uiA, uiB ); - goto uiZ; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - invalid: - softfloat_raiseFlags( softfloat_flag_invalid ); - uiZ = defaultNaNF16UI; - goto uiZ; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - infinity: - uiZ = packToF16UI( signZ, 0x1F, 0 ); - goto uiZ; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - zero: - uiZ = packToF16UI( signZ, 0, 0 ); - uiZ: - uZ.ui = uiZ; - return uZ.f; - -} - diff --git a/deps/SoftFloat-3e/source/f16_eq.c b/deps/SoftFloat-3e/source/f16_eq.c deleted file mode 100644 index 692fa035f94b..000000000000 --- a/deps/SoftFloat-3e/source/f16_eq.c +++ /dev/null @@ -1,66 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -bool f16_eq( float16_t a, float16_t b ) -{ - union ui16_f16 uA; - uint_fast16_t uiA; - union ui16_f16 uB; - uint_fast16_t uiB; - - uA.f = a; - uiA = uA.ui; - uB.f = b; - uiB = uB.ui; - if ( isNaNF16UI( uiA ) || isNaNF16UI( uiB ) ) { - if ( - softfloat_isSigNaNF16UI( uiA ) || softfloat_isSigNaNF16UI( uiB ) - ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - } - return false; - } - return (uiA == uiB) || ! (uint16_t) ((uiA | uiB)<<1); - -} - diff --git a/deps/SoftFloat-3e/source/f16_eq_signaling.c b/deps/SoftFloat-3e/source/f16_eq_signaling.c deleted file mode 100644 index c1e7a509ca90..000000000000 --- a/deps/SoftFloat-3e/source/f16_eq_signaling.c +++ /dev/null @@ -1,61 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "softfloat.h" - -bool f16_eq_signaling( float16_t a, float16_t b ) -{ - union ui16_f16 uA; - uint_fast16_t uiA; - union ui16_f16 uB; - uint_fast16_t uiB; - - uA.f = a; - uiA = uA.ui; - uB.f = b; - uiB = uB.ui; - if ( isNaNF16UI( uiA ) || isNaNF16UI( uiB ) ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - return false; - } - return (uiA == uiB) || ! (uint16_t) ((uiA | uiB)<<1); - -} - diff --git a/deps/SoftFloat-3e/source/f16_isSignalingNaN.c b/deps/SoftFloat-3e/source/f16_isSignalingNaN.c deleted file mode 100644 index 3eb3d4cc6bab..000000000000 --- a/deps/SoftFloat-3e/source/f16_isSignalingNaN.c +++ /dev/null @@ -1,51 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -bool f16_isSignalingNaN( float16_t a ) -{ - union ui16_f16 uA; - - uA.f = a; - return softfloat_isSigNaNF16UI( uA.ui ); - -} - diff --git a/deps/SoftFloat-3e/source/f16_le.c b/deps/SoftFloat-3e/source/f16_le.c deleted file mode 100644 index d7313debd54e..000000000000 --- a/deps/SoftFloat-3e/source/f16_le.c +++ /dev/null @@ -1,66 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "softfloat.h" - -bool f16_le( float16_t a, float16_t b ) -{ - union ui16_f16 uA; - uint_fast16_t uiA; - union ui16_f16 uB; - uint_fast16_t uiB; - bool signA, signB; - - uA.f = a; - uiA = uA.ui; - uB.f = b; - uiB = uB.ui; - if ( isNaNF16UI( uiA ) || isNaNF16UI( uiB ) ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - return false; - } - signA = signF16UI( uiA ); - signB = signF16UI( uiB ); - return - (signA != signB) ? signA || ! (uint16_t) ((uiA | uiB)<<1) - : (uiA == uiB) || (signA ^ (uiA < uiB)); - -} - diff --git a/deps/SoftFloat-3e/source/f16_le_quiet.c b/deps/SoftFloat-3e/source/f16_le_quiet.c deleted file mode 100644 index 15181c2602f6..000000000000 --- a/deps/SoftFloat-3e/source/f16_le_quiet.c +++ /dev/null @@ -1,71 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -bool f16_le_quiet( float16_t a, float16_t b ) -{ - union ui16_f16 uA; - uint_fast16_t uiA; - union ui16_f16 uB; - uint_fast16_t uiB; - bool signA, signB; - - uA.f = a; - uiA = uA.ui; - uB.f = b; - uiB = uB.ui; - if ( isNaNF16UI( uiA ) || isNaNF16UI( uiB ) ) { - if ( - softfloat_isSigNaNF16UI( uiA ) || softfloat_isSigNaNF16UI( uiB ) - ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - } - return false; - } - signA = signF16UI( uiA ); - signB = signF16UI( uiB ); - return - (signA != signB) ? signA || ! (uint16_t) ((uiA | uiB)<<1) - : (uiA == uiB) || (signA ^ (uiA < uiB)); - -} - diff --git a/deps/SoftFloat-3e/source/f16_lt.c b/deps/SoftFloat-3e/source/f16_lt.c deleted file mode 100644 index 7745699a2c0a..000000000000 --- a/deps/SoftFloat-3e/source/f16_lt.c +++ /dev/null @@ -1,66 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "softfloat.h" - -bool f16_lt( float16_t a, float16_t b ) -{ - union ui16_f16 uA; - uint_fast16_t uiA; - union ui16_f16 uB; - uint_fast16_t uiB; - bool signA, signB; - - uA.f = a; - uiA = uA.ui; - uB.f = b; - uiB = uB.ui; - if ( isNaNF16UI( uiA ) || isNaNF16UI( uiB ) ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - return false; - } - signA = signF16UI( uiA ); - signB = signF16UI( uiB ); - return - (signA != signB) ? signA && ((uint16_t) ((uiA | uiB)<<1) != 0) - : (uiA != uiB) && (signA ^ (uiA < uiB)); - -} - diff --git a/deps/SoftFloat-3e/source/f16_lt_quiet.c b/deps/SoftFloat-3e/source/f16_lt_quiet.c deleted file mode 100644 index a31e4a13f439..000000000000 --- a/deps/SoftFloat-3e/source/f16_lt_quiet.c +++ /dev/null @@ -1,71 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -bool f16_lt_quiet( float16_t a, float16_t b ) -{ - union ui16_f16 uA; - uint_fast16_t uiA; - union ui16_f16 uB; - uint_fast16_t uiB; - bool signA, signB; - - uA.f = a; - uiA = uA.ui; - uB.f = b; - uiB = uB.ui; - if ( isNaNF16UI( uiA ) || isNaNF16UI( uiB ) ) { - if ( - softfloat_isSigNaNF16UI( uiA ) || softfloat_isSigNaNF16UI( uiB ) - ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - } - return false; - } - signA = signF16UI( uiA ); - signB = signF16UI( uiB ); - return - (signA != signB) ? signA && ((uint16_t) ((uiA | uiB)<<1) != 0) - : (uiA != uiB) && (signA ^ (uiA < uiB)); - -} - diff --git a/deps/SoftFloat-3e/source/f16_mul.c b/deps/SoftFloat-3e/source/f16_mul.c deleted file mode 100644 index a47cab8ce353..000000000000 --- a/deps/SoftFloat-3e/source/f16_mul.c +++ /dev/null @@ -1,140 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -float16_t f16_mul( float16_t a, float16_t b ) -{ - union ui16_f16 uA; - uint_fast16_t uiA; - bool signA; - int_fast8_t expA; - uint_fast16_t sigA; - union ui16_f16 uB; - uint_fast16_t uiB; - bool signB; - int_fast8_t expB; - uint_fast16_t sigB; - bool signZ; - uint_fast16_t magBits; - struct exp8_sig16 normExpSig; - int_fast8_t expZ; - uint_fast32_t sig32Z; - uint_fast16_t sigZ, uiZ; - union ui16_f16 uZ; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uA.f = a; - uiA = uA.ui; - signA = signF16UI( uiA ); - expA = expF16UI( uiA ); - sigA = fracF16UI( uiA ); - uB.f = b; - uiB = uB.ui; - signB = signF16UI( uiB ); - expB = expF16UI( uiB ); - sigB = fracF16UI( uiB ); - signZ = signA ^ signB; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( expA == 0x1F ) { - if ( sigA || ((expB == 0x1F) && sigB) ) goto propagateNaN; - magBits = expB | sigB; - goto infArg; - } - if ( expB == 0x1F ) { - if ( sigB ) goto propagateNaN; - magBits = expA | sigA; - goto infArg; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( ! expA ) { - if ( ! sigA ) goto zero; - normExpSig = softfloat_normSubnormalF16Sig( sigA ); - expA = normExpSig.exp; - sigA = normExpSig.sig; - } - if ( ! expB ) { - if ( ! sigB ) goto zero; - normExpSig = softfloat_normSubnormalF16Sig( sigB ); - expB = normExpSig.exp; - sigB = normExpSig.sig; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - expZ = expA + expB - 0xF; - sigA = (sigA | 0x0400)<<4; - sigB = (sigB | 0x0400)<<5; - sig32Z = (uint_fast32_t) sigA * sigB; - sigZ = sig32Z>>16; - if ( sig32Z & 0xFFFF ) sigZ |= 1; - if ( sigZ < 0x4000 ) { - --expZ; - sigZ <<= 1; - } - return softfloat_roundPackToF16( signZ, expZ, sigZ ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - propagateNaN: - uiZ = softfloat_propagateNaNF16UI( uiA, uiB ); - goto uiZ; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - infArg: - if ( ! magBits ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - uiZ = defaultNaNF16UI; - } else { - uiZ = packToF16UI( signZ, 0x1F, 0 ); - } - goto uiZ; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - zero: - uiZ = packToF16UI( signZ, 0, 0 ); - uiZ: - uZ.ui = uiZ; - return uZ.f; - -} - diff --git a/deps/SoftFloat-3e/source/f16_mulAdd.c b/deps/SoftFloat-3e/source/f16_mulAdd.c deleted file mode 100644 index e97571ac509a..000000000000 --- a/deps/SoftFloat-3e/source/f16_mulAdd.c +++ /dev/null @@ -1,60 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "internals.h" -#include "softfloat.h" - -float16_t f16_mulAdd( float16_t a, float16_t b, float16_t c ) -{ - union ui16_f16 uA; - uint_fast16_t uiA; - union ui16_f16 uB; - uint_fast16_t uiB; - union ui16_f16 uC; - uint_fast16_t uiC; - - uA.f = a; - uiA = uA.ui; - uB.f = b; - uiB = uB.ui; - uC.f = c; - uiC = uC.ui; - return softfloat_mulAddF16( uiA, uiB, uiC, 0 ); - -} - diff --git a/deps/SoftFloat-3e/source/f16_rem.c b/deps/SoftFloat-3e/source/f16_rem.c deleted file mode 100644 index 0ffa498a1747..000000000000 --- a/deps/SoftFloat-3e/source/f16_rem.c +++ /dev/null @@ -1,171 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -float16_t f16_rem( float16_t a, float16_t b ) -{ - union ui16_f16 uA; - uint_fast16_t uiA; - bool signA; - int_fast8_t expA; - uint_fast16_t sigA; - union ui16_f16 uB; - uint_fast16_t uiB; - int_fast8_t expB; - uint_fast16_t sigB; - struct exp8_sig16 normExpSig; - uint16_t rem; - int_fast8_t expDiff; - uint_fast16_t q; - uint32_t recip32, q32; - uint16_t altRem, meanRem; - bool signRem; - uint_fast16_t uiZ; - union ui16_f16 uZ; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uA.f = a; - uiA = uA.ui; - signA = signF16UI( uiA ); - expA = expF16UI( uiA ); - sigA = fracF16UI( uiA ); - uB.f = b; - uiB = uB.ui; - expB = expF16UI( uiB ); - sigB = fracF16UI( uiB ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( expA == 0x1F ) { - if ( sigA || ((expB == 0x1F) && sigB) ) goto propagateNaN; - goto invalid; - } - if ( expB == 0x1F ) { - if ( sigB ) goto propagateNaN; - return a; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( ! expB ) { - if ( ! sigB ) goto invalid; - normExpSig = softfloat_normSubnormalF16Sig( sigB ); - expB = normExpSig.exp; - sigB = normExpSig.sig; - } - if ( ! expA ) { - if ( ! sigA ) return a; - normExpSig = softfloat_normSubnormalF16Sig( sigA ); - expA = normExpSig.exp; - sigA = normExpSig.sig; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - rem = sigA | 0x0400; - sigB |= 0x0400; - expDiff = expA - expB; - if ( expDiff < 1 ) { - if ( expDiff < -1 ) return a; - sigB <<= 3; - if ( expDiff ) { - rem <<= 2; - q = 0; - } else { - rem <<= 3; - q = (sigB <= rem); - if ( q ) rem -= sigB; - } - } else { - recip32 = softfloat_approxRecip32_1( (uint_fast32_t) sigB<<21 ); - /*-------------------------------------------------------------------- - | Changing the shift of `rem' here requires also changing the initial - | subtraction from `expDiff'. - *--------------------------------------------------------------------*/ - rem <<= 4; - expDiff -= 31; - /*-------------------------------------------------------------------- - | The scale of `sigB' affects how many bits are obtained during each - | cycle of the loop. Currently this is 29 bits per loop iteration, - | which is believed to be the maximum possible. - *--------------------------------------------------------------------*/ - sigB <<= 3; - for (;;) { - q32 = (rem * (uint_fast64_t) recip32)>>16; - if ( expDiff < 0 ) break; - rem = -((uint_fast16_t) q32 * sigB); - expDiff -= 29; - } - /*-------------------------------------------------------------------- - | (`expDiff' cannot be less than -30 here.) - *--------------------------------------------------------------------*/ - q32 >>= ~expDiff & 31; - q = q32; - rem = (rem<<(expDiff + 30)) - q * sigB; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - do { - altRem = rem; - ++q; - rem -= sigB; - } while ( ! (rem & 0x8000) ); - meanRem = rem + altRem; - if ( (meanRem & 0x8000) || (! meanRem && (q & 1)) ) rem = altRem; - signRem = signA; - if ( 0x8000 <= rem ) { - signRem = ! signRem; - rem = -rem; - } - return softfloat_normRoundPackToF16( signRem, expB, rem ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - propagateNaN: - uiZ = softfloat_propagateNaNF16UI( uiA, uiB ); - goto uiZ; - invalid: - softfloat_raiseFlags( softfloat_flag_invalid ); - uiZ = defaultNaNF16UI; - uiZ: - uZ.ui = uiZ; - return uZ.f; - -} - diff --git a/deps/SoftFloat-3e/source/f16_roundToInt.c b/deps/SoftFloat-3e/source/f16_roundToInt.c deleted file mode 100644 index a567d51d9fd5..000000000000 --- a/deps/SoftFloat-3e/source/f16_roundToInt.c +++ /dev/null @@ -1,120 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2017 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -float16_t f16_roundToInt( float16_t a, uint_fast8_t roundingMode, bool exact ) -{ - union ui16_f16 uA; - uint_fast16_t uiA; - int_fast8_t exp; - uint_fast16_t uiZ, lastBitMask, roundBitsMask; - union ui16_f16 uZ; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uA.f = a; - uiA = uA.ui; - exp = expF16UI( uiA ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( exp <= 0xE ) { - if ( !(uint16_t) (uiA<<1) ) return a; - if ( exact ) softfloat_exceptionFlags |= softfloat_flag_inexact; - uiZ = uiA & packToF16UI( 1, 0, 0 ); - switch ( roundingMode ) { - case softfloat_round_near_even: - if ( !fracF16UI( uiA ) ) break; - case softfloat_round_near_maxMag: - if ( exp == 0xE ) uiZ |= packToF16UI( 0, 0xF, 0 ); - break; - case softfloat_round_min: - if ( uiZ ) uiZ = packToF16UI( 1, 0xF, 0 ); - break; - case softfloat_round_max: - if ( !uiZ ) uiZ = packToF16UI( 0, 0xF, 0 ); - break; -#ifdef SOFTFLOAT_ROUND_ODD - case softfloat_round_odd: - uiZ |= packToF16UI( 0, 0xF, 0 ); - break; -#endif - } - goto uiZ; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( 0x19 <= exp ) { - if ( (exp == 0x1F) && fracF16UI( uiA ) ) { - uiZ = softfloat_propagateNaNF16UI( uiA, 0 ); - goto uiZ; - } - return a; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uiZ = uiA; - lastBitMask = (uint_fast16_t) 1<<(0x19 - exp); - roundBitsMask = lastBitMask - 1; - if ( roundingMode == softfloat_round_near_maxMag ) { - uiZ += lastBitMask>>1; - } else if ( roundingMode == softfloat_round_near_even ) { - uiZ += lastBitMask>>1; - if ( !(uiZ & roundBitsMask) ) uiZ &= ~lastBitMask; - } else if ( - roundingMode - == (signF16UI( uiZ ) ? softfloat_round_min : softfloat_round_max) - ) { - uiZ += roundBitsMask; - } - uiZ &= ~roundBitsMask; - if ( uiZ != uiA ) { -#ifdef SOFTFLOAT_ROUND_ODD - if ( roundingMode == softfloat_round_odd ) uiZ |= lastBitMask; -#endif - if ( exact ) softfloat_exceptionFlags |= softfloat_flag_inexact; - } - uiZ: - uZ.ui = uiZ; - return uZ.f; - -} - diff --git a/deps/SoftFloat-3e/source/f16_sqrt.c b/deps/SoftFloat-3e/source/f16_sqrt.c deleted file mode 100644 index 47a3bbf148bb..000000000000 --- a/deps/SoftFloat-3e/source/f16_sqrt.c +++ /dev/null @@ -1,136 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -extern const uint16_t softfloat_approxRecipSqrt_1k0s[]; -extern const uint16_t softfloat_approxRecipSqrt_1k1s[]; - -float16_t f16_sqrt( float16_t a ) -{ - union ui16_f16 uA; - uint_fast16_t uiA; - bool signA; - int_fast8_t expA; - uint_fast16_t sigA, uiZ; - struct exp8_sig16 normExpSig; - int_fast8_t expZ; - int index; - uint_fast16_t r0; - uint_fast32_t ESqrR0; - uint16_t sigma0; - uint_fast16_t recipSqrt16, sigZ, shiftedSigZ; - uint16_t negRem; - union ui16_f16 uZ; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uA.f = a; - uiA = uA.ui; - signA = signF16UI( uiA ); - expA = expF16UI( uiA ); - sigA = fracF16UI( uiA ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( expA == 0x1F ) { - if ( sigA ) { - uiZ = softfloat_propagateNaNF16UI( uiA, 0 ); - goto uiZ; - } - if ( ! signA ) return a; - goto invalid; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( signA ) { - if ( ! (expA | sigA) ) return a; - goto invalid; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( ! expA ) { - if ( ! sigA ) return a; - normExpSig = softfloat_normSubnormalF16Sig( sigA ); - expA = normExpSig.exp; - sigA = normExpSig.sig; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - expZ = ((expA - 0xF)>>1) + 0xE; - expA &= 1; - sigA |= 0x0400; - index = (sigA>>6 & 0xE) + expA; - r0 = softfloat_approxRecipSqrt_1k0s[index] - - (((uint_fast32_t) softfloat_approxRecipSqrt_1k1s[index] - * (sigA & 0x7F)) - >>11); - ESqrR0 = ((uint_fast32_t) r0 * r0)>>1; - if ( expA ) ESqrR0 >>= 1; - sigma0 = ~(uint_fast16_t) ((ESqrR0 * sigA)>>16); - recipSqrt16 = r0 + (((uint_fast32_t) r0 * sigma0)>>25); - if ( ! (recipSqrt16 & 0x8000) ) recipSqrt16 = 0x8000; - sigZ = ((uint_fast32_t) (sigA<<5) * recipSqrt16)>>16; - if ( expA ) sigZ >>= 1; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - ++sigZ; - if ( ! (sigZ & 7) ) { - shiftedSigZ = sigZ>>1; - negRem = shiftedSigZ * shiftedSigZ; - sigZ &= ~1; - if ( negRem & 0x8000 ) { - sigZ |= 1; - } else { - if ( negRem ) --sigZ; - } - } - return softfloat_roundPackToF16( 0, expZ, sigZ ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - invalid: - softfloat_raiseFlags( softfloat_flag_invalid ); - uiZ = defaultNaNF16UI; - uiZ: - uZ.ui = uiZ; - return uZ.f; - -} - diff --git a/deps/SoftFloat-3e/source/f16_sub.c b/deps/SoftFloat-3e/source/f16_sub.c deleted file mode 100644 index 03a87cf32530..000000000000 --- a/deps/SoftFloat-3e/source/f16_sub.c +++ /dev/null @@ -1,70 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "softfloat.h" - -float16_t f16_sub( float16_t a, float16_t b ) -{ - union ui16_f16 uA; - uint_fast16_t uiA; - union ui16_f16 uB; - uint_fast16_t uiB; -#if ! defined INLINE_LEVEL || (INLINE_LEVEL < 1) - float16_t (*magsFuncPtr)( uint_fast16_t, uint_fast16_t ); -#endif - - uA.f = a; - uiA = uA.ui; - uB.f = b; - uiB = uB.ui; -#if defined INLINE_LEVEL && (1 <= INLINE_LEVEL) - if ( signF16UI( uiA ^ uiB ) ) { - return softfloat_addMagsF16( uiA, uiB ); - } else { - return softfloat_subMagsF16( uiA, uiB ); - } -#else - magsFuncPtr = - signF16UI( uiA ^ uiB ) ? softfloat_addMagsF16 : softfloat_subMagsF16; - return (*magsFuncPtr)( uiA, uiB ); -#endif - -} - diff --git a/deps/SoftFloat-3e/source/f16_to_extF80.c b/deps/SoftFloat-3e/source/f16_to_extF80.c deleted file mode 100644 index 99c2dfc74660..000000000000 --- a/deps/SoftFloat-3e/source/f16_to_extF80.c +++ /dev/null @@ -1,101 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -extFloat80_t f16_to_extF80( float16_t a ) -{ - union ui16_f16 uA; - uint_fast16_t uiA; - bool sign; - int_fast8_t exp; - uint_fast16_t frac; - struct commonNaN commonNaN; - struct uint128 uiZ; - uint_fast16_t uiZ64; - uint_fast64_t uiZ0; - struct exp8_sig16 normExpSig; - union { struct extFloat80M s; extFloat80_t f; } uZ; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uA.f = a; - uiA = uA.ui; - sign = signF16UI( uiA ); - exp = expF16UI( uiA ); - frac = fracF16UI( uiA ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( exp == 0x1F ) { - if ( frac ) { - softfloat_f16UIToCommonNaN( uiA, &commonNaN ); - uiZ = softfloat_commonNaNToExtF80UI( &commonNaN ); - uiZ64 = uiZ.v64; - uiZ0 = uiZ.v0; - } else { - uiZ64 = packToExtF80UI64( sign, 0x7FFF ); - uiZ0 = UINT64_C( 0x8000000000000000 ); - } - goto uiZ; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( ! exp ) { - if ( ! frac ) { - uiZ64 = packToExtF80UI64( sign, 0 ); - uiZ0 = 0; - goto uiZ; - } - normExpSig = softfloat_normSubnormalF16Sig( frac ); - exp = normExpSig.exp; - frac = normExpSig.sig; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uiZ64 = packToExtF80UI64( sign, exp + 0x3FF0 ); - uiZ0 = (uint_fast64_t) (frac | 0x0400)<<53; - uiZ: - uZ.s.signExp = uiZ64; - uZ.s.signif = uiZ0; - return uZ.f; - -} - diff --git a/deps/SoftFloat-3e/source/f16_to_extF80M.c b/deps/SoftFloat-3e/source/f16_to_extF80M.c deleted file mode 100644 index 7f2d53458d81..000000000000 --- a/deps/SoftFloat-3e/source/f16_to_extF80M.c +++ /dev/null @@ -1,111 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -#ifdef SOFTFLOAT_FAST_INT64 - -void f16_to_extF80M( float16_t a, extFloat80_t *zPtr ) -{ - - *zPtr = f16_to_extF80( a ); - -} - -#else - -void f16_to_extF80M( float16_t a, extFloat80_t *zPtr ) -{ - struct extFloat80M *zSPtr; - union ui16_f16 uA; - uint16_t uiA; - bool sign; - int_fast8_t exp; - uint16_t frac; - struct commonNaN commonNaN; - uint_fast16_t uiZ64; - uint32_t uiZ32; - struct exp8_sig16 normExpSig; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - zSPtr = (struct extFloat80M *) zPtr; - uA.f = a; - uiA = uA.ui; - sign = signF16UI( uiA ); - exp = expF16UI( uiA ); - frac = fracF16UI( uiA ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( exp == 0x1F ) { - if ( frac ) { - softfloat_f16UIToCommonNaN( uiA, &commonNaN ); - softfloat_commonNaNToExtF80M( &commonNaN, zSPtr ); - return; - } - uiZ64 = packToExtF80UI64( sign, 0x7FFF ); - uiZ32 = 0x80000000; - goto uiZ; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( ! exp ) { - if ( ! frac ) { - uiZ64 = packToExtF80UI64( sign, 0 ); - uiZ32 = 0; - goto uiZ; - } - normExpSig = softfloat_normSubnormalF16Sig( frac ); - exp = normExpSig.exp; - frac = normExpSig.sig; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uiZ64 = packToExtF80UI64( sign, exp + 0x3FF0 ); - uiZ32 = 0x80000000 | (uint32_t) frac<<21; - uiZ: - zSPtr->signExp = uiZ64; - zSPtr->signif = (uint64_t) uiZ32<<32; - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/f16_to_f128.c b/deps/SoftFloat-3e/source/f16_to_f128.c deleted file mode 100644 index c4b81dc840d1..000000000000 --- a/deps/SoftFloat-3e/source/f16_to_f128.c +++ /dev/null @@ -1,96 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -float128_t f16_to_f128( float16_t a ) -{ - union ui16_f16 uA; - uint_fast16_t uiA; - bool sign; - int_fast8_t exp; - uint_fast16_t frac; - struct commonNaN commonNaN; - struct uint128 uiZ; - struct exp8_sig16 normExpSig; - union ui128_f128 uZ; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uA.f = a; - uiA = uA.ui; - sign = signF16UI( uiA ); - exp = expF16UI( uiA ); - frac = fracF16UI( uiA ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( exp == 0x1F ) { - if ( frac ) { - softfloat_f16UIToCommonNaN( uiA, &commonNaN ); - uiZ = softfloat_commonNaNToF128UI( &commonNaN ); - } else { - uiZ.v64 = packToF128UI64( sign, 0x7FFF, 0 ); - uiZ.v0 = 0; - } - goto uiZ; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( ! exp ) { - if ( ! frac ) { - uiZ.v64 = packToF128UI64( sign, 0, 0 ); - uiZ.v0 = 0; - goto uiZ; - } - normExpSig = softfloat_normSubnormalF16Sig( frac ); - exp = normExpSig.exp - 1; - frac = normExpSig.sig; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uiZ.v64 = packToF128UI64( sign, exp + 0x3FF0, (uint_fast64_t) frac<<38 ); - uiZ.v0 = 0; - uiZ: - uZ.ui = uiZ; - return uZ.f; - -} - diff --git a/deps/SoftFloat-3e/source/f16_to_f128M.c b/deps/SoftFloat-3e/source/f16_to_f128M.c deleted file mode 100644 index b4fc873b5627..000000000000 --- a/deps/SoftFloat-3e/source/f16_to_f128M.c +++ /dev/null @@ -1,111 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2017 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -#ifdef SOFTFLOAT_FAST_INT64 - -void f16_to_f128M( float16_t a, float128_t *zPtr ) -{ - - *zPtr = f16_to_f128( a ); - -} - -#else - -void f16_to_f128M( float16_t a, float128_t *zPtr ) -{ - uint32_t *zWPtr; - union ui16_f16 uA; - uint16_t uiA; - bool sign; - int_fast8_t exp; - uint16_t frac; - struct commonNaN commonNaN; - uint32_t uiZ96; - struct exp8_sig16 normExpSig; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - zWPtr = (uint32_t *) zPtr; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uA.f = a; - uiA = uA.ui; - sign = signF16UI( uiA ); - exp = expF16UI( uiA ); - frac = fracF16UI( uiA ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( exp == 0x1F ) { - if ( frac ) { - softfloat_f16UIToCommonNaN( uiA, &commonNaN ); - softfloat_commonNaNToF128M( &commonNaN, zWPtr ); - return; - } - uiZ96 = packToF128UI96( sign, 0x7FFF, 0 ); - goto uiZ; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( ! exp ) { - if ( ! frac ) { - uiZ96 = packToF128UI96( sign, 0, 0 ); - goto uiZ; - } - normExpSig = softfloat_normSubnormalF16Sig( frac ); - exp = normExpSig.exp - 1; - frac = normExpSig.sig; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uiZ96 = packToF128UI96( sign, exp + 0x3FF0, (uint32_t) frac<<6 ); - uiZ: - zWPtr[indexWord( 4, 3 )] = uiZ96; - zWPtr[indexWord( 4, 2 )] = 0; - zWPtr[indexWord( 4, 1 )] = 0; - zWPtr[indexWord( 4, 0 )] = 0; - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/f16_to_f32.c b/deps/SoftFloat-3e/source/f16_to_f32.c deleted file mode 100644 index a219454bf286..000000000000 --- a/deps/SoftFloat-3e/source/f16_to_f32.c +++ /dev/null @@ -1,93 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -float32_t f16_to_f32( float16_t a ) -{ - union ui16_f16 uA; - uint_fast16_t uiA; - bool sign; - int_fast8_t exp; - uint_fast16_t frac; - struct commonNaN commonNaN; - uint_fast32_t uiZ; - struct exp8_sig16 normExpSig; - union ui32_f32 uZ; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uA.f = a; - uiA = uA.ui; - sign = signF16UI( uiA ); - exp = expF16UI( uiA ); - frac = fracF16UI( uiA ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( exp == 0x1F ) { - if ( frac ) { - softfloat_f16UIToCommonNaN( uiA, &commonNaN ); - uiZ = softfloat_commonNaNToF32UI( &commonNaN ); - } else { - uiZ = packToF32UI( sign, 0xFF, 0 ); - } - goto uiZ; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( ! exp ) { - if ( ! frac ) { - uiZ = packToF32UI( sign, 0, 0 ); - goto uiZ; - } - normExpSig = softfloat_normSubnormalF16Sig( frac ); - exp = normExpSig.exp - 1; - frac = normExpSig.sig; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uiZ = packToF32UI( sign, exp + 0x70, (uint_fast32_t) frac<<13 ); - uiZ: - uZ.ui = uiZ; - return uZ.f; - -} - diff --git a/deps/SoftFloat-3e/source/f16_to_f64.c b/deps/SoftFloat-3e/source/f16_to_f64.c deleted file mode 100644 index 7e87c25f4f06..000000000000 --- a/deps/SoftFloat-3e/source/f16_to_f64.c +++ /dev/null @@ -1,93 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -float64_t f16_to_f64( float16_t a ) -{ - union ui16_f16 uA; - uint_fast16_t uiA; - bool sign; - int_fast8_t exp; - uint_fast16_t frac; - struct commonNaN commonNaN; - uint_fast64_t uiZ; - struct exp8_sig16 normExpSig; - union ui64_f64 uZ; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uA.f = a; - uiA = uA.ui; - sign = signF16UI( uiA ); - exp = expF16UI( uiA ); - frac = fracF16UI( uiA ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( exp == 0x1F ) { - if ( frac ) { - softfloat_f16UIToCommonNaN( uiA, &commonNaN ); - uiZ = softfloat_commonNaNToF64UI( &commonNaN ); - } else { - uiZ = packToF64UI( sign, 0x7FF, 0 ); - } - goto uiZ; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( ! exp ) { - if ( ! frac ) { - uiZ = packToF64UI( sign, 0, 0 ); - goto uiZ; - } - normExpSig = softfloat_normSubnormalF16Sig( frac ); - exp = normExpSig.exp - 1; - frac = normExpSig.sig; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uiZ = packToF64UI( sign, exp + 0x3F0, (uint_fast64_t) frac<<42 ); - uiZ: - uZ.ui = uiZ; - return uZ.f; - -} - diff --git a/deps/SoftFloat-3e/source/f16_to_i32.c b/deps/SoftFloat-3e/source/f16_to_i32.c deleted file mode 100644 index 805c4e55038c..000000000000 --- a/deps/SoftFloat-3e/source/f16_to_i32.c +++ /dev/null @@ -1,87 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017 The Regents of the -University of California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -int_fast32_t f16_to_i32( float16_t a, uint_fast8_t roundingMode, bool exact ) -{ - union ui16_f16 uA; - uint_fast16_t uiA; - bool sign; - int_fast8_t exp; - uint_fast16_t frac; - int_fast32_t sig32; - int_fast8_t shiftDist; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uA.f = a; - uiA = uA.ui; - sign = signF16UI( uiA ); - exp = expF16UI( uiA ); - frac = fracF16UI( uiA ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( exp == 0x1F ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - return - frac ? i32_fromNaN - : sign ? i32_fromNegOverflow : i32_fromPosOverflow; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - sig32 = frac; - if ( exp ) { - sig32 |= 0x0400; - shiftDist = exp - 0x19; - if ( 0 <= shiftDist ) { - sig32 <<= shiftDist; - return sign ? -sig32 : sig32; - } - shiftDist = exp - 0x0D; - if ( 0 < shiftDist ) sig32 <<= shiftDist; - } - return - softfloat_roundToI32( - sign, (uint_fast32_t) sig32, roundingMode, exact ); - -} - diff --git a/deps/SoftFloat-3e/source/f16_to_i32_r_minMag.c b/deps/SoftFloat-3e/source/f16_to_i32_r_minMag.c deleted file mode 100644 index b1f9963718a9..000000000000 --- a/deps/SoftFloat-3e/source/f16_to_i32_r_minMag.c +++ /dev/null @@ -1,88 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -int_fast32_t f16_to_i32_r_minMag( float16_t a, bool exact ) -{ - union ui16_f16 uA; - uint_fast16_t uiA; - int_fast8_t exp; - uint_fast16_t frac; - int_fast8_t shiftDist; - bool sign; - int_fast32_t alignedSig; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uA.f = a; - uiA = uA.ui; - exp = expF16UI( uiA ); - frac = fracF16UI( uiA ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - shiftDist = exp - 0x0F; - if ( shiftDist < 0 ) { - if ( exact && (exp | frac) ) { - softfloat_exceptionFlags |= softfloat_flag_inexact; - } - return 0; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - sign = signF16UI( uiA ); - if ( exp == 0x1F ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - return - (exp == 0x1F) && frac ? i32_fromNaN - : sign ? i32_fromNegOverflow : i32_fromPosOverflow; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - alignedSig = (int_fast32_t) (frac | 0x0400)<>= 10; - return sign ? -alignedSig : alignedSig; - -} - diff --git a/deps/SoftFloat-3e/source/f16_to_i64.c b/deps/SoftFloat-3e/source/f16_to_i64.c deleted file mode 100644 index e3c0065f619e..000000000000 --- a/deps/SoftFloat-3e/source/f16_to_i64.c +++ /dev/null @@ -1,87 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017 The Regents of the -University of California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -int_fast64_t f16_to_i64( float16_t a, uint_fast8_t roundingMode, bool exact ) -{ - union ui16_f16 uA; - uint_fast16_t uiA; - bool sign; - int_fast8_t exp; - uint_fast16_t frac; - int_fast32_t sig32; - int_fast8_t shiftDist; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uA.f = a; - uiA = uA.ui; - sign = signF16UI( uiA ); - exp = expF16UI( uiA ); - frac = fracF16UI( uiA ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( exp == 0x1F ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - return - frac ? i64_fromNaN - : sign ? i64_fromNegOverflow : i64_fromPosOverflow; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - sig32 = frac; - if ( exp ) { - sig32 |= 0x0400; - shiftDist = exp - 0x19; - if ( 0 <= shiftDist ) { - sig32 <<= shiftDist; - return sign ? -sig32 : sig32; - } - shiftDist = exp - 0x0D; - if ( 0 < shiftDist ) sig32 <<= shiftDist; - } - return - softfloat_roundToI32( - sign, (uint_fast32_t) sig32, roundingMode, exact ); - -} - diff --git a/deps/SoftFloat-3e/source/f16_to_i64_r_minMag.c b/deps/SoftFloat-3e/source/f16_to_i64_r_minMag.c deleted file mode 100644 index a5a6a077e6ff..000000000000 --- a/deps/SoftFloat-3e/source/f16_to_i64_r_minMag.c +++ /dev/null @@ -1,88 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -int_fast64_t f16_to_i64_r_minMag( float16_t a, bool exact ) -{ - union ui16_f16 uA; - uint_fast16_t uiA; - int_fast8_t exp; - uint_fast16_t frac; - int_fast8_t shiftDist; - bool sign; - int_fast32_t alignedSig; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uA.f = a; - uiA = uA.ui; - exp = expF16UI( uiA ); - frac = fracF16UI( uiA ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - shiftDist = exp - 0x0F; - if ( shiftDist < 0 ) { - if ( exact && (exp | frac) ) { - softfloat_exceptionFlags |= softfloat_flag_inexact; - } - return 0; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - sign = signF16UI( uiA ); - if ( exp == 0x1F ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - return - (exp == 0x1F) && frac ? i64_fromNaN - : sign ? i64_fromNegOverflow : i64_fromPosOverflow; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - alignedSig = (int_fast32_t) (frac | 0x0400)<>= 10; - return sign ? -alignedSig : alignedSig; - -} - diff --git a/deps/SoftFloat-3e/source/f16_to_ui32.c b/deps/SoftFloat-3e/source/f16_to_ui32.c deleted file mode 100644 index 5371ca339581..000000000000 --- a/deps/SoftFloat-3e/source/f16_to_ui32.c +++ /dev/null @@ -1,84 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017 The Regents of the -University of California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -uint_fast32_t f16_to_ui32( float16_t a, uint_fast8_t roundingMode, bool exact ) -{ - union ui16_f16 uA; - uint_fast16_t uiA; - bool sign; - int_fast8_t exp; - uint_fast16_t frac; - uint_fast32_t sig32; - int_fast8_t shiftDist; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uA.f = a; - uiA = uA.ui; - sign = signF16UI( uiA ); - exp = expF16UI( uiA ); - frac = fracF16UI( uiA ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( exp == 0x1F ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - return - frac ? ui32_fromNaN - : sign ? ui32_fromNegOverflow : ui32_fromPosOverflow; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - sig32 = frac; - if ( exp ) { - sig32 |= 0x0400; - shiftDist = exp - 0x19; - if ( (0 <= shiftDist) && ! sign ) { - return sig32< -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -uint_fast32_t f16_to_ui32_r_minMag( float16_t a, bool exact ) -{ - union ui16_f16 uA; - uint_fast16_t uiA; - int_fast8_t exp; - uint_fast16_t frac; - int_fast8_t shiftDist; - bool sign; - uint_fast32_t alignedSig; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uA.f = a; - uiA = uA.ui; - exp = expF16UI( uiA ); - frac = fracF16UI( uiA ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - shiftDist = exp - 0x0F; - if ( shiftDist < 0 ) { - if ( exact && (exp | frac) ) { - softfloat_exceptionFlags |= softfloat_flag_inexact; - } - return 0; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - sign = signF16UI( uiA ); - if ( sign || (exp == 0x1F) ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - return - (exp == 0x1F) && frac ? ui32_fromNaN - : sign ? ui32_fromNegOverflow : ui32_fromPosOverflow; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - alignedSig = (uint_fast32_t) (frac | 0x0400)<>10; - -} - diff --git a/deps/SoftFloat-3e/source/f16_to_ui64.c b/deps/SoftFloat-3e/source/f16_to_ui64.c deleted file mode 100644 index e6cb000f1e27..000000000000 --- a/deps/SoftFloat-3e/source/f16_to_ui64.c +++ /dev/null @@ -1,96 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the -University of California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -uint_fast64_t f16_to_ui64( float16_t a, uint_fast8_t roundingMode, bool exact ) -{ - union ui16_f16 uA; - uint_fast16_t uiA; - bool sign; - int_fast8_t exp; - uint_fast16_t frac; - uint_fast32_t sig32; - int_fast8_t shiftDist; -#ifndef SOFTFLOAT_FAST_INT64 - uint32_t extSig[3]; -#endif - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uA.f = a; - uiA = uA.ui; - sign = signF16UI( uiA ); - exp = expF16UI( uiA ); - frac = fracF16UI( uiA ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( exp == 0x1F ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - return - frac ? ui64_fromNaN - : sign ? ui64_fromNegOverflow : ui64_fromPosOverflow; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - sig32 = frac; - if ( exp ) { - sig32 |= 0x0400; - shiftDist = exp - 0x19; - if ( (0 <= shiftDist) && ! sign ) { - return sig32<>12, (uint_fast64_t) sig32<<52, roundingMode, exact ); -#else - extSig[indexWord( 3, 2 )] = 0; - extSig[indexWord( 3, 1 )] = sig32>>12; - extSig[indexWord( 3, 0 )] = sig32<<20; - return softfloat_roundMToUI64( sign, extSig, roundingMode, exact ); -#endif - -} - diff --git a/deps/SoftFloat-3e/source/f16_to_ui64_r_minMag.c b/deps/SoftFloat-3e/source/f16_to_ui64_r_minMag.c deleted file mode 100644 index b4f975f83339..000000000000 --- a/deps/SoftFloat-3e/source/f16_to_ui64_r_minMag.c +++ /dev/null @@ -1,87 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -uint_fast64_t f16_to_ui64_r_minMag( float16_t a, bool exact ) -{ - union ui16_f16 uA; - uint_fast16_t uiA; - int_fast8_t exp; - uint_fast16_t frac; - int_fast8_t shiftDist; - bool sign; - uint_fast32_t alignedSig; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uA.f = a; - uiA = uA.ui; - exp = expF16UI( uiA ); - frac = fracF16UI( uiA ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - shiftDist = exp - 0x0F; - if ( shiftDist < 0 ) { - if ( exact && (exp | frac) ) { - softfloat_exceptionFlags |= softfloat_flag_inexact; - } - return 0; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - sign = signF16UI( uiA ); - if ( sign || (exp == 0x1F) ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - return - (exp == 0x1F) && frac ? ui64_fromNaN - : sign ? ui64_fromNegOverflow : ui64_fromPosOverflow; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - alignedSig = (uint_fast32_t) (frac | 0x0400)<>10; - -} - diff --git a/deps/SoftFloat-3e/source/f32_add.c b/deps/SoftFloat-3e/source/f32_add.c deleted file mode 100644 index 70e03e7f94fe..000000000000 --- a/deps/SoftFloat-3e/source/f32_add.c +++ /dev/null @@ -1,70 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "softfloat.h" - -float32_t f32_add( float32_t a, float32_t b ) -{ - union ui32_f32 uA; - uint_fast32_t uiA; - union ui32_f32 uB; - uint_fast32_t uiB; -#if ! defined INLINE_LEVEL || (INLINE_LEVEL < 1) - float32_t (*magsFuncPtr)( uint_fast32_t, uint_fast32_t ); -#endif - - uA.f = a; - uiA = uA.ui; - uB.f = b; - uiB = uB.ui; -#if defined INLINE_LEVEL && (1 <= INLINE_LEVEL) - if ( signF32UI( uiA ^ uiB ) ) { - return softfloat_subMagsF32( uiA, uiB ); - } else { - return softfloat_addMagsF32( uiA, uiB ); - } -#else - magsFuncPtr = - signF32UI( uiA ^ uiB ) ? softfloat_subMagsF32 : softfloat_addMagsF32; - return (*magsFuncPtr)( uiA, uiB ); -#endif - -} - diff --git a/deps/SoftFloat-3e/source/f32_div.c b/deps/SoftFloat-3e/source/f32_div.c deleted file mode 100644 index 05ec701f76ff..000000000000 --- a/deps/SoftFloat-3e/source/f32_div.c +++ /dev/null @@ -1,180 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -float32_t f32_div( float32_t a, float32_t b ) -{ - union ui32_f32 uA; - uint_fast32_t uiA; - bool signA; - int_fast16_t expA; - uint_fast32_t sigA; - union ui32_f32 uB; - uint_fast32_t uiB; - bool signB; - int_fast16_t expB; - uint_fast32_t sigB; - bool signZ; - struct exp16_sig32 normExpSig; - int_fast16_t expZ; -#ifdef SOFTFLOAT_FAST_DIV64TO32 - uint_fast64_t sig64A; - uint_fast32_t sigZ; -#else - uint_fast32_t sigZ; - uint_fast64_t rem; -#endif - uint_fast32_t uiZ; - union ui32_f32 uZ; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uA.f = a; - uiA = uA.ui; - signA = signF32UI( uiA ); - expA = expF32UI( uiA ); - sigA = fracF32UI( uiA ); - uB.f = b; - uiB = uB.ui; - signB = signF32UI( uiB ); - expB = expF32UI( uiB ); - sigB = fracF32UI( uiB ); - signZ = signA ^ signB; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( expA == 0xFF ) { - if ( sigA ) goto propagateNaN; - if ( expB == 0xFF ) { - if ( sigB ) goto propagateNaN; - goto invalid; - } - goto infinity; - } - if ( expB == 0xFF ) { - if ( sigB ) goto propagateNaN; - goto zero; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( ! expB ) { - if ( ! sigB ) { - if ( ! (expA | sigA) ) goto invalid; - softfloat_raiseFlags( softfloat_flag_infinite ); - goto infinity; - } - normExpSig = softfloat_normSubnormalF32Sig( sigB ); - expB = normExpSig.exp; - sigB = normExpSig.sig; - } - if ( ! expA ) { - if ( ! sigA ) goto zero; - normExpSig = softfloat_normSubnormalF32Sig( sigA ); - expA = normExpSig.exp; - sigA = normExpSig.sig; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - expZ = expA - expB + 0x7E; - sigA |= 0x00800000; - sigB |= 0x00800000; -#ifdef SOFTFLOAT_FAST_DIV64TO32 - if ( sigA < sigB ) { - --expZ; - sig64A = (uint_fast64_t) sigA<<31; - } else { - sig64A = (uint_fast64_t) sigA<<30; - } - sigZ = sig64A / sigB; - if ( ! (sigZ & 0x3F) ) sigZ |= ((uint_fast64_t) sigB * sigZ != sig64A); -#else - if ( sigA < sigB ) { - --expZ; - sigA <<= 8; - } else { - sigA <<= 7; - } - sigB <<= 8; - sigZ = ((uint_fast64_t) sigA * softfloat_approxRecip32_1( sigB ))>>32; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - sigZ += 2; - if ( (sigZ & 0x3F) < 2 ) { - sigZ &= ~3; -#ifdef SOFTFLOAT_FAST_INT64 - rem = ((uint_fast64_t) sigA<<31) - (uint_fast64_t) sigZ * sigB; -#else - rem = ((uint_fast64_t) sigA<<32) - (uint_fast64_t) (sigZ<<1) * sigB; -#endif - if ( rem & UINT64_C( 0x8000000000000000 ) ) { - sigZ -= 4; - } else { - if ( rem ) sigZ |= 1; - } - } -#endif - return softfloat_roundPackToF32( signZ, expZ, sigZ ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - propagateNaN: - uiZ = softfloat_propagateNaNF32UI( uiA, uiB ); - goto uiZ; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - invalid: - softfloat_raiseFlags( softfloat_flag_invalid ); - uiZ = defaultNaNF32UI; - goto uiZ; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - infinity: - uiZ = packToF32UI( signZ, 0xFF, 0 ); - goto uiZ; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - zero: - uiZ = packToF32UI( signZ, 0, 0 ); - uiZ: - uZ.ui = uiZ; - return uZ.f; - -} - diff --git a/deps/SoftFloat-3e/source/f32_eq.c b/deps/SoftFloat-3e/source/f32_eq.c deleted file mode 100644 index 801bbfd73453..000000000000 --- a/deps/SoftFloat-3e/source/f32_eq.c +++ /dev/null @@ -1,66 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -bool f32_eq( float32_t a, float32_t b ) -{ - union ui32_f32 uA; - uint_fast32_t uiA; - union ui32_f32 uB; - uint_fast32_t uiB; - - uA.f = a; - uiA = uA.ui; - uB.f = b; - uiB = uB.ui; - if ( isNaNF32UI( uiA ) || isNaNF32UI( uiB ) ) { - if ( - softfloat_isSigNaNF32UI( uiA ) || softfloat_isSigNaNF32UI( uiB ) - ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - } - return false; - } - return (uiA == uiB) || ! (uint32_t) ((uiA | uiB)<<1); - -} - diff --git a/deps/SoftFloat-3e/source/f32_eq_signaling.c b/deps/SoftFloat-3e/source/f32_eq_signaling.c deleted file mode 100644 index 4c610ffae87e..000000000000 --- a/deps/SoftFloat-3e/source/f32_eq_signaling.c +++ /dev/null @@ -1,61 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "softfloat.h" - -bool f32_eq_signaling( float32_t a, float32_t b ) -{ - union ui32_f32 uA; - uint_fast32_t uiA; - union ui32_f32 uB; - uint_fast32_t uiB; - - uA.f = a; - uiA = uA.ui; - uB.f = b; - uiB = uB.ui; - if ( isNaNF32UI( uiA ) || isNaNF32UI( uiB ) ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - return false; - } - return (uiA == uiB) || ! (uint32_t) ((uiA | uiB)<<1); - -} - diff --git a/deps/SoftFloat-3e/source/f32_isSignalingNaN.c b/deps/SoftFloat-3e/source/f32_isSignalingNaN.c deleted file mode 100644 index f5954cbbc441..000000000000 --- a/deps/SoftFloat-3e/source/f32_isSignalingNaN.c +++ /dev/null @@ -1,51 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -bool f32_isSignalingNaN( float32_t a ) -{ - union ui32_f32 uA; - - uA.f = a; - return softfloat_isSigNaNF32UI( uA.ui ); - -} - diff --git a/deps/SoftFloat-3e/source/f32_le.c b/deps/SoftFloat-3e/source/f32_le.c deleted file mode 100644 index d89d1e88df72..000000000000 --- a/deps/SoftFloat-3e/source/f32_le.c +++ /dev/null @@ -1,66 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "softfloat.h" - -bool f32_le( float32_t a, float32_t b ) -{ - union ui32_f32 uA; - uint_fast32_t uiA; - union ui32_f32 uB; - uint_fast32_t uiB; - bool signA, signB; - - uA.f = a; - uiA = uA.ui; - uB.f = b; - uiB = uB.ui; - if ( isNaNF32UI( uiA ) || isNaNF32UI( uiB ) ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - return false; - } - signA = signF32UI( uiA ); - signB = signF32UI( uiB ); - return - (signA != signB) ? signA || ! (uint32_t) ((uiA | uiB)<<1) - : (uiA == uiB) || (signA ^ (uiA < uiB)); - -} - diff --git a/deps/SoftFloat-3e/source/f32_le_quiet.c b/deps/SoftFloat-3e/source/f32_le_quiet.c deleted file mode 100644 index c2d4297a2928..000000000000 --- a/deps/SoftFloat-3e/source/f32_le_quiet.c +++ /dev/null @@ -1,71 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -bool f32_le_quiet( float32_t a, float32_t b ) -{ - union ui32_f32 uA; - uint_fast32_t uiA; - union ui32_f32 uB; - uint_fast32_t uiB; - bool signA, signB; - - uA.f = a; - uiA = uA.ui; - uB.f = b; - uiB = uB.ui; - if ( isNaNF32UI( uiA ) || isNaNF32UI( uiB ) ) { - if ( - softfloat_isSigNaNF32UI( uiA ) || softfloat_isSigNaNF32UI( uiB ) - ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - } - return false; - } - signA = signF32UI( uiA ); - signB = signF32UI( uiB ); - return - (signA != signB) ? signA || ! (uint32_t) ((uiA | uiB)<<1) - : (uiA == uiB) || (signA ^ (uiA < uiB)); - -} - diff --git a/deps/SoftFloat-3e/source/f32_lt.c b/deps/SoftFloat-3e/source/f32_lt.c deleted file mode 100644 index 5b5fd22821ad..000000000000 --- a/deps/SoftFloat-3e/source/f32_lt.c +++ /dev/null @@ -1,66 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "softfloat.h" - -bool f32_lt( float32_t a, float32_t b ) -{ - union ui32_f32 uA; - uint_fast32_t uiA; - union ui32_f32 uB; - uint_fast32_t uiB; - bool signA, signB; - - uA.f = a; - uiA = uA.ui; - uB.f = b; - uiB = uB.ui; - if ( isNaNF32UI( uiA ) || isNaNF32UI( uiB ) ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - return false; - } - signA = signF32UI( uiA ); - signB = signF32UI( uiB ); - return - (signA != signB) ? signA && ((uint32_t) ((uiA | uiB)<<1) != 0) - : (uiA != uiB) && (signA ^ (uiA < uiB)); - -} - diff --git a/deps/SoftFloat-3e/source/f32_lt_quiet.c b/deps/SoftFloat-3e/source/f32_lt_quiet.c deleted file mode 100644 index 015388143711..000000000000 --- a/deps/SoftFloat-3e/source/f32_lt_quiet.c +++ /dev/null @@ -1,71 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -bool f32_lt_quiet( float32_t a, float32_t b ) -{ - union ui32_f32 uA; - uint_fast32_t uiA; - union ui32_f32 uB; - uint_fast32_t uiB; - bool signA, signB; - - uA.f = a; - uiA = uA.ui; - uB.f = b; - uiB = uB.ui; - if ( isNaNF32UI( uiA ) || isNaNF32UI( uiB ) ) { - if ( - softfloat_isSigNaNF32UI( uiA ) || softfloat_isSigNaNF32UI( uiB ) - ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - } - return false; - } - signA = signF32UI( uiA ); - signB = signF32UI( uiB ); - return - (signA != signB) ? signA && ((uint32_t) ((uiA | uiB)<<1) != 0) - : (uiA != uiB) && (signA ^ (uiA < uiB)); - -} - diff --git a/deps/SoftFloat-3e/source/f32_mul.c b/deps/SoftFloat-3e/source/f32_mul.c deleted file mode 100644 index f5c856002f62..000000000000 --- a/deps/SoftFloat-3e/source/f32_mul.c +++ /dev/null @@ -1,137 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -float32_t f32_mul( float32_t a, float32_t b ) -{ - union ui32_f32 uA; - uint_fast32_t uiA; - bool signA; - int_fast16_t expA; - uint_fast32_t sigA; - union ui32_f32 uB; - uint_fast32_t uiB; - bool signB; - int_fast16_t expB; - uint_fast32_t sigB; - bool signZ; - uint_fast32_t magBits; - struct exp16_sig32 normExpSig; - int_fast16_t expZ; - uint_fast32_t sigZ, uiZ; - union ui32_f32 uZ; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uA.f = a; - uiA = uA.ui; - signA = signF32UI( uiA ); - expA = expF32UI( uiA ); - sigA = fracF32UI( uiA ); - uB.f = b; - uiB = uB.ui; - signB = signF32UI( uiB ); - expB = expF32UI( uiB ); - sigB = fracF32UI( uiB ); - signZ = signA ^ signB; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( expA == 0xFF ) { - if ( sigA || ((expB == 0xFF) && sigB) ) goto propagateNaN; - magBits = expB | sigB; - goto infArg; - } - if ( expB == 0xFF ) { - if ( sigB ) goto propagateNaN; - magBits = expA | sigA; - goto infArg; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( ! expA ) { - if ( ! sigA ) goto zero; - normExpSig = softfloat_normSubnormalF32Sig( sigA ); - expA = normExpSig.exp; - sigA = normExpSig.sig; - } - if ( ! expB ) { - if ( ! sigB ) goto zero; - normExpSig = softfloat_normSubnormalF32Sig( sigB ); - expB = normExpSig.exp; - sigB = normExpSig.sig; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - expZ = expA + expB - 0x7F; - sigA = (sigA | 0x00800000)<<7; - sigB = (sigB | 0x00800000)<<8; - sigZ = softfloat_shortShiftRightJam64( (uint_fast64_t) sigA * sigB, 32 ); - if ( sigZ < 0x40000000 ) { - --expZ; - sigZ <<= 1; - } - return softfloat_roundPackToF32( signZ, expZ, sigZ ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - propagateNaN: - uiZ = softfloat_propagateNaNF32UI( uiA, uiB ); - goto uiZ; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - infArg: - if ( ! magBits ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - uiZ = defaultNaNF32UI; - } else { - uiZ = packToF32UI( signZ, 0xFF, 0 ); - } - goto uiZ; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - zero: - uiZ = packToF32UI( signZ, 0, 0 ); - uiZ: - uZ.ui = uiZ; - return uZ.f; - -} - diff --git a/deps/SoftFloat-3e/source/f32_mulAdd.c b/deps/SoftFloat-3e/source/f32_mulAdd.c deleted file mode 100644 index 9a28e212ce13..000000000000 --- a/deps/SoftFloat-3e/source/f32_mulAdd.c +++ /dev/null @@ -1,60 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "internals.h" -#include "softfloat.h" - -float32_t f32_mulAdd( float32_t a, float32_t b, float32_t c ) -{ - union ui32_f32 uA; - uint_fast32_t uiA; - union ui32_f32 uB; - uint_fast32_t uiB; - union ui32_f32 uC; - uint_fast32_t uiC; - - uA.f = a; - uiA = uA.ui; - uB.f = b; - uiB = uB.ui; - uC.f = c; - uiC = uC.ui; - return softfloat_mulAddF32( uiA, uiB, uiC, 0 ); - -} - diff --git a/deps/SoftFloat-3e/source/f32_rem.c b/deps/SoftFloat-3e/source/f32_rem.c deleted file mode 100644 index b29bf416e461..000000000000 --- a/deps/SoftFloat-3e/source/f32_rem.c +++ /dev/null @@ -1,168 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -float32_t f32_rem( float32_t a, float32_t b ) -{ - union ui32_f32 uA; - uint_fast32_t uiA; - bool signA; - int_fast16_t expA; - uint_fast32_t sigA; - union ui32_f32 uB; - uint_fast32_t uiB; - int_fast16_t expB; - uint_fast32_t sigB; - struct exp16_sig32 normExpSig; - uint32_t rem; - int_fast16_t expDiff; - uint32_t q, recip32, altRem, meanRem; - bool signRem; - uint_fast32_t uiZ; - union ui32_f32 uZ; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uA.f = a; - uiA = uA.ui; - signA = signF32UI( uiA ); - expA = expF32UI( uiA ); - sigA = fracF32UI( uiA ); - uB.f = b; - uiB = uB.ui; - expB = expF32UI( uiB ); - sigB = fracF32UI( uiB ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( expA == 0xFF ) { - if ( sigA || ((expB == 0xFF) && sigB) ) goto propagateNaN; - goto invalid; - } - if ( expB == 0xFF ) { - if ( sigB ) goto propagateNaN; - return a; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( ! expB ) { - if ( ! sigB ) goto invalid; - normExpSig = softfloat_normSubnormalF32Sig( sigB ); - expB = normExpSig.exp; - sigB = normExpSig.sig; - } - if ( ! expA ) { - if ( ! sigA ) return a; - normExpSig = softfloat_normSubnormalF32Sig( sigA ); - expA = normExpSig.exp; - sigA = normExpSig.sig; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - rem = sigA | 0x00800000; - sigB |= 0x00800000; - expDiff = expA - expB; - if ( expDiff < 1 ) { - if ( expDiff < -1 ) return a; - sigB <<= 6; - if ( expDiff ) { - rem <<= 5; - q = 0; - } else { - rem <<= 6; - q = (sigB <= rem); - if ( q ) rem -= sigB; - } - } else { - recip32 = softfloat_approxRecip32_1( sigB<<8 ); - /*-------------------------------------------------------------------- - | Changing the shift of `rem' here requires also changing the initial - | subtraction from `expDiff'. - *--------------------------------------------------------------------*/ - rem <<= 7; - expDiff -= 31; - /*-------------------------------------------------------------------- - | The scale of `sigB' affects how many bits are obtained during each - | cycle of the loop. Currently this is 29 bits per loop iteration, - | which is believed to be the maximum possible. - *--------------------------------------------------------------------*/ - sigB <<= 6; - for (;;) { - q = (rem * (uint_fast64_t) recip32)>>32; - if ( expDiff < 0 ) break; - rem = -(q * (uint32_t) sigB); - expDiff -= 29; - } - /*-------------------------------------------------------------------- - | (`expDiff' cannot be less than -30 here.) - *--------------------------------------------------------------------*/ - q >>= ~expDiff & 31; - rem = (rem<<(expDiff + 30)) - q * (uint32_t) sigB; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - do { - altRem = rem; - ++q; - rem -= sigB; - } while ( ! (rem & 0x80000000) ); - meanRem = rem + altRem; - if ( (meanRem & 0x80000000) || (! meanRem && (q & 1)) ) rem = altRem; - signRem = signA; - if ( 0x80000000 <= rem ) { - signRem = ! signRem; - rem = -rem; - } - return softfloat_normRoundPackToF32( signRem, expB, rem ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - propagateNaN: - uiZ = softfloat_propagateNaNF32UI( uiA, uiB ); - goto uiZ; - invalid: - softfloat_raiseFlags( softfloat_flag_invalid ); - uiZ = defaultNaNF32UI; - uiZ: - uZ.ui = uiZ; - return uZ.f; - -} - diff --git a/deps/SoftFloat-3e/source/f32_roundToInt.c b/deps/SoftFloat-3e/source/f32_roundToInt.c deleted file mode 100644 index 305af79ddef0..000000000000 --- a/deps/SoftFloat-3e/source/f32_roundToInt.c +++ /dev/null @@ -1,120 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2017 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -float32_t f32_roundToInt( float32_t a, uint_fast8_t roundingMode, bool exact ) -{ - union ui32_f32 uA; - uint_fast32_t uiA; - int_fast16_t exp; - uint_fast32_t uiZ, lastBitMask, roundBitsMask; - union ui32_f32 uZ; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uA.f = a; - uiA = uA.ui; - exp = expF32UI( uiA ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( exp <= 0x7E ) { - if ( !(uint32_t) (uiA<<1) ) return a; - if ( exact ) softfloat_exceptionFlags |= softfloat_flag_inexact; - uiZ = uiA & packToF32UI( 1, 0, 0 ); - switch ( roundingMode ) { - case softfloat_round_near_even: - if ( !fracF32UI( uiA ) ) break; - case softfloat_round_near_maxMag: - if ( exp == 0x7E ) uiZ |= packToF32UI( 0, 0x7F, 0 ); - break; - case softfloat_round_min: - if ( uiZ ) uiZ = packToF32UI( 1, 0x7F, 0 ); - break; - case softfloat_round_max: - if ( !uiZ ) uiZ = packToF32UI( 0, 0x7F, 0 ); - break; -#ifdef SOFTFLOAT_ROUND_ODD - case softfloat_round_odd: - uiZ |= packToF32UI( 0, 0x7F, 0 ); - break; -#endif - } - goto uiZ; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( 0x96 <= exp ) { - if ( (exp == 0xFF) && fracF32UI( uiA ) ) { - uiZ = softfloat_propagateNaNF32UI( uiA, 0 ); - goto uiZ; - } - return a; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uiZ = uiA; - lastBitMask = (uint_fast32_t) 1<<(0x96 - exp); - roundBitsMask = lastBitMask - 1; - if ( roundingMode == softfloat_round_near_maxMag ) { - uiZ += lastBitMask>>1; - } else if ( roundingMode == softfloat_round_near_even ) { - uiZ += lastBitMask>>1; - if ( !(uiZ & roundBitsMask) ) uiZ &= ~lastBitMask; - } else if ( - roundingMode - == (signF32UI( uiZ ) ? softfloat_round_min : softfloat_round_max) - ) { - uiZ += roundBitsMask; - } - uiZ &= ~roundBitsMask; - if ( uiZ != uiA ) { -#ifdef SOFTFLOAT_ROUND_ODD - if ( roundingMode == softfloat_round_odd ) uiZ |= lastBitMask; -#endif - if ( exact ) softfloat_exceptionFlags |= softfloat_flag_inexact; - } - uiZ: - uZ.ui = uiZ; - return uZ.f; - -} - diff --git a/deps/SoftFloat-3e/source/f32_sqrt.c b/deps/SoftFloat-3e/source/f32_sqrt.c deleted file mode 100644 index 9263bde595e2..000000000000 --- a/deps/SoftFloat-3e/source/f32_sqrt.c +++ /dev/null @@ -1,121 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -float32_t f32_sqrt( float32_t a ) -{ - union ui32_f32 uA; - uint_fast32_t uiA; - bool signA; - int_fast16_t expA; - uint_fast32_t sigA, uiZ; - struct exp16_sig32 normExpSig; - int_fast16_t expZ; - uint_fast32_t sigZ, shiftedSigZ; - uint32_t negRem; - union ui32_f32 uZ; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uA.f = a; - uiA = uA.ui; - signA = signF32UI( uiA ); - expA = expF32UI( uiA ); - sigA = fracF32UI( uiA ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( expA == 0xFF ) { - if ( sigA ) { - uiZ = softfloat_propagateNaNF32UI( uiA, 0 ); - goto uiZ; - } - if ( ! signA ) return a; - goto invalid; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( signA ) { - if ( ! (expA | sigA) ) return a; - goto invalid; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( ! expA ) { - if ( ! sigA ) return a; - normExpSig = softfloat_normSubnormalF32Sig( sigA ); - expA = normExpSig.exp; - sigA = normExpSig.sig; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - expZ = ((expA - 0x7F)>>1) + 0x7E; - expA &= 1; - sigA = (sigA | 0x00800000)<<8; - sigZ = - ((uint_fast64_t) sigA * softfloat_approxRecipSqrt32_1( expA, sigA )) - >>32; - if ( expA ) sigZ >>= 1; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - sigZ += 2; - if ( (sigZ & 0x3F) < 2 ) { - shiftedSigZ = sigZ>>2; - negRem = shiftedSigZ * shiftedSigZ; - sigZ &= ~3; - if ( negRem & 0x80000000 ) { - sigZ |= 1; - } else { - if ( negRem ) --sigZ; - } - } - return softfloat_roundPackToF32( 0, expZ, sigZ ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - invalid: - softfloat_raiseFlags( softfloat_flag_invalid ); - uiZ = defaultNaNF32UI; - uiZ: - uZ.ui = uiZ; - return uZ.f; - -} - diff --git a/deps/SoftFloat-3e/source/f32_sub.c b/deps/SoftFloat-3e/source/f32_sub.c deleted file mode 100644 index 383484dae16a..000000000000 --- a/deps/SoftFloat-3e/source/f32_sub.c +++ /dev/null @@ -1,70 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "softfloat.h" - -float32_t f32_sub( float32_t a, float32_t b ) -{ - union ui32_f32 uA; - uint_fast32_t uiA; - union ui32_f32 uB; - uint_fast32_t uiB; -#if ! defined INLINE_LEVEL || (INLINE_LEVEL < 1) - float32_t (*magsFuncPtr)( uint_fast32_t, uint_fast32_t ); -#endif - - uA.f = a; - uiA = uA.ui; - uB.f = b; - uiB = uB.ui; -#if defined INLINE_LEVEL && (1 <= INLINE_LEVEL) - if ( signF32UI( uiA ^ uiB ) ) { - return softfloat_addMagsF32( uiA, uiB ); - } else { - return softfloat_subMagsF32( uiA, uiB ); - } -#else - magsFuncPtr = - signF32UI( uiA ^ uiB ) ? softfloat_addMagsF32 : softfloat_subMagsF32; - return (*magsFuncPtr)( uiA, uiB ); -#endif - -} - diff --git a/deps/SoftFloat-3e/source/f32_to_extF80.c b/deps/SoftFloat-3e/source/f32_to_extF80.c deleted file mode 100644 index 742ed649c58c..000000000000 --- a/deps/SoftFloat-3e/source/f32_to_extF80.c +++ /dev/null @@ -1,101 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -extFloat80_t f32_to_extF80( float32_t a ) -{ - union ui32_f32 uA; - uint_fast32_t uiA; - bool sign; - int_fast16_t exp; - uint_fast32_t frac; - struct commonNaN commonNaN; - struct uint128 uiZ; - uint_fast16_t uiZ64; - uint_fast64_t uiZ0; - struct exp16_sig32 normExpSig; - union { struct extFloat80M s; extFloat80_t f; } uZ; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uA.f = a; - uiA = uA.ui; - sign = signF32UI( uiA ); - exp = expF32UI( uiA ); - frac = fracF32UI( uiA ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( exp == 0xFF ) { - if ( frac ) { - softfloat_f32UIToCommonNaN( uiA, &commonNaN ); - uiZ = softfloat_commonNaNToExtF80UI( &commonNaN ); - uiZ64 = uiZ.v64; - uiZ0 = uiZ.v0; - } else { - uiZ64 = packToExtF80UI64( sign, 0x7FFF ); - uiZ0 = UINT64_C( 0x8000000000000000 ); - } - goto uiZ; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( ! exp ) { - if ( ! frac ) { - uiZ64 = packToExtF80UI64( sign, 0 ); - uiZ0 = 0; - goto uiZ; - } - normExpSig = softfloat_normSubnormalF32Sig( frac ); - exp = normExpSig.exp; - frac = normExpSig.sig; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uiZ64 = packToExtF80UI64( sign, exp + 0x3F80 ); - uiZ0 = (uint_fast64_t) (frac | 0x00800000)<<40; - uiZ: - uZ.s.signExp = uiZ64; - uZ.s.signif = uiZ0; - return uZ.f; - -} - diff --git a/deps/SoftFloat-3e/source/f32_to_extF80M.c b/deps/SoftFloat-3e/source/f32_to_extF80M.c deleted file mode 100644 index af7e32a76eac..000000000000 --- a/deps/SoftFloat-3e/source/f32_to_extF80M.c +++ /dev/null @@ -1,111 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -#ifdef SOFTFLOAT_FAST_INT64 - -void f32_to_extF80M( float32_t a, extFloat80_t *zPtr ) -{ - - *zPtr = f32_to_extF80( a ); - -} - -#else - -void f32_to_extF80M( float32_t a, extFloat80_t *zPtr ) -{ - struct extFloat80M *zSPtr; - union ui32_f32 uA; - uint32_t uiA; - bool sign; - int_fast16_t exp; - uint32_t frac; - struct commonNaN commonNaN; - uint_fast16_t uiZ64; - uint32_t uiZ32; - struct exp16_sig32 normExpSig; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - zSPtr = (struct extFloat80M *) zPtr; - uA.f = a; - uiA = uA.ui; - sign = signF32UI( uiA ); - exp = expF32UI( uiA ); - frac = fracF32UI( uiA ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( exp == 0xFF ) { - if ( frac ) { - softfloat_f32UIToCommonNaN( uiA, &commonNaN ); - softfloat_commonNaNToExtF80M( &commonNaN, zSPtr ); - return; - } - uiZ64 = packToExtF80UI64( sign, 0x7FFF ); - uiZ32 = 0x80000000; - goto uiZ; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( ! exp ) { - if ( ! frac ) { - uiZ64 = packToExtF80UI64( sign, 0 ); - uiZ32 = 0; - goto uiZ; - } - normExpSig = softfloat_normSubnormalF32Sig( frac ); - exp = normExpSig.exp; - frac = normExpSig.sig; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uiZ64 = packToExtF80UI64( sign, exp + 0x3F80 ); - uiZ32 = 0x80000000 | (uint32_t) frac<<8; - uiZ: - zSPtr->signExp = uiZ64; - zSPtr->signif = (uint64_t) uiZ32<<32; - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/f32_to_f128.c b/deps/SoftFloat-3e/source/f32_to_f128.c deleted file mode 100644 index 6a765a44e493..000000000000 --- a/deps/SoftFloat-3e/source/f32_to_f128.c +++ /dev/null @@ -1,96 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -float128_t f32_to_f128( float32_t a ) -{ - union ui32_f32 uA; - uint_fast32_t uiA; - bool sign; - int_fast16_t exp; - uint_fast32_t frac; - struct commonNaN commonNaN; - struct uint128 uiZ; - struct exp16_sig32 normExpSig; - union ui128_f128 uZ; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uA.f = a; - uiA = uA.ui; - sign = signF32UI( uiA ); - exp = expF32UI( uiA ); - frac = fracF32UI( uiA ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( exp == 0xFF ) { - if ( frac ) { - softfloat_f32UIToCommonNaN( uiA, &commonNaN ); - uiZ = softfloat_commonNaNToF128UI( &commonNaN ); - } else { - uiZ.v64 = packToF128UI64( sign, 0x7FFF, 0 ); - uiZ.v0 = 0; - } - goto uiZ; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( ! exp ) { - if ( ! frac ) { - uiZ.v64 = packToF128UI64( sign, 0, 0 ); - uiZ.v0 = 0; - goto uiZ; - } - normExpSig = softfloat_normSubnormalF32Sig( frac ); - exp = normExpSig.exp - 1; - frac = normExpSig.sig; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uiZ.v64 = packToF128UI64( sign, exp + 0x3F80, (uint_fast64_t) frac<<25 ); - uiZ.v0 = 0; - uiZ: - uZ.ui = uiZ; - return uZ.f; - -} - diff --git a/deps/SoftFloat-3e/source/f32_to_f128M.c b/deps/SoftFloat-3e/source/f32_to_f128M.c deleted file mode 100644 index ee7e6b367c9a..000000000000 --- a/deps/SoftFloat-3e/source/f32_to_f128M.c +++ /dev/null @@ -1,115 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -#ifdef SOFTFLOAT_FAST_INT64 - -void f32_to_f128M( float32_t a, float128_t *zPtr ) -{ - - *zPtr = f32_to_f128( a ); - -} - -#else - -void f32_to_f128M( float32_t a, float128_t *zPtr ) -{ - uint32_t *zWPtr; - union ui32_f32 uA; - uint32_t uiA; - bool sign; - int_fast16_t exp; - uint32_t frac, uiZ64; - struct commonNaN commonNaN; - uint32_t uiZ96; - struct exp16_sig32 normExpSig; - uint64_t frac64; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - zWPtr = (uint32_t *) zPtr; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uA.f = a; - uiA = uA.ui; - sign = signF32UI( uiA ); - exp = expF32UI( uiA ); - frac = fracF32UI( uiA ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uiZ64 = 0; - if ( exp == 0xFF ) { - if ( frac ) { - softfloat_f32UIToCommonNaN( uiA, &commonNaN ); - softfloat_commonNaNToF128M( &commonNaN, zWPtr ); - return; - } - uiZ96 = packToF128UI96( sign, 0x7FFF, 0 ); - goto uiZ; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( ! exp ) { - if ( ! frac ) { - uiZ96 = packToF128UI96( sign, 0, 0 ); - goto uiZ; - } - normExpSig = softfloat_normSubnormalF32Sig( frac ); - exp = normExpSig.exp - 1; - frac = normExpSig.sig; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - frac64 = (uint64_t) frac<<25; - uiZ96 = packToF128UI96( sign, exp + 0x3F80, frac64>>32 ); - uiZ64 = frac64; - uiZ: - zWPtr[indexWord( 4, 3 )] = uiZ96; - zWPtr[indexWord( 4, 2 )] = uiZ64; - zWPtr[indexWord( 4, 1 )] = 0; - zWPtr[indexWord( 4, 0 )] = 0; - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/f32_to_f16.c b/deps/SoftFloat-3e/source/f32_to_f16.c deleted file mode 100644 index a9e77b775aa8..000000000000 --- a/deps/SoftFloat-3e/source/f32_to_f16.c +++ /dev/null @@ -1,88 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -float16_t f32_to_f16( float32_t a ) -{ - union ui32_f32 uA; - uint_fast32_t uiA; - bool sign; - int_fast16_t exp; - uint_fast32_t frac; - struct commonNaN commonNaN; - uint_fast16_t uiZ, frac16; - union ui16_f16 uZ; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uA.f = a; - uiA = uA.ui; - sign = signF32UI( uiA ); - exp = expF32UI( uiA ); - frac = fracF32UI( uiA ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( exp == 0xFF ) { - if ( frac ) { - softfloat_f32UIToCommonNaN( uiA, &commonNaN ); - uiZ = softfloat_commonNaNToF16UI( &commonNaN ); - } else { - uiZ = packToF16UI( sign, 0x1F, 0 ); - } - goto uiZ; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - frac16 = frac>>9 | ((frac & 0x1FF) != 0); - if ( ! (exp | frac16) ) { - uiZ = packToF16UI( sign, 0, 0 ); - goto uiZ; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - return softfloat_roundPackToF16( sign, exp - 0x71, frac16 | 0x4000 ); - uiZ: - uZ.ui = uiZ; - return uZ.f; - -} - diff --git a/deps/SoftFloat-3e/source/f32_to_f64.c b/deps/SoftFloat-3e/source/f32_to_f64.c deleted file mode 100644 index 4f97519e8637..000000000000 --- a/deps/SoftFloat-3e/source/f32_to_f64.c +++ /dev/null @@ -1,93 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -float64_t f32_to_f64( float32_t a ) -{ - union ui32_f32 uA; - uint_fast32_t uiA; - bool sign; - int_fast16_t exp; - uint_fast32_t frac; - struct commonNaN commonNaN; - uint_fast64_t uiZ; - struct exp16_sig32 normExpSig; - union ui64_f64 uZ; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uA.f = a; - uiA = uA.ui; - sign = signF32UI( uiA ); - exp = expF32UI( uiA ); - frac = fracF32UI( uiA ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( exp == 0xFF ) { - if ( frac ) { - softfloat_f32UIToCommonNaN( uiA, &commonNaN ); - uiZ = softfloat_commonNaNToF64UI( &commonNaN ); - } else { - uiZ = packToF64UI( sign, 0x7FF, 0 ); - } - goto uiZ; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( ! exp ) { - if ( ! frac ) { - uiZ = packToF64UI( sign, 0, 0 ); - goto uiZ; - } - normExpSig = softfloat_normSubnormalF32Sig( frac ); - exp = normExpSig.exp - 1; - frac = normExpSig.sig; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uiZ = packToF64UI( sign, exp + 0x380, (uint_fast64_t) frac<<29 ); - uiZ: - uZ.ui = uiZ; - return uZ.f; - -} - diff --git a/deps/SoftFloat-3e/source/f32_to_i32.c b/deps/SoftFloat-3e/source/f32_to_i32.c deleted file mode 100644 index 7d0356fbe3b9..000000000000 --- a/deps/SoftFloat-3e/source/f32_to_i32.c +++ /dev/null @@ -1,84 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017 The Regents of the -University of California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -int_fast32_t f32_to_i32( float32_t a, uint_fast8_t roundingMode, bool exact ) -{ - union ui32_f32 uA; - uint_fast32_t uiA; - bool sign; - int_fast16_t exp; - uint_fast32_t sig; - uint_fast64_t sig64; - int_fast16_t shiftDist; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uA.f = a; - uiA = uA.ui; - sign = signF32UI( uiA ); - exp = expF32UI( uiA ); - sig = fracF32UI( uiA ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ -#if (i32_fromNaN != i32_fromPosOverflow) || (i32_fromNaN != i32_fromNegOverflow) - if ( (exp == 0xFF) && sig ) { -#if (i32_fromNaN == i32_fromPosOverflow) - sign = 0; -#elif (i32_fromNaN == i32_fromNegOverflow) - sign = 1; -#else - softfloat_raiseFlags( softfloat_flag_invalid ); - return i32_fromNaN; -#endif - } -#endif - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( exp ) sig |= 0x00800000; - sig64 = (uint_fast64_t) sig<<32; - shiftDist = 0xAA - exp; - if ( 0 < shiftDist ) sig64 = softfloat_shiftRightJam64( sig64, shiftDist ); - return softfloat_roundToI32( sign, sig64, roundingMode, exact ); - -} - diff --git a/deps/SoftFloat-3e/source/f32_to_i32_r_minMag.c b/deps/SoftFloat-3e/source/f32_to_i32_r_minMag.c deleted file mode 100644 index 7652f2ebb024..000000000000 --- a/deps/SoftFloat-3e/source/f32_to_i32_r_minMag.c +++ /dev/null @@ -1,89 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -int_fast32_t f32_to_i32_r_minMag( float32_t a, bool exact ) -{ - union ui32_f32 uA; - uint_fast32_t uiA; - int_fast16_t exp; - uint_fast32_t sig; - int_fast16_t shiftDist; - bool sign; - int_fast32_t absZ; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uA.f = a; - uiA = uA.ui; - exp = expF32UI( uiA ); - sig = fracF32UI( uiA ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - shiftDist = 0x9E - exp; - if ( 32 <= shiftDist ) { - if ( exact && (exp | sig) ) { - softfloat_exceptionFlags |= softfloat_flag_inexact; - } - return 0; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - sign = signF32UI( uiA ); - if ( shiftDist <= 0 ) { - if ( uiA == packToF32UI( 1, 0x9E, 0 ) ) return -0x7FFFFFFF - 1; - softfloat_raiseFlags( softfloat_flag_invalid ); - return - (exp == 0xFF) && sig ? i32_fromNaN - : sign ? i32_fromNegOverflow : i32_fromPosOverflow; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - sig = (sig | 0x00800000)<<8; - absZ = sig>>shiftDist; - if ( exact && ((uint_fast32_t) absZ< -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -int_fast64_t f32_to_i64( float32_t a, uint_fast8_t roundingMode, bool exact ) -{ - union ui32_f32 uA; - uint_fast32_t uiA; - bool sign; - int_fast16_t exp; - uint_fast32_t sig; - int_fast16_t shiftDist; -#ifdef SOFTFLOAT_FAST_INT64 - uint_fast64_t sig64, extra; - struct uint64_extra sig64Extra; -#else - uint32_t extSig[3]; -#endif - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uA.f = a; - uiA = uA.ui; - sign = signF32UI( uiA ); - exp = expF32UI( uiA ); - sig = fracF32UI( uiA ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - shiftDist = 0xBE - exp; - if ( shiftDist < 0 ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - return - (exp == 0xFF) && sig ? i64_fromNaN - : sign ? i64_fromNegOverflow : i64_fromPosOverflow; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( exp ) sig |= 0x00800000; -#ifdef SOFTFLOAT_FAST_INT64 - sig64 = (uint_fast64_t) sig<<40; - extra = 0; - if ( shiftDist ) { - sig64Extra = softfloat_shiftRightJam64Extra( sig64, 0, shiftDist ); - sig64 = sig64Extra.v; - extra = sig64Extra.extra; - } - return softfloat_roundToI64( sign, sig64, extra, roundingMode, exact ); -#else - extSig[indexWord( 3, 2 )] = sig<<8; - extSig[indexWord( 3, 1 )] = 0; - extSig[indexWord( 3, 0 )] = 0; - if ( shiftDist ) softfloat_shiftRightJam96M( extSig, shiftDist, extSig ); - return softfloat_roundMToI64( sign, extSig, roundingMode, exact ); -#endif - -} - diff --git a/deps/SoftFloat-3e/source/f32_to_i64_r_minMag.c b/deps/SoftFloat-3e/source/f32_to_i64_r_minMag.c deleted file mode 100644 index 397ddf6d0dc5..000000000000 --- a/deps/SoftFloat-3e/source/f32_to_i64_r_minMag.c +++ /dev/null @@ -1,94 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -int_fast64_t f32_to_i64_r_minMag( float32_t a, bool exact ) -{ - union ui32_f32 uA; - uint_fast32_t uiA; - int_fast16_t exp; - uint_fast32_t sig; - int_fast16_t shiftDist; - bool sign; - uint_fast64_t sig64; - int_fast64_t absZ; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uA.f = a; - uiA = uA.ui; - exp = expF32UI( uiA ); - sig = fracF32UI( uiA ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - shiftDist = 0xBE - exp; - if ( 64 <= shiftDist ) { - if ( exact && (exp | sig) ) { - softfloat_exceptionFlags |= softfloat_flag_inexact; - } - return 0; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - sign = signF32UI( uiA ); - if ( shiftDist <= 0 ) { - if ( uiA == packToF32UI( 1, 0xBE, 0 ) ) { - return -INT64_C( 0x7FFFFFFFFFFFFFFF ) - 1; - } - softfloat_raiseFlags( softfloat_flag_invalid ); - return - (exp == 0xFF) && sig ? i64_fromNaN - : sign ? i64_fromNegOverflow : i64_fromPosOverflow; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - sig |= 0x00800000; - sig64 = (uint_fast64_t) sig<<40; - absZ = sig64>>shiftDist; - shiftDist = 40 - shiftDist; - if ( exact && (shiftDist < 0) && (uint32_t) (sig<<(shiftDist & 31)) ) { - softfloat_exceptionFlags |= softfloat_flag_inexact; - } - return sign ? -absZ : absZ; - -} - diff --git a/deps/SoftFloat-3e/source/f32_to_ui32.c b/deps/SoftFloat-3e/source/f32_to_ui32.c deleted file mode 100644 index cb47d9458f0d..000000000000 --- a/deps/SoftFloat-3e/source/f32_to_ui32.c +++ /dev/null @@ -1,84 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017 The Regents of the -University of California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -uint_fast32_t f32_to_ui32( float32_t a, uint_fast8_t roundingMode, bool exact ) -{ - union ui32_f32 uA; - uint_fast32_t uiA; - bool sign; - int_fast16_t exp; - uint_fast32_t sig; - uint_fast64_t sig64; - int_fast16_t shiftDist; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uA.f = a; - uiA = uA.ui; - sign = signF32UI( uiA ); - exp = expF32UI( uiA ); - sig = fracF32UI( uiA ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ -#if (ui32_fromNaN != ui32_fromPosOverflow) || (ui32_fromNaN != ui32_fromNegOverflow) - if ( (exp == 0xFF) && sig ) { -#if (ui32_fromNaN == ui32_fromPosOverflow) - sign = 0; -#elif (ui32_fromNaN == ui32_fromNegOverflow) - sign = 1; -#else - softfloat_raiseFlags( softfloat_flag_invalid ); - return ui32_fromNaN; -#endif - } -#endif - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( exp ) sig |= 0x00800000; - sig64 = (uint_fast64_t) sig<<32; - shiftDist = 0xAA - exp; - if ( 0 < shiftDist ) sig64 = softfloat_shiftRightJam64( sig64, shiftDist ); - return softfloat_roundToUI32( sign, sig64, roundingMode, exact ); - -} - diff --git a/deps/SoftFloat-3e/source/f32_to_ui32_r_minMag.c b/deps/SoftFloat-3e/source/f32_to_ui32_r_minMag.c deleted file mode 100644 index cdeb75f9f2ca..000000000000 --- a/deps/SoftFloat-3e/source/f32_to_ui32_r_minMag.c +++ /dev/null @@ -1,88 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -uint_fast32_t f32_to_ui32_r_minMag( float32_t a, bool exact ) -{ - union ui32_f32 uA; - uint_fast32_t uiA; - int_fast16_t exp; - uint_fast32_t sig; - int_fast16_t shiftDist; - bool sign; - uint_fast32_t z; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uA.f = a; - uiA = uA.ui; - exp = expF32UI( uiA ); - sig = fracF32UI( uiA ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - shiftDist = 0x9E - exp; - if ( 32 <= shiftDist ) { - if ( exact && (exp | sig) ) { - softfloat_exceptionFlags |= softfloat_flag_inexact; - } - return 0; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - sign = signF32UI( uiA ); - if ( sign || (shiftDist < 0) ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - return - (exp == 0xFF) && sig ? ui32_fromNaN - : sign ? ui32_fromNegOverflow : ui32_fromPosOverflow; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - sig = (sig | 0x00800000)<<8; - z = sig>>shiftDist; - if ( exact && (z< -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -uint_fast64_t f32_to_ui64( float32_t a, uint_fast8_t roundingMode, bool exact ) -{ - union ui32_f32 uA; - uint_fast32_t uiA; - bool sign; - int_fast16_t exp; - uint_fast32_t sig; - int_fast16_t shiftDist; -#ifdef SOFTFLOAT_FAST_INT64 - uint_fast64_t sig64, extra; - struct uint64_extra sig64Extra; -#else - uint32_t extSig[3]; -#endif - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uA.f = a; - uiA = uA.ui; - sign = signF32UI( uiA ); - exp = expF32UI( uiA ); - sig = fracF32UI( uiA ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - shiftDist = 0xBE - exp; - if ( shiftDist < 0 ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - return - (exp == 0xFF) && sig ? ui64_fromNaN - : sign ? ui64_fromNegOverflow : ui64_fromPosOverflow; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( exp ) sig |= 0x00800000; -#ifdef SOFTFLOAT_FAST_INT64 - sig64 = (uint_fast64_t) sig<<40; - extra = 0; - if ( shiftDist ) { - sig64Extra = softfloat_shiftRightJam64Extra( sig64, 0, shiftDist ); - sig64 = sig64Extra.v; - extra = sig64Extra.extra; - } - return softfloat_roundToUI64( sign, sig64, extra, roundingMode, exact ); -#else - extSig[indexWord( 3, 2 )] = sig<<8; - extSig[indexWord( 3, 1 )] = 0; - extSig[indexWord( 3, 0 )] = 0; - if ( shiftDist ) softfloat_shiftRightJam96M( extSig, shiftDist, extSig ); - return softfloat_roundMToUI64( sign, extSig, roundingMode, exact ); -#endif - -} - diff --git a/deps/SoftFloat-3e/source/f32_to_ui64_r_minMag.c b/deps/SoftFloat-3e/source/f32_to_ui64_r_minMag.c deleted file mode 100644 index c0fe54f6e195..000000000000 --- a/deps/SoftFloat-3e/source/f32_to_ui64_r_minMag.c +++ /dev/null @@ -1,90 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -uint_fast64_t f32_to_ui64_r_minMag( float32_t a, bool exact ) -{ - union ui32_f32 uA; - uint_fast32_t uiA; - int_fast16_t exp; - uint_fast32_t sig; - int_fast16_t shiftDist; - bool sign; - uint_fast64_t sig64, z; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uA.f = a; - uiA = uA.ui; - exp = expF32UI( uiA ); - sig = fracF32UI( uiA ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - shiftDist = 0xBE - exp; - if ( 64 <= shiftDist ) { - if ( exact && (exp | sig) ) { - softfloat_exceptionFlags |= softfloat_flag_inexact; - } - return 0; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - sign = signF32UI( uiA ); - if ( sign || (shiftDist < 0) ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - return - (exp == 0xFF) && sig ? ui64_fromNaN - : sign ? ui64_fromNegOverflow : ui64_fromPosOverflow; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - sig |= 0x00800000; - sig64 = (uint_fast64_t) sig<<40; - z = sig64>>shiftDist; - shiftDist = 40 - shiftDist; - if ( exact && (shiftDist < 0) && (uint32_t) (sig<<(shiftDist & 31)) ) { - softfloat_exceptionFlags |= softfloat_flag_inexact; - } - return z; - -} - diff --git a/deps/SoftFloat-3e/source/f64_add.c b/deps/SoftFloat-3e/source/f64_add.c deleted file mode 100644 index 42f840dc59bf..000000000000 --- a/deps/SoftFloat-3e/source/f64_add.c +++ /dev/null @@ -1,74 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "softfloat.h" - -float64_t f64_add( float64_t a, float64_t b ) -{ - union ui64_f64 uA; - uint_fast64_t uiA; - bool signA; - union ui64_f64 uB; - uint_fast64_t uiB; - bool signB; -#if ! defined INLINE_LEVEL || (INLINE_LEVEL < 2) - float64_t (*magsFuncPtr)( uint_fast64_t, uint_fast64_t, bool ); -#endif - - uA.f = a; - uiA = uA.ui; - signA = signF64UI( uiA ); - uB.f = b; - uiB = uB.ui; - signB = signF64UI( uiB ); -#if defined INLINE_LEVEL && (2 <= INLINE_LEVEL) - if ( signA == signB ) { - return softfloat_addMagsF64( uiA, uiB, signA ); - } else { - return softfloat_subMagsF64( uiA, uiB, signA ); - } -#else - magsFuncPtr = - (signA == signB) ? softfloat_addMagsF64 : softfloat_subMagsF64; - return (*magsFuncPtr)( uiA, uiB, signA ); -#endif - -} - diff --git a/deps/SoftFloat-3e/source/f64_div.c b/deps/SoftFloat-3e/source/f64_div.c deleted file mode 100644 index 9c967bb740ab..000000000000 --- a/deps/SoftFloat-3e/source/f64_div.c +++ /dev/null @@ -1,172 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -float64_t f64_div( float64_t a, float64_t b ) -{ - union ui64_f64 uA; - uint_fast64_t uiA; - bool signA; - int_fast16_t expA; - uint_fast64_t sigA; - union ui64_f64 uB; - uint_fast64_t uiB; - bool signB; - int_fast16_t expB; - uint_fast64_t sigB; - bool signZ; - struct exp16_sig64 normExpSig; - int_fast16_t expZ; - uint32_t recip32, sig32Z, doubleTerm; - uint_fast64_t rem; - uint32_t q; - uint_fast64_t sigZ; - uint_fast64_t uiZ; - union ui64_f64 uZ; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uA.f = a; - uiA = uA.ui; - signA = signF64UI( uiA ); - expA = expF64UI( uiA ); - sigA = fracF64UI( uiA ); - uB.f = b; - uiB = uB.ui; - signB = signF64UI( uiB ); - expB = expF64UI( uiB ); - sigB = fracF64UI( uiB ); - signZ = signA ^ signB; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( expA == 0x7FF ) { - if ( sigA ) goto propagateNaN; - if ( expB == 0x7FF ) { - if ( sigB ) goto propagateNaN; - goto invalid; - } - goto infinity; - } - if ( expB == 0x7FF ) { - if ( sigB ) goto propagateNaN; - goto zero; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( ! expB ) { - if ( ! sigB ) { - if ( ! (expA | sigA) ) goto invalid; - softfloat_raiseFlags( softfloat_flag_infinite ); - goto infinity; - } - normExpSig = softfloat_normSubnormalF64Sig( sigB ); - expB = normExpSig.exp; - sigB = normExpSig.sig; - } - if ( ! expA ) { - if ( ! sigA ) goto zero; - normExpSig = softfloat_normSubnormalF64Sig( sigA ); - expA = normExpSig.exp; - sigA = normExpSig.sig; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - expZ = expA - expB + 0x3FE; - sigA |= UINT64_C( 0x0010000000000000 ); - sigB |= UINT64_C( 0x0010000000000000 ); - if ( sigA < sigB ) { - --expZ; - sigA <<= 11; - } else { - sigA <<= 10; - } - sigB <<= 11; - recip32 = softfloat_approxRecip32_1( sigB>>32 ) - 2; - sig32Z = ((uint32_t) (sigA>>32) * (uint_fast64_t) recip32)>>32; - doubleTerm = sig32Z<<1; - rem = - ((sigA - (uint_fast64_t) doubleTerm * (uint32_t) (sigB>>32))<<28) - - (uint_fast64_t) doubleTerm * ((uint32_t) sigB>>4); - q = (((uint32_t) (rem>>32) * (uint_fast64_t) recip32)>>32) + 4; - sigZ = ((uint_fast64_t) sig32Z<<32) + ((uint_fast64_t) q<<4); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( (sigZ & 0x1FF) < 4<<4 ) { - q &= ~7; - sigZ &= ~(uint_fast64_t) 0x7F; - doubleTerm = q<<1; - rem = - ((rem - (uint_fast64_t) doubleTerm * (uint32_t) (sigB>>32))<<28) - - (uint_fast64_t) doubleTerm * ((uint32_t) sigB>>4); - if ( rem & UINT64_C( 0x8000000000000000 ) ) { - sigZ -= 1<<7; - } else { - if ( rem ) sigZ |= 1; - } - } - return softfloat_roundPackToF64( signZ, expZ, sigZ ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - propagateNaN: - uiZ = softfloat_propagateNaNF64UI( uiA, uiB ); - goto uiZ; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - invalid: - softfloat_raiseFlags( softfloat_flag_invalid ); - uiZ = defaultNaNF64UI; - goto uiZ; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - infinity: - uiZ = packToF64UI( signZ, 0x7FF, 0 ); - goto uiZ; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - zero: - uiZ = packToF64UI( signZ, 0, 0 ); - uiZ: - uZ.ui = uiZ; - return uZ.f; - -} - diff --git a/deps/SoftFloat-3e/source/f64_eq.c b/deps/SoftFloat-3e/source/f64_eq.c deleted file mode 100644 index 36020037953e..000000000000 --- a/deps/SoftFloat-3e/source/f64_eq.c +++ /dev/null @@ -1,66 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -bool f64_eq( float64_t a, float64_t b ) -{ - union ui64_f64 uA; - uint_fast64_t uiA; - union ui64_f64 uB; - uint_fast64_t uiB; - - uA.f = a; - uiA = uA.ui; - uB.f = b; - uiB = uB.ui; - if ( isNaNF64UI( uiA ) || isNaNF64UI( uiB ) ) { - if ( - softfloat_isSigNaNF64UI( uiA ) || softfloat_isSigNaNF64UI( uiB ) - ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - } - return false; - } - return (uiA == uiB) || ! ((uiA | uiB) & UINT64_C( 0x7FFFFFFFFFFFFFFF )); - -} - diff --git a/deps/SoftFloat-3e/source/f64_eq_signaling.c b/deps/SoftFloat-3e/source/f64_eq_signaling.c deleted file mode 100644 index 5daa17937320..000000000000 --- a/deps/SoftFloat-3e/source/f64_eq_signaling.c +++ /dev/null @@ -1,61 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "softfloat.h" - -bool f64_eq_signaling( float64_t a, float64_t b ) -{ - union ui64_f64 uA; - uint_fast64_t uiA; - union ui64_f64 uB; - uint_fast64_t uiB; - - uA.f = a; - uiA = uA.ui; - uB.f = b; - uiB = uB.ui; - if ( isNaNF64UI( uiA ) || isNaNF64UI( uiB ) ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - return false; - } - return (uiA == uiB) || ! ((uiA | uiB) & UINT64_C( 0x7FFFFFFFFFFFFFFF )); - -} - diff --git a/deps/SoftFloat-3e/source/f64_isSignalingNaN.c b/deps/SoftFloat-3e/source/f64_isSignalingNaN.c deleted file mode 100644 index e5d38321ecdd..000000000000 --- a/deps/SoftFloat-3e/source/f64_isSignalingNaN.c +++ /dev/null @@ -1,51 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -bool f64_isSignalingNaN( float64_t a ) -{ - union ui64_f64 uA; - - uA.f = a; - return softfloat_isSigNaNF64UI( uA.ui ); - -} - diff --git a/deps/SoftFloat-3e/source/f64_le.c b/deps/SoftFloat-3e/source/f64_le.c deleted file mode 100644 index 0b43d0467706..000000000000 --- a/deps/SoftFloat-3e/source/f64_le.c +++ /dev/null @@ -1,67 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "softfloat.h" - -bool f64_le( float64_t a, float64_t b ) -{ - union ui64_f64 uA; - uint_fast64_t uiA; - union ui64_f64 uB; - uint_fast64_t uiB; - bool signA, signB; - - uA.f = a; - uiA = uA.ui; - uB.f = b; - uiB = uB.ui; - if ( isNaNF64UI( uiA ) || isNaNF64UI( uiB ) ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - return false; - } - signA = signF64UI( uiA ); - signB = signF64UI( uiB ); - return - (signA != signB) - ? signA || ! ((uiA | uiB) & UINT64_C( 0x7FFFFFFFFFFFFFFF )) - : (uiA == uiB) || (signA ^ (uiA < uiB)); - -} - diff --git a/deps/SoftFloat-3e/source/f64_le_quiet.c b/deps/SoftFloat-3e/source/f64_le_quiet.c deleted file mode 100644 index 832eee7a76bf..000000000000 --- a/deps/SoftFloat-3e/source/f64_le_quiet.c +++ /dev/null @@ -1,72 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -bool f64_le_quiet( float64_t a, float64_t b ) -{ - union ui64_f64 uA; - uint_fast64_t uiA; - union ui64_f64 uB; - uint_fast64_t uiB; - bool signA, signB; - - uA.f = a; - uiA = uA.ui; - uB.f = b; - uiB = uB.ui; - if ( isNaNF64UI( uiA ) || isNaNF64UI( uiB ) ) { - if ( - softfloat_isSigNaNF64UI( uiA ) || softfloat_isSigNaNF64UI( uiB ) - ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - } - return false; - } - signA = signF64UI( uiA ); - signB = signF64UI( uiB ); - return - (signA != signB) - ? signA || ! ((uiA | uiB) & UINT64_C( 0x7FFFFFFFFFFFFFFF )) - : (uiA == uiB) || (signA ^ (uiA < uiB)); - -} - diff --git a/deps/SoftFloat-3e/source/f64_lt.c b/deps/SoftFloat-3e/source/f64_lt.c deleted file mode 100644 index 49ee05be031b..000000000000 --- a/deps/SoftFloat-3e/source/f64_lt.c +++ /dev/null @@ -1,67 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "softfloat.h" - -bool f64_lt( float64_t a, float64_t b ) -{ - union ui64_f64 uA; - uint_fast64_t uiA; - union ui64_f64 uB; - uint_fast64_t uiB; - bool signA, signB; - - uA.f = a; - uiA = uA.ui; - uB.f = b; - uiB = uB.ui; - if ( isNaNF64UI( uiA ) || isNaNF64UI( uiB ) ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - return false; - } - signA = signF64UI( uiA ); - signB = signF64UI( uiB ); - return - (signA != signB) - ? signA && ((uiA | uiB) & UINT64_C( 0x7FFFFFFFFFFFFFFF )) - : (uiA != uiB) && (signA ^ (uiA < uiB)); - -} - diff --git a/deps/SoftFloat-3e/source/f64_lt_quiet.c b/deps/SoftFloat-3e/source/f64_lt_quiet.c deleted file mode 100644 index d64088054927..000000000000 --- a/deps/SoftFloat-3e/source/f64_lt_quiet.c +++ /dev/null @@ -1,72 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -bool f64_lt_quiet( float64_t a, float64_t b ) -{ - union ui64_f64 uA; - uint_fast64_t uiA; - union ui64_f64 uB; - uint_fast64_t uiB; - bool signA, signB; - - uA.f = a; - uiA = uA.ui; - uB.f = b; - uiB = uB.ui; - if ( isNaNF64UI( uiA ) || isNaNF64UI( uiB ) ) { - if ( - softfloat_isSigNaNF64UI( uiA ) || softfloat_isSigNaNF64UI( uiB ) - ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - } - return false; - } - signA = signF64UI( uiA ); - signB = signF64UI( uiB ); - return - (signA != signB) - ? signA && ((uiA | uiB) & UINT64_C( 0x7FFFFFFFFFFFFFFF )) - : (uiA != uiB) && (signA ^ (uiA < uiB)); - -} - diff --git a/deps/SoftFloat-3e/source/f64_mul.c b/deps/SoftFloat-3e/source/f64_mul.c deleted file mode 100644 index 222e91dce4b7..000000000000 --- a/deps/SoftFloat-3e/source/f64_mul.c +++ /dev/null @@ -1,150 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -float64_t f64_mul( float64_t a, float64_t b ) -{ - union ui64_f64 uA; - uint_fast64_t uiA; - bool signA; - int_fast16_t expA; - uint_fast64_t sigA; - union ui64_f64 uB; - uint_fast64_t uiB; - bool signB; - int_fast16_t expB; - uint_fast64_t sigB; - bool signZ; - uint_fast64_t magBits; - struct exp16_sig64 normExpSig; - int_fast16_t expZ; -#ifdef SOFTFLOAT_FAST_INT64 - struct uint128 sig128Z; -#else - uint32_t sig128Z[4]; -#endif - uint_fast64_t sigZ, uiZ; - union ui64_f64 uZ; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uA.f = a; - uiA = uA.ui; - signA = signF64UI( uiA ); - expA = expF64UI( uiA ); - sigA = fracF64UI( uiA ); - uB.f = b; - uiB = uB.ui; - signB = signF64UI( uiB ); - expB = expF64UI( uiB ); - sigB = fracF64UI( uiB ); - signZ = signA ^ signB; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( expA == 0x7FF ) { - if ( sigA || ((expB == 0x7FF) && sigB) ) goto propagateNaN; - magBits = expB | sigB; - goto infArg; - } - if ( expB == 0x7FF ) { - if ( sigB ) goto propagateNaN; - magBits = expA | sigA; - goto infArg; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( ! expA ) { - if ( ! sigA ) goto zero; - normExpSig = softfloat_normSubnormalF64Sig( sigA ); - expA = normExpSig.exp; - sigA = normExpSig.sig; - } - if ( ! expB ) { - if ( ! sigB ) goto zero; - normExpSig = softfloat_normSubnormalF64Sig( sigB ); - expB = normExpSig.exp; - sigB = normExpSig.sig; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - expZ = expA + expB - 0x3FF; - sigA = (sigA | UINT64_C( 0x0010000000000000 ))<<10; - sigB = (sigB | UINT64_C( 0x0010000000000000 ))<<11; -#ifdef SOFTFLOAT_FAST_INT64 - sig128Z = softfloat_mul64To128( sigA, sigB ); - sigZ = sig128Z.v64 | (sig128Z.v0 != 0); -#else - softfloat_mul64To128M( sigA, sigB, sig128Z ); - sigZ = - (uint64_t) sig128Z[indexWord( 4, 3 )]<<32 | sig128Z[indexWord( 4, 2 )]; - if ( sig128Z[indexWord( 4, 1 )] || sig128Z[indexWord( 4, 0 )] ) sigZ |= 1; -#endif - if ( sigZ < UINT64_C( 0x4000000000000000 ) ) { - --expZ; - sigZ <<= 1; - } - return softfloat_roundPackToF64( signZ, expZ, sigZ ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - propagateNaN: - uiZ = softfloat_propagateNaNF64UI( uiA, uiB ); - goto uiZ; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - infArg: - if ( ! magBits ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - uiZ = defaultNaNF64UI; - } else { - uiZ = packToF64UI( signZ, 0x7FF, 0 ); - } - goto uiZ; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - zero: - uiZ = packToF64UI( signZ, 0, 0 ); - uiZ: - uZ.ui = uiZ; - return uZ.f; - -} - diff --git a/deps/SoftFloat-3e/source/f64_mulAdd.c b/deps/SoftFloat-3e/source/f64_mulAdd.c deleted file mode 100644 index fea3d968bf1d..000000000000 --- a/deps/SoftFloat-3e/source/f64_mulAdd.c +++ /dev/null @@ -1,60 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "internals.h" -#include "softfloat.h" - -float64_t f64_mulAdd( float64_t a, float64_t b, float64_t c ) -{ - union ui64_f64 uA; - uint_fast64_t uiA; - union ui64_f64 uB; - uint_fast64_t uiB; - union ui64_f64 uC; - uint_fast64_t uiC; - - uA.f = a; - uiA = uA.ui; - uB.f = b; - uiB = uB.ui; - uC.f = c; - uiC = uC.ui; - return softfloat_mulAddF64( uiA, uiB, uiC, 0 ); - -} - diff --git a/deps/SoftFloat-3e/source/f64_rem.c b/deps/SoftFloat-3e/source/f64_rem.c deleted file mode 100644 index ffce679aa30d..000000000000 --- a/deps/SoftFloat-3e/source/f64_rem.c +++ /dev/null @@ -1,189 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -float64_t f64_rem( float64_t a, float64_t b ) -{ - union ui64_f64 uA; - uint_fast64_t uiA; - bool signA; - int_fast16_t expA; - uint_fast64_t sigA; - union ui64_f64 uB; - uint_fast64_t uiB; - int_fast16_t expB; - uint_fast64_t sigB; - struct exp16_sig64 normExpSig; - uint64_t rem; - int_fast16_t expDiff; - uint32_t q, recip32; - uint_fast64_t q64; - uint64_t altRem, meanRem; - bool signRem; - uint_fast64_t uiZ; - union ui64_f64 uZ; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uA.f = a; - uiA = uA.ui; - signA = signF64UI( uiA ); - expA = expF64UI( uiA ); - sigA = fracF64UI( uiA ); - uB.f = b; - uiB = uB.ui; - expB = expF64UI( uiB ); - sigB = fracF64UI( uiB ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( expA == 0x7FF ) { - if ( sigA || ((expB == 0x7FF) && sigB) ) goto propagateNaN; - goto invalid; - } - if ( expB == 0x7FF ) { - if ( sigB ) goto propagateNaN; - return a; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( expA < expB - 1 ) return a; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( ! expB ) { - if ( ! sigB ) goto invalid; - normExpSig = softfloat_normSubnormalF64Sig( sigB ); - expB = normExpSig.exp; - sigB = normExpSig.sig; - } - if ( ! expA ) { - if ( ! sigA ) return a; - normExpSig = softfloat_normSubnormalF64Sig( sigA ); - expA = normExpSig.exp; - sigA = normExpSig.sig; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - rem = sigA | UINT64_C( 0x0010000000000000 ); - sigB |= UINT64_C( 0x0010000000000000 ); - expDiff = expA - expB; - if ( expDiff < 1 ) { - if ( expDiff < -1 ) return a; - sigB <<= 9; - if ( expDiff ) { - rem <<= 8; - q = 0; - } else { - rem <<= 9; - q = (sigB <= rem); - if ( q ) rem -= sigB; - } - } else { - recip32 = softfloat_approxRecip32_1( sigB>>21 ); - /*-------------------------------------------------------------------- - | Changing the shift of `rem' here requires also changing the initial - | subtraction from `expDiff'. - *--------------------------------------------------------------------*/ - rem <<= 9; - expDiff -= 30; - /*-------------------------------------------------------------------- - | The scale of `sigB' affects how many bits are obtained during each - | cycle of the loop. Currently this is 29 bits per loop iteration, - | the maximum possible. - *--------------------------------------------------------------------*/ - sigB <<= 9; - for (;;) { - q64 = (uint32_t) (rem>>32) * (uint_fast64_t) recip32; - if ( expDiff < 0 ) break; - q = (q64 + 0x80000000)>>32; -#ifdef SOFTFLOAT_FAST_INT64 - rem <<= 29; -#else - rem = (uint_fast64_t) (uint32_t) (rem>>3)<<32; -#endif - rem -= q * (uint64_t) sigB; - if ( rem & UINT64_C( 0x8000000000000000 ) ) rem += sigB; - expDiff -= 29; - } - /*-------------------------------------------------------------------- - | (`expDiff' cannot be less than -29 here.) - *--------------------------------------------------------------------*/ - q = (uint32_t) (q64>>32)>>(~expDiff & 31); - rem = (rem<<(expDiff + 30)) - q * (uint64_t) sigB; - if ( rem & UINT64_C( 0x8000000000000000 ) ) { - altRem = rem + sigB; - goto selectRem; - } - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - do { - altRem = rem; - ++q; - rem -= sigB; - } while ( ! (rem & UINT64_C( 0x8000000000000000 )) ); - selectRem: - meanRem = rem + altRem; - if ( - (meanRem & UINT64_C( 0x8000000000000000 )) || (! meanRem && (q & 1)) - ) { - rem = altRem; - } - signRem = signA; - if ( rem & UINT64_C( 0x8000000000000000 ) ) { - signRem = ! signRem; - rem = -rem; - } - return softfloat_normRoundPackToF64( signRem, expB, rem ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - propagateNaN: - uiZ = softfloat_propagateNaNF64UI( uiA, uiB ); - goto uiZ; - invalid: - softfloat_raiseFlags( softfloat_flag_invalid ); - uiZ = defaultNaNF64UI; - uiZ: - uZ.ui = uiZ; - return uZ.f; - -} - diff --git a/deps/SoftFloat-3e/source/f64_roundToInt.c b/deps/SoftFloat-3e/source/f64_roundToInt.c deleted file mode 100644 index 54e7b0542767..000000000000 --- a/deps/SoftFloat-3e/source/f64_roundToInt.c +++ /dev/null @@ -1,120 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2017 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -float64_t f64_roundToInt( float64_t a, uint_fast8_t roundingMode, bool exact ) -{ - union ui64_f64 uA; - uint_fast64_t uiA; - int_fast16_t exp; - uint_fast64_t uiZ, lastBitMask, roundBitsMask; - union ui64_f64 uZ; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uA.f = a; - uiA = uA.ui; - exp = expF64UI( uiA ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( exp <= 0x3FE ) { - if ( !(uiA & UINT64_C( 0x7FFFFFFFFFFFFFFF )) ) return a; - if ( exact ) softfloat_exceptionFlags |= softfloat_flag_inexact; - uiZ = uiA & packToF64UI( 1, 0, 0 ); - switch ( roundingMode ) { - case softfloat_round_near_even: - if ( !fracF64UI( uiA ) ) break; - case softfloat_round_near_maxMag: - if ( exp == 0x3FE ) uiZ |= packToF64UI( 0, 0x3FF, 0 ); - break; - case softfloat_round_min: - if ( uiZ ) uiZ = packToF64UI( 1, 0x3FF, 0 ); - break; - case softfloat_round_max: - if ( !uiZ ) uiZ = packToF64UI( 0, 0x3FF, 0 ); - break; -#ifdef SOFTFLOAT_ROUND_ODD - case softfloat_round_odd: - uiZ |= packToF64UI( 0, 0x3FF, 0 ); - break; -#endif - } - goto uiZ; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( 0x433 <= exp ) { - if ( (exp == 0x7FF) && fracF64UI( uiA ) ) { - uiZ = softfloat_propagateNaNF64UI( uiA, 0 ); - goto uiZ; - } - return a; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uiZ = uiA; - lastBitMask = (uint_fast64_t) 1<<(0x433 - exp); - roundBitsMask = lastBitMask - 1; - if ( roundingMode == softfloat_round_near_maxMag ) { - uiZ += lastBitMask>>1; - } else if ( roundingMode == softfloat_round_near_even ) { - uiZ += lastBitMask>>1; - if ( !(uiZ & roundBitsMask) ) uiZ &= ~lastBitMask; - } else if ( - roundingMode - == (signF64UI( uiZ ) ? softfloat_round_min : softfloat_round_max) - ) { - uiZ += roundBitsMask; - } - uiZ &= ~roundBitsMask; - if ( uiZ != uiA ) { -#ifdef SOFTFLOAT_ROUND_ODD - if ( roundingMode == softfloat_round_odd ) uiZ |= lastBitMask; -#endif - if ( exact ) softfloat_exceptionFlags |= softfloat_flag_inexact; - } - uiZ: - uZ.ui = uiZ; - return uZ.f; - -} - diff --git a/deps/SoftFloat-3e/source/f64_sqrt.c b/deps/SoftFloat-3e/source/f64_sqrt.c deleted file mode 100644 index f9f226b69766..000000000000 --- a/deps/SoftFloat-3e/source/f64_sqrt.c +++ /dev/null @@ -1,133 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2017 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -float64_t f64_sqrt( float64_t a ) -{ - union ui64_f64 uA; - uint_fast64_t uiA; - bool signA; - int_fast16_t expA; - uint_fast64_t sigA, uiZ; - struct exp16_sig64 normExpSig; - int_fast16_t expZ; - uint32_t sig32A, recipSqrt32, sig32Z; - uint_fast64_t rem; - uint32_t q; - uint_fast64_t sigZ, shiftedSigZ; - union ui64_f64 uZ; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uA.f = a; - uiA = uA.ui; - signA = signF64UI( uiA ); - expA = expF64UI( uiA ); - sigA = fracF64UI( uiA ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( expA == 0x7FF ) { - if ( sigA ) { - uiZ = softfloat_propagateNaNF64UI( uiA, 0 ); - goto uiZ; - } - if ( ! signA ) return a; - goto invalid; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( signA ) { - if ( ! (expA | sigA) ) return a; - goto invalid; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( ! expA ) { - if ( ! sigA ) return a; - normExpSig = softfloat_normSubnormalF64Sig( sigA ); - expA = normExpSig.exp; - sigA = normExpSig.sig; - } - /*------------------------------------------------------------------------ - | (`sig32Z' is guaranteed to be a lower bound on the square root of - | `sig32A', which makes `sig32Z' also a lower bound on the square root of - | `sigA'.) - *------------------------------------------------------------------------*/ - expZ = ((expA - 0x3FF)>>1) + 0x3FE; - expA &= 1; - sigA |= UINT64_C( 0x0010000000000000 ); - sig32A = sigA>>21; - recipSqrt32 = softfloat_approxRecipSqrt32_1( expA, sig32A ); - sig32Z = ((uint_fast64_t) sig32A * recipSqrt32)>>32; - if ( expA ) { - sigA <<= 8; - sig32Z >>= 1; - } else { - sigA <<= 9; - } - rem = sigA - (uint_fast64_t) sig32Z * sig32Z; - q = ((uint32_t) (rem>>2) * (uint_fast64_t) recipSqrt32)>>32; - sigZ = ((uint_fast64_t) sig32Z<<32 | 1<<5) + ((uint_fast64_t) q<<3); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( (sigZ & 0x1FF) < 0x22 ) { - sigZ &= ~(uint_fast64_t) 0x3F; - shiftedSigZ = sigZ>>6; - rem = (sigA<<52) - shiftedSigZ * shiftedSigZ; - if ( rem & UINT64_C( 0x8000000000000000 ) ) { - --sigZ; - } else { - if ( rem ) sigZ |= 1; - } - } - return softfloat_roundPackToF64( 0, expZ, sigZ ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - invalid: - softfloat_raiseFlags( softfloat_flag_invalid ); - uiZ = defaultNaNF64UI; - uiZ: - uZ.ui = uiZ; - return uZ.f; - -} - diff --git a/deps/SoftFloat-3e/source/f64_sub.c b/deps/SoftFloat-3e/source/f64_sub.c deleted file mode 100644 index b5ccb882bbd5..000000000000 --- a/deps/SoftFloat-3e/source/f64_sub.c +++ /dev/null @@ -1,74 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "softfloat.h" - -float64_t f64_sub( float64_t a, float64_t b ) -{ - union ui64_f64 uA; - uint_fast64_t uiA; - bool signA; - union ui64_f64 uB; - uint_fast64_t uiB; - bool signB; -#if ! defined INLINE_LEVEL || (INLINE_LEVEL < 2) - float64_t (*magsFuncPtr)( uint_fast64_t, uint_fast64_t, bool ); -#endif - - uA.f = a; - uiA = uA.ui; - signA = signF64UI( uiA ); - uB.f = b; - uiB = uB.ui; - signB = signF64UI( uiB ); -#if defined INLINE_LEVEL && (2 <= INLINE_LEVEL) - if ( signA == signB ) { - return softfloat_subMagsF64( uiA, uiB, signA ); - } else { - return softfloat_addMagsF64( uiA, uiB, signA ); - } -#else - magsFuncPtr = - (signA == signB) ? softfloat_subMagsF64 : softfloat_addMagsF64; - return (*magsFuncPtr)( uiA, uiB, signA ); -#endif - -} - diff --git a/deps/SoftFloat-3e/source/f64_to_extF80.c b/deps/SoftFloat-3e/source/f64_to_extF80.c deleted file mode 100644 index 2799d9b0709a..000000000000 --- a/deps/SoftFloat-3e/source/f64_to_extF80.c +++ /dev/null @@ -1,101 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -extFloat80_t f64_to_extF80( float64_t a ) -{ - union ui64_f64 uA; - uint_fast64_t uiA; - bool sign; - int_fast16_t exp; - uint_fast64_t frac; - struct commonNaN commonNaN; - struct uint128 uiZ; - uint_fast16_t uiZ64; - uint_fast64_t uiZ0; - struct exp16_sig64 normExpSig; - union { struct extFloat80M s; extFloat80_t f; } uZ; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uA.f = a; - uiA = uA.ui; - sign = signF64UI( uiA ); - exp = expF64UI( uiA ); - frac = fracF64UI( uiA ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( exp == 0x7FF ) { - if ( frac ) { - softfloat_f64UIToCommonNaN( uiA, &commonNaN ); - uiZ = softfloat_commonNaNToExtF80UI( &commonNaN ); - uiZ64 = uiZ.v64; - uiZ0 = uiZ.v0; - } else { - uiZ64 = packToExtF80UI64( sign, 0x7FFF ); - uiZ0 = UINT64_C( 0x8000000000000000 ); - } - goto uiZ; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( ! exp ) { - if ( ! frac ) { - uiZ64 = packToExtF80UI64( sign, 0 ); - uiZ0 = 0; - goto uiZ; - } - normExpSig = softfloat_normSubnormalF64Sig( frac ); - exp = normExpSig.exp; - frac = normExpSig.sig; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uiZ64 = packToExtF80UI64( sign, exp + 0x3C00 ); - uiZ0 = (frac | UINT64_C( 0x0010000000000000 ))<<11; - uiZ: - uZ.s.signExp = uiZ64; - uZ.s.signif = uiZ0; - return uZ.f; - -} - diff --git a/deps/SoftFloat-3e/source/f64_to_extF80M.c b/deps/SoftFloat-3e/source/f64_to_extF80M.c deleted file mode 100644 index a2e67e46fcff..000000000000 --- a/deps/SoftFloat-3e/source/f64_to_extF80M.c +++ /dev/null @@ -1,111 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -#ifdef SOFTFLOAT_FAST_INT64 - -void f64_to_extF80M( float64_t a, extFloat80_t *zPtr ) -{ - - *zPtr = f64_to_extF80( a ); - -} - -#else - -void f64_to_extF80M( float64_t a, extFloat80_t *zPtr ) -{ - struct extFloat80M *zSPtr; - union ui64_f64 uA; - uint64_t uiA; - bool sign; - int_fast16_t exp; - uint64_t frac; - struct commonNaN commonNaN; - uint_fast16_t uiZ64; - uint64_t uiZ0; - struct exp16_sig64 normExpSig; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - zSPtr = (struct extFloat80M *) zPtr; - uA.f = a; - uiA = uA.ui; - sign = signF64UI( uiA ); - exp = expF64UI( uiA ); - frac = fracF64UI( uiA ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( exp == 0x7FF ) { - if ( frac ) { - softfloat_f64UIToCommonNaN( uiA, &commonNaN ); - softfloat_commonNaNToExtF80M( &commonNaN, zSPtr ); - return; - } - uiZ64 = packToExtF80UI64( sign, 0x7FFF ); - uiZ0 = UINT64_C( 0x8000000000000000 ); - goto uiZ; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( ! exp ) { - if ( ! frac ) { - uiZ64 = packToExtF80UI64( sign, 0 ); - uiZ0 = 0; - goto uiZ; - } - normExpSig = softfloat_normSubnormalF64Sig( frac ); - exp = normExpSig.exp; - frac = normExpSig.sig; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uiZ64 = packToExtF80UI64( sign, exp + 0x3C00 ); - uiZ0 = UINT64_C( 0x8000000000000000 ) | frac<<11; - uiZ: - zSPtr->signExp = uiZ64; - zSPtr->signif = uiZ0; - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/f64_to_f128.c b/deps/SoftFloat-3e/source/f64_to_f128.c deleted file mode 100644 index 60af3b0be1aa..000000000000 --- a/deps/SoftFloat-3e/source/f64_to_f128.c +++ /dev/null @@ -1,98 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -float128_t f64_to_f128( float64_t a ) -{ - union ui64_f64 uA; - uint_fast64_t uiA; - bool sign; - int_fast16_t exp; - uint_fast64_t frac; - struct commonNaN commonNaN; - struct uint128 uiZ; - struct exp16_sig64 normExpSig; - struct uint128 frac128; - union ui128_f128 uZ; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uA.f = a; - uiA = uA.ui; - sign = signF64UI( uiA ); - exp = expF64UI( uiA ); - frac = fracF64UI( uiA ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( exp == 0x7FF ) { - if ( frac ) { - softfloat_f64UIToCommonNaN( uiA, &commonNaN ); - uiZ = softfloat_commonNaNToF128UI( &commonNaN ); - } else { - uiZ.v64 = packToF128UI64( sign, 0x7FFF, 0 ); - uiZ.v0 = 0; - } - goto uiZ; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( ! exp ) { - if ( ! frac ) { - uiZ.v64 = packToF128UI64( sign, 0, 0 ); - uiZ.v0 = 0; - goto uiZ; - } - normExpSig = softfloat_normSubnormalF64Sig( frac ); - exp = normExpSig.exp - 1; - frac = normExpSig.sig; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - frac128 = softfloat_shortShiftLeft128( 0, frac, 60 ); - uiZ.v64 = packToF128UI64( sign, exp + 0x3C00, frac128.v64 ); - uiZ.v0 = frac128.v0; - uiZ: - uZ.ui = uiZ; - return uZ.f; - -} - diff --git a/deps/SoftFloat-3e/source/f64_to_f128M.c b/deps/SoftFloat-3e/source/f64_to_f128M.c deleted file mode 100644 index fbc451537397..000000000000 --- a/deps/SoftFloat-3e/source/f64_to_f128M.c +++ /dev/null @@ -1,117 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -#ifdef SOFTFLOAT_FAST_INT64 - -void f64_to_f128M( float64_t a, float128_t *zPtr ) -{ - - *zPtr = f64_to_f128( a ); - -} - -#else - -void f64_to_f128M( float64_t a, float128_t *zPtr ) -{ - uint32_t *zWPtr; - union ui64_f64 uA; - uint64_t uiA; - bool sign; - int_fast16_t exp; - uint64_t frac; - struct commonNaN commonNaN; - uint32_t uiZ96; - struct exp16_sig64 normExpSig; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - zWPtr = (uint32_t *) zPtr; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uA.f = a; - uiA = uA.ui; - sign = signF64UI( uiA ); - exp = expF64UI( uiA ); - frac = fracF64UI( uiA ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - zWPtr[indexWord( 4, 0 )] = 0; - if ( exp == 0x7FF ) { - if ( frac ) { - softfloat_f64UIToCommonNaN( uiA, &commonNaN ); - softfloat_commonNaNToF128M( &commonNaN, zWPtr ); - return; - } - uiZ96 = packToF128UI96( sign, 0x7FFF, 0 ); - goto uiZ; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( ! exp ) { - if ( ! frac ) { - uiZ96 = packToF128UI96( sign, 0, 0 ); - goto uiZ; - } - normExpSig = softfloat_normSubnormalF64Sig( frac ); - exp = normExpSig.exp - 1; - frac = normExpSig.sig; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - zWPtr[indexWord( 4, 1 )] = (uint32_t) frac<<28; - frac >>= 4; - zWPtr[indexWordHi( 4 )] = packToF128UI96( sign, exp + 0x3C00, frac>>32 ); - zWPtr[indexWord( 4, 2 )] = frac; - return; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uiZ: - zWPtr[indexWord( 4, 3 )] = uiZ96; - zWPtr[indexWord( 4, 2 )] = 0; - zWPtr[indexWord( 4, 1 )] = 0; - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/f64_to_f16.c b/deps/SoftFloat-3e/source/f64_to_f16.c deleted file mode 100644 index 121e3062a041..000000000000 --- a/deps/SoftFloat-3e/source/f64_to_f16.c +++ /dev/null @@ -1,88 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -float16_t f64_to_f16( float64_t a ) -{ - union ui64_f64 uA; - uint_fast64_t uiA; - bool sign; - int_fast16_t exp; - uint_fast64_t frac; - struct commonNaN commonNaN; - uint_fast16_t uiZ, frac16; - union ui16_f16 uZ; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uA.f = a; - uiA = uA.ui; - sign = signF64UI( uiA ); - exp = expF64UI( uiA ); - frac = fracF64UI( uiA ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( exp == 0x7FF ) { - if ( frac ) { - softfloat_f64UIToCommonNaN( uiA, &commonNaN ); - uiZ = softfloat_commonNaNToF16UI( &commonNaN ); - } else { - uiZ = packToF16UI( sign, 0x1F, 0 ); - } - goto uiZ; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - frac16 = softfloat_shortShiftRightJam64( frac, 38 ); - if ( ! (exp | frac16) ) { - uiZ = packToF16UI( sign, 0, 0 ); - goto uiZ; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - return softfloat_roundPackToF16( sign, exp - 0x3F1, frac16 | 0x4000 ); - uiZ: - uZ.ui = uiZ; - return uZ.f; - -} - diff --git a/deps/SoftFloat-3e/source/f64_to_f32.c b/deps/SoftFloat-3e/source/f64_to_f32.c deleted file mode 100644 index a18106556da3..000000000000 --- a/deps/SoftFloat-3e/source/f64_to_f32.c +++ /dev/null @@ -1,88 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -float32_t f64_to_f32( float64_t a ) -{ - union ui64_f64 uA; - uint_fast64_t uiA; - bool sign; - int_fast16_t exp; - uint_fast64_t frac; - struct commonNaN commonNaN; - uint_fast32_t uiZ, frac32; - union ui32_f32 uZ; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uA.f = a; - uiA = uA.ui; - sign = signF64UI( uiA ); - exp = expF64UI( uiA ); - frac = fracF64UI( uiA ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( exp == 0x7FF ) { - if ( frac ) { - softfloat_f64UIToCommonNaN( uiA, &commonNaN ); - uiZ = softfloat_commonNaNToF32UI( &commonNaN ); - } else { - uiZ = packToF32UI( sign, 0xFF, 0 ); - } - goto uiZ; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - frac32 = softfloat_shortShiftRightJam64( frac, 22 ); - if ( ! (exp | frac32) ) { - uiZ = packToF32UI( sign, 0, 0 ); - goto uiZ; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - return softfloat_roundPackToF32( sign, exp - 0x381, frac32 | 0x40000000 ); - uiZ: - uZ.ui = uiZ; - return uZ.f; - -} - diff --git a/deps/SoftFloat-3e/source/f64_to_i32.c b/deps/SoftFloat-3e/source/f64_to_i32.c deleted file mode 100644 index 8d9785b0bc62..000000000000 --- a/deps/SoftFloat-3e/source/f64_to_i32.c +++ /dev/null @@ -1,82 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017 The Regents of the -University of California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -int_fast32_t f64_to_i32( float64_t a, uint_fast8_t roundingMode, bool exact ) -{ - union ui64_f64 uA; - uint_fast64_t uiA; - bool sign; - int_fast16_t exp; - uint_fast64_t sig; - int_fast16_t shiftDist; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uA.f = a; - uiA = uA.ui; - sign = signF64UI( uiA ); - exp = expF64UI( uiA ); - sig = fracF64UI( uiA ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ -#if (i32_fromNaN != i32_fromPosOverflow) || (i32_fromNaN != i32_fromNegOverflow) - if ( (exp == 0x7FF) && sig ) { -#if (i32_fromNaN == i32_fromPosOverflow) - sign = 0; -#elif (i32_fromNaN == i32_fromNegOverflow) - sign = 1; -#else - softfloat_raiseFlags( softfloat_flag_invalid ); - return i32_fromNaN; -#endif - } -#endif - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( exp ) sig |= UINT64_C( 0x0010000000000000 ); - shiftDist = 0x427 - exp; - if ( 0 < shiftDist ) sig = softfloat_shiftRightJam64( sig, shiftDist ); - return softfloat_roundToI32( sign, sig, roundingMode, exact ); - -} - diff --git a/deps/SoftFloat-3e/source/f64_to_i32_r_minMag.c b/deps/SoftFloat-3e/source/f64_to_i32_r_minMag.c deleted file mode 100644 index 8b7a91f1c068..000000000000 --- a/deps/SoftFloat-3e/source/f64_to_i32_r_minMag.c +++ /dev/null @@ -1,96 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -int_fast32_t f64_to_i32_r_minMag( float64_t a, bool exact ) -{ - union ui64_f64 uA; - uint_fast64_t uiA; - int_fast16_t exp; - uint_fast64_t sig; - int_fast16_t shiftDist; - bool sign; - int_fast32_t absZ; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uA.f = a; - uiA = uA.ui; - exp = expF64UI( uiA ); - sig = fracF64UI( uiA ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - shiftDist = 0x433 - exp; - if ( 53 <= shiftDist ) { - if ( exact && (exp | sig) ) { - softfloat_exceptionFlags |= softfloat_flag_inexact; - } - return 0; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - sign = signF64UI( uiA ); - if ( shiftDist < 22 ) { - if ( - sign && (exp == 0x41E) && (sig < UINT64_C( 0x0000000000200000 )) - ) { - if ( exact && sig ) { - softfloat_exceptionFlags |= softfloat_flag_inexact; - } - return -0x7FFFFFFF - 1; - } - softfloat_raiseFlags( softfloat_flag_invalid ); - return - (exp == 0x7FF) && sig ? i32_fromNaN - : sign ? i32_fromNegOverflow : i32_fromPosOverflow; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - sig |= UINT64_C( 0x0010000000000000 ); - absZ = sig>>shiftDist; - if ( exact && ((uint_fast64_t) (uint_fast32_t) absZ< -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -int_fast64_t f64_to_i64( float64_t a, uint_fast8_t roundingMode, bool exact ) -{ - union ui64_f64 uA; - uint_fast64_t uiA; - bool sign; - int_fast16_t exp; - uint_fast64_t sig; - int_fast16_t shiftDist; -#ifdef SOFTFLOAT_FAST_INT64 - struct uint64_extra sigExtra; -#else - uint32_t extSig[3]; -#endif - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uA.f = a; - uiA = uA.ui; - sign = signF64UI( uiA ); - exp = expF64UI( uiA ); - sig = fracF64UI( uiA ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( exp ) sig |= UINT64_C( 0x0010000000000000 ); - shiftDist = 0x433 - exp; -#ifdef SOFTFLOAT_FAST_INT64 - if ( shiftDist <= 0 ) { - if ( shiftDist < -11 ) goto invalid; - sigExtra.v = sig<<-shiftDist; - sigExtra.extra = 0; - } else { - sigExtra = softfloat_shiftRightJam64Extra( sig, 0, shiftDist ); - } - return - softfloat_roundToI64( - sign, sigExtra.v, sigExtra.extra, roundingMode, exact ); -#else - extSig[indexWord( 3, 0 )] = 0; - if ( shiftDist <= 0 ) { - if ( shiftDist < -11 ) goto invalid; - sig <<= -shiftDist; - extSig[indexWord( 3, 2 )] = sig>>32; - extSig[indexWord( 3, 1 )] = sig; - } else { - extSig[indexWord( 3, 2 )] = sig>>32; - extSig[indexWord( 3, 1 )] = sig; - softfloat_shiftRightJam96M( extSig, shiftDist, extSig ); - } - return softfloat_roundMToI64( sign, extSig, roundingMode, exact ); -#endif - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - invalid: - softfloat_raiseFlags( softfloat_flag_invalid ); - return - (exp == 0x7FF) && fracF64UI( uiA ) ? i64_fromNaN - : sign ? i64_fromNegOverflow : i64_fromPosOverflow; - -} - diff --git a/deps/SoftFloat-3e/source/f64_to_i64_r_minMag.c b/deps/SoftFloat-3e/source/f64_to_i64_r_minMag.c deleted file mode 100644 index 56c6a101016e..000000000000 --- a/deps/SoftFloat-3e/source/f64_to_i64_r_minMag.c +++ /dev/null @@ -1,100 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -int_fast64_t f64_to_i64_r_minMag( float64_t a, bool exact ) -{ - union ui64_f64 uA; - uint_fast64_t uiA; - bool sign; - int_fast16_t exp; - uint_fast64_t sig; - int_fast16_t shiftDist; - int_fast64_t absZ; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uA.f = a; - uiA = uA.ui; - sign = signF64UI( uiA ); - exp = expF64UI( uiA ); - sig = fracF64UI( uiA ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - shiftDist = 0x433 - exp; - if ( shiftDist <= 0 ) { - /*-------------------------------------------------------------------- - *--------------------------------------------------------------------*/ - if ( shiftDist < -10 ) { - if ( uiA == packToF64UI( 1, 0x43E, 0 ) ) { - return -INT64_C( 0x7FFFFFFFFFFFFFFF ) - 1; - } - softfloat_raiseFlags( softfloat_flag_invalid ); - return - (exp == 0x7FF) && sig ? i64_fromNaN - : sign ? i64_fromNegOverflow : i64_fromPosOverflow; - } - /*-------------------------------------------------------------------- - *--------------------------------------------------------------------*/ - sig |= UINT64_C( 0x0010000000000000 ); - absZ = sig<<-shiftDist; - } else { - /*-------------------------------------------------------------------- - *--------------------------------------------------------------------*/ - if ( 53 <= shiftDist ) { - if ( exact && (exp | sig) ) { - softfloat_exceptionFlags |= softfloat_flag_inexact; - } - return 0; - } - /*-------------------------------------------------------------------- - *--------------------------------------------------------------------*/ - sig |= UINT64_C( 0x0010000000000000 ); - absZ = sig>>shiftDist; - if ( exact && (absZ< -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -uint_fast32_t f64_to_ui32( float64_t a, uint_fast8_t roundingMode, bool exact ) -{ - union ui64_f64 uA; - uint_fast64_t uiA; - bool sign; - int_fast16_t exp; - uint_fast64_t sig; - int_fast16_t shiftDist; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uA.f = a; - uiA = uA.ui; - sign = signF64UI( uiA ); - exp = expF64UI( uiA ); - sig = fracF64UI( uiA ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ -#if (ui32_fromNaN != ui32_fromPosOverflow) || (ui32_fromNaN != ui32_fromNegOverflow) - if ( (exp == 0x7FF) && sig ) { -#if (ui32_fromNaN == ui32_fromPosOverflow) - sign = 0; -#elif (ui32_fromNaN == ui32_fromNegOverflow) - sign = 1; -#else - softfloat_raiseFlags( softfloat_flag_invalid ); - return ui32_fromNaN; -#endif - } -#endif - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( exp ) sig |= UINT64_C( 0x0010000000000000 ); - shiftDist = 0x427 - exp; - if ( 0 < shiftDist ) sig = softfloat_shiftRightJam64( sig, shiftDist ); - return softfloat_roundToUI32( sign, sig, roundingMode, exact ); - -} - diff --git a/deps/SoftFloat-3e/source/f64_to_ui32_r_minMag.c b/deps/SoftFloat-3e/source/f64_to_ui32_r_minMag.c deleted file mode 100644 index 6e3d14e8f338..000000000000 --- a/deps/SoftFloat-3e/source/f64_to_ui32_r_minMag.c +++ /dev/null @@ -1,88 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -uint_fast32_t f64_to_ui32_r_minMag( float64_t a, bool exact ) -{ - union ui64_f64 uA; - uint_fast64_t uiA; - int_fast16_t exp; - uint_fast64_t sig; - int_fast16_t shiftDist; - bool sign; - uint_fast32_t z; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uA.f = a; - uiA = uA.ui; - exp = expF64UI( uiA ); - sig = fracF64UI( uiA ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - shiftDist = 0x433 - exp; - if ( 53 <= shiftDist ) { - if ( exact && (exp | sig) ) { - softfloat_exceptionFlags |= softfloat_flag_inexact; - } - return 0; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - sign = signF64UI( uiA ); - if ( sign || (shiftDist < 21) ) { - softfloat_raiseFlags( softfloat_flag_invalid ); - return - (exp == 0x7FF) && sig ? ui32_fromNaN - : sign ? ui32_fromNegOverflow : ui32_fromPosOverflow; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - sig |= UINT64_C( 0x0010000000000000 ); - z = sig>>shiftDist; - if ( exact && ((uint_fast64_t) z< -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -uint_fast64_t f64_to_ui64( float64_t a, uint_fast8_t roundingMode, bool exact ) -{ - union ui64_f64 uA; - uint_fast64_t uiA; - bool sign; - int_fast16_t exp; - uint_fast64_t sig; - int_fast16_t shiftDist; -#ifdef SOFTFLOAT_FAST_INT64 - struct uint64_extra sigExtra; -#else - uint32_t extSig[3]; -#endif - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uA.f = a; - uiA = uA.ui; - sign = signF64UI( uiA ); - exp = expF64UI( uiA ); - sig = fracF64UI( uiA ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( exp ) sig |= UINT64_C( 0x0010000000000000 ); - shiftDist = 0x433 - exp; -#ifdef SOFTFLOAT_FAST_INT64 - if ( shiftDist <= 0 ) { - if ( shiftDist < -11 ) goto invalid; - sigExtra.v = sig<<-shiftDist; - sigExtra.extra = 0; - } else { - sigExtra = softfloat_shiftRightJam64Extra( sig, 0, shiftDist ); - } - return - softfloat_roundToUI64( - sign, sigExtra.v, sigExtra.extra, roundingMode, exact ); -#else - extSig[indexWord( 3, 0 )] = 0; - if ( shiftDist <= 0 ) { - if ( shiftDist < -11 ) goto invalid; - sig <<= -shiftDist; - extSig[indexWord( 3, 2 )] = sig>>32; - extSig[indexWord( 3, 1 )] = sig; - } else { - extSig[indexWord( 3, 2 )] = sig>>32; - extSig[indexWord( 3, 1 )] = sig; - softfloat_shiftRightJam96M( extSig, shiftDist, extSig ); - } - return softfloat_roundMToUI64( sign, extSig, roundingMode, exact ); -#endif - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - invalid: - softfloat_raiseFlags( softfloat_flag_invalid ); - return - (exp == 0x7FF) && fracF64UI( uiA ) ? ui64_fromNaN - : sign ? ui64_fromNegOverflow : ui64_fromPosOverflow; - -} - diff --git a/deps/SoftFloat-3e/source/f64_to_ui64_r_minMag.c b/deps/SoftFloat-3e/source/f64_to_ui64_r_minMag.c deleted file mode 100644 index 87eb0d05cb3b..000000000000 --- a/deps/SoftFloat-3e/source/f64_to_ui64_r_minMag.c +++ /dev/null @@ -1,93 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -uint_fast64_t f64_to_ui64_r_minMag( float64_t a, bool exact ) -{ - union ui64_f64 uA; - uint_fast64_t uiA; - int_fast16_t exp; - uint_fast64_t sig; - int_fast16_t shiftDist; - bool sign; - uint_fast64_t z; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uA.f = a; - uiA = uA.ui; - exp = expF64UI( uiA ); - sig = fracF64UI( uiA ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - shiftDist = 0x433 - exp; - if ( 53 <= shiftDist ) { - if ( exact && (exp | sig) ) { - softfloat_exceptionFlags |= softfloat_flag_inexact; - } - return 0; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - sign = signF64UI( uiA ); - if ( sign ) goto invalid; - if ( shiftDist <= 0 ) { - if ( shiftDist < -11 ) goto invalid; - z = (sig | UINT64_C( 0x0010000000000000 ))<<-shiftDist; - } else { - sig |= UINT64_C( 0x0010000000000000 ); - z = sig>>shiftDist; - if ( exact && (uint64_t) (sig<<(-shiftDist & 63)) ) { - softfloat_exceptionFlags |= softfloat_flag_inexact; - } - } - return z; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - invalid: - softfloat_raiseFlags( softfloat_flag_invalid ); - return - (exp == 0x7FF) && sig ? ui64_fromNaN - : sign ? ui64_fromNegOverflow : ui64_fromPosOverflow; - -} - diff --git a/deps/SoftFloat-3e/source/i32_to_extF80.c b/deps/SoftFloat-3e/source/i32_to_extF80.c deleted file mode 100644 index 8036fa9f1186..000000000000 --- a/deps/SoftFloat-3e/source/i32_to_extF80.c +++ /dev/null @@ -1,65 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "softfloat.h" - -extFloat80_t i32_to_extF80( int32_t a ) -{ - uint_fast16_t uiZ64; - uint_fast32_t absA; - bool sign; - int_fast8_t shiftDist; - union { struct extFloat80M s; extFloat80_t f; } uZ; - - uiZ64 = 0; - absA = 0; - if ( a ) { - sign = (a < 0); - absA = sign ? -(uint_fast32_t) a : (uint_fast32_t) a; - shiftDist = softfloat_countLeadingZeros32( absA ); - uiZ64 = packToExtF80UI64( sign, 0x401E - shiftDist ); - absA <<= shiftDist; - } - uZ.s.signExp = uiZ64; - uZ.s.signif = (uint_fast64_t) absA<<32; - return uZ.f; - -} - diff --git a/deps/SoftFloat-3e/source/i32_to_extF80M.c b/deps/SoftFloat-3e/source/i32_to_extF80M.c deleted file mode 100644 index 6d5431c1c19c..000000000000 --- a/deps/SoftFloat-3e/source/i32_to_extF80M.c +++ /dev/null @@ -1,78 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "internals.h" -#include "softfloat.h" - -#ifdef SOFTFLOAT_FAST_INT64 - -void i32_to_extF80M( int32_t a, extFloat80_t *zPtr ) -{ - - *zPtr = i32_to_extF80( a ); - -} - -#else - -void i32_to_extF80M( int32_t a, extFloat80_t *zPtr ) -{ - struct extFloat80M *zSPtr; - uint_fast16_t uiZ64; - uint64_t sigZ; - bool sign; - uint32_t absA; - int_fast8_t shiftDist; - - zSPtr = (struct extFloat80M *) zPtr; - uiZ64 = 0; - sigZ = 0; - if ( a ) { - sign = (a < 0); - absA = sign ? -(uint32_t) a : (uint32_t) a; - shiftDist = softfloat_countLeadingZeros32( absA ); - uiZ64 = packToExtF80UI64( sign, 0x401E - shiftDist ); - sigZ = (uint64_t) (absA<signExp = uiZ64; - zSPtr->signif = sigZ; - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/i32_to_f128.c b/deps/SoftFloat-3e/source/i32_to_f128.c deleted file mode 100644 index a7d55cba429a..000000000000 --- a/deps/SoftFloat-3e/source/i32_to_f128.c +++ /dev/null @@ -1,64 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "internals.h" -#include "softfloat.h" - -float128_t i32_to_f128( int32_t a ) -{ - uint_fast64_t uiZ64; - bool sign; - uint_fast32_t absA; - int_fast8_t shiftDist; - union ui128_f128 uZ; - - uiZ64 = 0; - if ( a ) { - sign = (a < 0); - absA = sign ? -(uint_fast32_t) a : (uint_fast32_t) a; - shiftDist = softfloat_countLeadingZeros32( absA ) + 17; - uiZ64 = - packToF128UI64( - sign, 0x402E - shiftDist, (uint_fast64_t) absA< -#include "platform.h" -#include "internals.h" -#include "softfloat.h" - -#ifdef SOFTFLOAT_FAST_INT64 - -void i32_to_f128M( int32_t a, float128_t *zPtr ) -{ - - *zPtr = i32_to_f128( a ); - -} - -#else - -void i32_to_f128M( int32_t a, float128_t *zPtr ) -{ - uint32_t *zWPtr; - uint32_t uiZ96, uiZ64; - bool sign; - uint32_t absA; - int_fast8_t shiftDist; - uint64_t normAbsA; - - zWPtr = (uint32_t *) zPtr; - uiZ96 = 0; - uiZ64 = 0; - if ( a ) { - sign = (a < 0); - absA = sign ? -(uint32_t) a : (uint32_t) a; - shiftDist = softfloat_countLeadingZeros32( absA ) + 17; - normAbsA = (uint64_t) absA<>32 ); - uiZ64 = normAbsA; - } - zWPtr[indexWord( 4, 3 )] = uiZ96; - zWPtr[indexWord( 4, 2 )] = uiZ64; - zWPtr[indexWord( 4, 1 )] = 0; - zWPtr[indexWord( 4, 0 )] = 0; - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/i32_to_f16.c b/deps/SoftFloat-3e/source/i32_to_f16.c deleted file mode 100644 index d3117248a233..000000000000 --- a/deps/SoftFloat-3e/source/i32_to_f16.c +++ /dev/null @@ -1,71 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "softfloat.h" - -float16_t i32_to_f16( int32_t a ) -{ - bool sign; - uint_fast32_t absA; - int_fast8_t shiftDist; - union ui16_f16 u; - uint_fast16_t sig; - - sign = (a < 0); - absA = sign ? -(uint_fast32_t) a : (uint_fast32_t) a; - shiftDist = softfloat_countLeadingZeros32( absA ) - 21; - if ( 0 <= shiftDist ) { - u.ui = - a ? packToF16UI( - sign, 0x18 - shiftDist, (uint_fast16_t) absA<>(-shiftDist) - | ((uint32_t) (absA<<(shiftDist & 31)) != 0) - : (uint_fast16_t) absA< -#include -#include "platform.h" -#include "internals.h" -#include "softfloat.h" - -float32_t i32_to_f32( int32_t a ) -{ - bool sign; - union ui32_f32 uZ; - uint_fast32_t absA; - - sign = (a < 0); - if ( ! (a & 0x7FFFFFFF) ) { - uZ.ui = sign ? packToF32UI( 1, 0x9E, 0 ) : 0; - return uZ.f; - } - absA = sign ? -(uint_fast32_t) a : (uint_fast32_t) a; - return softfloat_normRoundPackToF32( sign, 0x9C, absA ); - -} - diff --git a/deps/SoftFloat-3e/source/i32_to_f64.c b/deps/SoftFloat-3e/source/i32_to_f64.c deleted file mode 100644 index 24feda542d24..000000000000 --- a/deps/SoftFloat-3e/source/i32_to_f64.c +++ /dev/null @@ -1,65 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "softfloat.h" - -float64_t i32_to_f64( int32_t a ) -{ - uint_fast64_t uiZ; - bool sign; - uint_fast32_t absA; - int_fast8_t shiftDist; - union ui64_f64 uZ; - - if ( ! a ) { - uiZ = 0; - } else { - sign = (a < 0); - absA = sign ? -(uint_fast32_t) a : (uint_fast32_t) a; - shiftDist = softfloat_countLeadingZeros32( absA ) + 21; - uiZ = - packToF64UI( - sign, 0x432 - shiftDist, (uint_fast64_t) absA< -#include -#include "platform.h" -#include "internals.h" -#include "softfloat.h" - -extFloat80_t i64_to_extF80( int64_t a ) -{ - uint_fast16_t uiZ64; - uint_fast64_t absA; - bool sign; - int_fast8_t shiftDist; - union { struct extFloat80M s; extFloat80_t f; } uZ; - - uiZ64 = 0; - absA = 0; - if ( a ) { - sign = (a < 0); - absA = sign ? -(uint_fast64_t) a : (uint_fast64_t) a; - shiftDist = softfloat_countLeadingZeros64( absA ); - uiZ64 = packToExtF80UI64( sign, 0x403E - shiftDist ); - absA <<= shiftDist; - } - uZ.s.signExp = uiZ64; - uZ.s.signif = absA; - return uZ.f; - -} - diff --git a/deps/SoftFloat-3e/source/i64_to_extF80M.c b/deps/SoftFloat-3e/source/i64_to_extF80M.c deleted file mode 100644 index 4838dde6dbbb..000000000000 --- a/deps/SoftFloat-3e/source/i64_to_extF80M.c +++ /dev/null @@ -1,78 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "internals.h" -#include "softfloat.h" - -#ifdef SOFTFLOAT_FAST_INT64 - -void i64_to_extF80M( int64_t a, extFloat80_t *zPtr ) -{ - - *zPtr = i64_to_extF80( a ); - -} - -#else - -void i64_to_extF80M( int64_t a, extFloat80_t *zPtr ) -{ - struct extFloat80M *zSPtr; - uint_fast16_t uiZ64; - uint64_t sigZ; - bool sign; - uint64_t absA; - int_fast8_t shiftDist; - - zSPtr = (struct extFloat80M *) zPtr; - uiZ64 = 0; - sigZ = 0; - if ( a ) { - sign = (a < 0); - absA = sign ? -(uint64_t) a : (uint64_t) a; - shiftDist = softfloat_countLeadingZeros64( absA ); - uiZ64 = packToExtF80UI64( sign, 0x403E - shiftDist ); - sigZ = absA<signExp = uiZ64; - zSPtr->signif = sigZ; - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/i64_to_f128.c b/deps/SoftFloat-3e/source/i64_to_f128.c deleted file mode 100644 index fcb0179392c5..000000000000 --- a/deps/SoftFloat-3e/source/i64_to_f128.c +++ /dev/null @@ -1,72 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "internals.h" -#include "softfloat.h" - -float128_t i64_to_f128( int64_t a ) -{ - uint_fast64_t uiZ64, uiZ0; - bool sign; - uint_fast64_t absA; - int_fast8_t shiftDist; - struct uint128 zSig; - union ui128_f128 uZ; - - if ( ! a ) { - uiZ64 = 0; - uiZ0 = 0; - } else { - sign = (a < 0); - absA = sign ? -(uint_fast64_t) a : (uint_fast64_t) a; - shiftDist = softfloat_countLeadingZeros64( absA ) + 49; - if ( 64 <= shiftDist ) { - zSig.v64 = absA<<(shiftDist - 64); - zSig.v0 = 0; - } else { - zSig = softfloat_shortShiftLeft128( 0, absA, shiftDist ); - } - uiZ64 = packToF128UI64( sign, 0x406E - shiftDist, zSig.v64 ); - uiZ0 = zSig.v0; - } - uZ.ui.v64 = uiZ64; - uZ.ui.v0 = uiZ0; - return uZ.f; - -} - diff --git a/deps/SoftFloat-3e/source/i64_to_f128M.c b/deps/SoftFloat-3e/source/i64_to_f128M.c deleted file mode 100644 index 0a04eb8d072b..000000000000 --- a/deps/SoftFloat-3e/source/i64_to_f128M.c +++ /dev/null @@ -1,92 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "internals.h" -#include "softfloat.h" - -#ifdef SOFTFLOAT_FAST_INT64 - -void i64_to_f128M( int64_t a, float128_t *zPtr ) -{ - - *zPtr = i64_to_f128( a ); - -} - -#else - -void i64_to_f128M( int64_t a, float128_t *zPtr ) -{ - uint32_t *zWPtr; - uint32_t uiZ96, uiZ64; - bool sign; - uint64_t absA; - uint_fast8_t shiftDist; - uint32_t *ptr; - - zWPtr = (uint32_t *) zPtr; - uiZ96 = 0; - uiZ64 = 0; - zWPtr[indexWord( 4, 1 )] = 0; - zWPtr[indexWord( 4, 0 )] = 0; - if ( a ) { - sign = (a < 0); - absA = sign ? -(uint64_t) a : (uint64_t) a; - shiftDist = softfloat_countLeadingZeros64( absA ) + 17; - if ( shiftDist < 32 ) { - ptr = zWPtr + indexMultiwordHi( 4, 3 ); - ptr[indexWord( 3, 2 )] = 0; - ptr[indexWord( 3, 1 )] = absA>>32; - ptr[indexWord( 3, 0 )] = absA; - softfloat_shortShiftLeft96M( ptr, shiftDist, ptr ); - ptr[indexWordHi( 3 )] = - packToF128UI96( - sign, 0x404E - shiftDist, ptr[indexWordHi( 3 )] ); - return; - } - absA <<= shiftDist - 32; - uiZ96 = packToF128UI96( sign, 0x404E - shiftDist, absA>>32 ); - uiZ64 = absA; - } - zWPtr[indexWord( 4, 3 )] = uiZ96; - zWPtr[indexWord( 4, 2 )] = uiZ64; - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/i64_to_f16.c b/deps/SoftFloat-3e/source/i64_to_f16.c deleted file mode 100644 index cef7b6133a03..000000000000 --- a/deps/SoftFloat-3e/source/i64_to_f16.c +++ /dev/null @@ -1,70 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "softfloat.h" - -float16_t i64_to_f16( int64_t a ) -{ - bool sign; - uint_fast64_t absA; - int_fast8_t shiftDist; - union ui16_f16 u; - uint_fast16_t sig; - - sign = (a < 0); - absA = sign ? -(uint_fast64_t) a : (uint_fast64_t) a; - shiftDist = softfloat_countLeadingZeros64( absA ) - 53; - if ( 0 <= shiftDist ) { - u.ui = - a ? packToF16UI( - sign, 0x18 - shiftDist, (uint_fast16_t) absA< -#include -#include "platform.h" -#include "internals.h" -#include "softfloat.h" - -float32_t i64_to_f32( int64_t a ) -{ - bool sign; - uint_fast64_t absA; - int_fast8_t shiftDist; - union ui32_f32 u; - uint_fast32_t sig; - - sign = (a < 0); - absA = sign ? -(uint_fast64_t) a : (uint_fast64_t) a; - shiftDist = softfloat_countLeadingZeros64( absA ) - 40; - if ( 0 <= shiftDist ) { - u.ui = - a ? packToF32UI( - sign, 0x95 - shiftDist, (uint_fast32_t) absA< -#include -#include "platform.h" -#include "internals.h" -#include "softfloat.h" - -float64_t i64_to_f64( int64_t a ) -{ - bool sign; - union ui64_f64 uZ; - uint_fast64_t absA; - - sign = (a < 0); - if ( ! (a & UINT64_C( 0x7FFFFFFFFFFFFFFF )) ) { - uZ.ui = sign ? packToF64UI( 1, 0x43E, 0 ) : 0; - return uZ.f; - } - absA = sign ? -(uint_fast64_t) a : (uint_fast64_t) a; - return softfloat_normRoundPackToF64( sign, 0x43C, absA ); - -} - diff --git a/deps/SoftFloat-3e/source/include/internals.h b/deps/SoftFloat-3e/source/include/internals.h deleted file mode 100644 index 020b3402f59f..000000000000 --- a/deps/SoftFloat-3e/source/include/internals.h +++ /dev/null @@ -1,278 +0,0 @@ - -/*============================================================================ - -This C header file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017 The Regents of the -University of California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#ifndef internals_h -#define internals_h 1 - -#include -#include -#include "primitives.h" -#include "softfloat_types.h" - -union ui16_f16 { uint16_t ui; float16_t f; }; -union ui32_f32 { uint32_t ui; float32_t f; }; -union ui64_f64 { uint64_t ui; float64_t f; }; - -#ifdef SOFTFLOAT_FAST_INT64 -union extF80M_extF80 { struct extFloat80M fM; extFloat80_t f; }; -union ui128_f128 { struct uint128 ui; float128_t f; }; -#endif - -enum { - softfloat_mulAdd_subC = 1, - softfloat_mulAdd_subProd = 2 -}; - -/*---------------------------------------------------------------------------- -*----------------------------------------------------------------------------*/ -uint_fast32_t softfloat_roundToUI32( bool, uint_fast64_t, uint_fast8_t, bool ); - -#ifdef SOFTFLOAT_FAST_INT64 -uint_fast64_t - softfloat_roundToUI64( - bool, uint_fast64_t, uint_fast64_t, uint_fast8_t, bool ); -#else -uint_fast64_t softfloat_roundMToUI64( bool, uint32_t *, uint_fast8_t, bool ); -#endif - -int_fast32_t softfloat_roundToI32( bool, uint_fast64_t, uint_fast8_t, bool ); - -#ifdef SOFTFLOAT_FAST_INT64 -int_fast64_t - softfloat_roundToI64( - bool, uint_fast64_t, uint_fast64_t, uint_fast8_t, bool ); -#else -int_fast64_t softfloat_roundMToI64( bool, uint32_t *, uint_fast8_t, bool ); -#endif - -/*---------------------------------------------------------------------------- -*----------------------------------------------------------------------------*/ -#define signF16UI( a ) ((bool) ((uint16_t) (a)>>15)) -#define expF16UI( a ) ((int_fast8_t) ((a)>>10) & 0x1F) -#define fracF16UI( a ) ((a) & 0x03FF) -#define packToF16UI( sign, exp, sig ) (((uint16_t) (sign)<<15) + ((uint16_t) (exp)<<10) + (sig)) - -#define isNaNF16UI( a ) (((~(a) & 0x7C00) == 0) && ((a) & 0x03FF)) - -struct exp8_sig16 { int_fast8_t exp; uint_fast16_t sig; }; -struct exp8_sig16 softfloat_normSubnormalF16Sig( uint_fast16_t ); - -float16_t softfloat_roundPackToF16( bool, int_fast16_t, uint_fast16_t ); -float16_t softfloat_normRoundPackToF16( bool, int_fast16_t, uint_fast16_t ); - -float16_t softfloat_addMagsF16( uint_fast16_t, uint_fast16_t ); -float16_t softfloat_subMagsF16( uint_fast16_t, uint_fast16_t ); -float16_t - softfloat_mulAddF16( - uint_fast16_t, uint_fast16_t, uint_fast16_t, uint_fast8_t ); - -/*---------------------------------------------------------------------------- -*----------------------------------------------------------------------------*/ -#define signF32UI( a ) ((bool) ((uint32_t) (a)>>31)) -#define expF32UI( a ) ((int_fast16_t) ((a)>>23) & 0xFF) -#define fracF32UI( a ) ((a) & 0x007FFFFF) -#define packToF32UI( sign, exp, sig ) (((uint32_t) (sign)<<31) + ((uint32_t) (exp)<<23) + (sig)) - -#define isNaNF32UI( a ) (((~(a) & 0x7F800000) == 0) && ((a) & 0x007FFFFF)) - -struct exp16_sig32 { int_fast16_t exp; uint_fast32_t sig; }; -struct exp16_sig32 softfloat_normSubnormalF32Sig( uint_fast32_t ); - -float32_t softfloat_roundPackToF32( bool, int_fast16_t, uint_fast32_t ); -float32_t softfloat_normRoundPackToF32( bool, int_fast16_t, uint_fast32_t ); - -float32_t softfloat_addMagsF32( uint_fast32_t, uint_fast32_t ); -float32_t softfloat_subMagsF32( uint_fast32_t, uint_fast32_t ); -float32_t - softfloat_mulAddF32( - uint_fast32_t, uint_fast32_t, uint_fast32_t, uint_fast8_t ); - -/*---------------------------------------------------------------------------- -*----------------------------------------------------------------------------*/ -#define signF64UI( a ) ((bool) ((uint64_t) (a)>>63)) -#define expF64UI( a ) ((int_fast16_t) ((a)>>52) & 0x7FF) -#define fracF64UI( a ) ((a) & UINT64_C( 0x000FFFFFFFFFFFFF )) -#define packToF64UI( sign, exp, sig ) ((uint64_t) (((uint_fast64_t) (sign)<<63) + ((uint_fast64_t) (exp)<<52) + (sig))) - -#define isNaNF64UI( a ) (((~(a) & UINT64_C( 0x7FF0000000000000 )) == 0) && ((a) & UINT64_C( 0x000FFFFFFFFFFFFF ))) - -struct exp16_sig64 { int_fast16_t exp; uint_fast64_t sig; }; -struct exp16_sig64 softfloat_normSubnormalF64Sig( uint_fast64_t ); - -float64_t softfloat_roundPackToF64( bool, int_fast16_t, uint_fast64_t ); -float64_t softfloat_normRoundPackToF64( bool, int_fast16_t, uint_fast64_t ); - -float64_t softfloat_addMagsF64( uint_fast64_t, uint_fast64_t, bool ); -float64_t softfloat_subMagsF64( uint_fast64_t, uint_fast64_t, bool ); -float64_t - softfloat_mulAddF64( - uint_fast64_t, uint_fast64_t, uint_fast64_t, uint_fast8_t ); - -/*---------------------------------------------------------------------------- -*----------------------------------------------------------------------------*/ -#define signExtF80UI64( a64 ) ((bool) ((uint16_t) (a64)>>15)) -#define expExtF80UI64( a64 ) ((a64) & 0x7FFF) -#define packToExtF80UI64( sign, exp ) ((uint_fast16_t) (sign)<<15 | (exp)) - -#define isNaNExtF80UI( a64, a0 ) ((((a64) & 0x7FFF) == 0x7FFF) && ((a0) & UINT64_C( 0x7FFFFFFFFFFFFFFF ))) - -#ifdef SOFTFLOAT_FAST_INT64 - -/*---------------------------------------------------------------------------- -*----------------------------------------------------------------------------*/ - -struct exp32_sig64 { int_fast32_t exp; uint64_t sig; }; -struct exp32_sig64 softfloat_normSubnormalExtF80Sig( uint_fast64_t ); - -extFloat80_t - softfloat_roundPackToExtF80( - bool, int_fast32_t, uint_fast64_t, uint_fast64_t, uint_fast8_t ); -extFloat80_t - softfloat_normRoundPackToExtF80( - bool, int_fast32_t, uint_fast64_t, uint_fast64_t, uint_fast8_t ); - -extFloat80_t - softfloat_addMagsExtF80( - uint_fast16_t, uint_fast64_t, uint_fast16_t, uint_fast64_t, bool ); -extFloat80_t - softfloat_subMagsExtF80( - uint_fast16_t, uint_fast64_t, uint_fast16_t, uint_fast64_t, bool ); - -/*---------------------------------------------------------------------------- -*----------------------------------------------------------------------------*/ -#define signF128UI64( a64 ) ((bool) ((uint64_t) (a64)>>63)) -#define expF128UI64( a64 ) ((int_fast32_t) ((a64)>>48) & 0x7FFF) -#define fracF128UI64( a64 ) ((a64) & UINT64_C( 0x0000FFFFFFFFFFFF )) -#define packToF128UI64( sign, exp, sig64 ) (((uint_fast64_t) (sign)<<63) + ((uint_fast64_t) (exp)<<48) + (sig64)) - -#define isNaNF128UI( a64, a0 ) (((~(a64) & UINT64_C( 0x7FFF000000000000 )) == 0) && (a0 || ((a64) & UINT64_C( 0x0000FFFFFFFFFFFF )))) - -struct exp32_sig128 { int_fast32_t exp; struct uint128 sig; }; -struct exp32_sig128 - softfloat_normSubnormalF128Sig( uint_fast64_t, uint_fast64_t ); - -float128_t - softfloat_roundPackToF128( - bool, int_fast32_t, uint_fast64_t, uint_fast64_t, uint_fast64_t ); -float128_t - softfloat_normRoundPackToF128( - bool, int_fast32_t, uint_fast64_t, uint_fast64_t ); - -float128_t - softfloat_addMagsF128( - uint_fast64_t, uint_fast64_t, uint_fast64_t, uint_fast64_t, bool ); -float128_t - softfloat_subMagsF128( - uint_fast64_t, uint_fast64_t, uint_fast64_t, uint_fast64_t, bool ); -float128_t - softfloat_mulAddF128( - uint_fast64_t, - uint_fast64_t, - uint_fast64_t, - uint_fast64_t, - uint_fast64_t, - uint_fast64_t, - uint_fast8_t - ); - -#else - -/*---------------------------------------------------------------------------- -*----------------------------------------------------------------------------*/ - -bool - softfloat_tryPropagateNaNExtF80M( - const struct extFloat80M *, - const struct extFloat80M *, - struct extFloat80M * - ); -void softfloat_invalidExtF80M( struct extFloat80M * ); - -int softfloat_normExtF80SigM( uint64_t * ); - -void - softfloat_roundPackMToExtF80M( - bool, int32_t, uint32_t *, uint_fast8_t, struct extFloat80M * ); -void - softfloat_normRoundPackMToExtF80M( - bool, int32_t, uint32_t *, uint_fast8_t, struct extFloat80M * ); - -void - softfloat_addExtF80M( - const struct extFloat80M *, - const struct extFloat80M *, - struct extFloat80M *, - bool - ); - -int - softfloat_compareNonnormExtF80M( - const struct extFloat80M *, const struct extFloat80M * ); - -/*---------------------------------------------------------------------------- -*----------------------------------------------------------------------------*/ -#define signF128UI96( a96 ) ((bool) ((uint32_t) (a96)>>31)) -#define expF128UI96( a96 ) ((int32_t) ((a96)>>16) & 0x7FFF) -#define fracF128UI96( a96 ) ((a96) & 0x0000FFFF) -#define packToF128UI96( sign, exp, sig96 ) (((uint32_t) (sign)<<31) + ((uint32_t) (exp)<<16) + (sig96)) - -bool softfloat_isNaNF128M( const uint32_t * ); - -bool - softfloat_tryPropagateNaNF128M( - const uint32_t *, const uint32_t *, uint32_t * ); -void softfloat_invalidF128M( uint32_t * ); - -int softfloat_shiftNormSigF128M( const uint32_t *, uint_fast8_t, uint32_t * ); - -void softfloat_roundPackMToF128M( bool, int32_t, uint32_t *, uint32_t * ); -void softfloat_normRoundPackMToF128M( bool, int32_t, uint32_t *, uint32_t * ); - -void - softfloat_addF128M( const uint32_t *, const uint32_t *, uint32_t *, bool ); -void - softfloat_mulAddF128M( - const uint32_t *, - const uint32_t *, - const uint32_t *, - uint32_t *, - uint_fast8_t - ); - -#endif - -#endif - diff --git a/deps/SoftFloat-3e/source/include/opts-GCC.h b/deps/SoftFloat-3e/source/include/opts-GCC.h deleted file mode 100644 index 18c1523e9205..000000000000 --- a/deps/SoftFloat-3e/source/include/opts-GCC.h +++ /dev/null @@ -1,114 +0,0 @@ - -/*============================================================================ - -This C header file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2017 The Regents of the University of California. All rights -reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#ifndef opts_GCC_h -#define opts_GCC_h 1 - -#ifdef INLINE - -#include -#include "primitiveTypes.h" - -#ifdef SOFTFLOAT_BUILTIN_CLZ - -INLINE uint_fast8_t softfloat_countLeadingZeros16( uint16_t a ) - { return a ? __builtin_clz( a ) - 16 : 16; } -#define softfloat_countLeadingZeros16 softfloat_countLeadingZeros16 - -INLINE uint_fast8_t softfloat_countLeadingZeros32( uint32_t a ) - { return a ? __builtin_clz( a ) : 32; } -#define softfloat_countLeadingZeros32 softfloat_countLeadingZeros32 - -INLINE uint_fast8_t softfloat_countLeadingZeros64( uint64_t a ) - { return a ? __builtin_clzll( a ) : 64; } -#define softfloat_countLeadingZeros64 softfloat_countLeadingZeros64 - -#endif - -#ifdef SOFTFLOAT_INTRINSIC_INT128 - -INLINE struct uint128 softfloat_mul64ByShifted32To128( uint64_t a, uint32_t b ) -{ - union { unsigned __int128 ui; struct uint128 s; } uZ; - uZ.ui = (unsigned __int128) a * ((uint_fast64_t) b<<32); - return uZ.s; -} -#define softfloat_mul64ByShifted32To128 softfloat_mul64ByShifted32To128 - -INLINE struct uint128 softfloat_mul64To128( uint64_t a, uint64_t b ) -{ - union { unsigned __int128 ui; struct uint128 s; } uZ; - uZ.ui = (unsigned __int128) a * b; - return uZ.s; -} -#define softfloat_mul64To128 softfloat_mul64To128 - -INLINE -struct uint128 softfloat_mul128By32( uint64_t a64, uint64_t a0, uint32_t b ) -{ - union { unsigned __int128 ui; struct uint128 s; } uZ; - uZ.ui = ((unsigned __int128) a64<<64 | a0) * b; - return uZ.s; -} -#define softfloat_mul128By32 softfloat_mul128By32 - -INLINE -void - softfloat_mul128To256M( - uint64_t a64, uint64_t a0, uint64_t b64, uint64_t b0, uint64_t *zPtr ) -{ - unsigned __int128 z0, mid1, mid, z128; - z0 = (unsigned __int128) a0 * b0; - mid1 = (unsigned __int128) a64 * b0; - mid = mid1 + (unsigned __int128) a0 * b64; - z128 = (unsigned __int128) a64 * b64; - z128 += (unsigned __int128) (mid < mid1)<<64 | mid>>64; - mid <<= 64; - z0 += mid; - z128 += (z0 < mid); - zPtr[indexWord( 4, 0 )] = z0; - zPtr[indexWord( 4, 1 )] = z0>>64; - zPtr[indexWord( 4, 2 )] = z128; - zPtr[indexWord( 4, 3 )] = z128>>64; -} -#define softfloat_mul128To256M softfloat_mul128To256M - -#endif - -#endif - -#endif - diff --git a/deps/SoftFloat-3e/source/include/primitiveTypes.h b/deps/SoftFloat-3e/source/include/primitiveTypes.h deleted file mode 100644 index 4407f5e7cb06..000000000000 --- a/deps/SoftFloat-3e/source/include/primitiveTypes.h +++ /dev/null @@ -1,86 +0,0 @@ - -/*============================================================================ - -This C header file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#ifndef primitiveTypes_h -#define primitiveTypes_h 1 - -#include "platform.h" -#include - -#ifdef SOFTFLOAT_FAST_INT64 - -#ifdef LITTLEENDIAN -struct uint128 { uint64_t v0, v64; }; -struct uint64_extra { uint64_t extra, v; }; -struct uint128_extra { uint64_t extra; struct uint128 v; }; -#else -struct uint128 { uint64_t v64, v0; }; -struct uint64_extra { uint64_t v, extra; }; -struct uint128_extra { struct uint128 v; uint64_t extra; }; -#endif - -#endif - -/*---------------------------------------------------------------------------- -| These macros are used to isolate the differences in word order between big- -| endian and little-endian platforms. -*----------------------------------------------------------------------------*/ -#ifdef LITTLEENDIAN -#define wordIncr 1 -#define indexWord( total, n ) (n) -#define indexWordHi( total ) ((total) - 1) -#define indexWordLo( total ) 0 -#define indexMultiword( total, m, n ) (n) -#define indexMultiwordHi( total, n ) ((total) - (n)) -#define indexMultiwordLo( total, n ) 0 -#define indexMultiwordHiBut( total, n ) (n) -#define indexMultiwordLoBut( total, n ) 0 -#define INIT_UINTM4( v3, v2, v1, v0 ) { v0, v1, v2, v3 } -#else -#define wordIncr -1 -#define indexWord( total, n ) ((total) - 1 - (n)) -#define indexWordHi( total ) 0 -#define indexWordLo( total ) ((total) - 1) -#define indexMultiword( total, m, n ) ((total) - 1 - (m)) -#define indexMultiwordHi( total, n ) 0 -#define indexMultiwordLo( total, n ) ((total) - (n)) -#define indexMultiwordHiBut( total, n ) 0 -#define indexMultiwordLoBut( total, n ) (n) -#define INIT_UINTM4( v3, v2, v1, v0 ) { v3, v2, v1, v0 } -#endif - -#endif - diff --git a/deps/SoftFloat-3e/source/include/primitives.h b/deps/SoftFloat-3e/source/include/primitives.h deleted file mode 100644 index 863ab45b57ca..000000000000 --- a/deps/SoftFloat-3e/source/include/primitives.h +++ /dev/null @@ -1,1160 +0,0 @@ - -/*============================================================================ - -This C header file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017 The Regents of the -University of California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#ifndef primitives_h -#define primitives_h 1 - -#include -#include -#include "primitiveTypes.h" - -#ifndef softfloat_shortShiftRightJam64 -/*---------------------------------------------------------------------------- -| Shifts 'a' right by the number of bits given in 'dist', which must be in -| the range 1 to 63. If any nonzero bits are shifted off, they are "jammed" -| into the least-significant bit of the shifted value by setting the least- -| significant bit to 1. This shifted-and-jammed value is returned. -*----------------------------------------------------------------------------*/ -#if defined INLINE_LEVEL && (2 <= INLINE_LEVEL) -INLINE -uint64_t softfloat_shortShiftRightJam64( uint64_t a, uint_fast8_t dist ) - { return a>>dist | ((a & (((uint_fast64_t) 1<>dist | ((uint32_t) (a<<(-dist & 31)) != 0) : (a != 0); -} -#else -uint32_t softfloat_shiftRightJam32( uint32_t a, uint_fast16_t dist ); -#endif -#endif - -#ifndef softfloat_shiftRightJam64 -/*---------------------------------------------------------------------------- -| Shifts 'a' right by the number of bits given in 'dist', which must not -| be zero. If any nonzero bits are shifted off, they are "jammed" into the -| least-significant bit of the shifted value by setting the least-significant -| bit to 1. This shifted-and-jammed value is returned. -| The value of 'dist' can be arbitrarily large. In particular, if 'dist' is -| greater than 64, the result will be either 0 or 1, depending on whether 'a' -| is zero or nonzero. -*----------------------------------------------------------------------------*/ -#if defined INLINE_LEVEL && (3 <= INLINE_LEVEL) -INLINE uint64_t softfloat_shiftRightJam64( uint64_t a, uint_fast32_t dist ) -{ - return - (dist < 63) ? a>>dist | ((uint64_t) (a<<(-dist & 63)) != 0) : (a != 0); -} -#else -uint64_t softfloat_shiftRightJam64( uint64_t a, uint_fast32_t dist ); -#endif -#endif - -/*---------------------------------------------------------------------------- -| A constant table that translates an 8-bit unsigned integer (the array index) -| into the number of leading 0 bits before the most-significant 1 of that -| integer. For integer zero (index 0), the corresponding table element is 8. -*----------------------------------------------------------------------------*/ -extern const uint_least8_t softfloat_countLeadingZeros8[256]; - -#ifndef softfloat_countLeadingZeros16 -/*---------------------------------------------------------------------------- -| Returns the number of leading 0 bits before the most-significant 1 bit of -| 'a'. If 'a' is zero, 16 is returned. -*----------------------------------------------------------------------------*/ -#if defined INLINE_LEVEL && (2 <= INLINE_LEVEL) -INLINE uint_fast8_t softfloat_countLeadingZeros16( uint16_t a ) -{ - uint_fast8_t count = 8; - if ( 0x100 <= a ) { - count = 0; - a >>= 8; - } - count += softfloat_countLeadingZeros8[a]; - return count; -} -#else -uint_fast8_t softfloat_countLeadingZeros16( uint16_t a ); -#endif -#endif - -#ifndef softfloat_countLeadingZeros32 -/*---------------------------------------------------------------------------- -| Returns the number of leading 0 bits before the most-significant 1 bit of -| 'a'. If 'a' is zero, 32 is returned. -*----------------------------------------------------------------------------*/ -#if defined INLINE_LEVEL && (3 <= INLINE_LEVEL) -INLINE uint_fast8_t softfloat_countLeadingZeros32( uint32_t a ) -{ - uint_fast8_t count = 0; - if ( a < 0x10000 ) { - count = 16; - a <<= 16; - } - if ( a < 0x1000000 ) { - count += 8; - a <<= 8; - } - count += softfloat_countLeadingZeros8[a>>24]; - return count; -} -#else -uint_fast8_t softfloat_countLeadingZeros32( uint32_t a ); -#endif -#endif - -#ifndef softfloat_countLeadingZeros64 -/*---------------------------------------------------------------------------- -| Returns the number of leading 0 bits before the most-significant 1 bit of -| 'a'. If 'a' is zero, 64 is returned. -*----------------------------------------------------------------------------*/ -uint_fast8_t softfloat_countLeadingZeros64( uint64_t a ); -#endif - -extern const uint16_t softfloat_approxRecip_1k0s[16]; -extern const uint16_t softfloat_approxRecip_1k1s[16]; - -#ifndef softfloat_approxRecip32_1 -/*---------------------------------------------------------------------------- -| Returns an approximation to the reciprocal of the number represented by 'a', -| where 'a' is interpreted as an unsigned fixed-point number with one integer -| bit and 31 fraction bits. The 'a' input must be "normalized", meaning that -| its most-significant bit (bit 31) must be 1. Thus, if A is the value of -| the fixed-point interpretation of 'a', then 1 <= A < 2. The returned value -| is interpreted as a pure unsigned fraction, having no integer bits and 32 -| fraction bits. The approximation returned is never greater than the true -| reciprocal 1/A, and it differs from the true reciprocal by at most 2.006 ulp -| (units in the last place). -*----------------------------------------------------------------------------*/ -#ifdef SOFTFLOAT_FAST_DIV64TO32 -#define softfloat_approxRecip32_1( a ) ((uint32_t) (UINT64_C( 0x7FFFFFFFFFFFFFFF ) / (uint32_t) (a))) -#else -uint32_t softfloat_approxRecip32_1( uint32_t a ); -#endif -#endif - -extern const uint16_t softfloat_approxRecipSqrt_1k0s[16]; -extern const uint16_t softfloat_approxRecipSqrt_1k1s[16]; - -#ifndef softfloat_approxRecipSqrt32_1 -/*---------------------------------------------------------------------------- -| Returns an approximation to the reciprocal of the square root of the number -| represented by 'a', where 'a' is interpreted as an unsigned fixed-point -| number either with one integer bit and 31 fraction bits or with two integer -| bits and 30 fraction bits. The format of 'a' is determined by 'oddExpA', -| which must be either 0 or 1. If 'oddExpA' is 1, 'a' is interpreted as -| having one integer bit, and if 'oddExpA' is 0, 'a' is interpreted as having -| two integer bits. The 'a' input must be "normalized", meaning that its -| most-significant bit (bit 31) must be 1. Thus, if A is the value of the -| fixed-point interpretation of 'a', it follows that 1 <= A < 2 when 'oddExpA' -| is 1, and 2 <= A < 4 when 'oddExpA' is 0. -| The returned value is interpreted as a pure unsigned fraction, having -| no integer bits and 32 fraction bits. The approximation returned is never -| greater than the true reciprocal 1/sqrt(A), and it differs from the true -| reciprocal by at most 2.06 ulp (units in the last place). The approximation -| returned is also always within the range 0.5 to 1; thus, the most- -| significant bit of the result is always set. -*----------------------------------------------------------------------------*/ -uint32_t softfloat_approxRecipSqrt32_1( unsigned int oddExpA, uint32_t a ); -#endif - -#ifdef SOFTFLOAT_FAST_INT64 - -/*---------------------------------------------------------------------------- -| The following functions are needed only when 'SOFTFLOAT_FAST_INT64' is -| defined. -*----------------------------------------------------------------------------*/ - -#ifndef softfloat_eq128 -/*---------------------------------------------------------------------------- -| Returns true if the 128-bit unsigned integer formed by concatenating 'a64' -| and 'a0' is equal to the 128-bit unsigned integer formed by concatenating -| 'b64' and 'b0'. -*----------------------------------------------------------------------------*/ -#if defined INLINE_LEVEL && (1 <= INLINE_LEVEL) -INLINE -bool softfloat_eq128( uint64_t a64, uint64_t a0, uint64_t b64, uint64_t b0 ) - { return (a64 == b64) && (a0 == b0); } -#else -bool softfloat_eq128( uint64_t a64, uint64_t a0, uint64_t b64, uint64_t b0 ); -#endif -#endif - -#ifndef softfloat_le128 -/*---------------------------------------------------------------------------- -| Returns true if the 128-bit unsigned integer formed by concatenating 'a64' -| and 'a0' is less than or equal to the 128-bit unsigned integer formed by -| concatenating 'b64' and 'b0'. -*----------------------------------------------------------------------------*/ -#if defined INLINE_LEVEL && (2 <= INLINE_LEVEL) -INLINE -bool softfloat_le128( uint64_t a64, uint64_t a0, uint64_t b64, uint64_t b0 ) - { return (a64 < b64) || ((a64 == b64) && (a0 <= b0)); } -#else -bool softfloat_le128( uint64_t a64, uint64_t a0, uint64_t b64, uint64_t b0 ); -#endif -#endif - -#ifndef softfloat_lt128 -/*---------------------------------------------------------------------------- -| Returns true if the 128-bit unsigned integer formed by concatenating 'a64' -| and 'a0' is less than the 128-bit unsigned integer formed by concatenating -| 'b64' and 'b0'. -*----------------------------------------------------------------------------*/ -#if defined INLINE_LEVEL && (2 <= INLINE_LEVEL) -INLINE -bool softfloat_lt128( uint64_t a64, uint64_t a0, uint64_t b64, uint64_t b0 ) - { return (a64 < b64) || ((a64 == b64) && (a0 < b0)); } -#else -bool softfloat_lt128( uint64_t a64, uint64_t a0, uint64_t b64, uint64_t b0 ); -#endif -#endif - -#ifndef softfloat_shortShiftLeft128 -/*---------------------------------------------------------------------------- -| Shifts the 128 bits formed by concatenating 'a64' and 'a0' left by the -| number of bits given in 'dist', which must be in the range 1 to 63. -*----------------------------------------------------------------------------*/ -#if defined INLINE_LEVEL && (2 <= INLINE_LEVEL) -INLINE -struct uint128 - softfloat_shortShiftLeft128( uint64_t a64, uint64_t a0, uint_fast8_t dist ) -{ - struct uint128 z; - z.v64 = a64<>(-dist & 63); - z.v0 = a0<>dist; - z.v0 = a64<<(-dist & 63) | a0>>dist; - return z; -} -#else -struct uint128 - softfloat_shortShiftRight128( uint64_t a64, uint64_t a0, uint_fast8_t dist ); -#endif -#endif - -#ifndef softfloat_shortShiftRightJam64Extra -/*---------------------------------------------------------------------------- -| This function is the same as 'softfloat_shiftRightJam64Extra' (below), -| except that 'dist' must be in the range 1 to 63. -*----------------------------------------------------------------------------*/ -#if defined INLINE_LEVEL && (2 <= INLINE_LEVEL) -INLINE -struct uint64_extra - softfloat_shortShiftRightJam64Extra( - uint64_t a, uint64_t extra, uint_fast8_t dist ) -{ - struct uint64_extra z; - z.v = a>>dist; - z.extra = a<<(-dist & 63) | (extra != 0); - return z; -} -#else -struct uint64_extra - softfloat_shortShiftRightJam64Extra( - uint64_t a, uint64_t extra, uint_fast8_t dist ); -#endif -#endif - -#ifndef softfloat_shortShiftRightJam128 -/*---------------------------------------------------------------------------- -| Shifts the 128 bits formed by concatenating 'a64' and 'a0' right by the -| number of bits given in 'dist', which must be in the range 1 to 63. If any -| nonzero bits are shifted off, they are "jammed" into the least-significant -| bit of the shifted value by setting the least-significant bit to 1. This -| shifted-and-jammed value is returned. -*----------------------------------------------------------------------------*/ -#if defined INLINE_LEVEL && (3 <= INLINE_LEVEL) -INLINE -struct uint128 - softfloat_shortShiftRightJam128( - uint64_t a64, uint64_t a0, uint_fast8_t dist ) -{ - uint_fast8_t negDist = -dist; - struct uint128 z; - z.v64 = a64>>dist; - z.v0 = - a64<<(negDist & 63) | a0>>dist - | ((uint64_t) (a0<<(negDist & 63)) != 0); - return z; -} -#else -struct uint128 - softfloat_shortShiftRightJam128( - uint64_t a64, uint64_t a0, uint_fast8_t dist ); -#endif -#endif - -#ifndef softfloat_shortShiftRightJam128Extra -/*---------------------------------------------------------------------------- -| This function is the same as 'softfloat_shiftRightJam128Extra' (below), -| except that 'dist' must be in the range 1 to 63. -*----------------------------------------------------------------------------*/ -#if defined INLINE_LEVEL && (3 <= INLINE_LEVEL) -INLINE -struct uint128_extra - softfloat_shortShiftRightJam128Extra( - uint64_t a64, uint64_t a0, uint64_t extra, uint_fast8_t dist ) -{ - uint_fast8_t negDist = -dist; - struct uint128_extra z; - z.v.v64 = a64>>dist; - z.v.v0 = a64<<(negDist & 63) | a0>>dist; - z.extra = a0<<(negDist & 63) | (extra != 0); - return z; -} -#else -struct uint128_extra - softfloat_shortShiftRightJam128Extra( - uint64_t a64, uint64_t a0, uint64_t extra, uint_fast8_t dist ); -#endif -#endif - -#ifndef softfloat_shiftRightJam64Extra -/*---------------------------------------------------------------------------- -| Shifts the 128 bits formed by concatenating 'a' and 'extra' right by 64 -| _plus_ the number of bits given in 'dist', which must not be zero. This -| shifted value is at most 64 nonzero bits and is returned in the 'v' field -| of the 'struct uint64_extra' result. The 64-bit 'extra' field of the result -| contains a value formed as follows from the bits that were shifted off: The -| _last_ bit shifted off is the most-significant bit of the 'extra' field, and -| the other 63 bits of the 'extra' field are all zero if and only if _all_but_ -| _the_last_ bits shifted off were all zero. -| (This function makes more sense if 'a' and 'extra' are considered to form -| an unsigned fixed-point number with binary point between 'a' and 'extra'. -| This fixed-point value is shifted right by the number of bits given in -| 'dist', and the integer part of this shifted value is returned in the 'v' -| field of the result. The fractional part of the shifted value is modified -| as described above and returned in the 'extra' field of the result.) -*----------------------------------------------------------------------------*/ -#if defined INLINE_LEVEL && (4 <= INLINE_LEVEL) -INLINE -struct uint64_extra - softfloat_shiftRightJam64Extra( - uint64_t a, uint64_t extra, uint_fast32_t dist ) -{ - struct uint64_extra z; - if ( dist < 64 ) { - z.v = a>>dist; - z.extra = a<<(-dist & 63); - } else { - z.v = 0; - z.extra = (dist == 64) ? a : (a != 0); - } - z.extra |= (extra != 0); - return z; -} -#else -struct uint64_extra - softfloat_shiftRightJam64Extra( - uint64_t a, uint64_t extra, uint_fast32_t dist ); -#endif -#endif - -#ifndef softfloat_shiftRightJam128 -/*---------------------------------------------------------------------------- -| Shifts the 128 bits formed by concatenating 'a64' and 'a0' right by the -| number of bits given in 'dist', which must not be zero. If any nonzero bits -| are shifted off, they are "jammed" into the least-significant bit of the -| shifted value by setting the least-significant bit to 1. This shifted-and- -| jammed value is returned. -| The value of 'dist' can be arbitrarily large. In particular, if 'dist' is -| greater than 128, the result will be either 0 or 1, depending on whether the -| original 128 bits are all zeros. -*----------------------------------------------------------------------------*/ -struct uint128 - softfloat_shiftRightJam128( uint64_t a64, uint64_t a0, uint_fast32_t dist ); -#endif - -#ifndef softfloat_shiftRightJam128Extra -/*---------------------------------------------------------------------------- -| Shifts the 192 bits formed by concatenating 'a64', 'a0', and 'extra' right -| by 64 _plus_ the number of bits given in 'dist', which must not be zero. -| This shifted value is at most 128 nonzero bits and is returned in the 'v' -| field of the 'struct uint128_extra' result. The 64-bit 'extra' field of the -| result contains a value formed as follows from the bits that were shifted -| off: The _last_ bit shifted off is the most-significant bit of the 'extra' -| field, and the other 63 bits of the 'extra' field are all zero if and only -| if _all_but_the_last_ bits shifted off were all zero. -| (This function makes more sense if 'a64', 'a0', and 'extra' are considered -| to form an unsigned fixed-point number with binary point between 'a0' and -| 'extra'. This fixed-point value is shifted right by the number of bits -| given in 'dist', and the integer part of this shifted value is returned -| in the 'v' field of the result. The fractional part of the shifted value -| is modified as described above and returned in the 'extra' field of the -| result.) -*----------------------------------------------------------------------------*/ -struct uint128_extra - softfloat_shiftRightJam128Extra( - uint64_t a64, uint64_t a0, uint64_t extra, uint_fast32_t dist ); -#endif - -#ifndef softfloat_shiftRightJam256M -/*---------------------------------------------------------------------------- -| Shifts the 256-bit unsigned integer pointed to by 'aPtr' right by the number -| of bits given in 'dist', which must not be zero. If any nonzero bits are -| shifted off, they are "jammed" into the least-significant bit of the shifted -| value by setting the least-significant bit to 1. This shifted-and-jammed -| value is stored at the location pointed to by 'zPtr'. Each of 'aPtr' and -| 'zPtr' points to an array of four 64-bit elements that concatenate in the -| platform's normal endian order to form a 256-bit integer. -| The value of 'dist' can be arbitrarily large. In particular, if 'dist' -| is greater than 256, the stored result will be either 0 or 1, depending on -| whether the original 256 bits are all zeros. -*----------------------------------------------------------------------------*/ -void - softfloat_shiftRightJam256M( - const uint64_t *aPtr, uint_fast32_t dist, uint64_t *zPtr ); -#endif - -#ifndef softfloat_add128 -/*---------------------------------------------------------------------------- -| Returns the sum of the 128-bit integer formed by concatenating 'a64' and -| 'a0' and the 128-bit integer formed by concatenating 'b64' and 'b0'. The -| addition is modulo 2^128, so any carry out is lost. -*----------------------------------------------------------------------------*/ -#if defined INLINE_LEVEL && (2 <= INLINE_LEVEL) -INLINE -struct uint128 - softfloat_add128( uint64_t a64, uint64_t a0, uint64_t b64, uint64_t b0 ) -{ - struct uint128 z; - z.v0 = a0 + b0; - z.v64 = a64 + b64 + (z.v0 < a0); - return z; -} -#else -struct uint128 - softfloat_add128( uint64_t a64, uint64_t a0, uint64_t b64, uint64_t b0 ); -#endif -#endif - -#ifndef softfloat_add256M -/*---------------------------------------------------------------------------- -| Adds the two 256-bit integers pointed to by 'aPtr' and 'bPtr'. The addition -| is modulo 2^256, so any carry out is lost. The sum is stored at the -| location pointed to by 'zPtr'. Each of 'aPtr', 'bPtr', and 'zPtr' points to -| an array of four 64-bit elements that concatenate in the platform's normal -| endian order to form a 256-bit integer. -*----------------------------------------------------------------------------*/ -void - softfloat_add256M( - const uint64_t *aPtr, const uint64_t *bPtr, uint64_t *zPtr ); -#endif - -#ifndef softfloat_sub128 -/*---------------------------------------------------------------------------- -| Returns the difference of the 128-bit integer formed by concatenating 'a64' -| and 'a0' and the 128-bit integer formed by concatenating 'b64' and 'b0'. -| The subtraction is modulo 2^128, so any borrow out (carry out) is lost. -*----------------------------------------------------------------------------*/ -#if defined INLINE_LEVEL && (2 <= INLINE_LEVEL) -INLINE -struct uint128 - softfloat_sub128( uint64_t a64, uint64_t a0, uint64_t b64, uint64_t b0 ) -{ - struct uint128 z; - z.v0 = a0 - b0; - z.v64 = a64 - b64; - z.v64 -= (a0 < b0); - return z; -} -#else -struct uint128 - softfloat_sub128( uint64_t a64, uint64_t a0, uint64_t b64, uint64_t b0 ); -#endif -#endif - -#ifndef softfloat_sub256M -/*---------------------------------------------------------------------------- -| Subtracts the 256-bit integer pointed to by 'bPtr' from the 256-bit integer -| pointed to by 'aPtr'. The addition is modulo 2^256, so any borrow out -| (carry out) is lost. The difference is stored at the location pointed to -| by 'zPtr'. Each of 'aPtr', 'bPtr', and 'zPtr' points to an array of four -| 64-bit elements that concatenate in the platform's normal endian order to -| form a 256-bit integer. -*----------------------------------------------------------------------------*/ -void - softfloat_sub256M( - const uint64_t *aPtr, const uint64_t *bPtr, uint64_t *zPtr ); -#endif - -#ifndef softfloat_mul64ByShifted32To128 -/*---------------------------------------------------------------------------- -| Returns the 128-bit product of 'a', 'b', and 2^32. -*----------------------------------------------------------------------------*/ -#if defined INLINE_LEVEL && (3 <= INLINE_LEVEL) -INLINE struct uint128 softfloat_mul64ByShifted32To128( uint64_t a, uint32_t b ) -{ - uint_fast64_t mid; - struct uint128 z; - mid = (uint_fast64_t) (uint32_t) a * b; - z.v0 = mid<<32; - z.v64 = (uint_fast64_t) (uint32_t) (a>>32) * b + (mid>>32); - return z; -} -#else -struct uint128 softfloat_mul64ByShifted32To128( uint64_t a, uint32_t b ); -#endif -#endif - -#ifndef softfloat_mul64To128 -/*---------------------------------------------------------------------------- -| Returns the 128-bit product of 'a' and 'b'. -*----------------------------------------------------------------------------*/ -struct uint128 softfloat_mul64To128( uint64_t a, uint64_t b ); -#endif - -#ifndef softfloat_mul128By32 -/*---------------------------------------------------------------------------- -| Returns the product of the 128-bit integer formed by concatenating 'a64' and -| 'a0', multiplied by 'b'. The multiplication is modulo 2^128; any overflow -| bits are discarded. -*----------------------------------------------------------------------------*/ -#if defined INLINE_LEVEL && (4 <= INLINE_LEVEL) -INLINE -struct uint128 softfloat_mul128By32( uint64_t a64, uint64_t a0, uint32_t b ) -{ - struct uint128 z; - uint_fast64_t mid; - uint_fast32_t carry; - z.v0 = a0 * b; - mid = (uint_fast64_t) (uint32_t) (a0>>32) * b; - carry = (uint32_t) ((uint_fast32_t) (z.v0>>32) - (uint_fast32_t) mid); - z.v64 = a64 * b + (uint_fast32_t) ((mid + carry)>>32); - return z; -} -#else -struct uint128 softfloat_mul128By32( uint64_t a64, uint64_t a0, uint32_t b ); -#endif -#endif - -#ifndef softfloat_mul128To256M -/*---------------------------------------------------------------------------- -| Multiplies the 128-bit unsigned integer formed by concatenating 'a64' and -| 'a0' by the 128-bit unsigned integer formed by concatenating 'b64' and -| 'b0'. The 256-bit product is stored at the location pointed to by 'zPtr'. -| Argument 'zPtr' points to an array of four 64-bit elements that concatenate -| in the platform's normal endian order to form a 256-bit integer. -*----------------------------------------------------------------------------*/ -void - softfloat_mul128To256M( - uint64_t a64, uint64_t a0, uint64_t b64, uint64_t b0, uint64_t *zPtr ); -#endif - -#else - -/*---------------------------------------------------------------------------- -| The following functions are needed only when 'SOFTFLOAT_FAST_INT64' is not -| defined. -*----------------------------------------------------------------------------*/ - -#ifndef softfloat_compare96M -/*---------------------------------------------------------------------------- -| Compares the two 96-bit unsigned integers pointed to by 'aPtr' and 'bPtr'. -| Returns -1 if the first integer (A) is less than the second (B); returns 0 -| if the two integers are equal; and returns +1 if the first integer (A) -| is greater than the second (B). (The result is thus the signum of A - B.) -| Each of 'aPtr' and 'bPtr' points to an array of three 32-bit elements that -| concatenate in the platform's normal endian order to form a 96-bit integer. -*----------------------------------------------------------------------------*/ -int_fast8_t softfloat_compare96M( const uint32_t *aPtr, const uint32_t *bPtr ); -#endif - -#ifndef softfloat_compare128M -/*---------------------------------------------------------------------------- -| Compares the two 128-bit unsigned integers pointed to by 'aPtr' and 'bPtr'. -| Returns -1 if the first integer (A) is less than the second (B); returns 0 -| if the two integers are equal; and returns +1 if the first integer (A) -| is greater than the second (B). (The result is thus the signum of A - B.) -| Each of 'aPtr' and 'bPtr' points to an array of four 32-bit elements that -| concatenate in the platform's normal endian order to form a 128-bit integer. -*----------------------------------------------------------------------------*/ -int_fast8_t - softfloat_compare128M( const uint32_t *aPtr, const uint32_t *bPtr ); -#endif - -#ifndef softfloat_shortShiftLeft64To96M -/*---------------------------------------------------------------------------- -| Extends 'a' to 96 bits and shifts the value left by the number of bits given -| in 'dist', which must be in the range 1 to 31. The result is stored at the -| location pointed to by 'zPtr'. Argument 'zPtr' points to an array of three -| 32-bit elements that concatenate in the platform's normal endian order to -| form a 96-bit integer. -*----------------------------------------------------------------------------*/ -#if defined INLINE_LEVEL && (2 <= INLINE_LEVEL) -INLINE -void - softfloat_shortShiftLeft64To96M( - uint64_t a, uint_fast8_t dist, uint32_t *zPtr ) -{ - zPtr[indexWord( 3, 0 )] = (uint32_t) a<>= 32 - dist; - zPtr[indexWord( 3, 2 )] = a>>32; - zPtr[indexWord( 3, 1 )] = a; -} -#else -void - softfloat_shortShiftLeft64To96M( - uint64_t a, uint_fast8_t dist, uint32_t *zPtr ); -#endif -#endif - -#ifndef softfloat_shortShiftLeftM -/*---------------------------------------------------------------------------- -| Shifts the N-bit unsigned integer pointed to by 'aPtr' left by the number -| of bits given in 'dist', where N = 'size_words' * 32. The value of 'dist' -| must be in the range 1 to 31. Any nonzero bits shifted off are lost. The -| shifted N-bit result is stored at the location pointed to by 'zPtr'. Each -| of 'aPtr' and 'zPtr' points to a 'size_words'-long array of 32-bit elements -| that concatenate in the platform's normal endian order to form an N-bit -| integer. -*----------------------------------------------------------------------------*/ -void - softfloat_shortShiftLeftM( - uint_fast8_t size_words, - const uint32_t *aPtr, - uint_fast8_t dist, - uint32_t *zPtr - ); -#endif - -#ifndef softfloat_shortShiftLeft96M -/*---------------------------------------------------------------------------- -| This function or macro is the same as 'softfloat_shortShiftLeftM' with -| 'size_words' = 3 (N = 96). -*----------------------------------------------------------------------------*/ -#define softfloat_shortShiftLeft96M( aPtr, dist, zPtr ) softfloat_shortShiftLeftM( 3, aPtr, dist, zPtr ) -#endif - -#ifndef softfloat_shortShiftLeft128M -/*---------------------------------------------------------------------------- -| This function or macro is the same as 'softfloat_shortShiftLeftM' with -| 'size_words' = 4 (N = 128). -*----------------------------------------------------------------------------*/ -#define softfloat_shortShiftLeft128M( aPtr, dist, zPtr ) softfloat_shortShiftLeftM( 4, aPtr, dist, zPtr ) -#endif - -#ifndef softfloat_shortShiftLeft160M -/*---------------------------------------------------------------------------- -| This function or macro is the same as 'softfloat_shortShiftLeftM' with -| 'size_words' = 5 (N = 160). -*----------------------------------------------------------------------------*/ -#define softfloat_shortShiftLeft160M( aPtr, dist, zPtr ) softfloat_shortShiftLeftM( 5, aPtr, dist, zPtr ) -#endif - -#ifndef softfloat_shiftLeftM -/*---------------------------------------------------------------------------- -| Shifts the N-bit unsigned integer pointed to by 'aPtr' left by the number -| of bits given in 'dist', where N = 'size_words' * 32. The value of 'dist' -| must not be zero. Any nonzero bits shifted off are lost. The shifted -| N-bit result is stored at the location pointed to by 'zPtr'. Each of 'aPtr' -| and 'zPtr' points to a 'size_words'-long array of 32-bit elements that -| concatenate in the platform's normal endian order to form an N-bit integer. -| The value of 'dist' can be arbitrarily large. In particular, if 'dist' is -| greater than N, the stored result will be 0. -*----------------------------------------------------------------------------*/ -void - softfloat_shiftLeftM( - uint_fast8_t size_words, - const uint32_t *aPtr, - uint32_t dist, - uint32_t *zPtr - ); -#endif - -#ifndef softfloat_shiftLeft96M -/*---------------------------------------------------------------------------- -| This function or macro is the same as 'softfloat_shiftLeftM' with -| 'size_words' = 3 (N = 96). -*----------------------------------------------------------------------------*/ -#define softfloat_shiftLeft96M( aPtr, dist, zPtr ) softfloat_shiftLeftM( 3, aPtr, dist, zPtr ) -#endif - -#ifndef softfloat_shiftLeft128M -/*---------------------------------------------------------------------------- -| This function or macro is the same as 'softfloat_shiftLeftM' with -| 'size_words' = 4 (N = 128). -*----------------------------------------------------------------------------*/ -#define softfloat_shiftLeft128M( aPtr, dist, zPtr ) softfloat_shiftLeftM( 4, aPtr, dist, zPtr ) -#endif - -#ifndef softfloat_shiftLeft160M -/*---------------------------------------------------------------------------- -| This function or macro is the same as 'softfloat_shiftLeftM' with -| 'size_words' = 5 (N = 160). -*----------------------------------------------------------------------------*/ -#define softfloat_shiftLeft160M( aPtr, dist, zPtr ) softfloat_shiftLeftM( 5, aPtr, dist, zPtr ) -#endif - -#ifndef softfloat_shortShiftRightM -/*---------------------------------------------------------------------------- -| Shifts the N-bit unsigned integer pointed to by 'aPtr' right by the number -| of bits given in 'dist', where N = 'size_words' * 32. The value of 'dist' -| must be in the range 1 to 31. Any nonzero bits shifted off are lost. The -| shifted N-bit result is stored at the location pointed to by 'zPtr'. Each -| of 'aPtr' and 'zPtr' points to a 'size_words'-long array of 32-bit elements -| that concatenate in the platform's normal endian order to form an N-bit -| integer. -*----------------------------------------------------------------------------*/ -void - softfloat_shortShiftRightM( - uint_fast8_t size_words, - const uint32_t *aPtr, - uint_fast8_t dist, - uint32_t *zPtr - ); -#endif - -#ifndef softfloat_shortShiftRight128M -/*---------------------------------------------------------------------------- -| This function or macro is the same as 'softfloat_shortShiftRightM' with -| 'size_words' = 4 (N = 128). -*----------------------------------------------------------------------------*/ -#define softfloat_shortShiftRight128M( aPtr, dist, zPtr ) softfloat_shortShiftRightM( 4, aPtr, dist, zPtr ) -#endif - -#ifndef softfloat_shortShiftRight160M -/*---------------------------------------------------------------------------- -| This function or macro is the same as 'softfloat_shortShiftRightM' with -| 'size_words' = 5 (N = 160). -*----------------------------------------------------------------------------*/ -#define softfloat_shortShiftRight160M( aPtr, dist, zPtr ) softfloat_shortShiftRightM( 5, aPtr, dist, zPtr ) -#endif - -#ifndef softfloat_shortShiftRightJamM -/*---------------------------------------------------------------------------- -| Shifts the N-bit unsigned integer pointed to by 'aPtr' right by the number -| of bits given in 'dist', where N = 'size_words' * 32. The value of 'dist' -| must be in the range 1 to 31. If any nonzero bits are shifted off, they are -| "jammed" into the least-significant bit of the shifted value by setting the -| least-significant bit to 1. This shifted-and-jammed N-bit result is stored -| at the location pointed to by 'zPtr'. Each of 'aPtr' and 'zPtr' points -| to a 'size_words'-long array of 32-bit elements that concatenate in the -| platform's normal endian order to form an N-bit integer. -*----------------------------------------------------------------------------*/ -void - softfloat_shortShiftRightJamM( - uint_fast8_t, const uint32_t *, uint_fast8_t, uint32_t * ); -#endif - -#ifndef softfloat_shortShiftRightJam160M -/*---------------------------------------------------------------------------- -| This function or macro is the same as 'softfloat_shortShiftRightJamM' with -| 'size_words' = 5 (N = 160). -*----------------------------------------------------------------------------*/ -#define softfloat_shortShiftRightJam160M( aPtr, dist, zPtr ) softfloat_shortShiftRightJamM( 5, aPtr, dist, zPtr ) -#endif - -#ifndef softfloat_shiftRightM -/*---------------------------------------------------------------------------- -| Shifts the N-bit unsigned integer pointed to by 'aPtr' right by the number -| of bits given in 'dist', where N = 'size_words' * 32. The value of 'dist' -| must not be zero. Any nonzero bits shifted off are lost. The shifted -| N-bit result is stored at the location pointed to by 'zPtr'. Each of 'aPtr' -| and 'zPtr' points to a 'size_words'-long array of 32-bit elements that -| concatenate in the platform's normal endian order to form an N-bit integer. -| The value of 'dist' can be arbitrarily large. In particular, if 'dist' is -| greater than N, the stored result will be 0. -*----------------------------------------------------------------------------*/ -void - softfloat_shiftRightM( - uint_fast8_t size_words, - const uint32_t *aPtr, - uint32_t dist, - uint32_t *zPtr - ); -#endif - -#ifndef softfloat_shiftRight96M -/*---------------------------------------------------------------------------- -| This function or macro is the same as 'softfloat_shiftRightM' with -| 'size_words' = 3 (N = 96). -*----------------------------------------------------------------------------*/ -#define softfloat_shiftRight96M( aPtr, dist, zPtr ) softfloat_shiftRightM( 3, aPtr, dist, zPtr ) -#endif - -#ifndef softfloat_shiftRightJamM -/*---------------------------------------------------------------------------- -| Shifts the N-bit unsigned integer pointed to by 'aPtr' right by the number -| of bits given in 'dist', where N = 'size_words' * 32. The value of 'dist' -| must not be zero. If any nonzero bits are shifted off, they are "jammed" -| into the least-significant bit of the shifted value by setting the least- -| significant bit to 1. This shifted-and-jammed N-bit result is stored -| at the location pointed to by 'zPtr'. Each of 'aPtr' and 'zPtr' points -| to a 'size_words'-long array of 32-bit elements that concatenate in the -| platform's normal endian order to form an N-bit integer. -| The value of 'dist' can be arbitrarily large. In particular, if 'dist' -| is greater than N, the stored result will be either 0 or 1, depending on -| whether the original N bits are all zeros. -*----------------------------------------------------------------------------*/ -void - softfloat_shiftRightJamM( - uint_fast8_t size_words, - const uint32_t *aPtr, - uint32_t dist, - uint32_t *zPtr - ); -#endif - -#ifndef softfloat_shiftRightJam96M -/*---------------------------------------------------------------------------- -| This function or macro is the same as 'softfloat_shiftRightJamM' with -| 'size_words' = 3 (N = 96). -*----------------------------------------------------------------------------*/ -#define softfloat_shiftRightJam96M( aPtr, dist, zPtr ) softfloat_shiftRightJamM( 3, aPtr, dist, zPtr ) -#endif - -#ifndef softfloat_shiftRightJam128M -/*---------------------------------------------------------------------------- -| This function or macro is the same as 'softfloat_shiftRightJamM' with -| 'size_words' = 4 (N = 128). -*----------------------------------------------------------------------------*/ -#define softfloat_shiftRightJam128M( aPtr, dist, zPtr ) softfloat_shiftRightJamM( 4, aPtr, dist, zPtr ) -#endif - -#ifndef softfloat_shiftRightJam160M -/*---------------------------------------------------------------------------- -| This function or macro is the same as 'softfloat_shiftRightJamM' with -| 'size_words' = 5 (N = 160). -*----------------------------------------------------------------------------*/ -#define softfloat_shiftRightJam160M( aPtr, dist, zPtr ) softfloat_shiftRightJamM( 5, aPtr, dist, zPtr ) -#endif - -#ifndef softfloat_addM -/*---------------------------------------------------------------------------- -| Adds the two N-bit integers pointed to by 'aPtr' and 'bPtr', where N = -| 'size_words' * 32. The addition is modulo 2^N, so any carry out is lost. -| The N-bit sum is stored at the location pointed to by 'zPtr'. Each of -| 'aPtr', 'bPtr', and 'zPtr' points to a 'size_words'-long array of 32-bit -| elements that concatenate in the platform's normal endian order to form an -| N-bit integer. -*----------------------------------------------------------------------------*/ -void - softfloat_addM( - uint_fast8_t size_words, - const uint32_t *aPtr, - const uint32_t *bPtr, - uint32_t *zPtr - ); -#endif - -#ifndef softfloat_add96M -/*---------------------------------------------------------------------------- -| This function or macro is the same as 'softfloat_addM' with 'size_words' -| = 3 (N = 96). -*----------------------------------------------------------------------------*/ -#define softfloat_add96M( aPtr, bPtr, zPtr ) softfloat_addM( 3, aPtr, bPtr, zPtr ) -#endif - -#ifndef softfloat_add128M -/*---------------------------------------------------------------------------- -| This function or macro is the same as 'softfloat_addM' with 'size_words' -| = 4 (N = 128). -*----------------------------------------------------------------------------*/ -#define softfloat_add128M( aPtr, bPtr, zPtr ) softfloat_addM( 4, aPtr, bPtr, zPtr ) -#endif - -#ifndef softfloat_add160M -/*---------------------------------------------------------------------------- -| This function or macro is the same as 'softfloat_addM' with 'size_words' -| = 5 (N = 160). -*----------------------------------------------------------------------------*/ -#define softfloat_add160M( aPtr, bPtr, zPtr ) softfloat_addM( 5, aPtr, bPtr, zPtr ) -#endif - -#ifndef softfloat_addCarryM -/*---------------------------------------------------------------------------- -| Adds the two N-bit unsigned integers pointed to by 'aPtr' and 'bPtr', where -| N = 'size_words' * 32, plus 'carry', which must be either 0 or 1. The N-bit -| sum (modulo 2^N) is stored at the location pointed to by 'zPtr', and any -| carry out is returned as the result. Each of 'aPtr', 'bPtr', and 'zPtr' -| points to a 'size_words'-long array of 32-bit elements that concatenate in -| the platform's normal endian order to form an N-bit integer. -*----------------------------------------------------------------------------*/ -uint_fast8_t - softfloat_addCarryM( - uint_fast8_t size_words, - const uint32_t *aPtr, - const uint32_t *bPtr, - uint_fast8_t carry, - uint32_t *zPtr - ); -#endif - -#ifndef softfloat_addComplCarryM -/*---------------------------------------------------------------------------- -| This function or macro is the same as 'softfloat_addCarryM', except that -| the value of the unsigned integer pointed to by 'bPtr' is bit-wise completed -| before the addition. -*----------------------------------------------------------------------------*/ -uint_fast8_t - softfloat_addComplCarryM( - uint_fast8_t size_words, - const uint32_t *aPtr, - const uint32_t *bPtr, - uint_fast8_t carry, - uint32_t *zPtr - ); -#endif - -#ifndef softfloat_addComplCarry96M -/*---------------------------------------------------------------------------- -| This function or macro is the same as 'softfloat_addComplCarryM' with -| 'size_words' = 3 (N = 96). -*----------------------------------------------------------------------------*/ -#define softfloat_addComplCarry96M( aPtr, bPtr, carry, zPtr ) softfloat_addComplCarryM( 3, aPtr, bPtr, carry, zPtr ) -#endif - -#ifndef softfloat_negXM -/*---------------------------------------------------------------------------- -| Replaces the N-bit unsigned integer pointed to by 'zPtr' by the -| 2s-complement of itself, where N = 'size_words' * 32. Argument 'zPtr' -| points to a 'size_words'-long array of 32-bit elements that concatenate in -| the platform's normal endian order to form an N-bit integer. -*----------------------------------------------------------------------------*/ -void softfloat_negXM( uint_fast8_t size_words, uint32_t *zPtr ); -#endif - -#ifndef softfloat_negX96M -/*---------------------------------------------------------------------------- -| This function or macro is the same as 'softfloat_negXM' with 'size_words' -| = 3 (N = 96). -*----------------------------------------------------------------------------*/ -#define softfloat_negX96M( zPtr ) softfloat_negXM( 3, zPtr ) -#endif - -#ifndef softfloat_negX128M -/*---------------------------------------------------------------------------- -| This function or macro is the same as 'softfloat_negXM' with 'size_words' -| = 4 (N = 128). -*----------------------------------------------------------------------------*/ -#define softfloat_negX128M( zPtr ) softfloat_negXM( 4, zPtr ) -#endif - -#ifndef softfloat_negX160M -/*---------------------------------------------------------------------------- -| This function or macro is the same as 'softfloat_negXM' with 'size_words' -| = 5 (N = 160). -*----------------------------------------------------------------------------*/ -#define softfloat_negX160M( zPtr ) softfloat_negXM( 5, zPtr ) -#endif - -#ifndef softfloat_negX256M -/*---------------------------------------------------------------------------- -| This function or macro is the same as 'softfloat_negXM' with 'size_words' -| = 8 (N = 256). -*----------------------------------------------------------------------------*/ -#define softfloat_negX256M( zPtr ) softfloat_negXM( 8, zPtr ) -#endif - -#ifndef softfloat_sub1XM -/*---------------------------------------------------------------------------- -| Subtracts 1 from the N-bit integer pointed to by 'zPtr', where N = -| 'size_words' * 32. The subtraction is modulo 2^N, so any borrow out (carry -| out) is lost. Argument 'zPtr' points to a 'size_words'-long array of 32-bit -| elements that concatenate in the platform's normal endian order to form an -| N-bit integer. -*----------------------------------------------------------------------------*/ -void softfloat_sub1XM( uint_fast8_t size_words, uint32_t *zPtr ); -#endif - -#ifndef softfloat_sub1X96M -/*---------------------------------------------------------------------------- -| This function or macro is the same as 'softfloat_sub1XM' with 'size_words' -| = 3 (N = 96). -*----------------------------------------------------------------------------*/ -#define softfloat_sub1X96M( zPtr ) softfloat_sub1XM( 3, zPtr ) -#endif - -#ifndef softfloat_sub1X160M -/*---------------------------------------------------------------------------- -| This function or macro is the same as 'softfloat_sub1XM' with 'size_words' -| = 5 (N = 160). -*----------------------------------------------------------------------------*/ -#define softfloat_sub1X160M( zPtr ) softfloat_sub1XM( 5, zPtr ) -#endif - -#ifndef softfloat_subM -/*---------------------------------------------------------------------------- -| Subtracts the two N-bit integers pointed to by 'aPtr' and 'bPtr', where N = -| 'size_words' * 32. The subtraction is modulo 2^N, so any borrow out (carry -| out) is lost. The N-bit difference is stored at the location pointed to by -| 'zPtr'. Each of 'aPtr', 'bPtr', and 'zPtr' points to a 'size_words'-long -| array of 32-bit elements that concatenate in the platform's normal endian -| order to form an N-bit integer. -*----------------------------------------------------------------------------*/ -void - softfloat_subM( - uint_fast8_t size_words, - const uint32_t *aPtr, - const uint32_t *bPtr, - uint32_t *zPtr - ); -#endif - -#ifndef softfloat_sub96M -/*---------------------------------------------------------------------------- -| This function or macro is the same as 'softfloat_subM' with 'size_words' -| = 3 (N = 96). -*----------------------------------------------------------------------------*/ -#define softfloat_sub96M( aPtr, bPtr, zPtr ) softfloat_subM( 3, aPtr, bPtr, zPtr ) -#endif - -#ifndef softfloat_sub128M -/*---------------------------------------------------------------------------- -| This function or macro is the same as 'softfloat_subM' with 'size_words' -| = 4 (N = 128). -*----------------------------------------------------------------------------*/ -#define softfloat_sub128M( aPtr, bPtr, zPtr ) softfloat_subM( 4, aPtr, bPtr, zPtr ) -#endif - -#ifndef softfloat_sub160M -/*---------------------------------------------------------------------------- -| This function or macro is the same as 'softfloat_subM' with 'size_words' -| = 5 (N = 160). -*----------------------------------------------------------------------------*/ -#define softfloat_sub160M( aPtr, bPtr, zPtr ) softfloat_subM( 5, aPtr, bPtr, zPtr ) -#endif - -#ifndef softfloat_mul64To128M -/*---------------------------------------------------------------------------- -| Multiplies 'a' and 'b' and stores the 128-bit product at the location -| pointed to by 'zPtr'. Argument 'zPtr' points to an array of four 32-bit -| elements that concatenate in the platform's normal endian order to form a -| 128-bit integer. -*----------------------------------------------------------------------------*/ -void softfloat_mul64To128M( uint64_t a, uint64_t b, uint32_t *zPtr ); -#endif - -#ifndef softfloat_mul128MTo256M -/*---------------------------------------------------------------------------- -| Multiplies the two 128-bit unsigned integers pointed to by 'aPtr' and -| 'bPtr', and stores the 256-bit product at the location pointed to by 'zPtr'. -| Each of 'aPtr' and 'bPtr' points to an array of four 32-bit elements that -| concatenate in the platform's normal endian order to form a 128-bit integer. -| Argument 'zPtr' points to an array of eight 32-bit elements that concatenate -| to form a 256-bit integer. -*----------------------------------------------------------------------------*/ -void - softfloat_mul128MTo256M( - const uint32_t *aPtr, const uint32_t *bPtr, uint32_t *zPtr ); -#endif - -#ifndef softfloat_remStepMBy32 -/*---------------------------------------------------------------------------- -| Performs a "remainder reduction step" as follows: Arguments 'remPtr' and -| 'bPtr' both point to N-bit unsigned integers, where N = 'size_words' * 32. -| Defining R and B as the values of those integers, the expression (R<<'dist') -| - B * q is computed modulo 2^N, and the N-bit result is stored at the -| location pointed to by 'zPtr'. Each of 'remPtr', 'bPtr', and 'zPtr' points -| to a 'size_words'-long array of 32-bit elements that concatenate in the -| platform's normal endian order to form an N-bit integer. -*----------------------------------------------------------------------------*/ -void - softfloat_remStepMBy32( - uint_fast8_t size_words, - const uint32_t *remPtr, - uint_fast8_t dist, - const uint32_t *bPtr, - uint32_t q, - uint32_t *zPtr - ); -#endif - -#ifndef softfloat_remStep96MBy32 -/*---------------------------------------------------------------------------- -| This function or macro is the same as 'softfloat_remStepMBy32' with -| 'size_words' = 3 (N = 96). -*----------------------------------------------------------------------------*/ -#define softfloat_remStep96MBy32( remPtr, dist, bPtr, q, zPtr ) softfloat_remStepMBy32( 3, remPtr, dist, bPtr, q, zPtr ) -#endif - -#ifndef softfloat_remStep128MBy32 -/*---------------------------------------------------------------------------- -| This function or macro is the same as 'softfloat_remStepMBy32' with -| 'size_words' = 4 (N = 128). -*----------------------------------------------------------------------------*/ -#define softfloat_remStep128MBy32( remPtr, dist, bPtr, q, zPtr ) softfloat_remStepMBy32( 4, remPtr, dist, bPtr, q, zPtr ) -#endif - -#ifndef softfloat_remStep160MBy32 -/*---------------------------------------------------------------------------- -| This function or macro is the same as 'softfloat_remStepMBy32' with -| 'size_words' = 5 (N = 160). -*----------------------------------------------------------------------------*/ -#define softfloat_remStep160MBy32( remPtr, dist, bPtr, q, zPtr ) softfloat_remStepMBy32( 5, remPtr, dist, bPtr, q, zPtr ) -#endif - -#endif - -#endif - diff --git a/deps/SoftFloat-3e/source/include/softfloat.h b/deps/SoftFloat-3e/source/include/softfloat.h deleted file mode 100644 index b33374cd6c8b..000000000000 --- a/deps/SoftFloat-3e/source/include/softfloat.h +++ /dev/null @@ -1,372 +0,0 @@ - -/*============================================================================ - -This C header file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017 The Regents of the -University of California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - - -/*============================================================================ -| Note: If SoftFloat is made available as a general library for programs to -| use, it is strongly recommended that a platform-specific version of this -| header, "softfloat.h", be created that folds in "softfloat_types.h" and that -| eliminates all dependencies on compile-time macros. -*============================================================================*/ - - -#ifndef softfloat_h -#define softfloat_h 1 - -#include -#include -#include "softfloat_types.h" - -#ifndef THREAD_LOCAL -#define THREAD_LOCAL -#endif - -/*---------------------------------------------------------------------------- -| Software floating-point underflow tininess-detection mode. -*----------------------------------------------------------------------------*/ -extern THREAD_LOCAL uint_fast8_t softfloat_detectTininess; -enum { - softfloat_tininess_beforeRounding = 0, - softfloat_tininess_afterRounding = 1 -}; - -/*---------------------------------------------------------------------------- -| Software floating-point rounding mode. (Mode "odd" is supported only if -| SoftFloat is compiled with macro 'SOFTFLOAT_ROUND_ODD' defined.) -*----------------------------------------------------------------------------*/ -extern THREAD_LOCAL uint_fast8_t softfloat_roundingMode; -enum { - softfloat_round_near_even = 0, - softfloat_round_minMag = 1, - softfloat_round_min = 2, - softfloat_round_max = 3, - softfloat_round_near_maxMag = 4, - softfloat_round_odd = 6 -}; - -/*---------------------------------------------------------------------------- -| Software floating-point exception flags. -*----------------------------------------------------------------------------*/ -extern THREAD_LOCAL uint_fast8_t softfloat_exceptionFlags; -enum { - softfloat_flag_inexact = 1, - softfloat_flag_underflow = 2, - softfloat_flag_overflow = 4, - softfloat_flag_infinite = 8, - softfloat_flag_invalid = 16 -}; - -/*---------------------------------------------------------------------------- -| Routine to raise any or all of the software floating-point exception flags. -*----------------------------------------------------------------------------*/ -void softfloat_raiseFlags( uint_fast8_t ); - -/*---------------------------------------------------------------------------- -| Integer-to-floating-point conversion routines. -*----------------------------------------------------------------------------*/ -float16_t ui32_to_f16( uint32_t ); -float32_t ui32_to_f32( uint32_t ); -float64_t ui32_to_f64( uint32_t ); -#ifdef SOFTFLOAT_FAST_INT64 -extFloat80_t ui32_to_extF80( uint32_t ); -float128_t ui32_to_f128( uint32_t ); -#endif -void ui32_to_extF80M( uint32_t, extFloat80_t * ); -void ui32_to_f128M( uint32_t, float128_t * ); -float16_t ui64_to_f16( uint64_t ); -float32_t ui64_to_f32( uint64_t ); -float64_t ui64_to_f64( uint64_t ); -#ifdef SOFTFLOAT_FAST_INT64 -extFloat80_t ui64_to_extF80( uint64_t ); -float128_t ui64_to_f128( uint64_t ); -#endif -void ui64_to_extF80M( uint64_t, extFloat80_t * ); -void ui64_to_f128M( uint64_t, float128_t * ); -float16_t i32_to_f16( int32_t ); -float32_t i32_to_f32( int32_t ); -float64_t i32_to_f64( int32_t ); -#ifdef SOFTFLOAT_FAST_INT64 -extFloat80_t i32_to_extF80( int32_t ); -float128_t i32_to_f128( int32_t ); -#endif -void i32_to_extF80M( int32_t, extFloat80_t * ); -void i32_to_f128M( int32_t, float128_t * ); -float16_t i64_to_f16( int64_t ); -float32_t i64_to_f32( int64_t ); -float64_t i64_to_f64( int64_t ); -#ifdef SOFTFLOAT_FAST_INT64 -extFloat80_t i64_to_extF80( int64_t ); -float128_t i64_to_f128( int64_t ); -#endif -void i64_to_extF80M( int64_t, extFloat80_t * ); -void i64_to_f128M( int64_t, float128_t * ); - -/*---------------------------------------------------------------------------- -| 16-bit (half-precision) floating-point operations. -*----------------------------------------------------------------------------*/ -uint_fast32_t f16_to_ui32( float16_t, uint_fast8_t, bool ); -uint_fast64_t f16_to_ui64( float16_t, uint_fast8_t, bool ); -int_fast32_t f16_to_i32( float16_t, uint_fast8_t, bool ); -int_fast64_t f16_to_i64( float16_t, uint_fast8_t, bool ); -uint_fast32_t f16_to_ui32_r_minMag( float16_t, bool ); -uint_fast64_t f16_to_ui64_r_minMag( float16_t, bool ); -int_fast32_t f16_to_i32_r_minMag( float16_t, bool ); -int_fast64_t f16_to_i64_r_minMag( float16_t, bool ); -float32_t f16_to_f32( float16_t ); -float64_t f16_to_f64( float16_t ); -#ifdef SOFTFLOAT_FAST_INT64 -extFloat80_t f16_to_extF80( float16_t ); -float128_t f16_to_f128( float16_t ); -#endif -void f16_to_extF80M( float16_t, extFloat80_t * ); -void f16_to_f128M( float16_t, float128_t * ); -float16_t f16_roundToInt( float16_t, uint_fast8_t, bool ); -float16_t f16_add( float16_t, float16_t ); -float16_t f16_sub( float16_t, float16_t ); -float16_t f16_mul( float16_t, float16_t ); -float16_t f16_mulAdd( float16_t, float16_t, float16_t ); -float16_t f16_div( float16_t, float16_t ); -float16_t f16_rem( float16_t, float16_t ); -float16_t f16_sqrt( float16_t ); -bool f16_eq( float16_t, float16_t ); -bool f16_le( float16_t, float16_t ); -bool f16_lt( float16_t, float16_t ); -bool f16_eq_signaling( float16_t, float16_t ); -bool f16_le_quiet( float16_t, float16_t ); -bool f16_lt_quiet( float16_t, float16_t ); -bool f16_isSignalingNaN( float16_t ); - -/*---------------------------------------------------------------------------- -| 32-bit (single-precision) floating-point operations. -*----------------------------------------------------------------------------*/ -uint_fast32_t f32_to_ui32( float32_t, uint_fast8_t, bool ); -uint_fast64_t f32_to_ui64( float32_t, uint_fast8_t, bool ); -int_fast32_t f32_to_i32( float32_t, uint_fast8_t, bool ); -int_fast64_t f32_to_i64( float32_t, uint_fast8_t, bool ); -uint_fast32_t f32_to_ui32_r_minMag( float32_t, bool ); -uint_fast64_t f32_to_ui64_r_minMag( float32_t, bool ); -int_fast32_t f32_to_i32_r_minMag( float32_t, bool ); -int_fast64_t f32_to_i64_r_minMag( float32_t, bool ); -float16_t f32_to_f16( float32_t ); -float64_t f32_to_f64( float32_t ); -#ifdef SOFTFLOAT_FAST_INT64 -extFloat80_t f32_to_extF80( float32_t ); -float128_t f32_to_f128( float32_t ); -#endif -void f32_to_extF80M( float32_t, extFloat80_t * ); -void f32_to_f128M( float32_t, float128_t * ); -float32_t f32_roundToInt( float32_t, uint_fast8_t, bool ); -float32_t f32_add( float32_t, float32_t ); -float32_t f32_sub( float32_t, float32_t ); -float32_t f32_mul( float32_t, float32_t ); -float32_t f32_mulAdd( float32_t, float32_t, float32_t ); -float32_t f32_div( float32_t, float32_t ); -float32_t f32_rem( float32_t, float32_t ); -float32_t f32_sqrt( float32_t ); -bool f32_eq( float32_t, float32_t ); -bool f32_le( float32_t, float32_t ); -bool f32_lt( float32_t, float32_t ); -bool f32_eq_signaling( float32_t, float32_t ); -bool f32_le_quiet( float32_t, float32_t ); -bool f32_lt_quiet( float32_t, float32_t ); -bool f32_isSignalingNaN( float32_t ); - -/*---------------------------------------------------------------------------- -| 64-bit (double-precision) floating-point operations. -*----------------------------------------------------------------------------*/ -uint_fast32_t f64_to_ui32( float64_t, uint_fast8_t, bool ); -uint_fast64_t f64_to_ui64( float64_t, uint_fast8_t, bool ); -int_fast32_t f64_to_i32( float64_t, uint_fast8_t, bool ); -int_fast64_t f64_to_i64( float64_t, uint_fast8_t, bool ); -uint_fast32_t f64_to_ui32_r_minMag( float64_t, bool ); -uint_fast64_t f64_to_ui64_r_minMag( float64_t, bool ); -int_fast32_t f64_to_i32_r_minMag( float64_t, bool ); -int_fast64_t f64_to_i64_r_minMag( float64_t, bool ); -float16_t f64_to_f16( float64_t ); -float32_t f64_to_f32( float64_t ); -#ifdef SOFTFLOAT_FAST_INT64 -extFloat80_t f64_to_extF80( float64_t ); -float128_t f64_to_f128( float64_t ); -#endif -void f64_to_extF80M( float64_t, extFloat80_t * ); -void f64_to_f128M( float64_t, float128_t * ); -float64_t f64_roundToInt( float64_t, uint_fast8_t, bool ); -float64_t f64_add( float64_t, float64_t ); -float64_t f64_sub( float64_t, float64_t ); -float64_t f64_mul( float64_t, float64_t ); -float64_t f64_mulAdd( float64_t, float64_t, float64_t ); -float64_t f64_div( float64_t, float64_t ); -float64_t f64_rem( float64_t, float64_t ); -float64_t f64_sqrt( float64_t ); -bool f64_eq( float64_t, float64_t ); -bool f64_le( float64_t, float64_t ); -bool f64_lt( float64_t, float64_t ); -bool f64_eq_signaling( float64_t, float64_t ); -bool f64_le_quiet( float64_t, float64_t ); -bool f64_lt_quiet( float64_t, float64_t ); -bool f64_isSignalingNaN( float64_t ); - -/*---------------------------------------------------------------------------- -| Rounding precision for 80-bit extended double-precision floating-point. -| Valid values are 32, 64, and 80. -*----------------------------------------------------------------------------*/ -extern THREAD_LOCAL uint_fast8_t extF80_roundingPrecision; - -/*---------------------------------------------------------------------------- -| 80-bit extended double-precision floating-point operations. -*----------------------------------------------------------------------------*/ -#ifdef SOFTFLOAT_FAST_INT64 -uint_fast32_t extF80_to_ui32( extFloat80_t, uint_fast8_t, bool ); -uint_fast64_t extF80_to_ui64( extFloat80_t, uint_fast8_t, bool ); -int_fast32_t extF80_to_i32( extFloat80_t, uint_fast8_t, bool ); -int_fast64_t extF80_to_i64( extFloat80_t, uint_fast8_t, bool ); -uint_fast32_t extF80_to_ui32_r_minMag( extFloat80_t, bool ); -uint_fast64_t extF80_to_ui64_r_minMag( extFloat80_t, bool ); -int_fast32_t extF80_to_i32_r_minMag( extFloat80_t, bool ); -int_fast64_t extF80_to_i64_r_minMag( extFloat80_t, bool ); -float16_t extF80_to_f16( extFloat80_t ); -float32_t extF80_to_f32( extFloat80_t ); -float64_t extF80_to_f64( extFloat80_t ); -float128_t extF80_to_f128( extFloat80_t ); -extFloat80_t extF80_roundToInt( extFloat80_t, uint_fast8_t, bool ); -extFloat80_t extF80_add( extFloat80_t, extFloat80_t ); -extFloat80_t extF80_sub( extFloat80_t, extFloat80_t ); -extFloat80_t extF80_mul( extFloat80_t, extFloat80_t ); -extFloat80_t extF80_div( extFloat80_t, extFloat80_t ); -extFloat80_t extF80_rem( extFloat80_t, extFloat80_t ); -extFloat80_t extF80_sqrt( extFloat80_t ); -bool extF80_eq( extFloat80_t, extFloat80_t ); -bool extF80_le( extFloat80_t, extFloat80_t ); -bool extF80_lt( extFloat80_t, extFloat80_t ); -bool extF80_eq_signaling( extFloat80_t, extFloat80_t ); -bool extF80_le_quiet( extFloat80_t, extFloat80_t ); -bool extF80_lt_quiet( extFloat80_t, extFloat80_t ); -bool extF80_isSignalingNaN( extFloat80_t ); -#endif -uint_fast32_t extF80M_to_ui32( const extFloat80_t *, uint_fast8_t, bool ); -uint_fast64_t extF80M_to_ui64( const extFloat80_t *, uint_fast8_t, bool ); -int_fast32_t extF80M_to_i32( const extFloat80_t *, uint_fast8_t, bool ); -int_fast64_t extF80M_to_i64( const extFloat80_t *, uint_fast8_t, bool ); -uint_fast32_t extF80M_to_ui32_r_minMag( const extFloat80_t *, bool ); -uint_fast64_t extF80M_to_ui64_r_minMag( const extFloat80_t *, bool ); -int_fast32_t extF80M_to_i32_r_minMag( const extFloat80_t *, bool ); -int_fast64_t extF80M_to_i64_r_minMag( const extFloat80_t *, bool ); -float16_t extF80M_to_f16( const extFloat80_t * ); -float32_t extF80M_to_f32( const extFloat80_t * ); -float64_t extF80M_to_f64( const extFloat80_t * ); -void extF80M_to_f128M( const extFloat80_t *, float128_t * ); -void - extF80M_roundToInt( - const extFloat80_t *, uint_fast8_t, bool, extFloat80_t * ); -void extF80M_add( const extFloat80_t *, const extFloat80_t *, extFloat80_t * ); -void extF80M_sub( const extFloat80_t *, const extFloat80_t *, extFloat80_t * ); -void extF80M_mul( const extFloat80_t *, const extFloat80_t *, extFloat80_t * ); -void extF80M_div( const extFloat80_t *, const extFloat80_t *, extFloat80_t * ); -void extF80M_rem( const extFloat80_t *, const extFloat80_t *, extFloat80_t * ); -void extF80M_sqrt( const extFloat80_t *, extFloat80_t * ); -bool extF80M_eq( const extFloat80_t *, const extFloat80_t * ); -bool extF80M_le( const extFloat80_t *, const extFloat80_t * ); -bool extF80M_lt( const extFloat80_t *, const extFloat80_t * ); -bool extF80M_eq_signaling( const extFloat80_t *, const extFloat80_t * ); -bool extF80M_le_quiet( const extFloat80_t *, const extFloat80_t * ); -bool extF80M_lt_quiet( const extFloat80_t *, const extFloat80_t * ); -bool extF80M_isSignalingNaN( const extFloat80_t * ); - -/*---------------------------------------------------------------------------- -| 128-bit (quadruple-precision) floating-point operations. -*----------------------------------------------------------------------------*/ -#ifdef SOFTFLOAT_FAST_INT64 -uint_fast32_t f128_to_ui32( float128_t, uint_fast8_t, bool ); -uint_fast64_t f128_to_ui64( float128_t, uint_fast8_t, bool ); -int_fast32_t f128_to_i32( float128_t, uint_fast8_t, bool ); -int_fast64_t f128_to_i64( float128_t, uint_fast8_t, bool ); -uint_fast32_t f128_to_ui32_r_minMag( float128_t, bool ); -uint_fast64_t f128_to_ui64_r_minMag( float128_t, bool ); -int_fast32_t f128_to_i32_r_minMag( float128_t, bool ); -int_fast64_t f128_to_i64_r_minMag( float128_t, bool ); -float16_t f128_to_f16( float128_t ); -float32_t f128_to_f32( float128_t ); -float64_t f128_to_f64( float128_t ); -extFloat80_t f128_to_extF80( float128_t ); -float128_t f128_roundToInt( float128_t, uint_fast8_t, bool ); -float128_t f128_add( float128_t, float128_t ); -float128_t f128_sub( float128_t, float128_t ); -float128_t f128_mul( float128_t, float128_t ); -float128_t f128_mulAdd( float128_t, float128_t, float128_t ); -float128_t f128_div( float128_t, float128_t ); -float128_t f128_rem( float128_t, float128_t ); -float128_t f128_sqrt( float128_t ); -bool f128_eq( float128_t, float128_t ); -bool f128_le( float128_t, float128_t ); -bool f128_lt( float128_t, float128_t ); -bool f128_eq_signaling( float128_t, float128_t ); -bool f128_le_quiet( float128_t, float128_t ); -bool f128_lt_quiet( float128_t, float128_t ); -bool f128_isSignalingNaN( float128_t ); -#endif -uint_fast32_t f128M_to_ui32( const float128_t *, uint_fast8_t, bool ); -uint_fast64_t f128M_to_ui64( const float128_t *, uint_fast8_t, bool ); -int_fast32_t f128M_to_i32( const float128_t *, uint_fast8_t, bool ); -int_fast64_t f128M_to_i64( const float128_t *, uint_fast8_t, bool ); -uint_fast32_t f128M_to_ui32_r_minMag( const float128_t *, bool ); -uint_fast64_t f128M_to_ui64_r_minMag( const float128_t *, bool ); -int_fast32_t f128M_to_i32_r_minMag( const float128_t *, bool ); -int_fast64_t f128M_to_i64_r_minMag( const float128_t *, bool ); -float16_t f128M_to_f16( const float128_t * ); -float32_t f128M_to_f32( const float128_t * ); -float64_t f128M_to_f64( const float128_t * ); -void f128M_to_extF80M( const float128_t *, extFloat80_t * ); -void f128M_roundToInt( const float128_t *, uint_fast8_t, bool, float128_t * ); -void f128M_add( const float128_t *, const float128_t *, float128_t * ); -void f128M_sub( const float128_t *, const float128_t *, float128_t * ); -void f128M_mul( const float128_t *, const float128_t *, float128_t * ); -void - f128M_mulAdd( - const float128_t *, const float128_t *, const float128_t *, float128_t * - ); -void f128M_div( const float128_t *, const float128_t *, float128_t * ); -void f128M_rem( const float128_t *, const float128_t *, float128_t * ); -void f128M_sqrt( const float128_t *, float128_t * ); -bool f128M_eq( const float128_t *, const float128_t * ); -bool f128M_le( const float128_t *, const float128_t * ); -bool f128M_lt( const float128_t *, const float128_t * ); -bool f128M_eq_signaling( const float128_t *, const float128_t * ); -bool f128M_le_quiet( const float128_t *, const float128_t * ); -bool f128M_lt_quiet( const float128_t *, const float128_t * ); -bool f128M_isSignalingNaN( const float128_t * ); - -#endif - diff --git a/deps/SoftFloat-3e/source/include/softfloat_types.h b/deps/SoftFloat-3e/source/include/softfloat_types.h deleted file mode 100644 index 27507741af47..000000000000 --- a/deps/SoftFloat-3e/source/include/softfloat_types.h +++ /dev/null @@ -1,82 +0,0 @@ - -/*============================================================================ - -This C header file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2017 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#ifndef softfloat_types_h -#define softfloat_types_h 1 - -#include "platform.h" -#include - -/*---------------------------------------------------------------------------- -| Types used to pass 16-bit, 32-bit, 64-bit, and 128-bit floating-point -| arguments and results to/from functions. These types must be exactly -| 16 bits, 32 bits, 64 bits, and 128 bits in size, respectively. Where a -| platform has "native" support for IEEE-Standard floating-point formats, -| the types below may, if desired, be defined as aliases for the native types -| (typically 'float' and 'double', and possibly 'long double'). -*----------------------------------------------------------------------------*/ -typedef struct { uint16_t v; } float16_t; -typedef struct { uint32_t v; } float32_t; -typedef struct { uint64_t v; } float64_t; -typedef struct { uint64_t v[2]; } float128_t; - -/*---------------------------------------------------------------------------- -| The format of an 80-bit extended floating-point number in memory. This -| structure must contain a 16-bit field named 'signExp' and a 64-bit field -| named 'signif'. -*----------------------------------------------------------------------------*/ -#ifdef LITTLEENDIAN -struct extFloat80M { uint64_t signif; uint16_t signExp; }; -#else -struct extFloat80M { uint16_t signExp; uint64_t signif; }; -#endif - -/*---------------------------------------------------------------------------- -| The type used to pass 80-bit extended floating-point arguments and -| results to/from functions. This type must have size identical to -| 'struct extFloat80M'. Type 'extFloat80_t' can be defined as an alias for -| 'struct extFloat80M'. Alternatively, if a platform has "native" support -| for IEEE-Standard 80-bit extended floating-point, it may be possible, -| if desired, to define 'extFloat80_t' as an alias for the native type -| (presumably either 'long double' or a nonstandard compiler-intrinsic type). -| In that case, the 'signif' and 'signExp' fields of 'struct extFloat80M' -| must align exactly with the locations in memory of the sign, exponent, and -| significand of the native type. -*----------------------------------------------------------------------------*/ -typedef struct extFloat80M extFloat80_t; - -#endif - diff --git a/deps/SoftFloat-3e/source/s_add128.c b/deps/SoftFloat-3e/source/s_add128.c deleted file mode 100644 index 5a9d5082a0b7..000000000000 --- a/deps/SoftFloat-3e/source/s_add128.c +++ /dev/null @@ -1,55 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "primitiveTypes.h" - -#ifndef softfloat_add128 - -struct uint128 - softfloat_add128( uint64_t a64, uint64_t a0, uint64_t b64, uint64_t b0 ) -{ - struct uint128 z; - - z.v0 = a0 + b0; - z.v64 = a64 + b64 + (z.v0 < a0); - return z; - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/s_add256M.c b/deps/SoftFloat-3e/source/s_add256M.c deleted file mode 100644 index 4fb46a1742cb..000000000000 --- a/deps/SoftFloat-3e/source/s_add256M.c +++ /dev/null @@ -1,65 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "primitiveTypes.h" - -#ifndef softfloat_add256M - -void - softfloat_add256M( - const uint64_t *aPtr, const uint64_t *bPtr, uint64_t *zPtr ) -{ - unsigned int index; - uint_fast8_t carry; - uint64_t wordA, wordZ; - - index = indexWordLo( 4 ); - carry = 0; - for (;;) { - wordA = aPtr[index]; - wordZ = wordA + bPtr[index] + carry; - zPtr[index] = wordZ; - if ( index == indexWordHi( 4 ) ) break; - if ( wordZ != wordA ) carry = (wordZ < wordA); - index += wordIncr; - } - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/s_addCarryM.c b/deps/SoftFloat-3e/source/s_addCarryM.c deleted file mode 100644 index f0ccf6724764..000000000000 --- a/deps/SoftFloat-3e/source/s_addCarryM.c +++ /dev/null @@ -1,70 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "primitiveTypes.h" - -#ifndef softfloat_addCarryM - -uint_fast8_t - softfloat_addCarryM( - uint_fast8_t size_words, - const uint32_t *aPtr, - const uint32_t *bPtr, - uint_fast8_t carry, - uint32_t *zPtr - ) -{ - unsigned int index, lastIndex; - uint32_t wordA, wordZ; - - index = indexWordLo( size_words ); - lastIndex = indexWordHi( size_words ); - for (;;) { - wordA = aPtr[index]; - wordZ = wordA + bPtr[index] + carry; - zPtr[index] = wordZ; - if ( wordZ != wordA ) carry = (wordZ < wordA); - if ( index == lastIndex ) break; - index += wordIncr; - } - return carry; - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/s_addComplCarryM.c b/deps/SoftFloat-3e/source/s_addComplCarryM.c deleted file mode 100644 index e1584c669a18..000000000000 --- a/deps/SoftFloat-3e/source/s_addComplCarryM.c +++ /dev/null @@ -1,70 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "primitiveTypes.h" - -#ifndef softfloat_addComplCarryM - -uint_fast8_t - softfloat_addComplCarryM( - uint_fast8_t size_words, - const uint32_t *aPtr, - const uint32_t *bPtr, - uint_fast8_t carry, - uint32_t *zPtr - ) -{ - unsigned int index, lastIndex; - uint32_t wordA, wordZ; - - index = indexWordLo( size_words ); - lastIndex = indexWordHi( size_words ); - for (;;) { - wordA = aPtr[index]; - wordZ = wordA + ~bPtr[index] + carry; - zPtr[index] = wordZ; - if ( wordZ != wordA ) carry = (wordZ < wordA); - if ( index == lastIndex ) break; - index += wordIncr; - } - return carry; - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/s_addExtF80M.c b/deps/SoftFloat-3e/source/s_addExtF80M.c deleted file mode 100644 index febfb65773dd..000000000000 --- a/deps/SoftFloat-3e/source/s_addExtF80M.c +++ /dev/null @@ -1,186 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -void - softfloat_addExtF80M( - const struct extFloat80M *aSPtr, - const struct extFloat80M *bSPtr, - struct extFloat80M *zSPtr, - bool negateB - ) -{ - uint32_t uiA64; - int32_t expA; - uint32_t uiB64; - int32_t expB; - uint32_t uiZ64; - bool signZ, signB; - const struct extFloat80M *tempSPtr; - uint64_t sigZ, sigB; - void - (*roundPackRoutinePtr)( - bool, int32_t, uint32_t *, uint_fast8_t, struct extFloat80M * ); - int32_t expDiff; - uint32_t extSigX[3], sigZExtra; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uiA64 = aSPtr->signExp; - expA = expExtF80UI64( uiA64 ); - uiB64 = bSPtr->signExp; - expB = expExtF80UI64( uiB64 ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( (expA == 0x7FFF) || (expB == 0x7FFF) ) { - if ( softfloat_tryPropagateNaNExtF80M( aSPtr, bSPtr, zSPtr ) ) return; - uiZ64 = uiA64; - if ( expB == 0x7FFF ) { - uiZ64 = uiB64 ^ packToExtF80UI64( negateB, 0 ); - if ( (expA == 0x7FFF) && (uiZ64 != uiA64) ) { - softfloat_invalidExtF80M( zSPtr ); - return; - } - } - zSPtr->signExp = uiZ64; - zSPtr->signif = UINT64_C( 0x8000000000000000 ); - return; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - signZ = signExtF80UI64( uiA64 ); - signB = signExtF80UI64( uiB64 ) ^ negateB; - negateB = (signZ != signB); - if ( expA < expB ) { - signZ = signB; - expA = expB; - expB = expExtF80UI64( uiA64 ); - tempSPtr = aSPtr; - aSPtr = bSPtr; - bSPtr = tempSPtr; - } - if ( ! expB ) { - expB = 1; - if ( ! expA ) expA = 1; - } - sigZ = aSPtr->signif; - sigB = bSPtr->signif; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - roundPackRoutinePtr = softfloat_roundPackMToExtF80M; - expDiff = expA - expB; - if ( expDiff ) { - /*-------------------------------------------------------------------- - *--------------------------------------------------------------------*/ - extSigX[indexWord( 3, 2 )] = sigB>>32; - extSigX[indexWord( 3, 1 )] = sigB; - extSigX[indexWord( 3, 0 )] = 0; - softfloat_shiftRightJam96M( extSigX, expDiff, extSigX ); - sigB = - (uint64_t) extSigX[indexWord( 3, 2 )]<<32 - | extSigX[indexWord( 3, 1 )]; - if ( negateB ) { - sigZ -= sigB; - sigZExtra = extSigX[indexWordLo( 3 )]; - if ( sigZExtra ) { - --sigZ; - sigZExtra = -sigZExtra; - } - if ( ! (sigZ & UINT64_C( 0x8000000000000000 )) ) { - if ( sigZ & UINT64_C( 0x4000000000000000 ) ) { - --expA; - sigZ = sigZ<<1 | sigZExtra>>31; - sigZExtra <<= 1; - } else { - roundPackRoutinePtr = softfloat_normRoundPackMToExtF80M; - } - } - } else { - sigZ += sigB; - if ( sigZ & UINT64_C( 0x8000000000000000 ) ) goto sigZ; - sigZExtra = (uint32_t) sigZ<<31 | (extSigX[indexWordLo( 3 )] != 0); - goto completeNormAfterAdd; - } - } else { - /*-------------------------------------------------------------------- - *--------------------------------------------------------------------*/ - sigZExtra = 0; - if ( negateB ) { - if ( sigZ < sigB ) { - signZ = ! signZ; - sigZ = sigB - sigZ; - } else { - sigZ -= sigB; - if ( ! sigZ ) { - signZ = (softfloat_roundingMode == softfloat_round_min); - zSPtr->signExp = packToExtF80UI64( signZ, 0 ); - zSPtr->signif = 0; - return; - } - } - roundPackRoutinePtr = softfloat_normRoundPackMToExtF80M; - } else { - sigZ += sigB; - if ( sigZ < sigB ) { - sigZExtra = (uint32_t) sigZ<<31; - completeNormAfterAdd: - ++expA; - sigZ = UINT64_C( 0x8000000000000000 ) | sigZ>>1; - } else { - if ( ! (sigZ & UINT64_C( 0x8000000000000000 )) ) { - roundPackRoutinePtr = softfloat_normRoundPackMToExtF80M; - } - } - } - } - extSigX[indexWord( 3, 0 )] = sigZExtra; - sigZ: - extSigX[indexWord( 3, 2 )] = sigZ>>32; - extSigX[indexWord( 3, 1 )] = sigZ; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - roundPack: - (*roundPackRoutinePtr)( - signZ, expA, extSigX, extF80_roundingPrecision, zSPtr ); - -} - diff --git a/deps/SoftFloat-3e/source/s_addF128M.c b/deps/SoftFloat-3e/source/s_addF128M.c deleted file mode 100644 index 8ed9d271fabb..000000000000 --- a/deps/SoftFloat-3e/source/s_addF128M.c +++ /dev/null @@ -1,211 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -void - softfloat_addF128M( - const uint32_t *aWPtr, - const uint32_t *bWPtr, - uint32_t *zWPtr, - bool negateB - ) -{ - uint32_t uiA96; - int32_t expA; - uint32_t uiB96; - int32_t expB; - uint32_t uiZ96; - bool signZ, signB; - const uint32_t *tempPtr; - uint32_t sig96A, sig96B; - int32_t expDiff; - uint_fast8_t - (*addCarryMRoutinePtr)( - uint_fast8_t, - const uint32_t *, - const uint32_t *, - uint_fast8_t, - uint32_t * - ); - uint32_t extSigZ[5], wordSigZ; - uint_fast8_t carry; - void (*roundPackRoutinePtr)( bool, int32_t, uint32_t *, uint32_t * ); - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uiA96 = aWPtr[indexWordHi( 4 )]; - expA = expF128UI96( uiA96 ); - uiB96 = bWPtr[indexWordHi( 4 )]; - expB = expF128UI96( uiB96 ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( (expA == 0x7FFF) || (expB == 0x7FFF) ) { - if ( softfloat_tryPropagateNaNF128M( aWPtr, bWPtr, zWPtr ) ) return; - uiZ96 = uiA96; - if ( expB == 0x7FFF ) { - uiZ96 = uiB96 ^ packToF128UI96( negateB, 0, 0 ); - if ( (expA == 0x7FFF) && (uiZ96 != uiA96) ) { - softfloat_invalidF128M( zWPtr ); - return; - } - } - zWPtr[indexWordHi( 4 )] = uiZ96; - zWPtr[indexWord( 4, 2 )] = 0; - zWPtr[indexWord( 4, 1 )] = 0; - zWPtr[indexWord( 4, 0 )] = 0; - return; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - signZ = signF128UI96( uiA96 ); - signB = signF128UI96( uiB96 ) ^ negateB; - negateB = (signZ != signB); - if ( (uint32_t) (uiA96<<1) < (uint32_t) (uiB96<<1) ) { - signZ = signB; - expA = expB; - expB = expF128UI96( uiA96 ); - tempPtr = aWPtr; - aWPtr = bWPtr; - bWPtr = tempPtr; - uiA96 = uiB96; - uiB96 = bWPtr[indexWordHi( 4 )]; - } - sig96A = fracF128UI96( uiA96 ); - sig96B = fracF128UI96( uiB96 ); - if ( expA ) { - --expA; - sig96A |= 0x00010000; - if ( expB ) { - --expB; - sig96B |= 0x00010000; - } - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - addCarryMRoutinePtr = - negateB ? softfloat_addComplCarryM : softfloat_addCarryM; - expDiff = expA - expB; - if ( expDiff ) { - /*-------------------------------------------------------------------- - *--------------------------------------------------------------------*/ - extSigZ[indexWordHi( 5 )] = sig96B; - extSigZ[indexWord( 5, 3 )] = bWPtr[indexWord( 4, 2 )]; - extSigZ[indexWord( 5, 2 )] = bWPtr[indexWord( 4, 1 )]; - extSigZ[indexWord( 5, 1 )] = bWPtr[indexWord( 4, 0 )]; - extSigZ[indexWord( 5, 0 )] = 0; - softfloat_shiftRightJam160M( extSigZ, expDiff, extSigZ ); - sig96B = extSigZ[indexWordHi( 5 )]; - carry = 0; - if ( negateB ) { - sig96B = ~sig96B; - wordSigZ = extSigZ[indexWordLo( 5 )]; - extSigZ[indexWordLo( 5 )] = -wordSigZ; - carry = ! wordSigZ; - } - carry = - (*addCarryMRoutinePtr)( - 3, - &aWPtr[indexMultiwordLo( 4, 3 )], - &extSigZ[indexMultiword( 5, 3, 1 )], - carry, - &extSigZ[indexMultiword( 5, 3, 1 )] - ); - wordSigZ = sig96A + sig96B + carry; - } else { - /*-------------------------------------------------------------------- - *--------------------------------------------------------------------*/ - extSigZ[indexWordLo( 5 )] = 0; - carry = - (*addCarryMRoutinePtr)( - 3, - &aWPtr[indexMultiwordLo( 4, 3 )], - &bWPtr[indexMultiwordLo( 4, 3 )], - negateB, - &extSigZ[indexMultiword( 5, 3, 1 )] - ); - if ( negateB ) { - wordSigZ = sig96A + ~sig96B + carry; - if ( wordSigZ & 0x80000000 ) { - signZ = ! signZ; - carry = - softfloat_addComplCarry96M( - &bWPtr[indexMultiwordLo( 4, 3 )], - &aWPtr[indexMultiwordLo( 4, 3 )], - 1, - &extSigZ[indexMultiword( 5, 3, 1 )] - ); - wordSigZ = sig96B + ~sig96A + carry; - } else { - if ( - ! wordSigZ && ! extSigZ[indexWord( 5, 3 )] - && ! ( extSigZ[indexWord( 5, 2 )] - | extSigZ[indexWord( 5, 1 )] - | extSigZ[indexWord( 5, 0 )] - ) - ) { - signZ = (softfloat_roundingMode == softfloat_round_min); - zWPtr[indexWordHi( 4 )] = packToF128UI96( signZ, 0, 0 ); - zWPtr[indexWord( 4, 2 )] = 0; - zWPtr[indexWord( 4, 1 )] = 0; - zWPtr[indexWord( 4, 0 )] = 0; - return; - } - } - } else { - wordSigZ = sig96A + sig96B + carry; - } - } - extSigZ[indexWordHi( 5 )] = wordSigZ; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - roundPackRoutinePtr = softfloat_normRoundPackMToF128M; - if ( 0x00010000 <= wordSigZ ) { - if ( 0x00020000 <= wordSigZ ) { - ++expA; - softfloat_shortShiftRightJam160M( extSigZ, 1, extSigZ ); - } - roundPackRoutinePtr = softfloat_roundPackMToF128M; - } - (*roundPackRoutinePtr)( signZ, expA, extSigZ, zWPtr ); - -} - diff --git a/deps/SoftFloat-3e/source/s_addM.c b/deps/SoftFloat-3e/source/s_addM.c deleted file mode 100644 index c935baaf7c9e..000000000000 --- a/deps/SoftFloat-3e/source/s_addM.c +++ /dev/null @@ -1,70 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "primitiveTypes.h" - -#ifndef softfloat_addM - -void - softfloat_addM( - uint_fast8_t size_words, - const uint32_t *aPtr, - const uint32_t *bPtr, - uint32_t *zPtr - ) -{ - unsigned int index, lastIndex; - uint_fast8_t carry; - uint32_t wordA, wordZ; - - index = indexWordLo( size_words ); - lastIndex = indexWordHi( size_words ); - carry = 0; - for (;;) { - wordA = aPtr[index]; - wordZ = wordA + bPtr[index] + carry; - zPtr[index] = wordZ; - if ( index == lastIndex ) break; - if ( wordZ != wordA ) carry = (wordZ < wordA); - index += wordIncr; - } - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/s_addMagsExtF80.c b/deps/SoftFloat-3e/source/s_addMagsExtF80.c deleted file mode 100644 index b1bb5dbe64a7..000000000000 --- a/deps/SoftFloat-3e/source/s_addMagsExtF80.c +++ /dev/null @@ -1,156 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -extFloat80_t - softfloat_addMagsExtF80( - uint_fast16_t uiA64, - uint_fast64_t uiA0, - uint_fast16_t uiB64, - uint_fast64_t uiB0, - bool signZ - ) -{ - int_fast32_t expA; - uint_fast64_t sigA; - int_fast32_t expB; - uint_fast64_t sigB; - int_fast32_t expDiff; - uint_fast16_t uiZ64; - uint_fast64_t uiZ0, sigZ, sigZExtra; - struct exp32_sig64 normExpSig; - int_fast32_t expZ; - struct uint64_extra sig64Extra; - struct uint128 uiZ; - union { struct extFloat80M s; extFloat80_t f; } uZ; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - expA = expExtF80UI64( uiA64 ); - sigA = uiA0; - expB = expExtF80UI64( uiB64 ); - sigB = uiB0; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - expDiff = expA - expB; - if ( ! expDiff ) { - if ( expA == 0x7FFF ) { - if ( (sigA | sigB) & UINT64_C( 0x7FFFFFFFFFFFFFFF ) ) { - goto propagateNaN; - } - uiZ64 = uiA64; - uiZ0 = uiA0; - goto uiZ; - } - sigZ = sigA + sigB; - sigZExtra = 0; - if ( ! expA ) { - normExpSig = softfloat_normSubnormalExtF80Sig( sigZ ); - expZ = normExpSig.exp + 1; - sigZ = normExpSig.sig; - goto roundAndPack; - } - expZ = expA; - goto shiftRight1; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( expDiff < 0 ) { - if ( expB == 0x7FFF ) { - if ( sigB & UINT64_C( 0x7FFFFFFFFFFFFFFF ) ) goto propagateNaN; - uiZ64 = packToExtF80UI64( signZ, 0x7FFF ); - uiZ0 = uiB0; - goto uiZ; - } - expZ = expB; - if ( ! expA ) { - ++expDiff; - sigZExtra = 0; - if ( ! expDiff ) goto newlyAligned; - } - sig64Extra = softfloat_shiftRightJam64Extra( sigA, 0, -expDiff ); - sigA = sig64Extra.v; - sigZExtra = sig64Extra.extra; - } else { - if ( expA == 0x7FFF ) { - if ( sigA & UINT64_C( 0x7FFFFFFFFFFFFFFF ) ) goto propagateNaN; - uiZ64 = uiA64; - uiZ0 = uiA0; - goto uiZ; - } - expZ = expA; - if ( ! expB ) { - --expDiff; - sigZExtra = 0; - if ( ! expDiff ) goto newlyAligned; - } - sig64Extra = softfloat_shiftRightJam64Extra( sigB, 0, expDiff ); - sigB = sig64Extra.v; - sigZExtra = sig64Extra.extra; - } - newlyAligned: - sigZ = sigA + sigB; - if ( sigZ & UINT64_C( 0x8000000000000000 ) ) goto roundAndPack; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - shiftRight1: - sig64Extra = softfloat_shortShiftRightJam64Extra( sigZ, sigZExtra, 1 ); - sigZ = sig64Extra.v | UINT64_C( 0x8000000000000000 ); - sigZExtra = sig64Extra.extra; - ++expZ; - roundAndPack: - return - softfloat_roundPackToExtF80( - signZ, expZ, sigZ, sigZExtra, extF80_roundingPrecision ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - propagateNaN: - uiZ = softfloat_propagateNaNExtF80UI( uiA64, uiA0, uiB64, uiB0 ); - uiZ64 = uiZ.v64; - uiZ0 = uiZ.v0; - uiZ: - uZ.s.signExp = uiZ64; - uZ.s.signif = uiZ0; - return uZ.f; - -} - diff --git a/deps/SoftFloat-3e/source/s_addMagsF128.c b/deps/SoftFloat-3e/source/s_addMagsF128.c deleted file mode 100644 index 8e5ce5b34e16..000000000000 --- a/deps/SoftFloat-3e/source/s_addMagsF128.c +++ /dev/null @@ -1,154 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" - -float128_t - softfloat_addMagsF128( - uint_fast64_t uiA64, - uint_fast64_t uiA0, - uint_fast64_t uiB64, - uint_fast64_t uiB0, - bool signZ - ) -{ - int_fast32_t expA; - struct uint128 sigA; - int_fast32_t expB; - struct uint128 sigB; - int_fast32_t expDiff; - struct uint128 uiZ, sigZ; - int_fast32_t expZ; - uint_fast64_t sigZExtra; - struct uint128_extra sig128Extra; - union ui128_f128 uZ; - - expA = expF128UI64( uiA64 ); - sigA.v64 = fracF128UI64( uiA64 ); - sigA.v0 = uiA0; - expB = expF128UI64( uiB64 ); - sigB.v64 = fracF128UI64( uiB64 ); - sigB.v0 = uiB0; - expDiff = expA - expB; - if ( ! expDiff ) { - if ( expA == 0x7FFF ) { - if ( sigA.v64 | sigA.v0 | sigB.v64 | sigB.v0 ) goto propagateNaN; - uiZ.v64 = uiA64; - uiZ.v0 = uiA0; - goto uiZ; - } - sigZ = softfloat_add128( sigA.v64, sigA.v0, sigB.v64, sigB.v0 ); - if ( ! expA ) { - uiZ.v64 = packToF128UI64( signZ, 0, sigZ.v64 ); - uiZ.v0 = sigZ.v0; - goto uiZ; - } - expZ = expA; - sigZ.v64 |= UINT64_C( 0x0002000000000000 ); - sigZExtra = 0; - goto shiftRight1; - } - if ( expDiff < 0 ) { - if ( expB == 0x7FFF ) { - if ( sigB.v64 | sigB.v0 ) goto propagateNaN; - uiZ.v64 = packToF128UI64( signZ, 0x7FFF, 0 ); - uiZ.v0 = 0; - goto uiZ; - } - expZ = expB; - if ( expA ) { - sigA.v64 |= UINT64_C( 0x0001000000000000 ); - } else { - ++expDiff; - sigZExtra = 0; - if ( ! expDiff ) goto newlyAligned; - } - sig128Extra = - softfloat_shiftRightJam128Extra( sigA.v64, sigA.v0, 0, -expDiff ); - sigA = sig128Extra.v; - sigZExtra = sig128Extra.extra; - } else { - if ( expA == 0x7FFF ) { - if ( sigA.v64 | sigA.v0 ) goto propagateNaN; - uiZ.v64 = uiA64; - uiZ.v0 = uiA0; - goto uiZ; - } - expZ = expA; - if ( expB ) { - sigB.v64 |= UINT64_C( 0x0001000000000000 ); - } else { - --expDiff; - sigZExtra = 0; - if ( ! expDiff ) goto newlyAligned; - } - sig128Extra = - softfloat_shiftRightJam128Extra( sigB.v64, sigB.v0, 0, expDiff ); - sigB = sig128Extra.v; - sigZExtra = sig128Extra.extra; - } - newlyAligned: - sigZ = - softfloat_add128( - sigA.v64 | UINT64_C( 0x0001000000000000 ), - sigA.v0, - sigB.v64, - sigB.v0 - ); - --expZ; - if ( sigZ.v64 < UINT64_C( 0x0002000000000000 ) ) goto roundAndPack; - ++expZ; - shiftRight1: - sig128Extra = - softfloat_shortShiftRightJam128Extra( - sigZ.v64, sigZ.v0, sigZExtra, 1 ); - sigZ = sig128Extra.v; - sigZExtra = sig128Extra.extra; - roundAndPack: - return - softfloat_roundPackToF128( signZ, expZ, sigZ.v64, sigZ.v0, sigZExtra ); - propagateNaN: - uiZ = softfloat_propagateNaNF128UI( uiA64, uiA0, uiB64, uiB0 ); - uiZ: - uZ.ui = uiZ; - return uZ.f; - -} - diff --git a/deps/SoftFloat-3e/source/s_addMagsF16.c b/deps/SoftFloat-3e/source/s_addMagsF16.c deleted file mode 100644 index b7fba09283e8..000000000000 --- a/deps/SoftFloat-3e/source/s_addMagsF16.c +++ /dev/null @@ -1,183 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017 The Regents of the -University of California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -float16_t softfloat_addMagsF16( uint_fast16_t uiA, uint_fast16_t uiB ) -{ - int_fast8_t expA; - uint_fast16_t sigA; - int_fast8_t expB; - uint_fast16_t sigB; - int_fast8_t expDiff; - uint_fast16_t uiZ; - bool signZ; - int_fast8_t expZ; - uint_fast16_t sigZ; - uint_fast16_t sigX, sigY; - int_fast8_t shiftDist; - uint_fast32_t sig32Z; - int_fast8_t roundingMode; - union ui16_f16 uZ; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - expA = expF16UI( uiA ); - sigA = fracF16UI( uiA ); - expB = expF16UI( uiB ); - sigB = fracF16UI( uiB ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - expDiff = expA - expB; - if ( ! expDiff ) { - /*-------------------------------------------------------------------- - *--------------------------------------------------------------------*/ - if ( ! expA ) { - uiZ = uiA + sigB; - goto uiZ; - } - if ( expA == 0x1F ) { - if ( sigA | sigB ) goto propagateNaN; - uiZ = uiA; - goto uiZ; - } - signZ = signF16UI( uiA ); - expZ = expA; - sigZ = 0x0800 + sigA + sigB; - if ( ! (sigZ & 1) && (expZ < 0x1E) ) { - sigZ >>= 1; - goto pack; - } - sigZ <<= 3; - } else { - /*-------------------------------------------------------------------- - *--------------------------------------------------------------------*/ - signZ = signF16UI( uiA ); - if ( expDiff < 0 ) { - /*---------------------------------------------------------------- - *----------------------------------------------------------------*/ - if ( expB == 0x1F ) { - if ( sigB ) goto propagateNaN; - uiZ = packToF16UI( signZ, 0x1F, 0 ); - goto uiZ; - } - if ( expDiff <= -13 ) { - uiZ = packToF16UI( signZ, expB, sigB ); - if ( expA | sigA ) goto addEpsilon; - goto uiZ; - } - expZ = expB; - sigX = sigB | 0x0400; - sigY = sigA + (expA ? 0x0400 : sigA); - shiftDist = 19 + expDiff; - } else { - /*---------------------------------------------------------------- - *----------------------------------------------------------------*/ - uiZ = uiA; - if ( expA == 0x1F ) { - if ( sigA ) goto propagateNaN; - goto uiZ; - } - if ( 13 <= expDiff ) { - if ( expB | sigB ) goto addEpsilon; - goto uiZ; - } - expZ = expA; - sigX = sigA | 0x0400; - sigY = sigB + (expB ? 0x0400 : sigB); - shiftDist = 19 - expDiff; - } - sig32Z = - ((uint_fast32_t) sigX<<19) + ((uint_fast32_t) sigY<>16; - if ( sig32Z & 0xFFFF ) { - sigZ |= 1; - } else { - if ( ! (sigZ & 0xF) && (expZ < 0x1E) ) { - sigZ >>= 4; - goto pack; - } - } - } - return softfloat_roundPackToF16( signZ, expZ, sigZ ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - propagateNaN: - uiZ = softfloat_propagateNaNF16UI( uiA, uiB ); - goto uiZ; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - addEpsilon: - roundingMode = softfloat_roundingMode; - if ( roundingMode != softfloat_round_near_even ) { - if ( - roundingMode - == (signF16UI( uiZ ) ? softfloat_round_min - : softfloat_round_max) - ) { - ++uiZ; - if ( (uint16_t) (uiZ<<1) == 0xF800 ) { - softfloat_raiseFlags( - softfloat_flag_overflow | softfloat_flag_inexact ); - } - } -#ifdef SOFTFLOAT_ROUND_ODD - else if ( roundingMode == softfloat_round_odd ) { - uiZ |= 1; - } -#endif - } - softfloat_exceptionFlags |= softfloat_flag_inexact; - goto uiZ; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - pack: - uiZ = packToF16UI( signZ, expZ, sigZ ); - uiZ: - uZ.ui = uiZ; - return uZ.f; - -} - diff --git a/deps/SoftFloat-3e/source/s_addMagsF32.c b/deps/SoftFloat-3e/source/s_addMagsF32.c deleted file mode 100644 index b74489decefe..000000000000 --- a/deps/SoftFloat-3e/source/s_addMagsF32.c +++ /dev/null @@ -1,126 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" - -float32_t softfloat_addMagsF32( uint_fast32_t uiA, uint_fast32_t uiB ) -{ - int_fast16_t expA; - uint_fast32_t sigA; - int_fast16_t expB; - uint_fast32_t sigB; - int_fast16_t expDiff; - uint_fast32_t uiZ; - bool signZ; - int_fast16_t expZ; - uint_fast32_t sigZ; - union ui32_f32 uZ; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - expA = expF32UI( uiA ); - sigA = fracF32UI( uiA ); - expB = expF32UI( uiB ); - sigB = fracF32UI( uiB ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - expDiff = expA - expB; - if ( ! expDiff ) { - /*-------------------------------------------------------------------- - *--------------------------------------------------------------------*/ - if ( ! expA ) { - uiZ = uiA + sigB; - goto uiZ; - } - if ( expA == 0xFF ) { - if ( sigA | sigB ) goto propagateNaN; - uiZ = uiA; - goto uiZ; - } - signZ = signF32UI( uiA ); - expZ = expA; - sigZ = 0x01000000 + sigA + sigB; - if ( ! (sigZ & 1) && (expZ < 0xFE) ) { - uiZ = packToF32UI( signZ, expZ, sigZ>>1 ); - goto uiZ; - } - sigZ <<= 6; - } else { - /*-------------------------------------------------------------------- - *--------------------------------------------------------------------*/ - signZ = signF32UI( uiA ); - sigA <<= 6; - sigB <<= 6; - if ( expDiff < 0 ) { - if ( expB == 0xFF ) { - if ( sigB ) goto propagateNaN; - uiZ = packToF32UI( signZ, 0xFF, 0 ); - goto uiZ; - } - expZ = expB; - sigA += expA ? 0x20000000 : sigA; - sigA = softfloat_shiftRightJam32( sigA, -expDiff ); - } else { - if ( expA == 0xFF ) { - if ( sigA ) goto propagateNaN; - uiZ = uiA; - goto uiZ; - } - expZ = expA; - sigB += expB ? 0x20000000 : sigB; - sigB = softfloat_shiftRightJam32( sigB, expDiff ); - } - sigZ = 0x20000000 + sigA + sigB; - if ( sigZ < 0x40000000 ) { - --expZ; - sigZ <<= 1; - } - } - return softfloat_roundPackToF32( signZ, expZ, sigZ ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - propagateNaN: - uiZ = softfloat_propagateNaNF32UI( uiA, uiB ); - uiZ: - uZ.ui = uiZ; - return uZ.f; - -} - diff --git a/deps/SoftFloat-3e/source/s_addMagsF64.c b/deps/SoftFloat-3e/source/s_addMagsF64.c deleted file mode 100644 index e8a489874562..000000000000 --- a/deps/SoftFloat-3e/source/s_addMagsF64.c +++ /dev/null @@ -1,128 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" - -float64_t - softfloat_addMagsF64( uint_fast64_t uiA, uint_fast64_t uiB, bool signZ ) -{ - int_fast16_t expA; - uint_fast64_t sigA; - int_fast16_t expB; - uint_fast64_t sigB; - int_fast16_t expDiff; - uint_fast64_t uiZ; - int_fast16_t expZ; - uint_fast64_t sigZ; - union ui64_f64 uZ; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - expA = expF64UI( uiA ); - sigA = fracF64UI( uiA ); - expB = expF64UI( uiB ); - sigB = fracF64UI( uiB ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - expDiff = expA - expB; - if ( ! expDiff ) { - /*-------------------------------------------------------------------- - *--------------------------------------------------------------------*/ - if ( ! expA ) { - uiZ = uiA + sigB; - goto uiZ; - } - if ( expA == 0x7FF ) { - if ( sigA | sigB ) goto propagateNaN; - uiZ = uiA; - goto uiZ; - } - expZ = expA; - sigZ = UINT64_C( 0x0020000000000000 ) + sigA + sigB; - sigZ <<= 9; - } else { - /*-------------------------------------------------------------------- - *--------------------------------------------------------------------*/ - sigA <<= 9; - sigB <<= 9; - if ( expDiff < 0 ) { - if ( expB == 0x7FF ) { - if ( sigB ) goto propagateNaN; - uiZ = packToF64UI( signZ, 0x7FF, 0 ); - goto uiZ; - } - expZ = expB; - if ( expA ) { - sigA += UINT64_C( 0x2000000000000000 ); - } else { - sigA <<= 1; - } - sigA = softfloat_shiftRightJam64( sigA, -expDiff ); - } else { - if ( expA == 0x7FF ) { - if ( sigA ) goto propagateNaN; - uiZ = uiA; - goto uiZ; - } - expZ = expA; - if ( expB ) { - sigB += UINT64_C( 0x2000000000000000 ); - } else { - sigB <<= 1; - } - sigB = softfloat_shiftRightJam64( sigB, expDiff ); - } - sigZ = UINT64_C( 0x2000000000000000 ) + sigA + sigB; - if ( sigZ < UINT64_C( 0x4000000000000000 ) ) { - --expZ; - sigZ <<= 1; - } - } - return softfloat_roundPackToF64( signZ, expZ, sigZ ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - propagateNaN: - uiZ = softfloat_propagateNaNF64UI( uiA, uiB ); - uiZ: - uZ.ui = uiZ; - return uZ.f; - -} - diff --git a/deps/SoftFloat-3e/source/s_approxRecip32_1.c b/deps/SoftFloat-3e/source/s_approxRecip32_1.c deleted file mode 100644 index 4a326a438fe4..000000000000 --- a/deps/SoftFloat-3e/source/s_approxRecip32_1.c +++ /dev/null @@ -1,66 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" - -#ifndef softfloat_approxRecip32_1 - -extern const uint16_t softfloat_approxRecip_1k0s[16]; -extern const uint16_t softfloat_approxRecip_1k1s[16]; - -uint32_t softfloat_approxRecip32_1( uint32_t a ) -{ - int index; - uint16_t eps, r0; - uint32_t sigma0; - uint_fast32_t r; - uint32_t sqrSigma0; - - index = a>>27 & 0xF; - eps = (uint16_t) (a>>11); - r0 = softfloat_approxRecip_1k0s[index] - - ((softfloat_approxRecip_1k1s[index] * (uint_fast32_t) eps)>>20); - sigma0 = ~(uint_fast32_t) ((r0 * (uint_fast64_t) a)>>7); - r = ((uint_fast32_t) r0<<16) + ((r0 * (uint_fast64_t) sigma0)>>24); - sqrSigma0 = ((uint_fast64_t) sigma0 * sigma0)>>32; - r += ((uint32_t) r * (uint_fast64_t) sqrSigma0)>>48; - return r; - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/s_approxRecipSqrt32_1.c b/deps/SoftFloat-3e/source/s_approxRecipSqrt32_1.c deleted file mode 100644 index b3fdeba68b75..000000000000 --- a/deps/SoftFloat-3e/source/s_approxRecipSqrt32_1.c +++ /dev/null @@ -1,73 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" - -#ifndef softfloat_approxRecipSqrt32_1 - -extern const uint16_t softfloat_approxRecipSqrt_1k0s[]; -extern const uint16_t softfloat_approxRecipSqrt_1k1s[]; - -uint32_t softfloat_approxRecipSqrt32_1( unsigned int oddExpA, uint32_t a ) -{ - int index; - uint16_t eps, r0; - uint_fast32_t ESqrR0; - uint32_t sigma0; - uint_fast32_t r; - uint32_t sqrSigma0; - - index = (a>>27 & 0xE) + oddExpA; - eps = (uint16_t) (a>>12); - r0 = softfloat_approxRecipSqrt_1k0s[index] - - ((softfloat_approxRecipSqrt_1k1s[index] * (uint_fast32_t) eps) - >>20); - ESqrR0 = (uint_fast32_t) r0 * r0; - if ( ! oddExpA ) ESqrR0 <<= 1; - sigma0 = ~(uint_fast32_t) (((uint32_t) ESqrR0 * (uint_fast64_t) a)>>23); - r = ((uint_fast32_t) r0<<16) + ((r0 * (uint_fast64_t) sigma0)>>25); - sqrSigma0 = ((uint_fast64_t) sigma0 * sigma0)>>32; - r += ((uint32_t) ((r>>1) + (r>>3) - ((uint_fast32_t) r0<<14)) - * (uint_fast64_t) sqrSigma0) - >>48; - if ( ! (r & 0x80000000) ) r = 0x80000000; - return r; - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/s_approxRecipSqrt_1Ks.c b/deps/SoftFloat-3e/source/s_approxRecipSqrt_1Ks.c deleted file mode 100644 index 38a27985c03e..000000000000 --- a/deps/SoftFloat-3e/source/s_approxRecipSqrt_1Ks.c +++ /dev/null @@ -1,49 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "primitives.h" - -const uint16_t softfloat_approxRecipSqrt_1k0s[16] = { - 0xB4C9, 0xFFAB, 0xAA7D, 0xF11C, 0xA1C5, 0xE4C7, 0x9A43, 0xDA29, - 0x93B5, 0xD0E5, 0x8DED, 0xC8B7, 0x88C6, 0xC16D, 0x8424, 0xBAE1 -}; -const uint16_t softfloat_approxRecipSqrt_1k1s[16] = { - 0xA5A5, 0xEA42, 0x8C21, 0xC62D, 0x788F, 0xAA7F, 0x6928, 0x94B6, - 0x5CC7, 0x8335, 0x52A6, 0x74E2, 0x4A3E, 0x68FE, 0x432B, 0x5EFD -}; - diff --git a/deps/SoftFloat-3e/source/s_approxRecip_1Ks.c b/deps/SoftFloat-3e/source/s_approxRecip_1Ks.c deleted file mode 100644 index f1fca74e73b7..000000000000 --- a/deps/SoftFloat-3e/source/s_approxRecip_1Ks.c +++ /dev/null @@ -1,49 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "primitives.h" - -const uint16_t softfloat_approxRecip_1k0s[16] = { - 0xFFC4, 0xF0BE, 0xE363, 0xD76F, 0xCCAD, 0xC2F0, 0xBA16, 0xB201, - 0xAA97, 0xA3C6, 0x9D7A, 0x97A6, 0x923C, 0x8D32, 0x887E, 0x8417 -}; -const uint16_t softfloat_approxRecip_1k1s[16] = { - 0xF0F1, 0xD62C, 0xBFA1, 0xAC77, 0x9C0A, 0x8DDB, 0x8185, 0x76BA, - 0x6D3B, 0x64D4, 0x5D5C, 0x56B1, 0x50B6, 0x4B55, 0x4679, 0x4211 -}; - diff --git a/deps/SoftFloat-3e/source/s_compare128M.c b/deps/SoftFloat-3e/source/s_compare128M.c deleted file mode 100644 index dc97ce9e5015..000000000000 --- a/deps/SoftFloat-3e/source/s_compare128M.c +++ /dev/null @@ -1,62 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "primitiveTypes.h" - -#ifndef softfloat_compare128M - -int_fast8_t softfloat_compare128M( const uint32_t *aPtr, const uint32_t *bPtr ) -{ - unsigned int index, lastIndex; - uint32_t wordA, wordB; - - index = indexWordHi( 4 ); - lastIndex = indexWordLo( 4 ); - for (;;) { - wordA = aPtr[index]; - wordB = bPtr[index]; - if ( wordA != wordB ) return (wordA < wordB) ? -1 : 1; - if ( index == lastIndex ) break; - index -= wordIncr; - } - return 0; - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/s_compare96M.c b/deps/SoftFloat-3e/source/s_compare96M.c deleted file mode 100644 index 2681c46274ac..000000000000 --- a/deps/SoftFloat-3e/source/s_compare96M.c +++ /dev/null @@ -1,62 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "primitiveTypes.h" - -#ifndef softfloat_compare96M - -int_fast8_t softfloat_compare96M( const uint32_t *aPtr, const uint32_t *bPtr ) -{ - unsigned int index, lastIndex; - uint32_t wordA, wordB; - - index = indexWordHi( 3 ); - lastIndex = indexWordLo( 3 ); - for (;;) { - wordA = aPtr[index]; - wordB = bPtr[index]; - if ( wordA != wordB ) return (wordA < wordB) ? -1 : 1; - if ( index == lastIndex ) break; - index -= wordIncr; - } - return 0; - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/s_compareNonnormExtF80M.c b/deps/SoftFloat-3e/source/s_compareNonnormExtF80M.c deleted file mode 100644 index 2673153048c1..000000000000 --- a/deps/SoftFloat-3e/source/s_compareNonnormExtF80M.c +++ /dev/null @@ -1,111 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "internals.h" -#include "softfloat_types.h" - -int - softfloat_compareNonnormExtF80M( - const struct extFloat80M *aSPtr, const struct extFloat80M *bSPtr ) -{ - uint_fast16_t uiA64, uiB64; - uint64_t sigA; - bool signB; - uint64_t sigB; - int32_t expA, expB; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uiA64 = aSPtr->signExp; - uiB64 = bSPtr->signExp; - sigA = aSPtr->signif; - signB = signExtF80UI64( uiB64 ); - sigB = bSPtr->signif; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( (uiA64 ^ uiB64) & 0x8000 ) { - if ( ! (sigA | sigB) ) return 0; - goto resultFromSignB; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - expA = expExtF80UI64( uiA64 ); - expB = expExtF80UI64( uiB64 ); - if ( expA == 0x7FFF ) { - if (expB == 0x7FFF) return 0; - signB = ! signB; - goto resultFromSignB; - } - if ( expB == 0x7FFF ) { - goto resultFromSignB; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( ! expA ) expA = 1; - if ( ! (sigA & UINT64_C( 0x8000000000000000 )) ) { - if ( sigA ) { - expA += softfloat_normExtF80SigM( &sigA ); - } else { - expA = -128; - } - } - if ( ! expB ) expB = 1; - if ( ! (sigB & UINT64_C( 0x8000000000000000 )) ) { - if ( sigB ) { - expB += softfloat_normExtF80SigM( &sigB ); - } else { - expB = -128; - } - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( signB ) { - if ( expA < expB ) return 1; - if ( (expB < expA) || (sigB < sigA) ) return -1; - } else { - if ( expB < expA ) return 1; - if ( (expA < expB) || (sigA < sigB) ) return -1; - } - return (sigA != sigB); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - resultFromSignB: - return signB ? 1 : -1; - -} - diff --git a/deps/SoftFloat-3e/source/s_countLeadingZeros16.c b/deps/SoftFloat-3e/source/s_countLeadingZeros16.c deleted file mode 100644 index 7a68da52f35e..000000000000 --- a/deps/SoftFloat-3e/source/s_countLeadingZeros16.c +++ /dev/null @@ -1,60 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" - -#ifndef softfloat_countLeadingZeros16 - -#define softfloat_countLeadingZeros16 softfloat_countLeadingZeros16 -#include "primitives.h" - -uint_fast8_t softfloat_countLeadingZeros16( uint16_t a ) -{ - uint_fast8_t count; - - count = 8; - if ( 0x100 <= a ) { - count = 0; - a >>= 8; - } - count += softfloat_countLeadingZeros8[a]; - return count; - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/s_countLeadingZeros32.c b/deps/SoftFloat-3e/source/s_countLeadingZeros32.c deleted file mode 100644 index 53ab22824f7e..000000000000 --- a/deps/SoftFloat-3e/source/s_countLeadingZeros32.c +++ /dev/null @@ -1,64 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" - -#ifndef softfloat_countLeadingZeros32 - -#define softfloat_countLeadingZeros32 softfloat_countLeadingZeros32 -#include "primitives.h" - -uint_fast8_t softfloat_countLeadingZeros32( uint32_t a ) -{ - uint_fast8_t count; - - count = 0; - if ( a < 0x10000 ) { - count = 16; - a <<= 16; - } - if ( a < 0x1000000 ) { - count += 8; - a <<= 8; - } - count += softfloat_countLeadingZeros8[a>>24]; - return count; - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/s_countLeadingZeros64.c b/deps/SoftFloat-3e/source/s_countLeadingZeros64.c deleted file mode 100644 index 13a222463643..000000000000 --- a/deps/SoftFloat-3e/source/s_countLeadingZeros64.c +++ /dev/null @@ -1,73 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" - -#ifndef softfloat_countLeadingZeros64 - -#define softfloat_countLeadingZeros64 softfloat_countLeadingZeros64 -#include "primitives.h" - -uint_fast8_t softfloat_countLeadingZeros64( uint64_t a ) -{ - uint_fast8_t count; - uint32_t a32; - - count = 0; - a32 = a>>32; - if ( ! a32 ) { - count = 32; - a32 = a; - } - /*------------------------------------------------------------------------ - | From here, result is current count + count leading zeros of `a32'. - *------------------------------------------------------------------------*/ - if ( a32 < 0x10000 ) { - count += 16; - a32 <<= 16; - } - if ( a32 < 0x1000000 ) { - count += 8; - a32 <<= 8; - } - count += softfloat_countLeadingZeros8[a32>>24]; - return count; - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/s_countLeadingZeros8.c b/deps/SoftFloat-3e/source/s_countLeadingZeros8.c deleted file mode 100644 index a56f5a40c52e..000000000000 --- a/deps/SoftFloat-3e/source/s_countLeadingZeros8.c +++ /dev/null @@ -1,59 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "primitives.h" - -const uint_least8_t softfloat_countLeadingZeros8[256] = { - 8, 7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 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, 2, 2, - 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, - 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, - 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, - 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, - 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, - 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 -}; - diff --git a/deps/SoftFloat-3e/source/s_eq128.c b/deps/SoftFloat-3e/source/s_eq128.c deleted file mode 100644 index 275b8ae29942..000000000000 --- a/deps/SoftFloat-3e/source/s_eq128.c +++ /dev/null @@ -1,51 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" - -#ifndef softfloat_eq128 - -bool softfloat_eq128( uint64_t a64, uint64_t a0, uint64_t b64, uint64_t b0 ) -{ - - return (a64 == b64) && (a0 == b0); - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/s_invalidExtF80M.c b/deps/SoftFloat-3e/source/s_invalidExtF80M.c deleted file mode 100644 index 237d217212ef..000000000000 --- a/deps/SoftFloat-3e/source/s_invalidExtF80M.c +++ /dev/null @@ -1,49 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include "platform.h" -#include "specialize.h" -#include "softfloat.h" - -void softfloat_invalidExtF80M( struct extFloat80M *zSPtr ) -{ - - softfloat_raiseFlags( softfloat_flag_invalid ); - zSPtr->signExp = defaultNaNExtF80UI64; - zSPtr->signif = defaultNaNExtF80UI0; - -} - diff --git a/deps/SoftFloat-3e/source/s_invalidF128M.c b/deps/SoftFloat-3e/source/s_invalidF128M.c deleted file mode 100644 index a20840e5f556..000000000000 --- a/deps/SoftFloat-3e/source/s_invalidF128M.c +++ /dev/null @@ -1,53 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "primitives.h" -#include "specialize.h" -#include "softfloat.h" - -void softfloat_invalidF128M( uint32_t *zWPtr ) -{ - - softfloat_raiseFlags( softfloat_flag_invalid ); - zWPtr[indexWord( 4, 3 )] = defaultNaNF128UI96; - zWPtr[indexWord( 4, 2 )] = defaultNaNF128UI64; - zWPtr[indexWord( 4, 1 )] = defaultNaNF128UI32; - zWPtr[indexWord( 4, 0 )] = defaultNaNF128UI0; - -} - diff --git a/deps/SoftFloat-3e/source/s_isNaNF128M.c b/deps/SoftFloat-3e/source/s_isNaNF128M.c deleted file mode 100644 index 6008cf3ebc19..000000000000 --- a/deps/SoftFloat-3e/source/s_isNaNF128M.c +++ /dev/null @@ -1,57 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "primitives.h" - -/*---------------------------------------------------------------------------- -*----------------------------------------------------------------------------*/ -bool softfloat_isNaNF128M( const uint32_t *aWPtr ) -{ - uint32_t uiA96; - - uiA96 = aWPtr[indexWordHi( 4 )]; - if ( (~uiA96 & 0x7FFF0000) != 0 ) return false; - return - ((uiA96 & 0x0000FFFF) != 0) - || ((aWPtr[indexWord( 4, 2 )] | aWPtr[indexWord( 4, 1 )] - | aWPtr[indexWord( 4, 0 )]) - != 0); - -} - diff --git a/deps/SoftFloat-3e/source/s_le128.c b/deps/SoftFloat-3e/source/s_le128.c deleted file mode 100644 index 1fce7af98ea2..000000000000 --- a/deps/SoftFloat-3e/source/s_le128.c +++ /dev/null @@ -1,51 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" - -#ifndef softfloat_le128 - -bool softfloat_le128( uint64_t a64, uint64_t a0, uint64_t b64, uint64_t b0 ) -{ - - return (a64 < b64) || ((a64 == b64) && (a0 <= b0)); - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/s_lt128.c b/deps/SoftFloat-3e/source/s_lt128.c deleted file mode 100644 index d7ce3b997154..000000000000 --- a/deps/SoftFloat-3e/source/s_lt128.c +++ /dev/null @@ -1,51 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" - -#ifndef softfloat_lt128 - -bool softfloat_lt128( uint64_t a64, uint64_t a0, uint64_t b64, uint64_t b0 ) -{ - - return (a64 < b64) || ((a64 == b64) && (a0 < b0)); - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/s_mul128By32.c b/deps/SoftFloat-3e/source/s_mul128By32.c deleted file mode 100644 index 7c0fdc867949..000000000000 --- a/deps/SoftFloat-3e/source/s_mul128By32.c +++ /dev/null @@ -1,58 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "primitiveTypes.h" - -#ifndef softfloat_mul128By32 - -struct uint128 softfloat_mul128By32( uint64_t a64, uint64_t a0, uint32_t b ) -{ - struct uint128 z; - uint_fast64_t mid; - uint_fast32_t carry; - - z.v0 = a0 * b; - mid = (uint_fast64_t) (uint32_t) (a0>>32) * b; - carry = (uint32_t) ((uint_fast32_t) (z.v0>>32) - (uint_fast32_t) mid); - z.v64 = a64 * b + (uint_fast32_t) ((mid + carry)>>32); - return z; - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/s_mul128MTo256M.c b/deps/SoftFloat-3e/source/s_mul128MTo256M.c deleted file mode 100644 index ea8865ea3529..000000000000 --- a/deps/SoftFloat-3e/source/s_mul128MTo256M.c +++ /dev/null @@ -1,100 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "primitiveTypes.h" - -#ifndef softfloat_mul128MTo256M - -void - softfloat_mul128MTo256M( - const uint32_t *aPtr, const uint32_t *bPtr, uint32_t *zPtr ) -{ - uint32_t *lastZPtr, wordB; - uint64_t dwordProd; - uint32_t wordZ; - uint_fast8_t carry; - - bPtr += indexWordLo( 4 ); - lastZPtr = zPtr + indexMultiwordHi( 8, 5 ); - zPtr += indexMultiwordLo( 8, 5 ); - wordB = *bPtr; - dwordProd = (uint64_t) aPtr[indexWord( 4, 0 )] * wordB; - zPtr[indexWord( 5, 0 )] = dwordProd; - dwordProd = (uint64_t) aPtr[indexWord( 4, 1 )] * wordB + (dwordProd>>32); - zPtr[indexWord( 5, 1 )] = dwordProd; - dwordProd = (uint64_t) aPtr[indexWord( 4, 2 )] * wordB + (dwordProd>>32); - zPtr[indexWord( 5, 2 )] = dwordProd; - dwordProd = (uint64_t) aPtr[indexWord( 4, 3 )] * wordB + (dwordProd>>32); - zPtr[indexWord( 5, 3 )] = dwordProd; - zPtr[indexWord( 5, 4 )] = dwordProd>>32; - do { - bPtr += wordIncr; - zPtr += wordIncr; - wordB = *bPtr; - dwordProd = (uint64_t) aPtr[indexWord( 4, 0 )] * wordB; - wordZ = zPtr[indexWord( 5, 0 )] + (uint32_t) dwordProd; - zPtr[indexWord( 5, 0 )] = wordZ; - carry = (wordZ < (uint32_t) dwordProd); - dwordProd = - (uint64_t) aPtr[indexWord( 4, 1 )] * wordB + (dwordProd>>32); - wordZ = zPtr[indexWord( 5, 1 )] + (uint32_t) dwordProd + carry; - zPtr[indexWord( 5, 1 )] = wordZ; - if ( wordZ != (uint32_t) dwordProd ) { - carry = (wordZ < (uint32_t) dwordProd); - } - dwordProd = - (uint64_t) aPtr[indexWord( 4, 2 )] * wordB + (dwordProd>>32); - wordZ = zPtr[indexWord( 5, 2 )] + (uint32_t) dwordProd + carry; - zPtr[indexWord( 5, 2 )] = wordZ; - if ( wordZ != (uint32_t) dwordProd ) { - carry = (wordZ < (uint32_t) dwordProd); - } - dwordProd = - (uint64_t) aPtr[indexWord( 4, 3 )] * wordB + (dwordProd>>32); - wordZ = zPtr[indexWord( 5, 3 )] + (uint32_t) dwordProd + carry; - zPtr[indexWord( 5, 3 )] = wordZ; - if ( wordZ != (uint32_t) dwordProd ) { - carry = (wordZ < (uint32_t) dwordProd); - } - zPtr[indexWord( 5, 4 )] = (dwordProd>>32) + carry; - } while ( zPtr != lastZPtr ); - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/s_mul128To256M.c b/deps/SoftFloat-3e/source/s_mul128To256M.c deleted file mode 100644 index 7c9d9b584140..000000000000 --- a/deps/SoftFloat-3e/source/s_mul128To256M.c +++ /dev/null @@ -1,71 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" - -#ifndef softfloat_mul128To256M - -#define softfloat_mul128To256M softfloat_mul128To256M -#include "primitives.h" - -void - softfloat_mul128To256M( - uint64_t a64, uint64_t a0, uint64_t b64, uint64_t b0, uint64_t *zPtr ) -{ - struct uint128 p0, p64, p128; - uint_fast64_t z64, z128, z192; - - p0 = softfloat_mul64To128( a0, b0 ); - zPtr[indexWord( 4, 0 )] = p0.v0; - p64 = softfloat_mul64To128( a64, b0 ); - z64 = p64.v0 + p0.v64; - z128 = p64.v64 + (z64 < p64.v0); - p128 = softfloat_mul64To128( a64, b64 ); - z128 += p128.v0; - z192 = p128.v64 + (z128 < p128.v0); - p64 = softfloat_mul64To128( a0, b64 ); - z64 += p64.v0; - zPtr[indexWord( 4, 1 )] = z64; - p64.v64 += (z64 < p64.v0); - z128 += p64.v64; - zPtr[indexWord( 4, 2 )] = z128; - zPtr[indexWord( 4, 3 )] = z192 + (z128 < p64.v64); - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/s_mul64ByShifted32To128.c b/deps/SoftFloat-3e/source/s_mul64ByShifted32To128.c deleted file mode 100644 index 57e528888bfd..000000000000 --- a/deps/SoftFloat-3e/source/s_mul64ByShifted32To128.c +++ /dev/null @@ -1,56 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "primitiveTypes.h" - -#ifndef softfloat_mul64ByShifted32To128 - -struct uint128 softfloat_mul64ByShifted32To128( uint64_t a, uint32_t b ) -{ - uint_fast64_t mid; - struct uint128 z; - - mid = (uint_fast64_t) (uint32_t) a * b; - z.v0 = mid<<32; - z.v64 = (uint_fast64_t) (uint32_t) (a>>32) * b + (mid>>32); - return z; - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/s_mul64To128.c b/deps/SoftFloat-3e/source/s_mul64To128.c deleted file mode 100644 index 5d360aa4b81e..000000000000 --- a/deps/SoftFloat-3e/source/s_mul64To128.c +++ /dev/null @@ -1,66 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "primitiveTypes.h" - -#ifndef softfloat_mul64To128 - -struct uint128 softfloat_mul64To128( uint64_t a, uint64_t b ) -{ - uint32_t a32, a0, b32, b0; - struct uint128 z; - uint64_t mid1, mid; - - a32 = a>>32; - a0 = a; - b32 = b>>32; - b0 = b; - z.v0 = (uint_fast64_t) a0 * b0; - mid1 = (uint_fast64_t) a32 * b0; - mid = mid1 + (uint_fast64_t) a0 * b32; - z.v64 = (uint_fast64_t) a32 * b32; - z.v64 += (uint_fast64_t) (mid < mid1)<<32 | mid>>32; - mid <<= 32; - z.v0 += mid; - z.v64 += (z.v0 < mid); - return z; - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/s_mul64To128M.c b/deps/SoftFloat-3e/source/s_mul64To128M.c deleted file mode 100644 index ed10be3243db..000000000000 --- a/deps/SoftFloat-3e/source/s_mul64To128M.c +++ /dev/null @@ -1,68 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "primitiveTypes.h" - -#ifndef softfloat_mul64To128M - -void softfloat_mul64To128M( uint64_t a, uint64_t b, uint32_t *zPtr ) -{ - uint32_t a32, a0, b32, b0; - uint64_t z0, mid1, z64, mid; - - a32 = a>>32; - a0 = a; - b32 = b>>32; - b0 = b; - z0 = (uint64_t) a0 * b0; - mid1 = (uint64_t) a32 * b0; - mid = mid1 + (uint64_t) a0 * b32; - z64 = (uint64_t) a32 * b32; - z64 += (uint64_t) (mid < mid1)<<32 | mid>>32; - mid <<= 32; - z0 += mid; - zPtr[indexWord( 4, 1 )] = z0>>32; - zPtr[indexWord( 4, 0 )] = z0; - z64 += (z0 < mid); - zPtr[indexWord( 4, 3 )] = z64>>32; - zPtr[indexWord( 4, 2 )] = z64; - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/s_mulAddF128.c b/deps/SoftFloat-3e/source/s_mulAddF128.c deleted file mode 100644 index f6b2b45df0ca..000000000000 --- a/deps/SoftFloat-3e/source/s_mulAddF128.c +++ /dev/null @@ -1,350 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -float128_t - softfloat_mulAddF128( - uint_fast64_t uiA64, - uint_fast64_t uiA0, - uint_fast64_t uiB64, - uint_fast64_t uiB0, - uint_fast64_t uiC64, - uint_fast64_t uiC0, - uint_fast8_t op - ) -{ - bool signA; - int_fast32_t expA; - struct uint128 sigA; - bool signB; - int_fast32_t expB; - struct uint128 sigB; - bool signC; - int_fast32_t expC; - struct uint128 sigC; - bool signZ; - uint_fast64_t magBits; - struct uint128 uiZ; - struct exp32_sig128 normExpSig; - int_fast32_t expZ; - uint64_t sig256Z[4]; - struct uint128 sigZ; - int_fast32_t shiftDist, expDiff; - struct uint128 x128; - uint64_t sig256C[4]; - static uint64_t zero256[4] = INIT_UINTM4( 0, 0, 0, 0 ); - uint_fast64_t sigZExtra, sig256Z0; - union ui128_f128 uZ; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - signA = signF128UI64( uiA64 ); - expA = expF128UI64( uiA64 ); - sigA.v64 = fracF128UI64( uiA64 ); - sigA.v0 = uiA0; - signB = signF128UI64( uiB64 ); - expB = expF128UI64( uiB64 ); - sigB.v64 = fracF128UI64( uiB64 ); - sigB.v0 = uiB0; - signC = signF128UI64( uiC64 ) ^ (op == softfloat_mulAdd_subC); - expC = expF128UI64( uiC64 ); - sigC.v64 = fracF128UI64( uiC64 ); - sigC.v0 = uiC0; - signZ = signA ^ signB ^ (op == softfloat_mulAdd_subProd); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( expA == 0x7FFF ) { - if ( - (sigA.v64 | sigA.v0) || ((expB == 0x7FFF) && (sigB.v64 | sigB.v0)) - ) { - goto propagateNaN_ABC; - } - magBits = expB | sigB.v64 | sigB.v0; - goto infProdArg; - } - if ( expB == 0x7FFF ) { - if ( sigB.v64 | sigB.v0 ) goto propagateNaN_ABC; - magBits = expA | sigA.v64 | sigA.v0; - goto infProdArg; - } - if ( expC == 0x7FFF ) { - if ( sigC.v64 | sigC.v0 ) { - uiZ.v64 = 0; - uiZ.v0 = 0; - goto propagateNaN_ZC; - } - uiZ.v64 = uiC64; - uiZ.v0 = uiC0; - goto uiZ; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( ! expA ) { - if ( ! (sigA.v64 | sigA.v0) ) goto zeroProd; - normExpSig = softfloat_normSubnormalF128Sig( sigA.v64, sigA.v0 ); - expA = normExpSig.exp; - sigA = normExpSig.sig; - } - if ( ! expB ) { - if ( ! (sigB.v64 | sigB.v0) ) goto zeroProd; - normExpSig = softfloat_normSubnormalF128Sig( sigB.v64, sigB.v0 ); - expB = normExpSig.exp; - sigB = normExpSig.sig; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - expZ = expA + expB - 0x3FFE; - sigA.v64 |= UINT64_C( 0x0001000000000000 ); - sigB.v64 |= UINT64_C( 0x0001000000000000 ); - sigA = softfloat_shortShiftLeft128( sigA.v64, sigA.v0, 8 ); - sigB = softfloat_shortShiftLeft128( sigB.v64, sigB.v0, 15 ); - softfloat_mul128To256M( sigA.v64, sigA.v0, sigB.v64, sigB.v0, sig256Z ); - sigZ.v64 = sig256Z[indexWord( 4, 3 )]; - sigZ.v0 = sig256Z[indexWord( 4, 2 )]; - shiftDist = 0; - if ( ! (sigZ.v64 & UINT64_C( 0x0100000000000000 )) ) { - --expZ; - shiftDist = -1; - } - if ( ! expC ) { - if ( ! (sigC.v64 | sigC.v0) ) { - shiftDist += 8; - goto sigZ; - } - normExpSig = softfloat_normSubnormalF128Sig( sigC.v64, sigC.v0 ); - expC = normExpSig.exp; - sigC = normExpSig.sig; - } - sigC.v64 |= UINT64_C( 0x0001000000000000 ); - sigC = softfloat_shortShiftLeft128( sigC.v64, sigC.v0, 8 ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - expDiff = expZ - expC; - if ( expDiff < 0 ) { - expZ = expC; - if ( (signZ == signC) || (expDiff < -1) ) { - shiftDist -= expDiff; - if ( shiftDist ) { - sigZ = - softfloat_shiftRightJam128( sigZ.v64, sigZ.v0, shiftDist ); - } - } else { - if ( ! shiftDist ) { - x128 = - softfloat_shortShiftRight128( - sig256Z[indexWord( 4, 1 )], sig256Z[indexWord( 4, 0 )], - 1 - ); - sig256Z[indexWord( 4, 1 )] = (sigZ.v0<<63) | x128.v64; - sig256Z[indexWord( 4, 0 )] = x128.v0; - sigZ = softfloat_shortShiftRight128( sigZ.v64, sigZ.v0, 1 ); - sig256Z[indexWord( 4, 3 )] = sigZ.v64; - sig256Z[indexWord( 4, 2 )] = sigZ.v0; - } - } - } else { - if ( shiftDist ) softfloat_add256M( sig256Z, sig256Z, sig256Z ); - if ( ! expDiff ) { - sigZ.v64 = sig256Z[indexWord( 4, 3 )]; - sigZ.v0 = sig256Z[indexWord( 4, 2 )]; - } else { - sig256C[indexWord( 4, 3 )] = sigC.v64; - sig256C[indexWord( 4, 2 )] = sigC.v0; - sig256C[indexWord( 4, 1 )] = 0; - sig256C[indexWord( 4, 0 )] = 0; - softfloat_shiftRightJam256M( sig256C, expDiff, sig256C ); - } - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - shiftDist = 8; - if ( signZ == signC ) { - /*-------------------------------------------------------------------- - *--------------------------------------------------------------------*/ - if ( expDiff <= 0 ) { - sigZ = softfloat_add128( sigC.v64, sigC.v0, sigZ.v64, sigZ.v0 ); - } else { - softfloat_add256M( sig256Z, sig256C, sig256Z ); - sigZ.v64 = sig256Z[indexWord( 4, 3 )]; - sigZ.v0 = sig256Z[indexWord( 4, 2 )]; - } - if ( sigZ.v64 & UINT64_C( 0x0200000000000000 ) ) { - ++expZ; - shiftDist = 9; - } - } else { - /*-------------------------------------------------------------------- - *--------------------------------------------------------------------*/ - if ( expDiff < 0 ) { - signZ = signC; - if ( expDiff < -1 ) { - sigZ = - softfloat_sub128( sigC.v64, sigC.v0, sigZ.v64, sigZ.v0 ); - sigZExtra = - sig256Z[indexWord( 4, 1 )] | sig256Z[indexWord( 4, 0 )]; - if ( sigZExtra ) { - sigZ = softfloat_sub128( sigZ.v64, sigZ.v0, 0, 1 ); - } - if ( ! (sigZ.v64 & UINT64_C( 0x0100000000000000 )) ) { - --expZ; - shiftDist = 7; - } - goto shiftRightRoundPack; - } else { - sig256C[indexWord( 4, 3 )] = sigC.v64; - sig256C[indexWord( 4, 2 )] = sigC.v0; - sig256C[indexWord( 4, 1 )] = 0; - sig256C[indexWord( 4, 0 )] = 0; - softfloat_sub256M( sig256C, sig256Z, sig256Z ); - } - } else if ( ! expDiff ) { - sigZ = softfloat_sub128( sigZ.v64, sigZ.v0, sigC.v64, sigC.v0 ); - if ( - ! (sigZ.v64 | sigZ.v0) && ! sig256Z[indexWord( 4, 1 )] - && ! sig256Z[indexWord( 4, 0 )] - ) { - goto completeCancellation; - } - sig256Z[indexWord( 4, 3 )] = sigZ.v64; - sig256Z[indexWord( 4, 2 )] = sigZ.v0; - if ( sigZ.v64 & UINT64_C( 0x8000000000000000 ) ) { - signZ = ! signZ; - softfloat_sub256M( zero256, sig256Z, sig256Z ); - } - } else { - softfloat_sub256M( sig256Z, sig256C, sig256Z ); - if ( 1 < expDiff ) { - sigZ.v64 = sig256Z[indexWord( 4, 3 )]; - sigZ.v0 = sig256Z[indexWord( 4, 2 )]; - if ( ! (sigZ.v64 & UINT64_C( 0x0100000000000000 )) ) { - --expZ; - shiftDist = 7; - } - goto sigZ; - } - } - /*-------------------------------------------------------------------- - *--------------------------------------------------------------------*/ - sigZ.v64 = sig256Z[indexWord( 4, 3 )]; - sigZ.v0 = sig256Z[indexWord( 4, 2 )]; - sigZExtra = sig256Z[indexWord( 4, 1 )]; - sig256Z0 = sig256Z[indexWord( 4, 0 )]; - if ( sigZ.v64 ) { - if ( sig256Z0 ) sigZExtra |= 1; - } else { - expZ -= 64; - sigZ.v64 = sigZ.v0; - sigZ.v0 = sigZExtra; - sigZExtra = sig256Z0; - if ( ! sigZ.v64 ) { - expZ -= 64; - sigZ.v64 = sigZ.v0; - sigZ.v0 = sigZExtra; - sigZExtra = 0; - if ( ! sigZ.v64 ) { - expZ -= 64; - sigZ.v64 = sigZ.v0; - sigZ.v0 = 0; - } - } - } - shiftDist = softfloat_countLeadingZeros64( sigZ.v64 ); - expZ += 7 - shiftDist; - shiftDist = 15 - shiftDist; - if ( 0 < shiftDist ) goto shiftRightRoundPack; - if ( shiftDist ) { - shiftDist = -shiftDist; - sigZ = softfloat_shortShiftLeft128( sigZ.v64, sigZ.v0, shiftDist ); - x128 = softfloat_shortShiftLeft128( 0, sigZExtra, shiftDist ); - sigZ.v0 |= x128.v64; - sigZExtra = x128.v0; - } - goto roundPack; - } - sigZ: - sigZExtra = sig256Z[indexWord( 4, 1 )] | sig256Z[indexWord( 4, 0 )]; - shiftRightRoundPack: - sigZExtra = (uint64_t) (sigZ.v0<<(64 - shiftDist)) | (sigZExtra != 0); - sigZ = softfloat_shortShiftRight128( sigZ.v64, sigZ.v0, shiftDist ); - roundPack: - return - softfloat_roundPackToF128( - signZ, expZ - 1, sigZ.v64, sigZ.v0, sigZExtra ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - propagateNaN_ABC: - uiZ = softfloat_propagateNaNF128UI( uiA64, uiA0, uiB64, uiB0 ); - goto propagateNaN_ZC; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - infProdArg: - if ( magBits ) { - uiZ.v64 = packToF128UI64( signZ, 0x7FFF, 0 ); - uiZ.v0 = 0; - if ( expC != 0x7FFF ) goto uiZ; - if ( sigC.v64 | sigC.v0 ) goto propagateNaN_ZC; - if ( signZ == signC ) goto uiZ; - } - softfloat_raiseFlags( softfloat_flag_invalid ); - uiZ.v64 = defaultNaNF128UI64; - uiZ.v0 = defaultNaNF128UI0; - propagateNaN_ZC: - uiZ = softfloat_propagateNaNF128UI( uiZ.v64, uiZ.v0, uiC64, uiC0 ); - goto uiZ; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - zeroProd: - uiZ.v64 = uiC64; - uiZ.v0 = uiC0; - if ( ! (expC | sigC.v64 | sigC.v0) && (signZ != signC) ) { - completeCancellation: - uiZ.v64 = - packToF128UI64( - (softfloat_roundingMode == softfloat_round_min), 0, 0 ); - uiZ.v0 = 0; - } - uiZ: - uZ.ui = uiZ; - return uZ.f; - -} - diff --git a/deps/SoftFloat-3e/source/s_mulAddF128M.c b/deps/SoftFloat-3e/source/s_mulAddF128M.c deleted file mode 100644 index f51fc71d28e3..000000000000 --- a/deps/SoftFloat-3e/source/s_mulAddF128M.c +++ /dev/null @@ -1,382 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -void - softfloat_mulAddF128M( - const uint32_t *aWPtr, - const uint32_t *bWPtr, - const uint32_t *cWPtr, - uint32_t *zWPtr, - uint_fast8_t op - ) -{ - uint32_t uiA96; - int32_t expA; - uint32_t uiB96; - int32_t expB; - uint32_t uiC96; - bool signC; - int32_t expC; - bool signProd, prodIsInfinite; - uint32_t *ptr, uiZ96, sigA[4]; - uint_fast8_t shiftDist; - uint32_t sigX[5]; - int32_t expProd; - uint32_t sigProd[8], wordSig; - bool doSub; - uint_fast8_t - (*addCarryMRoutinePtr)( - uint_fast8_t, - const uint32_t *, - const uint32_t *, - uint_fast8_t, - uint32_t * - ); - int32_t expDiff; - bool signZ; - int32_t expZ; - uint32_t *extSigPtr; - uint_fast8_t carry; - void (*roundPackRoutinePtr)( bool, int32_t, uint32_t *, uint32_t * ); - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uiA96 = aWPtr[indexWordHi( 4 )]; - expA = expF128UI96( uiA96 ); - uiB96 = bWPtr[indexWordHi( 4 )]; - expB = expF128UI96( uiB96 ); - uiC96 = cWPtr[indexWordHi( 4 )]; - signC = signF128UI96( uiC96 ) ^ (op == softfloat_mulAdd_subC); - expC = expF128UI96( uiC96 ); - signProd = - signF128UI96( uiA96 ) ^ signF128UI96( uiB96 ) - ^ (op == softfloat_mulAdd_subProd); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - prodIsInfinite = false; - if ( (expA == 0x7FFF) || (expB == 0x7FFF) ) { - if ( softfloat_tryPropagateNaNF128M( aWPtr, bWPtr, zWPtr ) ) { - goto propagateNaN_ZC; - } - ptr = (uint32_t *) aWPtr; - if ( ! (uint32_t) (uiA96<<1) ) goto possibleInvalidProd; - if ( ! (uint32_t) (uiB96<<1) ) { - ptr = (uint32_t *) bWPtr; - possibleInvalidProd: - if ( - ! (ptr[indexWord( 4, 2 )] | ptr[indexWord( 4, 1 )] - | ptr[indexWord( 4, 0 )]) - ) { - goto invalid; - } - } - prodIsInfinite = true; - } - if ( expC == 0x7FFF ) { - if ( - fracF128UI96( uiC96 ) - || (cWPtr[indexWord( 4, 2 )] | cWPtr[indexWord( 4, 1 )] - | cWPtr[indexWord( 4, 0 )]) - ) { - zWPtr[indexWordHi( 4 )] = 0; - goto propagateNaN_ZC; - } - if ( prodIsInfinite && (signProd != signC) ) goto invalid; - goto copyC; - } - if ( prodIsInfinite ) { - uiZ96 = packToF128UI96( signProd, 0x7FFF, 0 ); - goto uiZ; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( expA ) { - sigA[indexWordHi( 4 )] = fracF128UI96( uiA96 ) | 0x00010000; - sigA[indexWord( 4, 2 )] = aWPtr[indexWord( 4, 2 )]; - sigA[indexWord( 4, 1 )] = aWPtr[indexWord( 4, 1 )]; - sigA[indexWord( 4, 0 )] = aWPtr[indexWord( 4, 0 )]; - } else { - expA = softfloat_shiftNormSigF128M( aWPtr, 0, sigA ); - if ( expA == -128 ) goto zeroProd; - } - if ( expB ) { - sigX[indexWordHi( 4 )] = fracF128UI96( uiB96 ) | 0x00010000; - sigX[indexWord( 4, 2 )] = bWPtr[indexWord( 4, 2 )]; - sigX[indexWord( 4, 1 )] = bWPtr[indexWord( 4, 1 )]; - sigX[indexWord( 4, 0 )] = bWPtr[indexWord( 4, 0 )]; - } else { - expB = softfloat_shiftNormSigF128M( bWPtr, 0, sigX ); - if ( expB == -128 ) goto zeroProd; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - expProd = expA + expB - 0x3FF0; - softfloat_mul128MTo256M( sigA, sigX, sigProd ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - wordSig = fracF128UI96( uiC96 ); - if ( expC ) { - --expC; - wordSig |= 0x00010000; - } - sigX[indexWordHi( 5 )] = wordSig; - sigX[indexWord( 5, 3 )] = cWPtr[indexWord( 4, 2 )]; - sigX[indexWord( 5, 2 )] = cWPtr[indexWord( 4, 1 )]; - sigX[indexWord( 5, 1 )] = cWPtr[indexWord( 4, 0 )]; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - doSub = (signProd != signC); - addCarryMRoutinePtr = - doSub ? softfloat_addComplCarryM : softfloat_addCarryM; - expDiff = expProd - expC; - if ( expDiff <= 0 ) { - /*-------------------------------------------------------------------- - *--------------------------------------------------------------------*/ - signZ = signC; - expZ = expC; - if ( - sigProd[indexWord( 8, 2 )] - || (sigProd[indexWord( 8, 1 )] | sigProd[indexWord( 8, 0 )]) - ) { - sigProd[indexWord( 8, 3 )] |= 1; - } - extSigPtr = &sigProd[indexMultiwordHi( 8, 5 )]; - if ( expDiff ) { - softfloat_shiftRightJam160M( extSigPtr, -expDiff, extSigPtr ); - } - carry = 0; - if ( doSub ) { - wordSig = extSigPtr[indexWordLo( 5 )]; - extSigPtr[indexWordLo( 5 )] = -wordSig; - carry = ! wordSig; - } - (*addCarryMRoutinePtr)( - 4, - &sigX[indexMultiwordHi( 5, 4 )], - extSigPtr + indexMultiwordHi( 5, 4 ), - carry, - extSigPtr + indexMultiwordHi( 5, 4 ) - ); - wordSig = extSigPtr[indexWordHi( 5 )]; - if ( ! expZ ) { - if ( wordSig & 0x80000000 ) { - signZ = ! signZ; - softfloat_negX160M( extSigPtr ); - wordSig = extSigPtr[indexWordHi( 5 )]; - } - goto checkCancellation; - } - if ( wordSig < 0x00010000 ) { - --expZ; - softfloat_add160M( extSigPtr, extSigPtr, extSigPtr ); - goto roundPack; - } - goto extSigReady_noCancellation; - } else { - /*-------------------------------------------------------------------- - *--------------------------------------------------------------------*/ - signZ = signProd; - expZ = expProd; - sigX[indexWordLo( 5 )] = 0; - expDiff -= 128; - if ( 0 <= expDiff ) { - /*---------------------------------------------------------------- - *----------------------------------------------------------------*/ - if ( expDiff ) softfloat_shiftRightJam160M( sigX, expDiff, sigX ); - wordSig = sigX[indexWordLo( 5 )]; - carry = 0; - if ( doSub ) { - carry = ! wordSig; - wordSig = -wordSig; - } - carry = - (*addCarryMRoutinePtr)( - 4, - &sigProd[indexMultiwordLo( 8, 4 )], - &sigX[indexMultiwordHi( 5, 4 )], - carry, - &sigProd[indexMultiwordLo( 8, 4 )] - ); - sigProd[indexWord( 8, 2 )] |= wordSig; - ptr = &sigProd[indexWord( 8, 4 )]; - } else { - /*---------------------------------------------------------------- - *----------------------------------------------------------------*/ - shiftDist = expDiff & 31; - if ( shiftDist ) { - softfloat_shortShiftRight160M( sigX, shiftDist, sigX ); - } - expDiff >>= 5; - extSigPtr = - &sigProd[indexMultiwordLo( 8, 5 )] - wordIncr - + expDiff * -wordIncr; - carry = - (*addCarryMRoutinePtr)( 5, extSigPtr, sigX, doSub, extSigPtr ); - if ( expDiff == -4 ) { - /*------------------------------------------------------------ - *------------------------------------------------------------*/ - wordSig = sigProd[indexWordHi( 8 )]; - if ( wordSig & 0x80000000 ) { - signZ = ! signZ; - softfloat_negX256M( sigProd ); - wordSig = sigProd[indexWordHi( 8 )]; - } - /*------------------------------------------------------------ - *------------------------------------------------------------*/ - if ( wordSig ) goto expProdBigger_noWordShift; - wordSig = sigProd[indexWord( 8, 6 )]; - if ( 0x00040000 <= wordSig ) goto expProdBigger_noWordShift; - expZ -= 32; - extSigPtr = &sigProd[indexMultiwordHi( 8, 5 )] - wordIncr; - for (;;) { - if ( wordSig ) break; - wordSig = extSigPtr[indexWord( 5, 3 )]; - if ( 0x00040000 <= wordSig ) break; - expZ -= 32; - extSigPtr -= wordIncr; - if ( extSigPtr == &sigProd[indexMultiwordLo( 8, 5 )] ) { - goto checkCancellation; - } - } - /*------------------------------------------------------------ - *------------------------------------------------------------*/ - ptr = extSigPtr + indexWordLo( 5 ); - do { - ptr -= wordIncr; - if ( *ptr ) { - extSigPtr[indexWordLo( 5 )] |= 1; - break; - } - } while ( ptr != &sigProd[indexWordLo( 8 )] ); - wordSig = extSigPtr[indexWordHi( 5 )]; - goto extSigReady; - } - ptr = extSigPtr + indexWordHi( 5 ) + wordIncr; - } - /*-------------------------------------------------------------------- - *--------------------------------------------------------------------*/ - if ( carry != doSub ) { - if ( doSub ) { - do { - wordSig = *ptr; - *ptr = wordSig - 1; - ptr += wordIncr; - } while ( ! wordSig ); - } else { - do { - wordSig = *ptr + 1; - *ptr = wordSig; - ptr += wordIncr; - } while ( ! wordSig ); - } - } - /*-------------------------------------------------------------------- - *--------------------------------------------------------------------*/ - expProdBigger_noWordShift: - if ( - sigProd[indexWord( 8, 2 )] - || (sigProd[indexWord( 8, 1 )] | sigProd[indexWord( 8, 0 )]) - ) { - sigProd[indexWord( 8, 3 )] |= 1; - } - extSigPtr = &sigProd[indexMultiwordHi( 8, 5 )]; - wordSig = extSigPtr[indexWordHi( 5 )]; - } - extSigReady: - roundPackRoutinePtr = softfloat_normRoundPackMToF128M; - if ( wordSig < 0x00010000 ) goto doRoundPack; - extSigReady_noCancellation: - if ( 0x00020000 <= wordSig ) { - ++expZ; - softfloat_shortShiftRightJam160M( extSigPtr, 1, extSigPtr ); - } - roundPack: - roundPackRoutinePtr = softfloat_roundPackMToF128M; - doRoundPack: - (*roundPackRoutinePtr)( signZ, expZ, extSigPtr, zWPtr ); - return; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - invalid: - softfloat_invalidF128M( zWPtr ); - propagateNaN_ZC: - softfloat_propagateNaNF128M( zWPtr, cWPtr, zWPtr ); - return; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - zeroProd: - if ( - ! (uint32_t) (uiC96<<1) && (signProd != signC) - && ! cWPtr[indexWord( 4, 2 )] - && ! (cWPtr[indexWord( 4, 1 )] | cWPtr[indexWord( 4, 0 )]) - ) { - goto completeCancellation; - } - copyC: - zWPtr[indexWordHi( 4 )] = uiC96; - zWPtr[indexWord( 4, 2 )] = cWPtr[indexWord( 4, 2 )]; - zWPtr[indexWord( 4, 1 )] = cWPtr[indexWord( 4, 1 )]; - zWPtr[indexWord( 4, 0 )] = cWPtr[indexWord( 4, 0 )]; - return; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - checkCancellation: - if ( - wordSig - || (extSigPtr[indexWord( 5, 3 )] | extSigPtr[indexWord( 5, 2 )]) - || (extSigPtr[indexWord( 5, 1 )] | extSigPtr[indexWord( 5, 0 )]) - ) { - goto extSigReady; - } - completeCancellation: - uiZ96 = - packToF128UI96( - (softfloat_roundingMode == softfloat_round_min), 0, 0 ); - uiZ: - zWPtr[indexWordHi( 4 )] = uiZ96; - zWPtr[indexWord( 4, 2 )] = 0; - zWPtr[indexWord( 4, 1 )] = 0; - zWPtr[indexWord( 4, 0 )] = 0; - -} - diff --git a/deps/SoftFloat-3e/source/s_mulAddF16.c b/deps/SoftFloat-3e/source/s_mulAddF16.c deleted file mode 100644 index 3a684ac32c6d..000000000000 --- a/deps/SoftFloat-3e/source/s_mulAddF16.c +++ /dev/null @@ -1,226 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -float16_t - softfloat_mulAddF16( - uint_fast16_t uiA, uint_fast16_t uiB, uint_fast16_t uiC, uint_fast8_t op ) -{ - bool signA; - int_fast8_t expA; - uint_fast16_t sigA; - bool signB; - int_fast8_t expB; - uint_fast16_t sigB; - bool signC; - int_fast8_t expC; - uint_fast16_t sigC; - bool signProd; - uint_fast16_t magBits, uiZ; - struct exp8_sig16 normExpSig; - int_fast8_t expProd; - uint_fast32_t sigProd; - bool signZ; - int_fast8_t expZ; - uint_fast16_t sigZ; - int_fast8_t expDiff; - uint_fast32_t sig32Z, sig32C; - int_fast8_t shiftDist; - union ui16_f16 uZ; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - signA = signF16UI( uiA ); - expA = expF16UI( uiA ); - sigA = fracF16UI( uiA ); - signB = signF16UI( uiB ); - expB = expF16UI( uiB ); - sigB = fracF16UI( uiB ); - signC = signF16UI( uiC ) ^ (op == softfloat_mulAdd_subC); - expC = expF16UI( uiC ); - sigC = fracF16UI( uiC ); - signProd = signA ^ signB ^ (op == softfloat_mulAdd_subProd); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( expA == 0x1F ) { - if ( sigA || ((expB == 0x1F) && sigB) ) goto propagateNaN_ABC; - magBits = expB | sigB; - goto infProdArg; - } - if ( expB == 0x1F ) { - if ( sigB ) goto propagateNaN_ABC; - magBits = expA | sigA; - goto infProdArg; - } - if ( expC == 0x1F ) { - if ( sigC ) { - uiZ = 0; - goto propagateNaN_ZC; - } - uiZ = uiC; - goto uiZ; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( ! expA ) { - if ( ! sigA ) goto zeroProd; - normExpSig = softfloat_normSubnormalF16Sig( sigA ); - expA = normExpSig.exp; - sigA = normExpSig.sig; - } - if ( ! expB ) { - if ( ! sigB ) goto zeroProd; - normExpSig = softfloat_normSubnormalF16Sig( sigB ); - expB = normExpSig.exp; - sigB = normExpSig.sig; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - expProd = expA + expB - 0xE; - sigA = (sigA | 0x0400)<<4; - sigB = (sigB | 0x0400)<<4; - sigProd = (uint_fast32_t) sigA * sigB; - if ( sigProd < 0x20000000 ) { - --expProd; - sigProd <<= 1; - } - signZ = signProd; - if ( ! expC ) { - if ( ! sigC ) { - expZ = expProd - 1; - sigZ = sigProd>>15 | ((sigProd & 0x7FFF) != 0); - goto roundPack; - } - normExpSig = softfloat_normSubnormalF16Sig( sigC ); - expC = normExpSig.exp; - sigC = normExpSig.sig; - } - sigC = (sigC | 0x0400)<<3; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - expDiff = expProd - expC; - if ( signProd == signC ) { - /*-------------------------------------------------------------------- - *--------------------------------------------------------------------*/ - if ( expDiff <= 0 ) { - expZ = expC; - sigZ = sigC + softfloat_shiftRightJam32( sigProd, 16 - expDiff ); - } else { - expZ = expProd; - sig32Z = - sigProd - + softfloat_shiftRightJam32( - (uint_fast32_t) sigC<<16, expDiff ); - sigZ = sig32Z>>16 | ((sig32Z & 0xFFFF) != 0 ); - } - if ( sigZ < 0x4000 ) { - --expZ; - sigZ <<= 1; - } - } else { - /*-------------------------------------------------------------------- - *--------------------------------------------------------------------*/ - sig32C = (uint_fast32_t) sigC<<16; - if ( expDiff < 0 ) { - signZ = signC; - expZ = expC; - sig32Z = sig32C - softfloat_shiftRightJam32( sigProd, -expDiff ); - } else if ( ! expDiff ) { - expZ = expProd; - sig32Z = sigProd - sig32C; - if ( ! sig32Z ) goto completeCancellation; - if ( sig32Z & 0x80000000 ) { - signZ = ! signZ; - sig32Z = -sig32Z; - } - } else { - expZ = expProd; - sig32Z = sigProd - softfloat_shiftRightJam32( sig32C, expDiff ); - } - shiftDist = softfloat_countLeadingZeros32( sig32Z ) - 1; - expZ -= shiftDist; - shiftDist -= 16; - if ( shiftDist < 0 ) { - sigZ = - sig32Z>>(-shiftDist) - | ((uint32_t) (sig32Z<<(shiftDist & 31)) != 0); - } else { - sigZ = (uint_fast16_t) sig32Z< -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -float32_t - softfloat_mulAddF32( - uint_fast32_t uiA, uint_fast32_t uiB, uint_fast32_t uiC, uint_fast8_t op ) -{ - bool signA; - int_fast16_t expA; - uint_fast32_t sigA; - bool signB; - int_fast16_t expB; - uint_fast32_t sigB; - bool signC; - int_fast16_t expC; - uint_fast32_t sigC; - bool signProd; - uint_fast32_t magBits, uiZ; - struct exp16_sig32 normExpSig; - int_fast16_t expProd; - uint_fast64_t sigProd; - bool signZ; - int_fast16_t expZ; - uint_fast32_t sigZ; - int_fast16_t expDiff; - uint_fast64_t sig64Z, sig64C; - int_fast8_t shiftDist; - union ui32_f32 uZ; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - signA = signF32UI( uiA ); - expA = expF32UI( uiA ); - sigA = fracF32UI( uiA ); - signB = signF32UI( uiB ); - expB = expF32UI( uiB ); - sigB = fracF32UI( uiB ); - signC = signF32UI( uiC ) ^ (op == softfloat_mulAdd_subC); - expC = expF32UI( uiC ); - sigC = fracF32UI( uiC ); - signProd = signA ^ signB ^ (op == softfloat_mulAdd_subProd); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( expA == 0xFF ) { - if ( sigA || ((expB == 0xFF) && sigB) ) goto propagateNaN_ABC; - magBits = expB | sigB; - goto infProdArg; - } - if ( expB == 0xFF ) { - if ( sigB ) goto propagateNaN_ABC; - magBits = expA | sigA; - goto infProdArg; - } - if ( expC == 0xFF ) { - if ( sigC ) { - uiZ = 0; - goto propagateNaN_ZC; - } - uiZ = uiC; - goto uiZ; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( ! expA ) { - if ( ! sigA ) goto zeroProd; - normExpSig = softfloat_normSubnormalF32Sig( sigA ); - expA = normExpSig.exp; - sigA = normExpSig.sig; - } - if ( ! expB ) { - if ( ! sigB ) goto zeroProd; - normExpSig = softfloat_normSubnormalF32Sig( sigB ); - expB = normExpSig.exp; - sigB = normExpSig.sig; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - expProd = expA + expB - 0x7E; - sigA = (sigA | 0x00800000)<<7; - sigB = (sigB | 0x00800000)<<7; - sigProd = (uint_fast64_t) sigA * sigB; - if ( sigProd < UINT64_C( 0x2000000000000000 ) ) { - --expProd; - sigProd <<= 1; - } - signZ = signProd; - if ( ! expC ) { - if ( ! sigC ) { - expZ = expProd - 1; - sigZ = softfloat_shortShiftRightJam64( sigProd, 31 ); - goto roundPack; - } - normExpSig = softfloat_normSubnormalF32Sig( sigC ); - expC = normExpSig.exp; - sigC = normExpSig.sig; - } - sigC = (sigC | 0x00800000)<<6; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - expDiff = expProd - expC; - if ( signProd == signC ) { - /*-------------------------------------------------------------------- - *--------------------------------------------------------------------*/ - if ( expDiff <= 0 ) { - expZ = expC; - sigZ = sigC + softfloat_shiftRightJam64( sigProd, 32 - expDiff ); - } else { - expZ = expProd; - sig64Z = - sigProd - + softfloat_shiftRightJam64( - (uint_fast64_t) sigC<<32, expDiff ); - sigZ = softfloat_shortShiftRightJam64( sig64Z, 32 ); - } - if ( sigZ < 0x40000000 ) { - --expZ; - sigZ <<= 1; - } - } else { - /*-------------------------------------------------------------------- - *--------------------------------------------------------------------*/ - sig64C = (uint_fast64_t) sigC<<32; - if ( expDiff < 0 ) { - signZ = signC; - expZ = expC; - sig64Z = sig64C - softfloat_shiftRightJam64( sigProd, -expDiff ); - } else if ( ! expDiff ) { - expZ = expProd; - sig64Z = sigProd - sig64C; - if ( ! sig64Z ) goto completeCancellation; - if ( sig64Z & UINT64_C( 0x8000000000000000 ) ) { - signZ = ! signZ; - sig64Z = -sig64Z; - } - } else { - expZ = expProd; - sig64Z = sigProd - softfloat_shiftRightJam64( sig64C, expDiff ); - } - shiftDist = softfloat_countLeadingZeros64( sig64Z ) - 1; - expZ -= shiftDist; - shiftDist -= 32; - if ( shiftDist < 0 ) { - sigZ = softfloat_shortShiftRightJam64( sig64Z, -shiftDist ); - } else { - sigZ = (uint_fast32_t) sig64Z< -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -#ifdef SOFTFLOAT_FAST_INT64 - -float64_t - softfloat_mulAddF64( - uint_fast64_t uiA, uint_fast64_t uiB, uint_fast64_t uiC, uint_fast8_t op ) -{ - bool signA; - int_fast16_t expA; - uint_fast64_t sigA; - bool signB; - int_fast16_t expB; - uint_fast64_t sigB; - bool signC; - int_fast16_t expC; - uint_fast64_t sigC; - bool signZ; - uint_fast64_t magBits, uiZ; - struct exp16_sig64 normExpSig; - int_fast16_t expZ; - struct uint128 sig128Z; - uint_fast64_t sigZ; - int_fast16_t expDiff; - struct uint128 sig128C; - int_fast8_t shiftDist; - union ui64_f64 uZ; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - signA = signF64UI( uiA ); - expA = expF64UI( uiA ); - sigA = fracF64UI( uiA ); - signB = signF64UI( uiB ); - expB = expF64UI( uiB ); - sigB = fracF64UI( uiB ); - signC = signF64UI( uiC ) ^ (op == softfloat_mulAdd_subC); - expC = expF64UI( uiC ); - sigC = fracF64UI( uiC ); - signZ = signA ^ signB ^ (op == softfloat_mulAdd_subProd); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( expA == 0x7FF ) { - if ( sigA || ((expB == 0x7FF) && sigB) ) goto propagateNaN_ABC; - magBits = expB | sigB; - goto infProdArg; - } - if ( expB == 0x7FF ) { - if ( sigB ) goto propagateNaN_ABC; - magBits = expA | sigA; - goto infProdArg; - } - if ( expC == 0x7FF ) { - if ( sigC ) { - uiZ = 0; - goto propagateNaN_ZC; - } - uiZ = uiC; - goto uiZ; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( ! expA ) { - if ( ! sigA ) goto zeroProd; - normExpSig = softfloat_normSubnormalF64Sig( sigA ); - expA = normExpSig.exp; - sigA = normExpSig.sig; - } - if ( ! expB ) { - if ( ! sigB ) goto zeroProd; - normExpSig = softfloat_normSubnormalF64Sig( sigB ); - expB = normExpSig.exp; - sigB = normExpSig.sig; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - expZ = expA + expB - 0x3FE; - sigA = (sigA | UINT64_C( 0x0010000000000000 ))<<10; - sigB = (sigB | UINT64_C( 0x0010000000000000 ))<<10; - sig128Z = softfloat_mul64To128( sigA, sigB ); - if ( sig128Z.v64 < UINT64_C( 0x2000000000000000 ) ) { - --expZ; - sig128Z = - softfloat_add128( - sig128Z.v64, sig128Z.v0, sig128Z.v64, sig128Z.v0 ); - } - if ( ! expC ) { - if ( ! sigC ) { - --expZ; - sigZ = sig128Z.v64<<1 | (sig128Z.v0 != 0); - goto roundPack; - } - normExpSig = softfloat_normSubnormalF64Sig( sigC ); - expC = normExpSig.exp; - sigC = normExpSig.sig; - } - sigC = (sigC | UINT64_C( 0x0010000000000000 ))<<9; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - expDiff = expZ - expC; - if ( expDiff < 0 ) { - expZ = expC; - if ( (signZ == signC) || (expDiff < -1) ) { - sig128Z.v64 = softfloat_shiftRightJam64( sig128Z.v64, -expDiff ); - } else { - sig128Z = - softfloat_shortShiftRightJam128( sig128Z.v64, sig128Z.v0, 1 ); - } - } else if ( expDiff ) { - sig128C = softfloat_shiftRightJam128( sigC, 0, expDiff ); - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( signZ == signC ) { - /*-------------------------------------------------------------------- - *--------------------------------------------------------------------*/ - if ( expDiff <= 0 ) { - sigZ = (sigC + sig128Z.v64) | (sig128Z.v0 != 0); - } else { - sig128Z = - softfloat_add128( - sig128Z.v64, sig128Z.v0, sig128C.v64, sig128C.v0 ); - sigZ = sig128Z.v64 | (sig128Z.v0 != 0); - } - if ( sigZ < UINT64_C( 0x4000000000000000 ) ) { - --expZ; - sigZ <<= 1; - } - } else { - /*-------------------------------------------------------------------- - *--------------------------------------------------------------------*/ - if ( expDiff < 0 ) { - signZ = signC; - sig128Z = softfloat_sub128( sigC, 0, sig128Z.v64, sig128Z.v0 ); - } else if ( ! expDiff ) { - sig128Z.v64 = sig128Z.v64 - sigC; - if ( ! (sig128Z.v64 | sig128Z.v0) ) goto completeCancellation; - if ( sig128Z.v64 & UINT64_C( 0x8000000000000000 ) ) { - signZ = ! signZ; - sig128Z = softfloat_sub128( 0, 0, sig128Z.v64, sig128Z.v0 ); - } - } else { - sig128Z = - softfloat_sub128( - sig128Z.v64, sig128Z.v0, sig128C.v64, sig128C.v0 ); - } - /*-------------------------------------------------------------------- - *--------------------------------------------------------------------*/ - if ( ! sig128Z.v64 ) { - expZ -= 64; - sig128Z.v64 = sig128Z.v0; - sig128Z.v0 = 0; - } - shiftDist = softfloat_countLeadingZeros64( sig128Z.v64 ) - 1; - expZ -= shiftDist; - if ( shiftDist < 0 ) { - sigZ = softfloat_shortShiftRightJam64( sig128Z.v64, -shiftDist ); - } else { - sig128Z = - softfloat_shortShiftLeft128( - sig128Z.v64, sig128Z.v0, shiftDist ); - sigZ = sig128Z.v64; - } - sigZ |= (sig128Z.v0 != 0); - } - roundPack: - return softfloat_roundPackToF64( signZ, expZ, sigZ ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - propagateNaN_ABC: - uiZ = softfloat_propagateNaNF64UI( uiA, uiB ); - goto propagateNaN_ZC; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - infProdArg: - if ( magBits ) { - uiZ = packToF64UI( signZ, 0x7FF, 0 ); - if ( expC != 0x7FF ) goto uiZ; - if ( sigC ) goto propagateNaN_ZC; - if ( signZ == signC ) goto uiZ; - } - softfloat_raiseFlags( softfloat_flag_invalid ); - uiZ = defaultNaNF64UI; - propagateNaN_ZC: - uiZ = softfloat_propagateNaNF64UI( uiZ, uiC ); - goto uiZ; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - zeroProd: - uiZ = uiC; - if ( ! (expC | sigC) && (signZ != signC) ) { - completeCancellation: - uiZ = - packToF64UI( - (softfloat_roundingMode == softfloat_round_min), 0, 0 ); - } - uiZ: - uZ.ui = uiZ; - return uZ.f; - -} - -#else - -float64_t - softfloat_mulAddF64( - uint_fast64_t uiA, uint_fast64_t uiB, uint_fast64_t uiC, uint_fast8_t op ) -{ - bool signA; - int_fast16_t expA; - uint64_t sigA; - bool signB; - int_fast16_t expB; - uint64_t sigB; - bool signC; - int_fast16_t expC; - uint64_t sigC; - bool signZ; - uint64_t magBits, uiZ; - struct exp16_sig64 normExpSig; - int_fast16_t expZ; - uint32_t sig128Z[4]; - uint64_t sigZ; - int_fast16_t shiftDist, expDiff; - uint32_t sig128C[4]; - union ui64_f64 uZ; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - signA = signF64UI( uiA ); - expA = expF64UI( uiA ); - sigA = fracF64UI( uiA ); - signB = signF64UI( uiB ); - expB = expF64UI( uiB ); - sigB = fracF64UI( uiB ); - signC = signF64UI( uiC ) ^ (op == softfloat_mulAdd_subC); - expC = expF64UI( uiC ); - sigC = fracF64UI( uiC ); - signZ = signA ^ signB ^ (op == softfloat_mulAdd_subProd); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( expA == 0x7FF ) { - if ( sigA || ((expB == 0x7FF) && sigB) ) goto propagateNaN_ABC; - magBits = expB | sigB; - goto infProdArg; - } - if ( expB == 0x7FF ) { - if ( sigB ) goto propagateNaN_ABC; - magBits = expA | sigA; - goto infProdArg; - } - if ( expC == 0x7FF ) { - if ( sigC ) { - uiZ = 0; - goto propagateNaN_ZC; - } - uiZ = uiC; - goto uiZ; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( ! expA ) { - if ( ! sigA ) goto zeroProd; - normExpSig = softfloat_normSubnormalF64Sig( sigA ); - expA = normExpSig.exp; - sigA = normExpSig.sig; - } - if ( ! expB ) { - if ( ! sigB ) goto zeroProd; - normExpSig = softfloat_normSubnormalF64Sig( sigB ); - expB = normExpSig.exp; - sigB = normExpSig.sig; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - expZ = expA + expB - 0x3FE; - sigA = (sigA | UINT64_C( 0x0010000000000000 ))<<10; - sigB = (sigB | UINT64_C( 0x0010000000000000 ))<<11; - softfloat_mul64To128M( sigA, sigB, sig128Z ); - sigZ = - (uint64_t) sig128Z[indexWord( 4, 3 )]<<32 | sig128Z[indexWord( 4, 2 )]; - shiftDist = 0; - if ( ! (sigZ & UINT64_C( 0x4000000000000000 )) ) { - --expZ; - shiftDist = -1; - } - if ( ! expC ) { - if ( ! sigC ) { - if ( shiftDist ) sigZ <<= 1; - goto sigZ; - } - normExpSig = softfloat_normSubnormalF64Sig( sigC ); - expC = normExpSig.exp; - sigC = normExpSig.sig; - } - sigC = (sigC | UINT64_C( 0x0010000000000000 ))<<10; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - expDiff = expZ - expC; - if ( expDiff < 0 ) { - expZ = expC; - if ( (signZ == signC) || (expDiff < -1) ) { - shiftDist -= expDiff; - if ( shiftDist) { - sigZ = softfloat_shiftRightJam64( sigZ, shiftDist ); - } - } else { - if ( ! shiftDist ) { - softfloat_shortShiftRight128M( sig128Z, 1, sig128Z ); - } - } - } else { - if ( shiftDist ) softfloat_add128M( sig128Z, sig128Z, sig128Z ); - if ( ! expDiff ) { - sigZ = - (uint64_t) sig128Z[indexWord( 4, 3 )]<<32 - | sig128Z[indexWord( 4, 2 )]; - } else { - sig128C[indexWord( 4, 3 )] = sigC>>32; - sig128C[indexWord( 4, 2 )] = sigC; - sig128C[indexWord( 4, 1 )] = 0; - sig128C[indexWord( 4, 0 )] = 0; - softfloat_shiftRightJam128M( sig128C, expDiff, sig128C ); - } - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( signZ == signC ) { - /*-------------------------------------------------------------------- - *--------------------------------------------------------------------*/ - if ( expDiff <= 0 ) { - sigZ += sigC; - } else { - softfloat_add128M( sig128Z, sig128C, sig128Z ); - sigZ = - (uint64_t) sig128Z[indexWord( 4, 3 )]<<32 - | sig128Z[indexWord( 4, 2 )]; - } - if ( sigZ & UINT64_C( 0x8000000000000000 ) ) { - ++expZ; - sigZ = softfloat_shortShiftRightJam64( sigZ, 1 ); - } - } else { - /*-------------------------------------------------------------------- - *--------------------------------------------------------------------*/ - if ( expDiff < 0 ) { - signZ = signC; - if ( expDiff < -1 ) { - sigZ = sigC - sigZ; - if ( - sig128Z[indexWord( 4, 1 )] || sig128Z[indexWord( 4, 0 )] - ) { - sigZ = (sigZ - 1) | 1; - } - if ( ! (sigZ & UINT64_C( 0x4000000000000000 )) ) { - --expZ; - sigZ <<= 1; - } - goto roundPack; - } else { - sig128C[indexWord( 4, 3 )] = sigC>>32; - sig128C[indexWord( 4, 2 )] = sigC; - sig128C[indexWord( 4, 1 )] = 0; - sig128C[indexWord( 4, 0 )] = 0; - softfloat_sub128M( sig128C, sig128Z, sig128Z ); - } - } else if ( ! expDiff ) { - sigZ -= sigC; - if ( - ! sigZ && ! sig128Z[indexWord( 4, 1 )] - && ! sig128Z[indexWord( 4, 0 )] - ) { - goto completeCancellation; - } - sig128Z[indexWord( 4, 3 )] = sigZ>>32; - sig128Z[indexWord( 4, 2 )] = sigZ; - if ( sigZ & UINT64_C( 0x8000000000000000 ) ) { - signZ = ! signZ; - softfloat_negX128M( sig128Z ); - } - } else { - softfloat_sub128M( sig128Z, sig128C, sig128Z ); - if ( 1 < expDiff ) { - sigZ = - (uint64_t) sig128Z[indexWord( 4, 3 )]<<32 - | sig128Z[indexWord( 4, 2 )]; - if ( ! (sigZ & UINT64_C( 0x4000000000000000 )) ) { - --expZ; - sigZ <<= 1; - } - goto sigZ; - } - } - /*-------------------------------------------------------------------- - *--------------------------------------------------------------------*/ - shiftDist = 0; - sigZ = - (uint64_t) sig128Z[indexWord( 4, 3 )]<<32 - | sig128Z[indexWord( 4, 2 )]; - if ( ! sigZ ) { - shiftDist = 64; - sigZ = - (uint64_t) sig128Z[indexWord( 4, 1 )]<<32 - | sig128Z[indexWord( 4, 0 )]; - } - shiftDist += softfloat_countLeadingZeros64( sigZ ) - 1; - if ( shiftDist ) { - expZ -= shiftDist; - softfloat_shiftLeft128M( sig128Z, shiftDist, sig128Z ); - sigZ = - (uint64_t) sig128Z[indexWord( 4, 3 )]<<32 - | sig128Z[indexWord( 4, 2 )]; - } - } - sigZ: - if ( sig128Z[indexWord( 4, 1 )] || sig128Z[indexWord( 4, 0 )] ) sigZ |= 1; - roundPack: - return softfloat_roundPackToF64( signZ, expZ - 1, sigZ ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - propagateNaN_ABC: - uiZ = softfloat_propagateNaNF64UI( uiA, uiB ); - goto propagateNaN_ZC; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - infProdArg: - if ( magBits ) { - uiZ = packToF64UI( signZ, 0x7FF, 0 ); - if ( expC != 0x7FF ) goto uiZ; - if ( sigC ) goto propagateNaN_ZC; - if ( signZ == signC ) goto uiZ; - } - softfloat_raiseFlags( softfloat_flag_invalid ); - uiZ = defaultNaNF64UI; - propagateNaN_ZC: - uiZ = softfloat_propagateNaNF64UI( uiZ, uiC ); - goto uiZ; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - zeroProd: - uiZ = uiC; - if ( ! (expC | sigC) && (signZ != signC) ) { - completeCancellation: - uiZ = - packToF64UI( - (softfloat_roundingMode == softfloat_round_min), 0, 0 ); - } - uiZ: - uZ.ui = uiZ; - return uZ.f; - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/s_negXM.c b/deps/SoftFloat-3e/source/s_negXM.c deleted file mode 100644 index ec8c928861ca..000000000000 --- a/deps/SoftFloat-3e/source/s_negXM.c +++ /dev/null @@ -1,63 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "primitiveTypes.h" - -#ifndef softfloat_negXM - -void softfloat_negXM( uint_fast8_t size_words, uint32_t *zPtr ) -{ - unsigned int index, lastIndex; - uint_fast8_t carry; - uint32_t word; - - index = indexWordLo( size_words ); - lastIndex = indexWordHi( size_words ); - carry = 1; - for (;;) { - word = ~zPtr[index] + carry; - zPtr[index] = word; - if ( index == lastIndex ) break; - index += wordIncr; - if ( word ) carry = 0; - } - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/s_normExtF80SigM.c b/deps/SoftFloat-3e/source/s_normExtF80SigM.c deleted file mode 100644 index acc54dc63c8d..000000000000 --- a/deps/SoftFloat-3e/source/s_normExtF80SigM.c +++ /dev/null @@ -1,52 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "internals.h" - -int softfloat_normExtF80SigM( uint64_t *sigPtr ) -{ - uint64_t sig; - int_fast8_t shiftDist; - - sig = *sigPtr; - shiftDist = softfloat_countLeadingZeros64( sig ); - *sigPtr = sig< -#include -#include "platform.h" -#include "internals.h" - -void - softfloat_normRoundPackMToExtF80M( - bool sign, - int32_t exp, - uint32_t *extSigPtr, - uint_fast8_t roundingPrecision, - struct extFloat80M *zSPtr - ) -{ - int_fast16_t shiftDist; - uint32_t wordSig; - - shiftDist = 0; - wordSig = extSigPtr[indexWord( 3, 2 )]; - if ( ! wordSig ) { - shiftDist = 32; - wordSig = extSigPtr[indexWord( 3, 1 )]; - if ( ! wordSig ) { - shiftDist = 64; - wordSig = extSigPtr[indexWord( 3, 0 )]; - if ( ! wordSig ) { - zSPtr->signExp = packToExtF80UI64( sign, 0 ); - zSPtr->signif = 0; - return; - } - } - } - shiftDist += softfloat_countLeadingZeros32( wordSig ); - if ( shiftDist ) { - exp -= shiftDist; - softfloat_shiftLeft96M( extSigPtr, shiftDist, extSigPtr ); - } - softfloat_roundPackMToExtF80M( - sign, exp, extSigPtr, roundingPrecision, zSPtr ); - -} - diff --git a/deps/SoftFloat-3e/source/s_normRoundPackMToF128M.c b/deps/SoftFloat-3e/source/s_normRoundPackMToF128M.c deleted file mode 100644 index 309455998c7f..000000000000 --- a/deps/SoftFloat-3e/source/s_normRoundPackMToF128M.c +++ /dev/null @@ -1,73 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" - -void - softfloat_normRoundPackMToF128M( - bool sign, int32_t exp, uint32_t *extSigPtr, uint32_t *zWPtr ) -{ - const uint32_t *ptr; - int_fast16_t shiftDist; - uint32_t wordSig; - - ptr = extSigPtr + indexWordHi( 5 ); - shiftDist = 0; - for (;;) { - wordSig = *ptr; - if ( wordSig ) break; - shiftDist += 32; - if ( 160 <= shiftDist ) { - zWPtr[indexWordHi( 4 )] = packToF128UI96( sign, 0, 0 ); - zWPtr[indexWord( 4, 2 )] = 0; - zWPtr[indexWord( 4, 1 )] = 0; - zWPtr[indexWord( 4, 0 )] = 0; - return; - } - ptr -= wordIncr; - } - shiftDist += softfloat_countLeadingZeros32( wordSig ) - 15; - if ( shiftDist ) { - exp -= shiftDist; - softfloat_shiftLeft160M( extSigPtr, shiftDist, extSigPtr ); - } - softfloat_roundPackMToF128M( sign, exp, extSigPtr, zWPtr ); - -} - diff --git a/deps/SoftFloat-3e/source/s_normRoundPackToExtF80.c b/deps/SoftFloat-3e/source/s_normRoundPackToExtF80.c deleted file mode 100644 index 76e791d911a3..000000000000 --- a/deps/SoftFloat-3e/source/s_normRoundPackToExtF80.c +++ /dev/null @@ -1,71 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" - -extFloat80_t - softfloat_normRoundPackToExtF80( - bool sign, - int_fast32_t exp, - uint_fast64_t sig, - uint_fast64_t sigExtra, - uint_fast8_t roundingPrecision - ) -{ - int_fast8_t shiftDist; - struct uint128 sig128; - - if ( ! sig ) { - exp -= 64; - sig = sigExtra; - sigExtra = 0; - } - shiftDist = softfloat_countLeadingZeros64( sig ); - exp -= shiftDist; - if ( shiftDist ) { - sig128 = softfloat_shortShiftLeft128( sig, sigExtra, shiftDist ); - sig = sig128.v64; - sigExtra = sig128.v0; - } - return - softfloat_roundPackToExtF80( - sign, exp, sig, sigExtra, roundingPrecision ); - -} - diff --git a/deps/SoftFloat-3e/source/s_normRoundPackToF128.c b/deps/SoftFloat-3e/source/s_normRoundPackToF128.c deleted file mode 100644 index 67f5b4349078..000000000000 --- a/deps/SoftFloat-3e/source/s_normRoundPackToF128.c +++ /dev/null @@ -1,81 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" - -float128_t - softfloat_normRoundPackToF128( - bool sign, int_fast32_t exp, uint_fast64_t sig64, uint_fast64_t sig0 ) -{ - int_fast8_t shiftDist; - struct uint128 sig128; - union ui128_f128 uZ; - uint_fast64_t sigExtra; - struct uint128_extra sig128Extra; - - if ( ! sig64 ) { - exp -= 64; - sig64 = sig0; - sig0 = 0; - } - shiftDist = softfloat_countLeadingZeros64( sig64 ) - 15; - exp -= shiftDist; - if ( 0 <= shiftDist ) { - if ( shiftDist ) { - sig128 = softfloat_shortShiftLeft128( sig64, sig0, shiftDist ); - sig64 = sig128.v64; - sig0 = sig128.v0; - } - if ( (uint32_t) exp < 0x7FFD ) { - uZ.ui.v64 = packToF128UI64( sign, sig64 | sig0 ? exp : 0, sig64 ); - uZ.ui.v0 = sig0; - return uZ.f; - } - sigExtra = 0; - } else { - sig128Extra = - softfloat_shortShiftRightJam128Extra( sig64, sig0, 0, -shiftDist ); - sig64 = sig128Extra.v.v64; - sig0 = sig128Extra.v.v0; - sigExtra = sig128Extra.extra; - } - return softfloat_roundPackToF128( sign, exp, sig64, sig0, sigExtra ); - -} - diff --git a/deps/SoftFloat-3e/source/s_normRoundPackToF16.c b/deps/SoftFloat-3e/source/s_normRoundPackToF16.c deleted file mode 100644 index 1d184d58ba9e..000000000000 --- a/deps/SoftFloat-3e/source/s_normRoundPackToF16.c +++ /dev/null @@ -1,58 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" - -float16_t - softfloat_normRoundPackToF16( bool sign, int_fast16_t exp, uint_fast16_t sig ) -{ - int_fast8_t shiftDist; - union ui16_f16 uZ; - - shiftDist = softfloat_countLeadingZeros16( sig ) - 1; - exp -= shiftDist; - if ( (4 <= shiftDist) && ((unsigned int) exp < 0x1D) ) { - uZ.ui = packToF16UI( sign, sig ? exp : 0, sig<<(shiftDist - 4) ); - return uZ.f; - } else { - return softfloat_roundPackToF16( sign, exp, sig< -#include -#include "platform.h" -#include "internals.h" - -float32_t - softfloat_normRoundPackToF32( bool sign, int_fast16_t exp, uint_fast32_t sig ) -{ - int_fast8_t shiftDist; - union ui32_f32 uZ; - - shiftDist = softfloat_countLeadingZeros32( sig ) - 1; - exp -= shiftDist; - if ( (7 <= shiftDist) && ((unsigned int) exp < 0xFD) ) { - uZ.ui = packToF32UI( sign, sig ? exp : 0, sig<<(shiftDist - 7) ); - return uZ.f; - } else { - return softfloat_roundPackToF32( sign, exp, sig< -#include -#include "platform.h" -#include "internals.h" - -float64_t - softfloat_normRoundPackToF64( bool sign, int_fast16_t exp, uint_fast64_t sig ) -{ - int_fast8_t shiftDist; - union ui64_f64 uZ; - - shiftDist = softfloat_countLeadingZeros64( sig ) - 1; - exp -= shiftDist; - if ( (10 <= shiftDist) && ((unsigned int) exp < 0x7FD) ) { - uZ.ui = packToF64UI( sign, sig ? exp : 0, sig<<(shiftDist - 10) ); - return uZ.f; - } else { - return softfloat_roundPackToF64( sign, exp, sig< -#include "platform.h" -#include "internals.h" - -struct exp32_sig64 softfloat_normSubnormalExtF80Sig( uint_fast64_t sig ) -{ - int_fast8_t shiftDist; - struct exp32_sig64 z; - - shiftDist = softfloat_countLeadingZeros64( sig ); - z.exp = -shiftDist; - z.sig = sig< -#include "platform.h" -#include "internals.h" - -struct exp32_sig128 - softfloat_normSubnormalF128Sig( uint_fast64_t sig64, uint_fast64_t sig0 ) -{ - int_fast8_t shiftDist; - struct exp32_sig128 z; - - if ( ! sig64 ) { - shiftDist = softfloat_countLeadingZeros64( sig0 ) - 15; - z.exp = -63 - shiftDist; - if ( shiftDist < 0 ) { - z.sig.v64 = sig0>>-shiftDist; - z.sig.v0 = sig0<<(shiftDist & 63); - } else { - z.sig.v64 = sig0< -#include "platform.h" -#include "internals.h" - -int softfloat_normSubnormalF128SigM( uint32_t *sigPtr ) -{ - const uint32_t *ptr; - int_fast16_t shiftDist; - uint32_t wordSig; - - ptr = sigPtr + indexWordHi( 4 ); - shiftDist = 0; - for (;;) { - wordSig = *ptr; - if ( wordSig ) break; - shiftDist += 32; - if ( 128 <= shiftDist ) return 1; - ptr -= wordIncr; - } - shiftDist += softfloat_countLeadingZeros32( wordSig ) - 15; - if ( shiftDist ) softfloat_shiftLeft128M( sigPtr, shiftDist, sigPtr ); - return 1 - shiftDist; - -} - diff --git a/deps/SoftFloat-3e/source/s_normSubnormalF16Sig.c b/deps/SoftFloat-3e/source/s_normSubnormalF16Sig.c deleted file mode 100644 index bb92adfea56a..000000000000 --- a/deps/SoftFloat-3e/source/s_normSubnormalF16Sig.c +++ /dev/null @@ -1,52 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "internals.h" - -struct exp8_sig16 softfloat_normSubnormalF16Sig( uint_fast16_t sig ) -{ - int_fast8_t shiftDist; - struct exp8_sig16 z; - - shiftDist = softfloat_countLeadingZeros16( sig ) - 5; - z.exp = 1 - shiftDist; - z.sig = sig< -#include "platform.h" -#include "internals.h" - -struct exp16_sig32 softfloat_normSubnormalF32Sig( uint_fast32_t sig ) -{ - int_fast8_t shiftDist; - struct exp16_sig32 z; - - shiftDist = softfloat_countLeadingZeros32( sig ) - 8; - z.exp = 1 - shiftDist; - z.sig = sig< -#include "platform.h" -#include "internals.h" - -struct exp16_sig64 softfloat_normSubnormalF64Sig( uint_fast64_t sig ) -{ - int_fast8_t shiftDist; - struct exp16_sig64 z; - - shiftDist = softfloat_countLeadingZeros64( sig ) - 11; - z.exp = 1 - shiftDist; - z.sig = sig< -#include "platform.h" -#include "primitiveTypes.h" - -#ifndef softfloat_remStepMBy32 - -void - softfloat_remStepMBy32( - uint_fast8_t size_words, - const uint32_t *remPtr, - uint_fast8_t dist, - const uint32_t *bPtr, - uint32_t q, - uint32_t *zPtr - ) -{ - unsigned int index, lastIndex; - uint64_t dwordProd; - uint32_t wordRem, wordShiftedRem, wordProd; - uint_fast8_t uNegDist, borrow; - - index = indexWordLo( size_words ); - lastIndex = indexWordHi( size_words ); - dwordProd = (uint64_t) bPtr[index] * q; - wordRem = remPtr[index]; - wordShiftedRem = wordRem<>(uNegDist & 31); - index += wordIncr; - dwordProd = (uint64_t) bPtr[index] * q + (dwordProd>>32); - wordRem = remPtr[index]; - wordShiftedRem |= wordRem< -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -int_fast64_t - softfloat_roundMToI64( - bool sign, uint32_t *extSigPtr, uint_fast8_t roundingMode, bool exact ) -{ - uint64_t sig; - uint32_t sigExtra; - union { uint64_t ui; int64_t i; } uZ; - int64_t z; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - sig = - (uint64_t) extSigPtr[indexWord( 3, 2 )]<<32 - | extSigPtr[indexWord( 3, 1 )]; - sigExtra = extSigPtr[indexWordLo( 3 )]; - if ( - (roundingMode == softfloat_round_near_maxMag) - || (roundingMode == softfloat_round_near_even) - ) { - if ( 0x80000000 <= sigExtra ) goto increment; - } else { - if ( - sigExtra - && (sign - ? (roundingMode == softfloat_round_min) -#ifdef SOFTFLOAT_ROUND_ODD - || (roundingMode == softfloat_round_odd) -#endif - : (roundingMode == softfloat_round_max)) - ) { - increment: - ++sig; - if ( !sig ) goto invalid; - if ( - (sigExtra == 0x80000000) - && (roundingMode == softfloat_round_near_even) - ) { - sig &= ~(uint_fast64_t) 1; - } - } - } - uZ.ui = sign ? -sig : sig; - z = uZ.i; - if ( z && ((z < 0) ^ sign) ) goto invalid; - if ( sigExtra ) { -#ifdef SOFTFLOAT_ROUND_ODD - if ( roundingMode == softfloat_round_odd ) z |= 1; -#endif - if ( exact ) softfloat_exceptionFlags |= softfloat_flag_inexact; - } - return z; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - invalid: - softfloat_raiseFlags( softfloat_flag_invalid ); - return sign ? i64_fromNegOverflow : i64_fromPosOverflow; - -} - diff --git a/deps/SoftFloat-3e/source/s_roundMToUI64.c b/deps/SoftFloat-3e/source/s_roundMToUI64.c deleted file mode 100644 index 196f53735f5b..000000000000 --- a/deps/SoftFloat-3e/source/s_roundMToUI64.c +++ /dev/null @@ -1,98 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017 The Regents of the -University of California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -uint_fast64_t - softfloat_roundMToUI64( - bool sign, uint32_t *extSigPtr, uint_fast8_t roundingMode, bool exact ) -{ - uint64_t sig; - uint32_t sigExtra; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - sig = - (uint64_t) extSigPtr[indexWord( 3, 2 )]<<32 - | extSigPtr[indexWord( 3, 1 )]; - sigExtra = extSigPtr[indexWordLo( 3 )]; - if ( - (roundingMode == softfloat_round_near_maxMag) - || (roundingMode == softfloat_round_near_even) - ) { - if ( 0x80000000 <= sigExtra ) goto increment; - } else { - if ( sign ) { - if ( !(sig | sigExtra) ) return 0; - if ( roundingMode == softfloat_round_min ) goto invalid; -#ifdef SOFTFLOAT_ROUND_ODD - if ( roundingMode == softfloat_round_odd ) goto invalid; -#endif - } else { - if ( (roundingMode == softfloat_round_max) && sigExtra ) { - increment: - ++sig; - if ( !sig ) goto invalid; - if ( - (sigExtra == 0x80000000) - && (roundingMode == softfloat_round_near_even) - ) { - sig &= ~(uint_fast64_t) 1; - } - } - } - } - if ( sign && sig ) goto invalid; - if ( sigExtra ) { -#ifdef SOFTFLOAT_ROUND_ODD - if ( roundingMode == softfloat_round_odd ) sig |= 1; -#endif - if ( exact ) softfloat_exceptionFlags |= softfloat_flag_inexact; - } - return sig; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - invalid: - softfloat_raiseFlags( softfloat_flag_invalid ); - return sign ? ui64_fromNegOverflow : ui64_fromPosOverflow; - -} - diff --git a/deps/SoftFloat-3e/source/s_roundPackMToExtF80M.c b/deps/SoftFloat-3e/source/s_roundPackMToExtF80M.c deleted file mode 100644 index 08620159f014..000000000000 --- a/deps/SoftFloat-3e/source/s_roundPackMToExtF80M.c +++ /dev/null @@ -1,256 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2017 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "softfloat.h" - -void - softfloat_roundPackMToExtF80M( - bool sign, - int32_t exp, - uint32_t *extSigPtr, - uint_fast8_t roundingPrecision, - struct extFloat80M *zSPtr - ) -{ - uint_fast8_t roundingMode; - bool roundNearEven; - uint64_t sig, roundIncrement, roundMask, roundBits; - bool isTiny; - uint32_t sigExtra; - bool doIncrement; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - roundingMode = softfloat_roundingMode; - roundNearEven = (roundingMode == softfloat_round_near_even); - sig = - (uint64_t) extSigPtr[indexWord( 3, 2 )]<<32 - | extSigPtr[indexWord( 3, 1 )]; - if ( roundingPrecision == 80 ) goto precision80; - if ( roundingPrecision == 64 ) { - roundIncrement = UINT64_C( 0x0000000000000400 ); - roundMask = UINT64_C( 0x00000000000007FF ); - } else if ( roundingPrecision == 32 ) { - roundIncrement = UINT64_C( 0x0000008000000000 ); - roundMask = UINT64_C( 0x000000FFFFFFFFFF ); - } else { - goto precision80; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( extSigPtr[indexWordLo( 3 )] ) sig |= 1; - if ( ! roundNearEven && (roundingMode != softfloat_round_near_maxMag) ) { - roundIncrement = - (roundingMode - == (sign ? softfloat_round_min : softfloat_round_max)) - ? roundMask - : 0; - } - roundBits = sig & roundMask; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( 0x7FFD <= (uint32_t) (exp - 1) ) { - if ( exp <= 0 ) { - /*---------------------------------------------------------------- - *----------------------------------------------------------------*/ - isTiny = - (softfloat_detectTininess - == softfloat_tininess_beforeRounding) - || (exp < 0) - || (sig <= (uint64_t) (sig + roundIncrement)); - sig = softfloat_shiftRightJam64( sig, 1 - exp ); - roundBits = sig & roundMask; - if ( roundBits ) { - if ( isTiny ) softfloat_raiseFlags( softfloat_flag_underflow ); - softfloat_exceptionFlags |= softfloat_flag_inexact; -#ifdef SOFTFLOAT_ROUND_ODD - if ( roundingMode == softfloat_round_odd ) { - sig |= roundMask + 1; - } -#endif - } - sig += roundIncrement; - exp = ((sig & UINT64_C( 0x8000000000000000 )) != 0); - roundIncrement = roundMask + 1; - if ( roundNearEven && (roundBits<<1 == roundIncrement) ) { - roundMask |= roundIncrement; - } - sig &= ~roundMask; - goto packReturn; - } - if ( - (0x7FFE < exp) - || ((exp == 0x7FFE) && ((uint64_t) (sig + roundIncrement) < sig)) - ) { - goto overflow; - } - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( roundBits ) { - softfloat_exceptionFlags |= softfloat_flag_inexact; -#ifdef SOFTFLOAT_ROUND_ODD - if ( roundingMode == softfloat_round_odd ) { - sig = (sig & ~roundMask) | (roundMask + 1); - goto packReturn; - } -#endif - } - sig += roundIncrement; - if ( sig < roundIncrement ) { - ++exp; - sig = UINT64_C( 0x8000000000000000 ); - } - roundIncrement = roundMask + 1; - if ( roundNearEven && (roundBits<<1 == roundIncrement) ) { - roundMask |= roundIncrement; - } - sig &= ~roundMask; - goto packReturn; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - precision80: - sigExtra = extSigPtr[indexWordLo( 3 )]; - doIncrement = (0x80000000 <= sigExtra); - if ( ! roundNearEven && (roundingMode != softfloat_round_near_maxMag) ) { - doIncrement = - (roundingMode - == (sign ? softfloat_round_min : softfloat_round_max)) - && sigExtra; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( 0x7FFD <= (uint32_t) (exp - 1) ) { - if ( exp <= 0 ) { - /*---------------------------------------------------------------- - *----------------------------------------------------------------*/ - isTiny = - (softfloat_detectTininess - == softfloat_tininess_beforeRounding) - || (exp < 0) - || ! doIncrement - || (sig < UINT64_C( 0xFFFFFFFFFFFFFFFF )); - softfloat_shiftRightJam96M( extSigPtr, 1 - exp, extSigPtr ); - exp = 0; - sig = - (uint64_t) extSigPtr[indexWord( 3, 2 )]<<32 - | extSigPtr[indexWord( 3, 1 )]; - sigExtra = extSigPtr[indexWordLo( 3 )]; - if ( sigExtra ) { - if ( isTiny ) softfloat_raiseFlags( softfloat_flag_underflow ); - softfloat_exceptionFlags |= softfloat_flag_inexact; -#ifdef SOFTFLOAT_ROUND_ODD - if ( roundingMode == softfloat_round_odd ) { - sig |= 1; - goto packReturn; - } -#endif - } - doIncrement = (0x80000000 <= sigExtra); - if ( - ! roundNearEven - && (roundingMode != softfloat_round_near_maxMag) - ) { - doIncrement = - (roundingMode - == (sign ? softfloat_round_min : softfloat_round_max)) - && sigExtra; - } - if ( doIncrement ) { - ++sig; - sig &= ~(uint64_t) (! (sigExtra & 0x7FFFFFFF) & roundNearEven); - exp = ((sig & UINT64_C( 0x8000000000000000 )) != 0); - } - goto packReturn; - } - if ( - (0x7FFE < exp) - || ((exp == 0x7FFE) && (sig == UINT64_C( 0xFFFFFFFFFFFFFFFF )) - && doIncrement) - ) { - /*---------------------------------------------------------------- - *----------------------------------------------------------------*/ - roundMask = 0; - overflow: - softfloat_raiseFlags( - softfloat_flag_overflow | softfloat_flag_inexact ); - if ( - roundNearEven - || (roundingMode == softfloat_round_near_maxMag) - || (roundingMode - == (sign ? softfloat_round_min : softfloat_round_max)) - ) { - exp = 0x7FFF; - sig = UINT64_C( 0x8000000000000000 ); - } else { - exp = 0x7FFE; - sig = ~roundMask; - } - goto packReturn; - } - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( sigExtra ) { - softfloat_exceptionFlags |= softfloat_flag_inexact; -#ifdef SOFTFLOAT_ROUND_ODD - if ( roundingMode == softfloat_round_odd ) { - sig |= 1; - goto packReturn; - } -#endif - } - if ( doIncrement ) { - ++sig; - if ( ! sig ) { - ++exp; - sig = UINT64_C( 0x8000000000000000 ); - } else { - sig &= ~(uint64_t) (! (sigExtra & 0x7FFFFFFF) & roundNearEven); - } - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - packReturn: - zSPtr->signExp = packToExtF80UI64( sign, exp ); - zSPtr->signif = sig; - -} - diff --git a/deps/SoftFloat-3e/source/s_roundPackMToF128M.c b/deps/SoftFloat-3e/source/s_roundPackMToF128M.c deleted file mode 100644 index 22591b8356b4..000000000000 --- a/deps/SoftFloat-3e/source/s_roundPackMToF128M.c +++ /dev/null @@ -1,178 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2017 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "softfloat.h" - -void - softfloat_roundPackMToF128M( - bool sign, int32_t exp, uint32_t *extSigPtr, uint32_t *zWPtr ) -{ - uint_fast8_t roundingMode; - bool roundNearEven; - uint32_t sigExtra; - bool doIncrement, isTiny; - static const uint32_t maxSig[4] = - INIT_UINTM4( 0x0001FFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF ); - uint32_t ui, uj; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - roundingMode = softfloat_roundingMode; - roundNearEven = (roundingMode == softfloat_round_near_even); - sigExtra = extSigPtr[indexWordLo( 5 )]; - doIncrement = (0x80000000 <= sigExtra); - if ( ! roundNearEven && (roundingMode != softfloat_round_near_maxMag) ) { - doIncrement = - (roundingMode - == (sign ? softfloat_round_min : softfloat_round_max)) - && sigExtra; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( 0x7FFD <= (uint32_t) exp ) { - if ( exp < 0 ) { - /*---------------------------------------------------------------- - *----------------------------------------------------------------*/ - isTiny = - (softfloat_detectTininess - == softfloat_tininess_beforeRounding) - || (exp < -1) - || ! doIncrement - || (softfloat_compare128M( - extSigPtr + indexMultiwordHi( 5, 4 ), maxSig ) - < 0); - softfloat_shiftRightJam160M( extSigPtr, -exp, extSigPtr ); - exp = 0; - sigExtra = extSigPtr[indexWordLo( 5 )]; - if ( isTiny && sigExtra ) { - softfloat_raiseFlags( softfloat_flag_underflow ); - } - doIncrement = (0x80000000 <= sigExtra); - if ( - ! roundNearEven - && (roundingMode != softfloat_round_near_maxMag) - ) { - doIncrement = - (roundingMode - == (sign ? softfloat_round_min : softfloat_round_max)) - && sigExtra; - } - } else if ( - (0x7FFD < exp) - || ((exp == 0x7FFD) && doIncrement - && (softfloat_compare128M( - extSigPtr + indexMultiwordHi( 5, 4 ), maxSig ) - == 0)) - ) { - /*---------------------------------------------------------------- - *----------------------------------------------------------------*/ - softfloat_raiseFlags( - softfloat_flag_overflow | softfloat_flag_inexact ); - if ( - roundNearEven - || (roundingMode == softfloat_round_near_maxMag) - || (roundingMode - == (sign ? softfloat_round_min : softfloat_round_max)) - ) { - ui = packToF128UI96( sign, 0x7FFF, 0 ); - uj = 0; - } else { - ui = packToF128UI96( sign, 0x7FFE, 0x0000FFFF ); - uj = 0xFFFFFFFF; - } - zWPtr[indexWordHi( 4 )] = ui; - zWPtr[indexWord( 4, 2 )] = uj; - zWPtr[indexWord( 4, 1 )] = uj; - zWPtr[indexWord( 4, 0 )] = uj; - return; - } - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - uj = extSigPtr[indexWord( 5, 1 )]; - if ( sigExtra ) { - softfloat_exceptionFlags |= softfloat_flag_inexact; -#ifdef SOFTFLOAT_ROUND_ODD - if ( roundingMode == softfloat_round_odd ) { - uj |= 1; - goto noIncrementPackReturn; - } -#endif - } - if ( doIncrement ) { - ++uj; - if ( uj ) { - if ( ! (sigExtra & 0x7FFFFFFF) && roundNearEven ) uj &= ~1; - zWPtr[indexWord( 4, 2 )] = extSigPtr[indexWord( 5, 3 )]; - zWPtr[indexWord( 4, 1 )] = extSigPtr[indexWord( 5, 2 )]; - zWPtr[indexWord( 4, 0 )] = uj; - ui = extSigPtr[indexWordHi( 5 )]; - } else { - zWPtr[indexWord( 4, 0 )] = uj; - ui = extSigPtr[indexWord( 5, 2 )] + 1; - zWPtr[indexWord( 4, 1 )] = ui; - uj = extSigPtr[indexWord( 5, 3 )]; - if ( ui ) { - zWPtr[indexWord( 4, 2 )] = uj; - ui = extSigPtr[indexWordHi( 5 )]; - } else { - ++uj; - zWPtr[indexWord( 4, 2 )] = uj; - ui = extSigPtr[indexWordHi( 5 )]; - if ( ! uj ) ++ui; - } - } - } else { - noIncrementPackReturn: - zWPtr[indexWord( 4, 0 )] = uj; - ui = extSigPtr[indexWord( 5, 2 )]; - zWPtr[indexWord( 4, 1 )] = ui; - uj |= ui; - ui = extSigPtr[indexWord( 5, 3 )]; - zWPtr[indexWord( 4, 2 )] = ui; - uj |= ui; - ui = extSigPtr[indexWordHi( 5 )]; - uj |= ui; - if ( ! uj ) exp = 0; - } - zWPtr[indexWordHi( 4 )] = packToF128UI96( sign, exp, ui ); - -} - diff --git a/deps/SoftFloat-3e/source/s_roundPackToExtF80.c b/deps/SoftFloat-3e/source/s_roundPackToExtF80.c deleted file mode 100644 index 0cc7af9851ba..000000000000 --- a/deps/SoftFloat-3e/source/s_roundPackToExtF80.c +++ /dev/null @@ -1,256 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2017 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "softfloat.h" - -extFloat80_t - softfloat_roundPackToExtF80( - bool sign, - int_fast32_t exp, - uint_fast64_t sig, - uint_fast64_t sigExtra, - uint_fast8_t roundingPrecision - ) -{ - uint_fast8_t roundingMode; - bool roundNearEven; - uint_fast64_t roundIncrement, roundMask, roundBits; - bool isTiny, doIncrement; - struct uint64_extra sig64Extra; - union { struct extFloat80M s; extFloat80_t f; } uZ; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - roundingMode = softfloat_roundingMode; - roundNearEven = (roundingMode == softfloat_round_near_even); - if ( roundingPrecision == 80 ) goto precision80; - if ( roundingPrecision == 64 ) { - roundIncrement = UINT64_C( 0x0000000000000400 ); - roundMask = UINT64_C( 0x00000000000007FF ); - } else if ( roundingPrecision == 32 ) { - roundIncrement = UINT64_C( 0x0000008000000000 ); - roundMask = UINT64_C( 0x000000FFFFFFFFFF ); - } else { - goto precision80; - } - sig |= (sigExtra != 0); - if ( ! roundNearEven && (roundingMode != softfloat_round_near_maxMag) ) { - roundIncrement = - (roundingMode - == (sign ? softfloat_round_min : softfloat_round_max)) - ? roundMask - : 0; - } - roundBits = sig & roundMask; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( 0x7FFD <= (uint32_t) (exp - 1) ) { - if ( exp <= 0 ) { - /*---------------------------------------------------------------- - *----------------------------------------------------------------*/ - isTiny = - (softfloat_detectTininess - == softfloat_tininess_beforeRounding) - || (exp < 0) - || (sig <= (uint64_t) (sig + roundIncrement)); - sig = softfloat_shiftRightJam64( sig, 1 - exp ); - roundBits = sig & roundMask; - if ( roundBits ) { - if ( isTiny ) softfloat_raiseFlags( softfloat_flag_underflow ); - softfloat_exceptionFlags |= softfloat_flag_inexact; -#ifdef SOFTFLOAT_ROUND_ODD - if ( roundingMode == softfloat_round_odd ) { - sig |= roundMask + 1; - } -#endif - } - sig += roundIncrement; - exp = ((sig & UINT64_C( 0x8000000000000000 )) != 0); - roundIncrement = roundMask + 1; - if ( roundNearEven && (roundBits<<1 == roundIncrement) ) { - roundMask |= roundIncrement; - } - sig &= ~roundMask; - goto packReturn; - } - if ( - (0x7FFE < exp) - || ((exp == 0x7FFE) && ((uint64_t) (sig + roundIncrement) < sig)) - ) { - goto overflow; - } - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( roundBits ) { - softfloat_exceptionFlags |= softfloat_flag_inexact; -#ifdef SOFTFLOAT_ROUND_ODD - if ( roundingMode == softfloat_round_odd ) { - sig = (sig & ~roundMask) | (roundMask + 1); - goto packReturn; - } -#endif - } - sig = (uint64_t) (sig + roundIncrement); - if ( sig < roundIncrement ) { - ++exp; - sig = UINT64_C( 0x8000000000000000 ); - } - roundIncrement = roundMask + 1; - if ( roundNearEven && (roundBits<<1 == roundIncrement) ) { - roundMask |= roundIncrement; - } - sig &= ~roundMask; - goto packReturn; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - precision80: - doIncrement = (UINT64_C( 0x8000000000000000 ) <= sigExtra); - if ( ! roundNearEven && (roundingMode != softfloat_round_near_maxMag) ) { - doIncrement = - (roundingMode - == (sign ? softfloat_round_min : softfloat_round_max)) - && sigExtra; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( 0x7FFD <= (uint32_t) (exp - 1) ) { - if ( exp <= 0 ) { - /*---------------------------------------------------------------- - *----------------------------------------------------------------*/ - isTiny = - (softfloat_detectTininess - == softfloat_tininess_beforeRounding) - || (exp < 0) - || ! doIncrement - || (sig < UINT64_C( 0xFFFFFFFFFFFFFFFF )); - sig64Extra = - softfloat_shiftRightJam64Extra( sig, sigExtra, 1 - exp ); - exp = 0; - sig = sig64Extra.v; - sigExtra = sig64Extra.extra; - if ( sigExtra ) { - if ( isTiny ) softfloat_raiseFlags( softfloat_flag_underflow ); - softfloat_exceptionFlags |= softfloat_flag_inexact; -#ifdef SOFTFLOAT_ROUND_ODD - if ( roundingMode == softfloat_round_odd ) { - sig |= 1; - goto packReturn; - } -#endif - } - doIncrement = (UINT64_C( 0x8000000000000000 ) <= sigExtra); - if ( - ! roundNearEven - && (roundingMode != softfloat_round_near_maxMag) - ) { - doIncrement = - (roundingMode - == (sign ? softfloat_round_min : softfloat_round_max)) - && sigExtra; - } - if ( doIncrement ) { - ++sig; - sig &= - ~(uint_fast64_t) - (! (sigExtra & UINT64_C( 0x7FFFFFFFFFFFFFFF )) - & roundNearEven); - exp = ((sig & UINT64_C( 0x8000000000000000 )) != 0); - } - goto packReturn; - } - if ( - (0x7FFE < exp) - || ((exp == 0x7FFE) && (sig == UINT64_C( 0xFFFFFFFFFFFFFFFF )) - && doIncrement) - ) { - /*---------------------------------------------------------------- - *----------------------------------------------------------------*/ - roundMask = 0; - overflow: - softfloat_raiseFlags( - softfloat_flag_overflow | softfloat_flag_inexact ); - if ( - roundNearEven - || (roundingMode == softfloat_round_near_maxMag) - || (roundingMode - == (sign ? softfloat_round_min : softfloat_round_max)) - ) { - exp = 0x7FFF; - sig = UINT64_C( 0x8000000000000000 ); - } else { - exp = 0x7FFE; - sig = ~roundMask; - } - goto packReturn; - } - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( sigExtra ) { - softfloat_exceptionFlags |= softfloat_flag_inexact; -#ifdef SOFTFLOAT_ROUND_ODD - if ( roundingMode == softfloat_round_odd ) { - sig |= 1; - goto packReturn; - } -#endif - } - if ( doIncrement ) { - ++sig; - if ( ! sig ) { - ++exp; - sig = UINT64_C( 0x8000000000000000 ); - } else { - sig &= - ~(uint_fast64_t) - (! (sigExtra & UINT64_C( 0x7FFFFFFFFFFFFFFF )) - & roundNearEven); - } - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - packReturn: - uZ.s.signExp = packToExtF80UI64( sign, exp ); - uZ.s.signif = sig; - return uZ.f; - -} - diff --git a/deps/SoftFloat-3e/source/s_roundPackToF128.c b/deps/SoftFloat-3e/source/s_roundPackToF128.c deleted file mode 100644 index 41584316a4af..000000000000 --- a/deps/SoftFloat-3e/source/s_roundPackToF128.c +++ /dev/null @@ -1,171 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2017 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "softfloat.h" - -float128_t - softfloat_roundPackToF128( - bool sign, - int_fast32_t exp, - uint_fast64_t sig64, - uint_fast64_t sig0, - uint_fast64_t sigExtra - ) -{ - uint_fast8_t roundingMode; - bool roundNearEven, doIncrement, isTiny; - struct uint128_extra sig128Extra; - uint_fast64_t uiZ64, uiZ0; - struct uint128 sig128; - union ui128_f128 uZ; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - roundingMode = softfloat_roundingMode; - roundNearEven = (roundingMode == softfloat_round_near_even); - doIncrement = (UINT64_C( 0x8000000000000000 ) <= sigExtra); - if ( ! roundNearEven && (roundingMode != softfloat_round_near_maxMag) ) { - doIncrement = - (roundingMode - == (sign ? softfloat_round_min : softfloat_round_max)) - && sigExtra; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( 0x7FFD <= (uint32_t) exp ) { - if ( exp < 0 ) { - /*---------------------------------------------------------------- - *----------------------------------------------------------------*/ - isTiny = - (softfloat_detectTininess - == softfloat_tininess_beforeRounding) - || (exp < -1) - || ! doIncrement - || softfloat_lt128( - sig64, - sig0, - UINT64_C( 0x0001FFFFFFFFFFFF ), - UINT64_C( 0xFFFFFFFFFFFFFFFF ) - ); - sig128Extra = - softfloat_shiftRightJam128Extra( sig64, sig0, sigExtra, -exp ); - sig64 = sig128Extra.v.v64; - sig0 = sig128Extra.v.v0; - sigExtra = sig128Extra.extra; - exp = 0; - if ( isTiny && sigExtra ) { - softfloat_raiseFlags( softfloat_flag_underflow ); - } - doIncrement = (UINT64_C( 0x8000000000000000 ) <= sigExtra); - if ( - ! roundNearEven - && (roundingMode != softfloat_round_near_maxMag) - ) { - doIncrement = - (roundingMode - == (sign ? softfloat_round_min : softfloat_round_max)) - && sigExtra; - } - } else if ( - (0x7FFD < exp) - || ((exp == 0x7FFD) - && softfloat_eq128( - sig64, - sig0, - UINT64_C( 0x0001FFFFFFFFFFFF ), - UINT64_C( 0xFFFFFFFFFFFFFFFF ) - ) - && doIncrement) - ) { - /*---------------------------------------------------------------- - *----------------------------------------------------------------*/ - softfloat_raiseFlags( - softfloat_flag_overflow | softfloat_flag_inexact ); - if ( - roundNearEven - || (roundingMode == softfloat_round_near_maxMag) - || (roundingMode - == (sign ? softfloat_round_min : softfloat_round_max)) - ) { - uiZ64 = packToF128UI64( sign, 0x7FFF, 0 ); - uiZ0 = 0; - } else { - uiZ64 = - packToF128UI64( - sign, 0x7FFE, UINT64_C( 0x0000FFFFFFFFFFFF ) ); - uiZ0 = UINT64_C( 0xFFFFFFFFFFFFFFFF ); - } - goto uiZ; - } - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( sigExtra ) { - softfloat_exceptionFlags |= softfloat_flag_inexact; -#ifdef SOFTFLOAT_ROUND_ODD - if ( roundingMode == softfloat_round_odd ) { - sig0 |= 1; - goto packReturn; - } -#endif - } - if ( doIncrement ) { - sig128 = softfloat_add128( sig64, sig0, 0, 1 ); - sig64 = sig128.v64; - sig0 = - sig128.v0 - & ~(uint64_t) - (! (sigExtra & UINT64_C( 0x7FFFFFFFFFFFFFFF )) - & roundNearEven); - } else { - if ( ! (sig64 | sig0) ) exp = 0; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - packReturn: - uiZ64 = packToF128UI64( sign, exp, sig64 ); - uiZ0 = sig0; - uiZ: - uZ.ui.v64 = uiZ64; - uZ.ui.v0 = uiZ0; - return uZ.f; - -} - diff --git a/deps/SoftFloat-3e/source/s_roundPackToF16.c b/deps/SoftFloat-3e/source/s_roundPackToF16.c deleted file mode 100644 index 2dde55bb40a9..000000000000 --- a/deps/SoftFloat-3e/source/s_roundPackToF16.c +++ /dev/null @@ -1,113 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2017 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "softfloat.h" - -float16_t - softfloat_roundPackToF16( bool sign, int_fast16_t exp, uint_fast16_t sig ) -{ - uint_fast8_t roundingMode; - bool roundNearEven; - uint_fast8_t roundIncrement, roundBits; - bool isTiny; - uint_fast16_t uiZ; - union ui16_f16 uZ; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - roundingMode = softfloat_roundingMode; - roundNearEven = (roundingMode == softfloat_round_near_even); - roundIncrement = 0x8; - if ( ! roundNearEven && (roundingMode != softfloat_round_near_maxMag) ) { - roundIncrement = - (roundingMode - == (sign ? softfloat_round_min : softfloat_round_max)) - ? 0xF - : 0; - } - roundBits = sig & 0xF; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( 0x1D <= (unsigned int) exp ) { - if ( exp < 0 ) { - /*---------------------------------------------------------------- - *----------------------------------------------------------------*/ - isTiny = - (softfloat_detectTininess == softfloat_tininess_beforeRounding) - || (exp < -1) || (sig + roundIncrement < 0x8000); - sig = softfloat_shiftRightJam32( sig, -exp ); - exp = 0; - roundBits = sig & 0xF; - if ( isTiny && roundBits ) { - softfloat_raiseFlags( softfloat_flag_underflow ); - } - } else if ( (0x1D < exp) || (0x8000 <= sig + roundIncrement) ) { - /*---------------------------------------------------------------- - *----------------------------------------------------------------*/ - softfloat_raiseFlags( - softfloat_flag_overflow | softfloat_flag_inexact ); - uiZ = packToF16UI( sign, 0x1F, 0 ) - ! roundIncrement; - goto uiZ; - } - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - sig = (sig + roundIncrement)>>4; - if ( roundBits ) { - softfloat_exceptionFlags |= softfloat_flag_inexact; -#ifdef SOFTFLOAT_ROUND_ODD - if ( roundingMode == softfloat_round_odd ) { - sig |= 1; - goto packReturn; - } -#endif - } - sig &= ~(uint_fast16_t) (! (roundBits ^ 8) & roundNearEven); - if ( ! sig ) exp = 0; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - packReturn: - uiZ = packToF16UI( sign, exp, sig ); - uiZ: - uZ.ui = uiZ; - return uZ.f; - -} - diff --git a/deps/SoftFloat-3e/source/s_roundPackToF32.c b/deps/SoftFloat-3e/source/s_roundPackToF32.c deleted file mode 100644 index a69b8d4d7022..000000000000 --- a/deps/SoftFloat-3e/source/s_roundPackToF32.c +++ /dev/null @@ -1,113 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2017 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "softfloat.h" - -float32_t - softfloat_roundPackToF32( bool sign, int_fast16_t exp, uint_fast32_t sig ) -{ - uint_fast8_t roundingMode; - bool roundNearEven; - uint_fast8_t roundIncrement, roundBits; - bool isTiny; - uint_fast32_t uiZ; - union ui32_f32 uZ; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - roundingMode = softfloat_roundingMode; - roundNearEven = (roundingMode == softfloat_round_near_even); - roundIncrement = 0x40; - if ( ! roundNearEven && (roundingMode != softfloat_round_near_maxMag) ) { - roundIncrement = - (roundingMode - == (sign ? softfloat_round_min : softfloat_round_max)) - ? 0x7F - : 0; - } - roundBits = sig & 0x7F; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( 0xFD <= (unsigned int) exp ) { - if ( exp < 0 ) { - /*---------------------------------------------------------------- - *----------------------------------------------------------------*/ - isTiny = - (softfloat_detectTininess == softfloat_tininess_beforeRounding) - || (exp < -1) || (sig + roundIncrement < 0x80000000); - sig = softfloat_shiftRightJam32( sig, -exp ); - exp = 0; - roundBits = sig & 0x7F; - if ( isTiny && roundBits ) { - softfloat_raiseFlags( softfloat_flag_underflow ); - } - } else if ( (0xFD < exp) || (0x80000000 <= sig + roundIncrement) ) { - /*---------------------------------------------------------------- - *----------------------------------------------------------------*/ - softfloat_raiseFlags( - softfloat_flag_overflow | softfloat_flag_inexact ); - uiZ = packToF32UI( sign, 0xFF, 0 ) - ! roundIncrement; - goto uiZ; - } - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - sig = (sig + roundIncrement)>>7; - if ( roundBits ) { - softfloat_exceptionFlags |= softfloat_flag_inexact; -#ifdef SOFTFLOAT_ROUND_ODD - if ( roundingMode == softfloat_round_odd ) { - sig |= 1; - goto packReturn; - } -#endif - } - sig &= ~(uint_fast32_t) (! (roundBits ^ 0x40) & roundNearEven); - if ( ! sig ) exp = 0; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - packReturn: - uiZ = packToF32UI( sign, exp, sig ); - uiZ: - uZ.ui = uiZ; - return uZ.f; - -} - diff --git a/deps/SoftFloat-3e/source/s_roundPackToF64.c b/deps/SoftFloat-3e/source/s_roundPackToF64.c deleted file mode 100644 index f7f3abff52e4..000000000000 --- a/deps/SoftFloat-3e/source/s_roundPackToF64.c +++ /dev/null @@ -1,117 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2017 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "softfloat.h" - -float64_t - softfloat_roundPackToF64( bool sign, int_fast16_t exp, uint_fast64_t sig ) -{ - uint_fast8_t roundingMode; - bool roundNearEven; - uint_fast16_t roundIncrement, roundBits; - bool isTiny; - uint_fast64_t uiZ; - union ui64_f64 uZ; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - roundingMode = softfloat_roundingMode; - roundNearEven = (roundingMode == softfloat_round_near_even); - roundIncrement = 0x200; - if ( ! roundNearEven && (roundingMode != softfloat_round_near_maxMag) ) { - roundIncrement = - (roundingMode - == (sign ? softfloat_round_min : softfloat_round_max)) - ? 0x3FF - : 0; - } - roundBits = sig & 0x3FF; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( 0x7FD <= (uint16_t) exp ) { - if ( exp < 0 ) { - /*---------------------------------------------------------------- - *----------------------------------------------------------------*/ - isTiny = - (softfloat_detectTininess == softfloat_tininess_beforeRounding) - || (exp < -1) - || (sig + roundIncrement < UINT64_C( 0x8000000000000000 )); - sig = softfloat_shiftRightJam64( sig, -exp ); - exp = 0; - roundBits = sig & 0x3FF; - if ( isTiny && roundBits ) { - softfloat_raiseFlags( softfloat_flag_underflow ); - } - } else if ( - (0x7FD < exp) - || (UINT64_C( 0x8000000000000000 ) <= sig + roundIncrement) - ) { - /*---------------------------------------------------------------- - *----------------------------------------------------------------*/ - softfloat_raiseFlags( - softfloat_flag_overflow | softfloat_flag_inexact ); - uiZ = packToF64UI( sign, 0x7FF, 0 ) - ! roundIncrement; - goto uiZ; - } - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - sig = (sig + roundIncrement)>>10; - if ( roundBits ) { - softfloat_exceptionFlags |= softfloat_flag_inexact; -#ifdef SOFTFLOAT_ROUND_ODD - if ( roundingMode == softfloat_round_odd ) { - sig |= 1; - goto packReturn; - } -#endif - } - sig &= ~(uint_fast64_t) (! (roundBits ^ 0x200) & roundNearEven); - if ( ! sig ) exp = 0; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - packReturn: - uiZ = packToF64UI( sign, exp, sig ); - uiZ: - uZ.ui = uiZ; - return uZ.f; - -} - diff --git a/deps/SoftFloat-3e/source/s_roundToI32.c b/deps/SoftFloat-3e/source/s_roundToI32.c deleted file mode 100644 index a3e727dc70e3..000000000000 --- a/deps/SoftFloat-3e/source/s_roundToI32.c +++ /dev/null @@ -1,98 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017 The Regents of the -University of California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -int_fast32_t - softfloat_roundToI32( - bool sign, uint_fast64_t sig, uint_fast8_t roundingMode, bool exact ) -{ - uint_fast16_t roundIncrement, roundBits; - uint_fast32_t sig32; - union { uint32_t ui; int32_t i; } uZ; - int_fast32_t z; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - roundIncrement = 0x800; - if ( - (roundingMode != softfloat_round_near_maxMag) - && (roundingMode != softfloat_round_near_even) - ) { - roundIncrement = 0; - if ( - sign - ? (roundingMode == softfloat_round_min) -#ifdef SOFTFLOAT_ROUND_ODD - || (roundingMode == softfloat_round_odd) -#endif - : (roundingMode == softfloat_round_max) - ) { - roundIncrement = 0xFFF; - } - } - roundBits = sig & 0xFFF; - sig += roundIncrement; - if ( sig & UINT64_C( 0xFFFFF00000000000 ) ) goto invalid; - sig32 = sig>>12; - if ( - (roundBits == 0x800) && (roundingMode == softfloat_round_near_even) - ) { - sig32 &= ~(uint_fast32_t) 1; - } - uZ.ui = sign ? -sig32 : sig32; - z = uZ.i; - if ( z && ((z < 0) ^ sign) ) goto invalid; - if ( roundBits ) { -#ifdef SOFTFLOAT_ROUND_ODD - if ( roundingMode == softfloat_round_odd ) z |= 1; -#endif - if ( exact ) softfloat_exceptionFlags |= softfloat_flag_inexact; - } - return z; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - invalid: - softfloat_raiseFlags( softfloat_flag_invalid ); - return sign ? i32_fromNegOverflow : i32_fromPosOverflow; - -} - diff --git a/deps/SoftFloat-3e/source/s_roundToI64.c b/deps/SoftFloat-3e/source/s_roundToI64.c deleted file mode 100644 index 773c82cfc253..000000000000 --- a/deps/SoftFloat-3e/source/s_roundToI64.c +++ /dev/null @@ -1,101 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017 The Regents of the -University of California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -int_fast64_t - softfloat_roundToI64( - bool sign, - uint_fast64_t sig, - uint_fast64_t sigExtra, - uint_fast8_t roundingMode, - bool exact - ) -{ - union { uint64_t ui; int64_t i; } uZ; - int_fast64_t z; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( - (roundingMode == softfloat_round_near_maxMag) - || (roundingMode == softfloat_round_near_even) - ) { - if ( UINT64_C( 0x8000000000000000 ) <= sigExtra ) goto increment; - } else { - if ( - sigExtra - && (sign - ? (roundingMode == softfloat_round_min) -#ifdef SOFTFLOAT_ROUND_ODD - || (roundingMode == softfloat_round_odd) -#endif - : (roundingMode == softfloat_round_max)) - ) { - increment: - ++sig; - if ( !sig ) goto invalid; - if ( - (sigExtra == UINT64_C( 0x8000000000000000 )) - && (roundingMode == softfloat_round_near_even) - ) { - sig &= ~(uint_fast64_t) 1; - } - } - } - uZ.ui = sign ? -sig : sig; - z = uZ.i; - if ( z && ((z < 0) ^ sign) ) goto invalid; - if ( sigExtra ) { -#ifdef SOFTFLOAT_ROUND_ODD - if ( roundingMode == softfloat_round_odd ) z |= 1; -#endif - if ( exact ) softfloat_exceptionFlags |= softfloat_flag_inexact; - } - return z; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - invalid: - softfloat_raiseFlags( softfloat_flag_invalid ); - return sign ? i64_fromNegOverflow : i64_fromPosOverflow; - -} - diff --git a/deps/SoftFloat-3e/source/s_roundToUI32.c b/deps/SoftFloat-3e/source/s_roundToUI32.c deleted file mode 100644 index 059e231e2edd..000000000000 --- a/deps/SoftFloat-3e/source/s_roundToUI32.c +++ /dev/null @@ -1,93 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017 The Regents of the -University of California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -uint_fast32_t - softfloat_roundToUI32( - bool sign, uint_fast64_t sig, uint_fast8_t roundingMode, bool exact ) -{ - uint_fast16_t roundIncrement, roundBits; - uint_fast32_t z; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - roundIncrement = 0x800; - if ( - (roundingMode != softfloat_round_near_maxMag) - && (roundingMode != softfloat_round_near_even) - ) { - roundIncrement = 0; - if ( sign ) { - if ( !sig ) return 0; - if ( roundingMode == softfloat_round_min ) goto invalid; -#ifdef SOFTFLOAT_ROUND_ODD - if ( roundingMode == softfloat_round_odd ) goto invalid; -#endif - } else { - if ( roundingMode == softfloat_round_max ) roundIncrement = 0xFFF; - } - } - roundBits = sig & 0xFFF; - sig += roundIncrement; - if ( sig & UINT64_C( 0xFFFFF00000000000 ) ) goto invalid; - z = sig>>12; - if ( - (roundBits == 0x800) && (roundingMode == softfloat_round_near_even) - ) { - z &= ~(uint_fast32_t) 1; - } - if ( sign && z ) goto invalid; - if ( roundBits ) { -#ifdef SOFTFLOAT_ROUND_ODD - if ( roundingMode == softfloat_round_odd ) z |= 1; -#endif - if ( exact ) softfloat_exceptionFlags |= softfloat_flag_inexact; - } - return z; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - invalid: - softfloat_raiseFlags( softfloat_flag_invalid ); - return sign ? ui32_fromNegOverflow : ui32_fromPosOverflow; - -} - diff --git a/deps/SoftFloat-3e/source/s_roundToUI64.c b/deps/SoftFloat-3e/source/s_roundToUI64.c deleted file mode 100644 index 856ad97929f1..000000000000 --- a/deps/SoftFloat-3e/source/s_roundToUI64.c +++ /dev/null @@ -1,97 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017 The Regents of the -University of California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -uint_fast64_t - softfloat_roundToUI64( - bool sign, - uint_fast64_t sig, - uint_fast64_t sigExtra, - uint_fast8_t roundingMode, - bool exact - ) -{ - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - if ( - (roundingMode == softfloat_round_near_maxMag) - || (roundingMode == softfloat_round_near_even) - ) { - if ( UINT64_C( 0x8000000000000000 ) <= sigExtra ) goto increment; - } else { - if ( sign ) { - if ( !(sig | sigExtra) ) return 0; - if ( roundingMode == softfloat_round_min ) goto invalid; -#ifdef SOFTFLOAT_ROUND_ODD - if ( roundingMode == softfloat_round_odd ) goto invalid; -#endif - } else { - if ( (roundingMode == softfloat_round_max) && sigExtra ) { - increment: - ++sig; - if ( !sig ) goto invalid; - if ( - (sigExtra == UINT64_C( 0x8000000000000000 )) - && (roundingMode == softfloat_round_near_even) - ) { - sig &= ~(uint_fast64_t) 1; - } - } - } - } - if ( sign && sig ) goto invalid; - if ( sigExtra ) { -#ifdef SOFTFLOAT_ROUND_ODD - if ( roundingMode == softfloat_round_odd ) sig |= 1; -#endif - if ( exact ) softfloat_exceptionFlags |= softfloat_flag_inexact; - } - return sig; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - invalid: - softfloat_raiseFlags( softfloat_flag_invalid ); - return sign ? ui64_fromNegOverflow : ui64_fromPosOverflow; - -} - diff --git a/deps/SoftFloat-3e/source/s_shiftLeftM.c b/deps/SoftFloat-3e/source/s_shiftLeftM.c deleted file mode 100644 index 71a309919919..000000000000 --- a/deps/SoftFloat-3e/source/s_shiftLeftM.c +++ /dev/null @@ -1,91 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" - -#ifndef softfloat_shiftLeftM - -#define softfloat_shiftLeftM softfloat_shiftLeftM -#include "primitives.h" - -void - softfloat_shiftLeftM( - uint_fast8_t size_words, - const uint32_t *aPtr, - uint32_t dist, - uint32_t *zPtr - ) -{ - uint32_t wordDist; - uint_fast8_t innerDist; - uint32_t *destPtr; - uint_fast8_t i; - - wordDist = dist>>5; - if ( wordDist < size_words ) { - aPtr += indexMultiwordLoBut( size_words, wordDist ); - innerDist = dist & 31; - if ( innerDist ) { - softfloat_shortShiftLeftM( - size_words - wordDist, - aPtr, - innerDist, - zPtr + indexMultiwordHiBut( size_words, wordDist ) - ); - if ( ! wordDist ) return; - } else { - aPtr += indexWordHi( size_words - wordDist ); - destPtr = zPtr + indexWordHi( size_words ); - for ( i = size_words - wordDist; i; --i ) { - *destPtr = *aPtr; - aPtr -= wordIncr; - destPtr -= wordIncr; - } - } - zPtr += indexMultiwordLo( size_words, wordDist ); - } else { - wordDist = size_words; - } - do { - *zPtr++ = 0; - --wordDist; - } while ( wordDist ); - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/s_shiftNormSigF128M.c b/deps/SoftFloat-3e/source/s_shiftNormSigF128M.c deleted file mode 100644 index fa4976c8e771..000000000000 --- a/deps/SoftFloat-3e/source/s_shiftNormSigF128M.c +++ /dev/null @@ -1,78 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "internals.h" - -int - softfloat_shiftNormSigF128M( - const uint32_t *wPtr, uint_fast8_t shiftDist, uint32_t *sigPtr ) -{ - uint32_t wordSig; - int32_t exp; - uint32_t leadingBit; - - wordSig = wPtr[indexWordHi( 4 )]; - exp = expF128UI96( wordSig ); - if ( exp ) { - softfloat_shortShiftLeft128M( wPtr, shiftDist, sigPtr ); - leadingBit = 0x00010000< -#include "platform.h" -#include "primitiveTypes.h" - -#ifndef softfloat_shiftRightJam128 - -struct uint128 - softfloat_shiftRightJam128( uint64_t a64, uint64_t a0, uint_fast32_t dist ) -{ - uint_fast8_t u8NegDist; - struct uint128 z; - - if ( dist < 64 ) { - u8NegDist = -dist; - z.v64 = a64>>dist; - z.v0 = - a64<<(u8NegDist & 63) | a0>>dist - | ((uint64_t) (a0<<(u8NegDist & 63)) != 0); - } else { - z.v64 = 0; - z.v0 = - (dist < 127) - ? a64>>(dist & 63) - | (((a64 & (((uint_fast64_t) 1<<(dist & 63)) - 1)) | a0) - != 0) - : ((a64 | a0) != 0); - } - return z; - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/s_shiftRightJam128Extra.c b/deps/SoftFloat-3e/source/s_shiftRightJam128Extra.c deleted file mode 100644 index 75722887bdf7..000000000000 --- a/deps/SoftFloat-3e/source/s_shiftRightJam128Extra.c +++ /dev/null @@ -1,77 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "primitiveTypes.h" - -#ifndef softfloat_shiftRightJam128Extra - -struct uint128_extra - softfloat_shiftRightJam128Extra( - uint64_t a64, uint64_t a0, uint64_t extra, uint_fast32_t dist ) -{ - uint_fast8_t u8NegDist; - struct uint128_extra z; - - u8NegDist = -dist; - if ( dist < 64 ) { - z.v.v64 = a64>>dist; - z.v.v0 = a64<<(u8NegDist & 63) | a0>>dist; - z.extra = a0<<(u8NegDist & 63); - } else { - z.v.v64 = 0; - if ( dist == 64 ) { - z.v.v0 = a64; - z.extra = a0; - } else { - extra |= a0; - if ( dist < 128 ) { - z.v.v0 = a64>>(dist & 63); - z.extra = a64<<(u8NegDist & 63); - } else { - z.v.v0 = 0; - z.extra = (dist == 128) ? a64 : (a64 != 0); - } - } - } - z.extra |= (extra != 0); - return z; - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/s_shiftRightJam256M.c b/deps/SoftFloat-3e/source/s_shiftRightJam256M.c deleted file mode 100644 index 433870a81767..000000000000 --- a/deps/SoftFloat-3e/source/s_shiftRightJam256M.c +++ /dev/null @@ -1,126 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "primitiveTypes.h" - -#ifndef softfloat_shiftRightJam256M - -static - void - softfloat_shortShiftRightJamM( - uint_fast8_t size_words, - const uint64_t *aPtr, - uint_fast8_t dist, - uint64_t *zPtr - ) -{ - uint_fast8_t uNegDist; - unsigned int index, lastIndex; - uint64_t partWordZ, wordA; - - uNegDist = -dist; - index = indexWordLo( size_words ); - lastIndex = indexWordHi( size_words ); - wordA = aPtr[index]; - partWordZ = wordA>>dist; - if ( partWordZ<>dist; - } - zPtr[index] = partWordZ; - -} - -void - softfloat_shiftRightJam256M( - const uint64_t *aPtr, uint_fast32_t dist, uint64_t *zPtr ) -{ - uint64_t wordJam; - uint_fast32_t wordDist; - uint64_t *ptr; - uint_fast8_t i, innerDist; - - wordJam = 0; - wordDist = dist>>6; - if ( wordDist ) { - if ( 4 < wordDist ) wordDist = 4; - ptr = (uint64_t *) (aPtr + indexMultiwordLo( 4, wordDist )); - i = wordDist; - do { - wordJam = *ptr++; - if ( wordJam ) break; - --i; - } while ( i ); - ptr = zPtr; - } - if ( wordDist < 4 ) { - aPtr += indexMultiwordHiBut( 4, wordDist ); - innerDist = dist & 63; - if ( innerDist ) { - softfloat_shortShiftRightJamM( - 4 - wordDist, - aPtr, - innerDist, - zPtr + indexMultiwordLoBut( 4, wordDist ) - ); - if ( ! wordDist ) goto wordJam; - } else { - aPtr += indexWordLo( 4 - wordDist ); - ptr = zPtr + indexWordLo( 4 ); - for ( i = 4 - wordDist; i; --i ) { - *ptr = *aPtr; - aPtr += wordIncr; - ptr += wordIncr; - } - } - ptr = zPtr + indexMultiwordHi( 4, wordDist ); - } - do { - *ptr++ = 0; - --wordDist; - } while ( wordDist ); - wordJam: - if ( wordJam ) zPtr[indexWordLo( 4 )] |= 1; - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/s_shiftRightJam32.c b/deps/SoftFloat-3e/source/s_shiftRightJam32.c deleted file mode 100644 index 2533fcd95621..000000000000 --- a/deps/SoftFloat-3e/source/s_shiftRightJam32.c +++ /dev/null @@ -1,51 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" - -#ifndef softfloat_shiftRightJam32 - -uint32_t softfloat_shiftRightJam32( uint32_t a, uint_fast16_t dist ) -{ - - return - (dist < 31) ? a>>dist | ((uint32_t) (a<<(-dist & 31)) != 0) : (a != 0); - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/s_shiftRightJam64.c b/deps/SoftFloat-3e/source/s_shiftRightJam64.c deleted file mode 100644 index 4b40e3de68c0..000000000000 --- a/deps/SoftFloat-3e/source/s_shiftRightJam64.c +++ /dev/null @@ -1,51 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" - -#ifndef softfloat_shiftRightJam64 - -uint64_t softfloat_shiftRightJam64( uint64_t a, uint_fast32_t dist ) -{ - - return - (dist < 63) ? a>>dist | ((uint64_t) (a<<(-dist & 63)) != 0) : (a != 0); - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/s_shiftRightJam64Extra.c b/deps/SoftFloat-3e/source/s_shiftRightJam64Extra.c deleted file mode 100644 index b93fad39c944..000000000000 --- a/deps/SoftFloat-3e/source/s_shiftRightJam64Extra.c +++ /dev/null @@ -1,62 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "primitiveTypes.h" - -#ifndef softfloat_shiftRightJam64Extra - -struct uint64_extra - softfloat_shiftRightJam64Extra( - uint64_t a, uint64_t extra, uint_fast32_t dist ) -{ - struct uint64_extra z; - - if ( dist < 64 ) { - z.v = a>>dist; - z.extra = a<<(-dist & 63); - } else { - z.v = 0; - z.extra = (dist == 64) ? a : (a != 0); - } - z.extra |= (extra != 0); - return z; - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/s_shiftRightJamM.c b/deps/SoftFloat-3e/source/s_shiftRightJamM.c deleted file mode 100644 index edf5f956b9d5..000000000000 --- a/deps/SoftFloat-3e/source/s_shiftRightJamM.c +++ /dev/null @@ -1,101 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" - -#ifndef softfloat_shiftRightJamM - -#define softfloat_shiftRightJamM softfloat_shiftRightJamM -#include "primitives.h" - -void - softfloat_shiftRightJamM( - uint_fast8_t size_words, - const uint32_t *aPtr, - uint32_t dist, - uint32_t *zPtr - ) -{ - uint32_t wordJam, wordDist, *ptr; - uint_fast8_t i, innerDist; - - wordJam = 0; - wordDist = dist>>5; - if ( wordDist ) { - if ( size_words < wordDist ) wordDist = size_words; - ptr = (uint32_t *) (aPtr + indexMultiwordLo( size_words, wordDist )); - i = wordDist; - do { - wordJam = *ptr++; - if ( wordJam ) break; - --i; - } while ( i ); - ptr = zPtr; - } - if ( wordDist < size_words ) { - aPtr += indexMultiwordHiBut( size_words, wordDist ); - innerDist = dist & 31; - if ( innerDist ) { - softfloat_shortShiftRightJamM( - size_words - wordDist, - aPtr, - innerDist, - zPtr + indexMultiwordLoBut( size_words, wordDist ) - ); - if ( ! wordDist ) goto wordJam; - } else { - aPtr += indexWordLo( size_words - wordDist ); - ptr = zPtr + indexWordLo( size_words ); - for ( i = size_words - wordDist; i; --i ) { - *ptr = *aPtr; - aPtr += wordIncr; - ptr += wordIncr; - } - } - ptr = zPtr + indexMultiwordHi( size_words, wordDist ); - } - do { - *ptr++ = 0; - --wordDist; - } while ( wordDist ); - wordJam: - if ( wordJam ) zPtr[indexWordLo( size_words )] |= 1; - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/s_shiftRightM.c b/deps/SoftFloat-3e/source/s_shiftRightM.c deleted file mode 100644 index 00265ea238e2..000000000000 --- a/deps/SoftFloat-3e/source/s_shiftRightM.c +++ /dev/null @@ -1,91 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" - -#ifndef softfloat_shiftRightM - -#define softfloat_shiftRightM softfloat_shiftRightM -#include "primitives.h" - -void - softfloat_shiftRightM( - uint_fast8_t size_words, - const uint32_t *aPtr, - uint32_t dist, - uint32_t *zPtr - ) -{ - uint32_t wordDist; - uint_fast8_t innerDist; - uint32_t *destPtr; - uint_fast8_t i; - - wordDist = dist>>5; - if ( wordDist < size_words ) { - aPtr += indexMultiwordHiBut( size_words, wordDist ); - innerDist = dist & 31; - if ( innerDist ) { - softfloat_shortShiftRightM( - size_words - wordDist, - aPtr, - innerDist, - zPtr + indexMultiwordLoBut( size_words, wordDist ) - ); - if ( ! wordDist ) return; - } else { - aPtr += indexWordLo( size_words - wordDist ); - destPtr = zPtr + indexWordLo( size_words ); - for ( i = size_words - wordDist; i; --i ) { - *destPtr = *aPtr; - aPtr += wordIncr; - destPtr += wordIncr; - } - } - zPtr += indexMultiwordHi( size_words, wordDist ); - } else { - wordDist = size_words; - } - do { - *zPtr++ = 0; - --wordDist; - } while ( wordDist ); - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/s_shortShiftLeft128.c b/deps/SoftFloat-3e/source/s_shortShiftLeft128.c deleted file mode 100644 index 7513bc627288..000000000000 --- a/deps/SoftFloat-3e/source/s_shortShiftLeft128.c +++ /dev/null @@ -1,55 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "primitiveTypes.h" - -#ifndef softfloat_shortShiftLeft128 - -struct uint128 - softfloat_shortShiftLeft128( uint64_t a64, uint64_t a0, uint_fast8_t dist ) -{ - struct uint128 z; - - z.v64 = a64<>(-dist & 63); - z.v0 = a0< -#include "platform.h" -#include "primitiveTypes.h" - -#ifndef softfloat_shortShiftLeft64To96M - -void - softfloat_shortShiftLeft64To96M( - uint64_t a, uint_fast8_t dist, uint32_t *zPtr ) -{ - - zPtr[indexWord( 3, 0 )] = (uint32_t) a<>= 32 - dist; - zPtr[indexWord( 3, 2 )] = a>>32; - zPtr[indexWord( 3, 1 )] = a; - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/s_shortShiftLeftM.c b/deps/SoftFloat-3e/source/s_shortShiftLeftM.c deleted file mode 100644 index 48e6e03b542f..000000000000 --- a/deps/SoftFloat-3e/source/s_shortShiftLeftM.c +++ /dev/null @@ -1,70 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "primitiveTypes.h" - -#ifndef softfloat_shortShiftLeftM - -void - softfloat_shortShiftLeftM( - uint_fast8_t size_words, - const uint32_t *aPtr, - uint_fast8_t dist, - uint32_t *zPtr - ) -{ - uint_fast8_t uNegDist; - unsigned int index, lastIndex; - uint32_t partWordZ, wordA; - - uNegDist = -dist; - index = indexWordHi( size_words ); - lastIndex = indexWordLo( size_words ); - partWordZ = aPtr[index]<>(uNegDist & 31); - index -= wordIncr; - partWordZ = wordA< -#include "platform.h" -#include "primitiveTypes.h" - -#ifndef softfloat_shortShiftRight128 - -struct uint128 - softfloat_shortShiftRight128( uint64_t a64, uint64_t a0, uint_fast8_t dist ) -{ - struct uint128 z; - - z.v64 = a64>>dist; - z.v0 = a64<<(-dist & 63) | a0>>dist; - return z; - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/s_shortShiftRightExtendM.c b/deps/SoftFloat-3e/source/s_shortShiftRightExtendM.c deleted file mode 100644 index bc441c731afe..000000000000 --- a/deps/SoftFloat-3e/source/s_shortShiftRightExtendM.c +++ /dev/null @@ -1,73 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "primitiveTypes.h" - -#ifndef softfloat_shortShiftRightExtendM - -void - softfloat_shortShiftRightExtendM( - uint_fast8_t size_words, - const uint32_t *aPtr, - uint_fast8_t dist, - uint32_t *zPtr - ) -{ - uint_fast8_t uNegDist; - unsigned int indexA, lastIndexA; - uint32_t partWordZ, wordA; - - uNegDist = -dist; - indexA = indexWordLo( size_words ); - lastIndexA = indexWordHi( size_words ); - zPtr += indexWordLo( size_words + 1 ); - partWordZ = 0; - for (;;) { - wordA = aPtr[indexA]; - *zPtr = wordA<<(uNegDist & 31) | partWordZ; - zPtr += wordIncr; - partWordZ = wordA>>dist; - if ( indexA == lastIndexA ) break; - indexA += wordIncr; - } - *zPtr = partWordZ; - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/s_shortShiftRightJam128.c b/deps/SoftFloat-3e/source/s_shortShiftRightJam128.c deleted file mode 100644 index 76008722bf90..000000000000 --- a/deps/SoftFloat-3e/source/s_shortShiftRightJam128.c +++ /dev/null @@ -1,60 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "primitiveTypes.h" - -#ifndef softfloat_shortShiftRightJam128 - -struct uint128 - softfloat_shortShiftRightJam128( - uint64_t a64, uint64_t a0, uint_fast8_t dist ) -{ - uint_fast8_t uNegDist; - struct uint128 z; - - uNegDist = -dist; - z.v64 = a64>>dist; - z.v0 = - a64<<(uNegDist & 63) | a0>>dist - | ((uint64_t) (a0<<(uNegDist & 63)) != 0); - return z; - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/s_shortShiftRightJam128Extra.c b/deps/SoftFloat-3e/source/s_shortShiftRightJam128Extra.c deleted file mode 100644 index b0774401d65b..000000000000 --- a/deps/SoftFloat-3e/source/s_shortShiftRightJam128Extra.c +++ /dev/null @@ -1,59 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "primitiveTypes.h" - -#ifndef softfloat_shortShiftRightJam128Extra - -struct uint128_extra - softfloat_shortShiftRightJam128Extra( - uint64_t a64, uint64_t a0, uint64_t extra, uint_fast8_t dist ) -{ - uint_fast8_t uNegDist; - struct uint128_extra z; - - uNegDist = -dist; - z.v.v64 = a64>>dist; - z.v.v0 = a64<<(uNegDist & 63) | a0>>dist; - z.extra = a0<<(uNegDist & 63) | (extra != 0); - return z; - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/s_shortShiftRightJam64.c b/deps/SoftFloat-3e/source/s_shortShiftRightJam64.c deleted file mode 100644 index d3044c853752..000000000000 --- a/deps/SoftFloat-3e/source/s_shortShiftRightJam64.c +++ /dev/null @@ -1,50 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" - -#ifndef softfloat_shortShiftRightJam64 - -uint64_t softfloat_shortShiftRightJam64( uint64_t a, uint_fast8_t dist ) -{ - - return a>>dist | ((a & (((uint_fast64_t) 1< -#include "platform.h" -#include "primitiveTypes.h" - -#ifndef softfloat_shortShiftRightJam64Extra - -struct uint64_extra - softfloat_shortShiftRightJam64Extra( - uint64_t a, uint64_t extra, uint_fast8_t dist ) -{ - struct uint64_extra z; - - z.v = a>>dist; - z.extra = a<<(-dist & 63) | (extra != 0); - return z; - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/s_shortShiftRightJamM.c b/deps/SoftFloat-3e/source/s_shortShiftRightJamM.c deleted file mode 100644 index b567e482a8ae..000000000000 --- a/deps/SoftFloat-3e/source/s_shortShiftRightJamM.c +++ /dev/null @@ -1,72 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "primitiveTypes.h" - -#ifndef softfloat_shortShiftRightJamM - -void - softfloat_shortShiftRightJamM( - uint_fast8_t size_words, - const uint32_t *aPtr, - uint_fast8_t dist, - uint32_t *zPtr - ) -{ - uint_fast8_t uNegDist; - unsigned int index, lastIndex; - uint32_t partWordZ, wordA; - - uNegDist = -dist; - index = indexWordLo( size_words ); - lastIndex = indexWordHi( size_words ); - wordA = aPtr[index]; - partWordZ = wordA>>dist; - if ( partWordZ<>dist; - } - zPtr[index] = partWordZ; - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/s_shortShiftRightM.c b/deps/SoftFloat-3e/source/s_shortShiftRightM.c deleted file mode 100644 index 54e0071c7bf4..000000000000 --- a/deps/SoftFloat-3e/source/s_shortShiftRightM.c +++ /dev/null @@ -1,70 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "primitiveTypes.h" - -#ifndef softfloat_shortShiftRightM - -void - softfloat_shortShiftRightM( - uint_fast8_t size_words, - const uint32_t *aPtr, - uint_fast8_t dist, - uint32_t *zPtr - ) -{ - uint_fast8_t uNegDist; - unsigned int index, lastIndex; - uint32_t partWordZ, wordA; - - uNegDist = -dist; - index = indexWordLo( size_words ); - lastIndex = indexWordHi( size_words ); - partWordZ = aPtr[index]>>dist; - while ( index != lastIndex ) { - wordA = aPtr[index + wordIncr]; - zPtr[index] = wordA<<(uNegDist & 31) | partWordZ; - index += wordIncr; - partWordZ = wordA>>dist; - } - zPtr[index] = partWordZ; - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/s_sub128.c b/deps/SoftFloat-3e/source/s_sub128.c deleted file mode 100644 index 9bf346391010..000000000000 --- a/deps/SoftFloat-3e/source/s_sub128.c +++ /dev/null @@ -1,55 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "primitiveTypes.h" - -#ifndef softfloat_sub128 - -struct uint128 - softfloat_sub128( uint64_t a64, uint64_t a0, uint64_t b64, uint64_t b0 ) -{ - struct uint128 z; - - z.v0 = a0 - b0; - z.v64 = a64 - b64 - (a0 < b0); - return z; - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/s_sub1XM.c b/deps/SoftFloat-3e/source/s_sub1XM.c deleted file mode 100644 index 30c5d36eea7b..000000000000 --- a/deps/SoftFloat-3e/source/s_sub1XM.c +++ /dev/null @@ -1,60 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "primitiveTypes.h" - -#ifndef softfloat_sub1XM - -void softfloat_sub1XM( uint_fast8_t size_words, uint32_t *zPtr ) -{ - unsigned int index, lastIndex; - uint32_t wordA; - - index = indexWordLo( size_words ); - lastIndex = indexWordHi( size_words ); - for (;;) { - wordA = zPtr[index]; - zPtr[index] = wordA - 1; - if ( wordA || (index == lastIndex) ) break; - index += wordIncr; - } - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/s_sub256M.c b/deps/SoftFloat-3e/source/s_sub256M.c deleted file mode 100644 index a4af5a1c9524..000000000000 --- a/deps/SoftFloat-3e/source/s_sub256M.c +++ /dev/null @@ -1,65 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "primitiveTypes.h" - -#ifndef softfloat_sub256M - -void - softfloat_sub256M( - const uint64_t *aPtr, const uint64_t *bPtr, uint64_t *zPtr ) -{ - unsigned int index; - uint_fast8_t borrow; - uint64_t wordA, wordB; - - index = indexWordLo( 4 ); - borrow = 0; - for (;;) { - wordA = aPtr[index]; - wordB = bPtr[index]; - zPtr[index] = wordA - wordB - borrow; - if ( index == indexWordHi( 4 ) ) break; - borrow = borrow ? (wordA <= wordB) : (wordA < wordB); - index += wordIncr; - } - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/s_subM.c b/deps/SoftFloat-3e/source/s_subM.c deleted file mode 100644 index fcccc744cfac..000000000000 --- a/deps/SoftFloat-3e/source/s_subM.c +++ /dev/null @@ -1,70 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "primitiveTypes.h" - -#ifndef softfloat_subM - -void - softfloat_subM( - uint_fast8_t size_words, - const uint32_t *aPtr, - const uint32_t *bPtr, - uint32_t *zPtr - ) -{ - unsigned int index, lastIndex; - uint_fast8_t borrow; - uint32_t wordA, wordB; - - index = indexWordLo( size_words ); - lastIndex = indexWordHi( size_words ); - borrow = 0; - for (;;) { - wordA = aPtr[index]; - wordB = bPtr[index]; - zPtr[index] = wordA - wordB - borrow; - if ( index == lastIndex ) break; - borrow = borrow ? (wordA <= wordB) : (wordA < wordB); - index += wordIncr; - } - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/s_subMagsExtF80.c b/deps/SoftFloat-3e/source/s_subMagsExtF80.c deleted file mode 100644 index 0c46c61a2b9c..000000000000 --- a/deps/SoftFloat-3e/source/s_subMagsExtF80.c +++ /dev/null @@ -1,158 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -extFloat80_t - softfloat_subMagsExtF80( - uint_fast16_t uiA64, - uint_fast64_t uiA0, - uint_fast16_t uiB64, - uint_fast64_t uiB0, - bool signZ - ) -{ - int_fast32_t expA; - uint_fast64_t sigA; - int_fast32_t expB; - uint_fast64_t sigB; - int_fast32_t expDiff; - uint_fast16_t uiZ64; - uint_fast64_t uiZ0; - int_fast32_t expZ; - uint_fast64_t sigExtra; - struct uint128 sig128, uiZ; - union { struct extFloat80M s; extFloat80_t f; } uZ; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - expA = expExtF80UI64( uiA64 ); - sigA = uiA0; - expB = expExtF80UI64( uiB64 ); - sigB = uiB0; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - expDiff = expA - expB; - if ( 0 < expDiff ) goto expABigger; - if ( expDiff < 0 ) goto expBBigger; - if ( expA == 0x7FFF ) { - if ( (sigA | sigB) & UINT64_C( 0x7FFFFFFFFFFFFFFF ) ) { - goto propagateNaN; - } - softfloat_raiseFlags( softfloat_flag_invalid ); - uiZ64 = defaultNaNExtF80UI64; - uiZ0 = defaultNaNExtF80UI0; - goto uiZ; - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - expZ = expA; - if ( ! expZ ) expZ = 1; - sigExtra = 0; - if ( sigB < sigA ) goto aBigger; - if ( sigA < sigB ) goto bBigger; - uiZ64 = - packToExtF80UI64( (softfloat_roundingMode == softfloat_round_min), 0 ); - uiZ0 = 0; - goto uiZ; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - expBBigger: - if ( expB == 0x7FFF ) { - if ( sigB & UINT64_C( 0x7FFFFFFFFFFFFFFF ) ) goto propagateNaN; - uiZ64 = packToExtF80UI64( signZ ^ 1, 0x7FFF ); - uiZ0 = UINT64_C( 0x8000000000000000 ); - goto uiZ; - } - if ( ! expA ) { - ++expDiff; - sigExtra = 0; - if ( ! expDiff ) goto newlyAlignedBBigger; - } - sig128 = softfloat_shiftRightJam128( sigA, 0, -expDiff ); - sigA = sig128.v64; - sigExtra = sig128.v0; - newlyAlignedBBigger: - expZ = expB; - bBigger: - signZ = ! signZ; - sig128 = softfloat_sub128( sigB, 0, sigA, sigExtra ); - goto normRoundPack; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - expABigger: - if ( expA == 0x7FFF ) { - if ( sigA & UINT64_C( 0x7FFFFFFFFFFFFFFF ) ) goto propagateNaN; - uiZ64 = uiA64; - uiZ0 = uiA0; - goto uiZ; - } - if ( ! expB ) { - --expDiff; - sigExtra = 0; - if ( ! expDiff ) goto newlyAlignedABigger; - } - sig128 = softfloat_shiftRightJam128( sigB, 0, expDiff ); - sigB = sig128.v64; - sigExtra = sig128.v0; - newlyAlignedABigger: - expZ = expA; - aBigger: - sig128 = softfloat_sub128( sigA, 0, sigB, sigExtra ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - normRoundPack: - return - softfloat_normRoundPackToExtF80( - signZ, expZ, sig128.v64, sig128.v0, extF80_roundingPrecision ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - propagateNaN: - uiZ = softfloat_propagateNaNExtF80UI( uiA64, uiA0, uiB64, uiB0 ); - uiZ64 = uiZ.v64; - uiZ0 = uiZ.v0; - uiZ: - uZ.s.signExp = uiZ64; - uZ.s.signif = uiZ0; - return uZ.f; - -} - diff --git a/deps/SoftFloat-3e/source/s_subMagsF128.c b/deps/SoftFloat-3e/source/s_subMagsF128.c deleted file mode 100644 index e93543f096f9..000000000000 --- a/deps/SoftFloat-3e/source/s_subMagsF128.c +++ /dev/null @@ -1,139 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -float128_t - softfloat_subMagsF128( - uint_fast64_t uiA64, - uint_fast64_t uiA0, - uint_fast64_t uiB64, - uint_fast64_t uiB0, - bool signZ - ) -{ - int_fast32_t expA; - struct uint128 sigA; - int_fast32_t expB; - struct uint128 sigB, sigZ; - int_fast32_t expDiff, expZ; - struct uint128 uiZ; - union ui128_f128 uZ; - - expA = expF128UI64( uiA64 ); - sigA.v64 = fracF128UI64( uiA64 ); - sigA.v0 = uiA0; - expB = expF128UI64( uiB64 ); - sigB.v64 = fracF128UI64( uiB64 ); - sigB.v0 = uiB0; - sigA = softfloat_shortShiftLeft128( sigA.v64, sigA.v0, 4 ); - sigB = softfloat_shortShiftLeft128( sigB.v64, sigB.v0, 4 ); - expDiff = expA - expB; - if ( 0 < expDiff ) goto expABigger; - if ( expDiff < 0 ) goto expBBigger; - if ( expA == 0x7FFF ) { - if ( sigA.v64 | sigA.v0 | sigB.v64 | sigB.v0 ) goto propagateNaN; - softfloat_raiseFlags( softfloat_flag_invalid ); - uiZ.v64 = defaultNaNF128UI64; - uiZ.v0 = defaultNaNF128UI0; - goto uiZ; - } - expZ = expA; - if ( ! expZ ) expZ = 1; - if ( sigB.v64 < sigA.v64 ) goto aBigger; - if ( sigA.v64 < sigB.v64 ) goto bBigger; - if ( sigB.v0 < sigA.v0 ) goto aBigger; - if ( sigA.v0 < sigB.v0 ) goto bBigger; - uiZ.v64 = - packToF128UI64( - (softfloat_roundingMode == softfloat_round_min), 0, 0 ); - uiZ.v0 = 0; - goto uiZ; - expBBigger: - if ( expB == 0x7FFF ) { - if ( sigB.v64 | sigB.v0 ) goto propagateNaN; - uiZ.v64 = packToF128UI64( signZ ^ 1, 0x7FFF, 0 ); - uiZ.v0 = 0; - goto uiZ; - } - if ( expA ) { - sigA.v64 |= UINT64_C( 0x0010000000000000 ); - } else { - ++expDiff; - if ( ! expDiff ) goto newlyAlignedBBigger; - } - sigA = softfloat_shiftRightJam128( sigA.v64, sigA.v0, -expDiff ); - newlyAlignedBBigger: - expZ = expB; - sigB.v64 |= UINT64_C( 0x0010000000000000 ); - bBigger: - signZ = ! signZ; - sigZ = softfloat_sub128( sigB.v64, sigB.v0, sigA.v64, sigA.v0 ); - goto normRoundPack; - expABigger: - if ( expA == 0x7FFF ) { - if ( sigA.v64 | sigA.v0 ) goto propagateNaN; - uiZ.v64 = uiA64; - uiZ.v0 = uiA0; - goto uiZ; - } - if ( expB ) { - sigB.v64 |= UINT64_C( 0x0010000000000000 ); - } else { - --expDiff; - if ( ! expDiff ) goto newlyAlignedABigger; - } - sigB = softfloat_shiftRightJam128( sigB.v64, sigB.v0, expDiff ); - newlyAlignedABigger: - expZ = expA; - sigA.v64 |= UINT64_C( 0x0010000000000000 ); - aBigger: - sigZ = softfloat_sub128( sigA.v64, sigA.v0, sigB.v64, sigB.v0 ); - normRoundPack: - return softfloat_normRoundPackToF128( signZ, expZ - 5, sigZ.v64, sigZ.v0 ); - propagateNaN: - uiZ = softfloat_propagateNaNF128UI( uiA64, uiA0, uiB64, uiB0 ); - uiZ: - uZ.ui = uiZ; - return uZ.f; - -} - diff --git a/deps/SoftFloat-3e/source/s_subMagsF16.c b/deps/SoftFloat-3e/source/s_subMagsF16.c deleted file mode 100644 index ae1417ea9441..000000000000 --- a/deps/SoftFloat-3e/source/s_subMagsF16.c +++ /dev/null @@ -1,187 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017 The Regents of the -University of California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -float16_t softfloat_subMagsF16( uint_fast16_t uiA, uint_fast16_t uiB ) -{ - int_fast8_t expA; - uint_fast16_t sigA; - int_fast8_t expB; - uint_fast16_t sigB; - int_fast8_t expDiff; - uint_fast16_t uiZ; - int_fast16_t sigDiff; - bool signZ; - int_fast8_t shiftDist, expZ; - uint_fast16_t sigZ, sigX, sigY; - uint_fast32_t sig32Z; - int_fast8_t roundingMode; - union ui16_f16 uZ; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - expA = expF16UI( uiA ); - sigA = fracF16UI( uiA ); - expB = expF16UI( uiB ); - sigB = fracF16UI( uiB ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - expDiff = expA - expB; - if ( ! expDiff ) { - /*-------------------------------------------------------------------- - *--------------------------------------------------------------------*/ - if ( expA == 0x1F ) { - if ( sigA | sigB ) goto propagateNaN; - softfloat_raiseFlags( softfloat_flag_invalid ); - uiZ = defaultNaNF16UI; - goto uiZ; - } - sigDiff = sigA - sigB; - if ( ! sigDiff ) { - uiZ = - packToF16UI( - (softfloat_roundingMode == softfloat_round_min), 0, 0 ); - goto uiZ; - } - if ( expA ) --expA; - signZ = signF16UI( uiA ); - if ( sigDiff < 0 ) { - signZ = ! signZ; - sigDiff = -sigDiff; - } - shiftDist = softfloat_countLeadingZeros16( sigDiff ) - 5; - expZ = expA - shiftDist; - if ( expZ < 0 ) { - shiftDist = expA; - expZ = 0; - } - sigZ = sigDiff<>16; - if ( sig32Z & 0xFFFF ) { - sigZ |= 1; - } else { - if ( ! (sigZ & 0xF) && ((unsigned int) expZ < 0x1E) ) { - sigZ >>= 4; - goto pack; - } - } - return softfloat_roundPackToF16( signZ, expZ, sigZ ); - } - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - propagateNaN: - uiZ = softfloat_propagateNaNF16UI( uiA, uiB ); - goto uiZ; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - subEpsilon: - roundingMode = softfloat_roundingMode; - if ( roundingMode != softfloat_round_near_even ) { - if ( - (roundingMode == softfloat_round_minMag) - || (roundingMode - == (signF16UI( uiZ ) ? softfloat_round_max - : softfloat_round_min)) - ) { - --uiZ; - } -#ifdef SOFTFLOAT_ROUND_ODD - else if ( roundingMode == softfloat_round_odd ) { - uiZ = (uiZ - 1) | 1; - } -#endif - } - softfloat_exceptionFlags |= softfloat_flag_inexact; - goto uiZ; - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - pack: - uiZ = packToF16UI( signZ, expZ, sigZ ); - uiZ: - uZ.ui = uiZ; - return uZ.f; - -} - diff --git a/deps/SoftFloat-3e/source/s_subMagsF32.c b/deps/SoftFloat-3e/source/s_subMagsF32.c deleted file mode 100644 index 0c1f32ed6f89..000000000000 --- a/deps/SoftFloat-3e/source/s_subMagsF32.c +++ /dev/null @@ -1,143 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of -California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -float32_t softfloat_subMagsF32( uint_fast32_t uiA, uint_fast32_t uiB ) -{ - int_fast16_t expA; - uint_fast32_t sigA; - int_fast16_t expB; - uint_fast32_t sigB; - int_fast16_t expDiff; - uint_fast32_t uiZ; - int_fast32_t sigDiff; - bool signZ; - int_fast8_t shiftDist; - int_fast16_t expZ; - uint_fast32_t sigX, sigY; - union ui32_f32 uZ; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - expA = expF32UI( uiA ); - sigA = fracF32UI( uiA ); - expB = expF32UI( uiB ); - sigB = fracF32UI( uiB ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - expDiff = expA - expB; - if ( ! expDiff ) { - /*-------------------------------------------------------------------- - *--------------------------------------------------------------------*/ - if ( expA == 0xFF ) { - if ( sigA | sigB ) goto propagateNaN; - softfloat_raiseFlags( softfloat_flag_invalid ); - uiZ = defaultNaNF32UI; - goto uiZ; - } - sigDiff = sigA - sigB; - if ( ! sigDiff ) { - uiZ = - packToF32UI( - (softfloat_roundingMode == softfloat_round_min), 0, 0 ); - goto uiZ; - } - if ( expA ) --expA; - signZ = signF32UI( uiA ); - if ( sigDiff < 0 ) { - signZ = ! signZ; - sigDiff = -sigDiff; - } - shiftDist = softfloat_countLeadingZeros32( sigDiff ) - 8; - expZ = expA - shiftDist; - if ( expZ < 0 ) { - shiftDist = expA; - expZ = 0; - } - uiZ = packToF32UI( signZ, expZ, sigDiff< -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -float64_t - softfloat_subMagsF64( uint_fast64_t uiA, uint_fast64_t uiB, bool signZ ) -{ - int_fast16_t expA; - uint_fast64_t sigA; - int_fast16_t expB; - uint_fast64_t sigB; - int_fast16_t expDiff; - uint_fast64_t uiZ; - int_fast64_t sigDiff; - int_fast8_t shiftDist; - int_fast16_t expZ; - uint_fast64_t sigZ; - union ui64_f64 uZ; - - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - expA = expF64UI( uiA ); - sigA = fracF64UI( uiA ); - expB = expF64UI( uiB ); - sigB = fracF64UI( uiB ); - /*------------------------------------------------------------------------ - *------------------------------------------------------------------------*/ - expDiff = expA - expB; - if ( ! expDiff ) { - /*-------------------------------------------------------------------- - *--------------------------------------------------------------------*/ - if ( expA == 0x7FF ) { - if ( sigA | sigB ) goto propagateNaN; - softfloat_raiseFlags( softfloat_flag_invalid ); - uiZ = defaultNaNF64UI; - goto uiZ; - } - sigDiff = sigA - sigB; - if ( ! sigDiff ) { - uiZ = - packToF64UI( - (softfloat_roundingMode == softfloat_round_min), 0, 0 ); - goto uiZ; - } - if ( expA ) --expA; - if ( sigDiff < 0 ) { - signZ = ! signZ; - sigDiff = -sigDiff; - } - shiftDist = softfloat_countLeadingZeros64( sigDiff ) - 11; - expZ = expA - shiftDist; - if ( expZ < 0 ) { - shiftDist = expA; - expZ = 0; - } - uiZ = packToF64UI( signZ, expZ, sigDiff< -#include "platform.h" -#include "internals.h" -#include "specialize.h" - -bool - softfloat_tryPropagateNaNExtF80M( - const struct extFloat80M *aSPtr, - const struct extFloat80M *bSPtr, - struct extFloat80M *zSPtr - ) -{ - uint_fast16_t ui64; - uint64_t ui0; - - ui64 = aSPtr->signExp; - ui0 = aSPtr->signif; - if ( isNaNExtF80UI( ui64, ui0 ) ) goto propagateNaN; - ui64 = bSPtr->signExp; - ui0 = bSPtr->signif; - if ( isNaNExtF80UI( ui64, ui0 ) ) goto propagateNaN; - return false; - propagateNaN: - softfloat_propagateNaNExtF80M( aSPtr, bSPtr, zSPtr ); - return true; - -} - diff --git a/deps/SoftFloat-3e/source/s_tryPropagateNaNF128M.c b/deps/SoftFloat-3e/source/s_tryPropagateNaNF128M.c deleted file mode 100644 index bab04a7c0859..000000000000 --- a/deps/SoftFloat-3e/source/s_tryPropagateNaNF128M.c +++ /dev/null @@ -1,55 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" - -bool - softfloat_tryPropagateNaNF128M( - const uint32_t *aWPtr, const uint32_t *bWPtr, uint32_t *zWPtr ) -{ - - if ( softfloat_isNaNF128M( aWPtr ) || softfloat_isNaNF128M( bWPtr ) ) { - softfloat_propagateNaNF128M( aWPtr, bWPtr, zWPtr ); - return true; - } - return false; - -} - diff --git a/deps/SoftFloat-3e/source/softfloat_state.c b/deps/SoftFloat-3e/source/softfloat_state.c deleted file mode 100644 index 0f296654fd48..000000000000 --- a/deps/SoftFloat-3e/source/softfloat_state.c +++ /dev/null @@ -1,52 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of -California. All Rights Reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "internals.h" -#include "specialize.h" -#include "softfloat.h" - -#ifndef THREAD_LOCAL -#define THREAD_LOCAL -#endif - -THREAD_LOCAL uint_fast8_t softfloat_roundingMode = softfloat_round_near_even; -THREAD_LOCAL uint_fast8_t softfloat_detectTininess = init_detectTininess; -THREAD_LOCAL uint_fast8_t softfloat_exceptionFlags = 0; - -THREAD_LOCAL uint_fast8_t extF80_roundingPrecision = 80; - diff --git a/deps/SoftFloat-3e/source/ui32_to_extF80.c b/deps/SoftFloat-3e/source/ui32_to_extF80.c deleted file mode 100644 index 34f79368f2fe..000000000000 --- a/deps/SoftFloat-3e/source/ui32_to_extF80.c +++ /dev/null @@ -1,59 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of -California. All Rights Reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "internals.h" -#include "softfloat.h" - -extFloat80_t ui32_to_extF80( uint32_t a ) -{ - uint_fast16_t uiZ64; - int_fast8_t shiftDist; - union { struct extFloat80M s; extFloat80_t f; } uZ; - - uiZ64 = 0; - if ( a ) { - shiftDist = softfloat_countLeadingZeros32( a ); - uiZ64 = 0x401E - shiftDist; - a <<= shiftDist; - } - uZ.s.signExp = uiZ64; - uZ.s.signif = (uint_fast64_t) a<<32; - return uZ.f; - -} - diff --git a/deps/SoftFloat-3e/source/ui32_to_extF80M.c b/deps/SoftFloat-3e/source/ui32_to_extF80M.c deleted file mode 100644 index 0a0c098c0051..000000000000 --- a/deps/SoftFloat-3e/source/ui32_to_extF80M.c +++ /dev/null @@ -1,74 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of -California. All Rights Reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "internals.h" -#include "softfloat.h" - -#ifdef SOFTFLOAT_FAST_INT64 - -void ui32_to_extF80M( uint32_t a, extFloat80_t *zPtr ) -{ - - *zPtr = ui32_to_extF80( a ); - -} - -#else - -void ui32_to_extF80M( uint32_t a, extFloat80_t *zPtr ) -{ - struct extFloat80M *zSPtr; - uint_fast16_t uiZ64; - uint64_t sigZ; - int_fast8_t shiftDist; - - zSPtr = (struct extFloat80M *) zPtr; - uiZ64 = 0; - sigZ = 0; - if ( a ) { - shiftDist = softfloat_countLeadingZeros32( a ); - uiZ64 = packToExtF80UI64( 0, 0x401E - shiftDist ); - sigZ = (uint64_t) (a<signExp = uiZ64; - zSPtr->signif = sigZ; - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/ui32_to_f128.c b/deps/SoftFloat-3e/source/ui32_to_f128.c deleted file mode 100644 index c3ab53daf7ce..000000000000 --- a/deps/SoftFloat-3e/source/ui32_to_f128.c +++ /dev/null @@ -1,60 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of -California. All Rights Reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "internals.h" -#include "softfloat.h" - -float128_t ui32_to_f128( uint32_t a ) -{ - uint_fast64_t uiZ64; - int_fast8_t shiftDist; - union ui128_f128 uZ; - - uiZ64 = 0; - if ( a ) { - shiftDist = softfloat_countLeadingZeros32( a ) + 17; - uiZ64 = - packToF128UI64( - 0, 0x402E - shiftDist, (uint_fast64_t) a< -#include "platform.h" -#include "internals.h" -#include "softfloat.h" - -#ifdef SOFTFLOAT_FAST_INT64 - -void ui32_to_f128M( uint32_t a, float128_t *zPtr ) -{ - - *zPtr = ui32_to_f128( a ); - -} - -#else - -void ui32_to_f128M( uint32_t a, float128_t *zPtr ) -{ - uint32_t *zWPtr, uiZ96, uiZ64; - int_fast8_t shiftDist; - uint64_t normA; - - zWPtr = (uint32_t *) zPtr; - uiZ96 = 0; - uiZ64 = 0; - if ( a ) { - shiftDist = softfloat_countLeadingZeros32( a ) + 17; - normA = (uint64_t) a<>32 ); - uiZ64 = normA; - } - zWPtr[indexWord( 4, 3 )] = uiZ96; - zWPtr[indexWord( 4, 2 )] = uiZ64; - zWPtr[indexWord( 4, 1 )] = 0; - zWPtr[indexWord( 4, 0 )] = 0; - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/ui32_to_f16.c b/deps/SoftFloat-3e/source/ui32_to_f16.c deleted file mode 100644 index 6fc377bca14c..000000000000 --- a/deps/SoftFloat-3e/source/ui32_to_f16.c +++ /dev/null @@ -1,65 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of -California. All Rights Reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "internals.h" -#include "softfloat.h" - -float16_t ui32_to_f16( uint32_t a ) -{ - int_fast8_t shiftDist; - union ui16_f16 u; - uint_fast16_t sig; - - shiftDist = softfloat_countLeadingZeros32( a ) - 21; - if ( 0 <= shiftDist ) { - u.ui = - a ? packToF16UI( - 0, 0x18 - shiftDist, (uint_fast16_t) a<>(-shiftDist) | ((uint32_t) (a<<(shiftDist & 31)) != 0) - : (uint_fast16_t) a< -#include "platform.h" -#include "internals.h" -#include "softfloat.h" - -float32_t ui32_to_f32( uint32_t a ) -{ - union ui32_f32 uZ; - - if ( ! a ) { - uZ.ui = 0; - return uZ.f; - } - if ( a & 0x80000000 ) { - return softfloat_roundPackToF32( 0, 0x9D, a>>1 | (a & 1) ); - } else { - return softfloat_normRoundPackToF32( 0, 0x9C, a ); - } - -} - diff --git a/deps/SoftFloat-3e/source/ui32_to_f64.c b/deps/SoftFloat-3e/source/ui32_to_f64.c deleted file mode 100644 index 504f96e6e2b4..000000000000 --- a/deps/SoftFloat-3e/source/ui32_to_f64.c +++ /dev/null @@ -1,59 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of -California. All Rights Reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "internals.h" -#include "softfloat.h" - -float64_t ui32_to_f64( uint32_t a ) -{ - uint_fast64_t uiZ; - int_fast8_t shiftDist; - union ui64_f64 uZ; - - if ( ! a ) { - uiZ = 0; - } else { - shiftDist = softfloat_countLeadingZeros32( a ) + 21; - uiZ = - packToF64UI( 0, 0x432 - shiftDist, (uint_fast64_t) a< -#include "platform.h" -#include "internals.h" -#include "softfloat.h" - -extFloat80_t ui64_to_extF80( uint64_t a ) -{ - uint_fast16_t uiZ64; - int_fast8_t shiftDist; - union { struct extFloat80M s; extFloat80_t f; } uZ; - - uiZ64 = 0; - if ( a ) { - shiftDist = softfloat_countLeadingZeros64( a ); - uiZ64 = 0x403E - shiftDist; - a <<= shiftDist; - } - uZ.s.signExp = uiZ64; - uZ.s.signif = a; - return uZ.f; - -} - diff --git a/deps/SoftFloat-3e/source/ui64_to_extF80M.c b/deps/SoftFloat-3e/source/ui64_to_extF80M.c deleted file mode 100644 index e676d904a4a0..000000000000 --- a/deps/SoftFloat-3e/source/ui64_to_extF80M.c +++ /dev/null @@ -1,74 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of -California. All Rights Reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "internals.h" -#include "softfloat.h" - -#ifdef SOFTFLOAT_FAST_INT64 - -void ui64_to_extF80M( uint64_t a, extFloat80_t *zPtr ) -{ - - *zPtr = ui64_to_extF80( a ); - -} - -#else - -void ui64_to_extF80M( uint64_t a, extFloat80_t *zPtr ) -{ - struct extFloat80M *zSPtr; - uint_fast16_t uiZ64; - uint64_t sigZ; - int_fast8_t shiftDist; - - zSPtr = (struct extFloat80M *) zPtr; - uiZ64 = 0; - sigZ = 0; - if ( a ) { - shiftDist = softfloat_countLeadingZeros64( a ); - uiZ64 = packToExtF80UI64( 0, 0x403E - shiftDist ); - sigZ = a<signExp = uiZ64; - zSPtr->signif = sigZ; - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/ui64_to_f128.c b/deps/SoftFloat-3e/source/ui64_to_f128.c deleted file mode 100644 index 6ff6a6fcfa57..000000000000 --- a/deps/SoftFloat-3e/source/ui64_to_f128.c +++ /dev/null @@ -1,68 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of -California. All Rights Reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "internals.h" -#include "softfloat.h" - -float128_t ui64_to_f128( uint64_t a ) -{ - uint_fast64_t uiZ64, uiZ0; - int_fast8_t shiftDist; - struct uint128 zSig; - union ui128_f128 uZ; - - if ( ! a ) { - uiZ64 = 0; - uiZ0 = 0; - } else { - shiftDist = softfloat_countLeadingZeros64( a ) + 49; - if ( 64 <= shiftDist ) { - zSig.v64 = a<<(shiftDist - 64); - zSig.v0 = 0; - } else { - zSig = softfloat_shortShiftLeft128( 0, a, shiftDist ); - } - uiZ64 = packToF128UI64( 0, 0x406E - shiftDist, zSig.v64 ); - uiZ0 = zSig.v0; - } - uZ.ui.v64 = uiZ64; - uZ.ui.v0 = uiZ0; - return uZ.f; - -} - diff --git a/deps/SoftFloat-3e/source/ui64_to_f128M.c b/deps/SoftFloat-3e/source/ui64_to_f128M.c deleted file mode 100644 index 043406cc4f83..000000000000 --- a/deps/SoftFloat-3e/source/ui64_to_f128M.c +++ /dev/null @@ -1,86 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of -California. All Rights Reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "internals.h" -#include "softfloat.h" - -#ifdef SOFTFLOAT_FAST_INT64 - -void ui64_to_f128M( uint64_t a, float128_t *zPtr ) -{ - - *zPtr = ui64_to_f128( a ); - -} - -#else - -void ui64_to_f128M( uint64_t a, float128_t *zPtr ) -{ - uint32_t *zWPtr, uiZ96, uiZ64; - uint_fast8_t shiftDist; - uint32_t *ptr; - - zWPtr = (uint32_t *) zPtr; - uiZ96 = 0; - uiZ64 = 0; - zWPtr[indexWord( 4, 1 )] = 0; - zWPtr[indexWord( 4, 0 )] = 0; - if ( a ) { - shiftDist = softfloat_countLeadingZeros64( a ) + 17; - if ( shiftDist < 32 ) { - ptr = zWPtr + indexMultiwordHi( 4, 3 ); - ptr[indexWord( 3, 2 )] = 0; - ptr[indexWord( 3, 1 )] = a>>32; - ptr[indexWord( 3, 0 )] = a; - softfloat_shortShiftLeft96M( ptr, shiftDist, ptr ); - ptr[indexWordHi( 3 )] = - packToF128UI96( 0, 0x404E - shiftDist, ptr[indexWordHi( 3 )] ); - return; - } - a <<= shiftDist - 32; - uiZ96 = packToF128UI96( 0, 0x404E - shiftDist, a>>32 ); - uiZ64 = a; - } - zWPtr[indexWord( 4, 3 )] = uiZ96; - zWPtr[indexWord( 4, 2 )] = uiZ64; - -} - -#endif - diff --git a/deps/SoftFloat-3e/source/ui64_to_f16.c b/deps/SoftFloat-3e/source/ui64_to_f16.c deleted file mode 100644 index 3d58e85cf647..000000000000 --- a/deps/SoftFloat-3e/source/ui64_to_f16.c +++ /dev/null @@ -1,64 +0,0 @@ - -/*============================================================================ - -This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic -Package, Release 3e, by John R. Hauser. - -Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of -California. All Rights Reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the University nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================*/ - -#include -#include "platform.h" -#include "internals.h" -#include "softfloat.h" - -float16_t ui64_to_f16( uint64_t a ) -{ - int_fast8_t shiftDist; - union ui16_f16 u; - uint_fast16_t sig; - - shiftDist = softfloat_countLeadingZeros64( a ) - 53; - if ( 0 <= shiftDist ) { - u.ui = - a ? packToF16UI( - 0, 0x18 - shiftDist, (uint_fast16_t) a< -#include "platform.h" -#include "internals.h" -#include "softfloat.h" - -float32_t ui64_to_f32( uint64_t a ) -{ - int_fast8_t shiftDist; - union ui32_f32 u; - uint_fast32_t sig; - - shiftDist = softfloat_countLeadingZeros64( a ) - 40; - if ( 0 <= shiftDist ) { - u.ui = - a ? packToF32UI( - 0, 0x95 - shiftDist, (uint_fast32_t) a< -#include "platform.h" -#include "internals.h" -#include "softfloat.h" - -float64_t ui64_to_f64( uint64_t a ) -{ - union ui64_f64 uZ; - - if ( ! a ) { - uZ.ui = 0; - return uZ.f; - } - if ( a & UINT64_C( 0x8000000000000000 ) ) { - return - softfloat_roundPackToF64( - 0, 0x43D, softfloat_shortShiftRightJam64( a, 1 ) ); - } else { - return softfloat_normRoundPackToF64( 0, 0x43C, a ); - } - -} - diff --git a/doc/langref.html.in b/doc/langref.html.in index bf2a6fd71d6c..b2e408dda774 100644 --- a/doc/langref.html.in +++ b/doc/langref.html.in @@ -10961,24 +10961,28 @@ pub fn main() !void { {#code_begin|exe|preopens#} {#target_wasi#} const std = @import("std"); -const PreopenList = std.fs.wasi.PreopenList; +const fs = std.fs; pub fn main() !void { var general_purpose_allocator = std.heap.GeneralPurposeAllocator(.{}){}; const gpa = general_purpose_allocator.allocator(); - var preopens = PreopenList.init(gpa); - defer preopens.deinit(); + var arena_instance = std.heap.ArenaAllocator.init(gpa); + defer arena_instance.deinit(); + const arena = arena_instance.allocator(); - try preopens.populate(null); + const preopens = try fs.wasi.preopensAlloc(arena); - for (preopens.asSlice()) |preopen, i| { - std.debug.print("{}: {}\n", .{ i, preopen }); + for (preopens.names) |preopen, i| { + std.debug.print("{}: {s}\n", .{ i, preopen }); } } {#code_end#} {#shell_samp#}$ wasmtime --dir=. preopens.wasm -0: Preopen{ .fd = 3, .type = PreopenType{ .Dir = '.' } } +0: stdin +1: stdout +2: stderr +3: . {#end_shell_samp#} {#header_close#} {#header_close#} diff --git a/lib/build_runner.zig b/lib/build_runner.zig index 510bae4a521e..735ddb9de185 100644 --- a/lib/build_runner.zig +++ b/lib/build_runner.zig @@ -183,10 +183,6 @@ pub fn main() !void { builder.enable_darling = true; } else if (mem.eql(u8, arg, "-fno-darling")) { builder.enable_darling = false; - } else if (mem.eql(u8, arg, "-fstage1")) { - builder.use_stage1 = true; - } else if (mem.eql(u8, arg, "-fno-stage1")) { - builder.use_stage1 = false; } else if (mem.eql(u8, arg, "-freference-trace")) { builder.reference_trace = 256; } else if (mem.startsWith(u8, arg, "-freference-trace=")) { @@ -318,8 +314,6 @@ fn usage(builder: *Builder, already_ran_build: bool, out_stream: anytype) !void try out_stream.writeAll( \\ \\Advanced Options: - \\ -fstage1 Force using bootstrap compiler as the codegen backend - \\ -fno-stage1 Prevent using bootstrap compiler as the codegen backend \\ -freference-trace[=num] How many lines of reference trace should be shown per compile error \\ -fno-reference-trace Disable reference trace \\ --build-file [file] Override path to build.zig diff --git a/lib/compiler_rt.zig b/lib/compiler_rt.zig index 44146d04e930..5cce3daf29e2 100644 --- a/lib/compiler_rt.zig +++ b/lib/compiler_rt.zig @@ -3,13 +3,6 @@ const builtin = @import("builtin"); pub const panic = @import("compiler_rt/common.zig").panic; comptime { - _ = @import("compiler_rt/atomics.zig"); - - // macOS has these functions inside libSystem. - if (builtin.cpu.arch.isAARCH64() and !builtin.os.tag.isDarwin()) { - _ = @import("compiler_rt/aarch64_outline_atomics.zig"); - } - _ = @import("compiler_rt/addf3.zig"); _ = @import("compiler_rt/addhf3.zig"); _ = @import("compiler_rt/addsf3.zig"); @@ -115,7 +108,6 @@ comptime { _ = @import("compiler_rt/sqrt.zig"); _ = @import("compiler_rt/tan.zig"); _ = @import("compiler_rt/trunc.zig"); - _ = @import("compiler_rt/stack_probe.zig"); _ = @import("compiler_rt/divti3.zig"); _ = @import("compiler_rt/modti3.zig"); _ = @import("compiler_rt/multi3.zig"); @@ -216,9 +208,19 @@ comptime { _ = @import("compiler_rt/aullrem.zig"); _ = @import("compiler_rt/clear_cache.zig"); - _ = @import("compiler_rt/memcpy.zig"); - _ = @import("compiler_rt/memset.zig"); - _ = @import("compiler_rt/memmove.zig"); - _ = @import("compiler_rt/memcmp.zig"); - _ = @import("compiler_rt/bcmp.zig"); + if (@import("builtin").object_format != .c) { + _ = @import("compiler_rt/atomics.zig"); + _ = @import("compiler_rt/stack_probe.zig"); + + // macOS has these functions inside libSystem. + if (builtin.cpu.arch.isAARCH64() and !builtin.os.tag.isDarwin()) { + _ = @import("compiler_rt/aarch64_outline_atomics.zig"); + } + + _ = @import("compiler_rt/memcpy.zig"); + _ = @import("compiler_rt/memset.zig"); + _ = @import("compiler_rt/memmove.zig"); + _ = @import("compiler_rt/memcmp.zig"); + _ = @import("compiler_rt/bcmp.zig"); + } } diff --git a/lib/compiler_rt/common.zig b/lib/compiler_rt/common.zig index 2d373031e5e8..f16ecf0e188a 100644 --- a/lib/compiler_rt/common.zig +++ b/lib/compiler_rt/common.zig @@ -20,7 +20,7 @@ pub const want_ppc_abi = builtin.cpu.arch.isPPC() or builtin.cpu.arch.isPPC64(); // Libcalls that involve u128 on Windows x86-64 are expected by LLVM to use the // calling convention of @Vector(2, u64), rather than what's standard. -pub const want_windows_v2u64_abi = builtin.os.tag == .windows and builtin.cpu.arch == .x86_64; +pub const want_windows_v2u64_abi = builtin.os.tag == .windows and builtin.cpu.arch == .x86_64 and @import("builtin").object_format != .c; /// This governs whether to use these symbol names for f16/f32 conversions /// rather than the standard names: diff --git a/lib/std/build.zig b/lib/std/build.zig index 77f0779c603e..73487d8ea9ab 100644 --- a/lib/std/build.zig +++ b/lib/std/build.zig @@ -46,7 +46,6 @@ pub const Builder = struct { prominent_compile_errors: bool, color: enum { auto, on, off } = .auto, reference_trace: ?u32 = null, - use_stage1: ?bool = null, invalid_user_input: bool, zig_exe: []const u8, default_step: *Step, @@ -1621,7 +1620,6 @@ pub const LibExeObjStep = struct { stack_size: ?u64 = null, want_lto: ?bool = null, - use_stage1: ?bool = null, use_llvm: ?bool = null, use_lld: ?bool = null, @@ -2467,20 +2465,6 @@ pub const LibExeObjStep = struct { try zig_args.append(try std.fmt.allocPrint(builder.allocator, "-freference-trace={d}", .{some})); } - if (self.use_stage1) |stage1| { - if (stage1) { - try zig_args.append("-fstage1"); - } else { - try zig_args.append("-fno-stage1"); - } - } else if (builder.use_stage1) |stage1| { - if (stage1) { - try zig_args.append("-fstage1"); - } else { - try zig_args.append("-fno-stage1"); - } - } - if (self.use_llvm) |use_llvm| { if (use_llvm) { try zig_args.append("-fLLVM"); diff --git a/lib/std/build/TranslateCStep.zig b/lib/std/build/TranslateCStep.zig index 7d7f2a62a46b..1f9bee463c74 100644 --- a/lib/std/build/TranslateCStep.zig +++ b/lib/std/build/TranslateCStep.zig @@ -21,7 +21,6 @@ output_dir: ?[]const u8, out_basename: []const u8, target: CrossTarget = CrossTarget{}, output_file: build.GeneratedFile, -use_stage1: ?bool = null, pub fn create(builder: *Builder, source: build.FileSource) *TranslateCStep { const self = builder.allocator.create(TranslateCStep) catch unreachable; @@ -92,19 +91,6 @@ fn make(step: *Step) !void { try argv_list.append("-D"); try argv_list.append(c_macro); } - if (self.use_stage1) |stage1| { - if (stage1) { - try argv_list.append("-fstage1"); - } else { - try argv_list.append("-fno-stage1"); - } - } else if (self.builder.use_stage1) |stage1| { - if (stage1) { - try argv_list.append("-fstage1"); - } else { - try argv_list.append("-fno-stage1"); - } - } try argv_list.append(self.source.getPath(self.builder)); diff --git a/lib/std/fmt.zig b/lib/std/fmt.zig index 6aac7386c97d..ac7f88ca9dec 100644 --- a/lib/std/fmt.zig +++ b/lib/std/fmt.zig @@ -827,7 +827,7 @@ fn formatSliceHexImpl(comptime case: Case) type { const charset = "0123456789" ++ if (case == .upper) "ABCDEF" else "abcdef"; return struct { - pub fn f( + pub fn formatSliceHexImpl( bytes: []const u8, comptime fmt: []const u8, options: std.fmt.FormatOptions, @@ -846,8 +846,8 @@ fn formatSliceHexImpl(comptime case: Case) type { }; } -const formatSliceHexLower = formatSliceHexImpl(.lower).f; -const formatSliceHexUpper = formatSliceHexImpl(.upper).f; +const formatSliceHexLower = formatSliceHexImpl(.lower).formatSliceHexImpl; +const formatSliceHexUpper = formatSliceHexImpl(.upper).formatSliceHexImpl; /// Return a Formatter for a []const u8 where every byte is formatted as a pair /// of lowercase hexadecimal digits. @@ -865,7 +865,7 @@ fn formatSliceEscapeImpl(comptime case: Case) type { const charset = "0123456789" ++ if (case == .upper) "ABCDEF" else "abcdef"; return struct { - pub fn f( + pub fn formatSliceEscapeImpl( bytes: []const u8, comptime fmt: []const u8, options: std.fmt.FormatOptions, @@ -891,8 +891,8 @@ fn formatSliceEscapeImpl(comptime case: Case) type { }; } -const formatSliceEscapeLower = formatSliceEscapeImpl(.lower).f; -const formatSliceEscapeUpper = formatSliceEscapeImpl(.upper).f; +const formatSliceEscapeLower = formatSliceEscapeImpl(.lower).formatSliceEscapeImpl; +const formatSliceEscapeUpper = formatSliceEscapeImpl(.upper).formatSliceEscapeImpl; /// Return a Formatter for a []const u8 where every non-printable ASCII /// character is escaped as \xNN, where NN is the character in lowercase @@ -910,7 +910,7 @@ pub fn fmtSliceEscapeUpper(bytes: []const u8) std.fmt.Formatter(formatSliceEscap fn formatSizeImpl(comptime radix: comptime_int) type { return struct { - fn f( + fn formatSizeImpl( value: u64, comptime fmt: []const u8, options: FormatOptions, @@ -958,8 +958,8 @@ fn formatSizeImpl(comptime radix: comptime_int) type { }; } -const formatSizeDec = formatSizeImpl(1000).f; -const formatSizeBin = formatSizeImpl(1024).f; +const formatSizeDec = formatSizeImpl(1000).formatSizeImpl; +const formatSizeBin = formatSizeImpl(1024).formatSizeImpl; /// Return a Formatter for a u64 value representing a file size. /// This formatter represents the number as multiple of 1000 and uses the SI diff --git a/lib/std/fs.zig b/lib/std/fs.zig index 8ae21259ae1d..e253aaff9e95 100644 --- a/lib/std/fs.zig +++ b/lib/std/fs.zig @@ -1130,13 +1130,6 @@ pub const Dir = struct { w.RIGHT.FD_FILESTAT_SET_TIMES | w.RIGHT.FD_FILESTAT_SET_SIZE; } - if (self.fd == os.wasi.AT.FDCWD or path.isAbsolute(sub_path)) { - // Resolve absolute or CWD-relative paths to a path within a Preopen - var resolved_path_buf: [MAX_PATH_BYTES]u8 = undefined; - const resolved_path = try os.resolvePathWasi(sub_path, &resolved_path_buf); - const fd = try os.openatWasi(resolved_path.dir_fd, resolved_path.relative_path, 0x0, 0x0, fdflags, base, 0x0); - return File{ .handle = fd }; - } const fd = try os.openatWasi(self.fd, sub_path, 0x0, 0x0, fdflags, base, 0x0); return File{ .handle = fd }; } @@ -1301,13 +1294,6 @@ pub const Dir = struct { if (flags.exclusive) { oflags |= w.O.EXCL; } - if (self.fd == os.wasi.AT.FDCWD or path.isAbsolute(sub_path)) { - // Resolve absolute or CWD-relative paths to a path within a Preopen - var resolved_path_buf: [MAX_PATH_BYTES]u8 = undefined; - const resolved_path = try os.resolvePathWasi(sub_path, &resolved_path_buf); - const fd = try os.openatWasi(resolved_path.dir_fd, resolved_path.relative_path, 0x0, oflags, 0x0, base, 0x0); - return File{ .handle = fd }; - } const fd = try os.openatWasi(self.fd, sub_path, 0x0, oflags, 0x0, base, 0x0); return File{ .handle = fd }; } @@ -1502,19 +1488,7 @@ pub const Dir = struct { /// See also `Dir.realpathZ`, `Dir.realpathW`, and `Dir.realpathAlloc`. pub fn realpath(self: Dir, pathname: []const u8, out_buffer: []u8) ![]u8 { if (builtin.os.tag == .wasi) { - if (self.fd == os.wasi.AT.FDCWD or path.isAbsolute(pathname)) { - var buffer: [MAX_PATH_BYTES]u8 = undefined; - const out_path = try os.realpath(pathname, &buffer); - if (out_path.len > out_buffer.len) { - return error.NameTooLong; - } - mem.copy(u8, out_buffer, out_path); - return out_buffer[0..out_path.len]; - } else { - // Unfortunately, we have no ability to look up the path for an fd_t - // on WASI, so we have to give up here. - return error.InvalidHandle; - } + @compileError("realpath is not available on WASI"); } if (builtin.os.tag == .windows) { const pathname_w = try os.windows.sliceToPrefixedFileW(pathname); @@ -1711,16 +1685,15 @@ pub const Dir = struct { // TODO do we really need all the rights here? const inheriting: w.rights_t = w.RIGHT.ALL ^ w.RIGHT.SOCK_SHUTDOWN; - const result = blk: { - if (self.fd == os.wasi.AT.FDCWD or path.isAbsolute(sub_path)) { - // Resolve absolute or CWD-relative paths to a path within a Preopen - var resolved_path_buf: [MAX_PATH_BYTES]u8 = undefined; - const resolved_path = try os.resolvePathWasi(sub_path, &resolved_path_buf); - break :blk os.openatWasi(resolved_path.dir_fd, resolved_path.relative_path, symlink_flags, w.O.DIRECTORY, 0x0, base, inheriting); - } else { - break :blk os.openatWasi(self.fd, sub_path, symlink_flags, w.O.DIRECTORY, 0x0, base, inheriting); - } - }; + const result = os.openatWasi( + self.fd, + sub_path, + symlink_flags, + w.O.DIRECTORY, + 0x0, + base, + inheriting, + ); const fd = result catch |err| switch (err) { error.FileTooBig => unreachable, // can't happen for directories error.IsDir => unreachable, // we're providing O.DIRECTORY @@ -2667,6 +2640,13 @@ pub const Dir = struct { pub fn cwd() Dir { if (builtin.os.tag == .windows) { return Dir{ .fd = os.windows.peb().ProcessParameters.CurrentDirectory.Handle }; + } else if (builtin.os.tag == .wasi) { + if (@hasDecl(root, "wasi_cwd")) { + return root.wasi_cwd(); + } else { + // Expect the first preopen to be current working directory. + return .{ .fd = 3 }; + } } else { return Dir{ .fd = os.AT.FDCWD }; } @@ -2685,12 +2665,12 @@ pub fn openDirAbsolute(absolute_path: []const u8, flags: Dir.OpenDirOptions) Fil /// Same as `openDirAbsolute` but the path parameter is null-terminated. pub fn openDirAbsoluteZ(absolute_path_c: [*:0]const u8, flags: Dir.OpenDirOptions) File.OpenError!Dir { assert(path.isAbsoluteZ(absolute_path_c)); - return cwd().openDirZ(absolute_path_c, flags); + return cwd().openDirZ(absolute_path_c, flags, false); } /// Same as `openDirAbsolute` but the path parameter is null-terminated. pub fn openDirAbsoluteW(absolute_path_c: [*:0]const u16, flags: Dir.OpenDirOptions) File.OpenError!Dir { assert(path.isAbsoluteWindowsW(absolute_path_c)); - return cwd().openDirW(absolute_path_c, flags); + return cwd().openDirW(absolute_path_c, flags, false); } /// Opens a directory at the given path. The directory is a system resource that remains diff --git a/lib/std/fs/test.zig b/lib/std/fs/test.zig index 556f3b845961..c497e213bf72 100644 --- a/lib/std/fs/test.zig +++ b/lib/std/fs/test.zig @@ -48,8 +48,7 @@ fn testReadLink(dir: Dir, target_path: []const u8, symlink_path: []const u8) !vo } test "accessAbsolute" { - if (builtin.os.tag == .wasi and builtin.link_libc) return error.SkipZigTest; - if (builtin.os.tag == .wasi and !builtin.link_libc) try os.initPreopensWasi(std.heap.page_allocator, "/"); + if (builtin.os.tag == .wasi) return error.SkipZigTest; var tmp = tmpDir(.{}); defer tmp.cleanup(); @@ -67,8 +66,7 @@ test "accessAbsolute" { } test "openDirAbsolute" { - if (builtin.os.tag == .wasi and builtin.link_libc) return error.SkipZigTest; - if (builtin.os.tag == .wasi and !builtin.link_libc) try os.initPreopensWasi(std.heap.page_allocator, "/"); + if (builtin.os.tag == .wasi) return error.SkipZigTest; var tmp = tmpDir(.{}); defer tmp.cleanup(); @@ -104,8 +102,7 @@ test "openDir cwd parent .." { } test "readLinkAbsolute" { - if (builtin.os.tag == .wasi and builtin.link_libc) return error.SkipZigTest; - if (builtin.os.tag == .wasi and !builtin.link_libc) try os.initPreopensWasi(std.heap.page_allocator, "/"); + if (builtin.os.tag == .wasi) return error.SkipZigTest; var tmp = tmpDir(.{}); defer tmp.cleanup(); @@ -187,8 +184,6 @@ test "Dir.Iterator" { } test "Dir.Iterator many entries" { - if (builtin.os.tag == .wasi and !builtin.link_libc) try os.initPreopensWasi(std.heap.page_allocator, "/"); - var tmp_dir = tmpIterableDir(.{}); defer tmp_dir.cleanup(); @@ -638,8 +633,7 @@ test "rename" { } test "renameAbsolute" { - if (builtin.os.tag == .wasi and builtin.link_libc) return error.SkipZigTest; - if (builtin.os.tag == .wasi and !builtin.link_libc) try os.initPreopensWasi(std.heap.page_allocator, "/"); + if (builtin.os.tag == .wasi) return error.SkipZigTest; var tmp_dir = tmpDir(.{}); defer tmp_dir.cleanup(); @@ -1149,7 +1143,6 @@ test "open file with exclusive nonblocking lock twice (absolute paths)" { test "walker" { if (builtin.os.tag == .wasi and builtin.link_libc) return error.SkipZigTest; - if (builtin.os.tag == .wasi and !builtin.link_libc) try os.initPreopensWasi(std.heap.page_allocator, "/"); var tmp = tmpIterableDir(.{}); defer tmp.cleanup(); @@ -1203,7 +1196,6 @@ test "walker" { test "walker without fully iterating" { if (builtin.os.tag == .wasi and builtin.link_libc) return error.SkipZigTest; - if (builtin.os.tag == .wasi and !builtin.link_libc) try os.initPreopensWasi(std.heap.page_allocator, "/"); var tmp = tmpIterableDir(.{}); defer tmp.cleanup(); @@ -1227,7 +1219,6 @@ test "walker without fully iterating" { test ". and .. in fs.Dir functions" { if (builtin.os.tag == .wasi and builtin.link_libc) return error.SkipZigTest; - if (builtin.os.tag == .wasi and !builtin.link_libc) try os.initPreopensWasi(std.heap.page_allocator, "/"); var tmp = tmpDir(.{}); defer tmp.cleanup(); @@ -1255,8 +1246,7 @@ test ". and .. in fs.Dir functions" { } test ". and .. in absolute functions" { - if (builtin.os.tag == .wasi and builtin.link_libc) return error.SkipZigTest; - if (builtin.os.tag == .wasi and !builtin.link_libc) try os.initPreopensWasi(std.heap.page_allocator, "/"); + if (builtin.os.tag == .wasi) return error.SkipZigTest; var tmp = tmpDir(.{}); defer tmp.cleanup(); diff --git a/lib/std/fs/wasi.zig b/lib/std/fs/wasi.zig index 706cec905e9b..fa9de0dff1e5 100644 --- a/lib/std/fs/wasi.zig +++ b/lib/std/fs/wasi.zig @@ -10,284 +10,47 @@ const wasi = std.os.wasi; const fd_t = wasi.fd_t; const prestat_t = wasi.prestat_t; -/// Type-tag of WASI preopen. -/// -/// WASI currently offers only `Dir` as a valid preopen resource. -pub const PreopenTypeTag = enum { - Dir, -}; - -/// Type of WASI preopen. -/// -/// WASI currently offers only `Dir` as a valid preopen resource. -pub const PreopenType = union(PreopenTypeTag) { - /// Preopened directory type. - Dir: []const u8, - - const Self = @This(); - - pub fn eql(self: Self, other: PreopenType) bool { - if (std.meta.activeTag(self) != std.meta.activeTag(other)) return false; - - switch (self) { - PreopenTypeTag.Dir => |this_path| return mem.eql(u8, this_path, other.Dir), - } - } - - // Checks whether `other` refers to a subdirectory of `self` and, if so, - // returns the relative path to `other` from `self` - // - // Expects `other` to be a canonical path, not containing "." or ".." - pub fn getRelativePath(self: Self, other: PreopenType) ?[]const u8 { - if (std.meta.activeTag(self) != std.meta.activeTag(other)) return null; - - switch (self) { - PreopenTypeTag.Dir => |self_path| { - const other_path = other.Dir; - if (mem.indexOfDiff(u8, self_path, other_path)) |index| { - if (index < self_path.len) return null; - } - - const rel_path = other_path[self_path.len..]; - if (rel_path.len == 0) { - return rel_path; - } else if (rel_path[0] == '/') { - return rel_path[1..]; - } else { - if (self_path[self_path.len - 1] != '/') return null; - return rel_path; - } - }, - } - } - - pub fn format(self: Self, comptime fmt: []const u8, options: std.fmt.FormatOptions, out_stream: anytype) !void { - if (fmt.len != 0) std.fmt.invalidFmtError(fmt, self); - _ = options; - try out_stream.print("PreopenType{{ ", .{}); - switch (self) { - PreopenType.Dir => |path| try out_stream.print(".Dir = '{}'", .{std.zig.fmtId(path)}), - } - return out_stream.print(" }}", .{}); - } -}; - -/// WASI preopen struct. This struct consists of a WASI file descriptor -/// and type of WASI preopen. It can be obtained directly from the WASI -/// runtime using `PreopenList.populate()` method. -pub const Preopen = struct { - /// WASI file descriptor. - fd: fd_t, - - /// Type of the preopen. - type: PreopenType, - - /// Construct new `Preopen` instance. - pub fn new(fd: fd_t, preopen_type: PreopenType) Preopen { - return Preopen{ - .fd = fd, - .type = preopen_type, - }; - } -}; - -/// WASI resource identifier struct. This is effectively a path within -/// a WASI Preopen. -pub const PreopenUri = struct { - /// WASI Preopen containing the resource. - base: Preopen, - /// Path to resource within `base`. - relative_path: []const u8, -}; - -/// Dynamically-sized array list of WASI preopens. This struct is a -/// convenience wrapper for issuing `std.os.wasi.fd_prestat_get` and -/// `std.os.wasi.fd_prestat_dir_name` syscalls to the WASI runtime, and -/// collecting the returned preopens. -/// -/// This struct is intended to be used in any WASI program which intends -/// to use the capabilities as passed on by the user of the runtime. -pub const PreopenList = struct { - const InnerList = std.ArrayList(Preopen); - - /// Internal dynamically-sized buffer for storing the gathered preopens. - buffer: InnerList, - - const Self = @This(); - - pub const Error = error{ OutOfMemory, Overflow } || os.UnexpectedError; - - /// Deinitialize with `deinit`. - pub fn init(allocator: Allocator) Self { - return Self{ .buffer = InnerList.init(allocator) }; - } - - /// Release all allocated memory. - pub fn deinit(pm: Self) void { - for (pm.buffer.items) |preopen| { - switch (preopen.type) { - PreopenType.Dir => |path| pm.buffer.allocator.free(path), - } - } - pm.buffer.deinit(); - } - - /// Populate the list with the preopens by issuing `std.os.wasi.fd_prestat_get` - /// and `std.os.wasi.fd_prestat_dir_name` syscalls to the runtime. - /// - /// If called more than once, it will clear its contents every time before - /// issuing the syscalls. - /// - /// In the unlinkely event of overflowing the number of available file descriptors, - /// returns `error.Overflow`. In this case, even though an error condition was reached - /// the preopen list still contains all valid preopened file descriptors that are valid - /// for use. Therefore, it is fine to call `find`, `asSlice`, or `toOwnedSlice`. Finally, - /// `deinit` still must be called! - /// - /// Usage of `cwd_root`: - /// If provided, `cwd_root` is inserted as prefix for any Preopens that - /// begin with "." and all paths are normalized as POSIX-style absolute - /// paths. `cwd_root` must be an absolute path. - /// - /// For example: - /// "./foo/bar" -> "{cwd_root}/foo/bar" - /// "foo/bar" -> "/foo/bar" - /// "/foo/bar" -> "/foo/bar" - /// - /// If `cwd_root` is not provided, all preopen directories are unmodified. - /// - pub fn populate(self: *Self, cwd_root: ?[]const u8) Error!void { - if (cwd_root) |root| assert(fs.path.isAbsolute(root)); - - // Clear contents if we're being called again - for (try self.toOwnedSlice()) |preopen| { - switch (preopen.type) { - PreopenType.Dir => |path| self.buffer.allocator.free(path), - } - } - errdefer self.deinit(); - var fd: fd_t = 3; // start fd has to be beyond stdio fds - - var path_buf: [fs.MAX_PATH_BYTES]u8 = undefined; - while (true) { - var buf: prestat_t = undefined; - switch (wasi.fd_prestat_get(fd, &buf)) { - .SUCCESS => {}, - .OPNOTSUPP => { - // not a preopen, so keep going - fd = try math.add(fd_t, fd, 1); - continue; - }, - .BADF => { - // OK, no more fds available - break; - }, - else => |err| return os.unexpectedErrno(err), - } - const preopen_len = buf.u.dir.pr_name_len; - - mem.set(u8, path_buf[0..preopen_len], 0); - switch (wasi.fd_prestat_dir_name(fd, &path_buf, preopen_len)) { - .SUCCESS => {}, - else => |err| return os.unexpectedErrno(err), - } - - // Unfortunately, WASI runtimes (e.g. wasmer) are not consistent about whether the - // NULL sentinel is included in the reported Preopen name_len - const raw_path = if (path_buf[preopen_len - 1] == 0) blk: { - break :blk path_buf[0 .. preopen_len - 1]; - } else path_buf[0..preopen_len]; - - // If we were provided a CWD root to resolve against, we try to treat Preopen dirs as - // POSIX paths, relative to "/" or `cwd_root` depending on whether they start with "." - const path = if (cwd_root) |cwd| blk: { - const resolve_paths: []const []const u8 = if (raw_path[0] == '.') &.{ cwd, raw_path } else &.{ "/", raw_path }; - break :blk try fs.path.resolve(self.buffer.allocator, resolve_paths); - } else blk: { - // If we were provided no CWD root, we preserve the preopen dir without resolving - break :blk try self.buffer.allocator.dupe(u8, raw_path); - }; - errdefer self.buffer.allocator.free(path); - const preopen = Preopen.new(fd, .{ .Dir = path }); - - try self.buffer.append(preopen); - fd = try math.add(fd_t, fd, 1); - } - } - - /// Find a preopen which includes access to `preopen_type`. - /// - /// If multiple preopens match the provided resource, the most specific - /// match is returned. More recent preopens take priority, as well. - pub fn findContaining(self: Self, preopen_type: PreopenType) ?PreopenUri { - var best_match: ?PreopenUri = null; - - for (self.buffer.items) |preopen| { - if (preopen.type.getRelativePath(preopen_type)) |rel_path| { - if (best_match == null or rel_path.len <= best_match.?.relative_path.len) { - best_match = PreopenUri{ - .base = preopen, - .relative_path = if (rel_path.len == 0) "." else rel_path, - }; - } - } - } - return best_match; - } - - /// Find preopen by fd. If the preopen exists, return it. - /// Otherwise, return `null`. - pub fn findByFd(self: Self, fd: fd_t) ?Preopen { - for (self.buffer.items) |preopen| { - if (preopen.fd == fd) { - return preopen; +pub const Preopens = struct { + // Indexed by file descriptor number. + names: []const []const u8, + + pub fn find(p: Preopens, name: []const u8) ?os.fd_t { + for (p.names) |elem_name, i| { + if (mem.eql(u8, elem_name, name)) { + return @intCast(os.fd_t, i); } } return null; } - - /// Find preopen by type. If the preopen exists, return it. - /// Otherwise, return `null`. - pub fn find(self: Self, preopen_type: PreopenType) ?*const Preopen { - for (self.buffer.items) |*preopen| { - if (preopen.type.eql(preopen_type)) { - return preopen; - } - } - return null; - } - - /// Return the inner buffer as read-only slice. - pub fn asSlice(self: Self) []const Preopen { - return self.buffer.items; - } - - /// The caller owns the returned memory. ArrayList becomes empty. - pub fn toOwnedSlice(self: *Self) ![]Preopen { - return try self.buffer.toOwnedSlice(); - } }; -test "extracting WASI preopens" { - if (builtin.os.tag != .wasi or builtin.link_libc) return error.SkipZigTest; - - var preopens = PreopenList.init(std.testing.allocator); - defer preopens.deinit(); - - try preopens.populate(null); - - const preopen = preopens.find(PreopenType{ .Dir = "." }) orelse unreachable; - try std.testing.expect(preopen.type.eql(PreopenType{ .Dir = "." })); - - const po_type1 = PreopenType{ .Dir = "/" }; - try std.testing.expect(std.mem.eql(u8, po_type1.getRelativePath(.{ .Dir = "/" }).?, "")); - try std.testing.expect(std.mem.eql(u8, po_type1.getRelativePath(.{ .Dir = "/test/foobar" }).?, "test/foobar")); - - const po_type2 = PreopenType{ .Dir = "/test/foo" }; - try std.testing.expect(po_type2.getRelativePath(.{ .Dir = "/test/foobar" }) == null); - - const po_type3 = PreopenType{ .Dir = "/test" }; - try std.testing.expect(std.mem.eql(u8, po_type3.getRelativePath(.{ .Dir = "/test" }).?, "")); - try std.testing.expect(std.mem.eql(u8, po_type3.getRelativePath(.{ .Dir = "/test/" }).?, "")); - try std.testing.expect(std.mem.eql(u8, po_type3.getRelativePath(.{ .Dir = "/test/foo/bar" }).?, "foo/bar")); +pub fn preopensAlloc(gpa: Allocator) Allocator.Error!Preopens { + var names: std.ArrayListUnmanaged([]const u8) = .{}; + defer names.deinit(gpa); + + try names.ensureUnusedCapacity(gpa, 3); + + names.appendAssumeCapacity("stdin"); // 0 + names.appendAssumeCapacity("stdout"); // 1 + names.appendAssumeCapacity("stderr"); // 2 + while (true) { + const fd = @intCast(wasi.fd_t, names.items.len); + var prestat: prestat_t = undefined; + switch (wasi.fd_prestat_get(fd, &prestat)) { + .SUCCESS => {}, + .OPNOTSUPP, .BADF => return .{ .names = try names.toOwnedSlice(gpa) }, + else => @panic("fd_prestat_get: unexpected error"), + } + try names.ensureUnusedCapacity(gpa, 1); + // This length does not include a null byte. Let's keep it this way to + // gently encourage WASI implementations to behave properly. + const name_len = prestat.u.dir.pr_name_len; + const name = try gpa.alloc(u8, name_len); + errdefer gpa.free(name); + switch (wasi.fd_prestat_dir_name(fd, name.ptr, name.len)) { + .SUCCESS => {}, + else => @panic("fd_prestat_dir_name: unexpected error"), + } + names.appendAssumeCapacity(name); + } } diff --git a/lib/std/heap.zig b/lib/std/heap.zig index ac77db7a798f..ee6525659eae 100644 --- a/lib/std/heap.zig +++ b/lib/std/heap.zig @@ -224,6 +224,16 @@ else .vtable = &PageAllocator.vtable, }; +/// This allocator is fast, small, and specific to WebAssembly. In the future, +/// this will be the implementation automatically selected by +/// `GeneralPurposeAllocator` when compiling in `ReleaseSmall` mode for wasm32 +/// and wasm64 architectures. +/// Until then, it is available here to play with. +pub const wasm_allocator = Allocator{ + .ptr = undefined, + .vtable = &std.heap.WasmAllocator.vtable, +}; + /// Verifies that the adjusted length will still map to the full length pub fn alignPageAllocLen(full_len: usize, len: usize) usize { const aligned_len = mem.alignAllocLen(full_len, len); diff --git a/lib/std/os.zig b/lib/std/os.zig index 7ebe41502695..fc021be954e3 100644 --- a/lib/std/os.zig +++ b/lib/std/os.zig @@ -1521,76 +1521,6 @@ pub fn openW(file_path_w: []const u16, flags: u32, perm: mode_t) OpenError!fd_t }; } -var wasi_cwd = if (builtin.os.tag == .wasi and !builtin.link_libc) struct { - // List of available Preopens - preopens: ?PreopenList = null, - // Memory buffer for storing the relative portion of the CWD - path_buffer: [MAX_PATH_BYTES]u8 = undefined, - // The absolute path associated with the current working directory - cwd: []const u8 = "/", -}{} else undefined; - -/// Initialize the available Preopen list on WASI and set the CWD to `cwd_init`. -/// Note that `cwd_init` corresponds to a Preopen directory, not necessarily -/// a POSIX path. For example, "." matches a Preopen provided with `--dir=.` -/// -/// This must be called before using any relative or absolute paths with `std.os` -/// functions, if you are on WASI without linking libc. -/// -/// The current working directory is initialized to `cwd_root`, and `cwd_root` -/// is inserted as a prefix for any Preopens whose dir begins with "." -/// For example: -/// "./foo/bar" - canonicalizes to -> "{cwd_root}/foo/bar" -/// "foo/bar" - canonicalizes to -> "/foo/bar" -/// "/foo/bar" - canonicalizes to -> "/foo/bar" -/// -/// `cwd_root` must be an absolute path. For initialization behavior similar to -/// wasi-libc, use "/" as the `cwd_root` -/// -/// `alloc` must not be a temporary or leak-detecting allocator, since `std.os` -/// retains ownership of allocations internally and may never call free(). -pub fn initPreopensWasi(alloc: Allocator, cwd_root: []const u8) !void { - if (builtin.os.tag == .wasi) { - if (!builtin.link_libc) { - var preopen_list = PreopenList.init(alloc); - errdefer preopen_list.deinit(); - try preopen_list.populate(cwd_root); - - var path_alloc = std.heap.FixedBufferAllocator.init(&wasi_cwd.path_buffer); - wasi_cwd.cwd = try path_alloc.allocator().dupe(u8, cwd_root); - - if (wasi_cwd.preopens) |preopens| preopens.deinit(); - wasi_cwd.preopens = preopen_list; - } else { - // wasi-libc defaults to an effective CWD root of "/" - if (!mem.eql(u8, cwd_root, "/")) return error.UnsupportedDirectory; - } - } -} - -/// Resolve a relative or absolute path to an handle (`fd_t`) and a relative subpath. -/// -/// For absolute paths, this automatically searches among available Preopens to find -/// a match. For relative paths, it uses the "emulated" CWD. -/// Automatically looks up the correct Preopen corresponding to the provided path. -pub fn resolvePathWasi(path: []const u8, out_buffer: *[MAX_PATH_BYTES]u8) !RelativePathWasi { - var allocator = std.heap.FixedBufferAllocator.init(out_buffer); - var alloc = allocator.allocator(); - - const abs_path = fs.path.resolve(alloc, &.{ wasi_cwd.cwd, path }) catch return error.NameTooLong; - const preopen_uri = wasi_cwd.preopens.?.findContaining(.{ .Dir = abs_path }); - - if (preopen_uri) |po| { - return RelativePathWasi{ - .dir_fd = po.base.fd, - .relative_path = po.relative_path, - }; - } else { - // No matching preopen found - return error.AccessDenied; - } -} - /// Open and possibly create a file. Keeps trying if it gets interrupted. /// `file_path` is relative to the open directory handle `dir_fd`. /// See also `openatZ`. @@ -1600,22 +1530,23 @@ pub fn openat(dir_fd: fd_t, file_path: []const u8, flags: u32, mode: mode_t) Ope return openatW(dir_fd, file_path_w.span(), flags, mode); } else if (builtin.os.tag == .wasi and !builtin.link_libc) { // `mode` is ignored on WASI, which does not support unix-style file permissions - const fd = if (dir_fd == wasi.AT.FDCWD or fs.path.isAbsolute(file_path)) blk: { - // Resolve absolute or CWD-relative paths to a path within a Preopen - var path_buf: [MAX_PATH_BYTES]u8 = undefined; - const path = try resolvePathWasi(file_path, &path_buf); - - const opts = try openOptionsFromFlagsWasi(path.dir_fd, flags); - break :blk try openatWasi(path.dir_fd, path.relative_path, opts.lookup_flags, opts.oflags, opts.fs_flags, opts.fs_rights_base, opts.fs_rights_inheriting); - } else blk: { - const opts = try openOptionsFromFlagsWasi(dir_fd, flags); - break :blk try openatWasi(dir_fd, file_path, opts.lookup_flags, opts.oflags, opts.fs_flags, opts.fs_rights_base, opts.fs_rights_inheriting); - }; + const opts = try openOptionsFromFlagsWasi(dir_fd, flags); + const fd = try openatWasi( + dir_fd, + file_path, + opts.lookup_flags, + opts.oflags, + opts.fs_flags, + opts.fs_rights_base, + opts.fs_rights_inheriting, + ); errdefer close(fd); - const info = try fstat(fd); - if (flags & O.WRONLY != 0 and info.filetype == .DIRECTORY) - return error.IsDir; + if (flags & O.WRONLY != 0) { + const info = try fstat(fd); + if (info.filetype == .DIRECTORY) + return error.IsDir; + } return fd; } @@ -1673,7 +1604,15 @@ fn openOptionsFromFlagsWasi(fd: fd_t, oflag: u32) OpenError!WasiOpenOptions { } /// Open and possibly create a file in WASI. -pub fn openatWasi(dir_fd: fd_t, file_path: []const u8, lookup_flags: lookupflags_t, oflags: oflags_t, fdflags: fdflags_t, base: rights_t, inheriting: rights_t) OpenError!fd_t { +pub fn openatWasi( + dir_fd: fd_t, + file_path: []const u8, + lookup_flags: lookupflags_t, + oflags: oflags_t, + fdflags: fdflags_t, + base: rights_t, + inheriting: rights_t, +) OpenError!fd_t { while (true) { var fd: fd_t = undefined; switch (wasi.path_open(dir_fd, lookup_flags, file_path.ptr, file_path.len, oflags, base, inheriting, fdflags, &fd)) { @@ -2031,7 +1970,7 @@ pub fn getcwd(out_buffer: []u8) GetCwdError![]u8 { if (builtin.os.tag == .windows) { return windows.GetCurrentDirectory(out_buffer); } else if (builtin.os.tag == .wasi and !builtin.link_libc) { - const path = wasi_cwd.cwd; + const path = "."; if (out_buffer.len < path.len) return error.NameTooLong; std.mem.copy(u8, out_buffer, path); return out_buffer[0..path.len]; @@ -2093,7 +2032,7 @@ pub fn symlinkZ(target_path: [*:0]const u8, sym_link_path: [*:0]const u8) SymLin if (builtin.os.tag == .windows) { @compileError("symlink is not supported on Windows; use std.os.windows.CreateSymbolicLink instead"); } else if (builtin.os.tag == .wasi and !builtin.link_libc) { - return symlink(mem.sliceTo(target_path, 0), mem.sliceTo(sym_link_path, 0)); + return symlinkatZ(target_path, fs.cwd().fd, sym_link_path); } switch (errno(system.symlink(target_path, sym_link_path))) { .SUCCESS => return, @@ -2125,12 +2064,6 @@ pub fn symlinkat(target_path: []const u8, newdirfd: fd_t, sym_link_path: []const if (builtin.os.tag == .windows) { @compileError("symlinkat is not supported on Windows; use std.os.windows.CreateSymbolicLink instead"); } else if (builtin.os.tag == .wasi and !builtin.link_libc) { - if (newdirfd == wasi.AT.FDCWD or fs.path.isAbsolute(target_path)) { - // Resolve absolute or CWD-relative paths to a path within a Preopen - var path_buf: [MAX_PATH_BYTES]u8 = undefined; - const path = try resolvePathWasi(sym_link_path, &path_buf); - return symlinkatWasi(target_path, path.dir_fd, path.relative_path); - } return symlinkatWasi(target_path, newdirfd, sym_link_path); } const target_path_c = try toPosixPath(target_path); @@ -2145,6 +2078,7 @@ pub fn symlinkatWasi(target_path: []const u8, newdirfd: fd_t, sym_link_path: []c .SUCCESS => {}, .FAULT => unreachable, .INVAL => unreachable, + .BADF => unreachable, .ACCES => return error.AccessDenied, .PERM => return error.AccessDenied, .DQUOT => return error.DiskQuota, @@ -2284,25 +2218,8 @@ pub fn linkat( flags: i32, ) LinkatError!void { if (builtin.os.tag == .wasi and !builtin.link_libc) { - var resolve_olddir: bool = (olddir == wasi.AT.FDCWD or fs.path.isAbsolute(oldpath)); - var resolve_newdir: bool = (newdir == wasi.AT.FDCWD or fs.path.isAbsolute(newpath)); - - var old: RelativePathWasi = .{ .dir_fd = olddir, .relative_path = oldpath }; - var new: RelativePathWasi = .{ .dir_fd = newdir, .relative_path = newpath }; - - // Resolve absolute or CWD-relative paths to a path within a Preopen - if (resolve_olddir or resolve_newdir) { - var buf_old: [MAX_PATH_BYTES]u8 = undefined; - var buf_new: [MAX_PATH_BYTES]u8 = undefined; - - if (resolve_olddir) - old = try resolvePathWasi(oldpath, &buf_old); - - if (resolve_newdir) - new = try resolvePathWasi(newpath, &buf_new); - - return linkatWasi(old, new, flags); - } + const old: RelativePathWasi = .{ .dir_fd = olddir, .relative_path = oldpath }; + const new: RelativePathWasi = .{ .dir_fd = newdir, .relative_path = newpath }; return linkatWasi(old, new, flags); } const old = try toPosixPath(oldpath); @@ -2423,12 +2340,6 @@ pub fn unlinkat(dirfd: fd_t, file_path: []const u8, flags: u32) UnlinkatError!vo const file_path_w = try windows.sliceToPrefixedFileW(file_path); return unlinkatW(dirfd, file_path_w.span(), flags); } else if (builtin.os.tag == .wasi and !builtin.link_libc) { - if (dirfd == wasi.AT.FDCWD or fs.path.isAbsolute(file_path)) { - // Resolve absolute or CWD-relative paths to a path within a Preopen - var path_buf: [MAX_PATH_BYTES]u8 = undefined; - const path = try resolvePathWasi(file_path, &path_buf); - return unlinkatWasi(path.dir_fd, path.relative_path, flags); - } return unlinkatWasi(dirfd, file_path, flags); } else { const file_path_c = try toPosixPath(file_path); @@ -2597,24 +2508,8 @@ pub fn renameat( const new_path_w = try windows.sliceToPrefixedFileW(new_path); return renameatW(old_dir_fd, old_path_w.span(), new_dir_fd, new_path_w.span(), windows.TRUE); } else if (builtin.os.tag == .wasi and !builtin.link_libc) { - var resolve_old: bool = (old_dir_fd == wasi.AT.FDCWD or fs.path.isAbsolute(old_path)); - var resolve_new: bool = (new_dir_fd == wasi.AT.FDCWD or fs.path.isAbsolute(new_path)); - - var old: RelativePathWasi = .{ .dir_fd = old_dir_fd, .relative_path = old_path }; - var new: RelativePathWasi = .{ .dir_fd = new_dir_fd, .relative_path = new_path }; - - // Resolve absolute or CWD-relative paths to a path within a Preopen - if (resolve_old or resolve_new) { - var buf_old: [MAX_PATH_BYTES]u8 = undefined; - var buf_new: [MAX_PATH_BYTES]u8 = undefined; - - if (resolve_old) - old = try resolvePathWasi(old_path, &buf_old); - if (resolve_new) - new = try resolvePathWasi(new_path, &buf_new); - - return renameatWasi(old, new); - } + const old: RelativePathWasi = .{ .dir_fd = old_dir_fd, .relative_path = old_path }; + const new: RelativePathWasi = .{ .dir_fd = new_dir_fd, .relative_path = new_path }; return renameatWasi(old, new); } else { const old_path_c = try toPosixPath(old_path); @@ -2755,12 +2650,6 @@ pub fn mkdirat(dir_fd: fd_t, sub_dir_path: []const u8, mode: u32) MakeDirError!v const sub_dir_path_w = try windows.sliceToPrefixedFileW(sub_dir_path); return mkdiratW(dir_fd, sub_dir_path_w.span(), mode); } else if (builtin.os.tag == .wasi and !builtin.link_libc) { - if (dir_fd == wasi.AT.FDCWD or fs.path.isAbsolute(sub_dir_path)) { - // Resolve absolute or CWD-relative paths to a path within a Preopen - var path_buf: [MAX_PATH_BYTES]u8 = undefined; - const path = try resolvePathWasi(sub_dir_path, &path_buf); - return mkdiratWasi(path.dir_fd, path.relative_path, mode); - } return mkdiratWasi(dir_fd, sub_dir_path, mode); } else { const sub_dir_path_c = try toPosixPath(sub_dir_path); @@ -2997,22 +2886,7 @@ pub const ChangeCurDirError = error{ /// `dir_path` is recommended to be a UTF-8 encoded string. pub fn chdir(dir_path: []const u8) ChangeCurDirError!void { if (builtin.os.tag == .wasi and !builtin.link_libc) { - var buf: [MAX_PATH_BYTES]u8 = undefined; - var alloc = std.heap.FixedBufferAllocator.init(&buf); - const path = fs.path.resolve(alloc.allocator(), &.{ wasi_cwd.cwd, dir_path }) catch |err| switch (err) { - error.OutOfMemory => return error.NameTooLong, - else => |e| return e, - }; - - const dirinfo = try fstatat(AT.FDCWD, path, 0); - if (dirinfo.filetype != .DIRECTORY) { - return error.NotDir; - } - - // This copy is guaranteed to succeed, since buf and path_buffer are the same size. - var cwd_alloc = std.heap.FixedBufferAllocator.init(&wasi_cwd.path_buffer); - wasi_cwd.cwd = cwd_alloc.allocator().dupe(u8, path) catch unreachable; - return; + @compileError("WASI does not support os.chdir"); } else if (builtin.os.tag == .windows) { var utf16_dir_path: [windows.PATH_MAX_WIDE]u16 = undefined; const len = try std.unicode.utf8ToUtf16Le(utf16_dir_path[0..], dir_path); @@ -3143,12 +3017,6 @@ pub fn readlinkZ(file_path: [*:0]const u8, out_buffer: []u8) ReadLinkError![]u8 /// See also `readlinkatWasi`, `realinkatZ` and `realinkatW`. pub fn readlinkat(dirfd: fd_t, file_path: []const u8, out_buffer: []u8) ReadLinkError![]u8 { if (builtin.os.tag == .wasi and !builtin.link_libc) { - if (dirfd == wasi.AT.FDCWD or fs.path.isAbsolute(file_path)) { - // Resolve absolute or CWD-relative paths to a path within a Preopen - var path_buf: [MAX_PATH_BYTES]u8 = undefined; - var path = try resolvePathWasi(file_path, &path_buf); - return readlinkatWasi(path.dir_fd, path.relative_path, out_buffer); - } return readlinkatWasi(dirfd, file_path, out_buffer); } if (builtin.os.tag == .windows) { @@ -4155,12 +4023,6 @@ pub const FStatAtError = FStatError || error{ NameTooLong, FileNotFound, SymLink pub fn fstatat(dirfd: fd_t, pathname: []const u8, flags: u32) FStatAtError!Stat { if (builtin.os.tag == .wasi and !builtin.link_libc) { const wasi_flags = if (flags & linux.AT.SYMLINK_NOFOLLOW == 0) wasi.LOOKUP_SYMLINK_FOLLOW else 0; - if (dirfd == wasi.AT.FDCWD or fs.path.isAbsolute(pathname)) { - // Resolve absolute or CWD-relative paths to a path within a Preopen - var path_buf: [MAX_PATH_BYTES]u8 = undefined; - const path = try resolvePathWasi(pathname, &path_buf); - return fstatatWasi(path.dir_fd, path.relative_path, wasi_flags); - } return fstatatWasi(dirfd, pathname, wasi_flags); } else if (builtin.os.tag == .windows) { @compileError("fstatat is not yet implemented on Windows"); @@ -4556,12 +4418,6 @@ pub fn faccessat(dirfd: fd_t, path: []const u8, mode: u32, flags: u32) AccessErr var resolved = RelativePathWasi{ .dir_fd = dirfd, .relative_path = path }; const file = blk: { - if (dirfd == wasi.AT.FDCWD or fs.path.isAbsolute(path)) { - // Resolve absolute or CWD-relative paths to a path within a Preopen - var path_buf: [MAX_PATH_BYTES]u8 = undefined; - resolved = resolvePathWasi(path, &path_buf) catch |err| break :blk @as(FStatAtError!Stat, err); - break :blk fstatat(resolved.dir_fd, resolved.relative_path, flags); - } break :blk fstatat(dirfd, path, flags); } catch |err| switch (err) { error.AccessDenied => return error.PermissionDenied, @@ -5147,12 +5003,7 @@ pub fn realpath(pathname: []const u8, out_buffer: *[MAX_PATH_BYTES]u8) RealPathE const pathname_w = try windows.sliceToPrefixedFileW(pathname); return realpathW(pathname_w.span(), out_buffer); } else if (builtin.os.tag == .wasi and !builtin.link_libc) { - var alloc = std.heap.FixedBufferAllocator.init(out_buffer); - - // NOTE: This emulation is incomplete. Symbolic links are not - // currently expanded during path canonicalization. - const paths = &.{ wasi_cwd.cwd, pathname }; - return fs.path.resolve(alloc.allocator(), paths) catch error.NameTooLong; + @compileError("WASI does not support os.realpath"); } const pathname_c = try toPosixPath(pathname); return realpathZ(&pathname_c, out_buffer); diff --git a/lib/std/os/test.zig b/lib/std/os/test.zig index ed86024dcdac..44d0e0c80891 100644 --- a/lib/std/os/test.zig +++ b/lib/std/os/test.zig @@ -22,8 +22,7 @@ const Dir = std.fs.Dir; const ArenaAllocator = std.heap.ArenaAllocator; test "chdir smoke test" { - if (native_os == .wasi and builtin.link_libc) return error.SkipZigTest; - if (native_os == .wasi and !builtin.link_libc) try os.initPreopensWasi(std.heap.page_allocator, "/preopens/cwd"); + if (native_os == .wasi) return error.SkipZigTest; // Get current working directory path var old_cwd_buf: [fs.MAX_PATH_BYTES]u8 = undefined; @@ -75,8 +74,7 @@ test "chdir smoke test" { } test "open smoke test" { - if (native_os == .wasi and builtin.link_libc) return error.SkipZigTest; - if (native_os == .wasi and !builtin.link_libc) try os.initPreopensWasi(std.heap.page_allocator, "/"); + if (native_os == .wasi) return error.SkipZigTest; // TODO verify file attributes using `fstat` @@ -131,7 +129,6 @@ test "open smoke test" { test "openat smoke test" { if (native_os == .wasi and builtin.link_libc) return error.SkipZigTest; - if (native_os == .wasi and !builtin.link_libc) try os.initPreopensWasi(std.heap.page_allocator, "/"); // TODO verify file attributes using `fstatat` @@ -168,7 +165,6 @@ test "openat smoke test" { test "symlink with relative paths" { if (native_os == .wasi and builtin.link_libc) return error.SkipZigTest; - if (native_os == .wasi and !builtin.link_libc) try os.initPreopensWasi(std.heap.page_allocator, "/"); const cwd = fs.cwd(); cwd.deleteFile("file.txt") catch {}; @@ -219,15 +215,10 @@ fn testReadlink(target_path: []const u8, symlink_path: []const u8) !void { } test "link with relative paths" { + if (native_os == .wasi and builtin.link_libc) return error.SkipZigTest; + switch (native_os) { - .wasi => { - if (builtin.link_libc) { - return error.SkipZigTest; - } else { - try os.initPreopensWasi(std.heap.page_allocator, "/"); - } - }, - .linux, .solaris => {}, + .wasi, .linux, .solaris => {}, else => return error.SkipZigTest, } var cwd = fs.cwd(); @@ -263,9 +254,10 @@ test "link with relative paths" { } test "linkat with different directories" { + if (native_os == .wasi and builtin.link_libc) return error.SkipZigTest; + switch (native_os) { - .wasi => if (!builtin.link_libc) try os.initPreopensWasi(std.heap.page_allocator, "/"), - .linux, .solaris => {}, + .wasi, .linux, .solaris => {}, else => return error.SkipZigTest, } var cwd = fs.cwd(); @@ -950,8 +942,7 @@ test "POSIX file locking with fcntl" { } test "rename smoke test" { - if (native_os == .wasi and builtin.link_libc) return error.SkipZigTest; - if (native_os == .wasi and !builtin.link_libc) try os.initPreopensWasi(std.heap.page_allocator, "/"); + if (native_os == .wasi) return error.SkipZigTest; var tmp = tmpDir(.{}); defer tmp.cleanup(); @@ -1007,8 +998,7 @@ test "rename smoke test" { } test "access smoke test" { - if (native_os == .wasi and builtin.link_libc) return error.SkipZigTest; - if (native_os == .wasi and !builtin.link_libc) try os.initPreopensWasi(std.heap.page_allocator, "/"); + if (native_os == .wasi) return error.SkipZigTest; var tmp = tmpDir(.{}); defer tmp.cleanup(); diff --git a/lib/std/os/wasi.zig b/lib/std/os/wasi.zig index 308b6cc23dea..711352e2fe20 100644 --- a/lib/std/os/wasi.zig +++ b/lib/std/os/wasi.zig @@ -1,6 +1,7 @@ // wasi_snapshot_preview1 spec available (in witx format) here: // * typenames -- https://github.com/WebAssembly/WASI/blob/master/phases/snapshot/witx/typenames.witx // * module -- https://github.com/WebAssembly/WASI/blob/master/phases/snapshot/witx/wasi_snapshot_preview1.witx +const builtin = @import("builtin"); const std = @import("std"); const assert = std.debug.assert; @@ -157,7 +158,12 @@ pub const IOV_MAX = 1024; pub const AT = struct { pub const REMOVEDIR: u32 = 0x4; - pub const FDCWD: fd_t = -2; + /// When linking libc, we follow their convention and use -2 for current working directory. + /// However, without libc, Zig does a different convention: it assumes the + /// current working directory is the first preopen. This behavior can be + /// overridden with a public function called `wasi_cwd` in the root source + /// file. + pub const FDCWD: fd_t = if (builtin.link_libc) -2 else 3; }; // As defined in the wasi_snapshot_preview1 spec file: diff --git a/lib/std/process.zig b/lib/std/process.zig index 22f5cc382eb4..23fad9e8c67d 100644 --- a/lib/std/process.zig +++ b/lib/std/process.zig @@ -355,7 +355,7 @@ pub const GetEnvVarOwnedError = error{ }; /// Caller must free returned memory. -pub fn getEnvVarOwned(allocator: mem.Allocator, key: []const u8) GetEnvVarOwnedError![]u8 { +pub fn getEnvVarOwned(allocator: Allocator, key: []const u8) GetEnvVarOwnedError![]u8 { if (builtin.os.tag == .windows) { const result_w = blk: { const key_w = try std.unicode.utf8ToUtf16LeWithNull(allocator, key); @@ -430,7 +430,7 @@ pub const ArgIteratorPosix = struct { }; pub const ArgIteratorWasi = struct { - allocator: mem.Allocator, + allocator: Allocator, index: usize, args: [][:0]u8, @@ -438,7 +438,7 @@ pub const ArgIteratorWasi = struct { /// You must call deinit to free the internal buffer of the /// iterator after you are done. - pub fn init(allocator: mem.Allocator) InitError!ArgIteratorWasi { + pub fn init(allocator: Allocator) InitError!ArgIteratorWasi { const fetched_args = try ArgIteratorWasi.internalInit(allocator); return ArgIteratorWasi{ .allocator = allocator, @@ -447,7 +447,7 @@ pub const ArgIteratorWasi = struct { }; } - fn internalInit(allocator: mem.Allocator) InitError![][:0]u8 { + fn internalInit(allocator: Allocator) InitError![][:0]u8 { const w = os.wasi; var count: usize = undefined; var buf_size: usize = undefined; @@ -760,7 +760,7 @@ pub const ArgIterator = struct { }; /// You must deinitialize iterator's internal buffers by calling `deinit` when done. - pub fn initWithAllocator(allocator: mem.Allocator) InitError!ArgIterator { + pub fn initWithAllocator(allocator: Allocator) InitError!ArgIterator { if (builtin.os.tag == .wasi and !builtin.link_libc) { return ArgIterator{ .inner = try InnerType.init(allocator) }; } @@ -804,7 +804,7 @@ pub fn args() ArgIterator { } /// You must deinitialize iterator's internal buffers by calling `deinit` when done. -pub fn argsWithAllocator(allocator: mem.Allocator) ArgIterator.InitError!ArgIterator { +pub fn argsWithAllocator(allocator: Allocator) ArgIterator.InitError!ArgIterator { return ArgIterator.initWithAllocator(allocator); } @@ -827,7 +827,7 @@ test "args iterator" { } /// Caller must call argsFree on result. -pub fn argsAlloc(allocator: mem.Allocator) ![][:0]u8 { +pub fn argsAlloc(allocator: Allocator) ![][:0]u8 { // TODO refactor to only make 1 allocation. var it = try argsWithAllocator(allocator); defer it.deinit(); @@ -864,7 +864,7 @@ pub fn argsAlloc(allocator: mem.Allocator) ![][:0]u8 { return result_slice_list; } -pub fn argsFree(allocator: mem.Allocator, args_alloc: []const [:0]u8) void { +pub fn argsFree(allocator: Allocator, args_alloc: []const [:0]u8) void { var total_bytes: usize = 0; for (args_alloc) |arg| { total_bytes += @sizeOf([]u8) + arg.len + 1; @@ -1089,7 +1089,7 @@ pub const ExecvError = std.os.ExecveError || error{OutOfMemory}; /// This function also uses the PATH environment variable to get the full path to the executable. /// Due to the heap-allocation, it is illegal to call this function in a fork() child. /// For that use case, use the `std.os` functions directly. -pub fn execv(allocator: mem.Allocator, argv: []const []const u8) ExecvError { +pub fn execv(allocator: Allocator, argv: []const []const u8) ExecvError { return execve(allocator, argv, null); } @@ -1102,7 +1102,7 @@ pub fn execv(allocator: mem.Allocator, argv: []const []const u8) ExecvError { /// Due to the heap-allocation, it is illegal to call this function in a fork() child. /// For that use case, use the `std.os` functions directly. pub fn execve( - allocator: mem.Allocator, + allocator: Allocator, argv: []const []const u8, env_map: ?*const EnvMap, ) ExecvError { diff --git a/lib/std/wasm.zig b/lib/std/wasm.zig index 3d47d43487c4..12026f185839 100644 --- a/lib/std/wasm.zig +++ b/lib/std/wasm.zig @@ -188,6 +188,8 @@ pub const Opcode = enum(u8) { i64_extend8_s = 0xC2, i64_extend16_s = 0xC3, i64_extend32_s = 0xC4, + + prefixed = 0xFC, _, }; @@ -232,6 +234,7 @@ pub const PrefixedOpcode = enum(u8) { table_grow = 0x0F, table_size = 0x10, table_fill = 0x11, + _, }; /// Enum representing all Wasm value types as per spec: diff --git a/lib/zig.h b/lib/zig.h index f827af1d5c4b..9fb01f8fbaa6 100644 --- a/lib/zig.h +++ b/lib/zig.h @@ -810,7 +810,7 @@ static inline void zig_vmulo_i16(zig_u8 *ov, zig_i16 *res, int n, \ static inline bool zig_shlo_u##w(zig_u##w *res, zig_u##w lhs, zig_u8 rhs, zig_u8 bits) { \ *res = zig_shlw_u##w(lhs, rhs, bits); \ - return (lhs & zig_maxInt_u##w << (bits - rhs)) != zig_as_u##w(0); \ + return lhs > zig_maxInt(u##w, bits) >> rhs; \ } \ \ static inline bool zig_shlo_i##w(zig_i##w *res, zig_i##w lhs, zig_u8 rhs, zig_u8 bits) { \ @@ -1340,7 +1340,7 @@ static inline zig_i128 zig_mulw_i128(zig_i128 lhs, zig_i128 rhs, zig_u8 bits) { static inline bool zig_shlo_u128(zig_u128 *res, zig_u128 lhs, zig_u8 rhs, zig_u8 bits) { *res = zig_shlw_u128(lhs, rhs, bits); - return zig_and_u128(lhs, zig_shl_u128(zig_maxInt_u128, bits - rhs)) != zig_as_u128(0, 0); + return zig_cmp_u128(lhs, zig_shr_u128(zig_maxInt(u128, bits), rhs)) > zig_as_i32(0); } static inline bool zig_shlo_i128(zig_i128 *res, zig_i128 lhs, zig_u8 rhs, zig_u8 bits) { @@ -1556,7 +1556,7 @@ typedef double zig_f16; #define zig_bitSizeOf_c_longdouble 16 typedef long double zig_f16; #define zig_as_f16(fp, repr) fp##l -#elif FLT16_MANT_DIG == 11 +#elif FLT16_MANT_DIG == 11 && zig_has_builtin(inff16) typedef _Float16 zig_f16; #define zig_as_f16(fp, repr) fp##f16 #elif defined(__SIZEOF_FP16__) diff --git a/src/Compilation.zig b/src/Compilation.zig index 48cf246287cb..e3c45678e2b1 100644 --- a/src/Compilation.zig +++ b/src/Compilation.zig @@ -30,7 +30,6 @@ const fatal = @import("main.zig").fatal; const clangMain = @import("main.zig").clangMain; const Module = @import("Module.zig"); const Cache = @import("Cache.zig"); -const stage1 = @import("stage1.zig"); const translate_c = @import("translate_c.zig"); const c_codegen = @import("codegen/c.zig"); const ThreadPool = @import("ThreadPool.zig"); @@ -935,7 +934,6 @@ pub const InitOptions = struct { use_llvm: ?bool = null, use_lld: ?bool = null, use_clang: ?bool = null, - use_stage1: ?bool = null, single_threaded: ?bool = null, strip: ?bool = null, formatted_panics: ?bool = null, @@ -1133,9 +1131,6 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation { const comp = try arena.create(Compilation); const root_name = try arena.dupeZ(u8, options.root_name); - const use_stage1 = options.use_stage1 orelse false; - if (use_stage1 and !build_options.have_stage1) return error.ZigCompilerBuiltWithoutStage1; - // Make a decision on whether to use LLVM or our own backend. const use_llvm = build_options.have_llvm and blk: { if (options.use_llvm) |explicit| @@ -1149,11 +1144,6 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation { if (options.main_pkg == null) break :blk false; - // The stage1 compiler depends on the stage1 C++ LLVM backend - // to compile zig code. - if (use_stage1) - break :blk true; - // If LLVM does not support the target, then we can't use it. if (!target_util.hasLlvmSupport(options.target, options.target.ofmt)) break :blk false; @@ -1181,8 +1171,10 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation { // compiler state, the second clause here can be removed so that incremental // cache mode is used for LLVM backend too. We need some fuzz testing before // that can be enabled. - const cache_mode = if ((use_stage1 and !options.disable_lld_caching) or - (use_llvm and !options.disable_lld_caching)) CacheMode.whole else options.cache_mode; + const cache_mode = if (use_llvm and !options.disable_lld_caching) + CacheMode.whole + else + options.cache_mode; const tsan = options.want_tsan orelse false; // TSAN is implemented in C++ so it requires linking libc++. @@ -1545,7 +1537,6 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation { // Synchronize with other matching comments: ZigOnlyHashStuff hash.add(valgrind); hash.add(single_threaded); - hash.add(use_stage1); hash.add(use_llvm); hash.add(dll_export_fns); hash.add(options.is_test); @@ -1587,9 +1578,6 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation { .handle = artifact_dir, .path = try options.local_cache_directory.join(arena, &[_][]const u8{artifact_sub_dir}), }; - log.debug("zig_cache_artifact_directory='{?s}' use_stage1={}", .{ - zig_cache_artifact_directory.path, use_stage1, - }); const builtin_pkg = try Package.createWithDir( gpa, @@ -1907,7 +1895,6 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation { .subsystem = options.subsystem, .is_test = options.is_test, .wasi_exec_model = wasi_exec_model, - .use_stage1 = use_stage1, .hash_style = options.hash_style, .enable_link_snapshots = options.enable_link_snapshots, .native_darwin_sdk = options.native_darwin_sdk, @@ -2344,7 +2331,6 @@ pub fn update(comp: *Compilation) !void { comp.c_object_work_queue.writeItemAssumeCapacity(key); } - const use_stage1 = build_options.have_stage1 and comp.bin_file.options.use_stage1; if (comp.bin_file.options.module) |module| { module.compile_log_text.shrinkAndFree(module.gpa, 0); module.generation += 1; @@ -2360,7 +2346,7 @@ pub fn update(comp: *Compilation) !void { // import_table here. // Likewise, in the case of `zig test`, the test runner is the root source file, // and so there is nothing to import the main file. - if (use_stage1 or comp.bin_file.options.is_test) { + if (comp.bin_file.options.is_test) { _ = try module.importPkg(module.main_pkg); } @@ -2374,21 +2360,19 @@ pub fn update(comp: *Compilation) !void { comp.astgen_work_queue.writeItemAssumeCapacity(value); } - if (!use_stage1) { - // Put a work item in for checking if any files used with `@embedFile` changed. - { - try comp.embed_file_work_queue.ensureUnusedCapacity(module.embed_table.count()); - var it = module.embed_table.iterator(); - while (it.next()) |entry| { - const embed_file = entry.value_ptr.*; - comp.embed_file_work_queue.writeItemAssumeCapacity(embed_file); - } + // Put a work item in for checking if any files used with `@embedFile` changed. + { + try comp.embed_file_work_queue.ensureUnusedCapacity(module.embed_table.count()); + var it = module.embed_table.iterator(); + while (it.next()) |entry| { + const embed_file = entry.value_ptr.*; + comp.embed_file_work_queue.writeItemAssumeCapacity(embed_file); } + } - try comp.work_queue.writeItem(.{ .analyze_pkg = std_pkg }); - if (comp.bin_file.options.is_test) { - try comp.work_queue.writeItem(.{ .analyze_pkg = module.main_pkg }); - } + try comp.work_queue.writeItem(.{ .analyze_pkg = std_pkg }); + if (comp.bin_file.options.is_test) { + try comp.work_queue.writeItem(.{ .analyze_pkg = module.main_pkg }); } } @@ -2400,36 +2384,34 @@ pub fn update(comp: *Compilation) !void { try comp.performAllTheWork(main_progress_node); - if (!use_stage1) { - if (comp.bin_file.options.module) |module| { - if (comp.bin_file.options.is_test and comp.totalErrorCount() == 0) { - // The `test_functions` decl has been intentionally postponed until now, - // at which point we must populate it with the list of test functions that - // have been discovered and not filtered out. - try module.populateTestFunctions(main_progress_node); - } + if (comp.bin_file.options.module) |module| { + if (comp.bin_file.options.is_test and comp.totalErrorCount() == 0) { + // The `test_functions` decl has been intentionally postponed until now, + // at which point we must populate it with the list of test functions that + // have been discovered and not filtered out. + try module.populateTestFunctions(main_progress_node); + } - // Process the deletion set. We use a while loop here because the - // deletion set may grow as we call `clearDecl` within this loop, - // and more unreferenced Decls are revealed. - while (module.deletion_set.count() != 0) { - const decl_index = module.deletion_set.keys()[0]; - const decl = module.declPtr(decl_index); - assert(decl.deletion_flag); - assert(decl.dependants.count() == 0); - const is_anon = if (decl.zir_decl_index == 0) blk: { - break :blk decl.src_namespace.anon_decls.swapRemove(decl_index); - } else false; - - try module.clearDecl(decl_index, null); - - if (is_anon) { - module.destroyDecl(decl_index); - } - } + // Process the deletion set. We use a while loop here because the + // deletion set may grow as we call `clearDecl` within this loop, + // and more unreferenced Decls are revealed. + while (module.deletion_set.count() != 0) { + const decl_index = module.deletion_set.keys()[0]; + const decl = module.declPtr(decl_index); + assert(decl.deletion_flag); + assert(decl.dependants.count() == 0); + const is_anon = if (decl.zir_decl_index == 0) blk: { + break :blk decl.src_namespace.anon_decls.swapRemove(decl_index); + } else false; + + try module.clearDecl(decl_index, null); - try module.processExports(); + if (is_anon) { + module.destroyDecl(decl_index); + } } + + try module.processExports(); } if (comp.totalErrorCount() != 0) { @@ -2438,11 +2420,13 @@ pub fn update(comp: *Compilation) !void { return; } - if (comp.emit_docs) |doc_location| { - if (comp.bin_file.options.module) |module| { - var autodoc = Autodoc.init(module, doc_location); - defer autodoc.deinit(); - try autodoc.generateZirData(); + if (!build_options.only_c) { + if (comp.emit_docs) |doc_location| { + if (comp.bin_file.options.module) |module| { + var autodoc = Autodoc.init(module, doc_location); + defer autodoc.deinit(); + try autodoc.generateZirData(); + } } } @@ -2536,11 +2520,8 @@ fn flush(comp: *Compilation, prog_node: *std.Progress.Node) !void { }; comp.link_error_flags = comp.bin_file.errorFlags(); - const use_stage1 = build_options.have_stage1 and comp.bin_file.options.use_stage1; - if (!use_stage1) { - if (comp.bin_file.options.module) |module| { - try link.File.C.flushEmitH(module); - } + if (comp.bin_file.options.module) |module| { + try link.File.C.flushEmitH(module); } } @@ -2610,7 +2591,6 @@ fn addNonIncrementalStuffToCacheManifest(comp: *Compilation, man: *Cache.Manifes // Synchronize with other matching comments: ZigOnlyHashStuff man.hash.add(comp.bin_file.options.valgrind); man.hash.add(comp.bin_file.options.single_threaded); - man.hash.add(comp.bin_file.options.use_stage1); man.hash.add(comp.bin_file.options.use_llvm); man.hash.add(comp.bin_file.options.dll_export_fns); man.hash.add(comp.bin_file.options.is_test); @@ -3010,8 +2990,6 @@ pub fn performAllTheWork( comp.work_queue_wait_group.reset(); defer comp.work_queue_wait_group.wait(); - const use_stage1 = build_options.have_stage1 and comp.bin_file.options.use_stage1; - { const astgen_frame = tracy.namedFrame("astgen"); defer astgen_frame.end(); @@ -3056,7 +3034,7 @@ pub fn performAllTheWork( } } - if (!use_stage1) { + { const outdated_and_deleted_decls_frame = tracy.namedFrame("outdated_and_deleted_decls"); defer outdated_and_deleted_decls_frame.end(); @@ -3064,15 +3042,6 @@ pub fn performAllTheWork( if (comp.bin_file.options.module) |mod| { try mod.processOutdatedAndDeletedDecls(); } - } else if (comp.bin_file.options.module) |mod| { - // If there are any AstGen compile errors, report them now to avoid - // hitting stage1 bugs. - if (mod.failed_files.count() != 0) { - return; - } - comp.updateStage1Module(main_progress_node) catch |err| { - fatal("unable to build stage1 zig object: {s}", .{@errorName(err)}); - }; } if (comp.bin_file.options.module) |mod| { @@ -3598,10 +3567,7 @@ pub fn cImport(comp: *Compilation, c_src: []const u8) !CImportResult { var man = comp.obtainCObjectCacheManifest(); defer man.deinit(); - const use_stage1 = build_options.have_stage1 and comp.bin_file.options.use_stage1; - man.hash.add(@as(u16, 0xb945)); // Random number to distinguish translate-c from compiling C objects - man.hash.add(use_stage1); man.hash.addBytes(c_src); // If the previous invocation resulted in clang errors, we will see a hit @@ -3665,7 +3631,6 @@ pub fn cImport(comp: *Compilation, c_src: []const u8) !CImportResult { new_argv.ptr + new_argv.len, &clang_errors, c_headers_dir_path_z, - use_stage1, ) catch |err| switch (err) { error.OutOfMemory => return error.OutOfMemory, error.ASTUnitFailure => { @@ -5097,8 +5062,6 @@ pub fn dump_argv(argv: []const []const u8) void { } pub fn getZigBackend(comp: Compilation) std.builtin.CompilerBackend { - const use_stage1 = build_options.have_stage1 and comp.bin_file.options.use_stage1; - if (use_stage1) return .stage1; if (build_options.have_llvm and comp.bin_file.options.use_llvm) return .stage2_llvm; const target = comp.bin_file.options.target; if (target.ofmt == .c) return .stage2_c; @@ -5394,7 +5357,6 @@ fn buildOutputFromZig( .link_mode = .Static, .function_sections = true, .no_builtin = true, - .use_stage1 = build_options.have_stage1 and comp.bin_file.options.use_stage1, .want_sanitize_c = false, .want_stack_check = false, .want_stack_protector = 0, @@ -5448,199 +5410,6 @@ fn buildOutputFromZig( }; } -fn updateStage1Module(comp: *Compilation, main_progress_node: *std.Progress.Node) !void { - const tracy_trace = trace(@src()); - defer tracy_trace.end(); - - var arena_allocator = std.heap.ArenaAllocator.init(comp.gpa); - defer arena_allocator.deinit(); - const arena = arena_allocator.allocator(); - - // Here we use the legacy stage1 C++ compiler to compile Zig code. - const mod = comp.bin_file.options.module.?; - const directory = mod.zig_cache_artifact_directory; // Just an alias to make it shorter to type. - const main_zig_file = try mod.main_pkg.root_src_directory.join(arena, &[_][]const u8{ - mod.main_pkg.root_src_path, - }); - const zig_lib_dir = comp.zig_lib_directory.path.?; - const target = comp.getTarget(); - - // The include_compiler_rt stored in the bin file options here means that we need - // compiler-rt symbols *somehow*. However, in the context of using the stage1 backend - // we need to tell stage1 to include compiler-rt only if stage1 is the place that - // needs to provide those symbols. Otherwise the stage2 infrastructure will take care - // of it in the linker, by putting compiler_rt.o into a static archive, or linking - // compiler_rt.a against an executable. In other words we only want to set this flag - // for stage1 if we are using build-obj. - const include_compiler_rt = comp.bin_file.options.output_mode == .Obj and - comp.bin_file.options.include_compiler_rt; - - const stage2_target = try arena.create(stage1.Stage2Target); - stage2_target.* = .{ - .arch = @enumToInt(target.cpu.arch) + 1, // skip over ZigLLVM_UnknownArch - .os = @enumToInt(target.os.tag), - .abi = @enumToInt(target.abi), - .is_native_os = comp.bin_file.options.is_native_os, - .is_native_cpu = false, // Only true when bootstrapping the compiler. - .llvm_cpu_name = if (target.cpu.model.llvm_name) |s| s.ptr else null, - .llvm_cpu_features = comp.bin_file.options.llvm_cpu_features.?, - .llvm_target_abi = if (target_util.llvmMachineAbi(target)) |s| s.ptr else null, - }; - - const main_pkg_path = mod.main_pkg.root_src_directory.path orelse ""; - const builtin_pkg = mod.main_pkg.table.get("builtin").?; - const builtin_zig_path = try builtin_pkg.root_src_directory.join(arena, &.{builtin_pkg.root_src_path}); - - const stage1_module = stage1.create( - @enumToInt(comp.bin_file.options.optimize_mode), - main_pkg_path.ptr, - main_pkg_path.len, - main_zig_file.ptr, - main_zig_file.len, - zig_lib_dir.ptr, - zig_lib_dir.len, - stage2_target, - comp.bin_file.options.is_test, - ) orelse return error.OutOfMemory; - - const emit_bin_path = if (comp.bin_file.options.emit != null) blk: { - const obj_basename = try std.zig.binNameAlloc(arena, .{ - .root_name = comp.bin_file.options.root_name, - .target = target, - .output_mode = .Obj, - }); - break :blk try directory.join(arena, &[_][]const u8{obj_basename}); - } else ""; - - if (mod.emit_h != null) { - log.warn("-femit-h is not available in the stage1 backend; no .h file will be produced", .{}); - } - const emit_h_loc: ?EmitLoc = if (mod.emit_h) |emit_h| emit_h.loc else null; - const emit_h_path = try stage1LocPath(arena, emit_h_loc, directory); - const emit_asm_path = try stage1LocPath(arena, comp.emit_asm, directory); - const emit_llvm_ir_path = try stage1LocPath(arena, comp.emit_llvm_ir, directory); - const emit_llvm_bc_path = try stage1LocPath(arena, comp.emit_llvm_bc, directory); - const stage1_pkg = try createStage1Pkg(arena, "root", mod.main_pkg, null); - const test_filter = comp.test_filter orelse ""[0..0]; - const test_name_prefix = comp.test_name_prefix orelse ""[0..0]; - const subsystem = if (comp.bin_file.options.subsystem) |s| - @intToEnum(stage1.TargetSubsystem, @enumToInt(s)) - else - stage1.TargetSubsystem.Auto; - stage1_module.* = .{ - .root_name_ptr = comp.bin_file.options.root_name.ptr, - .root_name_len = comp.bin_file.options.root_name.len, - .emit_o_ptr = emit_bin_path.ptr, - .emit_o_len = emit_bin_path.len, - .emit_h_ptr = emit_h_path.ptr, - .emit_h_len = emit_h_path.len, - .emit_asm_ptr = emit_asm_path.ptr, - .emit_asm_len = emit_asm_path.len, - .emit_llvm_ir_ptr = emit_llvm_ir_path.ptr, - .emit_llvm_ir_len = emit_llvm_ir_path.len, - .emit_bitcode_ptr = emit_llvm_bc_path.ptr, - .emit_bitcode_len = emit_llvm_bc_path.len, - .builtin_zig_path_ptr = builtin_zig_path.ptr, - .builtin_zig_path_len = builtin_zig_path.len, - .test_filter_ptr = test_filter.ptr, - .test_filter_len = test_filter.len, - .test_name_prefix_ptr = test_name_prefix.ptr, - .test_name_prefix_len = test_name_prefix.len, - .userdata = @ptrToInt(comp), - .main_pkg = stage1_pkg, - .code_model = @enumToInt(comp.bin_file.options.machine_code_model), - .subsystem = subsystem, - .err_color = @enumToInt(comp.color), - .pic = comp.bin_file.options.pic, - .pie = comp.bin_file.options.pie, - .lto = comp.bin_file.options.lto, - .unwind_tables = comp.unwind_tables, - .link_libc = comp.bin_file.options.link_libc, - .link_libcpp = comp.bin_file.options.link_libcpp, - .strip = comp.bin_file.options.strip, - .is_single_threaded = comp.bin_file.options.single_threaded, - .dll_export_fns = comp.bin_file.options.dll_export_fns, - .link_mode_dynamic = comp.bin_file.options.link_mode == .Dynamic, - .valgrind_enabled = comp.bin_file.options.valgrind, - .tsan_enabled = comp.bin_file.options.tsan, - .function_sections = comp.bin_file.options.function_sections, - .include_compiler_rt = include_compiler_rt, - .enable_stack_probing = comp.bin_file.options.stack_check, - .red_zone = comp.bin_file.options.red_zone, - .omit_frame_pointer = comp.bin_file.options.omit_frame_pointer, - .enable_time_report = comp.time_report, - .enable_stack_report = comp.stack_report, - .test_is_evented = comp.test_evented_io, - .verbose_ir = comp.verbose_air, - .verbose_llvm_ir = comp.verbose_llvm_ir, - .verbose_cimport = comp.verbose_cimport, - .verbose_llvm_cpu_features = comp.verbose_llvm_cpu_features, - .main_progress_node = main_progress_node, - .have_c_main = false, - .have_winmain = false, - .have_wwinmain = false, - .have_winmain_crt_startup = false, - .have_wwinmain_crt_startup = false, - .have_dllmain_crt_startup = false, - }; - - stage1_module.build_object(); - - mod.stage1_flags = .{ - .have_c_main = stage1_module.have_c_main, - .have_winmain = stage1_module.have_winmain, - .have_wwinmain = stage1_module.have_wwinmain, - .have_winmain_crt_startup = stage1_module.have_winmain_crt_startup, - .have_wwinmain_crt_startup = stage1_module.have_wwinmain_crt_startup, - .have_dllmain_crt_startup = stage1_module.have_dllmain_crt_startup, - }; - - stage1_module.destroy(); -} - -fn stage1LocPath(arena: Allocator, opt_loc: ?EmitLoc, cache_directory: Directory) ![]const u8 { - const loc = opt_loc orelse return ""; - const directory = loc.directory orelse cache_directory; - return directory.join(arena, &[_][]const u8{loc.basename}); -} - -fn createStage1Pkg( - arena: Allocator, - name: []const u8, - pkg: *Package, - parent_pkg: ?*stage1.Pkg, -) error{OutOfMemory}!*stage1.Pkg { - const child_pkg = try arena.create(stage1.Pkg); - - const pkg_children = blk: { - var children = std.ArrayList(*stage1.Pkg).init(arena); - var it = pkg.table.iterator(); - while (it.next()) |entry| { - if (mem.eql(u8, entry.key_ptr.*, "std") or - mem.eql(u8, entry.key_ptr.*, "builtin") or - mem.eql(u8, entry.key_ptr.*, "root")) - { - continue; - } - try children.append(try createStage1Pkg(arena, entry.key_ptr.*, entry.value_ptr.*, child_pkg)); - } - break :blk children.items; - }; - - const src_path = try pkg.root_src_directory.join(arena, &[_][]const u8{pkg.root_src_path}); - - child_pkg.* = .{ - .name_ptr = name.ptr, - .name_len = name.len, - .path_ptr = src_path.ptr, - .path_len = src_path.len, - .children_ptr = pkg_children.ptr, - .children_len = pkg_children.len, - .parent = parent_pkg, - }; - return child_pkg; -} - pub fn build_crt_file( comp: *Compilation, root_name: []const u8, diff --git a/src/Sema.zig b/src/Sema.zig index debd18005abb..ecabd7b65edf 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -2121,8 +2121,6 @@ fn failWithUseOfAsync(sema: *Sema, block: *Block, src: LazySrcLoc) CompileError const msg = msg: { const msg = try sema.errMsg(block, src, "async has not been implemented in the self-hosted compiler yet", .{}); errdefer msg.destroy(sema.gpa); - - try sema.errNote(block, src, msg, "to use async enable the stage1 compiler with either '-fstage1' or by setting '.use_stage1 = true` in your 'build.zig' script", .{}); break :msg msg; }; return sema.failWithOwnedErrorMsg(msg); @@ -15084,14 +15082,11 @@ fn zirBuiltinSrc( const file_name_val = blk: { var anon_decl = try block.startAnonDecl(); defer anon_decl.deinit(); - const relative_path = try fn_owner_decl.getFileScope().fullPath(sema.arena); - const absolute_path = std.fs.realpathAlloc(sema.arena, relative_path) catch |err| { - return sema.fail(block, src, "failed to get absolute path of file '{s}': {s}", .{ relative_path, @errorName(err) }); - }; - const aboslute_duped = try anon_decl.arena().dupeZ(u8, absolute_path); + // The compiler must not call realpath anywhere. + const name = try fn_owner_decl.getFileScope().fullPathZ(anon_decl.arena()); const new_decl = try anon_decl.finish( - try Type.Tag.array_u8_sentinel_0.create(anon_decl.arena(), aboslute_duped.len), - try Value.Tag.bytes.create(anon_decl.arena(), aboslute_duped[0 .. aboslute_duped.len + 1]), + try Type.Tag.array_u8_sentinel_0.create(anon_decl.arena(), name.len), + try Value.Tag.bytes.create(anon_decl.arena(), name[0 .. name.len + 1]), 0, // default alignment ); break :blk try Value.Tag.decl_ref.create(sema.arena, new_decl); @@ -20956,6 +20951,7 @@ fn zirFieldParentPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileEr } try sema.requireRuntimeBlock(block, src, ptr_src); + try sema.queueFullTypeResolution(result_ptr); return block.addInst(.{ .tag = .field_parent_ptr, .data = .{ .ty_pl = .{ diff --git a/src/codegen/c.zig b/src/codegen/c.zig index a569e47401f6..0c2822739c1e 100644 --- a/src/codegen/c.zig +++ b/src/codegen/c.zig @@ -120,6 +120,7 @@ pub fn typeToCIdentifier(ty: Type, mod: *Module) std.fmt.Formatter(formatTypeAsC } const reserved_idents = std.ComptimeStringMap(void, .{ + // C language .{ "alignas", { @setEvalBranchQuota(4000); } }, @@ -215,14 +216,22 @@ const reserved_idents = std.ComptimeStringMap(void, .{ .{ "void", {} }, .{ "volatile", {} }, .{ "while ", {} }, + + // windows.h + .{ "max", {} }, + .{ "min", {} }, }); fn isReservedIdent(ident: []const u8) bool { - if (ident.len >= 2 and ident[0] == '_') { + if (ident.len >= 2 and ident[0] == '_') { // C language switch (ident[1]) { 'A'...'Z', '_' => return true, else => return false, } + } else if (std.mem.startsWith(u8, ident, "DUMMYSTRUCTNAME") or + std.mem.startsWith(u8, ident, "DUMMYUNIONNAME")) + { // windows.h + return true; } else return reserved_idents.has(ident); } @@ -4425,8 +4434,9 @@ fn airSwitchBr(f: *Function, inst: Air.Inst.Index) !CValue { try writer.writeByte(')'); } try f.object.dg.renderValue(writer, condition_ty, f.air.value(item).?, .Other); - try writer.writeAll(": "); + try writer.writeByte(':'); } + try writer.writeByte(' '); if (case_i != last_case_i) { const old_value_map = f.value_map; @@ -5935,16 +5945,15 @@ fn airMemset(f: *Function, inst: Air.Inst.Index) !CValue { const dest_ptr = try f.resolveInst(pl_op.operand); const value = try f.resolveInst(extra.lhs); const len = try f.resolveInst(extra.rhs); - try reap(f, inst, &.{ pl_op.operand, extra.lhs, extra.rhs }); const writer = f.object.writer(); if (dest_ty.isVolatilePtr()) { var u8_ptr_pl = dest_ty.ptrInfo(); u8_ptr_pl.data.pointee_type = Type.u8; const u8_ptr_ty = Type.initPayload(&u8_ptr_pl.base); + const index = try f.allocLocal(inst, Type.usize); try writer.writeAll("for ("); - const index = try f.allocLocal(inst, Type.usize); try f.writeCValue(writer, index, .Other); try writer.writeAll(" = "); try f.object.dg.renderValue(writer, Type.usize, Value.zero, .Initializer); @@ -5966,11 +5975,13 @@ fn airMemset(f: *Function, inst: Air.Inst.Index) !CValue { try f.writeCValue(writer, value, .FunctionArgument); try writer.writeAll(";\n"); + try reap(f, inst, &.{ pl_op.operand, extra.lhs, extra.rhs }); try freeLocal(f, inst, index.local, 0); return CValue.none; } + try reap(f, inst, &.{ pl_op.operand, extra.lhs, extra.rhs }); try writer.writeAll("memset("); try f.writeCValue(writer, dest_ptr, .FunctionArgument); try writer.writeAll(", "); diff --git a/src/introspect.zig b/src/introspect.zig index 27925ab667a6..2eeae956ec91 100644 --- a/src/introspect.zig +++ b/src/introspect.zig @@ -37,34 +37,7 @@ fn testZigInstallPrefix(base_dir: fs.Dir) ?Compilation.Directory { /// based on a hard-coded Preopen directory ("/zig") pub fn findZigExePath(allocator: mem.Allocator) ![]u8 { if (builtin.os.tag == .wasi) { - var args = try std.process.argsWithAllocator(allocator); - defer args.deinit(); - // On WASI, argv[0] is always just the basename of the current executable - const argv0 = args.next() orelse return error.FileNotFound; - - // Check these paths: - // 1. "/zig/{exe_name}" - // 2. "/zig/bin/{exe_name}" - const base_paths_to_check = &[_][]const u8{ "/zig", "/zig/bin" }; - const exe_names_to_check = &[_][]const u8{ fs.path.basename(argv0), "zig.wasm" }; - - for (base_paths_to_check) |base_path| { - for (exe_names_to_check) |exe_name| { - const test_path = fs.path.join(allocator, &.{ base_path, exe_name }) catch continue; - defer allocator.free(test_path); - - // Make sure it's a file we're pointing to - const file = os.fstatat(os.wasi.AT.FDCWD, test_path, 0) catch continue; - if (file.filetype != .REGULAR_FILE) continue; - - // Path seems to be valid, let's try to turn it into an absolute path - var real_path_buf: [fs.MAX_PATH_BYTES]u8 = undefined; - if (os.realpath(test_path, &real_path_buf)) |real_path| { - return allocator.dupe(u8, real_path); // Success: return absolute path - } else |_| continue; - } - } - return error.FileNotFound; + @compileError("this function is unsupported on WASI"); } return fs.selfExePathAlloc(allocator); @@ -107,6 +80,9 @@ pub fn findZigLibDirFromSelfExe( /// Caller owns returned memory. pub fn resolveGlobalCacheDir(allocator: mem.Allocator) ![]u8 { + if (builtin.os.tag == .wasi) { + @compileError("on WASI the global cache dir must be resolved with preopens"); + } if (std.process.getEnvVarOwned(allocator, "ZIG_GLOBAL_CACHE_DIR")) |value| { if (value.len > 0) { return value; @@ -125,17 +101,7 @@ pub fn resolveGlobalCacheDir(allocator: mem.Allocator) ![]u8 { } } - if (builtin.os.tag == .wasi) { - // On WASI, we have no way to get an App data dir, so we try to use a fixed - // Preopen path "/cache" as a last resort - const path = "/cache"; - - const file = os.fstatat(os.wasi.AT.FDCWD, path, 0) catch return error.CacheDirUnavailable; - if (file.filetype != .DIRECTORY) return error.CacheDirUnavailable; - return allocator.dupe(u8, path); - } else { - return fs.getAppDataDir(allocator, appname); - } + return fs.getAppDataDir(allocator, appname); } /// Similar to std.fs.path.resolve, with a few important differences: diff --git a/src/link.zig b/src/link.zig index 4dfcf171af15..e57ffd425662 100644 --- a/src/link.zig +++ b/src/link.zig @@ -155,7 +155,6 @@ pub const Options = struct { build_id: bool, disable_lld_caching: bool, is_test: bool, - use_stage1: bool, hash_style: HashStyle, major_subsystem_version: ?u32, minor_subsystem_version: ?u32, @@ -293,8 +292,7 @@ pub const File = struct { return &(try MachO.openPath(allocator, options)).base; } - const use_stage1 = build_options.have_stage1 and options.use_stage1; - if (use_stage1 or options.emit == null) { + if (options.emit == null) { return switch (options.target.ofmt) { .coff => &(try Coff.createEmpty(allocator, options)).base, .elf => &(try Elf.createEmpty(allocator, options)).base, @@ -983,24 +981,7 @@ pub const File = struct { // If there is no Zig code to compile, then we should skip flushing the output file // because it will not be part of the linker line anyway. - const module_obj_path: ?[]const u8 = if (base.options.module) |module| blk: { - const use_stage1 = build_options.have_stage1 and base.options.use_stage1; - if (use_stage1) { - const obj_basename = try std.zig.binNameAlloc(arena, .{ - .root_name = base.options.root_name, - .target = base.options.target, - .output_mode = .Obj, - }); - switch (base.options.cache_mode) { - .incremental => break :blk try module.zig_cache_artifact_directory.join( - arena, - &[_][]const u8{obj_basename}, - ), - .whole => break :blk try fs.path.join(arena, &.{ - fs.path.dirname(full_out_path_z).?, obj_basename, - }), - } - } + const module_obj_path: ?[]const u8 = if (base.options.module != null) blk: { try base.flushModule(comp, prog_node); const dirname = fs.path.dirname(full_out_path_z) orelse "."; diff --git a/src/link/Coff.zig b/src/link/Coff.zig index 3f89de960881..aa94704c5451 100644 --- a/src/link/Coff.zig +++ b/src/link/Coff.zig @@ -248,8 +248,7 @@ pub fn createEmpty(gpa: Allocator, options: link.Options) !*Coff { }; const use_llvm = build_options.have_llvm and options.use_llvm; - const use_stage1 = build_options.have_stage1 and options.use_stage1; - if (use_llvm and !use_stage1) { + if (use_llvm) { self.llvm_object = try LlvmObject.create(gpa, options); } return self; diff --git a/src/link/Coff/lld.zig b/src/link/Coff/lld.zig index 7c53ef30bdb4..c1edb55b8092 100644 --- a/src/link/Coff/lld.zig +++ b/src/link/Coff/lld.zig @@ -30,25 +30,7 @@ pub fn linkWithLLD(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod // If there is no Zig code to compile, then we should skip flushing the output file because it // will not be part of the linker line anyway. - const module_obj_path: ?[]const u8 = if (self.base.options.module) |module| blk: { - const use_stage1 = build_options.have_stage1 and self.base.options.use_stage1; - if (use_stage1) { - const obj_basename = try std.zig.binNameAlloc(arena, .{ - .root_name = self.base.options.root_name, - .target = self.base.options.target, - .output_mode = .Obj, - }); - switch (self.base.options.cache_mode) { - .incremental => break :blk try module.zig_cache_artifact_directory.join( - arena, - &[_][]const u8{obj_basename}, - ), - .whole => break :blk try fs.path.join(arena, &.{ - fs.path.dirname(full_out_path).?, obj_basename, - }), - } - } - + const module_obj_path: ?[]const u8 = if (self.base.options.module != null) blk: { try self.flushModule(comp, prog_node); if (fs.path.dirname(full_out_path)) |dirname| { diff --git a/src/link/Elf.zig b/src/link/Elf.zig index f98e33e58b2a..b7968b3f1c10 100644 --- a/src/link/Elf.zig +++ b/src/link/Elf.zig @@ -328,8 +328,7 @@ pub fn createEmpty(gpa: Allocator, options: link.Options) !*Elf { .page_size = page_size, }; const use_llvm = build_options.have_llvm and options.use_llvm; - const use_stage1 = build_options.have_stage1 and options.use_stage1; - if (use_llvm and !use_stage1) { + if (use_llvm) { self.llvm_object = try LlvmObject.create(gpa, options); } return self; @@ -1228,25 +1227,7 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v // If there is no Zig code to compile, then we should skip flushing the output file because it // will not be part of the linker line anyway. - const module_obj_path: ?[]const u8 = if (self.base.options.module) |module| blk: { - // stage1 puts the object file in the cache directory. - if (self.base.options.use_stage1) { - const obj_basename = try std.zig.binNameAlloc(arena, .{ - .root_name = self.base.options.root_name, - .target = self.base.options.target, - .output_mode = .Obj, - }); - switch (self.base.options.cache_mode) { - .incremental => break :blk try module.zig_cache_artifact_directory.join( - arena, - &[_][]const u8{obj_basename}, - ), - .whole => break :blk try fs.path.join(arena, &.{ - fs.path.dirname(full_out_path).?, obj_basename, - }), - } - } - + const module_obj_path: ?[]const u8 = if (self.base.options.module != null) blk: { try self.flushModule(comp, prog_node); if (fs.path.dirname(full_out_path)) |dirname| { diff --git a/src/link/MachO.zig b/src/link/MachO.zig index fb651edbe38e..8c9e5329f2ec 100644 --- a/src/link/MachO.zig +++ b/src/link/MachO.zig @@ -290,8 +290,7 @@ pub const Export = struct { pub fn openPath(allocator: Allocator, options: link.Options) !*MachO { assert(options.target.ofmt == .macho); - const use_stage1 = build_options.have_stage1 and options.use_stage1; - if (use_stage1 or options.emit == null or options.module == null) { + if (options.emit == null or options.module == null) { return createEmpty(allocator, options); } @@ -377,7 +376,6 @@ pub fn createEmpty(gpa: Allocator, options: link.Options) !*MachO { const cpu_arch = options.target.cpu.arch; const page_size: u16 = if (cpu_arch == .aarch64) 0x4000 else 0x1000; const use_llvm = build_options.have_llvm and options.use_llvm; - const use_stage1 = build_options.have_stage1 and options.use_stage1; const self = try gpa.create(MachO); errdefer gpa.destroy(self); @@ -390,13 +388,13 @@ pub fn createEmpty(gpa: Allocator, options: link.Options) !*MachO { .file = null, }, .page_size = page_size, - .mode = if (use_stage1 or use_llvm or options.module == null or options.cache_mode == .whole) + .mode = if (use_llvm or options.module == null or options.cache_mode == .whole) .one_shot else .incremental, }; - if (use_llvm and !use_stage1) { + if (use_llvm) { self.llvm_object = try LlvmObject.create(gpa, options); } diff --git a/src/link/MachO/zld.zig b/src/link/MachO/zld.zig index 5baaf71f18b0..9baecd326a3c 100644 --- a/src/link/MachO/zld.zig +++ b/src/link/MachO/zld.zig @@ -3746,24 +3746,7 @@ pub fn linkWithZld(macho_file: *MachO, comp: *Compilation, prog_node: *std.Progr // If there is no Zig code to compile, then we should skip flushing the output file because it // will not be part of the linker line anyway. - const module_obj_path: ?[]const u8 = if (options.module) |module| blk: { - if (options.use_stage1) { - const obj_basename = try std.zig.binNameAlloc(arena, .{ - .root_name = options.root_name, - .target = target, - .output_mode = .Obj, - }); - switch (options.cache_mode) { - .incremental => break :blk try module.zig_cache_artifact_directory.join( - arena, - &[_][]const u8{obj_basename}, - ), - .whole => break :blk try fs.path.join(arena, &.{ - fs.path.dirname(full_out_path).?, obj_basename, - }), - } - } - + const module_obj_path: ?[]const u8 = if (options.module != null) blk: { try macho_file.flushModule(comp, prog_node); if (fs.path.dirname(full_out_path)) |dirname| { diff --git a/src/link/Wasm.zig b/src/link/Wasm.zig index adcb539bd65a..4a9db75c9806 100644 --- a/src/link/Wasm.zig +++ b/src/link/Wasm.zig @@ -382,8 +382,7 @@ pub fn createEmpty(gpa: Allocator, options: link.Options) !*Wasm { }; const use_llvm = build_options.have_llvm and options.use_llvm; - const use_stage1 = build_options.have_stage1 and options.use_stage1; - if (use_llvm and !use_stage1) { + if (use_llvm) { wasm.llvm_object = try LlvmObject.create(gpa, options); } return wasm; @@ -2986,25 +2985,7 @@ fn linkWithLLD(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) ! // If there is no Zig code to compile, then we should skip flushing the output file because it // will not be part of the linker line anyway. - const module_obj_path: ?[]const u8 = if (wasm.base.options.module) |mod| blk: { - const use_stage1 = build_options.have_stage1 and wasm.base.options.use_stage1; - if (use_stage1) { - const obj_basename = try std.zig.binNameAlloc(arena, .{ - .root_name = wasm.base.options.root_name, - .target = wasm.base.options.target, - .output_mode = .Obj, - }); - switch (wasm.base.options.cache_mode) { - .incremental => break :blk try mod.zig_cache_artifact_directory.join( - arena, - &[_][]const u8{obj_basename}, - ), - .whole => break :blk try fs.path.join(arena, &.{ - fs.path.dirname(full_out_path).?, obj_basename, - }), - } - } - + const module_obj_path: ?[]const u8 = if (wasm.base.options.module != null) blk: { try wasm.flushModule(comp, prog_node); if (fs.path.dirname(full_out_path)) |dirname| { @@ -3198,26 +3179,19 @@ fn linkWithLLD(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) ! if (wasm.base.options.module) |mod| { // when we use stage1, we use the exports that stage1 provided us. // For stage2, we can directly retrieve them from the module. - const use_stage1 = build_options.have_stage1 and wasm.base.options.use_stage1; - if (use_stage1) { - for (comp.export_symbol_names.items) |symbol_name| { - try argv.append(try std.fmt.allocPrint(arena, "--export={s}", .{symbol_name})); - } - } else { - const skip_export_non_fn = target.os.tag == .wasi and - wasm.base.options.wasi_exec_model == .command; - for (mod.decl_exports.values()) |exports| { - for (exports.items) |exprt| { - const exported_decl = mod.declPtr(exprt.exported_decl); - if (skip_export_non_fn and exported_decl.ty.zigTypeTag() != .Fn) { - // skip exporting symbols when we're building a WASI command - // and the symbol is not a function - continue; - } - const symbol_name = exported_decl.name; - const arg = try std.fmt.allocPrint(arena, "--export={s}", .{symbol_name}); - try argv.append(arg); + const skip_export_non_fn = target.os.tag == .wasi and + wasm.base.options.wasi_exec_model == .command; + for (mod.decl_exports.values()) |exports| { + for (exports.items) |exprt| { + const exported_decl = mod.declPtr(exprt.exported_decl); + if (skip_export_non_fn and exported_decl.ty.zigTypeTag() != .Fn) { + // skip exporting symbols when we're building a WASI command + // and the symbol is not a function + continue; } + const symbol_name = exported_decl.name; + const arg = try std.fmt.allocPrint(arena, "--export={s}", .{symbol_name}); + try argv.append(arg); } } } diff --git a/src/main.zig b/src/main.zig index c1bf8c88d165..067a8246317b 100644 --- a/src/main.zig +++ b/src/main.zig @@ -27,6 +27,23 @@ const crash_report = @import("crash_report.zig"); // Crash report needs to override the panic handler and other root decls pub usingnamespace crash_report.root_decls; +var wasi_preopens: fs.wasi.Preopens = undefined; +pub inline fn wasi_cwd() fs.Dir { + // Expect the first preopen to be current working directory. + const cwd_fd: std.os.fd_t = 3; + assert(mem.eql(u8, wasi_preopens.names[cwd_fd], ".")); + return .{ .fd = cwd_fd }; +} + +pub fn getWasiPreopen(name: []const u8) Compilation.Directory { + return .{ + .path = name, + .handle = .{ + .fd = wasi_preopens.find(name) orelse fatal("WASI preopen not found: '{s}'", .{name}), + }, + }; +} + pub fn fatal(comptime format: []const u8, args: anytype) noreturn { std.log.err(format, args); process.exit(1); @@ -135,8 +152,11 @@ var general_purpose_allocator = std.heap.GeneralPurposeAllocator(.{ pub fn main() anyerror!void { crash_report.initialize(); - const use_gpa = build_options.force_gpa or !builtin.link_libc; + const use_gpa = (build_options.force_gpa or !builtin.link_libc) and builtin.os.tag != .wasi; const gpa = gpa: { + if (builtin.os.tag == .wasi) { + break :gpa std.heap.wasm_allocator; + } if (use_gpa) { break :gpa general_purpose_allocator.allocator(); } @@ -161,14 +181,19 @@ pub fn main() anyerror!void { return mainArgs(gpa_tracy.allocator(), arena, args); } - // WASI: `--dir` instructs the WASM runtime to "preopen" a directory, making - // it available to the us, the guest program. This is the only way for us to - // access files/dirs on the host filesystem if (builtin.os.tag == .wasi) { - // This sets our CWD to "/preopens/cwd" - // Dot-prefixed preopens like `--dir=.` are "mounted" at "/preopens/cwd" - // Other preopens like `--dir=lib` are "mounted" at "/" - try std.os.initPreopensWasi(std.heap.page_allocator, "/preopens/cwd"); + wasi_preopens = try fs.wasi.preopensAlloc(arena); + } + + // Short circuit some of the other logic for bootstrapping. + if (build_options.only_c) { + if (mem.eql(u8, args[1], "build-exe")) { + return buildOutputType(gpa, arena, args, .{ .build = .Exe }); + } else if (mem.eql(u8, args[1], "build-obj")) { + return buildOutputType(gpa, arena, args, .{ .build = .Obj }); + } else { + @panic("only build-exe or build-obj is supported in a -Donly-c build"); + } } return mainArgs(gpa, arena, args); @@ -394,8 +419,6 @@ const usage_build_generic = \\ -fno-LLVM Prevent using LLVM as the codegen backend \\ -fClang Force using Clang as the C/C++ compilation backend \\ -fno-Clang Prevent using Clang as the C/C++ compilation backend - \\ -fstage1 Force using bootstrap compiler as the codegen backend - \\ -fno-stage1 Prevent using bootstrap compiler as the codegen backend \\ -freference-trace[=num] How many lines of reference trace should be shown per compile error \\ -fno-reference-trace Disable reference trace \\ -fsingle-threaded Code assumes there is only one thread @@ -719,7 +742,6 @@ fn buildOutputType( var use_llvm: ?bool = null; var use_lld: ?bool = null; var use_clang: ?bool = null; - var use_stage1: ?bool = null; var link_eh_frame_hdr = false; var link_emit_relocs = false; var each_lib_rpath: ?bool = null; @@ -1158,10 +1180,6 @@ fn buildOutputType( use_clang = true; } else if (mem.eql(u8, arg, "-fno-Clang")) { use_clang = false; - } else if (mem.eql(u8, arg, "-fstage1")) { - use_stage1 = true; - } else if (mem.eql(u8, arg, "-fno-stage1")) { - use_stage1 = false; } else if (mem.eql(u8, arg, "-freference-trace")) { reference_trace = 256; } else if (mem.startsWith(u8, arg, "-freference-trace=")) { @@ -1385,6 +1403,8 @@ fn buildOutputType( } }, .cc, .cpp => { + if (build_options.only_c) unreachable; + emit_h = .no; soname = .no; ensure_libc_on_non_freestanding = true; @@ -2301,7 +2321,7 @@ fn buildOutputType( }, } - if (std.fs.path.isAbsolute(lib_name)) { + if (fs.path.isAbsolute(lib_name)) { fatal("cannot use absolute path as a system library: {s}", .{lib_name}); } @@ -2764,18 +2784,33 @@ fn buildOutputType( } } - const self_exe_path = try introspect.findZigExePath(arena); - var zig_lib_directory: Compilation.Directory = if (override_lib_dir) |unresolved_lib_dir| l: { - const lib_dir = try introspect.resolvePath(arena, unresolved_lib_dir); - break :l .{ - .path = lib_dir, - .handle = fs.cwd().openDir(lib_dir, .{}) catch |err| { - fatal("unable to open zig lib directory '{s}': {s}", .{ lib_dir, @errorName(err) }); - }, + const self_exe_path: ?[]const u8 = if (!process.can_spawn) + null + else + introspect.findZigExePath(arena) catch |err| { + fatal("unable to find zig self exe path: {s}", .{@errorName(err)}); }; - } else introspect.findZigLibDirFromSelfExe(arena, self_exe_path) catch |err| { - fatal("unable to find zig installation directory: {s}\n", .{@errorName(err)}); + + var zig_lib_directory: Compilation.Directory = d: { + if (override_lib_dir) |unresolved_lib_dir| { + const lib_dir = try introspect.resolvePath(arena, unresolved_lib_dir); + break :d .{ + .path = lib_dir, + .handle = fs.cwd().openDir(lib_dir, .{}) catch |err| { + fatal("unable to open zig lib directory '{s}': {s}", .{ lib_dir, @errorName(err) }); + }, + }; + } else if (builtin.os.tag == .wasi) { + break :d getWasiPreopen("/lib"); + } else if (self_exe_path) |p| { + break :d introspect.findZigLibDirFromSelfExe(arena, p) catch |err| { + fatal("unable to find zig installation directory: {s}", .{@errorName(err)}); + }; + } else { + unreachable; + } }; + defer zig_lib_directory.handle.close(); var thread_pool: ThreadPool = undefined; @@ -2792,7 +2827,16 @@ fn buildOutputType( } var global_cache_directory: Compilation.Directory = l: { - const p = override_global_cache_dir orelse try introspect.resolveGlobalCacheDir(arena); + if (override_global_cache_dir) |p| { + break :l .{ + .handle = try fs.cwd().makeOpenPath(p, .{}), + .path = p, + }; + } + if (builtin.os.tag == .wasi) { + break :l getWasiPreopen("/cache"); + } + const p = try introspect.resolveGlobalCacheDir(arena); break :l .{ .handle = try fs.cwd().makeOpenPath(p, .{}), .path = p, @@ -2909,7 +2953,6 @@ fn buildOutputType( .use_llvm = use_llvm, .use_lld = use_lld, .use_clang = use_clang, - .use_stage1 = use_stage1, .hash_style = hash_style, .rdynamic = rdynamic, .linker_script = linker_script, @@ -3024,8 +3067,7 @@ fn buildOutputType( return std.io.getStdOut().writeAll(try comp.generateBuiltinZigSource(arena)); } if (arg_mode == .translate_c) { - const stage1_mode = use_stage1 orelse false; - return cmdTranslateC(comp, arena, have_enable_cache, stage1_mode); + return cmdTranslateC(comp, arena, have_enable_cache); } const hook: AfterUpdateHook = blk: { @@ -3044,6 +3086,7 @@ fn buildOutputType( error.SemanticAnalyzeFail => if (!watch) process.exit(1), else => |e| return e, }; + if (build_options.only_c) return cleanExit(); try comp.makeBinFileExecutable(); if (test_exec_args.items.len == 0 and object_format == .c) default_exec_args: { @@ -3093,7 +3136,7 @@ fn buildOutputType( gpa, arena, test_exec_args.items, - self_exe_path, + self_exe_path.?, arg_mode, target_info, watch, @@ -3165,7 +3208,7 @@ fn buildOutputType( gpa, arena, test_exec_args.items, - self_exe_path, + self_exe_path.?, arg_mode, target_info, watch, @@ -3190,7 +3233,7 @@ fn buildOutputType( gpa, arena, test_exec_args.items, - self_exe_path, + self_exe_path.?, arg_mode, target_info, watch, @@ -3452,7 +3495,7 @@ fn freePkgTree(gpa: Allocator, pkg: *Package, free_parent: bool) void { } } -fn cmdTranslateC(comp: *Compilation, arena: Allocator, enable_cache: bool, stage1_mode: bool) !void { +fn cmdTranslateC(comp: *Compilation, arena: Allocator, enable_cache: bool) !void { if (!build_options.have_llvm) fatal("cannot translate-c: compiler built without LLVM extensions", .{}); @@ -3465,7 +3508,6 @@ fn cmdTranslateC(comp: *Compilation, arena: Allocator, enable_cache: bool, stage defer if (enable_cache) man.deinit(); man.hash.add(@as(u16, 0xb945)); // Random number to distinguish translate-c from compiling C objects - man.hash.add(stage1_mode); man.hashCSource(c_source_file) catch |err| { fatal("unable to process '{s}': {s}", .{ c_source_file.src_path, @errorName(err) }); }; @@ -3517,7 +3559,6 @@ fn cmdTranslateC(comp: *Compilation, arena: Allocator, enable_cache: bool, stage new_argv.ptr + new_argv.len, &clang_errors, c_headers_dir_path_z, - stage1_mode, ) catch |err| switch (err) { error.OutOfMemory => return error.OutOfMemory, error.ASTUnitFailure => fatal("clang API returned errors but due to a clang bug, it is not exposing the errors for zig to see. For more details: https://github.com/ziglang/zig/issues/4455", .{}), @@ -3536,7 +3577,7 @@ fn cmdTranslateC(comp: *Compilation, arena: Allocator, enable_cache: bool, stage defer tree.deinit(comp.gpa); if (out_dep_path) |dep_file_path| { - const dep_basename = std.fs.path.basename(dep_file_path); + const dep_basename = fs.path.basename(dep_file_path); // Add the files depended on to the cache system. try man.addDepFilePost(zig_cache_tmp_dir, dep_basename); // Just to save disk space, we delete the file because it is never needed again. @@ -3763,8 +3804,6 @@ pub const usage_build = \\ Build a project from build.zig. \\ \\Options: - \\ -fstage1 Force using bootstrap compiler as the codegen backend - \\ -fno-stage1 Prevent using bootstrap compiler as the codegen backend \\ -freference-trace[=num] How many lines of reference trace should be shown per compile error \\ -fno-reference-trace Disable reference trace \\ --build-file [file] Override path to build.zig @@ -3778,7 +3817,6 @@ pub const usage_build = pub fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !void { var prominent_compile_errors: bool = false; - var use_stage1: ?bool = null; // We want to release all the locks before executing the child process, so we make a nice // big block here to ensure the cleanup gets run when we extract out our argv. @@ -3835,12 +3873,6 @@ pub fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !voi continue; } else if (mem.eql(u8, arg, "--prominent-compile-errors")) { prominent_compile_errors = true; - } else if (mem.eql(u8, arg, "-fstage1")) { - use_stage1 = true; - try child_argv.append(arg); - } else if (mem.eql(u8, arg, "-fno-stage1")) { - use_stage1 = false; - try child_argv.append(arg); } else if (mem.eql(u8, arg, "-freference-trace")) { try child_argv.append(arg); reference_trace = 256; @@ -3987,7 +4019,6 @@ pub fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !voi .optimize_mode = .Debug, .self_exe_path = self_exe_path, .thread_pool = &thread_pool, - .use_stage1 = use_stage1, .cache_mode = .whole, .reference_trace = reference_trace, .debug_compile_errors = debug_compile_errors, diff --git a/src/stage1.zig b/src/stage1.zig deleted file mode 100644 index bb2752c80296..000000000000 --- a/src/stage1.zig +++ /dev/null @@ -1,479 +0,0 @@ -//! This is the main entry point for the Zig/C++ hybrid compiler (stage1). -//! It has the functions exported from Zig, called in C++, and bindings for -//! the functions exported from C++, called from Zig. - -const std = @import("std"); -const assert = std.debug.assert; -const mem = std.mem; -const CrossTarget = std.zig.CrossTarget; -const Target = std.Target; -const builtin = @import("builtin"); - -const build_options = @import("build_options"); -const stage2 = @import("main.zig"); -const fatal = stage2.fatal; -const Compilation = @import("Compilation.zig"); -const translate_c = @import("translate_c.zig"); -const target_util = @import("target.zig"); - -comptime { - assert(builtin.link_libc); - assert(build_options.have_stage1); - assert(build_options.have_llvm); - if (!builtin.is_test) { - @export(main, .{ .name = "main" }); - } -} - -pub const log = stage2.log; -pub const log_level = stage2.log_level; - -pub fn main(argc: c_int, argv: [*][*:0]u8) callconv(.C) c_int { - std.os.argv = argv[0..@intCast(usize, argc)]; - - std.debug.maybeEnableSegfaultHandler(); - - zig_stage1_os_init(); - - const gpa = std.heap.c_allocator; - var arena_instance = std.heap.ArenaAllocator.init(gpa); - defer arena_instance.deinit(); - const arena = arena_instance.allocator(); - - const args: []const []const u8 = args: { - if (builtin.os.tag == .windows) { - break :args std.process.argsAlloc(arena) catch fatal("{s}", .{"OutOfMemory"}); - } else { - const args = arena.alloc([]const u8, @intCast(usize, argc)) catch fatal("{s}", .{"OutOfMemory"}); - for (args) |*arg, i| { - arg.* = mem.sliceTo(argv[i], 0); - } - break :args args; - } - }; - - if (builtin.mode == .Debug) { - stage2.mainArgs(gpa, arena, args) catch unreachable; - } else { - stage2.mainArgs(gpa, arena, args) catch |err| fatal("{s}", .{@errorName(err)}); - } - return 0; -} - -/// Matches stage2.Color; -pub const ErrColor = c_int; -/// Matches std.builtin.CodeModel -pub const CodeModel = c_int; -/// Matches std.Target.Os.Tag -pub const OS = c_int; -/// Matches std.builtin.BuildMode -pub const BuildMode = c_int; - -pub const TargetSubsystem = enum(c_int) { - Console, - Windows, - Posix, - Native, - EfiApplication, - EfiBootServiceDriver, - EfiRom, - EfiRuntimeDriver, - Auto, -}; - -pub const Pkg = extern struct { - name_ptr: [*]const u8, - name_len: usize, - path_ptr: [*]const u8, - path_len: usize, - children_ptr: [*]*Pkg, - children_len: usize, - parent: ?*Pkg, -}; - -pub const Module = extern struct { - root_name_ptr: [*]const u8, - root_name_len: usize, - emit_o_ptr: [*]const u8, - emit_o_len: usize, - emit_h_ptr: [*]const u8, - emit_h_len: usize, - emit_asm_ptr: [*]const u8, - emit_asm_len: usize, - emit_llvm_ir_ptr: [*]const u8, - emit_llvm_ir_len: usize, - emit_bitcode_ptr: [*]const u8, - emit_bitcode_len: usize, - builtin_zig_path_ptr: [*]const u8, - builtin_zig_path_len: usize, - test_filter_ptr: [*]const u8, - test_filter_len: usize, - test_name_prefix_ptr: [*]const u8, - test_name_prefix_len: usize, - userdata: usize, - main_pkg: *Pkg, - main_progress_node: ?*std.Progress.Node, - code_model: CodeModel, - subsystem: TargetSubsystem, - err_color: ErrColor, - pic: bool, - pie: bool, - lto: bool, - unwind_tables: bool, - link_libc: bool, - link_libcpp: bool, - strip: bool, - is_single_threaded: bool, - dll_export_fns: bool, - link_mode_dynamic: bool, - valgrind_enabled: bool, - tsan_enabled: bool, - function_sections: bool, - include_compiler_rt: bool, - enable_stack_probing: bool, - red_zone: bool, - omit_frame_pointer: bool, - enable_time_report: bool, - enable_stack_report: bool, - test_is_evented: bool, - verbose_ir: bool, - verbose_llvm_ir: bool, - verbose_cimport: bool, - verbose_llvm_cpu_features: bool, - - // Set by stage1 - have_c_main: bool, - have_winmain: bool, - have_wwinmain: bool, - have_winmain_crt_startup: bool, - have_wwinmain_crt_startup: bool, - have_dllmain_crt_startup: bool, - - pub fn build_object(mod: *Module) void { - zig_stage1_build_object(mod); - } - - pub fn destroy(mod: *Module) void { - zig_stage1_destroy(mod); - } -}; - -pub const os_init = zig_stage1_os_init; -extern fn zig_stage1_os_init() void; - -pub const create = zig_stage1_create; -extern fn zig_stage1_create( - optimize_mode: BuildMode, - main_pkg_path_ptr: [*]const u8, - main_pkg_path_len: usize, - root_src_path_ptr: [*]const u8, - root_src_path_len: usize, - zig_lib_dir_ptr: [*c]const u8, - zig_lib_dir_len: usize, - target: [*c]const Stage2Target, - is_test_build: bool, -) ?*Module; - -extern fn zig_stage1_build_object(*Module) void; -extern fn zig_stage1_destroy(*Module) void; - -// ABI warning -export fn stage2_panic(ptr: [*]const u8, len: usize) void { - @panic(ptr[0..len]); -} - -// ABI warning -const Error = enum(c_int) { - None, - OutOfMemory, - InvalidFormat, - SemanticAnalyzeFail, - AccessDenied, - Interrupted, - SystemResources, - FileNotFound, - FileSystem, - FileTooBig, - DivByZero, - Overflow, - PathAlreadyExists, - Unexpected, - ExactDivRemainder, - NegativeDenominator, - ShiftedOutOneBits, - CCompileErrors, - EndOfFile, - IsDir, - NotDir, - UnsupportedOperatingSystem, - SharingViolation, - PipeBusy, - PrimitiveTypeNotFound, - CacheUnavailable, - PathTooLong, - CCompilerCannotFindFile, - NoCCompilerInstalled, - ReadingDepFile, - InvalidDepFile, - MissingArchitecture, - MissingOperatingSystem, - UnknownArchitecture, - UnknownOperatingSystem, - UnknownABI, - InvalidFilename, - DiskQuota, - DiskSpace, - UnexpectedWriteFailure, - UnexpectedSeekFailure, - UnexpectedFileTruncationFailure, - Unimplemented, - OperationAborted, - BrokenPipe, - NoSpaceLeft, - NotLazy, - IsAsync, - ImportOutsidePkgPath, - UnknownCpuModel, - UnknownCpuFeature, - InvalidCpuFeatures, - InvalidLlvmCpuFeaturesFormat, - UnknownApplicationBinaryInterface, - ASTUnitFailure, - BadPathName, - SymLinkLoop, - ProcessFdQuotaExceeded, - SystemFdQuotaExceeded, - NoDevice, - DeviceBusy, - UnableToSpawnCCompiler, - CCompilerExitCode, - CCompilerCrashed, - CCompilerCannotFindHeaders, - LibCRuntimeNotFound, - LibCStdLibHeaderNotFound, - LibCKernel32LibNotFound, - UnsupportedArchitecture, - WindowsSdkNotFound, - UnknownDynamicLinkerPath, - TargetHasNoDynamicLinker, - InvalidAbiVersion, - InvalidOperatingSystemVersion, - UnknownClangOption, - NestedResponseFile, - ZigIsTheCCompiler, - FileBusy, - Locked, - InvalidCharacter, - UnicodePointTooLarge, -}; - -// ABI warning -export fn stage2_version_string() [*:0]const u8 { - return build_options.version; -} - -// ABI warning -export fn stage2_version() Stage2SemVer { - return .{ - .major = build_options.semver.major, - .minor = build_options.semver.minor, - .patch = build_options.semver.patch, - }; -} - -// ABI warning -export fn stage2_attach_segfault_handler() void { - if (std.debug.runtime_safety and std.debug.have_segfault_handling_support) { - std.debug.attachSegfaultHandler(); - } -} - -// ABI warning -export fn stage2_progress_create() *std.Progress { - const ptr = std.heap.c_allocator.create(std.Progress) catch @panic("out of memory"); - // If the terminal is dumb, we dont want to show the user all the - // output. - ptr.* = std.Progress{ .dont_print_on_dumb = true }; - return ptr; -} - -// ABI warning -export fn stage2_progress_destroy(progress: *std.Progress) void { - std.heap.c_allocator.destroy(progress); -} - -// ABI warning -export fn stage2_progress_start_root( - progress: *std.Progress, - name_ptr: [*]const u8, - name_len: usize, - estimated_total_items: usize, -) *std.Progress.Node { - return progress.start(name_ptr[0..name_len], estimated_total_items); -} - -// ABI warning -export fn stage2_progress_disable_tty(progress: *std.Progress) void { - progress.terminal = null; -} - -// ABI warning -export fn stage2_progress_start( - node: *std.Progress.Node, - name_ptr: [*]const u8, - name_len: usize, - estimated_total_items: usize, -) *std.Progress.Node { - const child_node = std.heap.c_allocator.create(std.Progress.Node) catch @panic("out of memory"); - child_node.* = node.start( - name_ptr[0..name_len], - estimated_total_items, - ); - child_node.activate(); - return child_node; -} - -// ABI warning -export fn stage2_progress_end(node: *std.Progress.Node) void { - node.end(); - if (&node.context.root != node) { - std.heap.c_allocator.destroy(node); - } -} - -// ABI warning -export fn stage2_progress_complete_one(node: *std.Progress.Node) void { - node.completeOne(); -} - -// ABI warning -export fn stage2_progress_update_node(node: *std.Progress.Node, done_count: usize, total_count: usize) void { - node.setCompletedItems(done_count); - node.setEstimatedTotalItems(total_count); - node.activate(); - node.context.maybeRefresh(); -} - -// ABI warning -pub const Stage2Target = extern struct { - arch: c_int, - os: OS, - abi: c_int, - - is_native_os: bool, - is_native_cpu: bool, - - llvm_cpu_name: ?[*:0]const u8, - llvm_cpu_features: ?[*:0]const u8, - llvm_target_abi: ?[*:0]const u8, -}; - -// ABI warning -const Stage2SemVer = extern struct { - major: u32, - minor: u32, - patch: u32, -}; - -// ABI warning -export fn stage2_cimport( - stage1: *Module, - c_src_ptr: [*]const u8, - c_src_len: usize, - out_zig_path_ptr: *[*]const u8, - out_zig_path_len: *usize, - out_errors_ptr: *[*]translate_c.ClangErrMsg, - out_errors_len: *usize, -) Error { - const comp = @intToPtr(*Compilation, stage1.userdata); - const c_src = c_src_ptr[0..c_src_len]; - const result = comp.cImport(c_src) catch |err| switch (err) { - error.SystemResources => return .SystemResources, - error.OperationAborted => return .OperationAborted, - error.BrokenPipe => return .BrokenPipe, - error.DiskQuota => return .DiskQuota, - error.FileTooBig => return .FileTooBig, - error.NoSpaceLeft => return .NoSpaceLeft, - error.AccessDenied => return .AccessDenied, - error.OutOfMemory => return .OutOfMemory, - error.Unexpected => return .Unexpected, - error.InputOutput => return .FileSystem, - error.ASTUnitFailure => return .ASTUnitFailure, - error.CacheUnavailable => return .CacheUnavailable, - else => return .Unexpected, - }; - out_zig_path_ptr.* = result.out_zig_path.ptr; - out_zig_path_len.* = result.out_zig_path.len; - out_errors_ptr.* = result.errors.ptr; - out_errors_len.* = result.errors.len; - if (result.errors.len != 0) return .CCompileErrors; - return Error.None; -} - -export fn stage2_add_link_lib( - stage1: *Module, - lib_name_ptr: [*c]const u8, - lib_name_len: usize, - symbol_name_ptr: [*c]const u8, - symbol_name_len: usize, -) ?[*:0]const u8 { - _ = symbol_name_len; - _ = symbol_name_ptr; - const comp = @intToPtr(*Compilation, stage1.userdata); - const lib_name = lib_name_ptr[0..lib_name_len]; - const target = comp.getTarget(); - const is_libc = target_util.is_libc_lib_name(target, lib_name); - if (is_libc) { - if (!comp.bin_file.options.link_libc and !comp.bin_file.options.parent_compilation_link_libc) { - return "dependency on libc must be explicitly specified in the build command"; - } - return null; - } - if (target_util.is_libcpp_lib_name(target, lib_name)) { - if (!comp.bin_file.options.link_libcpp) { - return "dependency on libc++ must be explicitly specified in the build command"; - } - return null; - } - if (!target.isWasm() and !comp.bin_file.options.pic) { - return std.fmt.allocPrintZ( - comp.gpa, - "dependency on dynamic library '{s}' requires enabling Position Independent Code. Fixed by `-l{s}` or `-fPIC`.", - .{ lib_name, lib_name }, - ) catch "out of memory"; - } - comp.stage1AddLinkLib(lib_name) catch |err| { - return std.fmt.allocPrintZ(comp.gpa, "unable to add link lib '{s}': {s}", .{ - lib_name, @errorName(err), - }) catch "out of memory"; - }; - return null; -} - -export fn stage2_fetch_file( - stage1: *Module, - path_ptr: [*]const u8, - path_len: usize, - result_len: *usize, -) ?[*]const u8 { - const comp = @intToPtr(*Compilation, stage1.userdata); - const file_path = path_ptr[0..path_len]; - const max_file_size = std.math.maxInt(u32); - const contents = if (comp.whole_cache_manifest) |man| blk: { - comp.whole_cache_manifest_mutex.lock(); - defer comp.whole_cache_manifest_mutex.unlock(); - break :blk man.addFilePostFetch(file_path, max_file_size) catch return null; - } else std.fs.cwd().readFileAlloc(comp.gpa, file_path, max_file_size) catch return null; - result_len.* = contents.len; - // TODO https://github.com/ziglang/zig/issues/3328#issuecomment-716749475 - if (contents.len == 0) return @intToPtr(?[*]const u8, 0x1); - return contents.ptr; -} - -export fn stage2_append_symbol(stage1: *Module, name_ptr: [*c]const u8, name_len: usize) Error { - if (name_len == 0) return Error.None; - const comp = @intToPtr(*Compilation, stage1.userdata); - const sym_name = comp.gpa.dupe(u8, name_ptr[0..name_len]) catch return Error.OutOfMemory; - comp.export_symbol_names.append(comp.gpa, sym_name) catch return Error.OutOfMemory; - return Error.None; -} diff --git a/src/stage1/all_types.hpp b/src/stage1/all_types.hpp deleted file mode 100644 index f29110b94bfd..000000000000 --- a/src/stage1/all_types.hpp +++ /dev/null @@ -1,4746 +0,0 @@ -/* - * Copyright (c) 2015 Andrew Kelley - * - * This file is part of zig, which is MIT licensed. - * See http://opensource.org/licenses/MIT - */ - -#ifndef ZIG_ALL_TYPES_HPP -#define ZIG_ALL_TYPES_HPP - -#include "list.hpp" -#include "buffer.hpp" -#include "zig_llvm.h" -#include "hash_map.hpp" -#include "errmsg.hpp" -#include "bigint.hpp" -#include "bigfloat.hpp" -#include "target.hpp" -#include "tokenizer.hpp" - -struct AstNode; -struct ZigFn; -struct Scope; -struct ScopeBlock; -struct ScopeFnDef; -struct ScopeExpr; -struct ZigType; -struct ZigVar; -struct ErrorTableEntry; -struct BuiltinFnEntry; -struct TypeStructField; -struct CodeGen; -struct ZigValue; -struct Stage1ZirInst; -struct Stage1AirInst; -struct Stage1AirInstCast; -struct Stage1AirInstAlloca; -struct Stage1AirInstCall; -struct Stage1AirInstAwait; -struct Stage1ZirBasicBlock; -struct Stage1AirBasicBlock; -struct ScopeDecls; -struct ZigWindowsSDK; -struct Tld; -struct TldExport; -struct IrAnalyze; -struct ResultLoc; -struct ResultLocPeer; -struct ResultLocPeerParent; -struct ResultLocBitCast; -struct ResultLocCast; -struct ResultLocReturn; -struct Stage1Air; - -enum FileExt { - FileExtUnknown, - FileExtAsm, - FileExtC, - FileExtCpp, - FileExtHeader, - FileExtLLVMIr, - FileExtLLVMBitCode, -}; - -enum PtrLen { - PtrLenUnknown, - PtrLenSingle, - PtrLenC, -}; - -enum CallingConvention { - CallingConventionUnspecified, - CallingConventionC, - CallingConventionNaked, - CallingConventionAsync, - CallingConventionInline, - CallingConventionInterrupt, - CallingConventionSignal, - CallingConventionStdcall, - CallingConventionFastcall, - CallingConventionVectorcall, - CallingConventionThiscall, - CallingConventionAPCS, - CallingConventionAAPCS, - CallingConventionAAPCSVFP, - CallingConventionSysV, - CallingConventionWin64, - CallingConventionPtxKernel, - CallingConventionAmdgpuKernel -}; - -// Stage 1 supports only the generic address space -enum AddressSpace { - AddressSpaceGeneric, - AddressSpaceGS, - AddressSpaceFS, - AddressSpaceSS, - AddressSpaceGlobal, - AddressSpaceConstant, - AddressSpaceParam, - AddressSpaceShared, - AddressSpaceLocal, -}; - -// This one corresponds to the builtin.zig enum. -enum BuiltinPtrSize { - BuiltinPtrSizeOne, - BuiltinPtrSizeMany, - BuiltinPtrSizeSlice, - BuiltinPtrSizeC, -}; - -enum UndefAllowed { - UndefOk, - UndefBad, - LazyOkNoUndef, - LazyOk, -}; - -enum X64CABIClass { - X64CABIClass_Unknown, - X64CABIClass_MEMORY, - X64CABIClass_MEMORY_nobyval, - X64CABIClass_INTEGER, - X64CABIClass_SSE, - X64CABIClass_AGG, -}; - -struct Stage1Zir { - ZigList basic_block_list; - Buf *name; - ZigFn *name_fn; - Scope *begin_scope; - ErrorMsg *first_err_trace_msg; - ZigList tld_list; - - bool is_inline; - bool need_err_code_spill; -}; - -struct Stage1Air { - ZigList basic_block_list; - Buf *name; - ZigFn *name_fn; - size_t mem_slot_count; - size_t next_debug_id; - Buf *c_import_buf; - AstNode *source_node; - Stage1Air *parent_exec; - Stage1Zir *source_exec; - Scope *begin_scope; - ErrorMsg *first_err_trace_msg; - ZigList tld_list; - - bool is_inline; - bool need_err_code_spill; - - // This is a function for use in the debugger to print - // the source location. - void src(); -}; - -enum OutType { - OutTypeUnknown, - OutTypeExe, - OutTypeLib, - OutTypeObj, -}; - -enum ConstParentId { - ConstParentIdNone, - ConstParentIdStruct, - ConstParentIdErrUnionCode, - ConstParentIdErrUnionPayload, - ConstParentIdOptionalPayload, - ConstParentIdArray, - ConstParentIdUnion, - ConstParentIdScalar, -}; - -struct ConstParent { - ConstParentId id; - - union { - struct { - ZigValue *array_val; - size_t elem_index; - } p_array; - struct { - ZigValue *struct_val; - size_t field_index; - } p_struct; - struct { - ZigValue *err_union_val; - } p_err_union_code; - struct { - ZigValue *err_union_val; - } p_err_union_payload; - struct { - ZigValue *optional_val; - } p_optional_payload; - struct { - ZigValue *union_val; - } p_union; - struct { - ZigValue *scalar_val; - } p_scalar; - } data; -}; - -struct ConstStructValue { - ZigValue **fields; -}; - -struct ConstUnionValue { - BigInt tag; - ZigValue *payload; -}; - -enum ConstArraySpecial { - ConstArraySpecialNone, - ConstArraySpecialUndef, - ConstArraySpecialBuf, -}; - -struct ConstArrayValue { - ConstArraySpecial special; - union { - struct { - ZigValue *elements; - } s_none; - Buf *s_buf; - } data; -}; - -enum ConstPtrSpecial { - // Enforce explicitly setting this ID by making the zero value invalid. - ConstPtrSpecialInvalid, - // The pointer is a reference to a single object. - ConstPtrSpecialRef, - // The pointer points to an element in an underlying array. - // Not to be confused with ConstPtrSpecialSubArray. - ConstPtrSpecialBaseArray, - // The pointer points to a field in an underlying struct. - ConstPtrSpecialBaseStruct, - // The pointer points to the error set field of an error union - ConstPtrSpecialBaseErrorUnionCode, - // The pointer points to the payload field of an error union - ConstPtrSpecialBaseErrorUnionPayload, - // The pointer points to the payload field of an optional - ConstPtrSpecialBaseOptionalPayload, - // This means that we did a compile-time pointer reinterpret and we cannot - // understand the value of pointee at compile time. However, we will still - // emit a binary with a compile time known address. - // In this case index is the numeric address value. - ConstPtrSpecialHardCodedAddr, - // This means that the pointer represents memory of assigning to _. - // That is, storing discards the data, and loading is invalid. - ConstPtrSpecialDiscard, - // This is actually a function. - ConstPtrSpecialFunction, - // This means the pointer is null. This is only allowed when the type is ?*T. - // We use this instead of ConstPtrSpecialHardCodedAddr because often we check - // for that value to avoid doing comptime work. - // We need the data layout for ConstCastOnly == true - // types to be the same, so all optionals of pointer types use x_ptr - // instead of x_optional. - ConstPtrSpecialNull, - // The pointer points to a sub-array (not an individual element). - // Not to be confused with ConstPtrSpecialBaseArray. However, it uses the same - // union payload struct (base_array). - ConstPtrSpecialSubArray, -}; - -enum ConstPtrMut { - // The pointer points to memory that is known at compile time and immutable. - ConstPtrMutComptimeConst, - // This means that the pointer points to memory used by a comptime variable, - // so attempting to write a non-compile-time known value is an error - // But the underlying value is allowed to change at compile time. - ConstPtrMutComptimeVar, - // The pointer points to memory that is known only at runtime. - // For example it may point to the initializer value of a variable. - ConstPtrMutRuntimeVar, - // The pointer points to memory for which it must be inferred whether the - // value is comptime known or not. - ConstPtrMutInfer, -}; - -struct ConstPtrValue { - ConstPtrSpecial special; - ConstPtrMut mut; - - union { - struct { - ZigValue *pointee; - } ref; - struct { - ZigValue *array_val; - size_t elem_index; - } base_array; - struct { - ZigValue *struct_val; - size_t field_index; - } base_struct; - struct { - ZigValue *err_union_val; - } base_err_union_code; - struct { - ZigValue *err_union_val; - } base_err_union_payload; - struct { - ZigValue *optional_val; - } base_optional_payload; - struct { - uint64_t addr; - } hard_coded_addr; - struct { - ZigFn *fn_entry; - } fn; - } data; -}; - -struct ConstErrValue { - ZigValue *error_set; - ZigValue *payload; -}; - -struct ConstBoundFnValue { - ZigFn *fn; - Stage1AirInst *first_arg; - AstNode *first_arg_src; -}; - -struct ConstArgTuple { - size_t start_index; - size_t end_index; -}; - -enum ConstValSpecial { - // The value is only available at runtime. However there may be runtime hints - // narrowing the possible values down via the `data.rh_*` fields. - ConstValSpecialRuntime, - // The value is comptime-known and resolved. The `data.x_*` fields can be - // accessed. - ConstValSpecialStatic, - // The value is comptime-known to be `undefined`. - ConstValSpecialUndef, - // The value is comptime-known, but not yet resolved. The lazy value system - // helps avoid dependency loops by providing answers to certain questions - // about values without forcing them to be resolved. For example, the - // equation `@sizeOf(Foo) == 0` can be resolved without forcing the struct - // layout of `Foo` because we can know whether `Foo` is zero bits without - // performing field layout. - // A `ZigValue` can be converted from Lazy to Static/Undef by calling the - // appropriate resolve function. - ConstValSpecialLazy, -}; - -enum RuntimeHintErrorUnion { - RuntimeHintErrorUnionUnknown, - RuntimeHintErrorUnionError, - RuntimeHintErrorUnionNonError, -}; - -enum RuntimeHintOptional { - RuntimeHintOptionalUnknown, - RuntimeHintOptionalNull, // TODO is this value even possible? if this is the case it might mean the const value is compile time known. - RuntimeHintOptionalNonNull, -}; - -enum RuntimeHintPtr { - RuntimeHintPtrUnknown, - RuntimeHintPtrStack, - RuntimeHintPtrNonStack, -}; - -enum RuntimeHintSliceId { - RuntimeHintSliceIdUnknown, - RuntimeHintSliceIdLen, -}; - -struct RuntimeHintSlice { - enum RuntimeHintSliceId id; - uint64_t len; -}; - -enum LazyValueId { - LazyValueIdInvalid, - LazyValueIdAlignOf, - LazyValueIdSizeOf, - LazyValueIdPtrType, - LazyValueIdPtrTypeSimple, - LazyValueIdPtrTypeSimpleConst, - LazyValueIdOptType, - LazyValueIdSliceType, - LazyValueIdFnType, - LazyValueIdErrUnionType, - LazyValueIdArrayType, - LazyValueIdTypeInfoDecls, -}; - -struct LazyValue { - LazyValueId id; -}; - -struct LazyValueTypeInfoDecls { - LazyValue base; - - IrAnalyze *ira; - - ScopeDecls *decls_scope; - AstNode *source_node; -}; - -struct LazyValueAlignOf { - LazyValue base; - - IrAnalyze *ira; - Stage1AirInst *target_type; -}; - -struct LazyValueSizeOf { - LazyValue base; - - IrAnalyze *ira; - Stage1AirInst *target_type; - - bool bit_size; -}; - -struct LazyValueSliceType { - LazyValue base; - - IrAnalyze *ira; - Stage1AirInst *sentinel; // can be null - Stage1AirInst *elem_type; - Stage1AirInst *align_inst; // can be null - - bool is_const; - bool is_volatile; - bool is_allowzero; -}; - -struct LazyValueArrayType { - LazyValue base; - - IrAnalyze *ira; - Stage1AirInst *sentinel; // can be null - Stage1AirInst *elem_type; - uint64_t length; -}; - -struct LazyValuePtrType { - LazyValue base; - - IrAnalyze *ira; - Stage1AirInst *sentinel; // can be null - Stage1AirInst *elem_type; - Stage1AirInst *align_inst; // can be null - - PtrLen ptr_len; - uint32_t bit_offset_in_host; - - uint32_t host_int_bytes; - bool is_const; - bool is_volatile; - bool is_allowzero; -}; - -struct LazyValuePtrTypeSimple { - LazyValue base; - - IrAnalyze *ira; - Stage1AirInst *elem_type; -}; - -struct LazyValueOptType { - LazyValue base; - - IrAnalyze *ira; - Stage1AirInst *payload_type; -}; - -struct LazyValueFnType { - LazyValue base; - - IrAnalyze *ira; - AstNode *proto_node; - Stage1AirInst **param_types; - Stage1AirInst *align_inst; // can be null - Stage1AirInst *return_type; - - CallingConvention cc; - bool is_generic; -}; - -struct LazyValueErrUnionType { - LazyValue base; - - IrAnalyze *ira; - Stage1AirInst *err_set_type; - Stage1AirInst *payload_type; - Buf *type_name; -}; - -struct ZigValue { - ZigType *type; - // This field determines how the value is stored. It must be checked - // before accessing the `data` union. - ConstValSpecial special; - uint32_t llvm_align; - ConstParent parent; - LLVMValueRef llvm_value; - LLVMValueRef llvm_global; - - union { - // populated if special == ConstValSpecialLazy - LazyValue *x_lazy; - - // populated if special == ConstValSpecialStatic - BigInt x_bigint; - BigFloat x_bigfloat; - float16_t x_f16; - float x_f32; - double x_f64; - extFloat80_t x_f80; - float128_t x_f128; - bool x_bool; - ConstBoundFnValue x_bound_fn; - ZigType *x_type; - ZigValue *x_optional; - ConstErrValue x_err_union; - ErrorTableEntry *x_err_set; - BigInt x_enum_tag; - ConstStructValue x_struct; - ConstUnionValue x_union; - ConstArrayValue x_array; - ConstPtrValue x_ptr; - ConstArgTuple x_arg_tuple; - Buf *x_enum_literal; - - // populated if special == ConstValSpecialRuntime - RuntimeHintErrorUnion rh_error_union; - RuntimeHintOptional rh_maybe; - RuntimeHintPtr rh_ptr; - RuntimeHintSlice rh_slice; - } data; - - // uncomment this to find bugs. can't leave it uncommented because of a gcc-9 warning - //ZigValue& operator= (const ZigValue &other) = delete; // use copy_const_val - - ZigValue(const ZigValue &other) = delete; // plz zero initialize with ZigValue val = {}; - - // for use in debuggers - void dump(); -}; - -enum ReturnKnowledge { - ReturnKnowledgeUnknown, - ReturnKnowledgeKnownError, - ReturnKnowledgeKnownNonError, - ReturnKnowledgeKnownNull, - ReturnKnowledgeKnownNonNull, - ReturnKnowledgeSkipDefers, -}; - -enum VisibMod { - VisibModPrivate, - VisibModPub, -}; - -enum GlobalLinkageId { - GlobalLinkageIdInternal, - GlobalLinkageIdStrong, - GlobalLinkageIdWeak, - GlobalLinkageIdLinkOnce, -}; - -enum TldId { - TldIdVar, - TldIdFn, - TldIdContainer, - TldIdCompTime, - TldIdUsingNamespace, -}; - -enum TldResolution { - TldResolutionUnresolved, - TldResolutionResolving, - TldResolutionInvalid, - TldResolutionOkLazy, - TldResolutionOk, -}; - -struct Tld { - TldId id; - Buf *name; - VisibMod visib_mod; - AstNode *source_node; - - ZigType *import; - Scope *parent_scope; - TldResolution resolution; -}; - -struct TldVar { - Tld base; - - ZigVar *var; - Buf *extern_lib_name; - bool analyzing_type; // flag to detect dependency loops -}; - -struct TldFn { - Tld base; - - ZigFn *fn_entry; - Buf *extern_lib_name; -}; - -struct TldContainer { - Tld base; - - ScopeDecls *decls_scope; - ZigType *type_entry; -}; - -struct TldCompTime { - Tld base; -}; - -struct TldUsingNamespace { - Tld base; - - ZigValue *using_namespace_value; -}; - -struct TypeEnumField { - Buf *name; - BigInt value; - uint32_t decl_index; - AstNode *decl_node; -}; - -struct TypeUnionField { - Buf *name; - ZigType *type_entry; // available after ResolveStatusSizeKnown - ZigValue *type_val; // available after ResolveStatusZeroBitsKnown - TypeEnumField *enum_field; - AstNode *decl_node; - uint32_t gen_index; - uint32_t align; -}; - -enum NodeType { - NodeTypeFnProto, - NodeTypeFnDef, - NodeTypeParamDecl, - NodeTypeBlock, - NodeTypeGroupedExpr, - NodeTypeReturnExpr, - NodeTypeDefer, - NodeTypeVariableDeclaration, - NodeTypeTestDecl, - NodeTypeBinOpExpr, - NodeTypeCatchExpr, - NodeTypeFloatLiteral, - NodeTypeIntLiteral, - NodeTypeStringLiteral, - NodeTypeCharLiteral, - NodeTypeIdentifier, - NodeTypePrefixOpExpr, - NodeTypePointerType, - NodeTypeFnCallExpr, - NodeTypeArrayAccessExpr, - NodeTypeSliceExpr, - NodeTypeFieldAccessExpr, - NodeTypePtrDeref, - NodeTypeUnwrapOptional, - NodeTypeUsingNamespace, - NodeTypeUnreachable, - NodeTypeIfBoolExpr, - NodeTypeWhileExpr, - NodeTypeForExpr, - NodeTypeSwitchExpr, - NodeTypeSwitchProng, - NodeTypeSwitchRange, - NodeTypeCompTime, - NodeTypeNoSuspend, - NodeTypeBreak, - NodeTypeContinue, - NodeTypeAsmExpr, - NodeTypeContainerDecl, - NodeTypeStructField, - NodeTypeContainerInitExpr, - NodeTypeStructValueField, - NodeTypeArrayType, - NodeTypeInferredArrayType, - NodeTypeErrorType, - NodeTypeIfErrorExpr, - NodeTypeIfOptional, - NodeTypeErrorSetDecl, - NodeTypeErrorSetField, - NodeTypeResume, - NodeTypeAwaitExpr, - NodeTypeSuspend, - NodeTypeAnyFrameType, - // main_token points to the identifier. - NodeTypeEnumLiteral, - NodeTypeAnyTypeField, -}; - -enum FnInline { - FnInlineAuto, - FnInlineAlways, - FnInlineNever, -}; - -struct AstNodeFnProto { - Buf *name; - ZigList params; - AstNode *return_type; - AstNode *fn_def_node; - // populated if this is an extern declaration - Buf *lib_name; - // populated if the "align A" is present - AstNode *align_expr; - // populated if the "section(S)" is present - AstNode *section_expr; - // populated if the "callconv(S)" is present - AstNode *callconv_expr; - - TokenIndex doc_comments; - - // This is set based only on the existence of a noinline or inline keyword. - // This is then resolved to an is_noinline bool and (potentially .Inline) - // calling convention in resolve_decl_fn() in analyze.cpp. - FnInline fn_inline; - - VisibMod visib_mod; - bool auto_err_set; - bool is_var_args; - bool is_extern; - bool is_export; -}; - -struct AstNodeFnDef { - AstNode *fn_proto; - AstNode *body; -}; - -struct AstNodeParamDecl { - Buf *name; - AstNode *type; - TokenIndex doc_comments; - TokenIndex anytype_token; - bool is_noalias; - bool is_comptime; - bool is_var_args; -}; - -struct AstNodeBlock { - Buf *name; - ZigList statements; -}; - -enum ReturnKind { - ReturnKindUnconditional, - ReturnKindError, -}; - -struct AstNodeReturnExpr { - ReturnKind kind; - // might be null in case of return void; - AstNode *expr; -}; - -struct AstNodeDefer { - ReturnKind kind; - AstNode *err_payload; - AstNode *expr; - - // temporary data used in IR generation - Scope *child_scope; - Scope *expr_scope; -}; - -struct AstNodeVariableDeclaration { - Buf *symbol; - // one or both of type and expr will be non null - AstNode *type; - AstNode *expr; - // populated if this is an extern declaration - Buf *lib_name; - // populated if the "align(A)" is present - AstNode *align_expr; - // populated if the "section(S)" is present - AstNode *section_expr; - TokenIndex doc_comments; - - TokenIndex threadlocal_tok; - VisibMod visib_mod; - bool is_const; - bool is_comptime; - bool is_export; - bool is_extern; -}; - -struct AstNodeTestDecl { - // nullptr if the test declaration has no name - Buf *name; - - AstNode *body; -}; - -enum BinOpType { - BinOpTypeInvalid, - BinOpTypeAssign, - BinOpTypeAssignTimes, - BinOpTypeAssignTimesSat, - BinOpTypeAssignTimesWrap, - BinOpTypeAssignDiv, - BinOpTypeAssignMod, - BinOpTypeAssignPlus, - BinOpTypeAssignPlusSat, - BinOpTypeAssignPlusWrap, - BinOpTypeAssignMinus, - BinOpTypeAssignMinusSat, - BinOpTypeAssignMinusWrap, - BinOpTypeAssignBitShiftLeft, - BinOpTypeAssignBitShiftLeftSat, - BinOpTypeAssignBitShiftRight, - BinOpTypeAssignBitAnd, - BinOpTypeAssignBitXor, - BinOpTypeAssignBitOr, - BinOpTypeBoolOr, - BinOpTypeBoolAnd, - BinOpTypeCmpEq, - BinOpTypeCmpNotEq, - BinOpTypeCmpLessThan, - BinOpTypeCmpGreaterThan, - BinOpTypeCmpLessOrEq, - BinOpTypeCmpGreaterOrEq, - BinOpTypeBinOr, - BinOpTypeBinXor, - BinOpTypeBinAnd, - BinOpTypeBitShiftLeft, - BinOpTypeBitShiftLeftSat, - BinOpTypeBitShiftRight, - BinOpTypeAdd, - BinOpTypeAddSat, - BinOpTypeAddWrap, - BinOpTypeSub, - BinOpTypeSubSat, - BinOpTypeSubWrap, - BinOpTypeMult, - BinOpTypeMultSat, - BinOpTypeMultWrap, - BinOpTypeDiv, - BinOpTypeMod, - BinOpTypeUnwrapOptional, - BinOpTypeArrayCat, - BinOpTypeArrayMult, - BinOpTypeErrorUnion, - BinOpTypeMergeErrorSets, -}; - -struct AstNodeBinOpExpr { - AstNode *op1; - BinOpType bin_op; - AstNode *op2; -}; - -struct AstNodeCatchExpr { - AstNode *op1; - AstNode *symbol; // can be null - AstNode *op2; -}; - -struct AstNodeUnwrapOptional { - AstNode *expr; -}; - -// Must be synchronized with std.builtin.CallOptions.Modifier -enum CallModifier { - CallModifierNone, - CallModifierAsync, - CallModifierNeverTail, - CallModifierNeverInline, - CallModifierNoSuspend, - CallModifierAlwaysTail, - CallModifierAlwaysInline, - CallModifierCompileTime, - - // These are additional tags in the compiler, but not exposed in the std lib. - CallModifierBuiltin, -}; - -struct AstNodeFnCallExpr { - AstNode *fn_ref_expr; - ZigList params; - CallModifier modifier; - bool seen; // used by @compileLog -}; - -// Must be kept in sync with std.builtin.PrefetchOptions.Rw -enum PrefetchRw { - PrefetchRwRead, - PrefetchRwWrite, -}; - -// Must be kept in sync with std.builtin.PrefetchOptions.Cache -enum PrefetchCache { - PrefetchCacheInstruction, - PrefetchCacheData, -}; - -struct AstNodeArrayAccessExpr { - AstNode *array_ref_expr; - AstNode *subscript; -}; - -struct AstNodeSliceExpr { - AstNode *array_ref_expr; - AstNode *start; - AstNode *end; - AstNode *sentinel; // can be null -}; - -struct AstNodeFieldAccessExpr { - AstNode *struct_expr; - Buf *field_name; -}; - -struct AstNodePtrDerefExpr { - AstNode *target; -}; - -enum PrefixOp { - PrefixOpInvalid, - PrefixOpBoolNot, - PrefixOpBinNot, - PrefixOpNegation, - PrefixOpNegationWrap, - PrefixOpOptional, - PrefixOpAddrOf, -}; - -struct AstNodePrefixOpExpr { - PrefixOp prefix_op; - AstNode *primary_expr; -}; - -struct AstNodePointerType { - TokenIndex star_token; - TokenIndex allow_zero_token; - TokenIndex bit_offset_start; - TokenIndex host_int_bytes; - - AstNode *sentinel; - AstNode *align_expr; - AstNode *op_expr; - bool is_const; - bool is_volatile; -}; - -struct AstNodeInferredArrayType { - AstNode *sentinel; // can be null - AstNode *child_type; -}; - -struct AstNodeArrayType { - AstNode *size; - AstNode *sentinel; - AstNode *child_type; - AstNode *align_expr; - TokenIndex allow_zero_token; - bool is_const; - bool is_volatile; -}; - -struct AstNodeUsingNamespace { - VisibMod visib_mod; - AstNode *expr; -}; - -struct AstNodeIfBoolExpr { - AstNode *condition; - AstNode *then_block; - AstNode *else_node; // null, block node, or other if expr node -}; - -struct AstNodeTryExpr { - Buf *var_symbol; - AstNode *target_node; - AstNode *then_node; - AstNode *else_node; - Buf *err_symbol; - bool var_is_ptr; -}; - -struct AstNodeTestExpr { - Buf *var_symbol; - bool var_is_ptr; - AstNode *target_node; - AstNode *then_node; - AstNode *else_node; // null, block node, or other if expr node -}; - -struct AstNodeWhileExpr { - Buf *name; - AstNode *condition; - Buf *var_symbol; - AstNode *continue_expr; - AstNode *body; - AstNode *else_node; - Buf *err_symbol; - bool is_inline; - bool var_is_ptr; -}; - -struct AstNodeForExpr { - Buf *name; - AstNode *array_expr; - AstNode *elem_node; // always a symbol - AstNode *index_node; // always a symbol, might be null - AstNode *body; - AstNode *else_node; // can be null - bool elem_is_ptr; - bool is_inline; -}; - -struct AstNodeSwitchExpr { - AstNode *expr; - ZigList prongs; -}; - -struct AstNodeSwitchProng { - ZigList items; - AstNode *var_symbol; - AstNode *expr; - bool var_is_ptr; - bool any_items_are_range; - bool is_inline; -}; - -struct AstNodeSwitchRange { - AstNode *start; - AstNode *end; -}; - -struct AstNodeCompTime { - AstNode *expr; -}; - -struct AstNodeNoSuspend { - AstNode *expr; -}; - -struct AsmOutput { - Buf *asm_symbolic_name; - Buf *constraint; - Buf *variable_name; - AstNode *return_type; // null unless "=r" and return -}; - -struct AsmInput { - Buf *asm_symbolic_name; - Buf *constraint; - AstNode *expr; -}; - -struct SrcPos { - size_t line; - size_t column; -}; - -enum AsmTokenId { - AsmTokenIdTemplate, - AsmTokenIdPercent, - AsmTokenIdVar, - AsmTokenIdUniqueId, -}; - -struct AsmToken { - enum AsmTokenId id; - size_t start; - size_t end; -}; - -struct AstNodeAsmExpr { - TokenIndex volatile_token; - AstNode *asm_template; - ZigList output_list; - ZigList input_list; - ZigList clobber_list; -}; - -enum ContainerKind { - ContainerKindStruct, - ContainerKindEnum, - ContainerKindUnion, - ContainerKindOpaque, -}; - -enum ContainerLayout { - ContainerLayoutAuto, - ContainerLayoutExtern, - ContainerLayoutPacked, -}; - -struct AstNodeContainerDecl { - AstNode *init_arg_expr; // enum(T), struct(endianness), or union(T), or union(enum(T)) - ZigList fields; - ZigList decls; - TokenIndex doc_comments; - - ContainerKind kind; - ContainerLayout layout; - - bool auto_enum, is_root; // union(enum) - bool unsupported_explicit_backing_int; -}; - -struct AstNodeErrorSetField { - TokenIndex doc_comments; - AstNode *field_name; -}; - -struct AstNodeErrorSetDecl { - // Each AstNode could be AstNodeErrorSetField or just AstNodeSymbolExpr to save memory - ZigList decls; -}; - -struct AstNodeStructField { - Buf *name; - AstNode *type; - AstNode *value; - // populated if the "align(A)" is present - AstNode *align_expr; - TokenIndex doc_comments; - TokenIndex comptime_token; -}; - -struct AstNodeStructValueField { - Buf *name; - AstNode *expr; -}; - -enum ContainerInitKind { - ContainerInitKindStruct, - ContainerInitKindArray, -}; - -struct AstNodeContainerInitExpr { - AstNode *type; - ZigList entries; - ContainerInitKind kind; -}; - -struct AstNodeIdentifier { - Buf *name; - bool is_at_syntax; -}; - -struct AstNodeEnumLiteral { - Buf *name; -}; - -struct AstNodeBreakExpr { - Buf *name; - AstNode *expr; // may be null -}; - -struct AstNodeResumeExpr { - AstNode *expr; -}; - -struct AstNodeContinueExpr { - Buf *name; -}; - -struct AstNodeAwaitExpr { - AstNode *expr; -}; - -struct AstNodeSuspend { - AstNode *block; -}; - -struct AstNodeAnyFrameType { - AstNode *payload_type; // can be NULL -}; - -struct AstNode { - enum NodeType type; - TokenIndex main_token; - ZigType *owner; - union { - AstNodeFnDef fn_def; - AstNodeFnProto fn_proto; - AstNodeParamDecl param_decl; - AstNodeBlock block; - AstNode * grouped_expr; - AstNodeReturnExpr return_expr; - AstNodeDefer defer; - AstNodeVariableDeclaration variable_declaration; - AstNodeTestDecl test_decl; - AstNodeBinOpExpr bin_op_expr; - AstNodeCatchExpr unwrap_err_expr; - AstNodeUnwrapOptional unwrap_optional; - AstNodePrefixOpExpr prefix_op_expr; - AstNodePointerType pointer_type; - AstNodeFnCallExpr fn_call_expr; - AstNodeArrayAccessExpr array_access_expr; - AstNodeSliceExpr slice_expr; - AstNodeUsingNamespace using_namespace; - AstNodeIfBoolExpr if_bool_expr; - AstNodeTryExpr if_err_expr; - AstNodeTestExpr test_expr; - AstNodeWhileExpr while_expr; - AstNodeForExpr for_expr; - AstNodeSwitchExpr switch_expr; - AstNodeSwitchProng switch_prong; - AstNodeSwitchRange switch_range; - AstNodeCompTime comptime_expr; - AstNodeNoSuspend nosuspend_expr; - AstNodeAsmExpr asm_expr; - AstNodeFieldAccessExpr field_access_expr; - AstNodePtrDerefExpr ptr_deref_expr; - AstNodeContainerDecl container_decl; - AstNodeStructField struct_field; - AstNodeContainerInitExpr container_init_expr; - AstNodeStructValueField struct_val_field; - AstNodeBreakExpr break_expr; - AstNodeContinueExpr continue_expr; - AstNodeArrayType array_type; - AstNodeInferredArrayType inferred_array_type; - AstNodeErrorSetDecl err_set_decl; - AstNodeErrorSetField err_set_field; - AstNodeResumeExpr resume_expr; - AstNodeAwaitExpr await_expr; - AstNodeSuspend suspend; - AstNodeAnyFrameType anyframe_type; - - // These are part of an astgen workaround to use less memory by - // memoizing into the AST. Once astgen is modified to only run once - // per corresponding source, this workaround can be removed. - AstNodeIdentifier identifier; - AstNodeEnumLiteral enum_literal; - } data; - - // This is a function for use in the debugger to print - // the source location. - void src(); -}; - -// this struct is allocated with allocate_nonzero -struct FnTypeParamInfo { - bool is_noalias; - ZigType *type; -}; - -struct GenericFnTypeId { - CodeGen *codegen; - ZigFn *fn_entry; - ZigValue *params; - size_t param_count; -}; - -uint32_t generic_fn_type_id_hash(GenericFnTypeId *id); -bool generic_fn_type_id_eql(GenericFnTypeId *a, GenericFnTypeId *b); - -struct FnTypeId { - ZigType *return_type; - FnTypeParamInfo *param_info; - size_t param_count; - size_t next_param_index; - bool is_var_args; - CallingConvention cc; - uint32_t alignment; -}; - -uint32_t fn_type_id_hash(FnTypeId*); -bool fn_type_id_eql(FnTypeId *a, FnTypeId *b); - -static const uint32_t VECTOR_INDEX_NONE = UINT32_MAX; -static const uint32_t VECTOR_INDEX_RUNTIME = UINT32_MAX - 1; - -struct InferredStructField { - ZigType *inferred_struct_type; - Buf *field_name; - bool already_resolved; -}; - -struct ZigTypePointer { - ZigType *child_type; - ZigType *slice_parent; - - // Anonymous struct literal syntax uses this when the result location has - // no type in it. This field is null if this pointer does not refer to - // a field of a currently-being-inferred struct type. - // When this is non-null, the pointer is pointing to the base of the inferred - // struct. - InferredStructField *inferred_struct_field; - - // This can be null. If it is non-null, it means the pointer is terminated by this - // sentinel value. This is most commonly used for C-style strings, with a 0 byte - // to specify the length of the memory pointed to. - ZigValue *sentinel; - - PtrLen ptr_len; - uint32_t explicit_alignment; // 0 means use ABI alignment - - uint32_t bit_offset_in_host; - // size of host integer. 0 means no host integer; this field is aligned - // when vector_index != VECTOR_INDEX_NONE this is the len of the containing vector - uint32_t host_int_bytes; - - uint32_t vector_index; // see the VECTOR_INDEX_* constants - bool is_const; - bool is_volatile; - bool allow_zero; - bool resolve_loop_flag_zero_bits; -}; - -struct ZigTypeInt { - uint32_t bit_count; - bool is_signed; -}; - -struct ZigTypeFloat { - size_t bit_count; -}; - -// Needs to have the same memory layout as ZigTypeVector -struct ZigTypeArray { - ZigType *child_type; - uint64_t len; - ZigValue *sentinel; -}; - -struct TypeStructField { - Buf *name; - ZigType *type_entry; // available after ResolveStatusSizeKnown - ZigValue *type_val; // available after ResolveStatusZeroBitsKnown - size_t src_index; - size_t gen_index; - size_t offset; // byte offset from beginning of struct - AstNode *decl_node; - ZigValue *init_val; // null and then memoized - uint32_t bit_offset_in_host; // offset from the memory at gen_index - uint32_t host_int_bytes; // size of host integer - uint32_t align; - bool is_comptime; -}; - -enum ResolveStatus { - ResolveStatusUnstarted, - ResolveStatusInvalid, - ResolveStatusBeingInferred, - ResolveStatusZeroBitsKnown, - ResolveStatusAlignmentKnown, - ResolveStatusSizeKnown, - ResolveStatusLLVMFwdDecl, - ResolveStatusLLVMFull, -}; - -struct ZigPackage { - Buf root_src_dir; - Buf root_src_path; // relative to root_src_dir - Buf pkg_path; // a.b.c.d which follows the package dependency chain from the root package - - // reminder: hash tables must be initialized before use - HashMap package_table; - - bool added_to_cache; -}; - -// Stuff that only applies to a struct which is the implicit root struct of a file -struct RootStruct { - ZigPackage *package; - Buf *path; // relative to root_package->root_src_dir - Buf *source_code; - ZigLLVMDIFile *di_file; - size_t token_count; - TokenId *token_ids; - TokenLoc *token_locs; -}; - -enum StructSpecial { - StructSpecialNone, - StructSpecialSlice, - StructSpecialInferredTuple, - StructSpecialInferredStruct, -}; - -struct ZigTypeStruct { - AstNode *decl_node; - TypeStructField **fields; - TypeStructField *misaligned_field; - ScopeDecls *decls_scope; - HashMap fields_by_name; - RootStruct *root_struct; - uint32_t *host_int_bytes; // available for packed structs, indexed by gen_index - size_t llvm_full_type_queue_index; - - uint32_t src_field_count; - uint32_t gen_field_count; - - ContainerLayout layout; - ResolveStatus resolve_status; - - StructSpecial special; - // whether any of the fields require comptime - // known after ResolveStatusZeroBitsKnown - bool requires_comptime; - bool resolve_loop_flag_zero_bits; - bool resolve_loop_flag_other; - bool created_by_at_type; -}; - -struct ZigTypeOptional { - ZigType *child_type; - ResolveStatus resolve_status; -}; - -struct ZigTypeErrorUnion { - ZigType *err_set_type; - ZigType *payload_type; - size_t pad_bytes; - LLVMTypeRef pad_llvm_type; -}; - -struct ZigTypeErrorSet { - ErrorTableEntry **errors; - ZigFn *infer_fn; - uint32_t err_count; - bool incomplete; -}; - -struct ZigTypeEnum { - AstNode *decl_node; - TypeEnumField *fields; - ZigType *tag_int_type; - - ScopeDecls *decls_scope; - - LLVMValueRef name_function; - - HashMap fields_by_name; - uint32_t src_field_count; - - ContainerLayout layout; - ResolveStatus resolve_status; - - bool has_explicit_tag_type; - bool non_exhaustive; - bool resolve_loop_flag; -}; - -uint32_t type_ptr_hash(const ZigType *ptr); -bool type_ptr_eql(const ZigType *a, const ZigType *b); - -uint32_t pkg_ptr_hash(const ZigPackage *ptr); -bool pkg_ptr_eql(const ZigPackage *a, const ZigPackage *b); - -uint32_t tld_ptr_hash(const Tld *ptr); -bool tld_ptr_eql(const Tld *a, const Tld *b); - -uint32_t node_ptr_hash(const AstNode *ptr); -bool node_ptr_eql(const AstNode *a, const AstNode *b); - -uint32_t fn_ptr_hash(const ZigFn *ptr); -bool fn_ptr_eql(const ZigFn *a, const ZigFn *b); - -uint32_t err_ptr_hash(const ErrorTableEntry *ptr); -bool err_ptr_eql(const ErrorTableEntry *a, const ErrorTableEntry *b); - -struct ZigTypeUnion { - AstNode *decl_node; - TypeUnionField *fields; - ScopeDecls *decls_scope; - HashMap fields_by_name; - ZigType *tag_type; // always an enum or null - LLVMTypeRef union_llvm_type; - TypeUnionField *most_aligned_union_member; - size_t gen_union_index; - size_t gen_tag_index; - size_t union_abi_size; - - uint32_t src_field_count; - uint32_t gen_field_count; - - ContainerLayout layout; - ResolveStatus resolve_status; - - bool have_explicit_tag_type; - // whether any of the fields require comptime - // the value is not valid until zero_bits_known == true - bool requires_comptime; - bool resolve_loop_flag_zero_bits; - bool resolve_loop_flag_other; -}; - -struct FnGenParamInfo { - size_t src_index; - size_t gen_index; - bool is_byval; - ZigType *type; -}; - -struct ZigTypeFn { - FnTypeId fn_type_id; - bool is_generic; - ZigType *gen_return_type; - size_t gen_param_count; - FnGenParamInfo *gen_param_info; - - LLVMTypeRef raw_type_ref; - ZigLLVMDIType *raw_di_type; - - ZigType *bound_fn_parent; -}; - -struct ZigTypeBoundFn { - ZigType *fn_type; -}; - -// Needs to have the same memory layout as ZigTypeArray -struct ZigTypeVector { - // The type must be a pointer, integer, bool, or float - ZigType *elem_type; - uint64_t len; - size_t padding; -}; - -// A lot of code is relying on ZigTypeArray and ZigTypeVector having the same layout/size -static_assert(sizeof(ZigTypeVector) == sizeof(ZigTypeArray), "Size of ZigTypeVector and ZigTypeArray do not match!"); - -enum ZigTypeId { - ZigTypeIdInvalid, - ZigTypeIdMetaType, - ZigTypeIdVoid, - ZigTypeIdBool, - ZigTypeIdUnreachable, - ZigTypeIdInt, - ZigTypeIdFloat, - ZigTypeIdPointer, - ZigTypeIdArray, - ZigTypeIdStruct, - ZigTypeIdComptimeFloat, - ZigTypeIdComptimeInt, - ZigTypeIdUndefined, - ZigTypeIdNull, - ZigTypeIdOptional, - ZigTypeIdErrorUnion, - ZigTypeIdErrorSet, - ZigTypeIdEnum, - ZigTypeIdUnion, - ZigTypeIdFn, - ZigTypeIdBoundFn, - ZigTypeIdOpaque, - ZigTypeIdFnFrame, - ZigTypeIdAnyFrame, - ZigTypeIdVector, - ZigTypeIdEnumLiteral, -}; - -enum OnePossibleValue { - OnePossibleValueInvalid, - OnePossibleValueNo, - OnePossibleValueYes, -}; - -struct ZigTypeOpaque { - AstNode *decl_node; - Buf *bare_name; - - ScopeDecls *decls_scope; -}; - -struct ZigTypeFnFrame { - ZigFn *fn; - ZigType *locals_struct; - - // This is set to the type that resolving the frame currently depends on, null if none. - // It's for generating a helpful error message. - ZigType *resolve_loop_type; - AstNode *resolve_loop_src_node; - bool reported_loop_err; -}; - -struct ZigTypeAnyFrame { - ZigType *result_type; // null if `anyframe` instead of `anyframe->T` - LLVMTypeRef struct_llvm_ty; -}; - -struct ZigType { - ZigTypeId id; - Buf name; - - // These are not supposed to be accessed directly. They're - // null during semantic analysis, memoized with get_llvm_type - // get_llvm_c_abi_type and get_llvm_di_type - LLVMTypeRef llvm_type; - LLVMTypeRef llvm_c_abi_type; - ZigLLVMDIType *llvm_di_type; - - union { - ZigTypePointer pointer; - ZigTypeInt integral; - ZigTypeFloat floating; - ZigTypeArray array; - ZigTypeStruct structure; - ZigTypeOptional maybe; - ZigTypeErrorUnion error_union; - ZigTypeErrorSet error_set; - ZigTypeEnum enumeration; - ZigTypeUnion unionation; - ZigTypeFn fn; - ZigTypeBoundFn bound_fn; - ZigTypeVector vector; - ZigTypeOpaque opaque; - ZigTypeFnFrame frame; - ZigTypeAnyFrame any_frame; - } data; - - // use these fields to make sure we don't duplicate type table entries for the same type - ZigType *pointer_parent[2]; // [0 - mut, 1 - const] - ZigType *optional_parent; - ZigType *any_frame_parent; - // If we generate a constant name value for this type, we memoize it here. - // The type of this is array - ZigValue *cached_const_name_val; - - OnePossibleValue one_possible_value; - // Known after ResolveStatusAlignmentKnown. - uint32_t abi_align; - // The offset in bytes between consecutive array elements of this type. Known - // after ResolveStatusSizeKnown. - size_t abi_size; - // Number of bits of information in this type. Known after ResolveStatusSizeKnown. - size_t size_in_bits; -}; - -enum FnAnalState { - FnAnalStateReady, - FnAnalStateProbing, - FnAnalStateComplete, - FnAnalStateInvalid, -}; - -struct GlobalExport { - Buf name; - GlobalLinkageId linkage; -}; - -struct ZigFn { - LLVMValueRef llvm_value; - LLVMValueRef abi_return_value; // alloca used when converting at SysV ABI boundaries - const char *llvm_name; - AstNode *proto_node; - AstNode *body_node; - ScopeFnDef *fndef_scope; // parent should be the top level decls or container decls - Scope *child_scope; // parent is scope for last parameter - ScopeBlock *def_scope; // parent is child_scope - Buf symbol_name; - // This is the function type assuming the function does not suspend. - // Note that for an async function, this can be shared with non-async functions. So the value here - // should only be read for things in common between non-async and async function types. - ZigType *type_entry; - // For normal functions one could use the type_entry->raw_type_ref and type_entry->raw_di_type. - // However for functions that suspend, those values could possibly be their non-suspending equivalents. - // So these values should be preferred. - LLVMTypeRef raw_type_ref; - ZigLLVMDIType *raw_di_type; - - ZigType *frame_type; - // in the case of normal functions this is the implicit return type - // in the case of async functions this is the implicit return type according to the - // zig source code, not according to zig ir - ZigType *src_implicit_return_type; - Stage1Zir *stage1_zir; - Stage1Air analyzed_executable; - size_t branch_quota; - AstNode **param_source_nodes; - Buf **param_names; - Stage1AirInst *err_code_spill; - AstNode *assumed_non_async; - - AstNode *fn_no_inline_set_node; - AstNode *fn_static_eval_set_node; - - ZigList alloca_gen_list; - ZigList variable_list; - - Buf *section_name; - AstNode *set_alignstack_node; - - AstNode *set_cold_node; - const AstNode *inferred_async_node; - ZigFn *inferred_async_fn; - AstNode *non_async_node; - - ZigList export_list; - ZigList call_list; - ZigList await_list; - - LLVMValueRef valgrind_client_request_array; - - FnAnalState anal_state; - - uint32_t align_bytes; - uint32_t alignstack_value; - - bool calls_or_awaits_errorable_fn; - bool is_cold; - bool is_noinline; -}; - -static inline bool fn_is_test(const ZigFn *fn) { - return fn->proto_node->type == NodeTypeTestDecl; -} - -uint32_t fn_table_entry_hash(ZigFn*); -bool fn_table_entry_eql(ZigFn *a, ZigFn *b); - -enum BuiltinFnId { - BuiltinFnIdInvalid, - BuiltinFnIdMemcpy, - BuiltinFnIdMemset, - BuiltinFnIdSizeof, - BuiltinFnIdAlignOf, - BuiltinFnIdField, - BuiltinFnIdTypeInfo, - BuiltinFnIdType, - BuiltinFnIdHasField, - BuiltinFnIdTypeof, - BuiltinFnIdAddWithOverflow, - BuiltinFnIdSubWithOverflow, - BuiltinFnIdMulWithOverflow, - BuiltinFnIdShlWithOverflow, - BuiltinFnIdMulAdd, - BuiltinFnIdCInclude, - BuiltinFnIdCDefine, - BuiltinFnIdCUndef, - BuiltinFnIdCompileErr, - BuiltinFnIdCompileLog, - BuiltinFnIdCtz, - BuiltinFnIdClz, - BuiltinFnIdPopCount, - BuiltinFnIdBswap, - BuiltinFnIdBitReverse, - BuiltinFnIdImport, - BuiltinFnIdCImport, - BuiltinFnIdErrName, - BuiltinFnIdBreakpoint, - BuiltinFnIdReturnAddress, - BuiltinFnIdEmbedFile, - BuiltinFnIdCmpxchgWeak, - BuiltinFnIdCmpxchgStrong, - BuiltinFnIdFence, - BuiltinFnIdDivExact, - BuiltinFnIdDivTrunc, - BuiltinFnIdDivFloor, - BuiltinFnIdRem, - BuiltinFnIdMod, - BuiltinFnIdSqrt, - BuiltinFnIdSin, - BuiltinFnIdCos, - BuiltinFnIdTan, - BuiltinFnIdExp, - BuiltinFnIdExp2, - BuiltinFnIdLog, - BuiltinFnIdLog2, - BuiltinFnIdLog10, - BuiltinFnIdFabs, - BuiltinFnIdFloor, - BuiltinFnIdCeil, - BuiltinFnIdTrunc, - BuiltinFnIdNearbyInt, - BuiltinFnIdRound, - BuiltinFnIdTruncate, - BuiltinFnIdIntCast, - BuiltinFnIdFloatCast, - BuiltinFnIdErrSetCast, - BuiltinFnIdIntToFloat, - BuiltinFnIdFloatToInt, - BuiltinFnIdBoolToInt, - BuiltinFnIdErrToInt, - BuiltinFnIdIntToErr, - BuiltinFnIdEnumToInt, - BuiltinFnIdIntToEnum, - BuiltinFnIdVectorType, - BuiltinFnIdShuffle, - BuiltinFnIdSelect, - BuiltinFnIdSplat, - BuiltinFnIdSetCold, - BuiltinFnIdSetRuntimeSafety, - BuiltinFnIdSetFloatMode, - BuiltinFnIdTypeName, - BuiltinFnIdPanic, - BuiltinFnIdPtrCast, - BuiltinFnIdBitCast, - BuiltinFnIdIntToPtr, - BuiltinFnIdPtrToInt, - BuiltinFnIdTagName, - BuiltinFnIdFieldParentPtr, - BuiltinFnIdOffsetOf, - BuiltinFnIdBitOffsetOf, - BuiltinFnIdAsyncCall, - BuiltinFnIdShlExact, - BuiltinFnIdShrExact, - BuiltinFnIdSetEvalBranchQuota, - BuiltinFnIdAlignCast, - BuiltinFnIdThis, - BuiltinFnIdSetAlignStack, - BuiltinFnIdExport, - BuiltinFnIdExtern, - BuiltinFnIdErrorReturnTrace, - BuiltinFnIdAtomicRmw, - BuiltinFnIdAtomicLoad, - BuiltinFnIdAtomicStore, - BuiltinFnIdHasDecl, - BuiltinFnIdUnionInit, - BuiltinFnIdFrameAddress, - BuiltinFnIdFrameType, - BuiltinFnIdFrameHandle, - BuiltinFnIdFrameSize, - BuiltinFnIdAs, - BuiltinFnIdCall, - BuiltinFnIdBitSizeof, - BuiltinFnIdWasmMemorySize, - BuiltinFnIdWasmMemoryGrow, - BuiltinFnIdSrc, - BuiltinFnIdReduce, - BuiltinFnIdMaximum, - BuiltinFnIdMinimum, - BuiltinFnIdPrefetch, - BuiltinFnIdAddrSpaceCast, -}; - -struct BuiltinFnEntry { - BuiltinFnId id; - Buf name; - size_t param_count; -}; - -enum PanicMsgId { - PanicMsgIdUnreachable, - PanicMsgIdBoundsCheckFailure, - PanicMsgIdCastNegativeToUnsigned, - PanicMsgIdCastTruncatedData, - PanicMsgIdIntegerOverflow, - PanicMsgIdShlOverflowedBits, - PanicMsgIdShrOverflowedBits, - PanicMsgIdDivisionByZero, - PanicMsgIdRemainderDivisionByZero, - PanicMsgIdExactDivisionRemainder, - PanicMsgIdUnwrapOptionalFail, - PanicMsgIdInvalidErrorCode, - PanicMsgIdIncorrectAlignment, - PanicMsgIdBadUnionField, - PanicMsgIdBadEnumValue, - PanicMsgIdFloatToInt, - PanicMsgIdPtrCastNull, - PanicMsgIdBadResume, - PanicMsgIdBadAwait, - PanicMsgIdBadReturn, - PanicMsgIdResumedAnAwaitingFn, - PanicMsgIdFrameTooSmall, - PanicMsgIdResumedFnPendingAwait, - PanicMsgIdBadNoSuspendCall, - PanicMsgIdResumeNotSuspendedFn, - PanicMsgIdBadSentinel, - PanicMsgIdShxTooBigRhs, - - PanicMsgIdCount, -}; - -uint32_t fn_eval_hash(Scope*); -bool fn_eval_eql(Scope *a, Scope *b); - -struct TypeId { - ZigTypeId id; - - union { - struct { - CodeGen *codegen; - ZigType *child_type; - InferredStructField *inferred_struct_field; - ZigValue *sentinel; - PtrLen ptr_len; - uint32_t alignment; - - uint32_t bit_offset_in_host; - uint32_t host_int_bytes; - - uint32_t vector_index; - bool is_const; - bool is_volatile; - bool allow_zero; - } pointer; - struct { - CodeGen *codegen; - ZigType *child_type; - uint64_t size; - ZigValue *sentinel; - } array; - struct { - bool is_signed; - uint32_t bit_count; - } integer; - struct { - ZigType *err_set_type; - ZigType *payload_type; - } error_union; - struct { - ZigType *elem_type; - uint32_t len; - } vector; - } data; -}; - -uint32_t type_id_hash(TypeId const *); -bool type_id_eql(TypeId const *a, TypeId const *b); - -enum ZigLLVMFnId { - ZigLLVMFnIdCtz, - ZigLLVMFnIdClz, - ZigLLVMFnIdPopCount, - ZigLLVMFnIdOverflowArithmetic, - ZigLLVMFnIdFMA, - ZigLLVMFnIdFloatOp, - ZigLLVMFnIdBswap, - ZigLLVMFnIdBitReverse, -}; - -// There are a bunch of places in code that rely on these values being in -// exactly this order. -enum AddSubMul { - AddSubMulAdd = 0, - AddSubMulSub = 1, - AddSubMulMul = 2, -}; - -struct ZigLLVMFnKey { - ZigLLVMFnId id; - - union { - struct { - uint32_t bit_count; - uint32_t vector_len; // 0 means not a vector - } ctz; - struct { - uint32_t bit_count; - uint32_t vector_len; // 0 means not a vector - } clz; - struct { - uint32_t bit_count; - uint32_t vector_len; // 0 means not a vector - } pop_count; - struct { - BuiltinFnId op; - uint32_t bit_count; - uint32_t vector_len; // 0 means not a vector - } floating; - struct { - AddSubMul add_sub_mul; - uint32_t bit_count; - uint32_t vector_len; // 0 means not a vector - bool is_signed; - } overflow_arithmetic; - struct { - uint32_t bit_count; - uint32_t vector_len; // 0 means not a vector - } bswap; - struct { - uint32_t bit_count; - uint32_t vector_len; // 0 means not a vector - } bit_reverse; - } data; -}; - -uint32_t zig_llvm_fn_key_hash(ZigLLVMFnKey const *); -bool zig_llvm_fn_key_eql(ZigLLVMFnKey const *a, ZigLLVMFnKey const *b); - -struct TimeEvent { - double time; - const char *name; -}; - -struct CFile { - ZigList args; - const char *source_path; - const char *preprocessor_only_basename; -}; - -struct CodeGen { - // Other code depends on this being first. - ZigStage1 stage1; - - // arena allocator destroyed just prior to codegen emit - heap::ArenaAllocator *pass1_arena; - - //////////////////////////// Runtime State - LLVMModuleRef module; - ZigList errors; - ErrorMsg *trace_err; - LLVMBuilderRef builder; - ZigLLVMDIBuilder *dbuilder; - ZigLLVMDICompileUnit *compile_unit; - ZigLLVMDIFile *compile_unit_file; - LLVMTargetDataRef target_data_ref; - LLVMTargetMachineRef target_machine; - ZigLLVMDIFile *dummy_di_file; - LLVMValueRef cur_ret_ptr; - LLVMValueRef cur_frame_ptr; - LLVMValueRef cur_fn_val; - LLVMValueRef cur_async_switch_instr; - LLVMValueRef cur_async_resume_index_ptr; - LLVMValueRef cur_async_awaiter_ptr; - LLVMBasicBlockRef cur_preamble_llvm_block; - size_t cur_resume_block_count; - LLVMValueRef cur_err_ret_trace_val_arg; - LLVMValueRef cur_err_ret_trace_val_stack; - LLVMValueRef cur_bad_not_suspended_index; - LLVMValueRef memcpy_fn_val; - LLVMValueRef memset_fn_val; - LLVMValueRef trap_fn_val; - LLVMValueRef return_address_fn_val; - LLVMValueRef frame_address_fn_val; - LLVMValueRef add_error_return_trace_addr_fn_val; - LLVMValueRef stacksave_fn_val; - LLVMValueRef stackrestore_fn_val; - LLVMValueRef write_register_fn_val; - LLVMValueRef merge_err_ret_traces_fn_val; - LLVMValueRef sp_md_node; - LLVMValueRef err_name_table; - LLVMValueRef safety_crash_err_fn; - LLVMValueRef return_err_fn; - LLVMValueRef wasm_memory_size; - LLVMValueRef wasm_memory_grow; - LLVMValueRef prefetch; - LLVMTypeRef anyframe_fn_type; - LLVMTypeRef any_frame_header_llvm_ty; - - // reminder: hash tables must be initialized before use - HashMap import_table; - HashMap builtin_fn_table; - HashMap primitive_type_table; - HashMap type_table; - HashMap fn_type_table; - HashMap error_table; - HashMap generic_table; - HashMap memoized_fn_eval_table; - HashMap llvm_fn_table; - HashMap exported_symbol_names; - HashMap external_symbol_names; - HashMap string_literals_table; - HashMap type_info_cache; - HashMap one_possible_values; - - ZigList resolve_queue; - size_t resolve_queue_index; - ZigList timing_events; - ZigList inline_fns; - ZigList test_fns; - ZigList errors_by_index; - size_t largest_err_name_len; - ZigList type_resolve_stack; - - ZigPackage *std_package; - ZigPackage *test_runner_package; - ZigPackage *compile_var_package; - ZigPackage *root_pkg; // @import("root") - ZigPackage *main_pkg; // usually same as root_pkg, except for `zig test` - ZigType *compile_var_import; - ZigType *root_import; - ZigType *start_import; - ZigType *std_builtin_import; - - struct { - ZigType *entry_bool; - ZigType *entry_c_int[CIntTypeCount]; - ZigType *entry_c_longdouble; - ZigType *entry_anyopaque; - ZigType *entry_u8; - ZigType *entry_u16; - ZigType *entry_u32; - ZigType *entry_u29; - ZigType *entry_u64; - ZigType *entry_i8; - ZigType *entry_i32; - ZigType *entry_i64; - ZigType *entry_isize; - ZigType *entry_usize; - ZigType *entry_f16; - ZigType *entry_f32; - ZigType *entry_f64; - ZigType *entry_f80; - ZigType *entry_f128; - ZigType *entry_void; - ZigType *entry_unreachable; - ZigType *entry_type; - ZigType *entry_invalid; - ZigType *entry_block; - ZigType *entry_num_lit_int; - ZigType *entry_num_lit_float; - ZigType *entry_undef; - ZigType *entry_null; - ZigType *entry_anytype; - ZigType *entry_global_error_set; - ZigType *entry_enum_literal; - ZigType *entry_any_frame; - ZigType *entry_opt_ptr_const_anyopaque; - } builtin_types; - - struct Intern { - ZigValue x_undefined; - ZigValue x_void; - ZigValue x_null; - ZigValue x_unreachable; - ZigValue zero_byte; - - ZigValue *for_undefined(); - ZigValue *for_void(); - ZigValue *for_null(); - ZigValue *for_unreachable(); - ZigValue *for_zero_byte(); - } intern; - - ZigType *align_amt_type; - ZigType *stack_trace_type; - ZigType *err_tag_type; - ZigType *test_fn_type; - - Buf llvm_triple_str; - Buf global_asm; - Buf o_file_output_path; - Buf h_file_output_path; - Buf asm_file_output_path; - Buf llvm_ir_file_output_path; - Buf bitcode_file_output_path; - - Buf *builtin_zig_path; - - Stage1ZirInst *invalid_inst_src; - Stage1AirInst *invalid_inst_gen; - Stage1AirInst *unreach_instruction; - - ZigValue panic_msg_vals[PanicMsgIdCount]; - - // The function definitions this module includes. - ZigList fn_defs; - size_t fn_defs_index; - ZigList global_vars; - - ZigFn *cur_fn; - ZigFn *panic_fn; - - ZigFn *largest_frame_fn; - - Stage2ProgressNode *main_progress_node; - Stage2ProgressNode *sub_progress_node; - - ErrColor err_color; - uint32_t next_unresolved_index; - unsigned pointer_size_bytes; - bool is_big_endian; - bool have_err_ret_tracing; - bool verbose_ir; - bool verbose_llvm_ir; - bool verbose_cimport; - bool verbose_llvm_cpu_features; - bool error_during_imports; - bool generate_error_name_table; - bool enable_time_report; - bool enable_stack_report; - bool reported_bad_link_libc_error; - bool need_frame_size_prefix_data; - bool link_libc; - bool link_libcpp; - - BuildMode build_mode; - const ZigTarget *zig_target; - TargetSubsystem subsystem; // careful using this directly; see detect_subsystem - CodeModel code_model; - bool strip_debug_symbols; - bool is_test_build; - bool is_single_threaded; - bool have_pic; - bool have_pie; - bool have_lto; - bool unwind_tables; - bool link_mode_dynamic; - bool dll_export_fns; - bool have_stack_probing; - bool red_zone; - bool omit_frame_pointer; - bool function_sections; - bool include_compiler_rt; - bool test_is_evented; - bool valgrind_enabled; - bool tsan_enabled; - - Buf *root_out_name; - Buf *test_filter; - Buf *test_name_prefix; - Buf *zig_lib_dir; - Buf *zig_std_dir; -}; - -struct ZigVar { - const char *name; - ZigValue *const_value; - ZigType *var_type; - LLVMValueRef value_ref; - Stage1ZirInst *is_comptime; - Stage1AirInst *ptr_instruction; - // which node is the declaration of the variable - AstNode *decl_node; - ZigLLVMDILocalVariable *di_loc_var; - size_t src_arg_index; - Scope *parent_scope; - Scope *child_scope; - LLVMValueRef param_value_ref; - - Buf *section_name; - - // In an inline loop, multiple variables may be created, - // In this case, a reference to a variable should follow - // this pointer to the redefined variable. - ZigVar *next_var; - - ZigList export_list; - - uint32_t align_bytes; - uint32_t ref_count; - - bool shadowable; - bool src_is_const; - bool gen_is_const; - bool is_thread_local; - bool is_comptime_memoized; - bool is_comptime_memoized_value; - bool did_the_decl_codegen; -}; - -struct ErrorTableEntry { - Buf name; - uint32_t value; - AstNode *decl_node; - ErrorTableEntry *other; // null, or another error decl that was merged into this - ZigType *set_with_only_this_in_it; - // If we generate a constant error name value for this error, we memoize it here. - // The type of this is array - ZigValue *cached_error_name_val; -}; - -enum ScopeId { - ScopeIdDecls, - ScopeIdBlock, - ScopeIdDefer, - ScopeIdDeferExpr, - ScopeIdVarDecl, - ScopeIdCImport, - ScopeIdLoop, - ScopeIdSuspend, - ScopeIdFnDef, - ScopeIdCompTime, - ScopeIdRuntime, - ScopeIdTypeOf, - ScopeIdExpr, - ScopeIdNoSuspend, -}; - -struct Scope { - CodeGen *codegen; - AstNode *source_node; - - // if the scope has a parent, this is it - Scope *parent; - - ZigLLVMDIScope *di_scope; - ScopeId id; -}; - -// This scope comes from global declarations or from -// declarations in a container declaration -// NodeTypeContainerDecl -struct ScopeDecls { - Scope base; - - HashMap decl_table; - ZigList use_decls; - AstNode *safety_set_node; - AstNode *fast_math_set_node; - ZigType *import; - // If this is a scope from a container, this is the type entry, otherwise null - ZigType *container_type; - Buf *bare_name; - - bool safety_off; - bool fast_math_on; - bool any_imports_failed; -}; - -enum LVal { - LValNone, - LValPtr, - LValAssign, -}; - -// This scope comes from a block expression in user code. -// NodeTypeBlock -struct ScopeBlock { - Scope base; - - Buf *name; - Stage1ZirBasicBlock *end_block; - Stage1ZirInst *is_comptime; - ResultLocPeerParent *peer_parent; - ZigList *incoming_values; - ZigList *incoming_blocks; - - AstNode *safety_set_node; - AstNode *fast_math_set_node; - - LVal lval; - bool safety_off; - bool fast_math_on; - bool name_used; -}; - -// This scope is created from every defer expression. -// It's the code following the defer statement. -// NodeTypeDefer -struct ScopeDefer { - Scope base; -}; - -// This scope is created from every defer expression. -// It's the parent of the defer expression itself. -// NodeTypeDefer -struct ScopeDeferExpr { - Scope base; - - bool reported_err; -}; - -// This scope is created for every variable declaration inside an IrExecutable -// NodeTypeVariableDeclaration, NodeTypeParamDecl -struct ScopeVarDecl { - Scope base; - - // The variable that creates this scope - ZigVar *var; -}; - -// This scope is created for a @cImport -// NodeTypeFnCallExpr -struct ScopeCImport { - Scope base; - - Buf buf; -}; - -// This scope is created for a loop such as for or while in order to -// make break and continue statements work. -// NodeTypeForExpr or NodeTypeWhileExpr -struct ScopeLoop { - Scope base; - - LVal lval; - Buf *name; - Stage1ZirBasicBlock *break_block; - Stage1ZirBasicBlock *continue_block; - Stage1ZirInst *is_comptime; - ZigList *incoming_values; - ZigList *incoming_blocks; - ResultLocPeerParent *peer_parent; - ScopeExpr *spill_scope; - - bool name_used; -}; - -// This scope blocks certain things from working such as comptime continue -// inside a runtime if expression. -// NodeTypeIfBoolExpr, NodeTypeWhileExpr, NodeTypeForExpr -struct ScopeRuntime { - Scope base; - - Stage1ZirInst *is_comptime; -}; - -// This scope is created for a suspend block in order to have labeled -// suspend for breaking out of a suspend and for detecting if a suspend -// block is inside a suspend block. -struct ScopeSuspend { - Scope base; - - bool reported_err; -}; - -// This scope is created for a comptime expression. -// NodeTypeCompTime, NodeTypeSwitchExpr -struct ScopeCompTime { - Scope base; -}; - -// This scope is created for a nosuspend expression. -// NodeTypeNoSuspend -struct ScopeNoSuspend { - Scope base; -}; - -// This scope is created for a function definition. -// NodeTypeFnDef -struct ScopeFnDef { - Scope base; - - ZigFn *fn_entry; -}; - -// This scope is created for a @TypeOf. -// All runtime side-effects are elided within it. -// NodeTypeFnCallExpr -struct ScopeTypeOf { - Scope base; -}; - -enum MemoizedBool { - MemoizedBoolUnknown, - MemoizedBoolFalse, - MemoizedBoolTrue, -}; - -// This scope is created for each expression. -// It's used to identify when an instruction needs to be spilled, -// so that it can be accessed after a suspend point. -struct ScopeExpr { - Scope base; - - ScopeExpr **children_ptr; - size_t children_len; - - MemoizedBool need_spill; - // This is a hack. I apologize for this, I need this to work so that I - // can make progress on other fronts. I'll pay off this tech debt eventually. - bool spill_harder; -}; - -// synchronized with code in define_builtin_compile_vars -enum AtomicOrder { - AtomicOrderUnordered, - AtomicOrderMonotonic, - AtomicOrderAcquire, - AtomicOrderRelease, - AtomicOrderAcqRel, - AtomicOrderSeqCst, -}; - -// synchronized with code in define_builtin_compile_vars -enum ReduceOp { - ReduceOp_and, - ReduceOp_or, - ReduceOp_xor, - ReduceOp_min, - ReduceOp_max, - ReduceOp_add, - ReduceOp_mul, -}; - -// synchronized with the code in define_builtin_compile_vars -enum AtomicRmwOp { - AtomicRmwOp_xchg, - AtomicRmwOp_add, - AtomicRmwOp_sub, - AtomicRmwOp_and, - AtomicRmwOp_nand, - AtomicRmwOp_or, - AtomicRmwOp_xor, - AtomicRmwOp_max, - AtomicRmwOp_min, -}; - -// A basic block contains no branching. Branches send control flow -// to another basic block. -// Phi instructions must be first in a basic block. -// The last instruction in a basic block must be of type unreachable. -struct Stage1ZirBasicBlock { - ZigList instruction_list; - Stage1AirBasicBlock *child; - Scope *scope; - const char *name_hint; - Stage1ZirInst *suspend_instruction_ref; - - uint32_t ref_count; - uint32_t index; // index into the basic block list - - uint32_t debug_id; - bool suspended; - bool in_resume_stack; -}; - -struct Stage1AirBasicBlock { - ZigList instruction_list; - Scope *scope; - const char *name_hint; - LLVMBasicBlockRef llvm_block; - LLVMBasicBlockRef llvm_exit_block; - // The instruction that referenced this basic block and caused us to - // analyze the basic block. If the same instruction wants us to emit - // the same basic block, then we re-generate it instead of saving it. - Stage1ZirInst *ref_instruction; - // When this is non-null, a branch to this basic block is only allowed - // if the branch is comptime. The instruction points to the reason - // the basic block must be comptime. - AstNode *must_be_comptime_source_node; - - uint32_t debug_id; - bool already_appended; -}; - -// Src instructions are generated by ir_gen_* functions in ir.cpp from AST. -// ir_analyze_* functions consume Src instructions and produce Gen instructions. -// Src instructions do not have type information; Gen instructions do. -enum Stage1ZirInstId : uint8_t { - Stage1ZirInstIdInvalid, - Stage1ZirInstIdDeclVar, - Stage1ZirInstIdBr, - Stage1ZirInstIdCondBr, - Stage1ZirInstIdSwitchBr, - Stage1ZirInstIdSwitchVar, - Stage1ZirInstIdSwitchElseVar, - Stage1ZirInstIdSwitchTarget, - Stage1ZirInstIdPhi, - Stage1ZirInstIdUnOp, - Stage1ZirInstIdBinOp, - Stage1ZirInstIdMergeErrSets, - Stage1ZirInstIdLoadPtr, - Stage1ZirInstIdStorePtr, - Stage1ZirInstIdFieldPtr, - Stage1ZirInstIdElemPtr, - Stage1ZirInstIdVarPtr, - Stage1ZirInstIdCall, - Stage1ZirInstIdCallArgs, - Stage1ZirInstIdCallExtra, - Stage1ZirInstIdAsyncCallExtra, - Stage1ZirInstIdConst, - Stage1ZirInstIdReturn, - Stage1ZirInstIdContainerInitList, - Stage1ZirInstIdContainerInitFields, - Stage1ZirInstIdUnreachable, - Stage1ZirInstIdTypeOf, - Stage1ZirInstIdSetCold, - Stage1ZirInstIdSetRuntimeSafety, - Stage1ZirInstIdSetFloatMode, - Stage1ZirInstIdArrayType, - Stage1ZirInstIdAnyFrameType, - Stage1ZirInstIdSliceType, - Stage1ZirInstIdAsm, - Stage1ZirInstIdSizeOf, - Stage1ZirInstIdTestNonNull, - Stage1ZirInstIdOptionalUnwrapPtr, - Stage1ZirInstIdClz, - Stage1ZirInstIdCtz, - Stage1ZirInstIdPopCount, - Stage1ZirInstIdBswap, - Stage1ZirInstIdBitReverse, - Stage1ZirInstIdImport, - Stage1ZirInstIdCImport, - Stage1ZirInstIdCInclude, - Stage1ZirInstIdCDefine, - Stage1ZirInstIdCUndef, - Stage1ZirInstIdRef, - Stage1ZirInstIdCompileErr, - Stage1ZirInstIdCompileLog, - Stage1ZirInstIdErrName, - Stage1ZirInstIdEmbedFile, - Stage1ZirInstIdCmpxchg, - Stage1ZirInstIdFence, - Stage1ZirInstIdReduce, - Stage1ZirInstIdTruncate, - Stage1ZirInstIdIntCast, - Stage1ZirInstIdFloatCast, - Stage1ZirInstIdIntToFloat, - Stage1ZirInstIdFloatToInt, - Stage1ZirInstIdBoolToInt, - Stage1ZirInstIdVectorType, - Stage1ZirInstIdShuffleVector, - Stage1ZirInstIdSelect, - Stage1ZirInstIdSplat, - Stage1ZirInstIdBoolNot, - Stage1ZirInstIdMemset, - Stage1ZirInstIdMemcpy, - Stage1ZirInstIdSlice, - Stage1ZirInstIdBreakpoint, - Stage1ZirInstIdReturnAddress, - Stage1ZirInstIdFrameAddress, - Stage1ZirInstIdFrameHandle, - Stage1ZirInstIdFrameType, - Stage1ZirInstIdFrameSize, - Stage1ZirInstIdAlignOf, - Stage1ZirInstIdOverflowOp, - Stage1ZirInstIdTestErr, - Stage1ZirInstIdMulAdd, - Stage1ZirInstIdFloatOp, - Stage1ZirInstIdUnwrapErrCode, - Stage1ZirInstIdUnwrapErrPayload, - Stage1ZirInstIdFnProto, - Stage1ZirInstIdTestComptime, - Stage1ZirInstIdPtrCast, - Stage1ZirInstIdBitCast, - Stage1ZirInstIdIntToPtr, - Stage1ZirInstIdPtrToInt, - Stage1ZirInstIdIntToEnum, - Stage1ZirInstIdEnumToInt, - Stage1ZirInstIdIntToErr, - Stage1ZirInstIdErrToInt, - Stage1ZirInstIdCheckSwitchProngsUnderYes, - Stage1ZirInstIdCheckSwitchProngsUnderNo, - Stage1ZirInstIdCheckStatementIsVoid, - Stage1ZirInstIdTypeName, - Stage1ZirInstIdDeclRef, - Stage1ZirInstIdPanic, - Stage1ZirInstIdTagName, - Stage1ZirInstIdFieldParentPtr, - Stage1ZirInstIdOffsetOf, - Stage1ZirInstIdBitOffsetOf, - Stage1ZirInstIdTypeInfo, - Stage1ZirInstIdType, - Stage1ZirInstIdHasField, - Stage1ZirInstIdSetEvalBranchQuota, - Stage1ZirInstIdPtrType, - Stage1ZirInstIdPtrTypeSimple, - Stage1ZirInstIdPtrTypeSimpleConst, - Stage1ZirInstIdAlignCast, - Stage1ZirInstIdImplicitCast, - Stage1ZirInstIdResolveResult, - Stage1ZirInstIdResetResult, - Stage1ZirInstIdSetAlignStack, - Stage1ZirInstIdArgTypeAllowVarFalse, - Stage1ZirInstIdArgTypeAllowVarTrue, - Stage1ZirInstIdExport, - Stage1ZirInstIdExtern, - Stage1ZirInstIdErrorReturnTrace, - Stage1ZirInstIdErrorUnion, - Stage1ZirInstIdAtomicRmw, - Stage1ZirInstIdAtomicLoad, - Stage1ZirInstIdAtomicStore, - Stage1ZirInstIdSaveErrRetAddr, - Stage1ZirInstIdAddImplicitReturnType, - Stage1ZirInstIdErrSetCast, - Stage1ZirInstIdCheckRuntimeScope, - Stage1ZirInstIdHasDecl, - Stage1ZirInstIdUndeclaredIdent, - Stage1ZirInstIdAlloca, - Stage1ZirInstIdEndExpr, - Stage1ZirInstIdUnionInitNamedField, - Stage1ZirInstIdSuspendBegin, - Stage1ZirInstIdSuspendFinish, - Stage1ZirInstIdAwait, - Stage1ZirInstIdResume, - Stage1ZirInstIdSpillBegin, - Stage1ZirInstIdSpillEnd, - Stage1ZirInstIdWasmMemorySize, - Stage1ZirInstIdWasmMemoryGrow, - Stage1ZirInstIdSrc, - Stage1ZirInstIdPrefetch, - Stage1ZirInstIdAddrSpaceCast, -}; - -// ir_render_* functions in codegen.cpp consume Gen instructions and produce LLVM IR. -// Src instructions do not have type information; Gen instructions do. -enum Stage1AirInstId : uint8_t { - Stage1AirInstIdInvalid, - Stage1AirInstIdDeclVar, - Stage1AirInstIdBr, - Stage1AirInstIdCondBr, - Stage1AirInstIdSwitchBr, - Stage1AirInstIdPhi, - Stage1AirInstIdBinaryNot, - Stage1AirInstIdNegation, - Stage1AirInstIdBinOp, - Stage1AirInstIdLoadPtr, - Stage1AirInstIdStorePtr, - Stage1AirInstIdVectorStoreElem, - Stage1AirInstIdStructFieldPtr, - Stage1AirInstIdUnionFieldPtr, - Stage1AirInstIdElemPtr, - Stage1AirInstIdVarPtr, - Stage1AirInstIdReturnPtr, - Stage1AirInstIdCall, - Stage1AirInstIdReturn, - Stage1AirInstIdCast, - Stage1AirInstIdUnreachable, - Stage1AirInstIdAsm, - Stage1AirInstIdTestNonNull, - Stage1AirInstIdOptionalUnwrapPtr, - Stage1AirInstIdOptionalWrap, - Stage1AirInstIdUnionTag, - Stage1AirInstIdClz, - Stage1AirInstIdCtz, - Stage1AirInstIdPopCount, - Stage1AirInstIdBswap, - Stage1AirInstIdBitReverse, - Stage1AirInstIdRef, - Stage1AirInstIdErrName, - Stage1AirInstIdCmpxchg, - Stage1AirInstIdFence, - Stage1AirInstIdReduce, - Stage1AirInstIdTruncate, - Stage1AirInstIdShuffleVector, - Stage1AirInstIdSelect, - Stage1AirInstIdSplat, - Stage1AirInstIdBoolNot, - Stage1AirInstIdMemset, - Stage1AirInstIdMemcpy, - Stage1AirInstIdSlice, - Stage1AirInstIdBreakpoint, - Stage1AirInstIdReturnAddress, - Stage1AirInstIdFrameAddress, - Stage1AirInstIdFrameHandle, - Stage1AirInstIdFrameSize, - Stage1AirInstIdOverflowOp, - Stage1AirInstIdTestErr, - Stage1AirInstIdMulAdd, - Stage1AirInstIdFloatOp, - Stage1AirInstIdUnwrapErrCode, - Stage1AirInstIdUnwrapErrPayload, - Stage1AirInstIdErrWrapCode, - Stage1AirInstIdErrWrapPayload, - Stage1AirInstIdPtrCast, - Stage1AirInstIdBitCast, - Stage1AirInstIdWidenOrShorten, - Stage1AirInstIdIntToPtr, - Stage1AirInstIdPtrToInt, - Stage1AirInstIdIntToEnum, - Stage1AirInstIdIntToErr, - Stage1AirInstIdErrToInt, - Stage1AirInstIdPanic, - Stage1AirInstIdTagName, - Stage1AirInstIdFieldParentPtr, - Stage1AirInstIdAlignCast, - Stage1AirInstIdErrorReturnTrace, - Stage1AirInstIdAtomicRmw, - Stage1AirInstIdAtomicLoad, - Stage1AirInstIdAtomicStore, - Stage1AirInstIdSaveErrRetAddr, - Stage1AirInstIdVectorToArray, - Stage1AirInstIdArrayToVector, - Stage1AirInstIdAssertZero, - Stage1AirInstIdAssertNonNull, - Stage1AirInstIdPtrOfArrayToSlice, - Stage1AirInstIdSuspendBegin, - Stage1AirInstIdSuspendFinish, - Stage1AirInstIdAwait, - Stage1AirInstIdResume, - Stage1AirInstIdSpillBegin, - Stage1AirInstIdSpillEnd, - Stage1AirInstIdVectorExtractElem, - Stage1AirInstIdAlloca, - Stage1AirInstIdConst, - Stage1AirInstIdWasmMemorySize, - Stage1AirInstIdWasmMemoryGrow, - Stage1AirInstIdExtern, - Stage1AirInstIdPrefetch, -}; - -struct Stage1ZirInst { - Stage1ZirInstId id; - uint16_t ref_count; - uint32_t debug_id; - - Scope *scope; - AstNode *source_node; - - // When analyzing IR, instructions that point to this instruction in the "old ir" - // can find the instruction that corresponds to this value in the "new ir" - // with this child field. - Stage1AirInst *child; - Stage1ZirBasicBlock *owner_bb; - - // for debugging purposes, these are useful to call to inspect the instruction - void dump(); - void src(); -}; - -struct Stage1AirInst { - Stage1AirInstId id; - // if ref_count is zero and the instruction has no side effects, - // the instruction can be omitted in codegen - uint16_t ref_count; - uint32_t debug_id; - - Scope *scope; - AstNode *source_node; - - LLVMValueRef llvm_value; - ZigValue *value; - // Nearly any instruction can have to be stored as a local variable before suspending - // and then loaded after resuming, in case there is an expression with a suspend point - // in it, such as: x + await y - Stage1AirInst *spill; - - // for debugging purposes, these are useful to call to inspect the instruction - void dump(); - void src(); -}; - -struct Stage1ZirInstDeclVar { - Stage1ZirInst base; - - ZigVar *var; - Stage1ZirInst *var_type; - Stage1ZirInst *align_value; - Stage1ZirInst *ptr; -}; - -struct Stage1AirInstDeclVar { - Stage1AirInst base; - - ZigVar *var; - Stage1AirInst *var_ptr; -}; - -struct Stage1ZirInstCondBr { - Stage1ZirInst base; - - Stage1ZirInst *condition; - Stage1ZirBasicBlock *then_block; - Stage1ZirBasicBlock *else_block; - Stage1ZirInst *is_comptime; - ResultLoc *result_loc; -}; - -struct Stage1AirInstCondBr { - Stage1AirInst base; - - Stage1AirInst *condition; - Stage1AirBasicBlock *then_block; - Stage1AirBasicBlock *else_block; -}; - -struct Stage1ZirInstBr { - Stage1ZirInst base; - - Stage1ZirBasicBlock *dest_block; - Stage1ZirInst *is_comptime; -}; - -struct Stage1AirInstBr { - Stage1AirInst base; - - Stage1AirBasicBlock *dest_block; -}; - -struct Stage1ZirInstSwitchBrCase { - Stage1ZirInst *value; - Stage1ZirBasicBlock *block; -}; - -struct Stage1ZirInstSwitchBr { - Stage1ZirInst base; - - Stage1ZirInst *target_value; - Stage1ZirBasicBlock *else_block; - size_t case_count; - Stage1ZirInstSwitchBrCase *cases; - Stage1ZirInst *is_comptime; - Stage1ZirInst *switch_prongs_void; -}; - -struct Stage1AirInstSwitchBrCase { - Stage1AirInst *value; - Stage1AirBasicBlock *block; -}; - -struct Stage1AirInstSwitchBr { - Stage1AirInst base; - - Stage1AirInst *target_value; - Stage1AirBasicBlock *else_block; - size_t case_count; - Stage1AirInstSwitchBrCase *cases; -}; - -struct Stage1ZirInstSwitchVar { - Stage1ZirInst base; - - Stage1ZirInst *target_value_ptr; - Stage1ZirInst **prongs_ptr; - size_t prongs_len; -}; - -struct Stage1ZirInstSwitchElseVar { - Stage1ZirInst base; - - Stage1ZirInst *target_value_ptr; - Stage1ZirInstSwitchBr *switch_br; -}; - -struct Stage1ZirInstSwitchTarget { - Stage1ZirInst base; - - Stage1ZirInst *target_value_ptr; -}; - -struct Stage1ZirInstPhi { - Stage1ZirInst base; - - size_t incoming_count; - bool merge_comptime; - Stage1ZirBasicBlock **incoming_blocks; - Stage1ZirInst **incoming_values; - ResultLocPeerParent *peer_parent; -}; - -struct Stage1AirInstPhi { - Stage1AirInst base; - - size_t incoming_count; - Stage1AirBasicBlock **incoming_blocks; - Stage1AirInst **incoming_values; -}; - -enum IrUnOp { - IrUnOpInvalid, - IrUnOpBinNot, - IrUnOpNegation, - IrUnOpNegationWrap, - IrUnOpDereference, - IrUnOpOptional, -}; - -struct Stage1ZirInstUnOp { - Stage1ZirInst base; - - IrUnOp op_id; - LVal lval; - Stage1ZirInst *value; - ResultLoc *result_loc; -}; - -struct Stage1AirInstBinaryNot { - Stage1AirInst base; - Stage1AirInst *operand; -}; - -struct Stage1AirInstNegation { - Stage1AirInst base; - Stage1AirInst *operand; - bool wrapping; -}; - -enum IrBinOp { - IrBinOpInvalid, - IrBinOpBoolOr, - IrBinOpBoolAnd, - IrBinOpCmpEq, - IrBinOpCmpNotEq, - IrBinOpCmpLessThan, - IrBinOpCmpGreaterThan, - IrBinOpCmpLessOrEq, - IrBinOpCmpGreaterOrEq, - IrBinOpBinOr, - IrBinOpBinXor, - IrBinOpBinAnd, - IrBinOpBitShiftLeftLossy, - IrBinOpBitShiftLeftExact, - IrBinOpBitShiftRightLossy, - IrBinOpBitShiftRightExact, - IrBinOpAdd, - IrBinOpAddWrap, - IrBinOpSub, - IrBinOpSubWrap, - IrBinOpMult, - IrBinOpMultWrap, - IrBinOpDivUnspecified, - IrBinOpDivExact, - IrBinOpDivTrunc, - IrBinOpDivFloor, - IrBinOpRemUnspecified, - IrBinOpRemRem, - IrBinOpRemMod, - IrBinOpArrayCat, - IrBinOpArrayMult, - IrBinOpMax, - IrBinOpMin, - IrBinOpAddSat, - IrBinOpSubSat, - IrBinOpMultSat, - IrBinOpShlSat, -}; - -struct Stage1ZirInstBinOp { - Stage1ZirInst base; - - Stage1ZirInst *op1; - Stage1ZirInst *op2; - IrBinOp op_id; - bool safety_check_on; -}; - -struct Stage1AirInstBinOp { - Stage1AirInst base; - - Stage1AirInst *op1; - Stage1AirInst *op2; - IrBinOp op_id; - bool safety_check_on; -}; - -struct Stage1ZirInstMergeErrSets { - Stage1ZirInst base; - - Stage1ZirInst *op1; - Stage1ZirInst *op2; - Buf *type_name; -}; - -struct Stage1ZirInstLoadPtr { - Stage1ZirInst base; - - Stage1ZirInst *ptr; -}; - -struct Stage1AirInstLoadPtr { - Stage1AirInst base; - - Stage1AirInst *ptr; - Stage1AirInst *result_loc; -}; - -struct Stage1ZirInstStorePtr { - Stage1ZirInst base; - - Stage1ZirInst *ptr; - Stage1ZirInst *value; - - bool allow_write_through_const; -}; - -struct Stage1AirInstStorePtr { - Stage1AirInst base; - - Stage1AirInst *ptr; - Stage1AirInst *value; -}; - -struct Stage1AirInstVectorStoreElem { - Stage1AirInst base; - - Stage1AirInst *vector_ptr; - Stage1AirInst *index; - Stage1AirInst *value; -}; - -struct Stage1ZirInstFieldPtr { - Stage1ZirInst base; - - Stage1ZirInst *container_ptr; - Buf *field_name_buffer; - Stage1ZirInst *field_name_expr; - bool initializing; -}; - -struct Stage1AirInstStructFieldPtr { - Stage1AirInst base; - - Stage1AirInst *struct_ptr; - TypeStructField *field; - bool is_const; -}; - -struct Stage1AirInstUnionFieldPtr { - Stage1AirInst base; - - Stage1AirInst *union_ptr; - TypeUnionField *field; - bool safety_check_on; - bool initializing; -}; - -struct Stage1ZirInstElemPtr { - Stage1ZirInst base; - - Stage1ZirInst *array_ptr; - Stage1ZirInst *elem_index; - AstNode *init_array_type_source_node; - PtrLen ptr_len; - bool safety_check_on; -}; - -struct Stage1AirInstElemPtr { - Stage1AirInst base; - - Stage1AirInst *array_ptr; - Stage1AirInst *elem_index; - bool safety_check_on; -}; - -struct Stage1ZirInstVarPtr { - Stage1ZirInst base; - - ZigVar *var; - ScopeFnDef *crossed_fndef_scope; -}; - -struct Stage1AirInstVarPtr { - Stage1AirInst base; - - ZigVar *var; -}; - -// For functions that have a return type for which handle_is_ptr is true, a -// result location pointer is the secret first parameter ("sret"). This -// instruction returns that pointer. -struct Stage1AirInstReturnPtr { - Stage1AirInst base; -}; - -struct Stage1ZirInstCall { - Stage1ZirInst base; - - Stage1ZirInst *fn_ref; - ZigFn *fn_entry; - size_t arg_count; - Stage1ZirInst **args; - Stage1ZirInst *ret_ptr; - ResultLoc *result_loc; - - Stage1ZirInst *new_stack; - - CallModifier modifier; - bool is_async_call_builtin; -}; - -// This is a pass1 instruction, used by @call when the args node is -// a tuple or struct literal. -struct Stage1ZirInstCallArgs { - Stage1ZirInst base; - - Stage1ZirInst *options; - Stage1ZirInst *fn_ref; - Stage1ZirInst **args_ptr; - size_t args_len; - ResultLoc *result_loc; -}; - -// This is a pass1 instruction, used by @call, when the args node -// is not a literal. -// `args` is expected to be either a struct or a tuple. -struct Stage1ZirInstCallExtra { - Stage1ZirInst base; - - Stage1ZirInst *options; - Stage1ZirInst *fn_ref; - Stage1ZirInst *args; - ResultLoc *result_loc; -}; - -// This is a pass1 instruction, used by @asyncCall, when the args node -// is not a literal. -// `args` is expected to be either a struct or a tuple. -struct Stage1ZirInstAsyncCallExtra { - Stage1ZirInst base; - - CallModifier modifier; - Stage1ZirInst *fn_ref; - Stage1ZirInst *ret_ptr; - Stage1ZirInst *new_stack; - Stage1ZirInst *args; - ResultLoc *result_loc; -}; - -struct Stage1AirInstCall { - Stage1AirInst base; - - Stage1AirInst *fn_ref; - ZigFn *fn_entry; - size_t arg_count; - Stage1AirInst **args; - Stage1AirInst *result_loc; - Stage1AirInst *frame_result_loc; - Stage1AirInst *new_stack; - - CallModifier modifier; - - bool is_async_call_builtin; -}; - -struct Stage1ZirInstConst { - Stage1ZirInst base; - - ZigValue *value; -}; - -struct Stage1AirInstConst { - Stage1AirInst base; -}; - -struct Stage1ZirInstReturn { - Stage1ZirInst base; - - Stage1ZirInst *operand; -}; - -// When an IrExecutable is not in a function, a return instruction means that -// the expression returns with that value, even though a return statement from -// an AST perspective is invalid. -struct Stage1AirInstReturn { - Stage1AirInst base; - - Stage1AirInst *operand; -}; - -enum CastOp { - CastOpNoCast, // signifies the function call expression is not a cast - CastOpNoop, // fn call expr is a cast, but does nothing - CastOpIntToFloat, - CastOpFloatToInt, - CastOpBoolToInt, - CastOpNumLitToConcrete, - CastOpErrSet, - CastOpBitCast, -}; - -// TODO get rid of this instruction, replace with instructions for each op code -struct Stage1AirInstCast { - Stage1AirInst base; - - Stage1AirInst *value; - CastOp cast_op; -}; - -struct Stage1ZirInstContainerInitList { - Stage1ZirInst base; - - Stage1ZirInst *elem_type; - size_t item_count; - Stage1ZirInst **elem_result_loc_list; - Stage1ZirInst *result_loc; - AstNode *init_array_type_source_node; -}; - -struct Stage1ZirInstContainerInitFieldsField { - Buf *name; - AstNode *source_node; - Stage1ZirInst *result_loc; -}; - -struct Stage1ZirInstContainerInitFields { - Stage1ZirInst base; - - size_t field_count; - Stage1ZirInstContainerInitFieldsField *fields; - Stage1ZirInst *result_loc; -}; - -struct Stage1ZirInstUnreachable { - Stage1ZirInst base; -}; - -struct Stage1AirInstUnreachable { - Stage1AirInst base; -}; - -struct Stage1ZirInstTypeOf { - Stage1ZirInst base; - - union { - Stage1ZirInst *scalar; // value_count == 1 - Stage1ZirInst **list; // value_count > 1 - } value; - size_t value_count; -}; - -struct Stage1ZirInstSetCold { - Stage1ZirInst base; - - Stage1ZirInst *is_cold; -}; - -struct Stage1ZirInstSetRuntimeSafety { - Stage1ZirInst base; - - Stage1ZirInst *safety_on; -}; - -struct Stage1ZirInstSetFloatMode { - Stage1ZirInst base; - - Stage1ZirInst *scope_value; - Stage1ZirInst *mode_value; -}; - -struct Stage1ZirInstArrayType { - Stage1ZirInst base; - - Stage1ZirInst *size; - Stage1ZirInst *sentinel; - Stage1ZirInst *child_type; -}; - -struct Stage1ZirInstPtrTypeSimple { - Stage1ZirInst base; - - Stage1ZirInst *child_type; -}; - -struct Stage1ZirInstPtrType { - Stage1ZirInst base; - - Stage1ZirInst *sentinel; - Stage1ZirInst *align_value; - Stage1ZirInst *child_type; - uint32_t bit_offset_start; - uint32_t host_int_bytes; - PtrLen ptr_len; - bool is_const; - bool is_volatile; - bool is_allow_zero; -}; - -struct Stage1ZirInstAnyFrameType { - Stage1ZirInst base; - - Stage1ZirInst *payload_type; -}; - -struct Stage1ZirInstSliceType { - Stage1ZirInst base; - - Stage1ZirInst *sentinel; - Stage1ZirInst *align_value; - Stage1ZirInst *child_type; - bool is_const; - bool is_volatile; - bool is_allow_zero; -}; - -struct Stage1ZirInstAsm { - Stage1ZirInst base; - - Stage1ZirInst *asm_template; - Stage1ZirInst **input_list; - Stage1ZirInst **output_types; - ZigVar **output_vars; - size_t return_count; - bool has_side_effects; - bool is_global; -}; - -struct Stage1AirInstAsm { - Stage1AirInst base; - - Buf *asm_template; - AsmToken *token_list; - size_t token_list_len; - Stage1AirInst **input_list; - Stage1AirInst **output_types; - ZigVar **output_vars; - size_t return_count; - bool has_side_effects; -}; - -struct Stage1ZirInstSizeOf { - Stage1ZirInst base; - - Stage1ZirInst *type_value; - bool bit_size; -}; - -// returns true if nonnull, returns false if null -struct Stage1ZirInstTestNonNull { - Stage1ZirInst base; - - Stage1ZirInst *value; -}; - -struct Stage1AirInstTestNonNull { - Stage1AirInst base; - - Stage1AirInst *value; -}; - -// Takes a pointer to an optional value, returns a pointer -// to the payload. -struct Stage1ZirInstOptionalUnwrapPtr { - Stage1ZirInst base; - - Stage1ZirInst *base_ptr; - bool safety_check_on; -}; - -struct Stage1AirInstOptionalUnwrapPtr { - Stage1AirInst base; - - Stage1AirInst *base_ptr; - bool safety_check_on; - bool initializing; -}; - -struct Stage1ZirInstCtz { - Stage1ZirInst base; - - Stage1ZirInst *type; - Stage1ZirInst *op; -}; - -struct Stage1AirInstCtz { - Stage1AirInst base; - - Stage1AirInst *op; -}; - -struct Stage1ZirInstClz { - Stage1ZirInst base; - - Stage1ZirInst *type; - Stage1ZirInst *op; -}; - -struct Stage1AirInstClz { - Stage1AirInst base; - - Stage1AirInst *op; -}; - -struct Stage1ZirInstPopCount { - Stage1ZirInst base; - - Stage1ZirInst *type; - Stage1ZirInst *op; -}; - -struct Stage1AirInstPopCount { - Stage1AirInst base; - - Stage1AirInst *op; -}; - -struct Stage1AirInstUnionTag { - Stage1AirInst base; - - Stage1AirInst *value; -}; - -struct Stage1ZirInstImport { - Stage1ZirInst base; - - Stage1ZirInst *name; -}; - -struct Stage1ZirInstRef { - Stage1ZirInst base; - - Stage1ZirInst *value; -}; - -struct Stage1AirInstRef { - Stage1AirInst base; - - Stage1AirInst *operand; - Stage1AirInst *result_loc; -}; - -struct Stage1ZirInstCompileErr { - Stage1ZirInst base; - - Stage1ZirInst *msg; -}; - -struct Stage1ZirInstCompileLog { - Stage1ZirInst base; - - size_t msg_count; - Stage1ZirInst **msg_list; -}; - -struct Stage1ZirInstErrName { - Stage1ZirInst base; - - Stage1ZirInst *value; -}; - -struct Stage1AirInstErrName { - Stage1AirInst base; - - Stage1AirInst *value; -}; - -struct Stage1ZirInstCImport { - Stage1ZirInst base; -}; - -struct Stage1ZirInstCInclude { - Stage1ZirInst base; - - Stage1ZirInst *name; -}; - -struct Stage1ZirInstCDefine { - Stage1ZirInst base; - - Stage1ZirInst *name; - Stage1ZirInst *value; -}; - -struct Stage1ZirInstCUndef { - Stage1ZirInst base; - - Stage1ZirInst *name; -}; - -struct Stage1ZirInstEmbedFile { - Stage1ZirInst base; - - Stage1ZirInst *name; -}; - -struct Stage1ZirInstCmpxchg { - Stage1ZirInst base; - - bool is_weak; - Stage1ZirInst *type_value; - Stage1ZirInst *ptr; - Stage1ZirInst *cmp_value; - Stage1ZirInst *new_value; - Stage1ZirInst *success_order_value; - Stage1ZirInst *failure_order_value; - ResultLoc *result_loc; -}; - -struct Stage1AirInstCmpxchg { - Stage1AirInst base; - - AtomicOrder success_order; - AtomicOrder failure_order; - Stage1AirInst *ptr; - Stage1AirInst *cmp_value; - Stage1AirInst *new_value; - Stage1AirInst *result_loc; - bool is_weak; -}; - -struct Stage1ZirInstFence { - Stage1ZirInst base; - - Stage1ZirInst *order; -}; - -struct Stage1AirInstFence { - Stage1AirInst base; - - AtomicOrder order; -}; - -struct Stage1ZirInstReduce { - Stage1ZirInst base; - - Stage1ZirInst *op; - Stage1ZirInst *value; -}; - -struct Stage1AirInstReduce { - Stage1AirInst base; - - ReduceOp op; - Stage1AirInst *value; -}; - -struct Stage1ZirInstTruncate { - Stage1ZirInst base; - - Stage1ZirInst *dest_type; - Stage1ZirInst *target; -}; - -struct Stage1AirInstTruncate { - Stage1AirInst base; - - Stage1AirInst *target; -}; - -struct Stage1ZirInstIntCast { - Stage1ZirInst base; - - Stage1ZirInst *dest_type; - Stage1ZirInst *target; -}; - -struct Stage1ZirInstFloatCast { - Stage1ZirInst base; - - Stage1ZirInst *dest_type; - Stage1ZirInst *target; -}; - -struct Stage1ZirInstErrSetCast { - Stage1ZirInst base; - - Stage1ZirInst *dest_type; - Stage1ZirInst *target; -}; - -struct Stage1ZirInstIntToFloat { - Stage1ZirInst base; - - Stage1ZirInst *dest_type; - Stage1ZirInst *target; -}; - -struct Stage1ZirInstFloatToInt { - Stage1ZirInst base; - - Stage1ZirInst *dest_type; - Stage1ZirInst *target; -}; - -struct Stage1ZirInstBoolToInt { - Stage1ZirInst base; - - Stage1ZirInst *target; -}; - -struct Stage1ZirInstVectorType { - Stage1ZirInst base; - - Stage1ZirInst *len; - Stage1ZirInst *elem_type; -}; - -struct Stage1ZirInstBoolNot { - Stage1ZirInst base; - - Stage1ZirInst *value; -}; - -struct Stage1AirInstBoolNot { - Stage1AirInst base; - - Stage1AirInst *value; -}; - -struct Stage1ZirInstMemset { - Stage1ZirInst base; - - Stage1ZirInst *dest_ptr; - Stage1ZirInst *byte; - Stage1ZirInst *count; -}; - -struct Stage1AirInstMemset { - Stage1AirInst base; - - Stage1AirInst *dest_ptr; - Stage1AirInst *byte; - Stage1AirInst *count; -}; - -struct Stage1ZirInstMemcpy { - Stage1ZirInst base; - - Stage1ZirInst *dest_ptr; - Stage1ZirInst *src_ptr; - Stage1ZirInst *count; -}; - -struct Stage1AirInstMemcpy { - Stage1AirInst base; - - Stage1AirInst *dest_ptr; - Stage1AirInst *src_ptr; - Stage1AirInst *count; -}; - -struct Stage1ZirInstWasmMemorySize { - Stage1ZirInst base; - - Stage1ZirInst *index; -}; - -struct Stage1AirInstWasmMemorySize { - Stage1AirInst base; - - Stage1AirInst *index; -}; - -struct Stage1ZirInstWasmMemoryGrow { - Stage1ZirInst base; - - Stage1ZirInst *index; - Stage1ZirInst *delta; -}; - -struct Stage1AirInstWasmMemoryGrow { - Stage1AirInst base; - - Stage1AirInst *index; - Stage1AirInst *delta; -}; - -struct Stage1ZirInstSrc { - Stage1ZirInst base; -}; - -struct Stage1ZirInstPrefetch { - Stage1ZirInst base; - - Stage1ZirInst *ptr; - Stage1ZirInst *options; -}; - -struct Stage1AirInstPrefetch { - Stage1AirInst base; - - Stage1AirInst *ptr; - PrefetchRw rw; - // Must be in the range 0-3 inclusive - uint8_t locality; - PrefetchCache cache; -}; - - -struct Stage1ZirInstSlice { - Stage1ZirInst base; - - Stage1ZirInst *ptr; - Stage1ZirInst *start; - Stage1ZirInst *end; - Stage1ZirInst *sentinel; - ResultLoc *result_loc; - bool safety_check_on; -}; - -struct Stage1AirInstSlice { - Stage1AirInst base; - - Stage1AirInst *ptr; - Stage1AirInst *start; - Stage1AirInst *end; - Stage1AirInst *result_loc; - ZigValue *sentinel; - bool safety_check_on; -}; - -struct Stage1ZirInstBreakpoint { - Stage1ZirInst base; -}; - -struct Stage1AirInstBreakpoint { - Stage1AirInst base; -}; - -struct Stage1ZirInstReturnAddress { - Stage1ZirInst base; -}; - -struct Stage1AirInstReturnAddress { - Stage1AirInst base; -}; - -struct Stage1ZirInstFrameAddress { - Stage1ZirInst base; -}; - -struct Stage1AirInstFrameAddress { - Stage1AirInst base; -}; - -struct Stage1ZirInstFrameHandle { - Stage1ZirInst base; -}; - -struct Stage1AirInstFrameHandle { - Stage1AirInst base; -}; - -struct Stage1ZirInstFrameType { - Stage1ZirInst base; - - Stage1ZirInst *fn; -}; - -struct Stage1ZirInstFrameSize { - Stage1ZirInst base; - - Stage1ZirInst *fn; -}; - -struct Stage1AirInstFrameSize { - Stage1AirInst base; - - Stage1AirInst *fn; -}; - -enum IrOverflowOp { - IrOverflowOpAdd, - IrOverflowOpSub, - IrOverflowOpMul, - IrOverflowOpShl, -}; - -struct Stage1ZirInstOverflowOp { - Stage1ZirInst base; - - IrOverflowOp op; - Stage1ZirInst *type_value; - Stage1ZirInst *op1; - Stage1ZirInst *op2; - Stage1ZirInst *result_ptr; -}; - -struct Stage1AirInstOverflowOp { - Stage1AirInst base; - - IrOverflowOp op; - Stage1AirInst *op1; - Stage1AirInst *op2; - Stage1AirInst *result_ptr; - - // TODO can this field be removed? - ZigType *result_ptr_type; -}; - -struct Stage1ZirInstMulAdd { - Stage1ZirInst base; - - Stage1ZirInst *type_value; - Stage1ZirInst *op1; - Stage1ZirInst *op2; - Stage1ZirInst *op3; -}; - -struct Stage1AirInstMulAdd { - Stage1AirInst base; - - Stage1AirInst *op1; - Stage1AirInst *op2; - Stage1AirInst *op3; -}; - -struct Stage1ZirInstAlignOf { - Stage1ZirInst base; - - Stage1ZirInst *type_value; -}; - -// returns true if error, returns false if not error -struct Stage1ZirInstTestErr { - Stage1ZirInst base; - - Stage1ZirInst *base_ptr; - bool resolve_err_set; - bool base_ptr_is_payload; -}; - -struct Stage1AirInstTestErr { - Stage1AirInst base; - - Stage1AirInst *err_union; -}; - -// Takes an error union pointer, returns a pointer to the error code. -struct Stage1ZirInstUnwrapErrCode { - Stage1ZirInst base; - - Stage1ZirInst *err_union_ptr; - bool initializing; -}; - -struct Stage1AirInstUnwrapErrCode { - Stage1AirInst base; - - Stage1AirInst *err_union_ptr; - bool initializing; -}; - -struct Stage1ZirInstUnwrapErrPayload { - Stage1ZirInst base; - - Stage1ZirInst *value; - bool safety_check_on; - bool initializing; -}; - -struct Stage1AirInstUnwrapErrPayload { - Stage1AirInst base; - - Stage1AirInst *value; - bool safety_check_on; - bool initializing; -}; - -struct Stage1AirInstOptionalWrap { - Stage1AirInst base; - - Stage1AirInst *operand; - Stage1AirInst *result_loc; -}; - -struct Stage1AirInstErrWrapPayload { - Stage1AirInst base; - - Stage1AirInst *operand; - Stage1AirInst *result_loc; -}; - -struct Stage1AirInstErrWrapCode { - Stage1AirInst base; - - Stage1AirInst *operand; - Stage1AirInst *result_loc; -}; - -struct Stage1ZirInstFnProto { - Stage1ZirInst base; - - Stage1ZirInst **param_types; - Stage1ZirInst *align_value; - Stage1ZirInst *callconv_value; - Stage1ZirInst *return_type; - bool is_var_args; -}; - -// true if the target value is compile time known, false otherwise -struct Stage1ZirInstTestComptime { - Stage1ZirInst base; - - Stage1ZirInst *value; -}; - -struct Stage1ZirInstPtrCast { - Stage1ZirInst base; - - Stage1ZirInst *dest_type; - Stage1ZirInst *ptr; - bool safety_check_on; -}; - -struct Stage1AirInstPtrCast { - Stage1AirInst base; - - Stage1AirInst *ptr; - bool safety_check_on; -}; - -struct Stage1ZirInstImplicitCast { - Stage1ZirInst base; - - Stage1ZirInst *operand; - ResultLocCast *result_loc_cast; -}; - -struct Stage1ZirInstBitCast { - Stage1ZirInst base; - - Stage1ZirInst *operand; - ResultLocBitCast *result_loc_bit_cast; -}; - -struct Stage1AirInstBitCast { - Stage1AirInst base; - - Stage1AirInst *operand; -}; - -struct Stage1AirInstWidenOrShorten { - Stage1AirInst base; - - Stage1AirInst *target; -}; - -struct Stage1ZirInstPtrToInt { - Stage1ZirInst base; - - Stage1ZirInst *target; -}; - -struct Stage1AirInstPtrToInt { - Stage1AirInst base; - - Stage1AirInst *target; -}; - -struct Stage1ZirInstIntToPtr { - Stage1ZirInst base; - - Stage1ZirInst *dest_type; - Stage1ZirInst *target; -}; - -struct Stage1AirInstIntToPtr { - Stage1AirInst base; - - Stage1AirInst *target; -}; - -struct Stage1ZirInstIntToEnum { - Stage1ZirInst base; - - Stage1ZirInst *dest_type; - Stage1ZirInst *target; -}; - -struct Stage1AirInstIntToEnum { - Stage1AirInst base; - - Stage1AirInst *target; -}; - -struct Stage1ZirInstEnumToInt { - Stage1ZirInst base; - - Stage1ZirInst *target; -}; - -struct Stage1ZirInstIntToErr { - Stage1ZirInst base; - - Stage1ZirInst *target; -}; - -struct Stage1AirInstIntToErr { - Stage1AirInst base; - - Stage1AirInst *target; -}; - -struct Stage1ZirInstErrToInt { - Stage1ZirInst base; - - Stage1ZirInst *target; -}; - -struct Stage1AirInstErrToInt { - Stage1AirInst base; - - Stage1AirInst *target; -}; - -struct Stage1ZirInstCheckSwitchProngsRange { - Stage1ZirInst *start; - Stage1ZirInst *end; -}; - -struct Stage1ZirInstCheckSwitchProngs { - Stage1ZirInst base; - - Stage1ZirInst *target_value; - Stage1ZirInstCheckSwitchProngsRange *ranges; - size_t range_count; - AstNode* else_prong; -}; - -struct Stage1ZirInstCheckStatementIsVoid { - Stage1ZirInst base; - - Stage1ZirInst *statement_value; -}; - -struct Stage1ZirInstTypeName { - Stage1ZirInst base; - - Stage1ZirInst *type_value; -}; - -struct Stage1ZirInstDeclRef { - Stage1ZirInst base; - - LVal lval; - Tld *tld; -}; - -struct Stage1ZirInstPanic { - Stage1ZirInst base; - - Stage1ZirInst *msg; -}; - -struct Stage1AirInstPanic { - Stage1AirInst base; - - Stage1AirInst *msg; -}; - -struct Stage1ZirInstTagName { - Stage1ZirInst base; - - Stage1ZirInst *target; -}; - -struct Stage1AirInstTagName { - Stage1AirInst base; - - Stage1AirInst *target; -}; - -struct Stage1ZirInstFieldParentPtr { - Stage1ZirInst base; - - Stage1ZirInst *type_value; - Stage1ZirInst *field_name; - Stage1ZirInst *field_ptr; -}; - -struct Stage1AirInstFieldParentPtr { - Stage1AirInst base; - - Stage1AirInst *field_ptr; - TypeStructField *field; -}; - -struct Stage1ZirInstOffsetOf { - Stage1ZirInst base; - - Stage1ZirInst *type_value; - Stage1ZirInst *field_name; -}; - -struct Stage1ZirInstBitOffsetOf { - Stage1ZirInst base; - - Stage1ZirInst *type_value; - Stage1ZirInst *field_name; -}; - -struct Stage1ZirInstTypeInfo { - Stage1ZirInst base; - - Stage1ZirInst *type_value; -}; - -struct Stage1ZirInstType { - Stage1ZirInst base; - - Stage1ZirInst *type_info; -}; - -struct Stage1ZirInstHasField { - Stage1ZirInst base; - - Stage1ZirInst *container_type; - Stage1ZirInst *field_name; -}; - -struct Stage1ZirInstSetEvalBranchQuota { - Stage1ZirInst base; - - Stage1ZirInst *new_quota; -}; - -struct Stage1ZirInstAlignCast { - Stage1ZirInst base; - - Stage1ZirInst *align_bytes; - Stage1ZirInst *target; -}; - -struct Stage1AirInstAlignCast { - Stage1AirInst base; - - Stage1AirInst *target; -}; - -struct Stage1ZirInstAddrSpaceCast { - Stage1ZirInst base; - - Stage1ZirInst *addrspace; - Stage1ZirInst *ptr; -}; - -struct Stage1ZirInstSetAlignStack { - Stage1ZirInst base; - - Stage1ZirInst *align_bytes; -}; - -struct Stage1ZirInstArgType { - Stage1ZirInst base; - - Stage1ZirInst *fn_type; - Stage1ZirInst *arg_index; -}; - -struct Stage1ZirInstExport { - Stage1ZirInst base; - - Stage1ZirInst *target; - Stage1ZirInst *options; -}; - -struct Stage1ZirInstExtern { - Stage1ZirInst base; - - Stage1ZirInst *type; - Stage1ZirInst *options; -}; - -struct Stage1AirInstExtern { - Stage1AirInst base; - - Buf *name; - GlobalLinkageId linkage; - bool is_thread_local; -}; - -enum IrInstErrorReturnTraceOptional { - IrInstErrorReturnTraceNull, - IrInstErrorReturnTraceNonNull, -}; - -struct Stage1ZirInstErrorReturnTrace { - Stage1ZirInst base; - - IrInstErrorReturnTraceOptional optional; -}; - -struct Stage1AirInstErrorReturnTrace { - Stage1AirInst base; - - IrInstErrorReturnTraceOptional optional; -}; - -struct Stage1ZirInstErrorUnion { - Stage1ZirInst base; - - Stage1ZirInst *err_set; - Stage1ZirInst *payload; - Buf *type_name; -}; - -struct Stage1ZirInstAtomicRmw { - Stage1ZirInst base; - - Stage1ZirInst *operand_type; - Stage1ZirInst *ptr; - Stage1ZirInst *op; - Stage1ZirInst *operand; - Stage1ZirInst *ordering; -}; - -struct Stage1AirInstAtomicRmw { - Stage1AirInst base; - - Stage1AirInst *ptr; - Stage1AirInst *operand; - AtomicRmwOp op; - AtomicOrder ordering; -}; - -struct Stage1ZirInstAtomicLoad { - Stage1ZirInst base; - - Stage1ZirInst *operand_type; - Stage1ZirInst *ptr; - Stage1ZirInst *ordering; -}; - -struct Stage1AirInstAtomicLoad { - Stage1AirInst base; - - Stage1AirInst *ptr; - AtomicOrder ordering; -}; - -struct Stage1ZirInstAtomicStore { - Stage1ZirInst base; - - Stage1ZirInst *operand_type; - Stage1ZirInst *ptr; - Stage1ZirInst *value; - Stage1ZirInst *ordering; -}; - -struct Stage1AirInstAtomicStore { - Stage1AirInst base; - - Stage1AirInst *ptr; - Stage1AirInst *value; - AtomicOrder ordering; -}; - -struct Stage1ZirInstSaveErrRetAddr { - Stage1ZirInst base; -}; - -struct Stage1AirInstSaveErrRetAddr { - Stage1AirInst base; -}; - -struct Stage1ZirInstAddImplicitReturnType { - Stage1ZirInst base; - - Stage1ZirInst *value; - ResultLocReturn *result_loc_ret; -}; - -// For float ops that take a single argument -struct Stage1ZirInstFloatOp { - Stage1ZirInst base; - - Stage1ZirInst *operand; - BuiltinFnId fn_id; -}; - -struct Stage1AirInstFloatOp { - Stage1AirInst base; - - Stage1AirInst *operand; - BuiltinFnId fn_id; -}; - -struct Stage1ZirInstCheckRuntimeScope { - Stage1ZirInst base; - - Stage1ZirInst *scope_is_comptime; - Stage1ZirInst *is_comptime; -}; - -struct Stage1ZirInstBswap { - Stage1ZirInst base; - - Stage1ZirInst *type; - Stage1ZirInst *op; -}; - -struct Stage1AirInstBswap { - Stage1AirInst base; - - Stage1AirInst *op; -}; - -struct Stage1ZirInstBitReverse { - Stage1ZirInst base; - - Stage1ZirInst *type; - Stage1ZirInst *op; -}; - -struct Stage1AirInstBitReverse { - Stage1AirInst base; - - Stage1AirInst *op; -}; - -struct Stage1AirInstArrayToVector { - Stage1AirInst base; - - Stage1AirInst *array; -}; - -struct Stage1AirInstVectorToArray { - Stage1AirInst base; - - Stage1AirInst *vector; - Stage1AirInst *result_loc; -}; - -struct Stage1ZirInstShuffleVector { - Stage1ZirInst base; - - Stage1ZirInst *scalar_type; - Stage1ZirInst *a; - Stage1ZirInst *b; - Stage1ZirInst *mask; // This is in zig-format, not llvm format -}; - -struct Stage1AirInstShuffleVector { - Stage1AirInst base; - - Stage1AirInst *a; - Stage1AirInst *b; - Stage1AirInst *mask; // This is in zig-format, not llvm format -}; - -struct Stage1ZirInstSelect { - Stage1ZirInst base; - - Stage1ZirInst *scalar_type; - Stage1ZirInst *pred; // This is in zig-format, not llvm format - Stage1ZirInst *a; - Stage1ZirInst *b; -}; - -struct Stage1AirInstSelect { - Stage1AirInst base; - - Stage1AirInst *pred; // This is in zig-format, not llvm format - Stage1AirInst *a; - Stage1AirInst *b; -}; - -struct Stage1ZirInstSplat { - Stage1ZirInst base; - - Stage1ZirInst *len; - Stage1ZirInst *scalar; -}; - -struct Stage1AirInstSplat { - Stage1AirInst base; - - Stage1AirInst *scalar; -}; - -struct Stage1AirInstAssertZero { - Stage1AirInst base; - - Stage1AirInst *target; -}; - -struct Stage1AirInstAssertNonNull { - Stage1AirInst base; - - Stage1AirInst *target; -}; - -struct Stage1ZirInstUnionInitNamedField { - Stage1ZirInst base; - - Stage1ZirInst *union_type; - Stage1ZirInst *field_name; - Stage1ZirInst *field_result_loc; - Stage1ZirInst *result_loc; -}; - -struct Stage1ZirInstHasDecl { - Stage1ZirInst base; - - Stage1ZirInst *container; - Stage1ZirInst *name; -}; - -struct Stage1ZirInstUndeclaredIdent { - Stage1ZirInst base; - - Buf *name; -}; - -struct Stage1ZirInstAlloca { - Stage1ZirInst base; - - Stage1ZirInst *align; - Stage1ZirInst *is_comptime; - const char *name_hint; -}; - -struct Stage1AirInstAlloca { - Stage1AirInst base; - - uint32_t align; - const char *name_hint; - size_t field_index; -}; - -struct Stage1ZirInstEndExpr { - Stage1ZirInst base; - - Stage1ZirInst *value; - ResultLoc *result_loc; -}; - -// This one is for writing through the result pointer. -struct Stage1ZirInstResolveResult { - Stage1ZirInst base; - - ResultLoc *result_loc; - Stage1ZirInst *ty; -}; - -struct Stage1ZirInstResetResult { - Stage1ZirInst base; - - ResultLoc *result_loc; -}; - -struct Stage1AirInstPtrOfArrayToSlice { - Stage1AirInst base; - - Stage1AirInst *operand; - Stage1AirInst *result_loc; -}; - -struct Stage1ZirInstSuspendBegin { - Stage1ZirInst base; -}; - -struct Stage1AirInstSuspendBegin { - Stage1AirInst base; - - LLVMBasicBlockRef resume_bb; -}; - -struct Stage1ZirInstSuspendFinish { - Stage1ZirInst base; - - Stage1ZirInstSuspendBegin *begin; -}; - -struct Stage1AirInstSuspendFinish { - Stage1AirInst base; - - Stage1AirInstSuspendBegin *begin; -}; - -struct Stage1ZirInstAwait { - Stage1ZirInst base; - - Stage1ZirInst *frame; - ResultLoc *result_loc; - bool is_nosuspend; -}; - -struct Stage1AirInstAwait { - Stage1AirInst base; - - Stage1AirInst *frame; - Stage1AirInst *result_loc; - ZigFn *target_fn; - bool is_nosuspend; -}; - -struct Stage1ZirInstResume { - Stage1ZirInst base; - - Stage1ZirInst *frame; -}; - -struct Stage1AirInstResume { - Stage1AirInst base; - - Stage1AirInst *frame; -}; - -enum SpillId { - SpillIdInvalid, - SpillIdRetErrCode, -}; - -struct Stage1ZirInstSpillBegin { - Stage1ZirInst base; - - Stage1ZirInst *operand; - SpillId spill_id; -}; - -struct Stage1AirInstSpillBegin { - Stage1AirInst base; - - SpillId spill_id; - Stage1AirInst *operand; -}; - -struct Stage1ZirInstSpillEnd { - Stage1ZirInst base; - - Stage1ZirInstSpillBegin *begin; -}; - -struct Stage1AirInstSpillEnd { - Stage1AirInst base; - - Stage1AirInstSpillBegin *begin; -}; - -struct Stage1AirInstVectorExtractElem { - Stage1AirInst base; - - Stage1AirInst *vector; - Stage1AirInst *index; -}; - -enum ResultLocId { - ResultLocIdInvalid, - ResultLocIdNone, - ResultLocIdVar, - ResultLocIdReturn, - ResultLocIdPeer, - ResultLocIdPeerParent, - ResultLocIdInstruction, - ResultLocIdBitCast, - ResultLocIdCast, -}; - -// Additions to this struct may need to be handled in -// ir_reset_result -struct ResultLoc { - ResultLocId id; - bool written; - bool allow_write_through_const; - Stage1AirInst *resolved_loc; // result ptr - Stage1ZirInst *source_instruction; - Stage1AirInst *gen_instruction; // value to store to the result loc - ZigType *implicit_elem_type; -}; - -struct ResultLocNone { - ResultLoc base; -}; - -struct ResultLocVar { - ResultLoc base; - - ZigVar *var; -}; - -struct ResultLocReturn { - ResultLoc base; - - bool implicit_return_type_done; -}; - -struct IrSuspendPosition { - size_t basic_block_index; - size_t instruction_index; -}; - -struct ResultLocPeerParent { - ResultLoc base; - - bool skipped; - bool done_resuming; - Stage1ZirBasicBlock *end_bb; - ResultLoc *parent; - ZigList peers; - ZigType *resolved_type; - Stage1ZirInst *is_comptime; -}; - -struct ResultLocPeer { - ResultLoc base; - - ResultLocPeerParent *parent; - Stage1ZirBasicBlock *next_bb; - IrSuspendPosition suspend_pos; -}; - -// The result location is the source instruction -struct ResultLocInstruction { - ResultLoc base; -}; - -// The source_instruction is the destination type -struct ResultLocBitCast { - ResultLoc base; - - ResultLoc *parent; -}; - -// The source_instruction is the destination type -struct ResultLocCast { - ResultLoc base; - - ResultLoc *parent; -}; - -static const size_t slice_ptr_index = 0; -static const size_t slice_len_index = 1; - -static const size_t maybe_child_index = 0; -static const size_t maybe_null_index = 1; - -static const size_t err_union_payload_index = 0; -static const size_t err_union_err_index = 1; - -// label (grep this): [fn_frame_struct_layout] -static const size_t frame_fn_ptr_index = 0; -static const size_t frame_resume_index = 1; -static const size_t frame_awaiter_index = 2; -static const size_t frame_ret_start = 3; - -// TODO https://github.com/ziglang/zig/issues/3056 -// We require this to be a power of 2 so that we can use shifting rather than -// remainder division. -static const size_t stack_trace_ptr_count = 32; // Must be a power of 2. - -#define NAMESPACE_SEP_CHAR '.' -#define NAMESPACE_SEP_STR "." - -#define CACHE_OUT_SUBDIR "o" -#define CACHE_HASH_SUBDIR "h" - -enum FloatMode { - FloatModeStrict, - FloatModeOptimized, -}; - -enum FnWalkId { - FnWalkIdAttrs, - FnWalkIdCall, - FnWalkIdTypes, - FnWalkIdVars, - FnWalkIdInits, -}; - -struct FnWalkAttrs { - ZigFn *fn; - LLVMValueRef llvm_fn; - unsigned gen_i; -}; - -struct FnWalkCall { - ZigList *gen_param_values; - ZigList *gen_param_types; - Stage1AirInstCall *inst; - bool is_var_args; -}; - -struct FnWalkTypes { - ZigList *param_di_types; - ZigList *gen_param_types; -}; - -struct FnWalkVars { - ZigType *import; - LLVMValueRef llvm_fn; - ZigFn *fn; - ZigVar *var; - unsigned gen_i; -}; - -struct FnWalkInits { - LLVMValueRef llvm_fn; - ZigFn *fn; - unsigned gen_i; -}; - -struct FnWalk { - FnWalkId id; - union { - FnWalkAttrs attrs; - FnWalkCall call; - FnWalkTypes types; - FnWalkVars vars; - FnWalkInits inits; - } data; -}; - -#endif diff --git a/src/stage1/analyze.cpp b/src/stage1/analyze.cpp deleted file mode 100644 index 0f8428d1b4a2..000000000000 --- a/src/stage1/analyze.cpp +++ /dev/null @@ -1,10443 +0,0 @@ -/* - * Copyright (c) 2015 Andrew Kelley - * - * This file is part of zig, which is MIT licensed. - * See http://opensource.org/licenses/MIT - */ - -#include "analyze.hpp" -#include "codegen.hpp" -#include "error.hpp" -#include "astgen.hpp" -#include "ir.hpp" -#include "ir_print.hpp" -#include "os.hpp" -#include "parser.hpp" -#include "softfloat.hpp" -#include "zig_llvm.h" - - -static const size_t default_backward_branch_quota = 1000; - -static Error ATTRIBUTE_MUST_USE resolve_struct_type(CodeGen *g, ZigType *struct_type); - -static Error ATTRIBUTE_MUST_USE resolve_struct_zero_bits(CodeGen *g, ZigType *struct_type); -static Error ATTRIBUTE_MUST_USE resolve_struct_alignment(CodeGen *g, ZigType *struct_type); -static Error ATTRIBUTE_MUST_USE resolve_enum_zero_bits(CodeGen *g, ZigType *enum_type); -static Error ATTRIBUTE_MUST_USE resolve_union_zero_bits(CodeGen *g, ZigType *union_type); -static Error ATTRIBUTE_MUST_USE resolve_union_alignment(CodeGen *g, ZigType *union_type); -static void analyze_fn_body(CodeGen *g, ZigFn *fn_table_entry); -static void resolve_llvm_types(CodeGen *g, ZigType *type, ResolveStatus wanted_resolve_status); -static void preview_use_decl(CodeGen *g, TldUsingNamespace *using_namespace, ScopeDecls *dest_decls_scope); -static void resolve_use_decl(CodeGen *g, TldUsingNamespace *tld_using_namespace, ScopeDecls *dest_decls_scope); -static void analyze_fn_async(CodeGen *g, ZigFn *fn, bool resolve_frame); - -// nullptr means not analyzed yet; this one means currently being analyzed -static const AstNode *inferred_async_checking = reinterpret_cast(0x1); -// this one means analyzed and it's not async -static const AstNode *inferred_async_none = reinterpret_cast(0x2); - -static bool is_top_level_struct(ZigType *import) { - return import->id == ZigTypeIdStruct && import->data.structure.root_struct != nullptr; -} - -static ErrorMsg *add_error_note_token(CodeGen *g, ErrorMsg *parent_msg, ZigType *owner, - TokenIndex token, Buf *msg) -{ - assert(is_top_level_struct(owner)); - RootStruct *root_struct = owner->data.structure.root_struct; - uint32_t byte_offset = root_struct->token_locs[token].offset; - ErrorMsg *err = err_msg_create_with_offset(root_struct->path, byte_offset, - buf_ptr(root_struct->source_code), msg); - - err_msg_add_note(parent_msg, err); - return err; -} - -ErrorMsg *add_token_error_offset(CodeGen *g, ZigType *owner, TokenIndex token, Buf *msg, - uint32_t bad_index) -{ - assert(is_top_level_struct(owner)); - RootStruct *root_struct = owner->data.structure.root_struct; - uint32_t byte_offset = root_struct->token_locs[token].offset + bad_index; - ErrorMsg *err = err_msg_create_with_offset(root_struct->path, byte_offset, - buf_ptr(root_struct->source_code), msg); - - g->errors.append(err); - g->trace_err = err; - return err; -} - -ErrorMsg *add_token_error(CodeGen *g, ZigType *owner, TokenIndex token, Buf *msg) { - return add_token_error_offset(g, owner, token, msg, 0); -} - -ErrorMsg *add_node_error(CodeGen *g, AstNode *node, Buf *msg) { - return add_token_error(g, node->owner, node->main_token, msg); -} - -ErrorMsg *add_error_note(CodeGen *g, ErrorMsg *parent_msg, const AstNode *node, Buf *msg) { - return add_error_note_token(g, parent_msg, node->owner, node->main_token, msg); -} - -ZigType *new_type_table_entry(ZigTypeId id) { - ZigType *entry = heap::c_allocator.create(); - entry->id = id; - return entry; -} - -static ScopeDecls **get_container_scope_ptr(ZigType *type_entry) { - switch (type_entry->id) { - case ZigTypeIdStruct: - return &type_entry->data.structure.decls_scope; - case ZigTypeIdEnum: - return &type_entry->data.enumeration.decls_scope; - case ZigTypeIdUnion: - return &type_entry->data.unionation.decls_scope; - case ZigTypeIdOpaque: - return &type_entry->data.opaque.decls_scope; - default: - zig_unreachable(); - } -} - -static ScopeExpr *find_expr_scope(Scope *scope) { - for (;;) { - switch (scope->id) { - case ScopeIdExpr: - return reinterpret_cast(scope); - case ScopeIdDefer: - case ScopeIdDeferExpr: - case ScopeIdDecls: - case ScopeIdFnDef: - case ScopeIdCompTime: - case ScopeIdNoSuspend: - case ScopeIdVarDecl: - case ScopeIdCImport: - case ScopeIdSuspend: - case ScopeIdTypeOf: - case ScopeIdBlock: - return nullptr; - case ScopeIdLoop: - case ScopeIdRuntime: - scope = scope->parent; - continue; - } - } -} - -static void update_progress_display(CodeGen *g) { - stage2_progress_update_node(g->sub_progress_node, - g->resolve_queue_index + g->fn_defs_index, - g->resolve_queue.length + g->fn_defs.length); -} - -ScopeDecls *get_container_scope(ZigType *type_entry) { - return *get_container_scope_ptr(type_entry); -} - -void init_scope(CodeGen *g, Scope *dest, ScopeId id, AstNode *source_node, Scope *parent) { - dest->codegen = g; - dest->id = id; - dest->source_node = source_node; - dest->parent = parent; -} - -ScopeDecls *create_decls_scope(CodeGen *g, AstNode *node, Scope *parent, ZigType *container_type, - ZigType *import, Buf *bare_name) -{ - ScopeDecls *scope = heap::c_allocator.create(); - init_scope(g, &scope->base, ScopeIdDecls, node, parent); - scope->decl_table.init(4); - scope->container_type = container_type; - scope->import = import; - scope->bare_name = bare_name; - return scope; -} - -ScopeBlock *create_block_scope(CodeGen *g, AstNode *node, Scope *parent) { - assert(node->type == NodeTypeBlock); - ScopeBlock *scope = heap::c_allocator.create(); - init_scope(g, &scope->base, ScopeIdBlock, node, parent); - scope->name = node->data.block.name; - return scope; -} - -ScopeDefer *create_defer_scope(CodeGen *g, AstNode *node, Scope *parent) { - assert(node->type == NodeTypeDefer); - ScopeDefer *scope = heap::c_allocator.create(); - init_scope(g, &scope->base, ScopeIdDefer, node, parent); - return scope; -} - -ScopeDeferExpr *create_defer_expr_scope(CodeGen *g, AstNode *node, Scope *parent) { - assert(node->type == NodeTypeDefer); - ScopeDeferExpr *scope = heap::c_allocator.create(); - init_scope(g, &scope->base, ScopeIdDeferExpr, node, parent); - return scope; -} - -Scope *create_var_scope(CodeGen *g, AstNode *node, Scope *parent, ZigVar *var) { - ScopeVarDecl *scope = heap::c_allocator.create(); - init_scope(g, &scope->base, ScopeIdVarDecl, node, parent); - scope->var = var; - return &scope->base; -} - -ScopeCImport *create_cimport_scope(CodeGen *g, AstNode *node, Scope *parent) { - assert(node->type == NodeTypeFnCallExpr); - ScopeCImport *scope = heap::c_allocator.create(); - init_scope(g, &scope->base, ScopeIdCImport, node, parent); - buf_resize(&scope->buf, 0); - return scope; -} - -ScopeLoop *create_loop_scope(CodeGen *g, AstNode *node, Scope *parent) { - ScopeLoop *scope = heap::c_allocator.create(); - init_scope(g, &scope->base, ScopeIdLoop, node, parent); - if (node->type == NodeTypeWhileExpr) { - scope->name = node->data.while_expr.name; - } else if (node->type == NodeTypeForExpr) { - scope->name = node->data.for_expr.name; - } else { - zig_unreachable(); - } - return scope; -} - -Scope *create_runtime_scope(CodeGen *g, AstNode *node, Scope *parent, Stage1ZirInst *is_comptime) { - ScopeRuntime *scope = heap::c_allocator.create(); - scope->is_comptime = is_comptime; - init_scope(g, &scope->base, ScopeIdRuntime, node, parent); - return &scope->base; -} - -ScopeSuspend *create_suspend_scope(CodeGen *g, AstNode *node, Scope *parent) { - assert(node->type == NodeTypeSuspend); - ScopeSuspend *scope = heap::c_allocator.create(); - init_scope(g, &scope->base, ScopeIdSuspend, node, parent); - return scope; -} - -ScopeFnDef *create_fndef_scope(CodeGen *g, AstNode *node, Scope *parent, ZigFn *fn_entry) { - ScopeFnDef *scope = heap::c_allocator.create(); - init_scope(g, &scope->base, ScopeIdFnDef, node, parent); - scope->fn_entry = fn_entry; - return scope; -} - -Scope *create_comptime_scope(CodeGen *g, AstNode *node, Scope *parent) { - ScopeCompTime *scope = heap::c_allocator.create(); - init_scope(g, &scope->base, ScopeIdCompTime, node, parent); - return &scope->base; -} - -Scope *create_nosuspend_scope(CodeGen *g, AstNode *node, Scope *parent) { - ScopeNoSuspend *scope = heap::c_allocator.create(); - init_scope(g, &scope->base, ScopeIdNoSuspend, node, parent); - return &scope->base; -} - -Scope *create_typeof_scope(CodeGen *g, AstNode *node, Scope *parent) { - ScopeTypeOf *scope = heap::c_allocator.create(); - init_scope(g, &scope->base, ScopeIdTypeOf, node, parent); - return &scope->base; -} - -ScopeExpr *create_expr_scope(CodeGen *g, AstNode *node, Scope *parent) { - ScopeExpr *scope = heap::c_allocator.create(); - init_scope(g, &scope->base, ScopeIdExpr, node, parent); - ScopeExpr *parent_expr = find_expr_scope(parent); - if (parent_expr != nullptr) { - size_t new_len = parent_expr->children_len + 1; - parent_expr->children_ptr = heap::c_allocator.reallocate_nonzero( - parent_expr->children_ptr, parent_expr->children_len, new_len); - parent_expr->children_ptr[parent_expr->children_len] = scope; - parent_expr->children_len = new_len; - } - return scope; -} - -ZigType *get_scope_import(Scope *scope) { - while (scope) { - if (scope->id == ScopeIdDecls) { - ScopeDecls *decls_scope = (ScopeDecls *)scope; - assert(is_top_level_struct(decls_scope->import)); - return decls_scope->import; - } - scope = scope->parent; - } - zig_unreachable(); -} - -ScopeTypeOf *get_scope_typeof(Scope *scope) { - while (scope) { - switch (scope->id) { - case ScopeIdTypeOf: - return reinterpret_cast(scope); - case ScopeIdFnDef: - case ScopeIdDecls: - return nullptr; - default: - scope = scope->parent; - continue; - } - } - zig_unreachable(); -} - -static ZigType *new_container_type_entry(CodeGen *g, ZigTypeId id, AstNode *source_node, Scope *parent_scope, - Buf *bare_name) -{ - ZigType *entry = new_type_table_entry(id); - *get_container_scope_ptr(entry) = create_decls_scope(g, source_node, parent_scope, entry, - get_scope_import(parent_scope), bare_name); - return entry; -} - -static uint8_t bits_needed_for_unsigned(uint64_t x) { - if (x == 0) { - return 0; - } - uint8_t base = log2_u64(x); - uint64_t upper = (((uint64_t)1) << base) - 1; - return (upper >= x) ? base : (base + 1); -} - -AstNode *type_decl_node(ZigType *type_entry) { - switch (type_entry->id) { - case ZigTypeIdInvalid: - zig_unreachable(); - case ZigTypeIdStruct: - return type_entry->data.structure.decl_node; - case ZigTypeIdEnum: - return type_entry->data.enumeration.decl_node; - case ZigTypeIdUnion: - return type_entry->data.unionation.decl_node; - case ZigTypeIdFnFrame: - return type_entry->data.frame.fn->proto_node; - case ZigTypeIdOpaque: - case ZigTypeIdMetaType: - case ZigTypeIdVoid: - case ZigTypeIdBool: - case ZigTypeIdUnreachable: - case ZigTypeIdInt: - case ZigTypeIdFloat: - case ZigTypeIdPointer: - case ZigTypeIdArray: - case ZigTypeIdComptimeFloat: - case ZigTypeIdComptimeInt: - case ZigTypeIdEnumLiteral: - case ZigTypeIdUndefined: - case ZigTypeIdNull: - case ZigTypeIdOptional: - case ZigTypeIdErrorUnion: - case ZigTypeIdErrorSet: - case ZigTypeIdFn: - case ZigTypeIdBoundFn: - case ZigTypeIdVector: - case ZigTypeIdAnyFrame: - return nullptr; - } - zig_unreachable(); -} - -bool type_is_resolved(ZigType *type_entry, ResolveStatus status) { - switch (type_entry->id) { - case ZigTypeIdInvalid: - zig_unreachable(); - case ZigTypeIdStruct: - return type_entry->data.structure.resolve_status >= status; - case ZigTypeIdUnion: - return type_entry->data.unionation.resolve_status >= status; - case ZigTypeIdEnum: - return type_entry->data.enumeration.resolve_status >= status; - case ZigTypeIdFnFrame: - switch (status) { - case ResolveStatusInvalid: - zig_unreachable(); - case ResolveStatusBeingInferred: - zig_unreachable(); - case ResolveStatusUnstarted: - case ResolveStatusZeroBitsKnown: - return true; - case ResolveStatusAlignmentKnown: - case ResolveStatusSizeKnown: - return type_entry->data.frame.locals_struct != nullptr; - case ResolveStatusLLVMFwdDecl: - case ResolveStatusLLVMFull: - return type_entry->llvm_type != nullptr; - } - zig_unreachable(); - case ZigTypeIdOpaque: - return status < ResolveStatusSizeKnown; - case ZigTypeIdPointer: - switch (status) { - case ResolveStatusInvalid: - zig_unreachable(); - case ResolveStatusBeingInferred: - zig_unreachable(); - case ResolveStatusUnstarted: - return true; - case ResolveStatusZeroBitsKnown: - case ResolveStatusAlignmentKnown: - case ResolveStatusSizeKnown: - return type_entry->abi_size != SIZE_MAX; - case ResolveStatusLLVMFwdDecl: - case ResolveStatusLLVMFull: - return type_entry->llvm_type != nullptr; - } - zig_unreachable(); - case ZigTypeIdMetaType: - case ZigTypeIdVoid: - case ZigTypeIdBool: - case ZigTypeIdUnreachable: - case ZigTypeIdInt: - case ZigTypeIdFloat: - case ZigTypeIdArray: - case ZigTypeIdComptimeFloat: - case ZigTypeIdComptimeInt: - case ZigTypeIdEnumLiteral: - case ZigTypeIdUndefined: - case ZigTypeIdNull: - case ZigTypeIdOptional: - case ZigTypeIdErrorUnion: - case ZigTypeIdErrorSet: - case ZigTypeIdFn: - case ZigTypeIdBoundFn: - case ZigTypeIdVector: - case ZigTypeIdAnyFrame: - return true; - } - zig_unreachable(); -} - -bool type_is_complete(ZigType *type_entry) { - return type_is_resolved(type_entry, ResolveStatusSizeKnown); -} - -uint64_t type_size(CodeGen *g, ZigType *type_entry) { - assert(type_is_resolved(type_entry, ResolveStatusSizeKnown)); - return type_entry->abi_size; -} - -uint64_t type_size_bits(CodeGen *g, ZigType *type_entry) { - assert(type_is_resolved(type_entry, ResolveStatusSizeKnown)); - return type_entry->size_in_bits; -} - -uint32_t get_abi_alignment(CodeGen *g, ZigType *type_entry) { - assert(type_is_resolved(type_entry, ResolveStatusAlignmentKnown)); - return type_entry->abi_align; -} - -static bool is_slice(ZigType *type) { - return type->id == ZigTypeIdStruct && type->data.structure.special == StructSpecialSlice; -} - -ZigType *get_smallest_unsigned_int_type(CodeGen *g, uint64_t x) { - return get_int_type(g, false, bits_needed_for_unsigned(x)); -} - -ZigType *get_any_frame_type(CodeGen *g, ZigType *result_type) { - if (result_type != nullptr && result_type->any_frame_parent != nullptr) { - return result_type->any_frame_parent; - } else if (result_type == nullptr && g->builtin_types.entry_any_frame != nullptr) { - return g->builtin_types.entry_any_frame; - } - - ZigType *entry = new_type_table_entry(ZigTypeIdAnyFrame); - entry->abi_size = g->builtin_types.entry_usize->abi_size; - entry->size_in_bits = g->builtin_types.entry_usize->size_in_bits; - entry->abi_align = g->builtin_types.entry_usize->abi_align; - entry->data.any_frame.result_type = result_type; - buf_init_from_str(&entry->name, "anyframe"); - if (result_type != nullptr) { - buf_appendf(&entry->name, "->%s", buf_ptr(&result_type->name)); - } - - if (result_type != nullptr) { - result_type->any_frame_parent = entry; - } else if (result_type == nullptr) { - g->builtin_types.entry_any_frame = entry; - } - return entry; -} - -ZigType *get_fn_frame_type(CodeGen *g, ZigFn *fn) { - if (fn->frame_type != nullptr) { - return fn->frame_type; - } - - ZigType *entry = new_type_table_entry(ZigTypeIdFnFrame); - buf_resize(&entry->name, 0); - buf_appendf(&entry->name, "@Frame(%s)", buf_ptr(&fn->symbol_name)); - - entry->data.frame.fn = fn; - - // Async function frames are always non-zero bits because they always have a resume index. - entry->abi_size = SIZE_MAX; - entry->size_in_bits = SIZE_MAX; - - fn->frame_type = entry; - return entry; -} - -static void append_ptr_type_attrs(Buf *type_name, ZigType *ptr_type) { - const char *const_str = ptr_type->data.pointer.is_const ? "const " : ""; - const char *volatile_str = ptr_type->data.pointer.is_volatile ? "volatile " : ""; - const char *allow_zero_str; - if (ptr_type->data.pointer.ptr_len == PtrLenC) { - assert(ptr_type->data.pointer.allow_zero); - allow_zero_str = ""; - } else { - allow_zero_str = ptr_type->data.pointer.allow_zero ? "allowzero " : ""; - } - if (ptr_type->data.pointer.explicit_alignment != 0 || ptr_type->data.pointer.host_int_bytes != 0 || - ptr_type->data.pointer.vector_index != VECTOR_INDEX_NONE) - { - buf_appendf(type_name, "align("); - if (ptr_type->data.pointer.explicit_alignment != 0) { - buf_appendf(type_name, "%" PRIu32, ptr_type->data.pointer.explicit_alignment); - } - if (ptr_type->data.pointer.host_int_bytes != 0) { - buf_appendf(type_name, ":%" PRIu32 ":%" PRIu32, ptr_type->data.pointer.bit_offset_in_host, ptr_type->data.pointer.host_int_bytes); - } - if (ptr_type->data.pointer.vector_index == VECTOR_INDEX_RUNTIME) { - buf_appendf(type_name, ":?"); - } else if (ptr_type->data.pointer.vector_index != VECTOR_INDEX_NONE) { - buf_appendf(type_name, ":%" PRIu32, ptr_type->data.pointer.vector_index); - } - buf_appendf(type_name, ") "); - } - buf_appendf(type_name, "%s%s%s", const_str, volatile_str, allow_zero_str); - if (ptr_type->data.pointer.inferred_struct_field != nullptr) { - buf_appendf(type_name, " field '%s' of %s)", - buf_ptr(ptr_type->data.pointer.inferred_struct_field->field_name), - buf_ptr(&ptr_type->data.pointer.inferred_struct_field->inferred_struct_type->name)); - } else { - buf_appendf(type_name, "%s", buf_ptr(&ptr_type->data.pointer.child_type->name)); - } -} - -ZigType *get_pointer_to_type_extra2(CodeGen *g, ZigType *child_type, bool is_const, - bool is_volatile, PtrLen ptr_len, uint32_t byte_alignment, - uint32_t bit_offset_in_host, uint32_t host_int_bytes, bool allow_zero, - uint32_t vector_index, InferredStructField *inferred_struct_field, ZigValue *sentinel) -{ - assert(ptr_len != PtrLenC || allow_zero); - assert(!type_is_invalid(child_type)); - assert(ptr_len == PtrLenSingle || child_type->id != ZigTypeIdOpaque); - - if (byte_alignment != 0) { - uint32_t abi_alignment = get_abi_alignment(g, child_type); - if (byte_alignment == abi_alignment) - byte_alignment = 0; - } - - if (host_int_bytes != 0 && vector_index == VECTOR_INDEX_NONE) { - uint32_t child_type_bits = type_size_bits(g, child_type); - if (host_int_bytes * 8 == child_type_bits) { - assert(bit_offset_in_host == 0); - host_int_bytes = 0; - } - } - - TypeId type_id = {}; - ZigType **parent_pointer = nullptr; - if (host_int_bytes != 0 || is_volatile || byte_alignment != 0 || ptr_len != PtrLenSingle || - allow_zero || vector_index != VECTOR_INDEX_NONE || inferred_struct_field != nullptr || - sentinel != nullptr) - { - type_id.id = ZigTypeIdPointer; - type_id.data.pointer.codegen = g; - type_id.data.pointer.child_type = child_type; - type_id.data.pointer.is_const = is_const; - type_id.data.pointer.is_volatile = is_volatile; - type_id.data.pointer.alignment = byte_alignment; - type_id.data.pointer.bit_offset_in_host = bit_offset_in_host; - type_id.data.pointer.host_int_bytes = host_int_bytes; - type_id.data.pointer.ptr_len = ptr_len; - type_id.data.pointer.allow_zero = allow_zero; - type_id.data.pointer.vector_index = vector_index; - type_id.data.pointer.inferred_struct_field = inferred_struct_field; - type_id.data.pointer.sentinel = sentinel; - - auto existing_entry = g->type_table.maybe_get(type_id); - if (existing_entry) - return existing_entry->value; - } else { - assert(bit_offset_in_host == 0); - parent_pointer = &child_type->pointer_parent[(is_const ? 1 : 0)]; - if (*parent_pointer) { - assert((*parent_pointer)->data.pointer.explicit_alignment == 0); - return *parent_pointer; - } - } - - ZigType *entry = new_type_table_entry(ZigTypeIdPointer); - - buf_resize(&entry->name, 0); - if (inferred_struct_field != nullptr) { - buf_appendf(&entry->name, "("); - } - switch (ptr_len) { - case PtrLenSingle: - assert(sentinel == nullptr); - buf_appendf(&entry->name, "*"); - break; - case PtrLenUnknown: - buf_appendf(&entry->name, "[*"); - break; - case PtrLenC: - assert(sentinel == nullptr); - buf_appendf(&entry->name, "[*c]"); - break; - } - if (sentinel != nullptr) { - buf_appendf(&entry->name, ":"); - render_const_value(g, &entry->name, sentinel); - } - switch (ptr_len) { - case PtrLenSingle: - case PtrLenC: - break; - case PtrLenUnknown: - buf_appendf(&entry->name, "]"); - break; - } - - if (inferred_struct_field != nullptr) { - entry->abi_size = SIZE_MAX; - entry->size_in_bits = SIZE_MAX; - entry->abi_align = UINT32_MAX; - } else if (type_is_resolved(child_type, ResolveStatusZeroBitsKnown)) { - if (type_has_bits(g, child_type)) { - entry->abi_size = g->builtin_types.entry_usize->abi_size; - entry->size_in_bits = g->builtin_types.entry_usize->size_in_bits; - entry->abi_align = g->builtin_types.entry_usize->abi_align; - } else { - assert(byte_alignment == 0); - entry->abi_size = 0; - entry->size_in_bits = 0; - entry->abi_align = 0; - } - } else { - entry->abi_size = SIZE_MAX; - entry->size_in_bits = SIZE_MAX; - entry->abi_align = UINT32_MAX; - } - - entry->data.pointer.ptr_len = ptr_len; - entry->data.pointer.child_type = child_type; - entry->data.pointer.is_const = is_const; - entry->data.pointer.is_volatile = is_volatile; - entry->data.pointer.explicit_alignment = byte_alignment; - entry->data.pointer.bit_offset_in_host = bit_offset_in_host; - entry->data.pointer.host_int_bytes = host_int_bytes; - entry->data.pointer.allow_zero = allow_zero; - entry->data.pointer.vector_index = vector_index; - entry->data.pointer.inferred_struct_field = inferred_struct_field; - entry->data.pointer.sentinel = sentinel; - - append_ptr_type_attrs(&entry->name, entry); - - if (parent_pointer) { - *parent_pointer = entry; - } else { - g->type_table.put(type_id, entry); - } - return entry; -} - -ZigType *get_pointer_to_type_extra(CodeGen *g, ZigType *child_type, bool is_const, - bool is_volatile, PtrLen ptr_len, uint32_t byte_alignment, - uint32_t bit_offset_in_host, uint32_t host_int_bytes, bool allow_zero) -{ - return get_pointer_to_type_extra2(g, child_type, is_const, is_volatile, ptr_len, - byte_alignment, bit_offset_in_host, host_int_bytes, allow_zero, VECTOR_INDEX_NONE, nullptr, nullptr); -} - -ZigType *get_pointer_to_type(CodeGen *g, ZigType *child_type, bool is_const) { - return get_pointer_to_type_extra2(g, child_type, is_const, false, PtrLenSingle, 0, 0, 0, false, - VECTOR_INDEX_NONE, nullptr, nullptr); -} - -ZigType *get_optional_type(CodeGen *g, ZigType *child_type) { - ZigType *result = get_optional_type2(g, child_type); - if (result == nullptr) { - codegen_report_errors_and_exit(g); - } - return result; -} - -ZigType *get_optional_type2(CodeGen *g, ZigType *child_type) { - if (child_type->optional_parent != nullptr) { - return child_type->optional_parent; - } - - Error err; - if ((err = type_resolve(g, child_type, ResolveStatusSizeKnown))) { - return nullptr; - } - - ZigType *entry = new_type_table_entry(ZigTypeIdOptional); - - buf_resize(&entry->name, 0); - buf_appendf(&entry->name, "?%s", buf_ptr(&child_type->name)); - - if (!type_has_bits(g, child_type)) { - entry->size_in_bits = g->builtin_types.entry_bool->size_in_bits; - entry->abi_size = g->builtin_types.entry_bool->abi_size; - entry->abi_align = g->builtin_types.entry_bool->abi_align; - } else if (type_is_nonnull_ptr(g, child_type) || child_type->id == ZigTypeIdErrorSet) { - // This is an optimization but also is necessary for calling C - // functions where all pointers are optional pointers. - // Function types are technically pointers. - entry->size_in_bits = child_type->size_in_bits; - entry->abi_size = child_type->abi_size; - entry->abi_align = child_type->abi_align; - } else { - // This value only matters if the type is legal in a packed struct, which is not - // true for optional types which did not fit the above 2 categories (zero bit child type, - // or nonnull ptr child type, or error set child type). - entry->size_in_bits = child_type->size_in_bits + 1; - - // We're going to make a struct with the child type as the first field, - // and a bool as the second. Since the child type's abi alignment is guaranteed - // to be >= the bool's abi size (1 byte), the added size is exactly equal to the - // child type's ABI alignment. - assert(child_type->abi_align >= g->builtin_types.entry_bool->abi_size); - entry->abi_align = child_type->abi_align; - entry->abi_size = child_type->abi_size + child_type->abi_align; - } - - entry->data.maybe.child_type = child_type; - entry->data.maybe.resolve_status = ResolveStatusSizeKnown; - - child_type->optional_parent = entry; - return entry; -} - -static size_t align_forward(size_t addr, size_t alignment) { - return (addr + alignment - 1) & ~(alignment - 1); -} - -static size_t next_field_offset(size_t offset, size_t align_from_zero, size_t field_size, size_t next_field_align) { - // Convert offset to a pretend address which has the specified alignment. - size_t addr = offset + align_from_zero; - // March the address forward to respect the field alignment. - size_t aligned_addr = align_forward(addr + field_size, next_field_align); - // Convert back from pretend address to offset. - return aligned_addr - align_from_zero; -} - -ZigType *get_error_union_type(CodeGen *g, ZigType *err_set_type, ZigType *payload_type) { - assert(err_set_type->id == ZigTypeIdErrorSet); - assert(!type_is_invalid(payload_type)); - - TypeId type_id = {}; - type_id.id = ZigTypeIdErrorUnion; - type_id.data.error_union.err_set_type = err_set_type; - type_id.data.error_union.payload_type = payload_type; - - auto existing_entry = g->type_table.maybe_get(type_id); - if (existing_entry) { - return existing_entry->value; - } - - Error err; - if ((err = type_resolve(g, err_set_type, ResolveStatusSizeKnown))) - return g->builtin_types.entry_invalid; - - if ((err = type_resolve(g, payload_type, ResolveStatusSizeKnown))) - return g->builtin_types.entry_invalid; - - ZigType *entry = new_type_table_entry(ZigTypeIdErrorUnion); - - buf_resize(&entry->name, 0); - buf_appendf(&entry->name, "%s!%s", buf_ptr(&err_set_type->name), buf_ptr(&payload_type->name)); - - entry->data.error_union.err_set_type = err_set_type; - entry->data.error_union.payload_type = payload_type; - - if (!type_has_bits(g, payload_type)) { - if (type_has_bits(g, err_set_type)) { - entry->size_in_bits = err_set_type->size_in_bits; - entry->abi_size = err_set_type->abi_size; - entry->abi_align = err_set_type->abi_align; - } else { - entry->size_in_bits = 0; - entry->abi_size = 0; - entry->abi_align = 0; - } - } else if (!type_has_bits(g, err_set_type)) { - entry->size_in_bits = payload_type->size_in_bits; - entry->abi_size = payload_type->abi_size; - entry->abi_align = payload_type->abi_align; - } else { - entry->abi_align = max(err_set_type->abi_align, payload_type->abi_align); - size_t field_sizes[2]; - size_t field_aligns[2]; - field_sizes[err_union_err_index] = err_set_type->abi_size; - field_aligns[err_union_err_index] = err_set_type->abi_align; - field_sizes[err_union_payload_index] = payload_type->abi_size; - field_aligns[err_union_payload_index] = payload_type->abi_align; - size_t field2_offset = next_field_offset(0, entry->abi_align, field_sizes[0], field_aligns[1]); - entry->abi_size = next_field_offset(field2_offset, entry->abi_align, field_sizes[1], entry->abi_align); - entry->size_in_bits = entry->abi_size * 8; - entry->data.error_union.pad_bytes = entry->abi_size - (field2_offset + field_sizes[1]); - } - - g->type_table.put(type_id, entry); - return entry; -} - -ZigType *get_array_type(CodeGen *g, ZigType *child_type, uint64_t array_size, ZigValue *sentinel) { - Error err; - - TypeId type_id = {}; - type_id.id = ZigTypeIdArray; - type_id.data.array.codegen = g; - type_id.data.array.child_type = child_type; - type_id.data.array.size = array_size; - type_id.data.array.sentinel = sentinel; - auto existing_entry = g->type_table.maybe_get(type_id); - if (existing_entry) { - return existing_entry->value; - } - - size_t full_array_size = array_size + ((sentinel != nullptr) ? 1 : 0); - - if (full_array_size != 0 && (err = type_resolve(g, child_type, ResolveStatusSizeKnown))) { - codegen_report_errors_and_exit(g); - } - - ZigType *entry = new_type_table_entry(ZigTypeIdArray); - - buf_resize(&entry->name, 0); - buf_appendf(&entry->name, "[%" ZIG_PRI_u64, array_size); - if (sentinel != nullptr) { - buf_appendf(&entry->name, ":"); - render_const_value(g, &entry->name, sentinel); - } - buf_appendf(&entry->name, "]%s", buf_ptr(&child_type->name)); - - entry->size_in_bits = child_type->size_in_bits * full_array_size; - entry->abi_align = (full_array_size == 0) ? 0 : child_type->abi_align; - entry->abi_size = child_type->abi_size * full_array_size; - - entry->data.array.child_type = child_type; - entry->data.array.len = array_size; - entry->data.array.sentinel = sentinel; - - g->type_table.put(type_id, entry); - return entry; -} - -ZigType *get_slice_type(CodeGen *g, ZigType *ptr_type) { - Error err; - assert(ptr_type->id == ZigTypeIdPointer); - assert(ptr_type->data.pointer.ptr_len == PtrLenUnknown); - - ZigType **parent_pointer = &ptr_type->data.pointer.slice_parent; - if (*parent_pointer) { - return *parent_pointer; - } - - // We use the pointer type's abi size below, so we have to resolve it now. - if ((err = type_resolve(g, ptr_type, ResolveStatusSizeKnown))) { - codegen_report_errors_and_exit(g); - } - - ZigType *entry = new_type_table_entry(ZigTypeIdStruct); - - buf_resize(&entry->name, 0); - buf_appendf(&entry->name, "["); - if (ptr_type->data.pointer.sentinel != nullptr) { - buf_appendf(&entry->name, ":"); - render_const_value(g, &entry->name, ptr_type->data.pointer.sentinel); - } - buf_appendf(&entry->name, "]"); - append_ptr_type_attrs(&entry->name, ptr_type); - - unsigned element_count = 2; - Buf *ptr_field_name = buf_create_from_str("ptr"); - Buf *len_field_name = buf_create_from_str("len"); - - entry->data.structure.resolve_status = ResolveStatusSizeKnown; - entry->data.structure.layout = ContainerLayoutAuto; - entry->data.structure.special = StructSpecialSlice; - entry->data.structure.src_field_count = element_count; - entry->data.structure.gen_field_count = element_count; - entry->data.structure.fields = alloc_type_struct_fields(element_count); - entry->data.structure.fields_by_name.init(element_count); - entry->data.structure.fields[slice_ptr_index]->name = ptr_field_name; - entry->data.structure.fields[slice_ptr_index]->type_entry = ptr_type; - entry->data.structure.fields[slice_ptr_index]->src_index = slice_ptr_index; - entry->data.structure.fields[slice_ptr_index]->gen_index = 0; - entry->data.structure.fields[slice_ptr_index]->offset = 0; - entry->data.structure.fields[slice_len_index]->name = len_field_name; - entry->data.structure.fields[slice_len_index]->type_entry = g->builtin_types.entry_usize; - entry->data.structure.fields[slice_len_index]->src_index = slice_len_index; - entry->data.structure.fields[slice_len_index]->gen_index = 1; - entry->data.structure.fields[slice_len_index]->offset = ptr_type->abi_size; - - entry->data.structure.fields_by_name.put(ptr_field_name, entry->data.structure.fields[slice_ptr_index]); - entry->data.structure.fields_by_name.put(len_field_name, entry->data.structure.fields[slice_len_index]); - - switch (type_requires_comptime(g, ptr_type)) { - case ReqCompTimeInvalid: - zig_unreachable(); - case ReqCompTimeNo: - break; - case ReqCompTimeYes: - entry->data.structure.requires_comptime = true; - } - - if (!type_has_bits(g, ptr_type)) { - entry->data.structure.gen_field_count = 1; - entry->data.structure.fields[slice_ptr_index]->gen_index = SIZE_MAX; - entry->data.structure.fields[slice_len_index]->gen_index = 0; - } - - if (type_has_bits(g, ptr_type)) { - entry->size_in_bits = ptr_type->size_in_bits + g->builtin_types.entry_usize->size_in_bits; - entry->abi_size = ptr_type->abi_size + g->builtin_types.entry_usize->abi_size; - entry->abi_align = ptr_type->abi_align; - } else { - entry->size_in_bits = g->builtin_types.entry_usize->size_in_bits; - entry->abi_size = g->builtin_types.entry_usize->abi_size; - entry->abi_align = g->builtin_types.entry_usize->abi_align; - } - - *parent_pointer = entry; - return entry; -} - -static uint32_t node_line_onebased(AstNode *node) { - RootStruct *root_struct = node->owner->data.structure.root_struct; - assert(node->main_token < root_struct->token_count); - return root_struct->token_locs[node->main_token].line + 1; -} - -static uint32_t node_column_onebased(AstNode *node) { - RootStruct *root_struct = node->owner->data.structure.root_struct; - assert(node->main_token < root_struct->token_count); - return root_struct->token_locs[node->main_token].column + 1; -} - -ZigType *get_opaque_type(CodeGen *g, Scope *scope, AstNode *source_node, const char *full_name, - Buf *bare_name) -{ - ZigType *entry = new_type_table_entry(ZigTypeIdOpaque); - - buf_init_from_str(&entry->name, full_name); - - ZigType *import = scope ? get_scope_import(scope) : nullptr; - unsigned line = source_node ? node_line_onebased(source_node) : 0; - - // Note: duplicated in get_partial_container_type - entry->llvm_type = LLVMInt8Type(); - entry->llvm_di_type = ZigLLVMCreateDebugForwardDeclType(g->dbuilder, - ZigLLVMTag_DW_structure_type(), full_name, - import ? ZigLLVMFileToScope(import->data.structure.root_struct->di_file) : nullptr, - import ? import->data.structure.root_struct->di_file : nullptr, - line); - entry->data.opaque.decl_node = source_node; - entry->data.opaque.bare_name = bare_name; - entry->data.opaque.decls_scope = create_decls_scope( - g, source_node, scope, entry, import, &entry->name); - - // The actual size is unknown, but the value must not be 0 because that - // is how type_has_bits is determined. - entry->abi_size = SIZE_MAX; - entry->size_in_bits = SIZE_MAX; - entry->abi_align = 1; - - return entry; -} - -ZigType *get_bound_fn_type(CodeGen *g, ZigFn *fn_entry) { - ZigType *fn_type = fn_entry->type_entry; - assert(fn_type->id == ZigTypeIdFn); - if (fn_type->data.fn.bound_fn_parent) - return fn_type->data.fn.bound_fn_parent; - - ZigType *bound_fn_type = new_type_table_entry(ZigTypeIdBoundFn); - bound_fn_type->data.bound_fn.fn_type = fn_type; - - buf_resize(&bound_fn_type->name, 0); - buf_appendf(&bound_fn_type->name, "(bound %s)", buf_ptr(&fn_type->name)); - - fn_type->data.fn.bound_fn_parent = bound_fn_type; - return bound_fn_type; -} - -const char *calling_convention_name(CallingConvention cc) { - switch (cc) { - case CallingConventionUnspecified: return "Unspecified"; - case CallingConventionC: return "C"; - case CallingConventionNaked: return "Naked"; - case CallingConventionAsync: return "Async"; - case CallingConventionInterrupt: return "Interrupt"; - case CallingConventionSignal: return "Signal"; - case CallingConventionStdcall: return "Stdcall"; - case CallingConventionFastcall: return "Fastcall"; - case CallingConventionVectorcall: return "Vectorcall"; - case CallingConventionThiscall: return "Thiscall"; - case CallingConventionAPCS: return "APCS"; - case CallingConventionAAPCS: return "AAPCS"; - case CallingConventionAAPCSVFP: return "AAPCSVFP"; - case CallingConventionInline: return "Inline"; - case CallingConventionSysV: return "SysV"; - case CallingConventionWin64: return "Win64"; - case CallingConventionPtxKernel: return "PtxKernel"; - case CallingConventionAmdgpuKernel: return "AmdgpuKernel"; - } - zig_unreachable(); -} - -bool calling_convention_allows_zig_types(CallingConvention cc) { - switch (cc) { - case CallingConventionUnspecified: - case CallingConventionAsync: - case CallingConventionInline: - case CallingConventionPtxKernel: - return true; - case CallingConventionC: - case CallingConventionNaked: - case CallingConventionInterrupt: - case CallingConventionSignal: - case CallingConventionStdcall: - case CallingConventionFastcall: - case CallingConventionVectorcall: - case CallingConventionThiscall: - case CallingConventionAPCS: - case CallingConventionAAPCS: - case CallingConventionAAPCSVFP: - case CallingConventionSysV: - case CallingConventionWin64: - case CallingConventionAmdgpuKernel: - return false; - } - zig_unreachable(); -} - -const char *address_space_name(AddressSpace as) { - switch (as) { - case AddressSpaceGeneric: return "generic"; - case AddressSpaceGS: return "gs"; - case AddressSpaceFS: return "fs"; - case AddressSpaceSS: return "ss"; - case AddressSpaceGlobal: return "global"; - case AddressSpaceConstant: return "constant"; - case AddressSpaceParam: return "param"; - case AddressSpaceShared: return "shared"; - case AddressSpaceLocal: return "local"; - } - zig_unreachable(); -} - -ZigType *get_stack_trace_type(CodeGen *g) { - if (g->stack_trace_type == nullptr) { - g->stack_trace_type = get_builtin_type(g, "StackTrace"); - assertNoError(type_resolve(g, g->stack_trace_type, ResolveStatusZeroBitsKnown)); - } - return g->stack_trace_type; -} - -bool want_first_arg_sret(CodeGen *g, FnTypeId *fn_type_id) { - if (fn_type_id->cc == CallingConventionUnspecified - || fn_type_id->cc == CallingConventionInline) { - return handle_is_ptr(g, fn_type_id->return_type); - } - if (fn_type_id->cc != CallingConventionC) { - return false; - } - if (type_is_c_abi_int_bail(g, fn_type_id->return_type)) { - return false; - } - if (g->zig_target->arch == ZigLLVM_x86 || - g->zig_target->arch == ZigLLVM_x86_64 || - target_is_arm(g->zig_target) || - target_is_riscv(g->zig_target) || - target_is_wasm(g->zig_target) || - target_is_sparc(g->zig_target) || - target_is_ppc(g->zig_target)) - { - X64CABIClass abi_class = type_c_abi_x86_64_class(g, fn_type_id->return_type); - return abi_class == X64CABIClass_MEMORY || abi_class == X64CABIClass_MEMORY_nobyval; - } else if (g->zig_target->arch == ZigLLVM_mips || g->zig_target->arch == ZigLLVM_mipsel) { - return false; - } - zig_panic("TODO implement C ABI for this architecture. See https://github.com/ziglang/zig/issues/1481"); -} - -ZigType *get_fn_type(CodeGen *g, FnTypeId *fn_type_id) { - Error err; - auto table_entry = g->fn_type_table.maybe_get(fn_type_id); - if (table_entry) { - return table_entry->value; - } - if (fn_type_id->return_type != nullptr) { - if ((err = type_resolve(g, fn_type_id->return_type, ResolveStatusSizeKnown))) - return g->builtin_types.entry_invalid; - assert(fn_type_id->return_type->id != ZigTypeIdOpaque); - } else { - zig_panic("TODO implement inferred return types https://github.com/ziglang/zig/issues/447"); - } - - ZigType *fn_type = new_type_table_entry(ZigTypeIdFn); - fn_type->data.fn.fn_type_id = *fn_type_id; - - // populate the name of the type - buf_resize(&fn_type->name, 0); - buf_appendf(&fn_type->name, "fn("); - for (size_t i = 0; i < fn_type_id->param_count; i += 1) { - FnTypeParamInfo *param_info = &fn_type_id->param_info[i]; - - ZigType *param_type = param_info->type; - const char *comma = (i == 0) ? "" : ", "; - const char *noalias_str = param_info->is_noalias ? "noalias " : ""; - buf_appendf(&fn_type->name, "%s%s%s", comma, noalias_str, buf_ptr(¶m_type->name)); - } - - if (fn_type_id->is_var_args) { - const char *comma = (fn_type_id->param_count == 0) ? "" : ", "; - buf_appendf(&fn_type->name, "%s...", comma); - } - buf_appendf(&fn_type->name, ")"); - if (fn_type_id->alignment != 0) { - buf_appendf(&fn_type->name, " align(%" PRIu32 ")", fn_type_id->alignment); - } - if (fn_type_id->cc != CallingConventionUnspecified) { - buf_appendf(&fn_type->name, " callconv(.%s)", calling_convention_name(fn_type_id->cc)); - } - buf_appendf(&fn_type->name, " %s", buf_ptr(&fn_type_id->return_type->name)); - - // The fn_type is a pointer; not to be confused with the raw function type. - fn_type->size_in_bits = g->builtin_types.entry_usize->size_in_bits; - fn_type->abi_size = g->builtin_types.entry_usize->abi_size; - fn_type->abi_align = g->builtin_types.entry_usize->abi_align; - - g->fn_type_table.put(&fn_type->data.fn.fn_type_id, fn_type); - - return fn_type; -} - -static ZigTypeId container_to_type(ContainerKind kind) { - switch (kind) { - case ContainerKindStruct: - return ZigTypeIdStruct; - case ContainerKindEnum: - return ZigTypeIdEnum; - case ContainerKindUnion: - return ZigTypeIdUnion; - case ContainerKindOpaque: - return ZigTypeIdOpaque; - } - zig_unreachable(); -} - -// This is like get_partial_container_type except it's for the implicit root struct of files. -static ZigType *get_root_container_type(CodeGen *g, const char *full_name, Buf *bare_name, - RootStruct *root_struct) -{ - ZigType *entry = new_type_table_entry(ZigTypeIdStruct); - entry->data.structure.decls_scope = create_decls_scope(g, nullptr, nullptr, entry, entry, bare_name); - entry->data.structure.root_struct = root_struct; - entry->data.structure.layout = ContainerLayoutAuto; - - if (full_name[0] == '\0') { - buf_init_from_str(&entry->name, "(root)"); - } else { - buf_init_from_str(&entry->name, full_name); - } - - return entry; -} - -ZigType *get_partial_container_type(CodeGen *g, Scope *scope, ContainerKind kind, - AstNode *decl_node, const char *full_name, Buf *bare_name, ContainerLayout layout) -{ - ZigTypeId type_id = container_to_type(kind); - ZigType *entry = new_container_type_entry(g, type_id, decl_node, scope, bare_name); - - switch (kind) { - case ContainerKindStruct: - entry->data.structure.decl_node = decl_node; - entry->data.structure.layout = layout; - break; - case ContainerKindEnum: - entry->data.enumeration.decl_node = decl_node; - entry->data.enumeration.layout = layout; - break; - case ContainerKindUnion: - entry->data.unionation.decl_node = decl_node; - entry->data.unionation.layout = layout; - break; - case ContainerKindOpaque: { - ZigType *import = scope ? get_scope_import(scope) : nullptr; - unsigned line = decl_node ? node_line_onebased(decl_node) : 0; - // Note: duplicated in get_opaque_type - entry->llvm_type = LLVMInt8Type(); - entry->llvm_di_type = ZigLLVMCreateDebugForwardDeclType(g->dbuilder, - ZigLLVMTag_DW_structure_type(), full_name, - import ? ZigLLVMFileToScope(import->data.structure.root_struct->di_file) : nullptr, - import ? import->data.structure.root_struct->di_file : nullptr, - line); - entry->data.opaque.decl_node = decl_node; - entry->abi_size = SIZE_MAX; - entry->size_in_bits = SIZE_MAX; - entry->abi_align = 1; - break; - } - } - - buf_init_from_str(&entry->name, full_name); - - return entry; -} - -ZigValue *analyze_const_value(CodeGen *g, Scope *scope, AstNode *node, ZigType *type_entry, - Buf *type_name, UndefAllowed undef) -{ - Error err; - - ZigValue *result = g->pass1_arena->create(); - ZigValue *result_ptr = g->pass1_arena->create(); - result->special = ConstValSpecialUndef; - result->type = (type_entry == nullptr) ? g->builtin_types.entry_anytype : type_entry; - result_ptr->special = ConstValSpecialStatic; - result_ptr->type = get_pointer_to_type(g, result->type, false); - result_ptr->data.x_ptr.mut = ConstPtrMutComptimeVar; - result_ptr->data.x_ptr.special = ConstPtrSpecialRef; - result_ptr->data.x_ptr.data.ref.pointee = result; - - size_t backward_branch_count = 0; - size_t backward_branch_quota = default_backward_branch_quota; - if ((err = ir_eval_const_value(g, scope, node, result_ptr, - &backward_branch_count, &backward_branch_quota, - nullptr, nullptr, node, type_name, nullptr, nullptr, undef))) - { - return g->invalid_inst_gen->value; - } - return result; -} - -Error type_val_resolve_zero_bits(CodeGen *g, ZigValue *type_val, ZigType *parent_type, - ZigValue *parent_type_val, bool *is_zero_bits) -{ - Error err; - if (type_val->special != ConstValSpecialLazy) { - assert(type_val->special == ConstValSpecialStatic); - - // Self-referencing types via pointers are allowed and have non-zero size - ZigType *ty = type_val->data.x_type; - while (ty->id == ZigTypeIdPointer && - !ty->data.pointer.resolve_loop_flag_zero_bits) - { - ty = ty->data.pointer.child_type; - } - - if ((ty->id == ZigTypeIdStruct && ty->data.structure.resolve_loop_flag_zero_bits) || - (ty->id == ZigTypeIdUnion && ty->data.unionation.resolve_loop_flag_zero_bits) || - (ty->id == ZigTypeIdPointer && ty->data.pointer.resolve_loop_flag_zero_bits)) - { - *is_zero_bits = false; - return ErrorNone; - } - - if ((err = type_resolve(g, type_val->data.x_type, ResolveStatusZeroBitsKnown))) - return err; - - *is_zero_bits = (type_val->data.x_type->abi_size == 0); - return ErrorNone; - } - switch (type_val->data.x_lazy->id) { - case LazyValueIdInvalid: - case LazyValueIdAlignOf: - case LazyValueIdSizeOf: - case LazyValueIdTypeInfoDecls: - zig_unreachable(); - case LazyValueIdPtrType: { - LazyValuePtrType *lazy_ptr_type = reinterpret_cast(type_val->data.x_lazy); - - if (parent_type_val == lazy_ptr_type->elem_type->value) { - // Does a struct which contains a pointer field to itself have bits? Yes. - *is_zero_bits = false; - return ErrorNone; - } else { - if (parent_type_val == nullptr) { - parent_type_val = type_val; - } - return type_val_resolve_zero_bits(g, lazy_ptr_type->elem_type->value, parent_type, - parent_type_val, is_zero_bits); - } - } - case LazyValueIdPtrTypeSimple: - case LazyValueIdPtrTypeSimpleConst: { - LazyValuePtrTypeSimple *lazy_ptr_type = reinterpret_cast(type_val->data.x_lazy); - - if (parent_type_val == lazy_ptr_type->elem_type->value) { - // Does a struct which contains a pointer field to itself have bits? Yes. - *is_zero_bits = false; - return ErrorNone; - } else { - if (parent_type_val == nullptr) { - parent_type_val = type_val; - } - return type_val_resolve_zero_bits(g, lazy_ptr_type->elem_type->value, parent_type, - parent_type_val, is_zero_bits); - } - } - case LazyValueIdArrayType: { - LazyValueArrayType *lazy_array_type = - reinterpret_cast(type_val->data.x_lazy); - - // The sentinel counts as an extra element - if (lazy_array_type->length == 0 && lazy_array_type->sentinel == nullptr) { - *is_zero_bits = true; - return ErrorNone; - } - - if ((err = type_val_resolve_zero_bits(g, lazy_array_type->elem_type->value, - parent_type, nullptr, is_zero_bits))) - return err; - - return ErrorNone; - } - case LazyValueIdOptType: - case LazyValueIdSliceType: - case LazyValueIdErrUnionType: - *is_zero_bits = false; - return ErrorNone; - case LazyValueIdFnType: { - LazyValueFnType *lazy_fn_type = reinterpret_cast(type_val->data.x_lazy); - *is_zero_bits = lazy_fn_type->is_generic; - return ErrorNone; - } - } - zig_unreachable(); -} - -Error type_val_resolve_is_opaque_type(CodeGen *g, ZigValue *type_val, bool *is_opaque_type) { - if (type_val->special != ConstValSpecialLazy) { - assert(type_val->special == ConstValSpecialStatic); - if (type_val->data.x_type == g->builtin_types.entry_anytype) { - *is_opaque_type = false; - return ErrorNone; - } - *is_opaque_type = (type_val->data.x_type->id == ZigTypeIdOpaque); - return ErrorNone; - } - switch (type_val->data.x_lazy->id) { - case LazyValueIdInvalid: - case LazyValueIdAlignOf: - case LazyValueIdSizeOf: - case LazyValueIdTypeInfoDecls: - zig_unreachable(); - case LazyValueIdSliceType: - case LazyValueIdPtrType: - case LazyValueIdPtrTypeSimple: - case LazyValueIdPtrTypeSimpleConst: - case LazyValueIdFnType: - case LazyValueIdOptType: - case LazyValueIdErrUnionType: - case LazyValueIdArrayType: - *is_opaque_type = false; - return ErrorNone; - } - zig_unreachable(); -} - -static ReqCompTime type_val_resolve_requires_comptime(CodeGen *g, ZigValue *type_val) { - if (type_val->special != ConstValSpecialLazy) { - return type_requires_comptime(g, type_val->data.x_type); - } - switch (type_val->data.x_lazy->id) { - case LazyValueIdInvalid: - case LazyValueIdAlignOf: - case LazyValueIdSizeOf: - case LazyValueIdTypeInfoDecls: - zig_unreachable(); - case LazyValueIdSliceType: { - LazyValueSliceType *lazy_slice_type = reinterpret_cast(type_val->data.x_lazy); - return type_val_resolve_requires_comptime(g, lazy_slice_type->elem_type->value); - } - case LazyValueIdPtrType: { - LazyValuePtrType *lazy_ptr_type = reinterpret_cast(type_val->data.x_lazy); - return type_val_resolve_requires_comptime(g, lazy_ptr_type->elem_type->value); - } - case LazyValueIdPtrTypeSimple: - case LazyValueIdPtrTypeSimpleConst: { - LazyValuePtrTypeSimple *lazy_ptr_type = reinterpret_cast(type_val->data.x_lazy); - return type_val_resolve_requires_comptime(g, lazy_ptr_type->elem_type->value); - } - case LazyValueIdOptType: { - LazyValueOptType *lazy_opt_type = reinterpret_cast(type_val->data.x_lazy); - return type_val_resolve_requires_comptime(g, lazy_opt_type->payload_type->value); - } - case LazyValueIdArrayType: { - LazyValueArrayType *lazy_array_type = reinterpret_cast(type_val->data.x_lazy); - return type_val_resolve_requires_comptime(g, lazy_array_type->elem_type->value); - } - case LazyValueIdFnType: { - LazyValueFnType *lazy_fn_type = reinterpret_cast(type_val->data.x_lazy); - if (lazy_fn_type->is_generic) - return ReqCompTimeYes; - switch (type_val_resolve_requires_comptime(g, lazy_fn_type->return_type->value)) { - case ReqCompTimeInvalid: - return ReqCompTimeInvalid; - case ReqCompTimeYes: - return ReqCompTimeYes; - case ReqCompTimeNo: - break; - } - size_t param_count = lazy_fn_type->proto_node->data.fn_proto.params.length; - for (size_t i = 0; i < param_count; i += 1) { - AstNode *param_node = lazy_fn_type->proto_node->data.fn_proto.params.at(i); - bool param_is_var_args = param_node->data.param_decl.is_var_args; - if (param_is_var_args) break; - switch (type_val_resolve_requires_comptime(g, lazy_fn_type->param_types[i]->value)) { - case ReqCompTimeInvalid: - return ReqCompTimeInvalid; - case ReqCompTimeYes: - return ReqCompTimeYes; - case ReqCompTimeNo: - break; - } - } - return ReqCompTimeNo; - } - case LazyValueIdErrUnionType: { - LazyValueErrUnionType *lazy_err_union_type = - reinterpret_cast(type_val->data.x_lazy); - return type_val_resolve_requires_comptime(g, lazy_err_union_type->payload_type->value); - } - } - zig_unreachable(); -} - -Error type_val_resolve_abi_size(CodeGen *g, AstNode *source_node, ZigValue *type_val, - size_t *abi_size, size_t *size_in_bits) -{ - Error err; - -start_over: - if (type_val->special != ConstValSpecialLazy) { - assert(type_val->special == ConstValSpecialStatic); - ZigType *ty = type_val->data.x_type; - if ((err = type_resolve(g, ty, ResolveStatusSizeKnown))) - return err; - *abi_size = ty->abi_size; - *size_in_bits = ty->size_in_bits; - return ErrorNone; - } - switch (type_val->data.x_lazy->id) { - case LazyValueIdInvalid: - case LazyValueIdAlignOf: - case LazyValueIdSizeOf: - case LazyValueIdTypeInfoDecls: - zig_unreachable(); - case LazyValueIdSliceType: { - LazyValueSliceType *lazy_slice_type = reinterpret_cast(type_val->data.x_lazy); - bool is_zero_bits; - if ((err = type_val_resolve_zero_bits(g, lazy_slice_type->elem_type->value, nullptr, - nullptr, &is_zero_bits))) - { - return err; - } - if (is_zero_bits) { - *abi_size = g->builtin_types.entry_usize->abi_size; - *size_in_bits = g->builtin_types.entry_usize->size_in_bits; - } else { - *abi_size = g->builtin_types.entry_usize->abi_size * 2; - *size_in_bits = g->builtin_types.entry_usize->size_in_bits * 2; - } - return ErrorNone; - } - case LazyValueIdPtrType: { - LazyValuePtrType *lazy_ptr_type = reinterpret_cast(type_val->data.x_lazy); - bool is_zero_bits; - if ((err = type_val_resolve_zero_bits(g, lazy_ptr_type->elem_type->value, nullptr, - nullptr, &is_zero_bits))) - { - return err; - } - if (is_zero_bits) { - *abi_size = 0; - *size_in_bits = 0; - } else { - *abi_size = g->builtin_types.entry_usize->abi_size; - *size_in_bits = g->builtin_types.entry_usize->size_in_bits; - } - return ErrorNone; - } - case LazyValueIdPtrTypeSimple: - case LazyValueIdPtrTypeSimpleConst: { - LazyValuePtrTypeSimple *lazy_ptr_type = reinterpret_cast(type_val->data.x_lazy); - bool is_zero_bits; - if ((err = type_val_resolve_zero_bits(g, lazy_ptr_type->elem_type->value, nullptr, - nullptr, &is_zero_bits))) - { - return err; - } - if (is_zero_bits) { - *abi_size = 0; - *size_in_bits = 0; - } else { - *abi_size = g->builtin_types.entry_usize->abi_size; - *size_in_bits = g->builtin_types.entry_usize->size_in_bits; - } - return ErrorNone; - } - case LazyValueIdFnType: - *abi_size = g->builtin_types.entry_usize->abi_size; - *size_in_bits = g->builtin_types.entry_usize->size_in_bits; - return ErrorNone; - case LazyValueIdOptType: - case LazyValueIdErrUnionType: - case LazyValueIdArrayType: - if ((err = ir_resolve_lazy(g, source_node, type_val))) - return err; - goto start_over; - } - zig_unreachable(); -} - -Error type_val_resolve_abi_align(CodeGen *g, AstNode *source_node, ZigValue *type_val, uint32_t *abi_align) { - Error err; - if (type_val->special != ConstValSpecialLazy) { - assert(type_val->special == ConstValSpecialStatic); - ZigType *ty = type_val->data.x_type; - if (ty->id == ZigTypeIdPointer) { - *abi_align = g->builtin_types.entry_usize->abi_align; - return ErrorNone; - } - if ((err = type_resolve(g, ty, ResolveStatusAlignmentKnown))) - return err; - *abi_align = ty->abi_align; - return ErrorNone; - } - switch (type_val->data.x_lazy->id) { - case LazyValueIdInvalid: - case LazyValueIdAlignOf: - case LazyValueIdSizeOf: - case LazyValueIdTypeInfoDecls: - zig_unreachable(); - case LazyValueIdSliceType: - case LazyValueIdPtrType: - case LazyValueIdPtrTypeSimple: - case LazyValueIdPtrTypeSimpleConst: - case LazyValueIdFnType: - *abi_align = g->builtin_types.entry_usize->abi_align; - return ErrorNone; - case LazyValueIdOptType: { - if ((err = ir_resolve_lazy(g, nullptr, type_val))) - return err; - - return type_val_resolve_abi_align(g, source_node, type_val, abi_align); - } - case LazyValueIdArrayType: { - LazyValueArrayType *lazy_array_type = - reinterpret_cast(type_val->data.x_lazy); - - if (lazy_array_type->length + (lazy_array_type->sentinel != nullptr) != 0) - return type_val_resolve_abi_align(g, source_node, lazy_array_type->elem_type->value, abi_align); - - *abi_align = 0; - return ErrorNone; - } - case LazyValueIdErrUnionType: { - LazyValueErrUnionType *lazy_err_union_type = - reinterpret_cast(type_val->data.x_lazy); - uint32_t payload_abi_align; - if ((err = type_val_resolve_abi_align(g, source_node, lazy_err_union_type->payload_type->value, - &payload_abi_align))) - { - return err; - } - *abi_align = (payload_abi_align > g->err_tag_type->abi_align) ? - payload_abi_align : g->err_tag_type->abi_align; - return ErrorNone; - } - } - zig_unreachable(); -} - -static OnePossibleValue type_val_resolve_has_one_possible_value(CodeGen *g, ZigValue *type_val) { - if (type_val->special != ConstValSpecialLazy) { - return type_has_one_possible_value(g, type_val->data.x_type); - } - switch (type_val->data.x_lazy->id) { - case LazyValueIdInvalid: - case LazyValueIdAlignOf: - case LazyValueIdSizeOf: - case LazyValueIdTypeInfoDecls: - zig_unreachable(); - case LazyValueIdSliceType: // it has the len field - case LazyValueIdOptType: // it has the optional bit - case LazyValueIdFnType: - return OnePossibleValueNo; - case LazyValueIdArrayType: { - LazyValueArrayType *lazy_array_type = - reinterpret_cast(type_val->data.x_lazy); - if (lazy_array_type->length == 0) - return OnePossibleValueYes; - return type_val_resolve_has_one_possible_value(g, lazy_array_type->elem_type->value); - } - case LazyValueIdPtrType: - case LazyValueIdPtrTypeSimple: - case LazyValueIdPtrTypeSimpleConst: { - Error err; - bool zero_bits; - if ((err = type_val_resolve_zero_bits(g, type_val, nullptr, nullptr, &zero_bits))) { - return OnePossibleValueInvalid; - } - if (zero_bits) { - return OnePossibleValueYes; - } else { - return OnePossibleValueNo; - } - } - case LazyValueIdErrUnionType: { - LazyValueErrUnionType *lazy_err_union_type = - reinterpret_cast(type_val->data.x_lazy); - switch (type_val_resolve_has_one_possible_value(g, lazy_err_union_type->err_set_type->value)) { - case OnePossibleValueInvalid: - return OnePossibleValueInvalid; - case OnePossibleValueNo: - return OnePossibleValueNo; - case OnePossibleValueYes: - return type_val_resolve_has_one_possible_value(g, lazy_err_union_type->payload_type->value); - } - } - } - zig_unreachable(); -} - -ZigType *analyze_type_expr(CodeGen *g, Scope *scope, AstNode *node) { - Error err; - // Hot path for simple identifiers, to avoid unnecessary memory allocations. - if (node->type == NodeTypeIdentifier) { - RootStruct *root_struct = node->owner->data.structure.root_struct; - Buf *variable_name = token_identifier_buf(root_struct, node->main_token); - if (buf_eql_str(variable_name, "_")) - goto abort_hot_path; - ZigType *primitive_type; - if ((err = get_primitive_type(g, variable_name, &primitive_type))) { - goto abort_hot_path; - } else { - return primitive_type; - } -abort_hot_path:; - } - ZigValue *result = analyze_const_value(g, scope, node, g->builtin_types.entry_type, - nullptr, UndefBad); - if (type_is_invalid(result->type)) - return g->builtin_types.entry_invalid; - src_assert(result->special == ConstValSpecialStatic, node); - src_assert(result->data.x_type != nullptr, node); - return result->data.x_type; -} - -ZigType *get_generic_fn_type(CodeGen *g, FnTypeId *fn_type_id) { - ZigType *fn_type = new_type_table_entry(ZigTypeIdFn); - buf_resize(&fn_type->name, 0); - buf_appendf(&fn_type->name, "fn("); - size_t i = 0; - for (; i < fn_type_id->next_param_index; i += 1) { - const char *comma_str = (i == 0) ? "" : ","; - buf_appendf(&fn_type->name, "%s%s", comma_str, - buf_ptr(&fn_type_id->param_info[i].type->name)); - } - for (; i < fn_type_id->param_count; i += 1) { - const char *comma_str = (i == 0) ? "" : ","; - buf_appendf(&fn_type->name, "%sanytype", comma_str); - } - buf_append_str(&fn_type->name, ")"); - if (fn_type_id->cc != CallingConventionUnspecified) { - buf_appendf(&fn_type->name, " callconv(.%s)", calling_convention_name(fn_type_id->cc)); - } - buf_append_str(&fn_type->name, " anytype"); - - fn_type->data.fn.fn_type_id = *fn_type_id; - fn_type->data.fn.is_generic = true; - fn_type->abi_size = 0; - fn_type->size_in_bits = 0; - fn_type->abi_align = 0; - return fn_type; -} - -CallingConvention cc_from_fn_proto(AstNodeFnProto *fn_proto) { - // Compatible with the C ABI - if (fn_proto->is_extern || fn_proto->is_export) - return CallingConventionC; - - if (fn_proto->fn_inline == FnInlineAlways) - return CallingConventionInline; - - return CallingConventionUnspecified; -} - -void init_fn_type_id(FnTypeId *fn_type_id, AstNode *proto_node, CallingConvention cc, size_t param_count_alloc) { - assert(proto_node->type == NodeTypeFnProto); - AstNodeFnProto *fn_proto = &proto_node->data.fn_proto; - - fn_type_id->cc = cc; - fn_type_id->param_count = fn_proto->params.length; - fn_type_id->param_info = heap::c_allocator.allocate(param_count_alloc); - fn_type_id->next_param_index = 0; - fn_type_id->is_var_args = fn_proto->is_var_args; -} - -static bool analyze_const_align(CodeGen *g, Scope *scope, AstNode *node, uint32_t *result) { - ZigValue *align_result = analyze_const_value(g, scope, node, get_align_amt_type(g), - nullptr, UndefBad); - if (type_is_invalid(align_result->type)) - return false; - - uint32_t align_bytes = bigint_as_u32(&align_result->data.x_bigint); - if (align_bytes == 0) { - add_node_error(g, node, buf_sprintf("alignment must be >= 1")); - return false; - } - if (!is_power_of_2(align_bytes)) { - add_node_error(g, node, buf_sprintf("alignment value %" PRIu32 " is not a power of 2", align_bytes)); - return false; - } - - *result = align_bytes; - return true; -} - -static bool analyze_const_string(CodeGen *g, Scope *scope, AstNode *node, Buf **out_buffer) { - ZigType *ptr_type = get_pointer_to_type_extra(g, g->builtin_types.entry_u8, true, false, - PtrLenUnknown, 0, 0, 0, false); - ZigType *str_type = get_slice_type(g, ptr_type); - ZigValue *result_val = analyze_const_value(g, scope, node, str_type, nullptr, UndefBad); - if (type_is_invalid(result_val->type)) - return false; - - ZigValue *ptr_field = result_val->data.x_struct.fields[slice_ptr_index]; - ZigValue *len_field = result_val->data.x_struct.fields[slice_len_index]; - - assert(ptr_field->data.x_ptr.special == ConstPtrSpecialBaseArray); - ZigValue *array_val = ptr_field->data.x_ptr.data.base_array.array_val; - if (array_val->data.x_array.special == ConstArraySpecialBuf) { - *out_buffer = array_val->data.x_array.data.s_buf; - return true; - } - expand_undef_array(g, array_val); - size_t len = bigint_as_usize(&len_field->data.x_bigint); - Buf *result = buf_alloc(); - buf_resize(result, len); - for (size_t i = 0; i < len; i += 1) { - size_t new_index = ptr_field->data.x_ptr.data.base_array.elem_index + i; - ZigValue *char_val = &array_val->data.x_array.data.s_none.elements[new_index]; - if (char_val->special == ConstValSpecialUndef) { - add_node_error(g, node, buf_sprintf("use of undefined value")); - return false; - } - uint64_t big_c = bigint_as_u64(&char_val->data.x_bigint); - assert(big_c <= UINT8_MAX); - uint8_t c = (uint8_t)big_c; - buf_ptr(result)[i] = c; - } - *out_buffer = result; - return true; -} - -static Error emit_error_unless_type_allowed_in_packed_container(CodeGen *g, ZigType *type_entry, - AstNode *source_node, const char* container_name) -{ - Error err; - switch (type_entry->id) { - case ZigTypeIdInvalid: - zig_unreachable(); - case ZigTypeIdMetaType: - case ZigTypeIdUnreachable: - case ZigTypeIdComptimeFloat: - case ZigTypeIdComptimeInt: - case ZigTypeIdEnumLiteral: - case ZigTypeIdUndefined: - case ZigTypeIdNull: - case ZigTypeIdErrorUnion: - case ZigTypeIdErrorSet: - case ZigTypeIdBoundFn: - case ZigTypeIdOpaque: - case ZigTypeIdFnFrame: - case ZigTypeIdAnyFrame: - add_node_error(g, source_node, - buf_sprintf("type '%s' not allowed in packed %s; no guaranteed in-memory representation", - buf_ptr(&type_entry->name), container_name)); - return ErrorSemanticAnalyzeFail; - case ZigTypeIdVoid: - case ZigTypeIdBool: - case ZigTypeIdInt: - case ZigTypeIdFloat: - case ZigTypeIdPointer: - case ZigTypeIdFn: - case ZigTypeIdVector: - return ErrorNone; - case ZigTypeIdArray: { - ZigType *elem_type = type_entry->data.array.child_type; - if ((err = emit_error_unless_type_allowed_in_packed_container(g, elem_type, source_node, container_name))) - return err; - // TODO revisit this when doing https://github.com/ziglang/zig/issues/1512 - size_t abi_size_in_bits = type_size(g, type_entry) * 8; - size_t size_in_bits = type_size_bits(g, type_entry); - if (abi_size_in_bits == size_in_bits) return ErrorNone; - add_node_error(g, source_node, - buf_sprintf("array of '%s' not allowed in packed %s due to padding bits (must be padded from %zu to %zu bits)", - buf_ptr(&elem_type->name), container_name, size_in_bits, abi_size_in_bits)); - return ErrorSemanticAnalyzeFail; - } - case ZigTypeIdStruct: - switch (type_entry->data.structure.layout) { - case ContainerLayoutPacked: - case ContainerLayoutExtern: - return ErrorNone; - case ContainerLayoutAuto: - add_node_error(g, source_node, - buf_sprintf("non-packed, non-extern struct '%s' not allowed in packed %s; no guaranteed in-memory representation", - buf_ptr(&type_entry->name), container_name)); - return ErrorSemanticAnalyzeFail; - } - zig_unreachable(); - case ZigTypeIdUnion: - switch (type_entry->data.unionation.layout) { - case ContainerLayoutPacked: - case ContainerLayoutExtern: - return ErrorNone; - case ContainerLayoutAuto: - add_node_error(g, source_node, - buf_sprintf("non-packed, non-extern union '%s' not allowed in packed %s; no guaranteed in-memory representation", - buf_ptr(&type_entry->name), container_name)); - return ErrorSemanticAnalyzeFail; - } - zig_unreachable(); - case ZigTypeIdOptional: { - ZigType *ptr_type; - if ((err = get_codegen_ptr_type(g, type_entry, &ptr_type))) return err; - if (ptr_type != nullptr) return ErrorNone; - - add_node_error(g, source_node, - buf_sprintf("type '%s' not allowed in packed %s; no guaranteed in-memory representation", - buf_ptr(&type_entry->name), container_name)); - return ErrorSemanticAnalyzeFail; - } - case ZigTypeIdEnum: { - AstNode *decl_node = type_entry->data.enumeration.decl_node; - if (decl_node->data.container_decl.init_arg_expr != nullptr) { - return ErrorNone; - } - ErrorMsg *msg = add_node_error(g, source_node, - buf_sprintf("type '%s' not allowed in packed %s; no guaranteed in-memory representation", - buf_ptr(&type_entry->name), container_name)); - add_error_note(g, msg, decl_node, - buf_sprintf("enum declaration does not specify an integer tag type")); - return ErrorSemanticAnalyzeFail; - } - } - zig_unreachable(); -} - -static Error emit_error_unless_type_allowed_in_packed_struct(CodeGen *g, ZigType *type_entry, - AstNode *source_node) -{ - return emit_error_unless_type_allowed_in_packed_container(g, type_entry, source_node, "struct"); -} - -static Error emit_error_unless_type_allowed_in_packed_union(CodeGen *g, ZigType *type_entry, - AstNode *source_node) -{ - return emit_error_unless_type_allowed_in_packed_container(g, type_entry, source_node, "union"); -} - -Error type_allowed_in_extern(CodeGen *g, ZigType *type_entry, ExternPosition position, bool *result) { - Error err; - switch (type_entry->id) { - case ZigTypeIdInvalid: - zig_unreachable(); - case ZigTypeIdMetaType: - case ZigTypeIdComptimeFloat: - case ZigTypeIdComptimeInt: - case ZigTypeIdEnumLiteral: - case ZigTypeIdUndefined: - case ZigTypeIdNull: - case ZigTypeIdErrorUnion: - case ZigTypeIdErrorSet: - case ZigTypeIdBoundFn: - case ZigTypeIdVoid: - case ZigTypeIdFnFrame: - case ZigTypeIdAnyFrame: - *result = false; - return ErrorNone; - case ZigTypeIdUnreachable: - *result = position == ExternPositionFunctionReturn; - return ErrorNone; - case ZigTypeIdOpaque: - case ZigTypeIdBool: - *result = true; - return ErrorNone; - case ZigTypeIdInt: - switch (type_entry->data.integral.bit_count) { - case 8: - case 16: - case 32: - case 64: - case 128: - *result = true; - return ErrorNone; - default: - *result = false; - return ErrorNone; - } - case ZigTypeIdVector: - return type_allowed_in_extern(g, type_entry->data.vector.elem_type, ExternPositionOther, result); - case ZigTypeIdFloat: - *result = true; - return ErrorNone; - case ZigTypeIdArray: - if ((err = type_allowed_in_extern(g, type_entry->data.array.child_type, ExternPositionOther, result))) - return err; - *result = *result && - position != ExternPositionFunctionParameter && - position != ExternPositionFunctionReturn; - return ErrorNone; - case ZigTypeIdFn: - *result = !calling_convention_allows_zig_types(type_entry->data.fn.fn_type_id.cc); - return ErrorNone; - case ZigTypeIdPointer: - if ((err = type_resolve(g, type_entry, ResolveStatusZeroBitsKnown))) - return err; - bool has_bits; - if ((err = type_has_bits2(g, type_entry, &has_bits))) - return err; - *result = has_bits; - return ErrorNone; - case ZigTypeIdStruct: - *result = type_entry->data.structure.layout == ContainerLayoutExtern || - type_entry->data.structure.layout == ContainerLayoutPacked; - return ErrorNone; - case ZigTypeIdOptional: { - ZigType *child_type = type_entry->data.maybe.child_type; - if (child_type->id != ZigTypeIdPointer && child_type->id != ZigTypeIdFn) { - *result = false; - return ErrorNone; - } - bool is_nonnull_ptr; - if ((err = type_is_nonnull_ptr2(g, child_type, &is_nonnull_ptr))) - return err; - if (!is_nonnull_ptr) { - *result = false; - return ErrorNone; - } - return type_allowed_in_extern(g, child_type, ExternPositionOther, result); - } - case ZigTypeIdEnum: { - if ((err = type_resolve(g, type_entry, ResolveStatusZeroBitsKnown))) - return err; - ZigType *tag_int_type = type_entry->data.enumeration.tag_int_type; - if (type_entry->data.enumeration.has_explicit_tag_type) - return type_allowed_in_extern(g, tag_int_type, position, result); - *result = type_entry->data.enumeration.layout == ContainerLayoutExtern || - type_entry->data.enumeration.layout == ContainerLayoutPacked; - return ErrorNone; - } - case ZigTypeIdUnion: - *result = type_entry->data.unionation.layout == ContainerLayoutExtern || - type_entry->data.unionation.layout == ContainerLayoutPacked; - return ErrorNone; - } - zig_unreachable(); -} - -ZigType *get_auto_err_set_type(CodeGen *g, ZigFn *fn_entry) { - ZigType *err_set_type = new_type_table_entry(ZigTypeIdErrorSet); - buf_resize(&err_set_type->name, 0); - buf_appendf(&err_set_type->name, "@typeInfo(@typeInfo(@TypeOf(%s)).Fn.return_type.?).ErrorUnion.error_set", buf_ptr(&fn_entry->symbol_name)); - err_set_type->data.error_set.err_count = 0; - err_set_type->data.error_set.errors = nullptr; - err_set_type->data.error_set.infer_fn = fn_entry; - err_set_type->data.error_set.incomplete = true; - err_set_type->size_in_bits = g->builtin_types.entry_global_error_set->size_in_bits; - err_set_type->abi_align = g->builtin_types.entry_global_error_set->abi_align; - err_set_type->abi_size = g->builtin_types.entry_global_error_set->abi_size; - - return err_set_type; -} - -// Sync this with get_llvm_cc in codegen.cpp -Error emit_error_unless_callconv_allowed_for_target(CodeGen *g, AstNode *source_node, CallingConvention cc) { - Error ret = ErrorNone; - const char *allowed_platforms = nullptr; - switch (cc) { - case CallingConventionUnspecified: - case CallingConventionC: - case CallingConventionNaked: - case CallingConventionAsync: - case CallingConventionInline: - break; - case CallingConventionInterrupt: - if (g->zig_target->arch != ZigLLVM_x86 - && g->zig_target->arch != ZigLLVM_x86_64 - && g->zig_target->arch != ZigLLVM_avr - && g->zig_target->arch != ZigLLVM_msp430) - { - allowed_platforms = "x86, x86_64, AVR, and MSP430"; - } - break; - case CallingConventionSignal: - if (g->zig_target->arch != ZigLLVM_avr) - allowed_platforms = "AVR"; - break; - case CallingConventionStdcall: - case CallingConventionFastcall: - case CallingConventionThiscall: - if (g->zig_target->arch != ZigLLVM_x86) - allowed_platforms = "x86"; - break; - case CallingConventionVectorcall: - if (g->zig_target->arch != ZigLLVM_x86 - && !(target_is_arm(g->zig_target) && target_arch_pointer_bit_width(g->zig_target->arch) == 64)) - { - allowed_platforms = "x86 and AArch64"; - } - break; - case CallingConventionAPCS: - case CallingConventionAAPCS: - case CallingConventionAAPCSVFP: - if (!target_is_arm(g->zig_target)) - allowed_platforms = "ARM"; - break; - case CallingConventionSysV: - case CallingConventionWin64: - if (g->zig_target->arch != ZigLLVM_x86_64) - allowed_platforms = "x86_64"; - break; - case CallingConventionPtxKernel: - if (g->zig_target->arch != ZigLLVM_nvptx - && g->zig_target->arch != ZigLLVM_nvptx64) - { - allowed_platforms = "nvptx and nvptx64"; - } - break; - case CallingConventionAmdgpuKernel: - if (g->zig_target->arch != ZigLLVM_amdgcn) - allowed_platforms = "amdgcn and amdpal"; - - } - if (allowed_platforms != nullptr) { - add_node_error(g, source_node, buf_sprintf( - "callconv '%s' is only available on %s, not %s", - calling_convention_name(cc), allowed_platforms, - target_arch_name(g->zig_target->arch))); - ret = ErrorSemanticAnalyzeFail; - } - return ret; -} - -static ZigType *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *child_scope, ZigFn *fn_entry, - CallingConvention cc) -{ - assert(proto_node->type == NodeTypeFnProto); - AstNodeFnProto *fn_proto = &proto_node->data.fn_proto; - Error err; - - FnTypeId fn_type_id = {0}; - init_fn_type_id(&fn_type_id, proto_node, cc, proto_node->data.fn_proto.params.length); - - for (; fn_type_id.next_param_index < fn_type_id.param_count; fn_type_id.next_param_index += 1) { - AstNode *param_node = fn_proto->params.at(fn_type_id.next_param_index); - assert(param_node->type == NodeTypeParamDecl); - - bool param_is_comptime = param_node->data.param_decl.is_comptime; - bool param_is_var_args = param_node->data.param_decl.is_var_args; - - if (param_is_comptime) { - if (!calling_convention_allows_zig_types(fn_type_id.cc)) { - add_node_error(g, param_node, - buf_sprintf("comptime parameter not allowed in function with calling convention '%s'", - calling_convention_name(fn_type_id.cc))); - return g->builtin_types.entry_invalid; - } - if (param_node->data.param_decl.type != nullptr) { - ZigType *type_entry = analyze_type_expr(g, child_scope, param_node->data.param_decl.type); - if (type_is_invalid(type_entry)) { - return g->builtin_types.entry_invalid; - } - FnTypeParamInfo *param_info = &fn_type_id.param_info[fn_type_id.next_param_index]; - param_info->type = type_entry; - param_info->is_noalias = param_node->data.param_decl.is_noalias; - fn_type_id.next_param_index += 1; - } - - return get_generic_fn_type(g, &fn_type_id); - } else if (param_is_var_args) { - if (fn_type_id.cc == CallingConventionC) { - fn_type_id.param_count = fn_type_id.next_param_index; - continue; - } else { - add_node_error(g, param_node, - buf_sprintf("var args only allowed in functions with C calling convention")); - return g->builtin_types.entry_invalid; - } - } else if (param_node->data.param_decl.anytype_token != 0) { - if (!calling_convention_allows_zig_types(fn_type_id.cc)) { - add_node_error(g, param_node, - buf_sprintf("parameter of type 'anytype' not allowed in function with calling convention '%s'", - calling_convention_name(fn_type_id.cc))); - return g->builtin_types.entry_invalid; - } - return get_generic_fn_type(g, &fn_type_id); - } - - ZigType *type_entry = analyze_type_expr(g, child_scope, param_node->data.param_decl.type); - if (type_is_invalid(type_entry)) { - return g->builtin_types.entry_invalid; - } - if (!calling_convention_allows_zig_types(fn_type_id.cc)) { - if ((err = type_resolve(g, type_entry, ResolveStatusZeroBitsKnown))) - return g->builtin_types.entry_invalid; - if (!type_has_bits(g, type_entry)) { - add_node_error(g, param_node->data.param_decl.type, - buf_sprintf("parameter of type '%s' has 0 bits; not allowed in function with calling convention '%s'", - buf_ptr(&type_entry->name), calling_convention_name(fn_type_id.cc))); - return g->builtin_types.entry_invalid; - } - } - - if (!calling_convention_allows_zig_types(fn_type_id.cc)) { - bool ok_type; - if ((err = type_allowed_in_extern(g, type_entry, ExternPositionFunctionParameter, &ok_type))) - return g->builtin_types.entry_invalid; - if (!ok_type) { - add_node_error(g, param_node->data.param_decl.type, - buf_sprintf("parameter of type '%s' not allowed in function with calling convention '%s'", - buf_ptr(&type_entry->name), - calling_convention_name(fn_type_id.cc))); - return g->builtin_types.entry_invalid; - } - } - - if(!is_valid_param_type(type_entry)){ - if(type_entry->id == ZigTypeIdOpaque){ - add_node_error(g, param_node->data.param_decl.type, - buf_sprintf("parameter of opaque type '%s' not allowed", buf_ptr(&type_entry->name))); - } else { - add_node_error(g, param_node->data.param_decl.type, - buf_sprintf("parameter of type '%s' not allowed", buf_ptr(&type_entry->name))); - } - - return g->builtin_types.entry_invalid; - } - - switch (type_requires_comptime(g, type_entry)) { - case ReqCompTimeNo: - break; - case ReqCompTimeYes: - add_node_error(g, param_node->data.param_decl.type, - buf_sprintf("parameter of type '%s' must be declared comptime", - buf_ptr(&type_entry->name))); - return g->builtin_types.entry_invalid; - case ReqCompTimeInvalid: - return g->builtin_types.entry_invalid; - } - - FnTypeParamInfo *param_info = &fn_type_id.param_info[fn_type_id.next_param_index]; - param_info->type = type_entry; - param_info->is_noalias = param_node->data.param_decl.is_noalias; - } - - if (fn_proto->align_expr != nullptr) { - if (target_is_wasm(g->zig_target)) { - // In Wasm, specifying alignment of function pointers makes little sense - // since function pointers are in fact indices to a Wasm table, therefore - // any alignment check on those is invalid. This can cause unexpected - // behaviour when checking expected alignment with `@ptrToInt(fn_ptr)` - // or similar. This commit proposes to make `align` expressions a - // compile error when compiled to Wasm architecture. - // - // Some references: - // [1] [Mozilla: WebAssembly Tables](https://developer.mozilla.org/en-US/docs/WebAssembly/Understanding_the_text_format#WebAssembly_tables) - // [2] [Sunfishcode's Wasm Ref Manual](https://github.com/sunfishcode/wasm-reference-manual/blob/master/WebAssembly.md#indirect-call) - add_node_error(g, fn_proto->align_expr, - buf_sprintf("align(N) expr is not allowed on function prototypes in wasm32/wasm64")); - return g->builtin_types.entry_invalid; - } - if (!analyze_const_align(g, child_scope, fn_proto->align_expr, &fn_type_id.alignment)) { - return g->builtin_types.entry_invalid; - } - fn_entry->align_bytes = fn_type_id.alignment; - } - - if (proto_node->data.fn_proto.callconv_expr != nullptr) { - if ((err = emit_error_unless_callconv_allowed_for_target(g, proto_node->data.fn_proto.callconv_expr, cc))) - return g->builtin_types.entry_invalid; - } - - ZigType *specified_return_type = analyze_type_expr(g, child_scope, fn_proto->return_type); - if (type_is_invalid(specified_return_type)) { - fn_type_id.return_type = g->builtin_types.entry_invalid; - return g->builtin_types.entry_invalid; - } - - if(!is_valid_return_type(specified_return_type)){ - ErrorMsg* msg = add_node_error(g, fn_proto->return_type, - buf_sprintf("%s return type '%s' not allowed", type_id_name(specified_return_type->id), buf_ptr(&specified_return_type->name))); - Tld *tld = find_decl(g, &fn_entry->fndef_scope->base, &specified_return_type->name); - if (tld != nullptr) { - add_error_note(g, msg, tld->source_node, buf_sprintf("type declared here")); - } - return g->builtin_types.entry_invalid; - } - - if (fn_proto->auto_err_set) { - ZigType *inferred_err_set_type = get_auto_err_set_type(g, fn_entry); - if ((err = type_resolve(g, specified_return_type, ResolveStatusSizeKnown))) - return g->builtin_types.entry_invalid; - fn_type_id.return_type = get_error_union_type(g, inferred_err_set_type, specified_return_type); - } else { - fn_type_id.return_type = specified_return_type; - } - - if (!calling_convention_allows_zig_types(fn_type_id.cc) && - fn_type_id.return_type->id != ZigTypeIdVoid) - { - if ((err = type_resolve(g, fn_type_id.return_type, ResolveStatusSizeKnown))) - return g->builtin_types.entry_invalid; - bool ok_type; - if ((err = type_allowed_in_extern(g, fn_type_id.return_type, ExternPositionFunctionReturn, &ok_type))) - return g->builtin_types.entry_invalid; - if (!ok_type) { - add_node_error(g, fn_proto->return_type, - buf_sprintf("return type '%s' not allowed in function with calling convention '%s'", - buf_ptr(&fn_type_id.return_type->name), - calling_convention_name(fn_type_id.cc))); - return g->builtin_types.entry_invalid; - } - } - - switch (type_requires_comptime(g, fn_type_id.return_type)) { - case ReqCompTimeInvalid: - return g->builtin_types.entry_invalid; - case ReqCompTimeYes: - return get_generic_fn_type(g, &fn_type_id); - case ReqCompTimeNo: - break; - } - - return get_fn_type(g, &fn_type_id); -} - -bool is_valid_return_type(ZigType* type) { - switch (type->id) { - case ZigTypeIdInvalid: - case ZigTypeIdUndefined: - case ZigTypeIdNull: - case ZigTypeIdOpaque: - return false; - default: - return true; - } - zig_unreachable(); -} - -bool is_valid_param_type(ZigType* type) { - switch (type->id) { - case ZigTypeIdInvalid: - case ZigTypeIdUndefined: - case ZigTypeIdNull: - case ZigTypeIdOpaque: - case ZigTypeIdUnreachable: - return false; - default: - return true; - } - zig_unreachable(); -} - -bool type_is_invalid(ZigType *type_entry) { - switch (type_entry->id) { - case ZigTypeIdInvalid: - return true; - case ZigTypeIdStruct: - return type_entry->data.structure.resolve_status == ResolveStatusInvalid; - case ZigTypeIdUnion: - return type_entry->data.unionation.resolve_status == ResolveStatusInvalid; - case ZigTypeIdEnum: - return type_entry->data.enumeration.resolve_status == ResolveStatusInvalid; - case ZigTypeIdFnFrame: - return type_entry->data.frame.reported_loop_err; - default: - return false; - } - zig_unreachable(); -} - -struct SrcField { - const char *name; - ZigType *ty; - unsigned align; -}; - -static ZigType *get_struct_type(CodeGen *g, const char *type_name, SrcField fields[], size_t field_count, - unsigned min_abi_align) -{ - ZigType *struct_type = new_type_table_entry(ZigTypeIdStruct); - - buf_init_from_str(&struct_type->name, type_name); - - struct_type->data.structure.src_field_count = field_count; - struct_type->data.structure.gen_field_count = 0; - struct_type->data.structure.resolve_status = ResolveStatusSizeKnown; - struct_type->data.structure.fields = alloc_type_struct_fields(field_count); - struct_type->data.structure.fields_by_name.init(field_count); - - size_t abi_align = min_abi_align; - for (size_t i = 0; i < field_count; i += 1) { - TypeStructField *field = struct_type->data.structure.fields[i]; - field->name = buf_create_from_str(fields[i].name); - field->type_entry = fields[i].ty; - field->src_index = i; - field->align = fields[i].align; - - if (type_has_bits(g, field->type_entry)) { - assert(type_is_resolved(field->type_entry, ResolveStatusSizeKnown)); - unsigned field_abi_align = max(field->align, field->type_entry->abi_align); - if (field_abi_align > abi_align) { - abi_align = field_abi_align; - } - } - - auto prev_entry = struct_type->data.structure.fields_by_name.put_unique(field->name, field); - assert(prev_entry == nullptr); - } - - size_t next_offset = 0; - for (size_t i = 0; i < field_count; i += 1) { - TypeStructField *field = struct_type->data.structure.fields[i]; - if (!type_has_bits(g, field->type_entry)) - continue; - - field->offset = next_offset; - - // find the next non-zero-byte field for offset calculations - size_t next_src_field_index = i + 1; - for (; next_src_field_index < field_count; next_src_field_index += 1) { - if (type_has_bits(g, struct_type->data.structure.fields[next_src_field_index]->type_entry)) - break; - } - size_t next_abi_align; - if (next_src_field_index == field_count) { - next_abi_align = abi_align; - } else { - next_abi_align = max(fields[next_src_field_index].align, - struct_type->data.structure.fields[next_src_field_index]->type_entry->abi_align); - } - next_offset = next_field_offset(next_offset, abi_align, field->type_entry->abi_size, next_abi_align); - } - - struct_type->abi_align = abi_align; - struct_type->abi_size = next_offset; - struct_type->size_in_bits = next_offset * 8; - - return struct_type; -} - -static size_t get_store_size_bytes(size_t size_in_bits) { - return (size_in_bits + 7) / 8; -} - -static size_t get_abi_align_bytes(size_t size_in_bits, size_t pointer_size_bytes) { - size_t store_size_bytes = get_store_size_bytes(size_in_bits); - if (store_size_bytes >= pointer_size_bytes) - return pointer_size_bytes; - return round_to_next_power_of_2(store_size_bytes); -} - -static size_t get_abi_size_bytes(size_t size_in_bits, size_t pointer_size_bytes) { - size_t store_size_bytes = get_store_size_bytes(size_in_bits); - size_t abi_align = get_abi_align_bytes(size_in_bits, pointer_size_bytes); - return align_forward(store_size_bytes, abi_align); -} - -ZigType *resolve_struct_field_type(CodeGen *g, TypeStructField *struct_field) { - Error err; - if (struct_field->type_entry == nullptr) { - if ((err = ir_resolve_lazy(g, struct_field->decl_node, struct_field->type_val))) { - return nullptr; - } - struct_field->type_entry = struct_field->type_val->data.x_type; - } - return struct_field->type_entry; -} - -static Error resolve_struct_type(CodeGen *g, ZigType *struct_type) { - assert(struct_type->id == ZigTypeIdStruct); - - Error err; - - if (struct_type->data.structure.resolve_status == ResolveStatusInvalid) - return ErrorSemanticAnalyzeFail; - if (struct_type->data.structure.resolve_status >= ResolveStatusSizeKnown) - return ErrorNone; - - if ((err = resolve_struct_alignment(g, struct_type))) - return err; - - AstNode *decl_node = struct_type->data.structure.decl_node; - - if (struct_type->data.structure.resolve_loop_flag_other) { - if (struct_type->data.structure.resolve_status != ResolveStatusInvalid) { - struct_type->data.structure.resolve_status = ResolveStatusInvalid; - add_node_error(g, decl_node, - buf_sprintf("struct '%s' depends on itself", buf_ptr(&struct_type->name))); - } - return ErrorSemanticAnalyzeFail; - } - - assert(struct_type->data.structure.fields || struct_type->data.structure.src_field_count == 0); - - size_t field_count = struct_type->data.structure.src_field_count; - - bool packed = (struct_type->data.structure.layout == ContainerLayoutPacked); - struct_type->data.structure.resolve_loop_flag_other = true; - - uint32_t *host_int_bytes = packed ? heap::c_allocator.allocate(struct_type->data.structure.gen_field_count) : nullptr; - - size_t packed_bits_offset = 0; - size_t next_offset = 0; - size_t first_packed_bits_offset_misalign = SIZE_MAX; - size_t gen_field_index = 0; - size_t size_in_bits = 0; - size_t abi_align = struct_type->abi_align; - - TypeStructField *last_packed_field = nullptr; - - // Calculate offsets - for (size_t i = 0; i < field_count; i += 1) { - TypeStructField *field = struct_type->data.structure.fields[i]; - if (field->gen_index == SIZE_MAX) - continue; - - field->gen_index = gen_field_index; - field->offset = next_offset; - - if (packed) { - ZigType *field_type = resolve_struct_field_type(g, field); - if (field_type == nullptr) { - struct_type->data.structure.resolve_status = ResolveStatusInvalid; - return ErrorSemanticAnalyzeFail; - } - if ((err = type_resolve(g, field->type_entry, ResolveStatusSizeKnown))) { - struct_type->data.structure.resolve_status = ResolveStatusInvalid; - return err; - } - if ((err = emit_error_unless_type_allowed_in_packed_struct(g, field->type_entry, field->decl_node))) { - struct_type->data.structure.resolve_status = ResolveStatusInvalid; - return err; - } - - last_packed_field = field; - size_t field_size_in_bits = type_size_bits(g, field_type); - size_t next_packed_bits_offset = packed_bits_offset + field_size_in_bits; - - size_in_bits += field_size_in_bits; - - if (first_packed_bits_offset_misalign != SIZE_MAX) { - // this field is not byte-aligned; it is part of the previous field with a bit offset - field->bit_offset_in_host = packed_bits_offset - first_packed_bits_offset_misalign; - - size_t full_bit_count = next_packed_bits_offset - first_packed_bits_offset_misalign; - size_t full_abi_size = get_abi_size_bytes(full_bit_count, g->pointer_size_bytes); - if (full_abi_size * 8 == full_bit_count) { - // next field recovers ABI alignment - host_int_bytes[gen_field_index] = full_abi_size; - gen_field_index += 1; - // TODO: https://github.com/ziglang/zig/issues/1512 - next_offset = next_field_offset(next_offset, abi_align, full_abi_size, 1); - size_in_bits = next_offset * 8; - - first_packed_bits_offset_misalign = SIZE_MAX; - } - } else if (get_abi_size_bytes(field_type->size_in_bits, g->pointer_size_bytes) * 8 != field_size_in_bits) { - first_packed_bits_offset_misalign = packed_bits_offset; - field->bit_offset_in_host = 0; - } else { - // This is a byte-aligned field (both start and end) in a packed struct. - host_int_bytes[gen_field_index] = field_type->size_in_bits / 8; - field->bit_offset_in_host = 0; - gen_field_index += 1; - // TODO: https://github.com/ziglang/zig/issues/1512 - next_offset = next_field_offset(next_offset, abi_align, field_type->size_in_bits / 8, 1); - size_in_bits = next_offset * 8; - } - packed_bits_offset = next_packed_bits_offset; - } else { - size_t field_abi_size; - size_t field_size_in_bits; - if ((err = type_val_resolve_abi_size(g, field->decl_node, field->type_val, - &field_abi_size, &field_size_in_bits))) - { - struct_type->data.structure.resolve_status = ResolveStatusInvalid; - return err; - } - - gen_field_index += 1; - size_t next_src_field_index = i + 1; - for (; next_src_field_index < field_count; next_src_field_index += 1) { - if (struct_type->data.structure.fields[next_src_field_index]->gen_index != SIZE_MAX) { - break; - } - } - size_t next_align = (next_src_field_index == field_count) ? - abi_align : struct_type->data.structure.fields[next_src_field_index]->align; - next_offset = next_field_offset(next_offset, abi_align, field_abi_size, next_align); - size_in_bits = next_offset * 8; - } - } - if (first_packed_bits_offset_misalign != SIZE_MAX) { - size_t full_bit_count = packed_bits_offset - first_packed_bits_offset_misalign; - size_t full_abi_size = get_abi_size_bytes(full_bit_count, 1); - next_offset = next_field_offset(next_offset, abi_align, full_abi_size, abi_align); - ZigType* last_field_type = last_packed_field->type_entry; - // If only last field is misaligned and it is of int type save it so we can generate proper code for it later - if (last_field_type->size_in_bits == full_bit_count && (last_field_type->id == ZigTypeIdInt || last_field_type->id == ZigTypeIdEnum)) { - struct_type->data.structure.misaligned_field = last_packed_field; - } - host_int_bytes[gen_field_index] = full_abi_size; - gen_field_index += 1; - } - - struct_type->abi_size = next_offset; - struct_type->size_in_bits = size_in_bits; - struct_type->data.structure.resolve_status = ResolveStatusSizeKnown; - struct_type->data.structure.gen_field_count = (uint32_t)gen_field_index; - struct_type->data.structure.resolve_loop_flag_other = false; - struct_type->data.structure.host_int_bytes = host_int_bytes; - - - // Resolve types for fields - for (size_t i = 0; i < field_count; i += 1) { - TypeStructField *field = struct_type->data.structure.fields[i]; - ZigType *field_type = resolve_struct_field_type(g, field); - if (field_type == nullptr) { - struct_type->data.structure.resolve_status = ResolveStatusInvalid; - return ErrorSemanticAnalyzeFail; - } - - if ((err = type_resolve(g, field_type, ResolveStatusSizeKnown))) { - struct_type->data.structure.resolve_status = ResolveStatusInvalid; - return err; - } - - if (struct_type->data.structure.layout == ContainerLayoutExtern) { - bool ok_type; - if ((err = type_allowed_in_extern(g, field_type, ExternPositionOther, &ok_type))) { - struct_type->data.structure.resolve_status = ResolveStatusInvalid; - return ErrorSemanticAnalyzeFail; - } - if (!ok_type) { - add_node_error(g, field->decl_node, - buf_sprintf("extern structs cannot contain fields of type '%s'", - buf_ptr(&field_type->name))); - struct_type->data.structure.resolve_status = ResolveStatusInvalid; - return ErrorSemanticAnalyzeFail; - } - } - } - - return ErrorNone; -} - -static Error resolve_union_alignment(CodeGen *g, ZigType *union_type) { - assert(union_type->id == ZigTypeIdUnion); - - Error err; - - if (union_type->data.unionation.resolve_status == ResolveStatusInvalid) - return ErrorSemanticAnalyzeFail; - if (union_type->data.unionation.resolve_status >= ResolveStatusAlignmentKnown) - return ErrorNone; - if ((err = resolve_union_zero_bits(g, union_type))) - return err; - if (union_type->data.unionation.resolve_status >= ResolveStatusAlignmentKnown) - return ErrorNone; - - AstNode *decl_node = union_type->data.structure.decl_node; - - if (union_type->data.unionation.resolve_loop_flag_other) { - if (union_type->data.unionation.resolve_status != ResolveStatusInvalid) { - union_type->data.unionation.resolve_status = ResolveStatusInvalid; - add_node_error(g, decl_node, - buf_sprintf("union '%s' depends on itself", buf_ptr(&union_type->name))); - } - return ErrorSemanticAnalyzeFail; - } - - // set temporary flag - union_type->data.unionation.resolve_loop_flag_other = true; - - TypeUnionField *most_aligned_union_member = nullptr; - uint32_t field_count = union_type->data.unionation.src_field_count; - bool packed = union_type->data.unionation.layout == ContainerLayoutPacked; - - for (uint32_t i = 0; i < field_count; i += 1) { - TypeUnionField *field = &union_type->data.unionation.fields[i]; - if (field->gen_index == UINT32_MAX) - continue; - - AstNode *align_expr = nullptr; - if (union_type->data.unionation.decl_node->type == NodeTypeContainerDecl) { - align_expr = field->decl_node->data.struct_field.align_expr; - } - if (align_expr != nullptr) { - if (!analyze_const_align(g, &union_type->data.unionation.decls_scope->base, align_expr, - &field->align)) - { - union_type->data.unionation.resolve_status = ResolveStatusInvalid; - return ErrorSemanticAnalyzeFail; - } - add_node_error(g, field->decl_node, - buf_create_from_str("TODO implement field alignment syntax for unions. https://github.com/ziglang/zig/issues/3125")); - } else if (packed) { - field->align = 1; - } else if (field->type_entry != nullptr) { - if ((err = type_resolve(g, field->type_entry, ResolveStatusAlignmentKnown))) { - union_type->data.unionation.resolve_status = ResolveStatusInvalid; - return err; - } - field->align = field->type_entry->abi_align; - } else { - if ((err = type_val_resolve_abi_align(g, field->decl_node, field->type_val, &field->align))) { - if (g->trace_err != nullptr) { - g->trace_err = add_error_note(g, g->trace_err, field->decl_node, - buf_create_from_str("while checking this field")); - } - union_type->data.unionation.resolve_status = ResolveStatusInvalid; - return err; - } - if (union_type->data.unionation.resolve_status == ResolveStatusInvalid) - return ErrorSemanticAnalyzeFail; - } - - if (most_aligned_union_member == nullptr || field->align > most_aligned_union_member->align) { - most_aligned_union_member = field; - } - } - - // unset temporary flag - union_type->data.unionation.resolve_loop_flag_other = false; - union_type->data.unionation.resolve_status = ResolveStatusAlignmentKnown; - union_type->data.unionation.most_aligned_union_member = most_aligned_union_member; - - ZigType *tag_type = union_type->data.unionation.tag_type; - if (tag_type != nullptr && type_has_bits(g, tag_type)) { - if ((err = type_resolve(g, tag_type, ResolveStatusAlignmentKnown))) { - union_type->data.unionation.resolve_status = ResolveStatusInvalid; - return ErrorSemanticAnalyzeFail; - } - if (most_aligned_union_member == nullptr) { - union_type->abi_align = tag_type->abi_align; - union_type->data.unionation.gen_tag_index = SIZE_MAX; - union_type->data.unionation.gen_union_index = SIZE_MAX; - } else if (tag_type->abi_align > most_aligned_union_member->align) { - union_type->abi_align = tag_type->abi_align; - union_type->data.unionation.gen_tag_index = 0; - union_type->data.unionation.gen_union_index = 1; - } else { - union_type->abi_align = most_aligned_union_member->align; - union_type->data.unionation.gen_union_index = 0; - union_type->data.unionation.gen_tag_index = 1; - } - } else { - union_type->abi_align = most_aligned_union_member? - most_aligned_union_member->align : 0; - union_type->data.unionation.gen_union_index = SIZE_MAX; - union_type->data.unionation.gen_tag_index = SIZE_MAX; - } - - return ErrorNone; -} - -ZigType *resolve_union_field_type(CodeGen *g, TypeUnionField *union_field) { - Error err; - if (union_field->type_entry == nullptr) { - if ((err = ir_resolve_lazy(g, union_field->decl_node, union_field->type_val))) { - return nullptr; - } - union_field->type_entry = union_field->type_val->data.x_type; - } - return union_field->type_entry; -} - -static Error resolve_union_type(CodeGen *g, ZigType *union_type) { - assert(union_type->id == ZigTypeIdUnion); - - Error err; - - if (union_type->data.unionation.resolve_status == ResolveStatusInvalid) - return ErrorSemanticAnalyzeFail; - if (union_type->data.unionation.resolve_status >= ResolveStatusSizeKnown) - return ErrorNone; - - if ((err = resolve_union_alignment(g, union_type))) - return err; - - AstNode *decl_node = union_type->data.unionation.decl_node; - - uint32_t field_count = union_type->data.unionation.src_field_count; - TypeUnionField *most_aligned_union_member = union_type->data.unionation.most_aligned_union_member; - - assert(union_type->data.unionation.fields); - - size_t union_abi_size = 0; - size_t union_size_in_bits = 0; - - if (union_type->data.unionation.resolve_loop_flag_other) { - if (union_type->data.unionation.resolve_status != ResolveStatusInvalid) { - union_type->data.unionation.resolve_status = ResolveStatusInvalid; - add_node_error(g, decl_node, - buf_sprintf("union '%s' depends on itself", buf_ptr(&union_type->name))); - } - return ErrorSemanticAnalyzeFail; - } - - // set temporary flag - union_type->data.unionation.resolve_loop_flag_other = true; - - const bool is_packed = union_type->data.unionation.layout == ContainerLayoutPacked; - - for (uint32_t i = 0; i < field_count; i += 1) { - TypeUnionField *union_field = &union_type->data.unionation.fields[i]; - ZigType *field_type = resolve_union_field_type(g, union_field); - if (field_type == nullptr) { - union_type->data.unionation.resolve_status = ResolveStatusInvalid; - return ErrorSemanticAnalyzeFail; - } - - if ((err = type_resolve(g, field_type, ResolveStatusSizeKnown))) { - union_type->data.unionation.resolve_status = ResolveStatusInvalid; - return ErrorSemanticAnalyzeFail; - } - - if (is_packed) { - if ((err = emit_error_unless_type_allowed_in_packed_union(g, field_type, union_field->decl_node))) { - union_type->data.unionation.resolve_status = ResolveStatusInvalid; - return err; - } - } - - if (type_is_invalid(union_type)) - return ErrorSemanticAnalyzeFail; - - if (!type_has_bits(g, field_type)) - continue; - - union_abi_size = max(union_abi_size, field_type->abi_size); - union_size_in_bits = max(union_size_in_bits, field_type->size_in_bits); - } - - // The union itself for now has to be treated as being independently aligned. - // See https://github.com/ziglang/zig/issues/2166. - if (most_aligned_union_member != nullptr) { - union_abi_size = align_forward(union_abi_size, most_aligned_union_member->align); - } - - // unset temporary flag - union_type->data.unionation.resolve_loop_flag_other = false; - union_type->data.unionation.resolve_status = ResolveStatusSizeKnown; - union_type->data.unionation.union_abi_size = union_abi_size; - - ZigType *tag_type = union_type->data.unionation.tag_type; - if (tag_type != nullptr && type_has_bits(g, tag_type)) { - if ((err = type_resolve(g, tag_type, ResolveStatusSizeKnown))) { - union_type->data.unionation.resolve_status = ResolveStatusInvalid; - return ErrorSemanticAnalyzeFail; - } - if (most_aligned_union_member == nullptr) { - union_type->abi_size = tag_type->abi_size; - union_type->size_in_bits = tag_type->size_in_bits; - } else { - size_t field_sizes[2]; - size_t field_aligns[2]; - field_sizes[union_type->data.unionation.gen_tag_index] = tag_type->abi_size; - field_aligns[union_type->data.unionation.gen_tag_index] = tag_type->abi_align; - field_sizes[union_type->data.unionation.gen_union_index] = union_abi_size; - field_aligns[union_type->data.unionation.gen_union_index] = most_aligned_union_member->align; - size_t field2_offset = next_field_offset(0, union_type->abi_align, field_sizes[0], field_aligns[1]); - union_type->abi_size = next_field_offset(field2_offset, union_type->abi_align, field_sizes[1], union_type->abi_align); - union_type->size_in_bits = union_type->abi_size * 8; - } - } else { - union_type->abi_size = union_abi_size; - union_type->size_in_bits = union_size_in_bits; - } - - return ErrorNone; -} - -static Error type_is_valid_extern_enum_tag(CodeGen *g, ZigType *ty, bool *result) { - // Only integer types are allowed by the C ABI - if(ty->id != ZigTypeIdInt) { - *result = false; - return ErrorNone; - } - - // According to the ANSI C standard the enumeration type should be either a - // signed char, a signed integer or an unsigned one. But GCC/Clang allow - // other integral types as a compiler extension so let's accommodate them - // aswell. - return type_allowed_in_extern(g, ty, ExternPositionOther, result); -} - -static Error resolve_enum_zero_bits(CodeGen *g, ZigType *enum_type) { - Error err; - assert(enum_type->id == ZigTypeIdEnum); - - if (enum_type->data.enumeration.resolve_status == ResolveStatusInvalid) - return ErrorSemanticAnalyzeFail; - if (enum_type->data.enumeration.resolve_status >= ResolveStatusZeroBitsKnown) - return ErrorNone; - - AstNode *decl_node = enum_type->data.enumeration.decl_node; - - if (enum_type->data.enumeration.resolve_loop_flag) { - if (enum_type->data.enumeration.resolve_status != ResolveStatusInvalid) { - enum_type->data.enumeration.resolve_status = ResolveStatusInvalid; - add_node_error(g, decl_node, - buf_sprintf("enum '%s' depends on itself", - buf_ptr(&enum_type->name))); - } - return ErrorSemanticAnalyzeFail; - } - - enum_type->data.enumeration.resolve_loop_flag = true; - - uint32_t field_count; - if (decl_node->type == NodeTypeContainerDecl) { - assert(!enum_type->data.enumeration.fields); - field_count = (uint32_t)decl_node->data.container_decl.fields.length; - } else { - field_count = enum_type->data.enumeration.src_field_count + enum_type->data.enumeration.non_exhaustive; - } - - if (field_count == 0) { - add_node_error(g, decl_node, buf_sprintf("enums must have 1 or more fields")); - enum_type->data.enumeration.src_field_count = field_count; - enum_type->data.enumeration.fields = nullptr; - enum_type->data.enumeration.resolve_status = ResolveStatusInvalid; - return ErrorSemanticAnalyzeFail; - } - - Scope *scope = &enum_type->data.enumeration.decls_scope->base; - - ZigType *tag_int_type; - if (enum_type->data.enumeration.layout == ContainerLayoutExtern) { - tag_int_type = get_c_int_type(g, CIntTypeInt); - } else { - tag_int_type = get_smallest_unsigned_int_type(g, field_count - 1); - } - - enum_type->size_in_bits = tag_int_type->size_in_bits; - enum_type->abi_size = tag_int_type->abi_size; - enum_type->abi_align = tag_int_type->abi_align; - - ZigType *wanted_tag_int_type = nullptr; - if (decl_node->type == NodeTypeContainerDecl) { - if (decl_node->data.container_decl.init_arg_expr != nullptr) { - wanted_tag_int_type = analyze_type_expr(g, scope, decl_node->data.container_decl.init_arg_expr); - enum_type->data.enumeration.has_explicit_tag_type = true; - } - } else { - wanted_tag_int_type = enum_type->data.enumeration.tag_int_type; - enum_type->data.enumeration.has_explicit_tag_type = true; - } - - if (wanted_tag_int_type != nullptr) { - if (type_is_invalid(wanted_tag_int_type)) { - enum_type->data.enumeration.resolve_status = ResolveStatusInvalid; - } else if (wanted_tag_int_type->id != ZigTypeIdInt && - wanted_tag_int_type->id != ZigTypeIdComptimeInt) { - enum_type->data.enumeration.resolve_status = ResolveStatusInvalid; - add_node_error(g, decl_node->data.container_decl.init_arg_expr, - buf_sprintf("expected integer, found '%s'", buf_ptr(&wanted_tag_int_type->name))); - } else { - if (enum_type->data.enumeration.layout == ContainerLayoutExtern) { - bool ok_type; - if ((err = type_is_valid_extern_enum_tag(g, wanted_tag_int_type, &ok_type))) { - enum_type->data.enumeration.resolve_status = ResolveStatusInvalid; - return err; - } - if (!ok_type) { - enum_type->data.enumeration.resolve_status = ResolveStatusInvalid; - ErrorMsg *msg = add_node_error(g, decl_node->data.container_decl.init_arg_expr, - buf_sprintf("'%s' is not a valid tag type for an extern enum", - buf_ptr(&wanted_tag_int_type->name))); - add_error_note(g, msg, decl_node->data.container_decl.init_arg_expr, - buf_sprintf("any integral type of size 8, 16, 32, 64 or 128 bit is valid")); - return ErrorSemanticAnalyzeFail; - } - } - tag_int_type = wanted_tag_int_type; - } - } - - enum_type->data.enumeration.tag_int_type = tag_int_type; - enum_type->size_in_bits = tag_int_type->size_in_bits; - enum_type->abi_size = tag_int_type->abi_size; - enum_type->abi_align = tag_int_type->abi_align; - - BigInt bi_one; - bigint_init_unsigned(&bi_one, 1); - - if (decl_node->type == NodeTypeContainerDecl) { - AstNode *last_field_node = decl_node->data.container_decl.fields.at(field_count - 1); - if (buf_eql_str(last_field_node->data.struct_field.name, "_")) { - if (last_field_node->data.struct_field.value != nullptr) { - add_node_error(g, last_field_node, buf_sprintf("value assigned to '_' field of non-exhaustive enum")); - enum_type->data.enumeration.resolve_status = ResolveStatusInvalid; - } - if (decl_node->data.container_decl.init_arg_expr == nullptr) { - add_node_error(g, decl_node, buf_sprintf("non-exhaustive enum must specify size")); - enum_type->data.enumeration.resolve_status = ResolveStatusInvalid; - } - enum_type->data.enumeration.non_exhaustive = true; - } else { - enum_type->data.enumeration.non_exhaustive = false; - } - } - - if (enum_type->data.enumeration.non_exhaustive) { - field_count -= 1; - if (field_count > 1 && log2_u64(field_count) == enum_type->size_in_bits) { - add_node_error(g, decl_node, buf_sprintf("non-exhaustive enum specifies every value")); - enum_type->data.enumeration.resolve_status = ResolveStatusInvalid; - } - } - - if (decl_node->type == NodeTypeContainerDecl) { - enum_type->data.enumeration.src_field_count = field_count; - enum_type->data.enumeration.fields = heap::c_allocator.allocate(field_count); - enum_type->data.enumeration.fields_by_name.init(field_count); - - HashMap occupied_tag_values = {}; - occupied_tag_values.init(field_count); - - TypeEnumField *last_enum_field = nullptr; - - for (uint32_t field_i = 0; field_i < field_count; field_i += 1) { - AstNode *field_node = decl_node->data.container_decl.fields.at(field_i); - TypeEnumField *type_enum_field = &enum_type->data.enumeration.fields[field_i]; - type_enum_field->name = field_node->data.struct_field.name; - type_enum_field->decl_index = field_i; - type_enum_field->decl_node = field_node; - - if (field_node->data.struct_field.type != nullptr) { - ErrorMsg *msg = add_node_error(g, field_node->data.struct_field.type, - buf_sprintf("structs and unions, not enums, support field types")); - add_error_note(g, msg, decl_node, - buf_sprintf("consider 'union(enum)' here")); - } else if (field_node->data.struct_field.align_expr != nullptr) { - ErrorMsg *msg = add_node_error(g, field_node->data.struct_field.align_expr, - buf_sprintf("structs and unions, not enums, support field alignment")); - add_error_note(g, msg, decl_node, - buf_sprintf("consider 'union(enum)' here")); - } - - if (buf_eql_str(type_enum_field->name, "_")) { - add_node_error(g, field_node, buf_sprintf("'_' field of non-exhaustive enum must be last")); - enum_type->data.enumeration.resolve_status = ResolveStatusInvalid; - } - - auto field_entry = enum_type->data.enumeration.fields_by_name.put_unique(type_enum_field->name, type_enum_field); - if (field_entry != nullptr) { - ErrorMsg *msg = add_node_error(g, field_node, - buf_sprintf("duplicate enum field: '%s'", buf_ptr(type_enum_field->name))); - add_error_note(g, msg, field_entry->value->decl_node, buf_sprintf("other field here")); - enum_type->data.enumeration.resolve_status = ResolveStatusInvalid; - continue; - } - - AstNode *tag_value = field_node->data.struct_field.value; - - if (tag_value != nullptr) { - // A user-specified value is available - ZigValue *result = analyze_const_value(g, scope, tag_value, tag_int_type, - nullptr, UndefBad); - if (type_is_invalid(result->type)) { - enum_type->data.enumeration.resolve_status = ResolveStatusInvalid; - continue; - } - - assert(result->special != ConstValSpecialRuntime); - assert(result->type->id == ZigTypeIdInt || result->type->id == ZigTypeIdComptimeInt); - - bigint_init_bigint(&type_enum_field->value, &result->data.x_bigint); - } else { - // No value was explicitly specified: allocate the last value + 1 - // or, if this is the first element, zero - if (last_enum_field != nullptr) { - bigint_add(&type_enum_field->value, &last_enum_field->value, &bi_one); - } else { - bigint_init_unsigned(&type_enum_field->value, 0); - } - - // Make sure we can represent this number with tag_int_type - if (!bigint_fits_in_bits(&type_enum_field->value, - tag_int_type->size_in_bits, - tag_int_type->data.integral.is_signed)) { - enum_type->data.enumeration.resolve_status = ResolveStatusInvalid; - - Buf *val_buf = buf_alloc(); - bigint_append_buf(val_buf, &type_enum_field->value, 10); - add_node_error(g, field_node, - buf_sprintf("enumeration value %s too large for type '%s'", - buf_ptr(val_buf), buf_ptr(&tag_int_type->name))); - - break; - } - } - - // Make sure the value is unique - auto entry = occupied_tag_values.put_unique(type_enum_field->value, field_node); - if (entry != nullptr && enum_type->data.enumeration.layout != ContainerLayoutExtern) { - enum_type->data.enumeration.resolve_status = ResolveStatusInvalid; - - Buf *val_buf = buf_alloc(); - bigint_append_buf(val_buf, &type_enum_field->value, 10); - - ErrorMsg *msg = add_node_error(g, field_node, - buf_sprintf("enum tag value %s already taken", buf_ptr(val_buf))); - add_error_note(g, msg, entry->value, - buf_sprintf("other occurrence here")); - } - - last_enum_field = type_enum_field; - } - occupied_tag_values.deinit(); - } - - if (enum_type->data.enumeration.resolve_status == ResolveStatusInvalid) - return ErrorSemanticAnalyzeFail; - - enum_type->data.enumeration.resolve_loop_flag = false; - enum_type->data.enumeration.resolve_status = ResolveStatusSizeKnown; - - return ErrorNone; -} - -static Error resolve_struct_zero_bits(CodeGen *g, ZigType *struct_type) { - assert(struct_type->id == ZigTypeIdStruct); - - Error err; - - if (struct_type->data.structure.resolve_status == ResolveStatusInvalid) - return ErrorSemanticAnalyzeFail; - if (struct_type->data.structure.resolve_status >= ResolveStatusZeroBitsKnown) - return ErrorNone; - - AstNode *decl_node = struct_type->data.structure.decl_node; - - if (decl_node->data.container_decl.unsupported_explicit_backing_int) { - add_node_error(g, decl_node, buf_create_from_str( - "the stage1 compiler does not support explicit backing integer types on packed structs")); - return ErrorSemanticAnalyzeFail; - } - - if (struct_type->data.structure.resolve_loop_flag_zero_bits) { - if (struct_type->data.structure.resolve_status != ResolveStatusInvalid) { - struct_type->data.structure.resolve_status = ResolveStatusInvalid; - add_node_error(g, decl_node, - buf_sprintf("struct '%s' depends on itself", - buf_ptr(&struct_type->name))); - } - return ErrorSemanticAnalyzeFail; - } - struct_type->data.structure.resolve_loop_flag_zero_bits = true; - - size_t field_count; - if (decl_node->type == NodeTypeContainerDecl) { - field_count = decl_node->data.container_decl.fields.length; - struct_type->data.structure.src_field_count = (uint32_t)field_count; - - src_assert(struct_type->data.structure.fields == nullptr, decl_node); - struct_type->data.structure.fields = alloc_type_struct_fields(field_count); - } else if (is_anon_container(struct_type) || struct_type->data.structure.created_by_at_type) { - field_count = struct_type->data.structure.src_field_count; - - src_assert(field_count == 0 || struct_type->data.structure.fields != nullptr, decl_node); - } else zig_unreachable(); - - struct_type->data.structure.fields_by_name.init(field_count); - - Scope *scope = &struct_type->data.structure.decls_scope->base; - - size_t gen_field_index = 0; - for (size_t i = 0; i < field_count; i += 1) { - TypeStructField *type_struct_field = struct_type->data.structure.fields[i]; - - AstNode *field_node; - if (decl_node->type == NodeTypeContainerDecl) { - field_node = decl_node->data.container_decl.fields.at(i); - type_struct_field->name = field_node->data.struct_field.name; - type_struct_field->decl_node = field_node; - if (field_node->data.struct_field.comptime_token != 0) { - if (field_node->data.struct_field.value == nullptr) { - add_token_error(g, field_node->owner, - field_node->data.struct_field.comptime_token, - buf_sprintf("comptime struct field missing initialization value")); - struct_type->data.structure.resolve_status = ResolveStatusInvalid; - return ErrorSemanticAnalyzeFail; - } - type_struct_field->is_comptime = true; - } - - if (field_node->data.struct_field.type == nullptr) { - add_node_error(g, field_node, buf_sprintf("struct field missing type")); - struct_type->data.structure.resolve_status = ResolveStatusInvalid; - return ErrorSemanticAnalyzeFail; - } - } else if (is_anon_container(struct_type) || struct_type->data.structure.created_by_at_type) { - field_node = type_struct_field->decl_node; - - src_assert(type_struct_field->type_entry != nullptr, field_node); - } else zig_unreachable(); - - auto field_entry = struct_type->data.structure.fields_by_name.put_unique(type_struct_field->name, type_struct_field); - if (field_entry != nullptr) { - ErrorMsg *msg = add_node_error(g, field_node, - buf_sprintf("duplicate struct field: '%s'", buf_ptr(type_struct_field->name))); - add_error_note(g, msg, field_entry->value->decl_node, buf_sprintf("other field here")); - struct_type->data.structure.resolve_status = ResolveStatusInvalid; - return ErrorSemanticAnalyzeFail; - } - - ZigValue *field_type_val; - if (decl_node->type == NodeTypeContainerDecl) { - field_type_val = analyze_const_value(g, scope, - field_node->data.struct_field.type, g->builtin_types.entry_type, nullptr, LazyOkNoUndef); - if (type_is_invalid(field_type_val->type)) { - struct_type->data.structure.resolve_status = ResolveStatusInvalid; - return ErrorSemanticAnalyzeFail; - } - assert(field_type_val->special != ConstValSpecialRuntime); - type_struct_field->type_val = field_type_val; - if (struct_type->data.structure.resolve_status == ResolveStatusInvalid) - return ErrorSemanticAnalyzeFail; - } else if (is_anon_container(struct_type) || struct_type->data.structure.created_by_at_type) { - field_type_val = type_struct_field->type_val; - } else zig_unreachable(); - - bool field_is_opaque_type; - if ((err = type_val_resolve_is_opaque_type(g, field_type_val, &field_is_opaque_type))) { - struct_type->data.structure.resolve_status = ResolveStatusInvalid; - return ErrorSemanticAnalyzeFail; - } - if (field_is_opaque_type) { - add_node_error(g, field_node, - buf_sprintf("opaque types have unknown size and therefore cannot be directly embedded in structs")); - struct_type->data.structure.resolve_status = ResolveStatusInvalid; - return ErrorSemanticAnalyzeFail; - } - - type_struct_field->src_index = i; - type_struct_field->gen_index = SIZE_MAX; - - if (type_struct_field->is_comptime) - continue; - - switch (type_val_resolve_requires_comptime(g, field_type_val)) { - case ReqCompTimeYes: - struct_type->data.structure.requires_comptime = true; - break; - case ReqCompTimeInvalid: - if (g->trace_err != nullptr) { - g->trace_err = add_error_note(g, g->trace_err, field_node, - buf_create_from_str("while checking this field")); - } - struct_type->data.structure.resolve_status = ResolveStatusInvalid; - return ErrorSemanticAnalyzeFail; - case ReqCompTimeNo: - break; - } - - bool field_is_zero_bits; - if ((err = type_val_resolve_zero_bits(g, field_type_val, struct_type, nullptr, &field_is_zero_bits))) { - struct_type->data.structure.resolve_status = ResolveStatusInvalid; - return ErrorSemanticAnalyzeFail; - } - if (field_is_zero_bits) - continue; - - type_struct_field->gen_index = gen_field_index; - gen_field_index += 1; - } - - struct_type->data.structure.resolve_loop_flag_zero_bits = false; - struct_type->data.structure.gen_field_count = (uint32_t)gen_field_index; - if (gen_field_index != 0) { - struct_type->abi_size = SIZE_MAX; - struct_type->size_in_bits = SIZE_MAX; - } - - if (struct_type->data.structure.resolve_status == ResolveStatusInvalid) - return ErrorSemanticAnalyzeFail; - - struct_type->data.structure.resolve_status = ResolveStatusZeroBitsKnown; - return ErrorNone; -} - -static Error resolve_struct_alignment(CodeGen *g, ZigType *struct_type) { - assert(struct_type->id == ZigTypeIdStruct); - - Error err; - - if (struct_type->data.structure.resolve_status == ResolveStatusInvalid) - return ErrorSemanticAnalyzeFail; - if (struct_type->data.structure.resolve_status >= ResolveStatusAlignmentKnown) - return ErrorNone; - if ((err = resolve_struct_zero_bits(g, struct_type))) - return err; - if (struct_type->data.structure.resolve_status >= ResolveStatusAlignmentKnown) - return ErrorNone; - - AstNode *decl_node = struct_type->data.structure.decl_node; - - if (struct_type->data.structure.resolve_loop_flag_other) { - if (struct_type->data.structure.resolve_status != ResolveStatusInvalid) { - struct_type->data.structure.resolve_status = ResolveStatusInvalid; - add_node_error(g, decl_node, - buf_sprintf("struct '%s' depends on itself", buf_ptr(&struct_type->name))); - } - return ErrorSemanticAnalyzeFail; - } - - struct_type->data.structure.resolve_loop_flag_other = true; - - size_t field_count = struct_type->data.structure.src_field_count; - bool packed = struct_type->data.structure.layout == ContainerLayoutPacked; - - for (size_t i = 0; i < field_count; i += 1) { - TypeStructField *field = struct_type->data.structure.fields[i]; - if (field->gen_index == SIZE_MAX) - continue; - - AstNode *align_expr = (field->decl_node->type == NodeTypeStructField) ? - field->decl_node->data.struct_field.align_expr : nullptr; - if (align_expr != nullptr) { - if (!analyze_const_align(g, &struct_type->data.structure.decls_scope->base, align_expr, - &field->align)) - { - struct_type->data.structure.resolve_status = ResolveStatusInvalid; - return ErrorSemanticAnalyzeFail; - } - } else if (packed) { - field->align = 1; - } else { - if ((err = type_val_resolve_abi_align(g, field->decl_node, field->type_val, &field->align))) { - if (g->trace_err != nullptr) { - g->trace_err = add_error_note(g, g->trace_err, field->decl_node, - buf_create_from_str("while checking this field")); - } - struct_type->data.structure.resolve_status = ResolveStatusInvalid; - return err; - } - if (struct_type->data.structure.resolve_status == ResolveStatusInvalid) - return ErrorSemanticAnalyzeFail; - } - - if (field->align > struct_type->abi_align) { - struct_type->abi_align = field->align; - } - } - - if (!type_has_bits(g, struct_type)) { - assert(struct_type->abi_align == 0); - } - - struct_type->data.structure.resolve_loop_flag_other = false; - - if (struct_type->data.structure.resolve_status == ResolveStatusInvalid) { - return ErrorSemanticAnalyzeFail; - } - - struct_type->data.structure.resolve_status = ResolveStatusAlignmentKnown; - return ErrorNone; -} - -static Error resolve_union_zero_bits(CodeGen *g, ZigType *union_type) { - assert(union_type->id == ZigTypeIdUnion); - - Error err; - - if (union_type->data.unionation.resolve_status == ResolveStatusInvalid) - return ErrorSemanticAnalyzeFail; - - if (union_type->data.unionation.resolve_status >= ResolveStatusZeroBitsKnown) - return ErrorNone; - - AstNode *decl_node = union_type->data.unionation.decl_node; - - if (union_type->data.unionation.resolve_loop_flag_zero_bits) { - if (union_type->data.unionation.resolve_status != ResolveStatusInvalid) { - union_type->data.unionation.resolve_status = ResolveStatusInvalid; - add_node_error(g, decl_node, - buf_sprintf("union '%s' depends on itself", - buf_ptr(&union_type->name))); - } - return ErrorSemanticAnalyzeFail; - } - - union_type->data.unionation.resolve_loop_flag_zero_bits = true; - - uint32_t field_count; - if (decl_node->type == NodeTypeContainerDecl) { - assert(union_type->data.unionation.fields == nullptr); - field_count = (uint32_t)decl_node->data.container_decl.fields.length; - union_type->data.unionation.src_field_count = field_count; - union_type->data.unionation.fields = heap::c_allocator.allocate(field_count); - union_type->data.unionation.fields_by_name.init(field_count); - } else { - field_count = union_type->data.unionation.src_field_count; - assert(field_count == 0 || union_type->data.unionation.fields != nullptr); - } - - if (field_count == 0) { - add_node_error(g, decl_node, buf_sprintf("unions must have 1 or more fields")); - union_type->data.unionation.src_field_count = field_count; - union_type->data.unionation.resolve_status = ResolveStatusInvalid; - return ErrorSemanticAnalyzeFail; - } - - Scope *scope = &union_type->data.unionation.decls_scope->base; - - HashMap occupied_tag_values = {}; - - bool is_auto_enum; // union(enum) or union(enum(expr)) - bool is_explicit_enum; // union(expr) - AstNode *enum_type_node; // expr in union(enum(expr)) or union(expr) - if (decl_node->type == NodeTypeContainerDecl) { - is_auto_enum = decl_node->data.container_decl.auto_enum; - is_explicit_enum = decl_node->data.container_decl.init_arg_expr != nullptr; - enum_type_node = decl_node->data.container_decl.init_arg_expr; - } else { - is_auto_enum = false; - is_explicit_enum = union_type->data.unionation.tag_type != nullptr; - enum_type_node = nullptr; - } - union_type->data.unionation.have_explicit_tag_type = is_auto_enum || is_explicit_enum; - - bool is_auto_layout = union_type->data.unionation.layout == ContainerLayoutAuto; - bool want_safety = (field_count >= 2) - && (is_auto_layout || is_explicit_enum) - && !(g->build_mode == BuildModeFastRelease || g->build_mode == BuildModeSmallRelease); - ZigType *tag_type; - bool create_enum_type = is_auto_enum || (!is_explicit_enum && want_safety); - bool *covered_enum_fields; - bool *is_zero_bits = heap::c_allocator.allocate(field_count); - if (create_enum_type) { - occupied_tag_values.init(field_count); - - ZigType *tag_int_type; - if (enum_type_node != nullptr) { - tag_int_type = analyze_type_expr(g, scope, enum_type_node); - if (type_is_invalid(tag_int_type)) { - union_type->data.unionation.resolve_status = ResolveStatusInvalid; - return ErrorSemanticAnalyzeFail; - } - if (tag_int_type->id != ZigTypeIdInt && tag_int_type->id != ZigTypeIdComptimeInt) { - add_node_error(g, enum_type_node, - buf_sprintf("expected integer tag type, found '%s'", buf_ptr(&tag_int_type->name))); - union_type->data.unionation.resolve_status = ResolveStatusInvalid; - return ErrorSemanticAnalyzeFail; - } - if (tag_int_type->id == ZigTypeIdInt) { - BigInt bi; - bigint_init_unsigned(&bi, field_count - 1); - if (!bigint_fits_in_bits(&bi, - tag_int_type->data.integral.bit_count, - tag_int_type->data.integral.is_signed)) - { - ErrorMsg *msg = add_node_error(g, enum_type_node, - buf_sprintf("specified integer tag type cannot represent every field")); - add_error_note(g, msg, enum_type_node, - buf_sprintf("type %s cannot fit values in range 0...%" PRIu32, - buf_ptr(&tag_int_type->name), field_count - 1)); - union_type->data.unionation.resolve_status = ResolveStatusInvalid; - return ErrorSemanticAnalyzeFail; - } - } - } else { - tag_int_type = get_smallest_unsigned_int_type(g, field_count - 1); - } - - tag_type = new_type_table_entry(ZigTypeIdEnum); - buf_resize(&tag_type->name, 0); - buf_appendf(&tag_type->name, "@typeInfo(%s).Union.tag_type.?", buf_ptr(&union_type->name)); - tag_type->llvm_type = tag_int_type->llvm_type; - tag_type->llvm_di_type = tag_int_type->llvm_di_type; - tag_type->abi_size = tag_int_type->abi_size; - tag_type->abi_align = tag_int_type->abi_align; - tag_type->size_in_bits = tag_int_type->size_in_bits; - - tag_type->data.enumeration.tag_int_type = tag_int_type; - tag_type->data.enumeration.resolve_status = ResolveStatusSizeKnown; - tag_type->data.enumeration.decl_node = decl_node; - tag_type->data.enumeration.layout = ContainerLayoutAuto; - tag_type->data.enumeration.src_field_count = field_count; - tag_type->data.enumeration.fields = heap::c_allocator.allocate(field_count); - tag_type->data.enumeration.fields_by_name.init(field_count); - tag_type->data.enumeration.decls_scope = create_decls_scope( - g, nullptr, nullptr, tag_type, get_scope_import(scope), &tag_type->name); - } else if (enum_type_node != nullptr) { - tag_type = analyze_type_expr(g, scope, enum_type_node); - } else { - if (decl_node->type == NodeTypeContainerDecl) { - tag_type = nullptr; - } else { - tag_type = union_type->data.unionation.tag_type; - } - } - if (tag_type != nullptr) { - if (type_is_invalid(tag_type)) { - union_type->data.unionation.resolve_status = ResolveStatusInvalid; - return ErrorSemanticAnalyzeFail; - } - if (tag_type->id != ZigTypeIdEnum) { - union_type->data.unionation.resolve_status = ResolveStatusInvalid; - add_node_error(g, enum_type_node != nullptr ? enum_type_node : decl_node, - buf_sprintf("expected enum tag type, found '%s'", buf_ptr(&tag_type->name))); - return ErrorSemanticAnalyzeFail; - } - if ((err = type_resolve(g, tag_type, ResolveStatusAlignmentKnown))) { - assert(g->errors.length != 0); - return err; - } - covered_enum_fields = heap::c_allocator.allocate(tag_type->data.enumeration.src_field_count); - } - union_type->data.unionation.tag_type = tag_type; - - for (uint32_t i = 0; i < field_count; i += 1) { - TypeUnionField *union_field = &union_type->data.unionation.fields[i]; - if (decl_node->type == NodeTypeContainerDecl) { - AstNode *field_node = decl_node->data.container_decl.fields.at(i); - union_field->name = field_node->data.struct_field.name; - union_field->decl_node = field_node; - union_field->gen_index = UINT32_MAX; - is_zero_bits[i] = false; - - auto field_entry = union_type->data.unionation.fields_by_name.put_unique(union_field->name, union_field); - if (field_entry != nullptr) { - ErrorMsg *msg = add_node_error(g, union_field->decl_node, - buf_sprintf("duplicate union field: '%s'", buf_ptr(union_field->name))); - add_error_note(g, msg, field_entry->value->decl_node, buf_sprintf("other field here")); - union_type->data.unionation.resolve_status = ResolveStatusInvalid; - return ErrorSemanticAnalyzeFail; - } - - if (field_node->data.struct_field.type == nullptr) { - if (is_auto_enum || is_explicit_enum) { - union_field->type_entry = g->builtin_types.entry_void; - is_zero_bits[i] = true; - } else { - add_node_error(g, field_node, buf_sprintf("union field missing type")); - union_type->data.unionation.resolve_status = ResolveStatusInvalid; - return ErrorSemanticAnalyzeFail; - } - } else { - ZigValue *field_type_val = analyze_const_value(g, scope, - field_node->data.struct_field.type, g->builtin_types.entry_type, nullptr, LazyOkNoUndef); - if (type_is_invalid(field_type_val->type)) { - union_type->data.unionation.resolve_status = ResolveStatusInvalid; - return ErrorSemanticAnalyzeFail; - } - assert(field_type_val->special != ConstValSpecialRuntime); - union_field->type_val = field_type_val; - } - - if (field_node->data.struct_field.value != nullptr && !is_auto_enum) { - ErrorMsg *msg = add_node_error(g, field_node->data.struct_field.value, - buf_create_from_str("untagged union field assignment")); - add_error_note(g, msg, decl_node, buf_create_from_str("consider 'union(enum)' here")); - } - } - - if (union_field->type_val != nullptr) { - bool field_is_opaque_type; - if ((err = type_val_resolve_is_opaque_type(g, union_field->type_val, &field_is_opaque_type))) { - union_type->data.unionation.resolve_status = ResolveStatusInvalid; - return ErrorSemanticAnalyzeFail; - } - if (field_is_opaque_type) { - add_node_error(g, union_field->decl_node, - buf_create_from_str( - "opaque types have unknown size and therefore cannot be directly embedded in unions")); - union_type->data.unionation.resolve_status = ResolveStatusInvalid; - return ErrorSemanticAnalyzeFail; - } - - switch (type_val_resolve_requires_comptime(g, union_field->type_val)) { - case ReqCompTimeInvalid: - if (g->trace_err != nullptr) { - g->trace_err = add_error_note(g, g->trace_err, union_field->decl_node, - buf_create_from_str("while checking this field")); - } - union_type->data.unionation.resolve_status = ResolveStatusInvalid; - return ErrorSemanticAnalyzeFail; - case ReqCompTimeYes: - union_type->data.unionation.requires_comptime = true; - break; - case ReqCompTimeNo: - break; - } - - if ((err = type_val_resolve_zero_bits(g, union_field->type_val, union_type, nullptr, &is_zero_bits[i]))) { - union_type->data.unionation.resolve_status = ResolveStatusInvalid; - return ErrorSemanticAnalyzeFail; - } - } - - if (create_enum_type) { - union_field->enum_field = &tag_type->data.enumeration.fields[i]; - union_field->enum_field->name = union_field->name; - union_field->enum_field->decl_index = i; - union_field->enum_field->decl_node = union_field->decl_node; - - auto prev_entry = tag_type->data.enumeration.fields_by_name.put_unique(union_field->enum_field->name, union_field->enum_field); - assert(prev_entry == nullptr); // caught by union de-duplicator above - - AstNode *tag_value = decl_node->type == NodeTypeContainerDecl - ? union_field->decl_node->data.struct_field.value : nullptr; - - // In this first pass we resolve explicit tag values. - // In a second pass we will fill in the unspecified ones. - if (tag_value != nullptr) { - ZigType *tag_int_type = tag_type->data.enumeration.tag_int_type; - ZigValue *result = analyze_const_value(g, scope, tag_value, tag_int_type, - nullptr, UndefBad); - if (type_is_invalid(result->type)) { - union_type->data.unionation.resolve_status = ResolveStatusInvalid; - return ErrorSemanticAnalyzeFail; - } - assert(result->special != ConstValSpecialRuntime); - assert(result->type->id == ZigTypeIdInt); - auto entry = occupied_tag_values.put_unique(result->data.x_bigint, tag_value); - if (entry == nullptr) { - bigint_init_bigint(&union_field->enum_field->value, &result->data.x_bigint); - } else { - Buf *val_buf = buf_alloc(); - bigint_append_buf(val_buf, &result->data.x_bigint, 10); - - ErrorMsg *msg = add_node_error(g, tag_value, - buf_sprintf("enum tag value %s already taken", buf_ptr(val_buf))); - add_error_note(g, msg, entry->value, - buf_sprintf("other occurrence here")); - union_type->data.unionation.resolve_status = ResolveStatusInvalid; - return ErrorSemanticAnalyzeFail; - } - } - } else if (tag_type != nullptr) { - union_field->enum_field = find_enum_type_field(tag_type, union_field->name); - if (union_field->enum_field == nullptr) { - ErrorMsg *msg = add_node_error(g, union_field->decl_node, - buf_sprintf("enum field not found: '%s'", buf_ptr(union_field->name))); - add_error_note(g, msg, tag_type->data.enumeration.decl_node, - buf_sprintf("enum declared here")); - union_type->data.unionation.resolve_status = ResolveStatusInvalid; - return ErrorSemanticAnalyzeFail; - } - covered_enum_fields[union_field->enum_field->decl_index] = true; - } else { - union_field->enum_field = heap::c_allocator.create(); - union_field->enum_field->name = union_field->name; - union_field->enum_field->decl_index = i; - bigint_init_unsigned(&union_field->enum_field->value, i); - } - assert(union_field->enum_field != nullptr); - } - - uint32_t gen_field_index = 0; - for (uint32_t i = 0; i < field_count; i += 1) { - TypeUnionField *union_field = &union_type->data.unionation.fields[i]; - if (!is_zero_bits[i]) { - union_field->gen_index = gen_field_index; - gen_field_index += 1; - } - } - heap::c_allocator.deallocate(is_zero_bits, field_count); - - bool src_have_tag = is_auto_enum || is_explicit_enum; - - if (src_have_tag && union_type->data.unionation.layout != ContainerLayoutAuto) { - const char *qual_str; - switch (union_type->data.unionation.layout) { - case ContainerLayoutAuto: - zig_unreachable(); - case ContainerLayoutPacked: - qual_str = "packed"; - break; - case ContainerLayoutExtern: - qual_str = "extern"; - break; - } - AstNode *source_node = enum_type_node != nullptr ? enum_type_node : decl_node; - add_node_error(g, source_node, - buf_sprintf("%s union does not support enum tag type", qual_str)); - union_type->data.unionation.resolve_status = ResolveStatusInvalid; - return ErrorSemanticAnalyzeFail; - } - - if (create_enum_type) { - if (decl_node->type == NodeTypeContainerDecl) { - // Now iterate again and populate the unspecified tag values - uint32_t next_maybe_unoccupied_index = 0; - - for (uint32_t field_i = 0; field_i < field_count; field_i += 1) { - AstNode *field_node = decl_node->data.container_decl.fields.at(field_i); - TypeUnionField *union_field = &union_type->data.unionation.fields[field_i]; - AstNode *tag_value = field_node->data.struct_field.value; - - if (tag_value == nullptr) { - if (occupied_tag_values.size() == 0) { - bigint_init_unsigned(&union_field->enum_field->value, next_maybe_unoccupied_index); - next_maybe_unoccupied_index += 1; - } else { - BigInt proposed_value; - for (;;) { - bigint_init_unsigned(&proposed_value, next_maybe_unoccupied_index); - next_maybe_unoccupied_index += 1; - auto entry = occupied_tag_values.put_unique(proposed_value, field_node); - if (entry != nullptr) { - continue; - } - break; - } - bigint_init_bigint(&union_field->enum_field->value, &proposed_value); - } - } - } - } - } else if (tag_type != nullptr) { - for (uint32_t i = 0; i < tag_type->data.enumeration.src_field_count; i += 1) { - TypeEnumField *enum_field = &tag_type->data.enumeration.fields[i]; - if (!covered_enum_fields[i]) { - ErrorMsg *msg = add_node_error(g, decl_node, - buf_sprintf("enum field missing: '%s'", buf_ptr(enum_field->name))); - if (decl_node->type == NodeTypeContainerDecl) { - AstNode *enum_decl_node = tag_type->data.enumeration.decl_node; - AstNode *field_node = enum_decl_node->data.container_decl.fields.at(i); - add_error_note(g, msg, field_node, - buf_sprintf("declared here")); - } - union_type->data.unionation.resolve_status = ResolveStatusInvalid; - } - } - heap::c_allocator.deallocate(covered_enum_fields, tag_type->data.enumeration.src_field_count); - } - - if (union_type->data.unionation.resolve_status == ResolveStatusInvalid) { - return ErrorSemanticAnalyzeFail; - } - - union_type->data.unionation.resolve_loop_flag_zero_bits = false; - - union_type->data.unionation.gen_field_count = gen_field_index; - bool zero_bits = gen_field_index == 0 && - (tag_type == nullptr || !type_has_bits(g, tag_type)); - if (!zero_bits) { - union_type->abi_size = SIZE_MAX; - union_type->size_in_bits = SIZE_MAX; - } - - union_type->data.unionation.resolve_status = ResolveStatusZeroBitsKnown; - - return ErrorNone; -} - -static Error resolve_opaque_type(CodeGen *g, ZigType *opaque_type) { - Error err = ErrorNone; - AstNode *container_node = opaque_type->data.opaque.decl_node; - if (container_node != nullptr) { - assert(container_node->type == NodeTypeContainerDecl); - AstNodeContainerDecl *container_decl = &container_node->data.container_decl; - for (size_t i = 0; i < container_decl->fields.length; i++) { - AstNode *field_node = container_decl->fields.items[i]; - add_node_error(g, field_node, buf_create_from_str("opaque types cannot have fields")); - err = ErrorSemanticAnalyzeFail; - } - } - return err; -} - -void append_namespace_qualification(CodeGen *g, Buf *buf, ZigType *container_type) { - if (g->root_import == container_type || buf_len(&container_type->name) == 0) return; - buf_append_buf(buf, &container_type->name); - buf_append_char(buf, NAMESPACE_SEP_CHAR); -} - -static void get_fully_qualified_decl_name(CodeGen *g, Buf *buf, Tld *tld, bool is_test) { - buf_resize(buf, 0); - - Scope *scope = tld->parent_scope; - while (scope->id != ScopeIdDecls) { - scope = scope->parent; - } - ScopeDecls *decls_scope = reinterpret_cast(scope); - append_namespace_qualification(g, buf, decls_scope->container_type); - if (is_test) { - buf_append_str(buf, "test \""); - buf_append_buf(buf, tld->name); - buf_append_char(buf, '"'); - } else { - buf_append_buf(buf, tld->name); - } -} - -static ZigFn *create_fn_raw(CodeGen *g, bool is_noinline) { - ZigFn *fn_entry = heap::c_allocator.create(); - fn_entry->stage1_zir = heap::c_allocator.create(); - fn_entry->is_noinline = is_noinline; - - return fn_entry; -} - -ZigFn *create_fn(CodeGen *g, AstNode *proto_node) { - assert(proto_node->type == NodeTypeFnProto); - AstNodeFnProto *fn_proto = &proto_node->data.fn_proto; - - ZigFn *fn_entry = create_fn_raw(g, fn_proto->fn_inline == FnInlineNever); - - fn_entry->proto_node = proto_node; - fn_entry->body_node = (proto_node->data.fn_proto.fn_def_node == nullptr) ? nullptr : - proto_node->data.fn_proto.fn_def_node->data.fn_def.body; - - fn_entry->analyzed_executable.source_node = fn_entry->body_node; - - return fn_entry; -} - -ZigType *get_test_fn_type(CodeGen *g) { - if (g->test_fn_type) - return g->test_fn_type; - - FnTypeId fn_type_id = {0}; - fn_type_id.return_type = get_error_union_type(g, g->builtin_types.entry_global_error_set, - g->builtin_types.entry_void); - g->test_fn_type = get_fn_type(g, &fn_type_id); - return g->test_fn_type; -} - -void add_var_export(CodeGen *g, ZigVar *var, const char *symbol_name, GlobalLinkageId linkage) { - GlobalExport *global_export = var->export_list.add_one(); - memset(global_export, 0, sizeof(GlobalExport)); - buf_init_from_str(&global_export->name, symbol_name); - global_export->linkage = linkage; -} - -void add_fn_export(CodeGen *g, ZigFn *fn_table_entry, const char *symbol_name, GlobalLinkageId linkage, CallingConvention cc) { - CallingConvention winapi_cc = g->zig_target->arch == ZigLLVM_x86 - ? CallingConventionStdcall - : CallingConventionC; - - if (cc == CallingConventionC && strcmp(symbol_name, "main") == 0 && g->link_libc) { - g->stage1.have_c_main = true; - } else if (cc == winapi_cc && g->zig_target->os == OsWindows) { - if (strcmp(symbol_name, "WinMain") == 0) { - g->stage1.have_winmain = true; - } else if (strcmp(symbol_name, "wWinMain") == 0) { - g->stage1.have_wwinmain = true; - } else if (strcmp(symbol_name, "WinMainCRTStartup") == 0) { - g->stage1.have_winmain_crt_startup = true; - } else if (strcmp(symbol_name, "wWinMainCRTStartup") == 0) { - g->stage1.have_wwinmain_crt_startup = true; - } else if (strcmp(symbol_name, "DllMainCRTStartup") == 0) { - g->stage1.have_dllmain_crt_startup = true; - } - } - - GlobalExport *fn_export = fn_table_entry->export_list.add_one(); - memset(fn_export, 0, sizeof(GlobalExport)); - buf_init_from_str(&fn_export->name, symbol_name); - fn_export->linkage = linkage; -} - -static void resolve_decl_fn(CodeGen *g, TldFn *tld_fn) { - AstNode *source_node = tld_fn->base.source_node; - if (source_node->type == NodeTypeFnProto) { - AstNodeFnProto *fn_proto = &source_node->data.fn_proto; - - AstNode *fn_def_node = fn_proto->fn_def_node; - - ZigFn *fn_table_entry = create_fn(g, source_node); - tld_fn->fn_entry = fn_table_entry; - - bool is_extern = (fn_table_entry->body_node == nullptr); - if (fn_proto->is_export || is_extern) { - buf_init_from_buf(&fn_table_entry->symbol_name, tld_fn->base.name); - } else { - get_fully_qualified_decl_name(g, &fn_table_entry->symbol_name, &tld_fn->base, false); - } - - if (!is_extern) { - fn_table_entry->fndef_scope = create_fndef_scope(g, - fn_table_entry->body_node, tld_fn->base.parent_scope, fn_table_entry); - - for (size_t i = 0; i < fn_proto->params.length; i += 1) { - AstNode *param_node = fn_proto->params.at(i); - assert(param_node->type == NodeTypeParamDecl); - if (param_node->data.param_decl.name == nullptr) { - add_node_error(g, param_node, buf_sprintf("missing parameter name")); - } - } - } else { - fn_table_entry->inferred_async_node = inferred_async_none; - g->external_symbol_names.put_unique(tld_fn->base.name, &tld_fn->base); - } - - Scope *child_scope = fn_table_entry->fndef_scope ? &fn_table_entry->fndef_scope->base : tld_fn->base.parent_scope; - - CallingConvention cc; - if (fn_proto->callconv_expr != nullptr) { - if (fn_proto->fn_inline == FnInlineAlways) { - add_node_error(g, fn_proto->callconv_expr, buf_sprintf("explicit callconv incompatible with inline keyword")); - } - ZigType *cc_enum_value = get_builtin_type(g, "CallingConvention"); - - ZigValue *result_val = analyze_const_value(g, child_scope, fn_proto->callconv_expr, - cc_enum_value, nullptr, UndefBad); - if (type_is_invalid(result_val->type)) { - fn_table_entry->type_entry = g->builtin_types.entry_invalid; - tld_fn->base.resolution = TldResolutionInvalid; - return; - } - - cc = (CallingConvention)bigint_as_u32(&result_val->data.x_enum_tag); - } else { - cc = cc_from_fn_proto(fn_proto); - } - - if (fn_proto->section_expr != nullptr) { - if (!analyze_const_string(g, child_scope, fn_proto->section_expr, &fn_table_entry->section_name)) { - fn_table_entry->type_entry = g->builtin_types.entry_invalid; - tld_fn->base.resolution = TldResolutionInvalid; - return; - } - } - - fn_table_entry->type_entry = analyze_fn_type(g, source_node, child_scope, fn_table_entry, cc); - - if (type_is_invalid(fn_table_entry->type_entry)) { - tld_fn->base.resolution = TldResolutionInvalid; - return; - } - - const CallingConvention fn_cc = fn_table_entry->type_entry->data.fn.fn_type_id.cc; - - if (fn_proto->is_export) { - switch (fn_cc) { - case CallingConventionAsync: - add_node_error(g, fn_def_node, - buf_sprintf("exported function cannot be async")); - fn_table_entry->type_entry = g->builtin_types.entry_invalid; - tld_fn->base.resolution = TldResolutionInvalid; - return; - case CallingConventionInline: - add_node_error(g, fn_def_node, - buf_sprintf("exported function cannot be inline")); - fn_table_entry->type_entry = g->builtin_types.entry_invalid; - tld_fn->base.resolution = TldResolutionInvalid; - return; - case CallingConventionC: - case CallingConventionNaked: - case CallingConventionInterrupt: - case CallingConventionSignal: - case CallingConventionStdcall: - case CallingConventionFastcall: - case CallingConventionVectorcall: - case CallingConventionThiscall: - case CallingConventionAPCS: - case CallingConventionAAPCS: - case CallingConventionAAPCSVFP: - case CallingConventionSysV: - case CallingConventionWin64: - case CallingConventionPtxKernel: - case CallingConventionAmdgpuKernel: - add_fn_export(g, fn_table_entry, buf_ptr(&fn_table_entry->symbol_name), - GlobalLinkageIdStrong, fn_cc); - break; - case CallingConventionUnspecified: - // An exported function without a specific calling - // convention defaults to C - add_fn_export(g, fn_table_entry, buf_ptr(&fn_table_entry->symbol_name), - GlobalLinkageIdStrong, CallingConventionC); - break; - } - } - - if (!fn_table_entry->type_entry->data.fn.is_generic) { - if (fn_def_node) - g->fn_defs.append(fn_table_entry); - } - - // if the calling convention implies that it cannot be async, we save that for later - // and leave the value to be nullptr to indicate that we have not emitted possible - // compile errors for improperly calling async functions. - if (fn_cc == CallingConventionAsync) { - fn_table_entry->inferred_async_node = fn_table_entry->proto_node; - } - } else if (source_node->type == NodeTypeTestDecl) { - ZigFn *fn_table_entry = create_fn_raw(g, false); - - get_fully_qualified_decl_name(g, &fn_table_entry->symbol_name, &tld_fn->base, true); - - tld_fn->fn_entry = fn_table_entry; - - fn_table_entry->proto_node = source_node; - fn_table_entry->fndef_scope = create_fndef_scope(g, source_node, tld_fn->base.parent_scope, fn_table_entry); - fn_table_entry->type_entry = get_test_fn_type(g); - fn_table_entry->body_node = source_node->data.test_decl.body; - - g->fn_defs.append(fn_table_entry); - g->test_fns.append(fn_table_entry); - - } else { - zig_unreachable(); - } -} - -static void resolve_decl_comptime(CodeGen *g, TldCompTime *tld_comptime) { - assert(tld_comptime->base.source_node->type == NodeTypeCompTime); - AstNode *expr_node = tld_comptime->base.source_node->data.comptime_expr.expr; - analyze_const_value(g, tld_comptime->base.parent_scope, expr_node, g->builtin_types.entry_void, - nullptr, UndefBad); -} - -static void add_top_level_decl(CodeGen *g, ScopeDecls *decls_scope, Tld *tld) { - bool is_export = false; - if (tld->id == TldIdVar) { - assert(tld->source_node->type == NodeTypeVariableDeclaration); - is_export = tld->source_node->data.variable_declaration.is_export; - } else if (tld->id == TldIdFn) { - assert(tld->source_node->type == NodeTypeFnProto); - is_export = tld->source_node->data.fn_proto.is_export; - - if (!tld->source_node->data.fn_proto.is_extern && - tld->source_node->data.fn_proto.fn_def_node == nullptr) - { - add_node_error(g, tld->source_node, buf_sprintf("non-extern function has no body")); - return; - } - if (!tld->source_node->data.fn_proto.is_extern && - tld->source_node->data.fn_proto.is_var_args) - { - add_node_error(g, tld->source_node, buf_sprintf("non-extern function is variadic")); - return; - } - } else if (tld->id == TldIdUsingNamespace) { - g->resolve_queue.append(tld); - } - if (is_export) { - g->resolve_queue.append(tld); - - auto entry = g->exported_symbol_names.put_unique(tld->name, tld); - if (entry) { - AstNode *other_source_node = entry->value->source_node; - ErrorMsg *msg = add_node_error(g, tld->source_node, - buf_sprintf("exported symbol collision: '%s'", buf_ptr(tld->name))); - add_error_note(g, msg, other_source_node, buf_sprintf("other symbol here")); - } - } - - if (tld->name != nullptr) { - auto entry = decls_scope->decl_table.put_unique(tld->name, tld); - if (entry) { - Tld *other_tld = entry->value; - if (other_tld->id == TldIdVar) { - ZigVar *var = reinterpret_cast(other_tld)->var; - if (var != nullptr && var->var_type != nullptr && type_is_invalid(var->var_type)) { - return; // already reported compile error - } - } - ErrorMsg *msg = add_node_error(g, tld->source_node, buf_sprintf("redefinition of '%s'", buf_ptr(tld->name))); - add_error_note(g, msg, other_tld->source_node, buf_sprintf("previous definition here")); - return; - } - } -} - -static void preview_test_decl(CodeGen *g, AstNode *node, ScopeDecls *decls_scope) { - assert(node->type == NodeTypeTestDecl); - - if (!g->is_test_build) - return; - - ZigType *import = get_scope_import(&decls_scope->base); - if (import->data.structure.root_struct->package != g->main_pkg) - return; - - Buf *decl_name_buf = node->data.test_decl.name; - Buf *test_name; - - if (decl_name_buf != nullptr) { - test_name = g->test_name_prefix ? - buf_sprintf("%s%s", buf_ptr(g->test_name_prefix), buf_ptr(decl_name_buf)) : decl_name_buf; - - if (g->test_filter != nullptr && strstr(buf_ptr(test_name), buf_ptr(g->test_filter)) == nullptr) { - return; - } - } else { - // Unnamed test blocks are always executed. - test_name = buf_sprintf("%s", g->test_name_prefix ? buf_ptr(g->test_name_prefix) : ""); - } - - TldFn *tld_fn = heap::c_allocator.create(); - init_tld(&tld_fn->base, TldIdFn, test_name, VisibModPrivate, node, &decls_scope->base); - g->resolve_queue.append(&tld_fn->base); -} - -static void preview_comptime_decl(CodeGen *g, AstNode *node, ScopeDecls *decls_scope) { - assert(node->type == NodeTypeCompTime); - - TldCompTime *tld_comptime = heap::c_allocator.create(); - init_tld(&tld_comptime->base, TldIdCompTime, nullptr, VisibModPrivate, node, &decls_scope->base); - g->resolve_queue.append(&tld_comptime->base); -} - -void init_tld(Tld *tld, TldId id, Buf *name, VisibMod visib_mod, AstNode *source_node, - Scope *parent_scope) -{ - tld->id = id; - tld->name = name; - tld->visib_mod = visib_mod; - tld->source_node = source_node; - tld->import = source_node ? source_node->owner : nullptr; - tld->parent_scope = parent_scope; -} - -void update_compile_var(CodeGen *g, Buf *name, ZigValue *value) { - ScopeDecls *builtin_scope = get_container_scope(g->compile_var_import); - Tld *tld = find_container_decl(g, builtin_scope, name); - assert(tld != nullptr); - resolve_top_level_decl(g, tld, tld->source_node, false); - assert(tld->id == TldIdVar && tld->resolution == TldResolutionOk); - TldVar *tld_var = (TldVar *)tld; - copy_const_val(g, tld_var->var->const_value, value); - tld_var->var->var_type = value->type; - tld_var->var->align_bytes = get_abi_alignment(g, value->type); -} - -void scan_decls(CodeGen *g, ScopeDecls *decls_scope, AstNode *node) { - switch (node->type) { - case NodeTypeFnDef: - scan_decls(g, decls_scope, node->data.fn_def.fn_proto); - break; - case NodeTypeVariableDeclaration: - { - Buf *name = node->data.variable_declaration.symbol; - VisibMod visib_mod = node->data.variable_declaration.visib_mod; - TldVar *tld_var = heap::c_allocator.create(); - init_tld(&tld_var->base, TldIdVar, name, visib_mod, node, &decls_scope->base); - tld_var->extern_lib_name = node->data.variable_declaration.lib_name; - add_top_level_decl(g, decls_scope, &tld_var->base); - break; - } - case NodeTypeFnProto: - { - // if the name is missing, we immediately announce an error - Buf *fn_name = node->data.fn_proto.name; - if (fn_name == nullptr) { - add_node_error(g, node, buf_sprintf("missing function name")); - break; - } - - VisibMod visib_mod = node->data.fn_proto.visib_mod; - TldFn *tld_fn = heap::c_allocator.create(); - init_tld(&tld_fn->base, TldIdFn, fn_name, visib_mod, node, &decls_scope->base); - tld_fn->extern_lib_name = node->data.fn_proto.lib_name; - add_top_level_decl(g, decls_scope, &tld_fn->base); - - break; - } - case NodeTypeUsingNamespace: { - VisibMod visib_mod = node->data.using_namespace.visib_mod; - TldUsingNamespace *tld_using_namespace = heap::c_allocator.create(); - init_tld(&tld_using_namespace->base, TldIdUsingNamespace, nullptr, visib_mod, node, &decls_scope->base); - add_top_level_decl(g, decls_scope, &tld_using_namespace->base); - decls_scope->use_decls.append(tld_using_namespace); - break; - } - case NodeTypeTestDecl: - preview_test_decl(g, node, decls_scope); - break; - case NodeTypeCompTime: - preview_comptime_decl(g, node, decls_scope); - break; - case NodeTypeContainerDecl: - case NodeTypeNoSuspend: - case NodeTypeParamDecl: - case NodeTypeReturnExpr: - case NodeTypeDefer: - case NodeTypeBlock: - case NodeTypeGroupedExpr: - case NodeTypeBinOpExpr: - case NodeTypeCatchExpr: - case NodeTypeFnCallExpr: - case NodeTypeArrayAccessExpr: - case NodeTypeSliceExpr: - case NodeTypeFloatLiteral: - case NodeTypeIntLiteral: - case NodeTypeStringLiteral: - case NodeTypeCharLiteral: - case NodeTypeIdentifier: - case NodeTypePrefixOpExpr: - case NodeTypePointerType: - case NodeTypeIfBoolExpr: - case NodeTypeWhileExpr: - case NodeTypeForExpr: - case NodeTypeSwitchExpr: - case NodeTypeSwitchProng: - case NodeTypeSwitchRange: - case NodeTypeBreak: - case NodeTypeContinue: - case NodeTypeUnreachable: - case NodeTypeAsmExpr: - case NodeTypeFieldAccessExpr: - case NodeTypePtrDeref: - case NodeTypeUnwrapOptional: - case NodeTypeStructField: - case NodeTypeContainerInitExpr: - case NodeTypeStructValueField: - case NodeTypeArrayType: - case NodeTypeInferredArrayType: - case NodeTypeErrorType: - case NodeTypeIfErrorExpr: - case NodeTypeIfOptional: - case NodeTypeErrorSetDecl: - case NodeTypeResume: - case NodeTypeAwaitExpr: - case NodeTypeSuspend: - case NodeTypeEnumLiteral: - case NodeTypeAnyFrameType: - case NodeTypeErrorSetField: - case NodeTypeAnyTypeField: - zig_unreachable(); - } -} - -static Error resolve_decl_container(CodeGen *g, TldContainer *tld_container) { - ZigType *type_entry = tld_container->type_entry; - assert(type_entry); - - switch (type_entry->id) { - case ZigTypeIdStruct: - return resolve_struct_type(g, tld_container->type_entry); - case ZigTypeIdEnum: - return resolve_enum_zero_bits(g, tld_container->type_entry); - case ZigTypeIdUnion: - return resolve_union_type(g, tld_container->type_entry); - case ZigTypeIdOpaque: - return resolve_opaque_type(g, tld_container->type_entry); - default: - zig_unreachable(); - } -} - -ZigType *validate_var_type(CodeGen *g, AstNodeVariableDeclaration *source_node, ZigType *type_entry) { - switch (type_entry->id) { - case ZigTypeIdInvalid: - return g->builtin_types.entry_invalid; - case ZigTypeIdOpaque: - if (source_node->is_extern) - return type_entry; - ZIG_FALLTHROUGH; - case ZigTypeIdUnreachable: - case ZigTypeIdUndefined: - case ZigTypeIdNull: - add_node_error(g, source_node->type, buf_sprintf("variable of type '%s' not allowed", - buf_ptr(&type_entry->name))); - return g->builtin_types.entry_invalid; - case ZigTypeIdComptimeFloat: - case ZigTypeIdComptimeInt: - case ZigTypeIdEnumLiteral: - case ZigTypeIdMetaType: - case ZigTypeIdVoid: - case ZigTypeIdBool: - case ZigTypeIdInt: - case ZigTypeIdFloat: - case ZigTypeIdPointer: - case ZigTypeIdArray: - case ZigTypeIdStruct: - case ZigTypeIdOptional: - case ZigTypeIdErrorUnion: - case ZigTypeIdErrorSet: - case ZigTypeIdEnum: - case ZigTypeIdUnion: - case ZigTypeIdFn: - case ZigTypeIdBoundFn: - case ZigTypeIdVector: - case ZigTypeIdFnFrame: - case ZigTypeIdAnyFrame: - return type_entry; - } - zig_unreachable(); -} - -// Set name to nullptr to make the variable anonymous (not visible to programmer). -// TODO merge with definition of add_local_var in ir.cpp -ZigVar *add_variable(CodeGen *g, AstNode *source_node, Scope *parent_scope, Buf *name, - bool is_const, ZigValue *const_value, Tld *src_tld, ZigType *var_type) -{ - Error err; - assert(const_value != nullptr); - assert(var_type != nullptr); - - ZigVar *variable_entry = heap::c_allocator.create(); - variable_entry->const_value = const_value; - variable_entry->var_type = var_type; - variable_entry->parent_scope = parent_scope; - variable_entry->shadowable = false; - variable_entry->src_arg_index = SIZE_MAX; - - assert(name); - variable_entry->name = strdup(buf_ptr(name)); - - if ((err = type_resolve(g, var_type, ResolveStatusAlignmentKnown))) { - variable_entry->var_type = g->builtin_types.entry_invalid; - } else { - variable_entry->align_bytes = get_abi_alignment(g, var_type); - } - - Scope *child_scope; - if (source_node && source_node->type == NodeTypeParamDecl) { - child_scope = create_var_scope(g, source_node, parent_scope, variable_entry); - } else { - // it's already in the decls table - child_scope = parent_scope; - } - - - variable_entry->src_is_const = is_const; - variable_entry->gen_is_const = is_const; - variable_entry->decl_node = source_node; - variable_entry->child_scope = child_scope; - - - return variable_entry; -} - -static void validate_export_var_type(CodeGen *g, ZigType* type, AstNode *source_node) { - switch (type->id) { - case ZigTypeIdMetaType: - add_node_error(g, source_node, buf_sprintf("cannot export variable of type 'type'")); - break; - default: - break; - } -} - -static void resolve_decl_var(CodeGen *g, TldVar *tld_var, bool allow_lazy) { - AstNode *source_node = tld_var->base.source_node; - AstNodeVariableDeclaration *var_decl = &source_node->data.variable_declaration; - - bool is_const = var_decl->is_const; - bool is_extern = var_decl->is_extern; - bool is_export = var_decl->is_export; - bool is_thread_local = var_decl->threadlocal_tok != 0; - - ZigType *explicit_type = nullptr; - if (var_decl->type) { - if (tld_var->analyzing_type) { - add_node_error(g, var_decl->type, - buf_sprintf("type of '%s' depends on itself", buf_ptr(tld_var->base.name))); - explicit_type = g->builtin_types.entry_invalid; - } else { - tld_var->analyzing_type = true; - ZigType *proposed_type = analyze_type_expr(g, tld_var->base.parent_scope, var_decl->type); - explicit_type = validate_var_type(g, var_decl, proposed_type); - } - } - - assert(!is_export || !is_extern); - - ZigValue *init_value = nullptr; - - // TODO more validation for types that can't be used for export/extern variables - ZigType *implicit_type = nullptr; - if (explicit_type != nullptr && type_is_invalid(explicit_type)) { - implicit_type = explicit_type; - } else if (var_decl->expr) { - init_value = analyze_const_value(g, tld_var->base.parent_scope, var_decl->expr, explicit_type, - var_decl->symbol, allow_lazy ? LazyOk : UndefOk); - assert(init_value); - implicit_type = init_value->type; - - if (implicit_type->id == ZigTypeIdUnreachable) { - add_node_error(g, source_node, buf_sprintf("variable initialization is unreachable")); - implicit_type = g->builtin_types.entry_invalid; - } else if ((!is_const || is_extern) && - (implicit_type->id == ZigTypeIdComptimeFloat || - implicit_type->id == ZigTypeIdComptimeInt || - implicit_type->id == ZigTypeIdEnumLiteral)) - { - add_node_error(g, source_node, buf_sprintf("unable to infer variable type")); - implicit_type = g->builtin_types.entry_invalid; - } else if (implicit_type->id == ZigTypeIdNull) { - add_node_error(g, source_node, buf_sprintf("unable to infer variable type")); - implicit_type = g->builtin_types.entry_invalid; - } else if (implicit_type->id == ZigTypeIdMetaType && !is_const) { - add_node_error(g, source_node, buf_sprintf("variable of type 'type' must be constant")); - implicit_type = g->builtin_types.entry_invalid; - } - assert(implicit_type->id == ZigTypeIdInvalid || init_value->special != ConstValSpecialRuntime); - } else if (!is_extern) { - add_node_error(g, source_node, buf_sprintf("variables must be initialized")); - implicit_type = g->builtin_types.entry_invalid; - } else if (explicit_type == nullptr) { - // extern variable without explicit type - add_node_error(g, source_node, buf_sprintf("unable to infer variable type")); - implicit_type = g->builtin_types.entry_invalid; - } - - ZigType *type = explicit_type ? explicit_type : implicit_type; - assert(type != nullptr); // should have been caught by the parser - - ZigValue *init_val = (init_value != nullptr) ? init_value : create_const_runtime(g, type); - - tld_var->var = add_variable(g, source_node, tld_var->base.parent_scope, var_decl->symbol, - is_const, init_val, &tld_var->base, type); - tld_var->var->is_thread_local = is_thread_local; - - if (implicit_type != nullptr && type_is_invalid(implicit_type)) { - tld_var->var->var_type = g->builtin_types.entry_invalid; - } - - if (var_decl->align_expr != nullptr) { - if (!analyze_const_align(g, tld_var->base.parent_scope, var_decl->align_expr, &tld_var->var->align_bytes)) { - tld_var->var->var_type = g->builtin_types.entry_invalid; - } - } - - if (var_decl->section_expr != nullptr) { - if (!analyze_const_string(g, tld_var->base.parent_scope, var_decl->section_expr, &tld_var->var->section_name)) { - tld_var->var->section_name = nullptr; - } - } - - if (is_thread_local && is_const) { - add_node_error(g, source_node, buf_sprintf("threadlocal variable cannot be constant")); - } - - if (is_export) { - validate_export_var_type(g, type, source_node); - add_var_export(g, tld_var->var, tld_var->var->name, GlobalLinkageIdStrong); - } - - if (is_extern) { - g->external_symbol_names.put_unique(tld_var->base.name, &tld_var->base); - } - - g->global_vars.append(tld_var); -} - -static void add_symbols_from_container(CodeGen *g, TldUsingNamespace *src_using_namespace, - TldUsingNamespace *dst_using_namespace, ScopeDecls* dest_decls_scope) -{ - if (src_using_namespace->base.resolution == TldResolutionUnresolved || - src_using_namespace->base.resolution == TldResolutionResolving) - { - assert(src_using_namespace->base.parent_scope->id == ScopeIdDecls); - ScopeDecls *src_decls_scope = (ScopeDecls *)src_using_namespace->base.parent_scope; - preview_use_decl(g, src_using_namespace, src_decls_scope); - if (src_using_namespace != dst_using_namespace) { - resolve_use_decl(g, src_using_namespace, src_decls_scope); - } - } - - ZigValue *use_expr = src_using_namespace->using_namespace_value; - if (type_is_invalid(use_expr->type)) { - dest_decls_scope->any_imports_failed = true; - return; - } - - dst_using_namespace->base.resolution = TldResolutionOk; - - assert(use_expr->special != ConstValSpecialRuntime); - - // The source scope for the imported symbols - ScopeDecls *src_scope = get_container_scope(use_expr->data.x_type); - // The top-level container where the symbols are defined, it's used in the - // loop below in order to exclude the ones coming from an import statement - ZigType *src_import = get_scope_import(&src_scope->base); - assert(src_import != nullptr); - - if (src_scope->any_imports_failed) { - dest_decls_scope->any_imports_failed = true; - } - - auto it = src_scope->decl_table.entry_iterator(); - for (;;) { - auto *entry = it.next(); - if (!entry) - break; - - Buf *target_tld_name = entry->key; - Tld *target_tld = entry->value; - - if (target_tld->visib_mod == VisibModPrivate) { - continue; - } - - if (target_tld->import != src_import) { - continue; - } - - auto existing_entry = dest_decls_scope->decl_table.put_unique(target_tld_name, target_tld); - if (existing_entry) { - Tld *existing_decl = existing_entry->value; - if (existing_decl != target_tld) { - ErrorMsg *msg = add_node_error(g, dst_using_namespace->base.source_node, - buf_sprintf("import of '%s' overrides existing definition", - buf_ptr(target_tld_name))); - add_error_note(g, msg, existing_decl->source_node, buf_sprintf("previous definition here")); - add_error_note(g, msg, target_tld->source_node, buf_sprintf("imported definition here")); - } - } - } - - for (size_t i = 0; i < src_scope->use_decls.length; i += 1) { - TldUsingNamespace *tld_using_namespace = src_scope->use_decls.at(i); - if (tld_using_namespace->base.visib_mod != VisibModPrivate) - add_symbols_from_container(g, tld_using_namespace, dst_using_namespace, dest_decls_scope); - } -} - -static void resolve_use_decl(CodeGen *g, TldUsingNamespace *tld_using_namespace, ScopeDecls *dest_decls_scope) { - if (tld_using_namespace->base.resolution == TldResolutionOk || - tld_using_namespace->base.resolution == TldResolutionInvalid) - { - return; - } - add_symbols_from_container(g, tld_using_namespace, tld_using_namespace, dest_decls_scope); -} - -static void preview_use_decl(CodeGen *g, TldUsingNamespace *using_namespace, ScopeDecls *dest_decls_scope) { - if (using_namespace->base.resolution == TldResolutionOk || - using_namespace->base.resolution == TldResolutionInvalid || - using_namespace->using_namespace_value != nullptr) - { - return; - } - - using_namespace->base.resolution = TldResolutionResolving; - assert(using_namespace->base.source_node->type == NodeTypeUsingNamespace); - ZigValue *result = analyze_const_value(g, &dest_decls_scope->base, - using_namespace->base.source_node->data.using_namespace.expr, g->builtin_types.entry_type, - nullptr, UndefBad); - using_namespace->using_namespace_value = result; - - if (type_is_invalid(result->type)) { - dest_decls_scope->any_imports_failed = true; - using_namespace->base.resolution = TldResolutionInvalid; - using_namespace->using_namespace_value = g->invalid_inst_gen->value; - return; - } - - if (!is_container(result->data.x_type)) { - add_node_error(g, using_namespace->base.source_node, - buf_sprintf("expected struct, enum, or union; found '%s'", buf_ptr(&result->data.x_type->name))); - dest_decls_scope->any_imports_failed = true; - using_namespace->base.resolution = TldResolutionInvalid; - using_namespace->using_namespace_value = g->invalid_inst_gen->value; - return; - } -} - -void resolve_top_level_decl(CodeGen *g, Tld *tld, AstNode *source_node, bool allow_lazy) { - bool want_resolve_lazy = tld->resolution == TldResolutionOkLazy && !allow_lazy; - if (tld->resolution != TldResolutionUnresolved && !want_resolve_lazy) - return; - - tld->resolution = TldResolutionResolving; - update_progress_display(g); - - switch (tld->id) { - case TldIdVar: { - TldVar *tld_var = (TldVar *)tld; - if (want_resolve_lazy) { - ir_resolve_lazy(g, source_node, tld_var->var->const_value); - } else { - resolve_decl_var(g, tld_var, allow_lazy); - } - tld->resolution = allow_lazy ? TldResolutionOkLazy : TldResolutionOk; - break; - } - case TldIdFn: { - TldFn *tld_fn = (TldFn *)tld; - resolve_decl_fn(g, tld_fn); - - tld->resolution = TldResolutionOk; - break; - } - case TldIdContainer: { - TldContainer *tld_container = (TldContainer *)tld; - resolve_decl_container(g, tld_container); - - tld->resolution = TldResolutionOk; - break; - } - case TldIdCompTime: { - TldCompTime *tld_comptime = (TldCompTime *)tld; - resolve_decl_comptime(g, tld_comptime); - - tld->resolution = TldResolutionOk; - break; - } - case TldIdUsingNamespace: { - TldUsingNamespace *tld_using_namespace = (TldUsingNamespace *)tld; - assert(tld_using_namespace->base.parent_scope->id == ScopeIdDecls); - ScopeDecls *dest_decls_scope = (ScopeDecls *)tld_using_namespace->base.parent_scope; - preview_use_decl(g, tld_using_namespace, dest_decls_scope); - resolve_use_decl(g, tld_using_namespace, dest_decls_scope); - - tld->resolution = TldResolutionOk; - break; - } - } -} - -void resolve_container_usingnamespace_decls(CodeGen *g, ScopeDecls *decls_scope) { - // resolve all the using_namespace decls - for (size_t i = 0; i < decls_scope->use_decls.length; i += 1) { - TldUsingNamespace *tld_using_namespace = decls_scope->use_decls.at(i); - if (tld_using_namespace->base.resolution == TldResolutionUnresolved) { - preview_use_decl(g, tld_using_namespace, decls_scope); - resolve_use_decl(g, tld_using_namespace, decls_scope); - } - } - -} - -Tld *find_container_decl(CodeGen *g, ScopeDecls *decls_scope, Buf *name) { - resolve_container_usingnamespace_decls(g, decls_scope); - auto entry = decls_scope->decl_table.maybe_get(name); - return (entry == nullptr) ? nullptr : entry->value; -} - -Tld *find_decl(CodeGen *g, Scope *scope, Buf *name) { - while (scope) { - if (scope->id == ScopeIdDecls) { - ScopeDecls *decls_scope = (ScopeDecls *)scope; - - Tld *result = find_container_decl(g, decls_scope, name); - if (result != nullptr) - return result; - } - scope = scope->parent; - } - return nullptr; -} - -ZigVar *find_variable(CodeGen *g, Scope *scope, Buf *name, ScopeFnDef **crossed_fndef_scope) { - ScopeFnDef *my_crossed_fndef_scope = nullptr; - while (scope) { - if (scope->id == ScopeIdVarDecl) { - ScopeVarDecl *var_scope = (ScopeVarDecl *)scope; - if (buf_eql_str(name, var_scope->var->name)) { - if (crossed_fndef_scope != nullptr) - *crossed_fndef_scope = my_crossed_fndef_scope; - return var_scope->var; - } - } else if (scope->id == ScopeIdDecls) { - ScopeDecls *decls_scope = (ScopeDecls *)scope; - auto entry = decls_scope->decl_table.maybe_get(name); - if (entry) { - Tld *tld = entry->value; - if (tld->id == TldIdVar) { - TldVar *tld_var = (TldVar *)tld; - if (tld_var->var) { - if (crossed_fndef_scope != nullptr) - *crossed_fndef_scope = nullptr; - return tld_var->var; - } - } - } - } else if (scope->id == ScopeIdFnDef) { - my_crossed_fndef_scope = (ScopeFnDef *)scope; - } - scope = scope->parent; - } - - return nullptr; -} - -ZigFn *scope_fn_entry(Scope *scope) { - while (scope) { - if (scope->id == ScopeIdFnDef) { - ScopeFnDef *fn_scope = (ScopeFnDef *)scope; - return fn_scope->fn_entry; - } - scope = scope->parent; - } - return nullptr; -} - -ZigPackage *scope_package(Scope *scope) { - ZigType *import = get_scope_import(scope); - assert(is_top_level_struct(import)); - return import->data.structure.root_struct->package; -} - -TypeEnumField *find_enum_type_field(ZigType *enum_type, Buf *name) { - assert(enum_type->id == ZigTypeIdEnum); - if (enum_type->data.enumeration.src_field_count == 0) - return nullptr; - auto entry = enum_type->data.enumeration.fields_by_name.maybe_get(name); - if (entry == nullptr) - return nullptr; - return entry->value; -} - -TypeStructField *find_struct_type_field(ZigType *type_entry, Buf *name) { - assert(type_entry->id == ZigTypeIdStruct); - if (type_entry->data.structure.resolve_status == ResolveStatusBeingInferred) { - for (size_t i = 0; i < type_entry->data.structure.src_field_count; i += 1) { - TypeStructField *field = type_entry->data.structure.fields[i]; - if (buf_eql_buf(field->name, name)) - return field; - } - return nullptr; - } else { - assert(type_is_resolved(type_entry, ResolveStatusZeroBitsKnown)); - if (type_entry->data.structure.src_field_count == 0) - return nullptr; - auto entry = type_entry->data.structure.fields_by_name.maybe_get(name); - if (entry == nullptr) - return nullptr; - return entry->value; - } -} - -TypeUnionField *find_union_type_field(ZigType *type_entry, Buf *name) { - assert(type_entry->id == ZigTypeIdUnion); - assert(type_is_resolved(type_entry, ResolveStatusZeroBitsKnown)); - if (type_entry->data.unionation.src_field_count == 0) - return nullptr; - auto entry = type_entry->data.unionation.fields_by_name.maybe_get(name); - if (entry == nullptr) - return nullptr; - return entry->value; -} - -TypeUnionField *find_union_field_by_tag(ZigType *type_entry, const BigInt *tag) { - assert(type_entry->id == ZigTypeIdUnion); - assert(type_is_resolved(type_entry, ResolveStatusZeroBitsKnown)); - for (uint32_t i = 0; i < type_entry->data.unionation.src_field_count; i += 1) { - TypeUnionField *field = &type_entry->data.unionation.fields[i]; - if (bigint_cmp(&field->enum_field->value, tag) == CmpEQ) { - return field; - } - } - return nullptr; -} - -TypeEnumField *find_enum_field_by_tag(ZigType *enum_type, const BigInt *tag) { - assert(type_is_resolved(enum_type, ResolveStatusZeroBitsKnown)); - for (uint32_t i = 0; i < enum_type->data.enumeration.src_field_count; i += 1) { - TypeEnumField *field = &enum_type->data.enumeration.fields[i]; - if (bigint_cmp(&field->value, tag) == CmpEQ) { - return field; - } - } - return nullptr; -} - - -bool is_container(ZigType *type_entry) { - switch (type_entry->id) { - case ZigTypeIdInvalid: - zig_unreachable(); - case ZigTypeIdStruct: - return type_entry->data.structure.special != StructSpecialSlice; - case ZigTypeIdEnum: - case ZigTypeIdUnion: - case ZigTypeIdOpaque: - return true; - case ZigTypeIdPointer: - case ZigTypeIdMetaType: - case ZigTypeIdVoid: - case ZigTypeIdBool: - case ZigTypeIdUnreachable: - case ZigTypeIdInt: - case ZigTypeIdFloat: - case ZigTypeIdArray: - case ZigTypeIdComptimeFloat: - case ZigTypeIdComptimeInt: - case ZigTypeIdEnumLiteral: - case ZigTypeIdUndefined: - case ZigTypeIdNull: - case ZigTypeIdOptional: - case ZigTypeIdErrorUnion: - case ZigTypeIdErrorSet: - case ZigTypeIdFn: - case ZigTypeIdBoundFn: - case ZigTypeIdVector: - case ZigTypeIdFnFrame: - case ZigTypeIdAnyFrame: - return false; - } - zig_unreachable(); -} - -bool is_ref(ZigType *type_entry) { - return type_entry->id == ZigTypeIdPointer && type_entry->data.pointer.ptr_len == PtrLenSingle; -} - -bool is_array_ref(ZigType *type_entry) { - ZigType *array = is_ref(type_entry) ? - type_entry->data.pointer.child_type : type_entry; - return array->id == ZigTypeIdArray; -} - -bool is_container_ref(ZigType *parent_ty) { - ZigType *ty = is_ref(parent_ty) ? parent_ty->data.pointer.child_type : parent_ty; - return is_slice(ty) || is_container(ty); -} - -ZigType *container_ref_type(ZigType *type_entry) { - assert(is_container_ref(type_entry)); - return is_ref(type_entry) ? - type_entry->data.pointer.child_type : type_entry; -} - -ZigType *get_src_ptr_type(ZigType *type) { - if (type->id == ZigTypeIdPointer) return type; - if (type->id == ZigTypeIdFn) return type; - if (type->id == ZigTypeIdAnyFrame) return type; - if (type->id == ZigTypeIdOptional) { - if (type->data.maybe.child_type->id == ZigTypeIdPointer) { - return type->data.maybe.child_type->data.pointer.allow_zero ? nullptr : type->data.maybe.child_type; - } - if (type->data.maybe.child_type->id == ZigTypeIdFn) return type->data.maybe.child_type; - if (type->data.maybe.child_type->id == ZigTypeIdAnyFrame) return type->data.maybe.child_type; - } - return nullptr; -} - -Error get_codegen_ptr_type(CodeGen *g, ZigType *type, ZigType **result) { - Error err; - - ZigType *ty = get_src_ptr_type(type); - if (ty == nullptr) { - *result = nullptr; - return ErrorNone; - } - - bool has_bits; - if ((err = type_has_bits2(g, ty, &has_bits))) return err; - if (!has_bits) { - *result = nullptr; - return ErrorNone; - } - - *result = ty; - return ErrorNone; -} - -ZigType *get_codegen_ptr_type_bail(CodeGen *g, ZigType *type) { - Error err; - ZigType *result; - if ((err = get_codegen_ptr_type(g, type, &result))) { - codegen_report_errors_and_exit(g); - } - return result; -} - -bool type_is_nonnull_ptr(CodeGen *g, ZigType *type) { - Error err; - bool result; - if ((err = type_is_nonnull_ptr2(g, type, &result))) { - codegen_report_errors_and_exit(g); - } - return result; -} - -Error type_is_nonnull_ptr2(CodeGen *g, ZigType *type, bool *result) { - Error err; - ZigType *ptr_type; - if ((err = get_codegen_ptr_type(g, type, &ptr_type))) return err; - *result = ptr_type == type && !ptr_allows_addr_zero(type); - return ErrorNone; -} - -uint32_t get_async_frame_align_bytes(CodeGen *g) { - // Due to how the frame structure is built the minimum alignment is the one - // of a usize (or pointer). - // label (grep this): [fn_frame_struct_layout] - return max(g->builtin_types.entry_usize->abi_align, target_fn_align(g->zig_target)); -} - -uint32_t get_ptr_align(CodeGen *g, ZigType *type) { - ZigType *ptr_type; - if (type->id == ZigTypeIdStruct) { - assert(type->data.structure.special == StructSpecialSlice); - TypeStructField *ptr_field = type->data.structure.fields[slice_ptr_index]; - ptr_type = resolve_struct_field_type(g, ptr_field); - } else { - ptr_type = get_src_ptr_type(type); - } - if (ptr_type->id == ZigTypeIdPointer) { - return (ptr_type->data.pointer.explicit_alignment == 0) ? - get_abi_alignment(g, ptr_type->data.pointer.child_type) : ptr_type->data.pointer.explicit_alignment; - } else if (ptr_type->id == ZigTypeIdFn) { - return (ptr_type->data.fn.fn_type_id.alignment == 0) ? - target_fn_ptr_align(g->zig_target) : ptr_type->data.fn.fn_type_id.alignment; - } else if (ptr_type->id == ZigTypeIdAnyFrame) { - return get_async_frame_align_bytes(g); - } else { - zig_unreachable(); - } -} - -bool get_ptr_const(CodeGen *g, ZigType *type) { - ZigType *ptr_type; - if (type->id == ZigTypeIdStruct) { - assert(type->data.structure.special == StructSpecialSlice); - TypeStructField *ptr_field = type->data.structure.fields[slice_ptr_index]; - ptr_type = resolve_struct_field_type(g, ptr_field); - } else { - ptr_type = get_src_ptr_type(type); - } - if (ptr_type->id == ZigTypeIdPointer) { - return ptr_type->data.pointer.is_const; - } else if (ptr_type->id == ZigTypeIdFn) { - return true; - } else if (ptr_type->id == ZigTypeIdAnyFrame) { - return true; - } else { - zig_unreachable(); - } -} - -AstNode *get_param_decl_node(ZigFn *fn_entry, size_t index) { - if (fn_entry->param_source_nodes) - return fn_entry->param_source_nodes[index]; - else if (fn_entry->proto_node) - return fn_entry->proto_node->data.fn_proto.params.at(index); - else - return nullptr; -} - -static Error define_local_param_variables(CodeGen *g, ZigFn *fn_table_entry) { - Error err; - ZigType *fn_type = fn_table_entry->type_entry; - assert(!fn_type->data.fn.is_generic); - FnTypeId *fn_type_id = &fn_type->data.fn.fn_type_id; - for (size_t i = 0; i < fn_type_id->param_count; i += 1) { - FnTypeParamInfo *param_info = &fn_type_id->param_info[i]; - AstNode *param_decl_node = get_param_decl_node(fn_table_entry, i); - Buf *param_name; - bool is_var_args = param_decl_node && param_decl_node->data.param_decl.is_var_args; - if (param_decl_node && !is_var_args) { - param_name = param_decl_node->data.param_decl.name; - } else { - param_name = buf_sprintf("arg%" ZIG_PRI_usize "", i); - } - if (param_name == nullptr) { - continue; - } - - ZigType *param_type = param_info->type; - if ((err = type_resolve(g, param_type, ResolveStatusSizeKnown))) { - return err; - } - - bool is_noalias = param_info->is_noalias; - if (is_noalias) { - ZigType *ptr_type; - if ((err = get_codegen_ptr_type(g, param_type, &ptr_type))) return err; - if (ptr_type == nullptr) { - add_node_error(g, param_decl_node, buf_sprintf("noalias on non-pointer parameter")); - } - } - - ZigVar *var = add_variable(g, param_decl_node, fn_table_entry->child_scope, - param_name, true, create_const_runtime(g, param_type), nullptr, param_type); - var->src_arg_index = i; - fn_table_entry->child_scope = var->child_scope; - var->shadowable = var->shadowable || is_var_args; - - if (type_has_bits(g, param_type)) { - fn_table_entry->variable_list.append(var); - } - } - - return ErrorNone; -} - -bool resolve_inferred_error_set(CodeGen *g, ZigType *err_set_type, AstNode *source_node) { - assert(err_set_type->id == ZigTypeIdErrorSet); - ZigFn *infer_fn = err_set_type->data.error_set.infer_fn; - if (infer_fn != nullptr && err_set_type->data.error_set.incomplete) { - if (infer_fn->anal_state == FnAnalStateInvalid) { - return false; - } else if (infer_fn->anal_state == FnAnalStateReady) { - analyze_fn_body(g, infer_fn); - if (infer_fn->anal_state == FnAnalStateInvalid || - err_set_type->data.error_set.incomplete) - { - assert(g->errors.length != 0); - return false; - } - } else { - add_node_error(g, source_node, - buf_sprintf("cannot resolve inferred error set '%s': function '%s' not fully analyzed yet", - buf_ptr(&err_set_type->name), buf_ptr(&err_set_type->data.error_set.infer_fn->symbol_name))); - return false; - } - } - return true; -} - -static void resolve_async_fn_frame(CodeGen *g, ZigFn *fn) { - ZigType *frame_type = get_fn_frame_type(g, fn); - Error err; - if ((err = type_resolve(g, frame_type, ResolveStatusSizeKnown))) { - if (g->trace_err != nullptr && frame_type->data.frame.resolve_loop_src_node != nullptr && - !frame_type->data.frame.reported_loop_err) - { - frame_type->data.frame.reported_loop_err = true; - g->trace_err = add_error_note(g, g->trace_err, frame_type->data.frame.resolve_loop_src_node, - buf_sprintf("when analyzing type '%s' here", buf_ptr(&frame_type->name))); - } - fn->anal_state = FnAnalStateInvalid; - return; - } -} - -bool fn_is_async(ZigFn *fn) { - assert(fn->inferred_async_node != nullptr); - assert(fn->inferred_async_node != inferred_async_checking); - return fn->inferred_async_node != inferred_async_none; -} - -void add_async_error_notes(CodeGen *g, ErrorMsg *msg, ZigFn *fn) { - assert(fn->inferred_async_node != nullptr); - assert(fn->inferred_async_node != inferred_async_checking); - assert(fn->inferred_async_node != inferred_async_none); - if (fn->inferred_async_fn != nullptr) { - ErrorMsg *new_msg; - if (fn->inferred_async_node->type == NodeTypeAwaitExpr) { - new_msg = add_error_note(g, msg, fn->inferred_async_node, - buf_create_from_str("await here is a suspend point")); - } else { - new_msg = add_error_note(g, msg, fn->inferred_async_node, - buf_sprintf("async function call here")); - } - return add_async_error_notes(g, new_msg, fn->inferred_async_fn); - } else if (fn->inferred_async_node->type == NodeTypeFnProto) { - add_error_note(g, msg, fn->inferred_async_node, - buf_sprintf("async calling convention here")); - } else if (fn->inferred_async_node->type == NodeTypeSuspend) { - add_error_note(g, msg, fn->inferred_async_node, - buf_sprintf("suspends here")); - } else if (fn->inferred_async_node->type == NodeTypeAwaitExpr) { - add_error_note(g, msg, fn->inferred_async_node, - buf_sprintf("await here is a suspend point")); - } else if (fn->inferred_async_node->type == NodeTypeFnCallExpr && - fn->inferred_async_node->data.fn_call_expr.modifier == CallModifierBuiltin) - { - add_error_note(g, msg, fn->inferred_async_node, - buf_sprintf("@frame() causes function to be async")); - } else { - add_error_note(g, msg, fn->inferred_async_node, - buf_sprintf("suspends here")); - } -} - -// ErrorNone - not async -// ErrorIsAsync - yes async -// ErrorSemanticAnalyzeFail - compile error emitted result is invalid -static Error analyze_callee_async(CodeGen *g, ZigFn *fn, ZigFn *callee, AstNode *call_node, - bool must_not_be_async, CallModifier modifier) -{ - if (modifier == CallModifierNoSuspend) - return ErrorNone; - bool callee_is_async = false; - switch (callee->type_entry->data.fn.fn_type_id.cc) { - case CallingConventionUnspecified: - break; - case CallingConventionAsync: - callee_is_async = true; - break; - default: - return ErrorNone; - } - if (!callee_is_async) { - if (callee->anal_state == FnAnalStateReady) { - analyze_fn_body(g, callee); - if (callee->anal_state == FnAnalStateInvalid) { - return ErrorSemanticAnalyzeFail; - } - } - if (callee->anal_state == FnAnalStateComplete) { - analyze_fn_async(g, callee, true); - if (callee->anal_state == FnAnalStateInvalid) { - if (g->trace_err != nullptr) { - g->trace_err = add_error_note(g, g->trace_err, call_node, - buf_sprintf("while checking if '%s' is async", buf_ptr(&fn->symbol_name))); - } - return ErrorSemanticAnalyzeFail; - } - callee_is_async = fn_is_async(callee); - } else { - // If it's already been determined, use that value. Otherwise - // assume non-async, emit an error later if it turned out to be async. - if (callee->inferred_async_node == nullptr || - callee->inferred_async_node == inferred_async_checking) - { - callee->assumed_non_async = call_node; - callee_is_async = false; - } else { - callee_is_async = callee->inferred_async_node != inferred_async_none; - } - } - } - if (callee_is_async) { - bool bad_recursion = (fn->inferred_async_node == inferred_async_none); - fn->inferred_async_node = call_node; - fn->inferred_async_fn = callee; - if (must_not_be_async) { - ErrorMsg *msg = add_node_error(g, fn->proto_node, - buf_sprintf("function with calling convention '%s' cannot be async", - calling_convention_name(fn->type_entry->data.fn.fn_type_id.cc))); - add_async_error_notes(g, msg, fn); - return ErrorSemanticAnalyzeFail; - } - if (bad_recursion) { - ErrorMsg *msg = add_node_error(g, fn->proto_node, - buf_sprintf("recursive function cannot be async")); - add_async_error_notes(g, msg, fn); - return ErrorSemanticAnalyzeFail; - } - if (fn->assumed_non_async != nullptr) { - ErrorMsg *msg = add_node_error(g, fn->proto_node, - buf_sprintf("unable to infer whether '%s' should be async", - buf_ptr(&fn->symbol_name))); - add_error_note(g, msg, fn->assumed_non_async, - buf_sprintf("assumed to be non-async here")); - add_async_error_notes(g, msg, fn); - fn->anal_state = FnAnalStateInvalid; - return ErrorSemanticAnalyzeFail; - } - return ErrorIsAsync; - } - return ErrorNone; -} - -// This function resolves functions being inferred async. -static void analyze_fn_async(CodeGen *g, ZigFn *fn, bool resolve_frame) { - if (fn->inferred_async_node == inferred_async_checking) { - // TODO call graph cycle detected, disallow the recursion - fn->inferred_async_node = inferred_async_none; - return; - } - if (fn->inferred_async_node == inferred_async_none) { - return; - } - if (fn->inferred_async_node != nullptr) { - if (resolve_frame) { - resolve_async_fn_frame(g, fn); - } - return; - } - fn->inferred_async_node = inferred_async_checking; - - bool must_not_be_async = false; - if (fn->type_entry->data.fn.fn_type_id.cc != CallingConventionUnspecified) { - must_not_be_async = true; - fn->inferred_async_node = inferred_async_none; - } - - for (size_t i = 0; i < fn->call_list.length; i += 1) { - Stage1AirInstCall *call = fn->call_list.at(i); - if (call->fn_entry == nullptr) { - // TODO function pointer call here, could be anything - continue; - } - switch (analyze_callee_async(g, fn, call->fn_entry, call->base.source_node, must_not_be_async, - call->modifier)) - { - case ErrorSemanticAnalyzeFail: - fn->anal_state = FnAnalStateInvalid; - return; - case ErrorNone: - continue; - case ErrorIsAsync: - if (resolve_frame) { - resolve_async_fn_frame(g, fn); - } - return; - default: - zig_unreachable(); - } - } - for (size_t i = 0; i < fn->await_list.length; i += 1) { - Stage1AirInstAwait *await = fn->await_list.at(i); - if (await->is_nosuspend) continue; - switch (analyze_callee_async(g, fn, await->target_fn, await->base.source_node, must_not_be_async, - CallModifierNone)) - { - case ErrorSemanticAnalyzeFail: - fn->anal_state = FnAnalStateInvalid; - return; - case ErrorNone: - continue; - case ErrorIsAsync: - if (resolve_frame) { - resolve_async_fn_frame(g, fn); - } - return; - default: - zig_unreachable(); - } - } - fn->inferred_async_node = inferred_async_none; -} - -static void analyze_fn_ir(CodeGen *g, ZigFn *fn, AstNode *return_type_node) { - ZigType *fn_type = fn->type_entry; - assert(!fn_type->data.fn.is_generic); - FnTypeId *fn_type_id = &fn_type->data.fn.fn_type_id; - - if (fn->analyzed_executable.begin_scope == nullptr) { - fn->analyzed_executable.begin_scope = &fn->def_scope->base; - } - if (fn->analyzed_executable.source_node == nullptr) { - fn->analyzed_executable.source_node = fn->body_node; - } - size_t backward_branch_count = 0; - size_t backward_branch_quota = max(fn->branch_quota, default_backward_branch_quota); - ZigType *block_return_type = ir_analyze(g, fn->stage1_zir, &fn->analyzed_executable, - &backward_branch_count, &backward_branch_quota, - fn_type_id->return_type, return_type_node, nullptr, fn); - fn->src_implicit_return_type = block_return_type; - - if (type_is_invalid(block_return_type) || fn->analyzed_executable.first_err_trace_msg != nullptr) { - assert(g->errors.length > 0); - fn->anal_state = FnAnalStateInvalid; - return; - } - - if (fn_type_id->return_type->id == ZigTypeIdErrorUnion) { - ZigType *return_err_set_type = fn_type_id->return_type->data.error_union.err_set_type; - if (return_err_set_type->data.error_set.infer_fn != nullptr && - return_err_set_type->data.error_set.incomplete) - { - // The inferred error set type is null if the function doesn't - // return any error - ZigType *inferred_err_set_type = nullptr; - - if (fn->src_implicit_return_type->id == ZigTypeIdErrorSet) { - inferred_err_set_type = fn->src_implicit_return_type; - } else if (fn->src_implicit_return_type->id == ZigTypeIdErrorUnion) { - inferred_err_set_type = fn->src_implicit_return_type->data.error_union.err_set_type; - } - - if (inferred_err_set_type != nullptr) { - if (inferred_err_set_type->data.error_set.infer_fn != nullptr && - inferred_err_set_type->data.error_set.incomplete) - { - if (!resolve_inferred_error_set(g, inferred_err_set_type, return_type_node)) { - fn->anal_state = FnAnalStateInvalid; - return; - } - } - - return_err_set_type->data.error_set.incomplete = false; - if (type_is_global_error_set(inferred_err_set_type)) { - return_err_set_type->data.error_set.err_count = UINT32_MAX; - } else { - return_err_set_type->data.error_set.err_count = inferred_err_set_type->data.error_set.err_count; - if (inferred_err_set_type->data.error_set.err_count > 0) { - return_err_set_type->data.error_set.errors = heap::c_allocator.allocate(inferred_err_set_type->data.error_set.err_count); - for (uint32_t i = 0; i < inferred_err_set_type->data.error_set.err_count; i += 1) { - return_err_set_type->data.error_set.errors[i] = inferred_err_set_type->data.error_set.errors[i]; - } - } - } - } else { - return_err_set_type->data.error_set.incomplete = false; - return_err_set_type->data.error_set.err_count = 0; - } - } - } - - CallingConvention cc = fn->type_entry->data.fn.fn_type_id.cc; - if (cc != CallingConventionUnspecified && cc != CallingConventionAsync && - fn->inferred_async_node != nullptr && - fn->inferred_async_node != inferred_async_checking && - fn->inferred_async_node != inferred_async_none) - { - ErrorMsg *msg = add_node_error(g, fn->proto_node, - buf_sprintf("function with calling convention '%s' cannot be async", - calling_convention_name(cc))); - add_async_error_notes(g, msg, fn); - fn->anal_state = FnAnalStateInvalid; - } - - if (g->verbose_ir) { - fprintf(stderr, "fn %s() { // (analyzed)\n", buf_ptr(&fn->symbol_name)); - ir_print_gen(g, stderr, &fn->analyzed_executable, 4); - fprintf(stderr, "}\n"); - } - fn->anal_state = FnAnalStateComplete; -} - -static void analyze_fn_body(CodeGen *g, ZigFn *fn_table_entry) { - assert(fn_table_entry->anal_state != FnAnalStateProbing); - if (fn_table_entry->anal_state != FnAnalStateReady) - return; - - fn_table_entry->anal_state = FnAnalStateProbing; - update_progress_display(g); - - AstNode *return_type_node = (fn_table_entry->proto_node != nullptr) ? - fn_table_entry->proto_node->data.fn_proto.return_type : fn_table_entry->fndef_scope->base.source_node; - - assert(fn_table_entry->fndef_scope); - if (!fn_table_entry->child_scope) - fn_table_entry->child_scope = &fn_table_entry->fndef_scope->base; - - if (define_local_param_variables(g, fn_table_entry) != ErrorNone) { - fn_table_entry->anal_state = FnAnalStateInvalid; - return; - } - - ZigType *fn_type = fn_table_entry->type_entry; - assert(!fn_type->data.fn.is_generic); - - if (!stage1_astgen_fn(g, fn_table_entry)) { - fn_table_entry->anal_state = FnAnalStateInvalid; - return; - } - - if (fn_table_entry->stage1_zir->first_err_trace_msg != nullptr) { - fn_table_entry->anal_state = FnAnalStateInvalid; - return; - } - - if (g->verbose_ir) { - fprintf(stderr, "\nfn %s() { // (IR)\n", buf_ptr(&fn_table_entry->symbol_name)); - ir_print_src(g, stderr, fn_table_entry->stage1_zir, 4); - fprintf(stderr, "}\n"); - } - - analyze_fn_ir(g, fn_table_entry, return_type_node); -} - -ZigType *add_source_file(CodeGen *g, ZigPackage *package, Buf *resolved_path, Buf *source_code, - SourceKind source_kind) -{ - Tokenization tokenization = {0}; - tokenize(buf_ptr(source_code), &tokenization); - - if (tokenization.err) { - ErrorMsg *err = err_msg_create_with_offset(resolved_path, tokenization.err_byte_offset, - buf_ptr(source_code), tokenization.err); - - print_err_msg(err, g->err_color); - exit(1); - } - - Buf *src_dirname = buf_alloc(); - Buf *src_basename = buf_alloc(); - os_path_split(resolved_path, src_dirname, src_basename); - - Buf noextname = BUF_INIT; - os_path_extname(resolved_path, &noextname, nullptr); - - Buf *pkg_root_src_dir = &package->root_src_dir; - Buf resolved_root_src_dir = os_path_resolve(&pkg_root_src_dir, 1); - - Buf *namespace_name = buf_create_from_buf(&package->pkg_path); - if (source_kind == SourceKindNonRoot) { - assert(buf_starts_with_buf(resolved_path, &resolved_root_src_dir)); - if (buf_len(namespace_name) != 0) { - buf_append_char(namespace_name, NAMESPACE_SEP_CHAR); - } - // The namespace components are obtained from the relative path to the - // source directory - if (buf_len(&noextname) > buf_len(&resolved_root_src_dir)) { - // Skip the trailing separator - buf_append_mem(namespace_name, - buf_ptr(&noextname) + buf_len(&resolved_root_src_dir) + 1, - buf_len(&noextname) - buf_len(&resolved_root_src_dir) - 1); - } - buf_replace(namespace_name, ZIG_OS_SEP_CHAR, NAMESPACE_SEP_CHAR); - } - Buf *bare_name = buf_alloc(); - os_path_extname(src_basename, bare_name, nullptr); - - RootStruct *root_struct = heap::c_allocator.create(); - root_struct->package = package; - root_struct->source_code = source_code; - root_struct->path = resolved_path; - root_struct->di_file = ZigLLVMCreateFile(g->dbuilder, buf_ptr(src_basename), buf_ptr(src_dirname)); - - assert(tokenization.ids.length == tokenization.locs.length); - size_t token_count = tokenization.ids.length; - root_struct->token_count = token_count; - root_struct->token_ids = g->pass1_arena->allocate(token_count); - memcpy(root_struct->token_ids, tokenization.ids.items, token_count * sizeof(TokenId)); - root_struct->token_locs = g->pass1_arena->allocate(token_count); - memcpy(root_struct->token_locs, tokenization.locs.items, token_count * sizeof(TokenLoc)); - - tokenization.ids.deinit(); - tokenization.locs.deinit(); - - ZigType *import_entry = get_root_container_type(g, buf_ptr(namespace_name), bare_name, root_struct); - if (source_kind == SourceKindRoot) { - assert(g->root_import == nullptr); - g->root_import = import_entry; - } - g->import_table.put(resolved_path, import_entry); - - AstNode *root_node = ast_parse(source_code, import_entry, g->err_color); - assert(root_node != nullptr); - assert(root_node->type == NodeTypeContainerDecl); - import_entry->data.structure.decl_node = root_node; - import_entry->data.structure.decls_scope->base.source_node = root_node; - - for (size_t decl_i = 0; decl_i < root_node->data.container_decl.decls.length; decl_i += 1) { - AstNode *top_level_decl = root_node->data.container_decl.decls.at(decl_i); - scan_decls(g, import_entry->data.structure.decls_scope, top_level_decl); - } - - TldContainer *tld_container = heap::c_allocator.create(); - init_tld(&tld_container->base, TldIdContainer, namespace_name, VisibModPub, root_node, nullptr); - tld_container->type_entry = import_entry; - tld_container->decls_scope = import_entry->data.structure.decls_scope; - g->resolve_queue.append(&tld_container->base); - - return import_entry; -} - -void semantic_analyze(CodeGen *g) { - while (g->resolve_queue_index < g->resolve_queue.length || - g->fn_defs_index < g->fn_defs.length) - { - for (; g->resolve_queue_index < g->resolve_queue.length; g->resolve_queue_index += 1) { - Tld *tld = g->resolve_queue.at(g->resolve_queue_index); - g->trace_err = nullptr; - AstNode *source_node = nullptr; - resolve_top_level_decl(g, tld, source_node, false); - } - - for (; g->fn_defs_index < g->fn_defs.length; g->fn_defs_index += 1) { - ZigFn *fn_entry = g->fn_defs.at(g->fn_defs_index); - g->trace_err = nullptr; - analyze_fn_body(g, fn_entry); - } - } - - if (g->errors.length != 0) { - return; - } - - // second pass over functions for detecting async - for (g->fn_defs_index = 0; g->fn_defs_index < g->fn_defs.length; g->fn_defs_index += 1) { - ZigFn *fn = g->fn_defs.at(g->fn_defs_index); - g->trace_err = nullptr; - analyze_fn_async(g, fn, true); - if (fn->anal_state == FnAnalStateInvalid) - continue; - if (fn_is_async(fn) && fn->non_async_node != nullptr) { - ErrorMsg *msg = add_node_error(g, fn->proto_node, - buf_sprintf("'%s' cannot be async", buf_ptr(&fn->symbol_name))); - add_error_note(g, msg, fn->non_async_node, - buf_sprintf("required to be non-async here")); - add_async_error_notes(g, msg, fn); - } - } -} - -ZigType *get_int_type(CodeGen *g, bool is_signed, uint32_t size_in_bits) { - assert(size_in_bits <= 65535); - TypeId type_id = {}; - type_id.id = ZigTypeIdInt; - type_id.data.integer.is_signed = is_signed; - type_id.data.integer.bit_count = size_in_bits; - - { - auto entry = g->type_table.maybe_get(type_id); - if (entry) - return entry->value; - } - - ZigType *new_entry = make_int_type(g, is_signed, size_in_bits); - g->type_table.put(type_id, new_entry); - return new_entry; -} - -Error is_valid_vector_elem_type(CodeGen *g, ZigType *elem_type, bool *result) { - if (elem_type->id == ZigTypeIdInt || - elem_type->id == ZigTypeIdFloat || - elem_type->id == ZigTypeIdBool) - { - *result = true; - return ErrorNone; - } - - Error err; - ZigType *ptr_type; - if ((err = get_codegen_ptr_type(g, elem_type, &ptr_type))) return err; - if (ptr_type != nullptr) { - *result = true; - return ErrorNone; - } - - *result = false; - return ErrorNone; -} - -ZigType *get_vector_type(CodeGen *g, uint32_t len, ZigType *elem_type) { - Error err; - - bool valid_vector_elem; - if ((err = is_valid_vector_elem_type(g, elem_type, &valid_vector_elem))) { - codegen_report_errors_and_exit(g); - } - assert(valid_vector_elem); - - TypeId type_id = {}; - type_id.id = ZigTypeIdVector; - type_id.data.vector.len = len; - type_id.data.vector.elem_type = elem_type; - - { - auto entry = g->type_table.maybe_get(type_id); - if (entry) - return entry->value; - } - - ZigType *entry = new_type_table_entry(ZigTypeIdVector); - if ((len != 0) && type_has_bits(g, elem_type)) { - // Vectors can only be ints, floats, bools, or pointers. ints (inc. bools) and floats have trivially resolvable - // llvm type refs. pointers we will use usize instead. - LLVMTypeRef example_vector_llvm_type; - if (elem_type->id == ZigTypeIdPointer) { - example_vector_llvm_type = LLVMVectorType(g->builtin_types.entry_usize->llvm_type, len); - } else { - example_vector_llvm_type = LLVMVectorType(elem_type->llvm_type, len); - } - assert(example_vector_llvm_type != nullptr); - entry->size_in_bits = elem_type->size_in_bits * len; - entry->abi_size = LLVMABISizeOfType(g->target_data_ref, example_vector_llvm_type); - entry->abi_align = LLVMABIAlignmentOfType(g->target_data_ref, example_vector_llvm_type); - } - entry->data.vector.len = len; - entry->data.vector.elem_type = elem_type; - entry->data.vector.padding = 0; - - buf_resize(&entry->name, 0); - buf_appendf(&entry->name, "@Vector(%u, %s)", len, buf_ptr(&elem_type->name)); - - g->type_table.put(type_id, entry); - return entry; -} - -ZigType **get_c_int_type_ptr(CodeGen *g, CIntType c_int_type) { - return &g->builtin_types.entry_c_int[c_int_type]; -} - -ZigType *get_c_int_type(CodeGen *g, CIntType c_int_type) { - return *get_c_int_type_ptr(g, c_int_type); -} - -bool handle_is_ptr(CodeGen *g, ZigType *type_entry) { - switch (type_entry->id) { - case ZigTypeIdInvalid: - case ZigTypeIdMetaType: - case ZigTypeIdComptimeFloat: - case ZigTypeIdComptimeInt: - case ZigTypeIdEnumLiteral: - case ZigTypeIdUndefined: - case ZigTypeIdNull: - case ZigTypeIdBoundFn: - case ZigTypeIdOpaque: - zig_unreachable(); - case ZigTypeIdUnreachable: - case ZigTypeIdVoid: - case ZigTypeIdBool: - case ZigTypeIdInt: - case ZigTypeIdFloat: - case ZigTypeIdPointer: - case ZigTypeIdErrorSet: - case ZigTypeIdFn: - case ZigTypeIdEnum: - case ZigTypeIdVector: - case ZigTypeIdAnyFrame: - return false; - case ZigTypeIdArray: - case ZigTypeIdStruct: - case ZigTypeIdFnFrame: - return type_has_bits(g, type_entry); - case ZigTypeIdErrorUnion: - return type_has_bits(g, type_entry->data.error_union.payload_type); - case ZigTypeIdOptional: - return type_has_bits(g, type_entry->data.maybe.child_type) && - !type_is_nonnull_ptr(g, type_entry->data.maybe.child_type) && - type_entry->data.maybe.child_type->id != ZigTypeIdErrorSet; - case ZigTypeIdUnion: - return type_has_bits(g, type_entry) && type_entry->data.unionation.gen_field_count != 0; - - } - zig_unreachable(); -} - -static const uint32_t HASH_INIT = 0x811c9dc5U; - -template -static uint32_t hash_combine(uint32_t hash, const T *value, size_t count = 1) { - // Simple FNV32 hash - size_t len = sizeof(T) * count; - const unsigned char *char_bytes = (const unsigned char*)value; - for (size_t c = 0; c < len; ++c) { - hash ^= char_bytes[c]; - hash *= 0x01000193U; - } - return hash; -} - -static uint32_t hash_combine_bigint(uint32_t hash, const BigInt *value) { - return hash_combine(hash, bigint_ptr(value), value->digit_count); -} - -static uint32_t hash_combine_buf(uint32_t hash, const Buf *buf) { - return hash_combine(hash, buf_ptr(buf), buf_len(buf)); -} - -uint32_t fn_table_entry_hash(ZigFn* value) { - return hash_combine(HASH_INIT, &value); -} - -bool fn_table_entry_eql(ZigFn *a, ZigFn *b) { - return a == b; -} - -uint32_t fn_type_id_hash(FnTypeId *id) { - uint32_t hash = HASH_INIT; - hash = hash_combine(hash, &id->cc); - hash = hash_combine(hash, &id->is_var_args); - hash = hash_combine(hash, &id->return_type); - hash = hash_combine(hash, &id->alignment); - for (size_t i = 0; i < id->param_count; i += 1) { - FnTypeParamInfo *info = &id->param_info[i]; - hash = hash_combine(hash, &info->is_noalias); - hash = hash_combine(hash, &info->type); - } - return hash; -} - -bool fn_type_id_eql(FnTypeId *a, FnTypeId *b) { - if (a->cc != b->cc || - a->return_type != b->return_type || - a->is_var_args != b->is_var_args || - a->param_count != b->param_count || - a->alignment != b->alignment) - { - return false; - } - for (size_t i = 0; i < a->param_count; i += 1) { - FnTypeParamInfo *a_param_info = &a->param_info[i]; - FnTypeParamInfo *b_param_info = &b->param_info[i]; - - if (a_param_info->type != b_param_info->type || - a_param_info->is_noalias != b_param_info->is_noalias) - { - return false; - } - } - return true; -} - -static uint32_t hash_combine_const_val_error_set(uint32_t hash_val, ZigValue *const_val) { - assert(const_val->data.x_err_set != nullptr); - return hash_combine(hash_val, &const_val->data.x_err_set->value); -} - -static uint32_t hash_combine_const_val_ptr(uint32_t hash_val, ZigValue *const_val) { - hash_val = hash_combine(hash_val, &const_val->data.x_ptr.special); - switch (const_val->data.x_ptr.special) { - case ConstPtrSpecialInvalid: - zig_unreachable(); - case ConstPtrSpecialRef: - hash_val = hash_combine(hash_val, &const_val->data.x_ptr.data.ref.pointee); - return hash_val; - case ConstPtrSpecialBaseArray: - hash_val = hash_combine(hash_val, &const_val->data.x_ptr.data.base_array.array_val); - hash_val = hash_combine(hash_val, &const_val->data.x_ptr.data.base_array.elem_index); - return hash_val; - case ConstPtrSpecialSubArray: - hash_val = hash_combine(hash_val, &const_val->data.x_ptr.data.base_array.array_val); - hash_val = hash_combine(hash_val, &const_val->data.x_ptr.data.base_array.elem_index); - return hash_val; - case ConstPtrSpecialBaseStruct: - hash_val = hash_combine(hash_val, &const_val->data.x_ptr.data.base_struct.struct_val); - hash_val = hash_combine(hash_val, &const_val->data.x_ptr.data.base_struct.field_index); - return hash_val; - case ConstPtrSpecialBaseErrorUnionCode: - hash_val = hash_combine(hash_val, &const_val->data.x_ptr.data.base_err_union_code.err_union_val); - return hash_val; - case ConstPtrSpecialBaseErrorUnionPayload: - hash_val = hash_combine(hash_val, &const_val->data.x_ptr.data.base_err_union_payload.err_union_val); - return hash_val; - case ConstPtrSpecialBaseOptionalPayload: - hash_val = hash_combine(hash_val, &const_val->data.x_ptr.data.base_optional_payload.optional_val); - return hash_val; - case ConstPtrSpecialHardCodedAddr: - hash_val = hash_combine(hash_val, &const_val->data.x_ptr.data.hard_coded_addr.addr); - return hash_val; - case ConstPtrSpecialFunction: - hash_val = hash_combine(hash_val, &const_val->data.x_ptr.data.fn.fn_entry); - return hash_val; - case ConstPtrSpecialDiscard: - case ConstPtrSpecialNull: - // No fields to hash - return hash_val; - } - zig_unreachable(); -} - -static uint32_t hash_combine_const_val(uint32_t hash_val, ZigValue *const_val); -static uint32_t hash_combine_const_val_array(uint32_t hash_val, ZigValue *array, size_t len) { - if (array->data.x_array.special == ConstArraySpecialUndef) { - char undef_tag = 56; - return hash_combine(hash_val, &undef_tag); - } else if (array->data.x_array.special == ConstArraySpecialBuf) { - // Hash in a way that is compatible with standard byte arrays - // If any of these asserts fails, the if after this needs to be modified - // to handle the new type in SpecialBuf. - assert(array->type->data.array.child_type->id == ZigTypeIdInt); - assert(array->type->data.array.child_type->data.integral.bit_count == 8); - assert(array->type->data.array.child_type->data.integral.is_signed == false); - const char *buf_pos = buf_ptr(array->data.x_array.data.s_buf); - const char *buf_end = buf_pos + buf_len(array->data.x_array.data.s_buf); - while (buf_pos < buf_end) { - hash_val = hash_combine(hash_val, buf_pos); - buf_pos++; - } - return hash_val; - } else if (array->type->data.array.child_type->id == ZigTypeIdInt && - array->type->data.array.child_type->data.integral.bit_count == 8 && - array->type->data.array.child_type->data.integral.is_signed == false) { - // If the type is u8, we hash it as if it's a ConstArraySpecialBuf, - // to maintain compatibility. - ZigValue *elems = array->data.x_array.data.s_none.elements; - for (size_t i = 0; i < len; i += 1) { - ZigValue *value = &elems[i]; - assert(value->type == array->type->data.array.child_type); - // N.B. Using char here instead of uint8_t to match the const char* - // returned by buf_ptr. - const char byte_value = (char) bigint_as_u8(&value->data.x_bigint); - hash_val = hash_combine(hash_val, &byte_value); - } - return hash_val; - } else { - ZigValue *elems = array->data.x_array.data.s_none.elements; - for (size_t i = 0; i < len; i += 1) { - hash_val = hash_combine_const_val(hash_val, &elems[i]); - } - return hash_val; - } -} -static uint32_t hash_combine_const_val(uint32_t hash_val, ZigValue *const_val) { - hash_val = hash_combine(hash_val, &const_val->special); - if (const_val->special == ConstValSpecialUndef) { - return hash_val; - } - assert(const_val->special == ConstValSpecialStatic); - hash_val = hash_combine(hash_val, &const_val->type->id); - switch (const_val->type->id) { - case ZigTypeIdOpaque: - zig_unreachable(); - case ZigTypeIdBool: - return hash_combine(hash_val, &const_val->data.x_bool); - case ZigTypeIdMetaType: - return hash_combine(hash_val, &const_val->data.x_type); - case ZigTypeIdInt: - case ZigTypeIdComptimeInt: - return hash_combine_bigint(hash_val, &const_val->data.x_bigint); - case ZigTypeIdEnumLiteral: - return hash_combine_buf(hash_val, const_val->data.x_enum_literal); - case ZigTypeIdEnum: - return hash_combine_bigint(hash_val, &const_val->data.x_enum_tag); - case ZigTypeIdFloat: - hash_val = hash_combine(hash_val, &const_val->type->data.floating.bit_count); - switch (const_val->type->data.floating.bit_count) { - case 16: return hash_combine(hash_val, &const_val->data.x_f16); - case 32: return hash_combine(hash_val, &const_val->data.x_f32); - case 64: return hash_combine(hash_val, &const_val->data.x_f64); - case 80: - hash_val = hash_combine(hash_val, &const_val->data.x_f80.signExp); - return hash_combine(hash_val, &const_val->data.x_f80.signif); - case 128: return hash_combine(hash_val, &const_val->data.x_f128); - default: zig_unreachable(); - } - case ZigTypeIdComptimeFloat: - return hash_combine(hash_val, &const_val->data.x_bigfloat.value); - case ZigTypeIdFn: - assert(const_val->data.x_ptr.mut == ConstPtrMutComptimeConst); - assert(const_val->data.x_ptr.special == ConstPtrSpecialFunction); - return hash_combine(hash_val, &const_val->data.x_ptr.data.fn.fn_entry); - case ZigTypeIdPointer: - return hash_combine_const_val_ptr(hash_val, const_val); - case ZigTypeIdVoid: - case ZigTypeIdUndefined: - case ZigTypeIdNull: - return hash_val; - case ZigTypeIdArray: - return hash_combine_const_val_array(hash_val, const_val, const_val->type->data.array.len); - case ZigTypeIdStruct: { - size_t field_count = const_val->type->data.structure.src_field_count; - for (size_t i = 0; i < field_count; i += 1) { - if (const_val->type->data.structure.fields[i]->is_comptime) { - // The values of comptime struct fields are part of the - // type, not the value, so they do not participate in equality - // or hash of comptime values. - continue; - } - ZigValue *field = const_val->data.x_struct.fields[i]; - hash_val = hash_combine_const_val(hash_val, field); - } - return hash_val; - } - case ZigTypeIdUnion: { - ConstUnionValue *union_value = &const_val->data.x_union; - hash_val = hash_combine_bigint(hash_val, &union_value->tag); - return hash_combine_const_val(hash_val, union_value->payload); - } - case ZigTypeIdOptional: - if (get_src_ptr_type(const_val->type) != nullptr) { - char tag = 1; - hash_val = hash_combine(hash_val, &tag); - return hash_combine_const_val_ptr(hash_val, const_val); - } else if (const_val->type->data.maybe.child_type->id == ZigTypeIdErrorSet) { - char tag = 2; - hash_val = hash_combine(hash_val, &tag); - return hash_combine_const_val_error_set(hash_val, const_val); - } else if (const_val->data.x_optional) { - char tag = 3; - hash_val = hash_combine(hash_val, &tag); - return hash_combine_const_val(hash_val, const_val->data.x_optional); - } else { - char tag = 4; - hash_val = hash_combine(hash_val, &tag); - return hash_val; - } - case ZigTypeIdErrorUnion: { - bool is_err = const_val->data.x_err_union.error_set->data.x_err_set != nullptr; - hash_val = hash_combine(hash_val, &is_err); - if (is_err) { - hash_val = hash_combine_const_val(hash_val, const_val->data.x_err_union.error_set); - } else { - hash_val = hash_combine_const_val(hash_val, const_val->data.x_err_union.payload); - } - return hash_val; - } - case ZigTypeIdErrorSet: - return hash_combine_const_val_error_set(hash_val, const_val); - case ZigTypeIdVector: - return hash_combine_const_val_array(hash_val, const_val, const_val->type->data.vector.len); - case ZigTypeIdFnFrame: - // TODO better hashing algorithm - return hash_val; - case ZigTypeIdAnyFrame: - // TODO better hashing algorithm - return hash_val; - case ZigTypeIdBoundFn: { - assert(const_val->data.x_bound_fn.fn != nullptr); - return hash_combine(hash_val, &const_val->data.x_bound_fn.fn); - } - case ZigTypeIdInvalid: - case ZigTypeIdUnreachable: - zig_unreachable(); - } - zig_unreachable(); -} - -uint32_t generic_fn_type_id_hash(GenericFnTypeId *id) { - uint32_t result = HASH_INIT; - result = hash_combine(result, &id->fn_entry); - for (size_t i = 0; i < id->param_count; i += 1) { - ZigValue *generic_param = &id->params[i]; - if (generic_param->special != ConstValSpecialRuntime) { - result = hash_combine_const_val(result, generic_param); - result = hash_combine(result, &generic_param->type); - } - } - return result; -} - -bool generic_fn_type_id_eql(GenericFnTypeId *a, GenericFnTypeId *b) { - assert(a->fn_entry); - if (a->fn_entry != b->fn_entry) return false; - if (a->param_count != b->param_count) return false; - for (size_t i = 0; i < a->param_count; i += 1) { - ZigValue *a_val = &a->params[i]; - ZigValue *b_val = &b->params[i]; - if (a_val->type != b_val->type) return false; - if (a_val->special != ConstValSpecialRuntime && b_val->special != ConstValSpecialRuntime) { - assert(a_val->special == ConstValSpecialStatic); - assert(b_val->special == ConstValSpecialStatic); - if (!const_values_equal(a->codegen, a_val, b_val)) { - return false; - } - } else { - assert(a_val->special == ConstValSpecialRuntime && b_val->special == ConstValSpecialRuntime); - } - } - return true; -} - -static bool can_mutate_comptime_var_state(ZigValue *value) { - assert(value != nullptr); - if (value->special == ConstValSpecialUndef) - return false; - - if (value->special == ConstValSpecialLazy) { - // No lazy value has side effects. - // Use a switch here to get a compile error whenever a new kind of lazy - // value is added. - switch (value->data.x_lazy->id) { - case LazyValueIdInvalid: - zig_unreachable(); - - case LazyValueIdAlignOf: - case LazyValueIdSizeOf: - case LazyValueIdPtrType: - case LazyValueIdPtrTypeSimple: - case LazyValueIdPtrTypeSimpleConst: - case LazyValueIdOptType: - case LazyValueIdSliceType: - case LazyValueIdFnType: - case LazyValueIdErrUnionType: - case LazyValueIdArrayType: - case LazyValueIdTypeInfoDecls: - return false; - } - } - - switch (value->type->id) { - case ZigTypeIdInvalid: - zig_unreachable(); - case ZigTypeIdMetaType: - case ZigTypeIdVoid: - case ZigTypeIdBool: - case ZigTypeIdUnreachable: - case ZigTypeIdInt: - case ZigTypeIdVector: - case ZigTypeIdFloat: - case ZigTypeIdComptimeFloat: - case ZigTypeIdComptimeInt: - case ZigTypeIdEnumLiteral: - case ZigTypeIdUndefined: - case ZigTypeIdNull: - case ZigTypeIdBoundFn: - case ZigTypeIdFn: - case ZigTypeIdOpaque: - case ZigTypeIdErrorSet: - case ZigTypeIdEnum: - case ZigTypeIdFnFrame: - case ZigTypeIdAnyFrame: - return false; - - case ZigTypeIdPointer: - return value->data.x_ptr.mut == ConstPtrMutComptimeVar; - - case ZigTypeIdArray: - if (value->special == ConstValSpecialUndef) - return false; - if (value->type->data.array.len == 0) - return false; - switch (value->data.x_array.special) { - case ConstArraySpecialUndef: - case ConstArraySpecialBuf: - return false; - case ConstArraySpecialNone: - for (uint32_t i = 0; i < value->type->data.array.len; i += 1) { - if (can_mutate_comptime_var_state(&value->data.x_array.data.s_none.elements[i])) - return true; - } - return false; - } - zig_unreachable(); - case ZigTypeIdStruct: - for (uint32_t i = 0; i < value->type->data.structure.src_field_count; i += 1) { - TypeStructField *type_struct_field = value->type->data.structure.fields[i]; - - ZigValue *field_value = type_struct_field->is_comptime ? - type_struct_field->init_val : - value->data.x_struct.fields[i]; - - if (can_mutate_comptime_var_state(field_value)) - return true; - } - return false; - - case ZigTypeIdOptional: - if (get_src_ptr_type(value->type) != nullptr) - return value->data.x_ptr.mut == ConstPtrMutComptimeVar; - if (value->data.x_optional == nullptr) - return false; - return can_mutate_comptime_var_state(value->data.x_optional); - - case ZigTypeIdErrorUnion: - if (value->data.x_err_union.error_set->data.x_err_set != nullptr) - return false; - assert(value->data.x_err_union.payload != nullptr); - return can_mutate_comptime_var_state(value->data.x_err_union.payload); - - case ZigTypeIdUnion: - return can_mutate_comptime_var_state(value->data.x_union.payload); - } - zig_unreachable(); -} - -bool fn_eval_cacheable(Scope *scope, ZigType *return_type) { - while (scope) { - if (scope->id == ScopeIdVarDecl) { - ScopeVarDecl *var_scope = (ScopeVarDecl *)scope; - if (type_is_invalid(var_scope->var->var_type)) - return false; - if (var_scope->var->const_value->special == ConstValSpecialUndef) - return false; - if (can_mutate_comptime_var_state(var_scope->var->const_value)) - return false; - } else if (scope->id == ScopeIdFnDef) { - return true; - } else { - zig_unreachable(); - } - - scope = scope->parent; - } - zig_unreachable(); -} - -uint32_t fn_eval_hash(Scope* scope) { - uint32_t hash = HASH_INIT; - while (scope) { - if (scope->id == ScopeIdVarDecl) { - ScopeVarDecl *var_scope = (ScopeVarDecl *)scope; - hash = hash_combine_const_val(hash, var_scope->var->const_value); - } else if (scope->id == ScopeIdFnDef) { - ScopeFnDef *fn_scope = (ScopeFnDef *)scope; - hash = hash_combine(hash, &fn_scope->fn_entry); - return hash; - } else { - zig_unreachable(); - } - - scope = scope->parent; - } - zig_unreachable(); -} - -bool fn_eval_eql(Scope *a, Scope *b) { - assert(a->codegen != nullptr); - assert(b->codegen != nullptr); - while (a && b) { - if (a->id != b->id) - return false; - - if (a->id == ScopeIdVarDecl) { - ScopeVarDecl *a_var_scope = (ScopeVarDecl *)a; - ScopeVarDecl *b_var_scope = (ScopeVarDecl *)b; - if (a_var_scope->var->var_type != b_var_scope->var->var_type) - return false; - if (a_var_scope->var->var_type == a_var_scope->var->const_value->type && - b_var_scope->var->var_type == b_var_scope->var->const_value->type) - { - if (!const_values_equal(a->codegen, a_var_scope->var->const_value, b_var_scope->var->const_value)) - return false; - } else { - zig_panic("TODO comptime ptr reinterpret for fn_eval_eql"); - } - } else if (a->id == ScopeIdFnDef) { - ScopeFnDef *a_fn_scope = (ScopeFnDef *)a; - ScopeFnDef *b_fn_scope = (ScopeFnDef *)b; - if (a_fn_scope->fn_entry != b_fn_scope->fn_entry) - return false; - - return true; - } else { - zig_unreachable(); - } - - a = a->parent; - b = b->parent; - } - return false; -} - -// Deprecated. Use type_has_bits2. -bool type_has_bits(CodeGen *g, ZigType *type_entry) { - Error err; - bool result; - if ((err = type_has_bits2(g, type_entry, &result))) { - codegen_report_errors_and_exit(g); - } - return result; -} - -// Whether the type has bits at runtime. -Error type_has_bits2(CodeGen *g, ZigType *type_entry, bool *result) { - Error err; - - if (type_is_invalid(type_entry)) - return ErrorSemanticAnalyzeFail; - - if (type_entry->id == ZigTypeIdStruct && - type_entry->data.structure.resolve_status == ResolveStatusBeingInferred) - { - *result = true; - return ErrorNone; - } - - if ((err = type_resolve(g, type_entry, ResolveStatusZeroBitsKnown))) - return err; - - *result = type_entry->abi_size != 0; - return ErrorNone; -} - -bool fn_returns_c_abi_small_struct(FnTypeId *fn_type_id) { - ZigType *type = fn_type_id->return_type; - return !calling_convention_allows_zig_types(fn_type_id->cc) && - type->id == ZigTypeIdStruct && type->abi_size <= 16; -} - -// Whether you can infer the value based solely on the type. -OnePossibleValue type_has_one_possible_value(CodeGen *g, ZigType *type_entry) { - assert(type_entry != nullptr); - - if (type_entry->one_possible_value != OnePossibleValueInvalid) - return type_entry->one_possible_value; - - if (type_entry->id == ZigTypeIdStruct && - type_entry->data.structure.resolve_status == ResolveStatusBeingInferred) - { - return OnePossibleValueNo; - } - - Error err; - if ((err = type_resolve(g, type_entry, ResolveStatusZeroBitsKnown))) - return OnePossibleValueInvalid; - switch (type_entry->id) { - case ZigTypeIdInvalid: - zig_unreachable(); - case ZigTypeIdOpaque: - case ZigTypeIdComptimeFloat: - case ZigTypeIdComptimeInt: - case ZigTypeIdEnumLiteral: - case ZigTypeIdMetaType: - case ZigTypeIdBoundFn: - case ZigTypeIdOptional: - case ZigTypeIdFn: - case ZigTypeIdBool: - case ZigTypeIdFloat: - case ZigTypeIdErrorUnion: - case ZigTypeIdFnFrame: - case ZigTypeIdAnyFrame: - return OnePossibleValueNo; - case ZigTypeIdUndefined: - case ZigTypeIdNull: - case ZigTypeIdVoid: - case ZigTypeIdUnreachable: - return OnePossibleValueYes; - case ZigTypeIdArray: - if (type_entry->data.array.len == 0) - return OnePossibleValueYes; - return type_has_one_possible_value(g, type_entry->data.array.child_type); - case ZigTypeIdStruct: - // If the recursive function call asks, then we are not one possible value. - type_entry->one_possible_value = OnePossibleValueNo; - for (size_t i = 0; i < type_entry->data.structure.src_field_count; i += 1) { - TypeStructField *field = type_entry->data.structure.fields[i]; - if (field->is_comptime) { - // If this field is comptime then the field can only be one possible value - continue; - } - OnePossibleValue opv = (field->type_entry != nullptr) ? - type_has_one_possible_value(g, field->type_entry) : - type_val_resolve_has_one_possible_value(g, field->type_val); - switch (opv) { - case OnePossibleValueInvalid: - type_entry->one_possible_value = OnePossibleValueInvalid; - return OnePossibleValueInvalid; - case OnePossibleValueNo: - return OnePossibleValueNo; - case OnePossibleValueYes: - continue; - } - } - type_entry->one_possible_value = OnePossibleValueYes; - return OnePossibleValueYes; - case ZigTypeIdErrorSet: - case ZigTypeIdEnum: - case ZigTypeIdInt: - case ZigTypeIdVector: - return type_has_bits(g, type_entry) ? OnePossibleValueNo : OnePossibleValueYes; - case ZigTypeIdPointer: { - ZigType *elem_type = type_entry->data.pointer.child_type; - // If the recursive function call asks, then we are not one possible value. - type_entry->one_possible_value = OnePossibleValueNo; - // Now update it to be the value of the recursive call. - type_entry->one_possible_value = type_has_one_possible_value(g, elem_type); - return type_entry->one_possible_value; - } - case ZigTypeIdUnion: - if (type_entry->data.unionation.src_field_count > 1) - return OnePossibleValueNo; - TypeUnionField *only_field = &type_entry->data.unionation.fields[0]; - if (only_field->type_entry != nullptr) { - return type_has_one_possible_value(g, only_field->type_entry); - } - return type_val_resolve_has_one_possible_value(g, only_field->type_val); - } - zig_unreachable(); -} - -ZigValue *get_the_one_possible_value(CodeGen *g, ZigType *type_entry) { - auto entry = g->one_possible_values.maybe_get(type_entry); - if (entry != nullptr) { - return entry->value; - } - ZigValue *result = g->pass1_arena->create(); - result->type = type_entry; - result->special = ConstValSpecialStatic; - - if (result->type->id == ZigTypeIdStruct) { - // The fields array cannot be left unpopulated - const ZigType *struct_type = result->type; - const size_t field_count = struct_type->data.structure.src_field_count; - result->data.x_struct.fields = alloc_const_vals_ptrs(g, field_count); - for (size_t i = 0; i < field_count; i += 1) { - TypeStructField *field = struct_type->data.structure.fields[i]; - if (field->is_comptime) { - // Comptime fields are part of the type, and do not need to - // be initialized. - continue; - } - ZigType *field_type = resolve_struct_field_type(g, field); - assert(field_type != nullptr); - copy_const_val(g, result->data.x_struct.fields[i], - get_the_one_possible_value(g, field_type)); - } - } else if (result->type->id == ZigTypeIdArray) { - // The elements array cannot be left unpopulated - ZigType *array_type = result->type; - ZigType *elem_type = array_type->data.array.child_type; - const size_t elem_count = array_type->data.array.len; - - result->data.x_array.data.s_none.elements = g->pass1_arena->allocate(elem_count); - for (size_t i = 0; i < elem_count; i += 1) { - ZigValue *elem_val = &result->data.x_array.data.s_none.elements[i]; - copy_const_val(g, elem_val, get_the_one_possible_value(g, elem_type)); - } - } else if (result->type->id == ZigTypeIdUnion) { - // The payload/tag fields cannot be left unpopulated - ZigType *union_type = result->type; - assert(union_type->data.unionation.src_field_count == 1); - TypeUnionField *only_field = &union_type->data.unionation.fields[0]; - ZigType *field_type = resolve_union_field_type(g, only_field); - assert(field_type); - bigint_init_bigint(&result->data.x_union.tag, &only_field->enum_field->value); - result->data.x_union.payload = g->pass1_arena->create(); - copy_const_val(g, result->data.x_union.payload, - get_the_one_possible_value(g, field_type)); - } else if (result->type->id == ZigTypeIdPointer) { - // Make sure nobody can modify the constant value - result->data.x_ptr.mut = ConstPtrMutComptimeConst; - result->data.x_ptr.special = ConstPtrSpecialRef; - result->data.x_ptr.data.ref.pointee = get_the_one_possible_value(g, result->type->data.pointer.child_type); - } else if (result->type->id == ZigTypeIdEnum) { - ZigType *enum_type = result->type; - assert(enum_type->data.enumeration.src_field_count == 1); - TypeEnumField *only_field = &result->type->data.enumeration.fields[0]; - bigint_init_bigint(&result->data.x_enum_tag, &only_field->value); - } - g->one_possible_values.put(type_entry, result); - return result; -} - -ReqCompTime type_requires_comptime(CodeGen *g, ZigType *ty) { - Error err; - if (ty == g->builtin_types.entry_anytype) { - return ReqCompTimeYes; - } - switch (ty->id) { - case ZigTypeIdInvalid: - zig_unreachable(); - case ZigTypeIdComptimeFloat: - case ZigTypeIdComptimeInt: - case ZigTypeIdEnumLiteral: - case ZigTypeIdUndefined: - case ZigTypeIdNull: - case ZigTypeIdMetaType: - case ZigTypeIdBoundFn: - return ReqCompTimeYes; - case ZigTypeIdArray: - return type_requires_comptime(g, ty->data.array.child_type); - case ZigTypeIdStruct: - if (ty->data.structure.resolve_loop_flag_zero_bits) { - // Does a struct which contains a pointer field to itself require comptime? No. - return ReqCompTimeNo; - } - if ((err = type_resolve(g, ty, ResolveStatusZeroBitsKnown))) - return ReqCompTimeInvalid; - return ty->data.structure.requires_comptime ? ReqCompTimeYes : ReqCompTimeNo; - case ZigTypeIdUnion: - if (ty->data.unionation.resolve_loop_flag_zero_bits) { - // Does a union which contains a pointer field to itself require comptime? No. - return ReqCompTimeNo; - } - if ((err = type_resolve(g, ty, ResolveStatusZeroBitsKnown))) - return ReqCompTimeInvalid; - return ty->data.unionation.requires_comptime ? ReqCompTimeYes : ReqCompTimeNo; - case ZigTypeIdOptional: - return type_requires_comptime(g, ty->data.maybe.child_type); - case ZigTypeIdErrorUnion: - return type_requires_comptime(g, ty->data.error_union.payload_type); - case ZigTypeIdPointer: - if (ty->data.pointer.child_type->id == ZigTypeIdOpaque) { - return ReqCompTimeNo; - } else { - return type_requires_comptime(g, ty->data.pointer.child_type); - } - case ZigTypeIdFn: - return ty->data.fn.is_generic ? ReqCompTimeYes : ReqCompTimeNo; - case ZigTypeIdOpaque: - case ZigTypeIdEnum: - case ZigTypeIdErrorSet: - case ZigTypeIdBool: - case ZigTypeIdInt: - case ZigTypeIdVector: - case ZigTypeIdFloat: - case ZigTypeIdVoid: - case ZigTypeIdUnreachable: - case ZigTypeIdFnFrame: - case ZigTypeIdAnyFrame: - return ReqCompTimeNo; - } - zig_unreachable(); -} - -void init_const_str_lit(CodeGen *g, ZigValue *const_val, Buf *str, bool move_str) { - auto entry = g->string_literals_table.maybe_get(str); - if (entry != nullptr) { - if (move_str) { - buf_destroy(str); - } - memcpy(const_val, entry->value, sizeof(ZigValue)); - return; - } - - // first we build the underlying array - ZigValue *array_val = g->pass1_arena->create(); - array_val->special = ConstValSpecialStatic; - array_val->type = get_array_type(g, g->builtin_types.entry_u8, buf_len(str), g->intern.for_zero_byte()); - array_val->data.x_array.special = ConstArraySpecialBuf; - array_val->data.x_array.data.s_buf = str; - - // then make the pointer point to it - const_val->special = ConstValSpecialStatic; - const_val->type = get_pointer_to_type_extra2(g, array_val->type, true, false, - PtrLenSingle, 0, 0, 0, false, VECTOR_INDEX_NONE, nullptr, nullptr); - const_val->data.x_ptr.special = ConstPtrSpecialRef; - const_val->data.x_ptr.data.ref.pointee = array_val; - - g->string_literals_table.put(str, const_val); -} - -ZigValue *create_const_str_lit(CodeGen *g, Buf *str) { - ZigValue *const_val = g->pass1_arena->create(); - init_const_str_lit(g, const_val, str, false); - return const_val; -} - -ZigValue *create_sentineled_str_lit(CodeGen *g, Buf *str, ZigValue *sentinel) { - ZigValue *array_val = create_const_str_lit(g, str)->data.x_ptr.data.ref.pointee; - return create_const_slice(g, array_val, 0, buf_len(str), true, sentinel); -} - -void init_const_bigint(ZigValue *const_val, ZigType *type, const BigInt *bigint) { - const_val->special = ConstValSpecialStatic; - const_val->type = type; - bigint_init_bigint(&const_val->data.x_bigint, bigint); -} - -ZigValue *create_const_bigint(CodeGen *g, ZigType *type, const BigInt *bigint) { - ZigValue *const_val = g->pass1_arena->create(); - init_const_bigint(const_val, type, bigint); - return const_val; -} - - -void init_const_unsigned_negative(ZigValue *const_val, ZigType *type, uint64_t x, bool negative) { - const_val->special = ConstValSpecialStatic; - const_val->type = type; - bigint_init_unsigned(&const_val->data.x_bigint, x); - const_val->data.x_bigint.is_negative = negative; -} - -ZigValue *create_const_unsigned_negative(CodeGen *g, ZigType *type, uint64_t x, bool negative) { - ZigValue *const_val = g->pass1_arena->create(); - init_const_unsigned_negative(const_val, type, x, negative); - return const_val; -} - -void init_const_usize(CodeGen *g, ZigValue *const_val, uint64_t x) { - return init_const_unsigned_negative(const_val, g->builtin_types.entry_usize, x, false); -} - -ZigValue *create_const_usize(CodeGen *g, uint64_t x) { - return create_const_unsigned_negative(g, g->builtin_types.entry_usize, x, false); -} - -void init_const_signed(ZigValue *const_val, ZigType *type, int64_t x) { - const_val->special = ConstValSpecialStatic; - const_val->type = type; - bigint_init_signed(&const_val->data.x_bigint, x); -} - -ZigValue *create_const_signed(CodeGen *g, ZigType *type, int64_t x) { - ZigValue *const_val = g->pass1_arena->create(); - init_const_signed(const_val, type, x); - return const_val; -} - -void init_const_null(ZigValue *const_val, ZigType *type) { - const_val->special = ConstValSpecialStatic; - const_val->type = type; - const_val->data.x_optional = nullptr; -} - -ZigValue *create_const_null(CodeGen *g, ZigType *type) { - ZigValue *const_val = g->pass1_arena->create(); - init_const_null(const_val, type); - return const_val; -} - -void init_const_fn(ZigValue *const_val, ZigFn *fn) { - const_val->special = ConstValSpecialStatic; - const_val->type = fn->type_entry; - const_val->data.x_ptr.special = ConstPtrSpecialFunction; - const_val->data.x_ptr.data.fn.fn_entry = fn; -} - -ZigValue *create_const_fn(CodeGen *g, ZigFn *fn) { - ZigValue *const_val = g->pass1_arena->create(); - init_const_fn(const_val, fn); - return const_val; -} - -void init_const_float(ZigValue *const_val, ZigType *type, double value) { - const_val->special = ConstValSpecialStatic; - const_val->type = type; - if (type->id == ZigTypeIdComptimeFloat) { - bigfloat_init_64(&const_val->data.x_bigfloat, value); - } else if (type->id == ZigTypeIdFloat) { - switch (type->data.floating.bit_count) { - case 16: - const_val->data.x_f16 = zig_double_to_f16(value); - break; - case 32: - const_val->data.x_f32 = value; - break; - case 64: - const_val->data.x_f64 = value; - break; - case 80: - zig_double_to_extF80M(value, &const_val->data.x_f80); - break; - case 128: - zig_double_to_f128M(value, &const_val->data.x_f128); - break; - default: - zig_unreachable(); - } - } else { - zig_unreachable(); - } -} - -ZigValue *create_const_float(CodeGen *g, ZigType *type, double value) { - ZigValue *const_val = g->pass1_arena->create(); - init_const_float(const_val, type, value); - return const_val; -} - -void init_const_enum(ZigValue *const_val, ZigType *type, const BigInt *tag) { - const_val->special = ConstValSpecialStatic; - const_val->type = type; - bigint_init_bigint(&const_val->data.x_enum_tag, tag); -} - -ZigValue *create_const_enum(CodeGen *g, ZigType *type, const BigInt *tag) { - ZigValue *const_val = g->pass1_arena->create(); - init_const_enum(const_val, type, tag); - return const_val; -} - - -void init_const_bool(CodeGen *g, ZigValue *const_val, bool value) { - const_val->special = ConstValSpecialStatic; - const_val->type = g->builtin_types.entry_bool; - const_val->data.x_bool = value; -} - -ZigValue *create_const_bool(CodeGen *g, bool value) { - ZigValue *const_val = g->pass1_arena->create(); - init_const_bool(g, const_val, value); - return const_val; -} - -void init_const_runtime(ZigValue *const_val, ZigType *type) { - const_val->special = ConstValSpecialRuntime; - const_val->type = type; -} - -ZigValue *create_const_runtime(CodeGen *g, ZigType *type) { - ZigValue *const_val = g->pass1_arena->create(); - init_const_runtime(const_val, type); - return const_val; -} - -void init_const_type(CodeGen *g, ZigValue *const_val, ZigType *type_value) { - const_val->special = ConstValSpecialStatic; - const_val->type = g->builtin_types.entry_type; - const_val->data.x_type = type_value; -} - -ZigValue *create_const_type(CodeGen *g, ZigType *type_value) { - ZigValue *const_val = g->pass1_arena->create(); - init_const_type(g, const_val, type_value); - return const_val; -} - -void init_const_slice(CodeGen *g, ZigValue *const_val, ZigValue *array_val, - size_t start, size_t len, bool is_const, ZigValue *sentinel) -{ - assert(array_val->type->id == ZigTypeIdArray); - - ZigType *ptr_type = get_pointer_to_type_extra2(g, array_val->type->data.array.child_type, - is_const, false, PtrLenUnknown, 0, 0, 0, false, VECTOR_INDEX_NONE, nullptr, sentinel); - - const_val->special = ConstValSpecialStatic; - const_val->type = get_slice_type(g, ptr_type); - const_val->data.x_struct.fields = alloc_const_vals_ptrs(g, 2); - - init_const_ptr_array(g, const_val->data.x_struct.fields[slice_ptr_index], array_val, start, is_const, - PtrLenUnknown); - init_const_usize(g, const_val->data.x_struct.fields[slice_len_index], len); -} - -ZigValue *create_const_slice(CodeGen *g, ZigValue *array_val, size_t start, size_t len, bool is_const, ZigValue *sentinel) { - ZigValue *const_val = g->pass1_arena->create(); - init_const_slice(g, const_val, array_val, start, len, is_const, sentinel); - return const_val; -} - -void init_const_ptr_array(CodeGen *g, ZigValue *const_val, ZigValue *array_val, - size_t elem_index, bool is_const, PtrLen ptr_len) -{ - assert(array_val->type->id == ZigTypeIdArray); - ZigType *child_type = array_val->type->data.array.child_type; - - const_val->special = ConstValSpecialStatic; - const_val->type = get_pointer_to_type_extra(g, child_type, is_const, false, - ptr_len, 0, 0, 0, false); - const_val->data.x_ptr.special = ConstPtrSpecialBaseArray; - const_val->data.x_ptr.data.base_array.array_val = array_val; - const_val->data.x_ptr.data.base_array.elem_index = elem_index; -} - -ZigValue *create_const_ptr_array(CodeGen *g, ZigValue *array_val, size_t elem_index, bool is_const, - PtrLen ptr_len) -{ - ZigValue *const_val = g->pass1_arena->create(); - init_const_ptr_array(g, const_val, array_val, elem_index, is_const, ptr_len); - return const_val; -} - -void init_const_ptr_ref(CodeGen *g, ZigValue *const_val, ZigValue *pointee_val, bool is_const) { - const_val->special = ConstValSpecialStatic; - const_val->type = get_pointer_to_type(g, pointee_val->type, is_const); - const_val->data.x_ptr.special = ConstPtrSpecialRef; - const_val->data.x_ptr.data.ref.pointee = pointee_val; -} - -ZigValue *create_const_ptr_ref(CodeGen *g, ZigValue *pointee_val, bool is_const) { - ZigValue *const_val = g->pass1_arena->create(); - init_const_ptr_ref(g, const_val, pointee_val, is_const); - return const_val; -} - -void init_const_ptr_hard_coded_addr(CodeGen *g, ZigValue *const_val, ZigType *pointee_type, - size_t addr, bool is_const) -{ - const_val->special = ConstValSpecialStatic; - const_val->type = get_pointer_to_type(g, pointee_type, is_const); - const_val->data.x_ptr.special = ConstPtrSpecialHardCodedAddr; - const_val->data.x_ptr.data.hard_coded_addr.addr = addr; -} - -ZigValue *create_const_ptr_hard_coded_addr(CodeGen *g, ZigType *pointee_type, - size_t addr, bool is_const) -{ - ZigValue *const_val = g->pass1_arena->create(); - init_const_ptr_hard_coded_addr(g, const_val, pointee_type, addr, is_const); - return const_val; -} - -ZigValue **alloc_const_vals_ptrs(CodeGen *g, size_t count) { - return realloc_const_vals_ptrs(g, nullptr, 0, count); -} - -ZigValue **realloc_const_vals_ptrs(CodeGen *g, ZigValue **ptr, size_t old_count, size_t new_count) { - assert(new_count >= old_count); - - size_t new_item_count = new_count - old_count; - ZigValue **result = heap::c_allocator.reallocate(ptr, old_count, new_count); - ZigValue *vals = g->pass1_arena->allocate(new_item_count); - for (size_t i = old_count; i < new_count; i += 1) { - result[i] = &vals[i - old_count]; - } - return result; -} - -TypeStructField **alloc_type_struct_fields(size_t count) { - return realloc_type_struct_fields(nullptr, 0, count); -} - -TypeStructField **realloc_type_struct_fields(TypeStructField **ptr, size_t old_count, size_t new_count) { - assert(new_count >= old_count); - - size_t new_item_count = new_count - old_count; - TypeStructField **result = heap::c_allocator.reallocate(ptr, old_count, new_count); - TypeStructField *vals = heap::c_allocator.allocate(new_item_count); - for (size_t i = old_count; i < new_count; i += 1) { - result[i] = &vals[i - old_count]; - } - return result; -} - -static ZigType *get_async_fn_type(CodeGen *g, ZigType *orig_fn_type) { - if (orig_fn_type->data.fn.fn_type_id.cc == CallingConventionAsync) - return orig_fn_type; - - ZigType *fn_type = heap::c_allocator.allocate_nonzero(1); - *fn_type = *orig_fn_type; - fn_type->data.fn.fn_type_id.cc = CallingConventionAsync; - fn_type->llvm_type = nullptr; - fn_type->llvm_di_type = nullptr; - - return fn_type; -} - -// Traverse up to the very top ExprScope, which has children. -// We have just arrived at the top from a child. That child, -// and its next siblings, do not need to be marked. But the previous -// siblings do. -// x + (await y) -// vs -// (await y) + x -static void mark_suspension_point(Scope *scope) { - ScopeExpr *child_expr_scope = (scope->id == ScopeIdExpr) ? reinterpret_cast(scope) : nullptr; - bool looking_for_exprs = true; - for (;;) { - scope = scope->parent; - switch (scope->id) { - case ScopeIdDeferExpr: - case ScopeIdDecls: - case ScopeIdFnDef: - case ScopeIdCompTime: - case ScopeIdNoSuspend: - case ScopeIdCImport: - case ScopeIdSuspend: - case ScopeIdTypeOf: - return; - case ScopeIdVarDecl: - case ScopeIdDefer: - case ScopeIdBlock: - looking_for_exprs = false; - continue; - case ScopeIdRuntime: - continue; - case ScopeIdLoop: { - ScopeLoop *loop_scope = reinterpret_cast(scope); - if (loop_scope->spill_scope != nullptr) { - loop_scope->spill_scope->need_spill = MemoizedBoolTrue; - } - looking_for_exprs = false; - continue; - } - case ScopeIdExpr: { - ScopeExpr *parent_expr_scope = reinterpret_cast(scope); - if (!looking_for_exprs) { - if (parent_expr_scope->spill_harder) { - parent_expr_scope->need_spill = MemoizedBoolTrue; - } - // Now we're only looking for a block, to see if it's in a loop (see the case ScopeIdBlock) - continue; - } - if (child_expr_scope != nullptr) { - for (size_t i = 0; parent_expr_scope->children_ptr[i] != child_expr_scope; i += 1) { - assert(i < parent_expr_scope->children_len); - parent_expr_scope->children_ptr[i]->need_spill = MemoizedBoolTrue; - } - } - parent_expr_scope->need_spill = MemoizedBoolTrue; - child_expr_scope = parent_expr_scope; - continue; - } - } - } -} - -static bool scope_needs_spill(Scope *scope) { - ScopeExpr *scope_expr = find_expr_scope(scope); - if (scope_expr == nullptr) return false; - - switch (scope_expr->need_spill) { - case MemoizedBoolUnknown: - if (scope_needs_spill(scope_expr->base.parent)) { - scope_expr->need_spill = MemoizedBoolTrue; - return true; - } else { - scope_expr->need_spill = MemoizedBoolFalse; - return false; - } - case MemoizedBoolFalse: - return false; - case MemoizedBoolTrue: - return true; - } - zig_unreachable(); -} - -static ZigType *resolve_type_isf(ZigType *ty) { - if (ty->id != ZigTypeIdPointer) return ty; - InferredStructField *isf = ty->data.pointer.inferred_struct_field; - if (isf == nullptr) return ty; - TypeStructField *field = find_struct_type_field(isf->inferred_struct_type, isf->field_name); - assert(field != nullptr); - return field->type_entry; -} - -static Error resolve_async_frame(CodeGen *g, ZigType *frame_type) { - Error err; - - if (frame_type->data.frame.locals_struct != nullptr) - return ErrorNone; - - ZigFn *fn = frame_type->data.frame.fn; - assert(!fn->type_entry->data.fn.is_generic); - - if (frame_type->data.frame.resolve_loop_type != nullptr) { - if (!frame_type->data.frame.reported_loop_err) { - add_node_error(g, fn->proto_node, - buf_sprintf("'%s' depends on itself", buf_ptr(&frame_type->name))); - } - return ErrorSemanticAnalyzeFail; - } - - switch (fn->anal_state) { - case FnAnalStateInvalid: - return ErrorSemanticAnalyzeFail; - case FnAnalStateComplete: - break; - case FnAnalStateReady: - analyze_fn_body(g, fn); - if (fn->anal_state == FnAnalStateInvalid) - return ErrorSemanticAnalyzeFail; - break; - case FnAnalStateProbing: { - add_node_error(g, fn->proto_node, - buf_sprintf("cannot resolve '%s': function not fully analyzed yet", - buf_ptr(&frame_type->name))); - return ErrorSemanticAnalyzeFail; - } - } - analyze_fn_async(g, fn, false); - if (fn->anal_state == FnAnalStateInvalid) - return ErrorSemanticAnalyzeFail; - - if (!fn_is_async(fn)) { - ZigType *fn_type = fn->type_entry; - FnTypeId *fn_type_id = &fn_type->data.fn.fn_type_id; - ZigType *ptr_return_type = get_pointer_to_type(g, fn_type_id->return_type, false); - - // label (grep this): [fn_frame_struct_layout] - ZigList fields = {}; - - fields.append({"@fn_ptr", g->builtin_types.entry_usize, 0}); - fields.append({"@resume_index", g->builtin_types.entry_usize, 0}); - fields.append({"@awaiter", g->builtin_types.entry_usize, 0}); - - fields.append({"@result_ptr_callee", ptr_return_type, 0}); - fields.append({"@result_ptr_awaiter", ptr_return_type, 0}); - fields.append({"@result", fn_type_id->return_type, 0}); - - if (codegen_fn_has_err_ret_tracing_arg(g, fn_type_id->return_type)) { - ZigType *ptr_to_stack_trace_type = get_pointer_to_type(g, get_stack_trace_type(g), false); - fields.append({"@ptr_stack_trace_callee", ptr_to_stack_trace_type, 0}); - fields.append({"@ptr_stack_trace_awaiter", ptr_to_stack_trace_type, 0}); - - fields.append({"@stack_trace", get_stack_trace_type(g), 0}); - fields.append({"@instruction_addresses", - get_array_type(g, g->builtin_types.entry_usize, stack_trace_ptr_count, nullptr), 0}); - } - - frame_type->data.frame.locals_struct = get_struct_type(g, buf_ptr(&frame_type->name), - fields.items, fields.length, target_fn_align(g->zig_target)); - frame_type->abi_size = frame_type->data.frame.locals_struct->abi_size; - frame_type->abi_align = frame_type->data.frame.locals_struct->abi_align; - frame_type->size_in_bits = frame_type->data.frame.locals_struct->size_in_bits; - - return ErrorNone; - } - - ZigType *fn_type = get_async_fn_type(g, fn->type_entry); - - if (fn->analyzed_executable.need_err_code_spill) { - Stage1AirInstAlloca *alloca_gen = heap::c_allocator.create(); - alloca_gen->base.id = Stage1AirInstIdAlloca; - alloca_gen->base.source_node = fn->proto_node; - alloca_gen->base.scope = fn->child_scope; - alloca_gen->base.value = g->pass1_arena->create(); - alloca_gen->base.value->type = get_pointer_to_type(g, g->builtin_types.entry_global_error_set, false); - alloca_gen->base.ref_count = 1; - alloca_gen->name_hint = ""; - fn->alloca_gen_list.append(alloca_gen); - fn->err_code_spill = &alloca_gen->base; - } - - ZigType *largest_call_frame_type = nullptr; - // Later we'll change this to be largest_call_frame_type instead of void. - Stage1AirInst *all_calls_alloca = ir_create_alloca(g, &fn->fndef_scope->base, fn->body_node, - fn, g->builtin_types.entry_void, "@async_call_frame"); - - for (size_t i = 0; i < fn->call_list.length; i += 1) { - Stage1AirInstCall *call = fn->call_list.at(i); - if (call->new_stack != nullptr) { - // don't need to allocate a frame for this - continue; - } - ZigFn *callee = call->fn_entry; - if (callee == nullptr) { - if (call->fn_ref->value->type->data.fn.fn_type_id.cc != CallingConventionAsync) { - continue; - } - add_node_error(g, call->base.source_node, - buf_sprintf("function is not comptime-known; @asyncCall required")); - return ErrorSemanticAnalyzeFail; - } - if (callee->body_node == nullptr) { - continue; - } - if (callee->anal_state == FnAnalStateProbing) { - ErrorMsg *msg = add_node_error(g, fn->proto_node, - buf_sprintf("unable to determine async function frame of '%s'", buf_ptr(&fn->symbol_name))); - g->trace_err = add_error_note(g, msg, call->base.source_node, - buf_sprintf("analysis of function '%s' depends on the frame", buf_ptr(&callee->symbol_name))); - return ErrorSemanticAnalyzeFail; - } - - ZigType *callee_frame_type = get_fn_frame_type(g, callee); - frame_type->data.frame.resolve_loop_type = callee_frame_type; - frame_type->data.frame.resolve_loop_src_node = call->base.source_node; - - analyze_fn_body(g, callee); - if (callee->anal_state == FnAnalStateInvalid) { - frame_type->data.frame.locals_struct = g->builtin_types.entry_invalid; - return ErrorSemanticAnalyzeFail; - } - analyze_fn_async(g, callee, true); - if (callee->inferred_async_node == inferred_async_checking) { - assert(g->errors.length != 0); - frame_type->data.frame.locals_struct = g->builtin_types.entry_invalid; - return ErrorSemanticAnalyzeFail; - } - if (!fn_is_async(callee)) - continue; - - mark_suspension_point(call->base.scope); - - if ((err = type_resolve(g, callee_frame_type, ResolveStatusSizeKnown))) { - return err; - } - if (largest_call_frame_type == nullptr || - callee_frame_type->abi_size > largest_call_frame_type->abi_size) - { - largest_call_frame_type = callee_frame_type; - } - - call->frame_result_loc = all_calls_alloca; - } - if (largest_call_frame_type != nullptr) { - all_calls_alloca->value->type = get_pointer_to_type(g, largest_call_frame_type, false); - } - - // Since this frame is async, an await might represent a suspend point, and - // therefore need to spill. It also needs to mark expr scopes as having to spill. - // For example: foo() + await z - // The function call result of foo() must be spilled. - for (size_t i = 0; i < fn->await_list.length; i += 1) { - Stage1AirInstAwait *await = fn->await_list.at(i); - if (await->is_nosuspend) { - continue; - } - if (await->base.value->special != ConstValSpecialRuntime) { - // Known at comptime. No spill, no suspend. - continue; - } - if (await->target_fn != nullptr) { - // we might not need to suspend - analyze_fn_async(g, await->target_fn, false); - if (await->target_fn->anal_state == FnAnalStateInvalid) { - frame_type->data.frame.locals_struct = g->builtin_types.entry_invalid; - return ErrorSemanticAnalyzeFail; - } - if (!fn_is_async(await->target_fn)) { - // This await does not represent a suspend point. No spill needed, - // and no need to mark ExprScope. - continue; - } - } - // This await is a suspend point, but it might not need a spill. - // We do need to mark the ExprScope as having a suspend point in it. - mark_suspension_point(await->base.scope); - - if (await->result_loc != nullptr) { - // If there's a result location, that is the spill - continue; - } - if (await->base.ref_count == 0) - continue; - if (!type_has_bits(g, await->base.value->type)) - continue; - await->result_loc = ir_create_alloca(g, await->base.scope, await->base.source_node, fn, - await->base.value->type, ""); - } - for (size_t block_i = 0; block_i < fn->analyzed_executable.basic_block_list.length; block_i += 1) { - Stage1AirBasicBlock *block = fn->analyzed_executable.basic_block_list.at(block_i); - for (size_t instr_i = 0; instr_i < block->instruction_list.length; instr_i += 1) { - Stage1AirInst *instruction = block->instruction_list.at(instr_i); - if (instruction->id == Stage1AirInstIdSuspendFinish) { - mark_suspension_point(instruction->scope); - } - } - } - // Now that we've marked all the expr scopes that have to spill, we go over the instructions - // and spill the relevant ones. - for (size_t block_i = 0; block_i < fn->analyzed_executable.basic_block_list.length; block_i += 1) { - Stage1AirBasicBlock *block = fn->analyzed_executable.basic_block_list.at(block_i); - for (size_t instr_i = 0; instr_i < block->instruction_list.length; instr_i += 1) { - Stage1AirInst *instruction = block->instruction_list.at(instr_i); - if (instruction->id == Stage1AirInstIdAwait || - instruction->id == Stage1AirInstIdVarPtr || - instruction->id == Stage1AirInstIdAlloca || - instruction->id == Stage1AirInstIdSpillBegin || - instruction->id == Stage1AirInstIdSpillEnd) - { - // This instruction does its own spilling specially, or otherwise doesn't need it. - continue; - } - if (instruction->id == Stage1AirInstIdCast && - reinterpret_cast(instruction)->cast_op == CastOpNoop) - { - // The IR instruction exists only to change the type according to Zig. No spill needed. - continue; - } - if (instruction->value->special != ConstValSpecialRuntime) - continue; - if (instruction->ref_count == 0) - continue; - if ((err = type_resolve(g, instruction->value->type, ResolveStatusZeroBitsKnown))) - return ErrorSemanticAnalyzeFail; - if (!type_has_bits(g, instruction->value->type)) - continue; - if (scope_needs_spill(instruction->scope)) { - instruction->spill = ir_create_alloca(g, instruction->scope, instruction->source_node, - fn, instruction->value->type, ""); - } - } - } - - FnTypeId *fn_type_id = &fn_type->data.fn.fn_type_id; - ZigType *ptr_return_type = get_pointer_to_type(g, fn_type_id->return_type, false); - - // label (grep this): [fn_frame_struct_layout] - ZigList fields = {}; - - fields.append({"@fn_ptr", fn_type, 0}); - fields.append({"@resume_index", g->builtin_types.entry_usize, 0}); - fields.append({"@awaiter", g->builtin_types.entry_usize, 0}); - - fields.append({"@result_ptr_callee", ptr_return_type, 0}); - fields.append({"@result_ptr_awaiter", ptr_return_type, 0}); - fields.append({"@result", fn_type_id->return_type, 0}); - - if (codegen_fn_has_err_ret_tracing_arg(g, fn_type_id->return_type)) { - ZigType *ptr_stack_trace_type = get_pointer_to_type(g, get_stack_trace_type(g), false); - fields.append({"@ptr_stack_trace_callee", ptr_stack_trace_type, 0}); - fields.append({"@ptr_stack_trace_awaiter", ptr_stack_trace_type, 0}); - } - - for (size_t arg_i = 0; arg_i < fn_type_id->param_count; arg_i += 1) { - FnTypeParamInfo *param_info = &fn_type_id->param_info[arg_i]; - AstNode *param_decl_node = get_param_decl_node(fn, arg_i); - Buf *param_name; - bool is_var_args = param_decl_node && param_decl_node->data.param_decl.is_var_args; - if (param_decl_node && !is_var_args) { - param_name = param_decl_node->data.param_decl.name; - } else { - param_name = buf_sprintf("@arg%" ZIG_PRI_usize, arg_i); - } - ZigType *param_type = resolve_type_isf(param_info->type); - if ((err = type_resolve(g, param_type, ResolveStatusSizeKnown))) { - return err; - } - - fields.append({buf_ptr(param_name), param_type, 0}); - } - - if (codegen_fn_has_err_ret_tracing_stack(g, fn, true)) { - fields.append({"@stack_trace", get_stack_trace_type(g), 0}); - fields.append({"@instruction_addresses", - get_array_type(g, g->builtin_types.entry_usize, stack_trace_ptr_count, nullptr), 0}); - } - - for (size_t alloca_i = 0; alloca_i < fn->alloca_gen_list.length; alloca_i += 1) { - Stage1AirInstAlloca *instruction = fn->alloca_gen_list.at(alloca_i); - instruction->field_index = SIZE_MAX; - ZigType *ptr_type = instruction->base.value->type; - assert(ptr_type->id == ZigTypeIdPointer); - ZigType *child_type = resolve_type_isf(ptr_type->data.pointer.child_type); - if (!type_has_bits(g, child_type)) - continue; - if (instruction->base.ref_count == 0) - continue; - if (instruction->base.value->special != ConstValSpecialRuntime) { - if (const_ptr_pointee(nullptr, g, instruction->base.value, nullptr)->special != - ConstValSpecialRuntime) - { - continue; - } - } - - frame_type->data.frame.resolve_loop_type = child_type; - frame_type->data.frame.resolve_loop_src_node = instruction->base.source_node; - if ((err = type_resolve(g, child_type, ResolveStatusSizeKnown))) { - return err; - } - - const char *name; - if (*instruction->name_hint == 0) { - name = buf_ptr(buf_sprintf("@local%" ZIG_PRI_usize, alloca_i)); - } else { - name = buf_ptr(buf_sprintf("%s.%" ZIG_PRI_usize, instruction->name_hint, alloca_i)); - } - instruction->field_index = fields.length; - - fields.append({name, child_type, instruction->align}); - } - - - frame_type->data.frame.locals_struct = get_struct_type(g, buf_ptr(&frame_type->name), - fields.items, fields.length, target_fn_align(g->zig_target)); - frame_type->abi_size = frame_type->data.frame.locals_struct->abi_size; - frame_type->abi_align = frame_type->data.frame.locals_struct->abi_align; - frame_type->size_in_bits = frame_type->data.frame.locals_struct->size_in_bits; - - if (g->largest_frame_fn == nullptr || frame_type->abi_size > g->largest_frame_fn->frame_type->abi_size) { - g->largest_frame_fn = fn; - } - - return ErrorNone; -} - -static Error resolve_pointer_zero_bits(CodeGen *g, ZigType *ty) { - Error err; - - if (ty->abi_size != SIZE_MAX) - return ErrorNone; - - if (ty->data.pointer.resolve_loop_flag_zero_bits) { - ty->abi_size = g->builtin_types.entry_usize->abi_size; - ty->size_in_bits = g->builtin_types.entry_usize->size_in_bits; - ty->abi_align = g->builtin_types.entry_usize->abi_align; - return ErrorNone; - } - ty->data.pointer.resolve_loop_flag_zero_bits = true; - - ZigType *elem_type; - InferredStructField *isf = ty->data.pointer.inferred_struct_field; - if (isf != nullptr) { - TypeStructField *field = find_struct_type_field(isf->inferred_struct_type, isf->field_name); - assert(field != nullptr); - if (field->is_comptime) { - ty->data.pointer.resolve_loop_flag_zero_bits = false; - - ty->abi_size = 0; - ty->size_in_bits = 0; - ty->abi_align = 0; - - return ErrorNone; - } - elem_type = field->type_entry; - } else { - elem_type = ty->data.pointer.child_type; - } - - bool has_bits; - if ((err = type_has_bits2(g, elem_type, &has_bits))) - return err; - - ty->data.pointer.resolve_loop_flag_zero_bits = false; - - if (has_bits) { - ty->abi_size = g->builtin_types.entry_usize->abi_size; - ty->size_in_bits = g->builtin_types.entry_usize->size_in_bits; - ty->abi_align = g->builtin_types.entry_usize->abi_align; - } else { - ty->abi_size = 0; - ty->size_in_bits = 0; - ty->abi_align = 0; - } - return ErrorNone; -} - -Error type_resolve(CodeGen *g, ZigType *ty, ResolveStatus status) { - if (type_is_invalid(ty)) - return ErrorSemanticAnalyzeFail; - switch (status) { - case ResolveStatusUnstarted: - return ErrorNone; - case ResolveStatusBeingInferred: - zig_unreachable(); - case ResolveStatusInvalid: - zig_unreachable(); - case ResolveStatusZeroBitsKnown: - switch (ty->id) { - case ZigTypeIdStruct: - return resolve_struct_zero_bits(g, ty); - case ZigTypeIdEnum: - return resolve_enum_zero_bits(g, ty); - case ZigTypeIdUnion: - return resolve_union_zero_bits(g, ty); - case ZigTypeIdPointer: - return resolve_pointer_zero_bits(g, ty); - default: - return ErrorNone; - } - case ResolveStatusAlignmentKnown: - switch (ty->id) { - case ZigTypeIdStruct: - return resolve_struct_alignment(g, ty); - case ZigTypeIdEnum: - return resolve_enum_zero_bits(g, ty); - case ZigTypeIdUnion: - return resolve_union_alignment(g, ty); - case ZigTypeIdFnFrame: - return resolve_async_frame(g, ty); - case ZigTypeIdPointer: - return resolve_pointer_zero_bits(g, ty); - default: - return ErrorNone; - } - case ResolveStatusSizeKnown: - switch (ty->id) { - case ZigTypeIdStruct: - return resolve_struct_type(g, ty); - case ZigTypeIdEnum: - return resolve_enum_zero_bits(g, ty); - case ZigTypeIdUnion: - return resolve_union_type(g, ty); - case ZigTypeIdFnFrame: - return resolve_async_frame(g, ty); - case ZigTypeIdPointer: - return resolve_pointer_zero_bits(g, ty); - default: - return ErrorNone; - } - case ResolveStatusLLVMFwdDecl: - case ResolveStatusLLVMFull: - resolve_llvm_types(g, ty, status); - return ErrorNone; - } - zig_unreachable(); -} - -bool ir_get_var_is_comptime(ZigVar *var) { - if (var->is_comptime_memoized) - return var->is_comptime_memoized_value; - - var->is_comptime_memoized = true; - - // The is_comptime field can be left null, which means not comptime. - if (var->is_comptime == nullptr) { - var->is_comptime_memoized_value = false; - return var->is_comptime_memoized_value; - } - // When the is_comptime field references an instruction that has to get analyzed, this - // is the value. - if (var->is_comptime->child != nullptr) { - assert(var->is_comptime->child->value->type->id == ZigTypeIdBool); - var->is_comptime_memoized_value = var->is_comptime->child->value->data.x_bool; - var->is_comptime = nullptr; - return var->is_comptime_memoized_value; - } - // As an optimization, is_comptime values which are constant are allowed - // to be omitted from analysis. In this case, there is no child instruction - // and we simply look at the unanalyzed const parent instruction. - assert(var->is_comptime->id == Stage1ZirInstIdConst); - Stage1ZirInstConst *const_inst = reinterpret_cast(var->is_comptime); - assert(const_inst->value->type->id == ZigTypeIdBool); - var->is_comptime_memoized_value = const_inst->value->data.x_bool; - var->is_comptime = nullptr; - return var->is_comptime_memoized_value; -} - -bool const_values_equal_ptr(ZigValue *a, ZigValue *b) { - if (a->data.x_ptr.special != b->data.x_ptr.special) - return false; - switch (a->data.x_ptr.special) { - case ConstPtrSpecialInvalid: - zig_unreachable(); - case ConstPtrSpecialRef: - if (a->data.x_ptr.data.ref.pointee != b->data.x_ptr.data.ref.pointee) - return false; - return true; - case ConstPtrSpecialBaseArray: - case ConstPtrSpecialSubArray: - if (a->data.x_ptr.data.base_array.array_val != b->data.x_ptr.data.base_array.array_val) { - return false; - } - if (a->data.x_ptr.data.base_array.elem_index != b->data.x_ptr.data.base_array.elem_index) - return false; - return true; - case ConstPtrSpecialBaseStruct: - if (a->data.x_ptr.data.base_struct.struct_val != b->data.x_ptr.data.base_struct.struct_val) { - return false; - } - if (a->data.x_ptr.data.base_struct.field_index != b->data.x_ptr.data.base_struct.field_index) - return false; - return true; - case ConstPtrSpecialBaseErrorUnionCode: - if (a->data.x_ptr.data.base_err_union_code.err_union_val != - b->data.x_ptr.data.base_err_union_code.err_union_val) - { - return false; - } - return true; - case ConstPtrSpecialBaseErrorUnionPayload: - if (a->data.x_ptr.data.base_err_union_payload.err_union_val != - b->data.x_ptr.data.base_err_union_payload.err_union_val) - { - return false; - } - return true; - case ConstPtrSpecialBaseOptionalPayload: - if (a->data.x_ptr.data.base_optional_payload.optional_val != - b->data.x_ptr.data.base_optional_payload.optional_val) - { - return false; - } - return true; - case ConstPtrSpecialHardCodedAddr: - if (a->data.x_ptr.data.hard_coded_addr.addr != b->data.x_ptr.data.hard_coded_addr.addr) - return false; - return true; - case ConstPtrSpecialDiscard: - return true; - case ConstPtrSpecialFunction: - return a->data.x_ptr.data.fn.fn_entry == b->data.x_ptr.data.fn.fn_entry; - case ConstPtrSpecialNull: - return true; - } - zig_unreachable(); -} - -static bool const_values_equal_array(CodeGen *g, ZigValue *a, ZigValue *b, size_t len) { - if (a->data.x_array.special == ConstArraySpecialUndef && - b->data.x_array.special == ConstArraySpecialUndef) - { - return true; - } - if (a->data.x_array.special == ConstArraySpecialUndef || - b->data.x_array.special == ConstArraySpecialUndef) - { - return false; - } - if (a->data.x_array.special == ConstArraySpecialBuf && - b->data.x_array.special == ConstArraySpecialBuf) - { - return buf_eql_buf(a->data.x_array.data.s_buf, b->data.x_array.data.s_buf); - } - expand_undef_array(g, a); - expand_undef_array(g, b); - - ZigValue *a_elems = a->data.x_array.data.s_none.elements; - ZigValue *b_elems = b->data.x_array.data.s_none.elements; - - for (size_t i = 0; i < len; i += 1) { - if (!const_values_equal(g, &a_elems[i], &b_elems[i])) - return false; - } - - return true; -} - -bool const_values_equal(CodeGen *g, ZigValue *a, ZigValue *b) { - if (a->type->id != b->type->id) return false; - if (a->type == b->type) { - switch (type_has_one_possible_value(g, a->type)) { - case OnePossibleValueInvalid: - zig_unreachable(); - case OnePossibleValueNo: - break; - case OnePossibleValueYes: - return true; - } - } - if (a->special == ConstValSpecialUndef || b->special == ConstValSpecialUndef) { - return a->special == b->special; - } - assert(a->special == ConstValSpecialStatic); - assert(b->special == ConstValSpecialStatic); - switch (a->type->id) { - case ZigTypeIdOpaque: - zig_unreachable(); - case ZigTypeIdEnum: - return bigint_cmp(&a->data.x_enum_tag, &b->data.x_enum_tag) == CmpEQ; - case ZigTypeIdUnion: { - ConstUnionValue *union1 = &a->data.x_union; - ConstUnionValue *union2 = &b->data.x_union; - - if (bigint_cmp(&union1->tag, &union2->tag) == CmpEQ) { - TypeUnionField *field = find_union_field_by_tag(a->type, &union1->tag); - assert(field != nullptr); - assert(find_union_field_by_tag(a->type, &union2->tag) != nullptr); - return const_values_equal(g, union1->payload, union2->payload); - } - return false; - } - case ZigTypeIdMetaType: - return a->data.x_type == b->data.x_type; - case ZigTypeIdVoid: - case ZigTypeIdUndefined: - case ZigTypeIdNull: - return true; - case ZigTypeIdErrorSet: - return a->data.x_err_set->value == b->data.x_err_set->value; - case ZigTypeIdBool: - return a->data.x_bool == b->data.x_bool; - case ZigTypeIdFloat: - assert(a->type->data.floating.bit_count == b->type->data.floating.bit_count); - switch (a->type->data.floating.bit_count) { - case 16: - return f16_eq(a->data.x_f16, b->data.x_f16); - case 32: - return a->data.x_f32 == b->data.x_f32; - case 64: - return a->data.x_f64 == b->data.x_f64; - case 80: - return extF80M_eq(&a->data.x_f80, &b->data.x_f80); - case 128: - return f128M_eq(&a->data.x_f128, &b->data.x_f128); - default: - zig_unreachable(); - } - case ZigTypeIdComptimeFloat: - return bigfloat_cmp(&a->data.x_bigfloat, &b->data.x_bigfloat) == CmpEQ; - case ZigTypeIdInt: - case ZigTypeIdComptimeInt: - return bigint_cmp(&a->data.x_bigint, &b->data.x_bigint) == CmpEQ; - case ZigTypeIdEnumLiteral: - return buf_eql_buf(a->data.x_enum_literal, b->data.x_enum_literal); - case ZigTypeIdPointer: - case ZigTypeIdFn: - return const_values_equal_ptr(a, b); - case ZigTypeIdVector: - assert(a->type->data.vector.len == b->type->data.vector.len); - return const_values_equal_array(g, a, b, a->type->data.vector.len); - case ZigTypeIdArray: - assert(a->type->data.array.len == b->type->data.array.len); - return const_values_equal_array(g, a, b, a->type->data.array.len); - case ZigTypeIdStruct: - for (size_t i = 0; i < a->type->data.structure.src_field_count; i += 1) { - if (a->type->data.structure.fields[i]->is_comptime) { - // The values of comptime struct fields are part of the - // type, not the value, so they do not participate in equality - // or hash of comptime values. - continue; - } - ZigValue *field_a = a->data.x_struct.fields[i]; - ZigValue *field_b = b->data.x_struct.fields[i]; - if (!const_values_equal(g, field_a, field_b)) - return false; - } - return true; - case ZigTypeIdFnFrame: - zig_panic("TODO: const_values_equal ZigTypeIdFnFrame"); - case ZigTypeIdAnyFrame: - zig_panic("TODO: const_values_equal ZigTypeIdAnyFrame"); - case ZigTypeIdOptional: - if (get_src_ptr_type(a->type) != nullptr) - return const_values_equal_ptr(a, b); - if (a->data.x_optional == nullptr || b->data.x_optional == nullptr) { - return (a->data.x_optional == nullptr && b->data.x_optional == nullptr); - } else { - return const_values_equal(g, a->data.x_optional, b->data.x_optional); - } - case ZigTypeIdErrorUnion: { - bool a_is_err = a->data.x_err_union.error_set->data.x_err_set != nullptr; - bool b_is_err = b->data.x_err_union.error_set->data.x_err_set != nullptr; - if (a_is_err != b_is_err) return false; - if (a_is_err) { - return const_values_equal(g, a->data.x_err_union.error_set, b->data.x_err_union.error_set); - } else { - return const_values_equal(g, a->data.x_err_union.payload, b->data.x_err_union.payload); - } - } - case ZigTypeIdBoundFn: - case ZigTypeIdInvalid: - case ZigTypeIdUnreachable: - zig_unreachable(); - } - zig_unreachable(); -} - -void eval_min_max_value_int(CodeGen *g, ZigType *int_type, BigInt *bigint, bool is_max) { - assert(int_type->id == ZigTypeIdInt); - if (int_type->data.integral.bit_count == 0) { - bigint_init_unsigned(bigint, 0); - return; - } - if (is_max) { - // is_signed=true (1 << (bit_count - 1)) - 1 - // is_signed=false (1 << (bit_count - 0)) - 1 - BigInt one = {0}; - bigint_init_unsigned(&one, 1); - - size_t shift_amt = int_type->data.integral.bit_count - (int_type->data.integral.is_signed ? 1 : 0); - BigInt bit_count_bi = {0}; - bigint_init_unsigned(&bit_count_bi, shift_amt); - - BigInt shifted_bi = {0}; - bigint_shl(&shifted_bi, &one, &bit_count_bi); - - bigint_sub(bigint, &shifted_bi, &one); - } else if (int_type->data.integral.is_signed) { - // - (1 << (bit_count - 1)) - BigInt one = {0}; - bigint_init_unsigned(&one, 1); - - BigInt bit_count_bi = {0}; - bigint_init_unsigned(&bit_count_bi, int_type->data.integral.bit_count - 1); - - BigInt shifted_bi = {0}; - bigint_shl(&shifted_bi, &one, &bit_count_bi); - - bigint_negate(bigint, &shifted_bi); - } else { - bigint_init_unsigned(bigint, 0); - } -} - -void eval_min_max_value(CodeGen *g, ZigType *type_entry, ZigValue *const_val, bool is_max) { - if (type_entry->id == ZigTypeIdInt) { - const_val->special = ConstValSpecialStatic; - eval_min_max_value_int(g, type_entry, &const_val->data.x_bigint, is_max); - } else if (type_entry->id == ZigTypeIdBool) { - const_val->special = ConstValSpecialStatic; - const_val->data.x_bool = is_max; - } else if (type_entry->id == ZigTypeIdVoid) { - // nothing to do - } else { - zig_unreachable(); - } -} - -static void render_const_val_ptr(CodeGen *g, Buf *buf, ZigValue *const_val, ZigType *type_entry) { - if (type_entry->id == ZigTypeIdPointer && type_entry->data.pointer.child_type->id == ZigTypeIdOpaque) { - buf_append_buf(buf, &type_entry->name); - return; - } - - switch (const_val->data.x_ptr.special) { - case ConstPtrSpecialInvalid: - zig_unreachable(); - case ConstPtrSpecialRef: - case ConstPtrSpecialBaseStruct: - case ConstPtrSpecialBaseErrorUnionCode: - case ConstPtrSpecialBaseErrorUnionPayload: - case ConstPtrSpecialBaseOptionalPayload: - buf_appendf(buf, "*"); - // TODO we need a source node for const_ptr_pointee because it can generate compile errors - render_const_value(g, buf, const_ptr_pointee(nullptr, g, const_val, nullptr)); - return; - case ConstPtrSpecialBaseArray: - case ConstPtrSpecialSubArray: - buf_appendf(buf, "*"); - // TODO we need a source node for const_ptr_pointee because it can generate compile errors - render_const_value(g, buf, const_ptr_pointee(nullptr, g, const_val, nullptr)); - return; - case ConstPtrSpecialHardCodedAddr: - buf_appendf(buf, "(%s)(%" ZIG_PRI_x64 ")", buf_ptr(&type_entry->name), - const_val->data.x_ptr.data.hard_coded_addr.addr); - return; - case ConstPtrSpecialDiscard: - buf_append_str(buf, "*_"); - return; - case ConstPtrSpecialFunction: - { - ZigFn *fn_entry = const_val->data.x_ptr.data.fn.fn_entry; - buf_appendf(buf, "@ptrCast(%s, %s)", buf_ptr(&const_val->type->name), buf_ptr(&fn_entry->symbol_name)); - return; - } - case ConstPtrSpecialNull: - buf_append_str(buf, "null"); - return; - } - zig_unreachable(); -} - -static void render_const_val_err_set(CodeGen *g, Buf *buf, ZigValue *const_val, ZigType *type_entry) { - if (const_val->data.x_err_set == nullptr) { - buf_append_str(buf, "null"); - } else { - buf_appendf(buf, "%s.%s", buf_ptr(&type_entry->name), buf_ptr(&const_val->data.x_err_set->name)); - } -} - -static void render_const_val_array(CodeGen *g, Buf *buf, Buf *type_name, ZigValue *const_val, uint64_t start, uint64_t len) { - ConstArrayValue *array = &const_val->data.x_array; - switch (array->special) { - case ConstArraySpecialUndef: - buf_append_str(buf, "undefined"); - return; - case ConstArraySpecialBuf: { - Buf *array_buf = array->data.s_buf; - const char *base = &buf_ptr(array_buf)[start]; - assert(start + len <= buf_len(array_buf)); - - buf_append_char(buf, '"'); - for (size_t i = 0; i < len; i += 1) { - uint8_t c = base[i]; - if (c == '"') { - buf_append_str(buf, "\\\""); - } else { - buf_append_char(buf, c); - } - } - buf_append_char(buf, '"'); - return; - } - case ConstArraySpecialNone: { - assert(start + len <= const_val->type->data.array.len); - ZigValue *base = &array->data.s_none.elements[start]; - assert(len == 0 || base != nullptr); - - buf_appendf(buf, "%s{", buf_ptr(type_name)); - for (uint64_t i = 0; i < len; i += 1) { - if (i != 0) buf_appendf(buf, ","); - render_const_value(g, buf, &base[i]); - } - buf_appendf(buf, "}"); - return; - } - } - zig_unreachable(); -} - -void render_const_value(CodeGen *g, Buf *buf, ZigValue *const_val) { - if (const_val == nullptr) { - buf_appendf(buf, "(invalid nullptr value)"); - return; - } - switch (const_val->special) { - case ConstValSpecialRuntime: - buf_appendf(buf, "(runtime value)"); - return; - case ConstValSpecialLazy: - buf_appendf(buf, "(lazy value)"); - return; - case ConstValSpecialUndef: - buf_appendf(buf, "undefined"); - return; - case ConstValSpecialStatic: - break; - } - assert(const_val->type); - - ZigType *type_entry = const_val->type; - switch (type_entry->id) { - case ZigTypeIdOpaque: - zig_unreachable(); - case ZigTypeIdInvalid: - buf_appendf(buf, "(invalid)"); - return; - case ZigTypeIdVoid: - buf_appendf(buf, "{}"); - return; - case ZigTypeIdComptimeFloat: - bigfloat_append_buf(buf, &const_val->data.x_bigfloat); - return; - case ZigTypeIdFloat: - switch (type_entry->data.floating.bit_count) { - case 16: - buf_appendf(buf, "%f", zig_f16_to_double(const_val->data.x_f16)); - return; - case 32: - buf_appendf(buf, "%f", const_val->data.x_f32); - return; - case 64: - buf_appendf(buf, "%f", const_val->data.x_f64); - return; - case 80: { - float64_t f64_value = extF80M_to_f64(&const_val->data.x_f80); - double double_value; - memcpy(&double_value, &f64_value, sizeof(double)); - buf_appendf(buf, "%f", double_value); - return; - } - case 128: - { - const size_t extra_len = 100; - size_t old_len = buf_len(buf); - buf_resize(buf, old_len + extra_len); - float64_t f64_value = f128M_to_f64(&const_val->data.x_f128); - double double_value; - memcpy(&double_value, &f64_value, sizeof(double)); - // TODO actual f128 printing to decimal - int len = snprintf(buf_ptr(buf) + old_len, extra_len, "%f", double_value); - assert(len > 0); - buf_resize(buf, old_len + len); - return; - } - default: - zig_unreachable(); - } - case ZigTypeIdComptimeInt: - case ZigTypeIdInt: - bigint_append_buf(buf, &const_val->data.x_bigint, 10); - return; - case ZigTypeIdEnumLiteral: - buf_append_buf(buf, const_val->data.x_enum_literal); - return; - case ZigTypeIdMetaType: - buf_appendf(buf, "%s", buf_ptr(&const_val->data.x_type->name)); - return; - case ZigTypeIdUnreachable: - buf_appendf(buf, "unreachable"); - return; - case ZigTypeIdBool: - { - const char *value = const_val->data.x_bool ? "true" : "false"; - buf_appendf(buf, "%s", value); - return; - } - case ZigTypeIdFn: - { - assert(const_val->data.x_ptr.mut == ConstPtrMutComptimeConst); - assert(const_val->data.x_ptr.special == ConstPtrSpecialFunction); - ZigFn *fn_entry = const_val->data.x_ptr.data.fn.fn_entry; - buf_appendf(buf, "%s", buf_ptr(&fn_entry->symbol_name)); - return; - } - case ZigTypeIdPointer: - return render_const_val_ptr(g, buf, const_val, type_entry); - case ZigTypeIdArray: { - uint64_t len = type_entry->data.array.len; - render_const_val_array(g, buf, &type_entry->name, const_val, 0, len); - return; - } - case ZigTypeIdVector: { - uint32_t len = type_entry->data.vector.len; - render_const_val_array(g, buf, &type_entry->name, const_val, 0, len); - return; - } - case ZigTypeIdNull: - { - buf_appendf(buf, "null"); - return; - } - case ZigTypeIdUndefined: - { - buf_appendf(buf, "undefined"); - return; - } - case ZigTypeIdOptional: - { - ZigType *src_ptr_type = get_src_ptr_type(const_val->type); - if (src_ptr_type != nullptr) { - if (src_ptr_type->id == ZigTypeIdPointer && !optional_value_is_null(const_val)) { - ZigValue tmp = {}; - copy_const_val(g, &tmp, const_val); - tmp.type = type_entry->data.maybe.child_type; - return render_const_val_ptr(g, buf, &tmp, tmp.type); - } - return render_const_val_ptr(g, buf, const_val, type_entry->data.maybe.child_type); - } - if (type_entry->data.maybe.child_type->id == ZigTypeIdErrorSet) - return render_const_val_err_set(g, buf, const_val, type_entry->data.maybe.child_type); - if (const_val->data.x_optional) { - render_const_value(g, buf, const_val->data.x_optional); - } else { - buf_appendf(buf, "null"); - } - return; - } - case ZigTypeIdBoundFn: - { - ZigFn *fn_entry = const_val->data.x_bound_fn.fn; - buf_appendf(buf, "(bound fn %s)", buf_ptr(&fn_entry->symbol_name)); - return; - } - case ZigTypeIdStruct: - { - if (is_slice(type_entry)) { - ZigValue *len_val = const_val->data.x_struct.fields[slice_len_index]; - size_t len = bigint_as_usize(&len_val->data.x_bigint); - - ZigValue *ptr_val = const_val->data.x_struct.fields[slice_ptr_index]; - if (ptr_val->special == ConstValSpecialUndef) { - assert(len == 0); - buf_appendf(buf, "((%s)(undefined))[0..0]", buf_ptr(&type_entry->name)); - return; - } - assert(ptr_val->data.x_ptr.special == ConstPtrSpecialBaseArray); - ZigValue *array = ptr_val->data.x_ptr.data.base_array.array_val; - size_t start = ptr_val->data.x_ptr.data.base_array.elem_index; - - if (array->special == ConstValSpecialUndef) - buf_append_str(buf, "undefined"); - else - render_const_val_array(g, buf, &type_entry->name, array, start, len); - } else { - buf_appendf(buf, "(struct %s constant)", buf_ptr(&type_entry->name)); - } - return; - } - case ZigTypeIdEnum: - { - TypeEnumField *field = find_enum_field_by_tag(type_entry, &const_val->data.x_enum_tag); - if(field != nullptr){ - buf_appendf(buf, "%s.%s", buf_ptr(&type_entry->name), buf_ptr(field->name)); - } else { - // untagged value in a non-exhaustive enum - buf_appendf(buf, "%s.(", buf_ptr(&type_entry->name)); - bigint_append_buf(buf, &const_val->data.x_enum_tag, 10); - buf_appendf(buf, ")"); - } - return; - } - case ZigTypeIdErrorUnion: - { - buf_appendf(buf, "%s(", buf_ptr(&type_entry->name)); - ErrorTableEntry *err_set = const_val->data.x_err_union.error_set->data.x_err_set; - if (err_set == nullptr) { - render_const_value(g, buf, const_val->data.x_err_union.payload); - } else { - buf_appendf(buf, "%s.%s", buf_ptr(&type_entry->data.error_union.err_set_type->name), - buf_ptr(&err_set->name)); - } - buf_appendf(buf, ")"); - return; - } - case ZigTypeIdUnion: - { - const BigInt *tag = &const_val->data.x_union.tag; - TypeUnionField *field = find_union_field_by_tag(type_entry, tag); - buf_appendf(buf, "%s { .%s = ", buf_ptr(&type_entry->name), buf_ptr(field->name)); - render_const_value(g, buf, const_val->data.x_union.payload); - buf_append_str(buf, "}"); - return; - } - case ZigTypeIdErrorSet: - return render_const_val_err_set(g, buf, const_val, type_entry); - case ZigTypeIdFnFrame: - buf_appendf(buf, "(TODO: async function frame value)"); - return; - - case ZigTypeIdAnyFrame: - buf_appendf(buf, "(TODO: anyframe value)"); - return; - - } - zig_unreachable(); -} - -ZigType *make_int_type(CodeGen *g, bool is_signed, uint32_t size_in_bits) { - assert(size_in_bits <= 65535); - ZigType *entry = new_type_table_entry(ZigTypeIdInt); - - entry->size_in_bits = size_in_bits; - if (size_in_bits != 0) { - entry->llvm_type = LLVMIntType(size_in_bits); - entry->abi_size = LLVMABISizeOfType(g->target_data_ref, entry->llvm_type); - entry->abi_align = LLVMABIAlignmentOfType(g->target_data_ref, entry->llvm_type); - - if (size_in_bits >= 128 && entry->abi_align < 16) { - // Override the incorrect alignment reported by LLVM. Clang does this as well. - // On x86_64 there are some instructions like CMPXCHG16B which require this. - // On all targets, integers 128 bits and above have ABI alignment of 16. - // However for some targets, LLVM incorrectly reports this as 8. - // See: https://github.com/ziglang/zig/issues/2987 - entry->abi_align = 16; - entry->abi_size = align_forward(entry->abi_size, entry->abi_align); - } - } - - const char u_or_i = is_signed ? 'i' : 'u'; - buf_resize(&entry->name, 0); - buf_appendf(&entry->name, "%c%" PRIu32, u_or_i, size_in_bits); - - entry->data.integral.is_signed = is_signed; - entry->data.integral.bit_count = size_in_bits; - return entry; -} - -uint32_t type_id_hash(TypeId const *x) { - uint32_t hash = hash_combine(HASH_INIT, &x->id); - switch (x->id) { - case ZigTypeIdInvalid: - case ZigTypeIdOpaque: - case ZigTypeIdMetaType: - case ZigTypeIdVoid: - case ZigTypeIdBool: - case ZigTypeIdUnreachable: - case ZigTypeIdFloat: - case ZigTypeIdStruct: - case ZigTypeIdComptimeFloat: - case ZigTypeIdComptimeInt: - case ZigTypeIdEnumLiteral: - case ZigTypeIdUndefined: - case ZigTypeIdNull: - case ZigTypeIdOptional: - case ZigTypeIdErrorSet: - case ZigTypeIdEnum: - case ZigTypeIdUnion: - case ZigTypeIdFn: - case ZigTypeIdBoundFn: - case ZigTypeIdFnFrame: - case ZigTypeIdAnyFrame: - zig_unreachable(); - case ZigTypeIdErrorUnion: - hash = hash_combine(hash, &x->data.error_union.err_set_type); - hash = hash_combine(hash, &x->data.error_union.payload_type); - return hash; - case ZigTypeIdPointer: - hash = hash_combine(hash, &x->data.pointer.child_type); - hash = hash_combine(hash, &x->data.pointer.ptr_len); - hash = hash_combine(hash, &x->data.pointer.is_const); - hash = hash_combine(hash, &x->data.pointer.is_volatile); - hash = hash_combine(hash, &x->data.pointer.allow_zero); - hash = hash_combine(hash, &x->data.pointer.alignment); - hash = hash_combine(hash, &x->data.pointer.bit_offset_in_host); - hash = hash_combine(hash, &x->data.pointer.vector_index); - hash = hash_combine(hash, &x->data.pointer.host_int_bytes); - if (x->data.pointer.sentinel != nullptr) { - hash = hash_combine_const_val(hash, x->data.pointer.sentinel); - } - if (x->data.pointer.inferred_struct_field) { - hash = hash_combine(hash, &x->data.pointer.inferred_struct_field->inferred_struct_type); - hash = hash_combine_buf(hash, x->data.pointer.inferred_struct_field->field_name); - } - return hash; - case ZigTypeIdArray: - hash = hash_combine(hash, &x->data.array.child_type); - hash = hash_combine(hash, &x->data.array.size); - if (x->data.array.sentinel != nullptr) { - hash = hash_combine_const_val(hash, x->data.array.sentinel); - } - return hash; - case ZigTypeIdInt: - hash = hash_combine(hash, &x->data.integer.is_signed); - hash = hash_combine(hash, &x->data.integer.bit_count); - return hash; - case ZigTypeIdVector: - hash = hash_combine(hash, &x->data.vector.elem_type); - hash = hash_combine(hash, &x->data.vector.len); - return hash; - } - zig_unreachable(); -} - -bool type_id_eql(TypeId const *a, TypeId const *b) { - if (a->id != b->id) - return false; - switch (a->id) { - case ZigTypeIdInvalid: - case ZigTypeIdMetaType: - case ZigTypeIdVoid: - case ZigTypeIdBool: - case ZigTypeIdUnreachable: - case ZigTypeIdFloat: - case ZigTypeIdStruct: - case ZigTypeIdComptimeFloat: - case ZigTypeIdComptimeInt: - case ZigTypeIdEnumLiteral: - case ZigTypeIdUndefined: - case ZigTypeIdNull: - case ZigTypeIdOptional: - case ZigTypeIdErrorSet: - case ZigTypeIdEnum: - case ZigTypeIdUnion: - case ZigTypeIdFn: - case ZigTypeIdBoundFn: - case ZigTypeIdOpaque: - case ZigTypeIdFnFrame: - case ZigTypeIdAnyFrame: - zig_unreachable(); - case ZigTypeIdErrorUnion: - return a->data.error_union.err_set_type == b->data.error_union.err_set_type && - a->data.error_union.payload_type == b->data.error_union.payload_type; - - case ZigTypeIdPointer: - return a->data.pointer.child_type == b->data.pointer.child_type && - a->data.pointer.ptr_len == b->data.pointer.ptr_len && - a->data.pointer.is_const == b->data.pointer.is_const && - a->data.pointer.is_volatile == b->data.pointer.is_volatile && - a->data.pointer.allow_zero == b->data.pointer.allow_zero && - a->data.pointer.alignment == b->data.pointer.alignment && - a->data.pointer.bit_offset_in_host == b->data.pointer.bit_offset_in_host && - a->data.pointer.vector_index == b->data.pointer.vector_index && - a->data.pointer.host_int_bytes == b->data.pointer.host_int_bytes && - ( - a->data.pointer.sentinel == b->data.pointer.sentinel || - (a->data.pointer.sentinel != nullptr && b->data.pointer.sentinel != nullptr && - const_values_equal(a->data.pointer.codegen, a->data.pointer.sentinel, b->data.pointer.sentinel)) - ) && - ( - a->data.pointer.inferred_struct_field == b->data.pointer.inferred_struct_field || - (a->data.pointer.inferred_struct_field != nullptr && - b->data.pointer.inferred_struct_field != nullptr && - a->data.pointer.inferred_struct_field->inferred_struct_type == - b->data.pointer.inferred_struct_field->inferred_struct_type && - buf_eql_buf(a->data.pointer.inferred_struct_field->field_name, - b->data.pointer.inferred_struct_field->field_name)) - ); - case ZigTypeIdArray: - return a->data.array.child_type == b->data.array.child_type && - a->data.array.size == b->data.array.size && - ( - a->data.array.sentinel == b->data.array.sentinel || - (a->data.array.sentinel != nullptr && b->data.array.sentinel != nullptr && - const_values_equal(a->data.array.codegen, a->data.array.sentinel, b->data.array.sentinel)) - ); - case ZigTypeIdInt: - return a->data.integer.is_signed == b->data.integer.is_signed && - a->data.integer.bit_count == b->data.integer.bit_count; - case ZigTypeIdVector: - return a->data.vector.elem_type == b->data.vector.elem_type && - a->data.vector.len == b->data.vector.len; - } - zig_unreachable(); -} - -uint32_t zig_llvm_fn_key_hash(ZigLLVMFnKey const *x) { - switch (x->id) { - case ZigLLVMFnIdCtz: - return (uint32_t)(x->data.ctz.bit_count) * (uint32_t)810453934 + - (uint32_t)(x->data.ctz.vector_len) * (((uint32_t)x->id << 5) + 1025); - case ZigLLVMFnIdClz: - return (uint32_t)(x->data.clz.bit_count) * (uint32_t)2428952817 + - (uint32_t)(x->data.clz.vector_len) * (((uint32_t)x->id << 5) + 1025); - case ZigLLVMFnIdPopCount: - return (uint32_t)(x->data.pop_count.bit_count) * (uint32_t)101195049 + - (uint32_t)(x->data.pop_count.vector_len) * (((uint32_t)x->id << 5) + 1025); - case ZigLLVMFnIdFloatOp: - return (uint32_t)(x->data.floating.bit_count) * ((uint32_t)x->id + 1025) + - (uint32_t)(x->data.floating.vector_len) * (((uint32_t)x->id << 5) + 1025) + - (uint32_t)(x->data.floating.op) * (uint32_t)43789879; - case ZigLLVMFnIdFMA: - return (uint32_t)(x->data.floating.bit_count) * ((uint32_t)x->id + 1025) + - (uint32_t)(x->data.floating.vector_len) * (((uint32_t)x->id << 5) + 1025); - case ZigLLVMFnIdBswap: - return (uint32_t)(x->data.bswap.bit_count) * ((uint32_t)3661994335) + - (uint32_t)(x->data.bswap.vector_len) * (((uint32_t)x->id << 5) + 1025); - case ZigLLVMFnIdBitReverse: - return (uint32_t)(x->data.bit_reverse.bit_count) * (uint32_t)2621398431; - case ZigLLVMFnIdOverflowArithmetic: - return ((uint32_t)(x->data.overflow_arithmetic.bit_count) * 87135777) + - ((uint32_t)(x->data.overflow_arithmetic.add_sub_mul) * 31640542) + - ((uint32_t)(x->data.overflow_arithmetic.is_signed) ? 1062315172 : 314955820) + - x->data.overflow_arithmetic.vector_len * 1435156945; - } - zig_unreachable(); -} - -bool zig_llvm_fn_key_eql(ZigLLVMFnKey const *a, ZigLLVMFnKey const *b) { - if (a->id != b->id) - return false; - switch (a->id) { - case ZigLLVMFnIdCtz: - return a->data.ctz.bit_count == b->data.ctz.bit_count; - case ZigLLVMFnIdClz: - return a->data.clz.bit_count == b->data.clz.bit_count; - case ZigLLVMFnIdPopCount: - return a->data.pop_count.bit_count == b->data.pop_count.bit_count; - case ZigLLVMFnIdBswap: - return a->data.bswap.bit_count == b->data.bswap.bit_count && - a->data.bswap.vector_len == b->data.bswap.vector_len; - case ZigLLVMFnIdBitReverse: - return a->data.bit_reverse.bit_count == b->data.bit_reverse.bit_count; - case ZigLLVMFnIdFloatOp: - return a->data.floating.bit_count == b->data.floating.bit_count && - a->data.floating.vector_len == b->data.floating.vector_len && - a->data.floating.op == b->data.floating.op; - case ZigLLVMFnIdFMA: - return a->data.floating.bit_count == b->data.floating.bit_count && - a->data.floating.vector_len == b->data.floating.vector_len; - case ZigLLVMFnIdOverflowArithmetic: - return (a->data.overflow_arithmetic.bit_count == b->data.overflow_arithmetic.bit_count) && - (a->data.overflow_arithmetic.add_sub_mul == b->data.overflow_arithmetic.add_sub_mul) && - (a->data.overflow_arithmetic.is_signed == b->data.overflow_arithmetic.is_signed) && - (a->data.overflow_arithmetic.vector_len == b->data.overflow_arithmetic.vector_len); - } - zig_unreachable(); -} - -static void init_const_undefined(CodeGen *g, ZigValue *const_val) { - Error err; - ZigType *wanted_type = const_val->type; - if (wanted_type->id == ZigTypeIdArray) { - const_val->special = ConstValSpecialStatic; - const_val->data.x_array.special = ConstArraySpecialUndef; - } else if (wanted_type->id == ZigTypeIdStruct) { - if ((err = type_resolve(g, wanted_type, ResolveStatusZeroBitsKnown))) { - return; - } - - const_val->special = ConstValSpecialStatic; - size_t field_count = wanted_type->data.structure.src_field_count; - const_val->data.x_struct.fields = alloc_const_vals_ptrs(g, field_count); - for (size_t i = 0; i < field_count; i += 1) { - TypeStructField *field = wanted_type->data.structure.fields[i]; - if (field->is_comptime) { - // Comptime fields are part of the type, and do not need to - // be initialized. - continue; - } - - ZigValue *field_val = const_val->data.x_struct.fields[i]; - field_val->type = resolve_struct_field_type(g, wanted_type->data.structure.fields[i]); - assert(field_val->type); - init_const_undefined(g, field_val); - field_val->parent.id = ConstParentIdStruct; - field_val->parent.data.p_struct.struct_val = const_val; - field_val->parent.data.p_struct.field_index = i; - } - } else { - const_val->special = ConstValSpecialUndef; - } -} - -void expand_undef_struct(CodeGen *g, ZigValue *const_val) { - if (const_val->special == ConstValSpecialUndef) { - init_const_undefined(g, const_val); - } -} - -// Canonicalize the array value as ConstArraySpecialNone -void expand_undef_array(CodeGen *g, ZigValue *const_val) { - size_t elem_count; - ZigType *elem_type; - if (const_val->type->id == ZigTypeIdArray) { - elem_count = const_val->type->data.array.len; - elem_type = const_val->type->data.array.child_type; - } else if (const_val->type->id == ZigTypeIdVector) { - elem_count = const_val->type->data.vector.len; - elem_type = const_val->type->data.vector.elem_type; - } else { - zig_unreachable(); - } - if (const_val->special == ConstValSpecialUndef) { - const_val->special = ConstValSpecialStatic; - const_val->data.x_array.special = ConstArraySpecialUndef; - } - switch (const_val->data.x_array.special) { - case ConstArraySpecialNone: - return; - case ConstArraySpecialUndef: { - const_val->data.x_array.special = ConstArraySpecialNone; - const_val->data.x_array.data.s_none.elements = g->pass1_arena->allocate(elem_count); - for (size_t i = 0; i < elem_count; i += 1) { - ZigValue *element_val = &const_val->data.x_array.data.s_none.elements[i]; - element_val->type = elem_type; - init_const_undefined(g, element_val); - element_val->parent.id = ConstParentIdArray; - element_val->parent.data.p_array.array_val = const_val; - element_val->parent.data.p_array.elem_index = i; - } - return; - } - case ConstArraySpecialBuf: { - Buf *buf = const_val->data.x_array.data.s_buf; - // If we're doing this it means that we are potentially modifying the data, - // so we can't have it be in the string literals table - g->string_literals_table.maybe_remove(buf); - - const_val->data.x_array.special = ConstArraySpecialNone; - assert(elem_count == buf_len(buf)); - const_val->data.x_array.data.s_none.elements = g->pass1_arena->allocate(elem_count); - for (size_t i = 0; i < elem_count; i += 1) { - ZigValue *this_char = &const_val->data.x_array.data.s_none.elements[i]; - this_char->special = ConstValSpecialStatic; - this_char->type = g->builtin_types.entry_u8; - bigint_init_unsigned(&this_char->data.x_bigint, (uint8_t)buf_ptr(buf)[i]); - this_char->parent.id = ConstParentIdArray; - this_char->parent.data.p_array.array_val = const_val; - this_char->parent.data.p_array.elem_index = i; - } - return; - } - } - zig_unreachable(); -} - -static const ZigTypeId all_type_ids[] = { - ZigTypeIdMetaType, - ZigTypeIdVoid, - ZigTypeIdBool, - ZigTypeIdUnreachable, - ZigTypeIdInt, - ZigTypeIdFloat, - ZigTypeIdPointer, - ZigTypeIdArray, - ZigTypeIdStruct, - ZigTypeIdComptimeFloat, - ZigTypeIdComptimeInt, - ZigTypeIdUndefined, - ZigTypeIdNull, - ZigTypeIdOptional, - ZigTypeIdErrorUnion, - ZigTypeIdErrorSet, - ZigTypeIdEnum, - ZigTypeIdUnion, - ZigTypeIdFn, - ZigTypeIdBoundFn, - ZigTypeIdOpaque, - ZigTypeIdFnFrame, - ZigTypeIdAnyFrame, - ZigTypeIdVector, - ZigTypeIdEnumLiteral, -}; - -ZigTypeId type_id_at_index(size_t index) { - assert(index < array_length(all_type_ids)); - return all_type_ids[index]; -} - -size_t type_id_len() { - return array_length(all_type_ids); -} - -size_t type_id_index(ZigType *entry) { - switch (entry->id) { - case ZigTypeIdInvalid: - zig_unreachable(); - case ZigTypeIdMetaType: - return 0; - case ZigTypeIdVoid: - return 1; - case ZigTypeIdBool: - return 2; - case ZigTypeIdUnreachable: - return 3; - case ZigTypeIdInt: - return 4; - case ZigTypeIdFloat: - return 5; - case ZigTypeIdPointer: - return 6; - case ZigTypeIdArray: - return 7; - case ZigTypeIdStruct: - if (entry->data.structure.special == StructSpecialSlice) - return 6; - return 8; - case ZigTypeIdComptimeFloat: - return 9; - case ZigTypeIdComptimeInt: - return 10; - case ZigTypeIdUndefined: - return 11; - case ZigTypeIdNull: - return 12; - case ZigTypeIdOptional: - return 13; - case ZigTypeIdErrorUnion: - return 14; - case ZigTypeIdErrorSet: - return 15; - case ZigTypeIdEnum: - return 16; - case ZigTypeIdUnion: - return 17; - case ZigTypeIdFn: - return 18; - case ZigTypeIdBoundFn: - return 19; - case ZigTypeIdOpaque: - return 20; - case ZigTypeIdFnFrame: - return 21; - case ZigTypeIdAnyFrame: - return 22; - case ZigTypeIdVector: - return 23; - case ZigTypeIdEnumLiteral: - return 24; - } - zig_unreachable(); -} - -const char *type_id_name(ZigTypeId id) { - switch (id) { - case ZigTypeIdInvalid: - zig_unreachable(); - case ZigTypeIdMetaType: - return "Type"; - case ZigTypeIdVoid: - return "Void"; - case ZigTypeIdBool: - return "Bool"; - case ZigTypeIdUnreachable: - return "NoReturn"; - case ZigTypeIdInt: - return "Int"; - case ZigTypeIdFloat: - return "Float"; - case ZigTypeIdPointer: - return "Pointer"; - case ZigTypeIdArray: - return "Array"; - case ZigTypeIdStruct: - return "Struct"; - case ZigTypeIdComptimeFloat: - return "ComptimeFloat"; - case ZigTypeIdComptimeInt: - return "ComptimeInt"; - case ZigTypeIdEnumLiteral: - return "EnumLiteral"; - case ZigTypeIdUndefined: - return "Undefined"; - case ZigTypeIdNull: - return "Null"; - case ZigTypeIdOptional: - return "Optional"; - case ZigTypeIdErrorUnion: - return "ErrorUnion"; - case ZigTypeIdErrorSet: - return "ErrorSet"; - case ZigTypeIdEnum: - return "Enum"; - case ZigTypeIdUnion: - return "Union"; - case ZigTypeIdFn: - return "Fn"; - case ZigTypeIdBoundFn: - return "BoundFn"; - case ZigTypeIdOpaque: - return "Opaque"; - case ZigTypeIdVector: - return "Vector"; - case ZigTypeIdFnFrame: - return "Frame"; - case ZigTypeIdAnyFrame: - return "AnyFrame"; - } - zig_unreachable(); -} - -ZigType *get_align_amt_type(CodeGen *g) { - if (g->align_amt_type == nullptr) { - // according to LLVM the maximum alignment is 1 << 29. - g->align_amt_type = get_int_type(g, false, 29); - } - return g->align_amt_type; -} - -uint32_t type_ptr_hash(const ZigType *ptr) { - return hash_combine(HASH_INIT, &ptr); -} - -bool type_ptr_eql(const ZigType *a, const ZigType *b) { - return a == b; -} - -uint32_t pkg_ptr_hash(const ZigPackage *ptr) { - return hash_combine(HASH_INIT, &ptr); -} - -bool pkg_ptr_eql(const ZigPackage *a, const ZigPackage *b) { - return a == b; -} - -uint32_t tld_ptr_hash(const Tld *ptr) { - return hash_combine(HASH_INIT, &ptr); -} - -bool tld_ptr_eql(const Tld *a, const Tld *b) { - return a == b; -} - -uint32_t node_ptr_hash(const AstNode *ptr) { - return hash_combine(HASH_INIT, &ptr); -} - -bool node_ptr_eql(const AstNode *a, const AstNode *b) { - return a == b; -} - -uint32_t fn_ptr_hash(const ZigFn *ptr) { - return hash_combine(HASH_INIT, &ptr); -} - -bool fn_ptr_eql(const ZigFn *a, const ZigFn *b) { - return a == b; -} - -uint32_t err_ptr_hash(const ErrorTableEntry *ptr) { - return hash_combine(HASH_INIT, &ptr); -} - -bool err_ptr_eql(const ErrorTableEntry *a, const ErrorTableEntry *b) { - return a == b; -} - -ZigValue *get_builtin_value(CodeGen *codegen, const char *name) { - Buf *buf_name = buf_create_from_str(name); - - ScopeDecls *builtin_scope = get_container_scope(codegen->std_builtin_import); - Tld *tld = find_container_decl(codegen, builtin_scope, buf_name); - assert(tld != nullptr); - resolve_top_level_decl(codegen, tld, nullptr, false); - assert(tld->id == TldIdVar && tld->resolution == TldResolutionOk); - TldVar *tld_var = (TldVar *)tld; - ZigValue *var_value = tld_var->var->const_value; - assert(var_value != nullptr); - - buf_destroy(buf_name); - return var_value; -} - -ZigType *get_builtin_type(CodeGen *codegen, const char *name) { - ZigValue *type_val = get_builtin_value(codegen, name); - assert(type_val->type->id == ZigTypeIdMetaType); - return type_val->data.x_type; -} - -bool type_is_global_error_set(ZigType *err_set_type) { - assert(err_set_type->id == ZigTypeIdErrorSet); - assert(!err_set_type->data.error_set.incomplete); - return err_set_type->data.error_set.err_count == UINT32_MAX; -} - -bool type_can_fail(ZigType *type_entry) { - return type_entry->id == ZigTypeIdErrorUnion || type_entry->id == ZigTypeIdErrorSet; -} - -bool fn_type_can_fail(FnTypeId *fn_type_id) { - return type_can_fail(fn_type_id->return_type); -} - -// ErrorNone - result pointer has the type -// ErrorOverflow - an integer primitive type has too large a bit width -// ErrorPrimitiveTypeNotFound - result pointer unchanged -Error get_primitive_type(CodeGen *g, Buf *name, ZigType **result) { - if (buf_len(name) >= 2) { - uint8_t first_c = buf_ptr(name)[0]; - if (first_c == 'i' || first_c == 'u') { - for (size_t i = 1; i < buf_len(name); i += 1) { - uint8_t c = buf_ptr(name)[i]; - if (c < '0' || c > '9') { - goto not_integer; - } - } - bool is_signed = (first_c == 'i'); - unsigned long int bit_count = strtoul(buf_ptr(name) + 1, nullptr, 10); - // strtoul returns ULONG_MAX on errors, so this comparison catches that as well. - if (bit_count >= 65536) return ErrorOverflow; - *result = get_int_type(g, is_signed, bit_count); - return ErrorNone; - } - } - -not_integer: - - auto primitive_table_entry = g->primitive_type_table.maybe_get(name); - if (primitive_table_entry == nullptr) - return ErrorPrimitiveTypeNotFound; - - *result = primitive_table_entry->value; - return ErrorNone; -} - -Error file_fetch(CodeGen *g, Buf *resolved_path, Buf *contents_buf) { - size_t len; - const char *contents = stage2_fetch_file(&g->stage1, buf_ptr(resolved_path), buf_len(resolved_path), &len); - if (contents == nullptr) - return ErrorFileNotFound; - buf_init_from_mem(contents_buf, contents, len); - return ErrorNone; -} - -static X64CABIClass type_windows_abi_x86_64_class(CodeGen *g, ZigType *ty, size_t ty_size) { - // https://docs.microsoft.com/en-gb/cpp/build/x64-calling-convention?view=vs-2017 - switch (ty_size) { - case 1: - case 2: - case 4: - case 8: - break; - case 16: - return (ty->id == ZigTypeIdVector) ? X64CABIClass_SSE : X64CABIClass_MEMORY; - default: - return X64CABIClass_MEMORY; - } - switch (ty->id) { - case ZigTypeIdInvalid: - case ZigTypeIdMetaType: - case ZigTypeIdComptimeFloat: - case ZigTypeIdComptimeInt: - case ZigTypeIdNull: - case ZigTypeIdUndefined: - case ZigTypeIdBoundFn: - case ZigTypeIdOpaque: - case ZigTypeIdEnumLiteral: - zig_unreachable(); - - case ZigTypeIdFn: - case ZigTypeIdPointer: - case ZigTypeIdInt: - case ZigTypeIdBool: - case ZigTypeIdEnum: - case ZigTypeIdVoid: - case ZigTypeIdUnreachable: - case ZigTypeIdErrorSet: - case ZigTypeIdErrorUnion: - case ZigTypeIdStruct: - case ZigTypeIdUnion: - case ZigTypeIdOptional: - case ZigTypeIdFnFrame: - case ZigTypeIdAnyFrame: - return X64CABIClass_INTEGER; - - case ZigTypeIdFloat: - case ZigTypeIdVector: - return X64CABIClass_SSE; - - case ZigTypeIdArray: - return X64CABIClass_Unknown; - } - zig_unreachable(); -} - -static X64CABIClass type_system_V_abi_x86_64_class(CodeGen *g, ZigType *ty, size_t ty_size) { - switch (ty->id) { - case ZigTypeIdEnum: - case ZigTypeIdInt: - case ZigTypeIdBool: - return X64CABIClass_INTEGER; - case ZigTypeIdFloat: - case ZigTypeIdVector: - return X64CABIClass_SSE; - case ZigTypeIdStruct: { - // "If the size of an object is larger than four eightbytes, or it contains unaligned - // fields, it has class MEMORY" - if (ty_size > 32) - return X64CABIClass_MEMORY; - if (ty->data.structure.layout != ContainerLayoutExtern) { - // TODO determine whether packed structs have any unaligned fields - return X64CABIClass_Unknown; - } - // "If the size of the aggregate exceeds two eightbytes and the first eight- - // byte isn’t SSE or any other eightbyte isn’t SSEUP, the whole argument - // is passed in memory." - if (ty_size > 16) { - // Zig doesn't support vectors and large fp registers yet, so this will always - // be memory. - return X64CABIClass_MEMORY; - } - // "If the size of the aggregate exceeds a single eightbyte, each is classified - // separately.". - // "If one of the classes is MEMORY, the whole argument is passed in memory" - X64CABIClass working_class = X64CABIClass_Unknown; - for (uint32_t i = 0; i < ty->data.structure.src_field_count; i += 1) { - X64CABIClass field_class = type_c_abi_x86_64_class(g, ty->data.structure.fields[0]->type_entry); - if (field_class == X64CABIClass_Unknown) - return X64CABIClass_Unknown; - if (i == 0 || field_class == X64CABIClass_MEMORY || working_class == X64CABIClass_SSE) { - working_class = field_class; - } - } - if (working_class == X64CABIClass_MEMORY) { - return X64CABIClass_MEMORY; - } - return X64CABIClass_AGG; - } - case ZigTypeIdUnion: { - // "If the size of an object is larger than four eightbytes, or it contains unaligned - // fields, it has class MEMORY" - if (ty_size > 32) - return X64CABIClass_MEMORY; - if (ty->data.unionation.layout != ContainerLayoutExtern) - return X64CABIClass_MEMORY; - // "If the size of the aggregate exceeds two eightbytes and the first eight- - // byte isn’t SSE or any other eightbyte isn’t SSEUP, the whole argument - // is passed in memory." - if (ty_size > 16) { - // Zig doesn't support vectors and large fp registers yet, so this will always - // be memory. - return X64CABIClass_MEMORY; - } - X64CABIClass working_class = X64CABIClass_Unknown; - for (uint32_t i = 0; i < ty->data.unionation.src_field_count; i += 1) { - X64CABIClass field_class = type_c_abi_x86_64_class(g, ty->data.unionation.fields->type_entry); - if (field_class == X64CABIClass_Unknown) - return X64CABIClass_Unknown; - if (i == 0 || field_class == X64CABIClass_MEMORY || field_class == X64CABIClass_INTEGER || working_class == X64CABIClass_SSE) { - working_class = field_class; - } - } - return working_class; - } - default: - return X64CABIClass_Unknown; - } -} - -X64CABIClass type_c_abi_x86_64_class(CodeGen *g, ZigType *ty) { - Error err; - const size_t ty_size = type_size(g, ty); - - if (g->zig_target->os == OsWindows || g->zig_target->os == OsUefi) { - return type_windows_abi_x86_64_class(g, ty, ty_size); - } - - ZigType *ptr_type; - if ((err = get_codegen_ptr_type(g, ty, &ptr_type))) return X64CABIClass_Unknown; - if (ptr_type != nullptr) - return X64CABIClass_INTEGER; - - if (g->zig_target->arch == ZigLLVM_aarch64 || - g->zig_target->arch == ZigLLVM_aarch64_be) - { - X64CABIClass result = type_system_V_abi_x86_64_class(g, ty, ty_size); - return (result == X64CABIClass_MEMORY) ? X64CABIClass_MEMORY_nobyval : result; - } else { - return type_system_V_abi_x86_64_class(g, ty, ty_size); - } -} - -// NOTE this does not depend on x86_64 -Error type_is_c_abi_int(CodeGen *g, ZigType *ty, bool *result) { - if (ty->id == ZigTypeIdInt || - ty->id == ZigTypeIdFloat || - ty->id == ZigTypeIdBool || - ty->id == ZigTypeIdEnum || - ty->id == ZigTypeIdVoid || - ty->id == ZigTypeIdUnreachable) - { - *result = true; - return ErrorNone; - } - - Error err; - ZigType *ptr_type; - if ((err = get_codegen_ptr_type(g, ty, &ptr_type))) return err; - *result = ptr_type != nullptr; - return ErrorNone; -} - -bool type_is_c_abi_int_bail(CodeGen *g, ZigType *ty) { - Error err; - bool result; - if ((err = type_is_c_abi_int(g, ty, &result))) - codegen_report_errors_and_exit(g); - - return result; -} - -uint32_t get_host_int_bytes(CodeGen *g, ZigType *struct_type, TypeStructField *field) { - assert(struct_type->id == ZigTypeIdStruct); - if (struct_type->data.structure.layout != ContainerLayoutAuto) { - assert(type_is_resolved(struct_type, ResolveStatusSizeKnown)); - } - if (struct_type->data.structure.host_int_bytes == nullptr) - return 0; - return struct_type->data.structure.host_int_bytes[field->gen_index]; -} - -Error ensure_const_val_repr(IrAnalyze *ira, CodeGen *codegen, AstNode *source_node, - ZigValue *const_val, ZigType *wanted_type) -{ - ZigValue ptr_val = {}; - ptr_val.special = ConstValSpecialStatic; - ptr_val.type = get_pointer_to_type(codegen, wanted_type, true); - ptr_val.data.x_ptr.mut = ConstPtrMutComptimeConst; - ptr_val.data.x_ptr.special = ConstPtrSpecialRef; - ptr_val.data.x_ptr.data.ref.pointee = const_val; - if (const_ptr_pointee(ira, codegen, &ptr_val, source_node) == nullptr) - return ErrorSemanticAnalyzeFail; - - return ErrorNone; -} - -const char *container_string(ContainerKind kind) { - switch (kind) { - case ContainerKindEnum: return "enum"; - case ContainerKindStruct: return "struct"; - case ContainerKindUnion: return "union"; - case ContainerKindOpaque: return "opaque"; - } - zig_unreachable(); -} - -bool ptr_allows_addr_zero(ZigType *ptr_type) { - if (ptr_type->id == ZigTypeIdPointer) { - return ptr_type->data.pointer.allow_zero; - } else if (ptr_type->id == ZigTypeIdOptional) { - return true; - } - return false; -} - -Buf *type_bare_name(ZigType *type_entry) { - if (is_slice(type_entry)) { - return &type_entry->name; - } else if (is_container(type_entry)) { - return get_container_scope(type_entry)->bare_name; - } else { - return &type_entry->name; - } -} - -// TODO this will have to be more clever, probably using the full name -// and replacing '.' with '_' or something like that -Buf *type_h_name(ZigType *t) { - return type_bare_name(t); -} - -static void resolve_llvm_types_slice(CodeGen *g, ZigType *type, ResolveStatus wanted_resolve_status) { - if (type->data.structure.resolve_status >= wanted_resolve_status) return; - - ZigType *ptr_type = type->data.structure.fields[slice_ptr_index]->type_entry; - ZigType *child_type = ptr_type->data.pointer.child_type; - ZigType *usize_type = g->builtin_types.entry_usize; - - bool done = false; - if (ptr_type->data.pointer.is_const || ptr_type->data.pointer.is_volatile || - ptr_type->data.pointer.explicit_alignment != 0 || ptr_type->data.pointer.allow_zero || - ptr_type->data.pointer.sentinel != nullptr) - { - ZigType *peer_ptr_type = get_pointer_to_type_extra(g, child_type, false, false, - PtrLenUnknown, 0, 0, 0, false); - ZigType *peer_slice_type = get_slice_type(g, peer_ptr_type); - - assertNoError(type_resolve(g, peer_slice_type, wanted_resolve_status)); - type->llvm_type = peer_slice_type->llvm_type; - type->llvm_di_type = peer_slice_type->llvm_di_type; - type->data.structure.resolve_status = peer_slice_type->data.structure.resolve_status; - done = true; - } - - // If the child type is []const T then we need to make sure the type ref - // and debug info is the same as if the child type were []T. - if (is_slice(child_type)) { - ZigType *child_ptr_type = child_type->data.structure.fields[slice_ptr_index]->type_entry; - assert(child_ptr_type->id == ZigTypeIdPointer); - if (child_ptr_type->data.pointer.is_const || child_ptr_type->data.pointer.is_volatile || - child_ptr_type->data.pointer.explicit_alignment != 0 || child_ptr_type->data.pointer.allow_zero || - child_ptr_type->data.pointer.sentinel != nullptr) - { - ZigType *grand_child_type = child_ptr_type->data.pointer.child_type; - ZigType *bland_child_ptr_type = get_pointer_to_type_extra(g, grand_child_type, false, false, - PtrLenUnknown, 0, 0, 0, false); - ZigType *bland_child_slice = get_slice_type(g, bland_child_ptr_type); - ZigType *peer_ptr_type = get_pointer_to_type_extra(g, bland_child_slice, false, false, - PtrLenUnknown, 0, 0, 0, false); - ZigType *peer_slice_type = get_slice_type(g, peer_ptr_type); - - assertNoError(type_resolve(g, peer_slice_type, wanted_resolve_status)); - type->llvm_type = peer_slice_type->llvm_type; - type->llvm_di_type = peer_slice_type->llvm_di_type; - type->data.structure.resolve_status = peer_slice_type->data.structure.resolve_status; - done = true; - } - } - - if (done) return; - - LLVMTypeRef usize_llvm_type = get_llvm_type(g, usize_type); - ZigLLVMDIType *usize_llvm_di_type = get_llvm_di_type(g, usize_type); - ZigLLVMDIScope *compile_unit_scope = ZigLLVMCompileUnitToScope(g->compile_unit); - ZigLLVMDIFile *di_file = nullptr; - unsigned line = 0; - - if (type->data.structure.resolve_status < ResolveStatusLLVMFwdDecl) { - type->llvm_type = LLVMStructCreateNamed(LLVMGetGlobalContext(), buf_ptr(&type->name)); - - type->llvm_di_type = ZigLLVMCreateReplaceableCompositeType(g->dbuilder, - ZigLLVMTag_DW_structure_type(), buf_ptr(&type->name), - compile_unit_scope, di_file, line); - - type->data.structure.resolve_status = ResolveStatusLLVMFwdDecl; - if (ResolveStatusLLVMFwdDecl >= wanted_resolve_status) return; - } - - if (!type_has_bits(g, child_type)) { - LLVMTypeRef element_types[] = { - usize_llvm_type, - }; - LLVMStructSetBody(type->llvm_type, element_types, 1, false); - - uint64_t len_debug_size_in_bits = usize_type->size_in_bits; - uint64_t len_debug_align_in_bits = 8*usize_type->abi_align; - uint64_t len_offset_in_bits = 8*LLVMOffsetOfElement(g->target_data_ref, type->llvm_type, 0); - - uint64_t debug_size_in_bits = type->size_in_bits; - uint64_t debug_align_in_bits = 8*type->abi_align; - - ZigLLVMDIType *di_element_types[] = { - ZigLLVMCreateDebugMemberType(g->dbuilder, ZigLLVMTypeToScope(type->llvm_di_type), - "len", di_file, line, - len_debug_size_in_bits, - len_debug_align_in_bits, - len_offset_in_bits, - ZigLLVM_DIFlags_Zero, - usize_llvm_di_type), - }; - ZigLLVMDIType *replacement_di_type = ZigLLVMCreateDebugStructType(g->dbuilder, - compile_unit_scope, - buf_ptr(&type->name), - di_file, line, debug_size_in_bits, debug_align_in_bits, - ZigLLVM_DIFlags_Zero, - nullptr, di_element_types, 1, 0, nullptr, ""); - - ZigLLVMReplaceTemporary(g->dbuilder, type->llvm_di_type, replacement_di_type); - type->llvm_di_type = replacement_di_type; - type->data.structure.resolve_status = ResolveStatusLLVMFull; - return; - } - - LLVMTypeRef element_types[2]; - element_types[slice_ptr_index] = get_llvm_type(g, ptr_type); - element_types[slice_len_index] = get_llvm_type(g, g->builtin_types.entry_usize); - if (type->data.structure.resolve_status >= wanted_resolve_status) return; - LLVMStructSetBody(type->llvm_type, element_types, 2, false); - - uint64_t ptr_debug_size_in_bits = ptr_type->size_in_bits; - uint64_t ptr_debug_align_in_bits = 8*ptr_type->abi_align; - uint64_t ptr_offset_in_bits = 8*LLVMOffsetOfElement(g->target_data_ref, type->llvm_type, 0); - - uint64_t len_debug_size_in_bits = usize_type->size_in_bits; - uint64_t len_debug_align_in_bits = 8*usize_type->abi_align; - uint64_t len_offset_in_bits = 8*LLVMOffsetOfElement(g->target_data_ref, type->llvm_type, 1); - - uint64_t debug_size_in_bits = type->size_in_bits; - uint64_t debug_align_in_bits = 8*type->abi_align; - - ZigLLVMDIType *di_element_types[] = { - ZigLLVMCreateDebugMemberType(g->dbuilder, ZigLLVMTypeToScope(type->llvm_di_type), - "ptr", di_file, line, - ptr_debug_size_in_bits, - ptr_debug_align_in_bits, - ptr_offset_in_bits, - ZigLLVM_DIFlags_Zero, get_llvm_di_type(g, ptr_type)), - ZigLLVMCreateDebugMemberType(g->dbuilder, ZigLLVMTypeToScope(type->llvm_di_type), - "len", di_file, line, - len_debug_size_in_bits, - len_debug_align_in_bits, - len_offset_in_bits, - ZigLLVM_DIFlags_Zero, usize_llvm_di_type), - }; - ZigLLVMDIType *replacement_di_type = ZigLLVMCreateDebugStructType(g->dbuilder, - compile_unit_scope, - buf_ptr(&type->name), - di_file, line, debug_size_in_bits, debug_align_in_bits, - ZigLLVM_DIFlags_Zero, - nullptr, di_element_types, 2, 0, nullptr, ""); - - ZigLLVMReplaceTemporary(g->dbuilder, type->llvm_di_type, replacement_di_type); - type->llvm_di_type = replacement_di_type; - type->data.structure.resolve_status = ResolveStatusLLVMFull; -} - -static LLVMTypeRef get_llvm_type_of_n_bytes(unsigned byte_size) { - return byte_size == 1 ? - LLVMInt8Type() : LLVMArrayType(LLVMInt8Type(), byte_size); -} - -static LLVMTypeRef llvm_int_for_size(size_t size) { - if (size > 4) { - return LLVMInt64Type(); - } else if (size > 2) { - return LLVMInt32Type(); - } else if (size == 2) { - return LLVMInt16Type(); - } else { - return LLVMInt8Type(); - } -} - -static LLVMTypeRef llvm_sse_for_size(size_t size) { - if (size > 4) - return LLVMDoubleType(); - else - return LLVMFloatType(); -} - -// Since it's not possible to control calling convention or register -// allocation in LLVM, clang seems to use intermediate types to manipulate -// LLVM into doing the right thing. It uses a float to force SSE registers, -// and a struct when 2 registers must be used. Some examples: -// { f32 } -> float -// { f32, i32 } -> { float, i32 } -// { i32, i32, f32 } -> { i64, float } -// -// The implementation below does not match clang 1:1. For instance, clang -// uses `<2x float>` while we generate `double`. There's a lot more edge -// cases and complexity when converting back and forth in clang though, -// so below is the simplest implementation that passes all tests. -static Error resolve_llvm_c_abi_type(CodeGen *g, ZigType *ty) { - size_t ty_size = type_size(g, ty); - LLVMTypeRef abi_type; - switch (ty->id) { - case ZigTypeIdEnum: - case ZigTypeIdInt: - case ZigTypeIdBool: - abi_type = llvm_int_for_size(ty_size); - break; - case ZigTypeIdFloat: - case ZigTypeIdVector: - abi_type = llvm_sse_for_size(ty_size); - break; - case ZigTypeIdStruct: { - uint32_t eightbyte_index = 0; - size_t type_sizes[] = {0, 0}; - X64CABIClass type_classes[] = {X64CABIClass_Unknown, X64CABIClass_Unknown}; - for (uint32_t i = 0; i < ty->data.structure.src_field_count; i += 1) { - if (ty->data.structure.fields[i]->offset >= 8) { - eightbyte_index = 1; - } - ZigType *field_ty = ty->data.structure.fields[i]->type_entry; - X64CABIClass field_class = type_c_abi_x86_64_class(g, field_ty); - - if (field_class == X64CABIClass_INTEGER) { - type_classes[eightbyte_index] = X64CABIClass_INTEGER; - } else if (type_classes[eightbyte_index] == X64CABIClass_Unknown) { - type_classes[eightbyte_index] = field_class; - } - if (field_ty->abi_size > 8) { - assert(eightbyte_index == 0); - type_sizes[0] = 8; - type_sizes[1] = field_ty->abi_size - 8; - type_classes[1] = type_classes[0]; - eightbyte_index = 1; - } else { - type_sizes[eightbyte_index] += field_ty->abi_size; - } - } - - LLVMTypeRef return_elem_types[] = { - LLVMVoidType(), - LLVMVoidType(), - }; - for (uint32_t i = 0; i <= eightbyte_index; i += 1) { - if (type_classes[i] == X64CABIClass_INTEGER) { - return_elem_types[i] = llvm_int_for_size(type_sizes[i]); - } else { - return_elem_types[i] = llvm_sse_for_size(type_sizes[i]); - } - } - if (eightbyte_index == 0) { - abi_type = return_elem_types[0]; - } else { - abi_type = LLVMStructType(return_elem_types, 2, false); - } - break; - } - case ZigTypeIdUnion: - default: - // currently unreachable - zig_panic("TODO: support C ABI unions"); - } - ty->llvm_c_abi_type = abi_type; - return ErrorNone; -} - -static void resolve_llvm_types_struct(CodeGen *g, ZigType *struct_type, ResolveStatus wanted_resolve_status, - ZigType *async_frame_type) -{ - assert(struct_type->id == ZigTypeIdStruct); - assert(struct_type->data.structure.resolve_status != ResolveStatusInvalid); - assert(struct_type->data.structure.resolve_status >= ResolveStatusSizeKnown); - assert(struct_type->data.structure.fields || struct_type->data.structure.src_field_count == 0); - if (struct_type->data.structure.resolve_status >= wanted_resolve_status) return; - - AstNode *decl_node = struct_type->data.structure.decl_node; - ZigLLVMDIFile *di_file; - ZigLLVMDIScope *di_scope; - unsigned line; - if (decl_node != nullptr) { - Scope *scope = &struct_type->data.structure.decls_scope->base; - ZigType *import = get_scope_import(scope); - di_file = import->data.structure.root_struct->di_file; - di_scope = ZigLLVMFileToScope(di_file); - line = node_line_onebased(decl_node); - } else { - di_file = nullptr; - di_scope = ZigLLVMCompileUnitToScope(g->compile_unit); - line = 0; - } - - if (struct_type->data.structure.resolve_status < ResolveStatusLLVMFwdDecl) { - struct_type->llvm_type = type_has_bits(g, struct_type) ? - LLVMStructCreateNamed(LLVMGetGlobalContext(), buf_ptr(&struct_type->name)) : LLVMVoidType(); - unsigned dwarf_kind = ZigLLVMTag_DW_structure_type(); - struct_type->llvm_di_type = ZigLLVMCreateReplaceableCompositeType(g->dbuilder, - dwarf_kind, buf_ptr(&struct_type->name), - di_scope, di_file, line); - - struct_type->data.structure.resolve_status = ResolveStatusLLVMFwdDecl; - if (ResolveStatusLLVMFwdDecl >= wanted_resolve_status) { - struct_type->data.structure.llvm_full_type_queue_index = g->type_resolve_stack.length; - g->type_resolve_stack.append(struct_type); - return; - } else { - struct_type->data.structure.llvm_full_type_queue_index = SIZE_MAX; - } - } - - size_t field_count = struct_type->data.structure.src_field_count; - // Every field could potentially have a generated padding field after it. - LLVMTypeRef *element_types = heap::c_allocator.allocate(field_count * 2); - - bool packed = (struct_type->data.structure.layout == ContainerLayoutPacked); - size_t packed_bits_offset = 0; - size_t first_packed_bits_offset_misalign = SIZE_MAX; - size_t debug_field_count = 0; - - // trigger all the recursive get_llvm_type calls - for (size_t i = 0; i < field_count; i += 1) { - TypeStructField *field = struct_type->data.structure.fields[i]; - ZigType *field_type = field->type_entry; - if (!type_has_bits(g, field_type)) - continue; - (void)get_llvm_type(g, field_type); - if (struct_type->data.structure.resolve_status >= wanted_resolve_status) return; - } - - size_t gen_field_index = 0; - - // Calculate what LLVM thinks the ABI align of the struct will be. We do this to avoid - // inserting padding bytes where LLVM would do it automatically. - size_t llvm_struct_abi_align = 0; - for (size_t i = 0; i < field_count; i += 1) { - TypeStructField *field = struct_type->data.structure.fields[i]; - ZigType *field_type = field->type_entry; - if (field->is_comptime || !type_has_bits(g, field_type)) - continue; - LLVMTypeRef field_llvm_type = get_llvm_type(g, field_type); - size_t llvm_field_abi_align = LLVMABIAlignmentOfType(g->target_data_ref, field_llvm_type); - llvm_struct_abi_align = max(llvm_struct_abi_align, llvm_field_abi_align); - } - - ZigType* last_packed_field_type = nullptr; - - for (size_t i = 0; i < field_count; i += 1) { - TypeStructField *field = struct_type->data.structure.fields[i]; - ZigType *field_type = field->type_entry; - - if (field->is_comptime || !type_has_bits(g, field_type)) { - field->gen_index = SIZE_MAX; - continue; - } - - if (packed) { - last_packed_field_type = field_type; - size_t field_size_in_bits = type_size_bits(g, field_type); - size_t next_packed_bits_offset = packed_bits_offset + field_size_in_bits; - - if (first_packed_bits_offset_misalign != SIZE_MAX) { - // this field is not byte-aligned; it is part of the previous field with a bit offset - - size_t full_bit_count = next_packed_bits_offset - first_packed_bits_offset_misalign; - size_t full_abi_size = get_abi_size_bytes(full_bit_count, g->pointer_size_bytes); - if (full_abi_size * 8 == full_bit_count) { - // next field recovers ABI alignment - element_types[gen_field_index] = get_llvm_type_of_n_bytes(full_abi_size); - gen_field_index += 1; - first_packed_bits_offset_misalign = SIZE_MAX; - } - } else if (get_abi_size_bytes(field_type->size_in_bits, g->pointer_size_bytes) * 8 != field_size_in_bits) { - first_packed_bits_offset_misalign = packed_bits_offset; - } else { - // This is a byte-aligned field (both start and end) in a packed struct. - element_types[gen_field_index] = get_llvm_type(g, field_type); - assert(get_abi_size_bytes(field_type->size_in_bits, g->pointer_size_bytes) == - LLVMStoreSizeOfType(g->target_data_ref, element_types[gen_field_index])); - gen_field_index += 1; - } - packed_bits_offset = next_packed_bits_offset; - } else { - LLVMTypeRef llvm_type; - if (i == 0 && async_frame_type != nullptr) { - assert(async_frame_type->id == ZigTypeIdFnFrame); - assert(field_type->id == ZigTypeIdFn); - resolve_llvm_types_fn(g, async_frame_type->data.frame.fn); - - const unsigned addrspace = ZigLLVMDataLayoutGetProgramAddressSpace(g->target_data_ref); - llvm_type = LLVMPointerType(async_frame_type->data.frame.fn->raw_type_ref, addrspace); - } else { - llvm_type = get_llvm_type(g, field_type); - } - element_types[gen_field_index] = llvm_type; - field->gen_index = gen_field_index; - gen_field_index += 1; - - // find the next non-zero-byte field for offset calculations - size_t next_src_field_index = i + 1; - for (; next_src_field_index < field_count; next_src_field_index += 1) { - if (type_has_bits(g, struct_type->data.structure.fields[next_src_field_index]->type_entry)) - break; - } - size_t next_abi_align; - if (next_src_field_index == field_count) { - next_abi_align = struct_type->abi_align; - } else { - if (struct_type->data.structure.fields[next_src_field_index]->align == 0) { - next_abi_align = struct_type->data.structure.fields[next_src_field_index]->type_entry->abi_align; - } else { - next_abi_align = struct_type->data.structure.fields[next_src_field_index]->align; - } - } - size_t llvm_next_abi_align = (next_src_field_index == field_count) ? - llvm_struct_abi_align : - LLVMABIAlignmentOfType(g->target_data_ref, - get_llvm_type(g, struct_type->data.structure.fields[next_src_field_index]->type_entry)); - - size_t next_offset = next_field_offset(field->offset, struct_type->abi_align, - field_type->abi_size, next_abi_align); - size_t llvm_next_offset = next_field_offset(field->offset, llvm_struct_abi_align, - LLVMABISizeOfType(g->target_data_ref, llvm_type), llvm_next_abi_align); - - assert(next_offset >= llvm_next_offset); - if (next_offset > llvm_next_offset) { - size_t pad_bytes = next_offset - (field->offset + LLVMABISizeOfType(g->target_data_ref, llvm_type)); - if (pad_bytes != 0) { - LLVMTypeRef pad_llvm_type = LLVMArrayType(LLVMInt8Type(), pad_bytes); - element_types[gen_field_index] = pad_llvm_type; - gen_field_index += 1; - } - } - } - debug_field_count += 1; - } - if (!packed) { - struct_type->data.structure.gen_field_count = gen_field_index; - } - - if (first_packed_bits_offset_misalign != SIZE_MAX) { - size_t full_bit_count = packed_bits_offset - first_packed_bits_offset_misalign; - size_t full_abi_size = get_abi_size_bytes(full_bit_count, 1); - if (last_packed_field_type->size_in_bits == full_bit_count && last_packed_field_type->id != ZigTypeIdInt && last_packed_field_type->id != ZigTypeIdEnum) { - // If there is only one field that is misaligned and it is a custom type just use it - element_types[gen_field_index] = get_llvm_type(g, last_packed_field_type); - assert(full_abi_size == LLVMStoreSizeOfType(g->target_data_ref, element_types[gen_field_index])); - } else { - // Otherwise represent it as array of proper number of bytes in LLVM - element_types[gen_field_index] = get_llvm_type_of_n_bytes(full_abi_size); - } - gen_field_index += 1; - } - - if (type_has_bits(g, struct_type)) { - assert(struct_type->data.structure.gen_field_count == gen_field_index); - LLVMStructSetBody(struct_type->llvm_type, element_types, - (unsigned)struct_type->data.structure.gen_field_count, packed); - } - - ZigLLVMDIType **di_element_types = heap::c_allocator.allocate(debug_field_count); - size_t debug_field_index = 0; - for (size_t i = 0; i < field_count; i += 1) { - TypeStructField *field = struct_type->data.structure.fields[i]; - //fprintf(stderr, "%s at gen index %zu\n", buf_ptr(field->name), field->gen_index); - - size_t gen_field_index = field->gen_index; - if (gen_field_index == SIZE_MAX) { - continue; - } - - ZigType *field_type = field->type_entry; - - // if the field is a function, actually the debug info should be a pointer. - ZigLLVMDIType *field_di_type; - if (field_type->id == ZigTypeIdFn) { - ZigType *field_ptr_type = get_pointer_to_type(g, field_type, true); - uint64_t debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, get_llvm_type(g, field_ptr_type)); - uint64_t debug_align_in_bits = 8*LLVMABISizeOfType(g->target_data_ref, get_llvm_type(g, field_ptr_type)); - field_di_type = ZigLLVMCreateDebugPointerType(g->dbuilder, get_llvm_di_type(g, field_type), - debug_size_in_bits, debug_align_in_bits, buf_ptr(&field_ptr_type->name)); - } else { - field_di_type = get_llvm_di_type(g, field_type); - } - - uint64_t debug_size_in_bits; - uint64_t debug_align_in_bits; - uint64_t debug_offset_in_bits; - if (packed) { - debug_size_in_bits = field->type_entry->size_in_bits; - debug_align_in_bits = 8 * field->type_entry->abi_align; - debug_offset_in_bits = 8 * field->offset + field->bit_offset_in_host; - } else { - debug_size_in_bits = 8 * get_store_size_bytes(field_type->size_in_bits); - debug_align_in_bits = 8 * field_type->abi_align; - debug_offset_in_bits = 8 * field->offset; - } - unsigned line; - if (decl_node != nullptr) { - AstNode *field_node = field->decl_node; - line = node_line_onebased(field_node); - } else { - line = 0; - } - di_element_types[debug_field_index] = ZigLLVMCreateDebugMemberType(g->dbuilder, - ZigLLVMTypeToScope(struct_type->llvm_di_type), buf_ptr(field->name), - di_file, line, - debug_size_in_bits, - debug_align_in_bits, - debug_offset_in_bits, - ZigLLVM_DIFlags_Zero, field_di_type); - assert(di_element_types[debug_field_index]); - debug_field_index += 1; - } - - uint64_t debug_size_in_bits = 8*get_store_size_bytes(struct_type->size_in_bits); - uint64_t debug_align_in_bits = 8*struct_type->abi_align; - ZigLLVMDIType *replacement_di_type = ZigLLVMCreateDebugStructType(g->dbuilder, - di_scope, - buf_ptr(&struct_type->name), - di_file, line, - debug_size_in_bits, - debug_align_in_bits, - ZigLLVM_DIFlags_Zero, - nullptr, di_element_types, (int)debug_field_count, 0, nullptr, ""); - - ZigLLVMReplaceTemporary(g->dbuilder, struct_type->llvm_di_type, replacement_di_type); - struct_type->llvm_di_type = replacement_di_type; - struct_type->data.structure.resolve_status = ResolveStatusLLVMFull; - if (struct_type->data.structure.llvm_full_type_queue_index != SIZE_MAX) { - ZigType *last = g->type_resolve_stack.last(); - assert(last->id == ZigTypeIdStruct); - last->data.structure.llvm_full_type_queue_index = struct_type->data.structure.llvm_full_type_queue_index; - g->type_resolve_stack.swap_remove(struct_type->data.structure.llvm_full_type_queue_index); - struct_type->data.structure.llvm_full_type_queue_index = SIZE_MAX; - } - - if (struct_type->abi_size <= 16 && - (struct_type->data.structure.layout == ContainerLayoutExtern || - struct_type->data.structure.layout == ContainerLayoutPacked)) - { - resolve_llvm_c_abi_type(g, struct_type); - } -} - -// This is to be used instead of void for debug info types, to avoid tripping -// Assertion `!isa(Scope) && "shouldn't make a namespace scope for a type"' -// when targeting CodeView (Windows). -static ZigLLVMDIType *make_empty_namespace_llvm_di_type(CodeGen *g, ZigType *import, const char *name, - AstNode *decl_node) -{ - uint64_t debug_size_in_bits = 0; - uint64_t debug_align_in_bits = 0; - ZigLLVMDIType **di_element_types = nullptr; - size_t debug_field_count = 0; - return ZigLLVMCreateDebugStructType(g->dbuilder, - ZigLLVMFileToScope(import->data.structure.root_struct->di_file), - name, - import->data.structure.root_struct->di_file, node_line_onebased(decl_node), - debug_size_in_bits, - debug_align_in_bits, - ZigLLVM_DIFlags_Zero, - nullptr, di_element_types, (int)debug_field_count, 0, nullptr, ""); -} - -static void resolve_llvm_types_enum(CodeGen *g, ZigType *enum_type, ResolveStatus wanted_resolve_status) { - assert(enum_type->data.enumeration.resolve_status >= ResolveStatusSizeKnown); - if (enum_type->data.enumeration.resolve_status >= wanted_resolve_status) return; - - Scope *scope = &enum_type->data.enumeration.decls_scope->base; - ZigType *import = get_scope_import(scope); - AstNode *decl_node = enum_type->data.enumeration.decl_node; - - if (!type_has_bits(g, enum_type)) { - enum_type->llvm_type = g->builtin_types.entry_void->llvm_type; - enum_type->llvm_di_type = make_empty_namespace_llvm_di_type(g, import, buf_ptr(&enum_type->name), - decl_node); - enum_type->data.enumeration.resolve_status = ResolveStatusLLVMFull; - return; - } - - uint32_t field_count = enum_type->data.enumeration.src_field_count; - - assert(field_count == 0 || enum_type->data.enumeration.fields != nullptr); - ZigLLVMDIEnumerator **di_enumerators = heap::c_allocator.allocate(field_count); - - for (uint32_t i = 0; i < field_count; i += 1) { - TypeEnumField *enum_field = &enum_type->data.enumeration.fields[i]; - - // https://github.com/ziglang/zig/issues/645 - di_enumerators[i] = ZigLLVMCreateDebugEnumerator(g->dbuilder, buf_ptr(enum_field->name), - bigint_as_signed(&enum_field->value), false); - } - - ZigType *tag_int_type = enum_type->data.enumeration.tag_int_type; - enum_type->llvm_type = get_llvm_type(g, tag_int_type); - - // create debug type for tag - uint64_t tag_debug_size_in_bits = 8*tag_int_type->abi_size; - uint64_t tag_debug_align_in_bits = 8*tag_int_type->abi_align; - ZigLLVMDIType *tag_di_type = ZigLLVMCreateDebugEnumerationType(g->dbuilder, - ZigLLVMFileToScope(import->data.structure.root_struct->di_file), buf_ptr(&enum_type->name), - import->data.structure.root_struct->di_file, node_line_onebased(decl_node), - tag_debug_size_in_bits, - tag_debug_align_in_bits, - di_enumerators, field_count, - get_llvm_di_type(g, tag_int_type), ""); - - enum_type->llvm_di_type = tag_di_type; - enum_type->data.enumeration.resolve_status = ResolveStatusLLVMFull; -} - -static void resolve_llvm_types_union(CodeGen *g, ZigType *union_type, ResolveStatus wanted_resolve_status) { - if (union_type->data.unionation.resolve_status >= wanted_resolve_status) return; - - bool packed = (union_type->data.unionation.layout == ContainerLayoutPacked); - Scope *scope = &union_type->data.unionation.decls_scope->base; - ZigType *import = get_scope_import(scope); - - TypeUnionField *most_aligned_union_member = union_type->data.unionation.most_aligned_union_member; - ZigType *tag_type = union_type->data.unionation.tag_type; - uint32_t gen_field_count = union_type->data.unionation.gen_field_count; - if (gen_field_count == 0) { - if (tag_type == nullptr) { - union_type->llvm_type = g->builtin_types.entry_void->llvm_type; - union_type->llvm_di_type = make_empty_namespace_llvm_di_type(g, import, buf_ptr(&union_type->name), - union_type->data.unionation.decl_node); - } else { - union_type->llvm_type = get_llvm_type(g, tag_type); - union_type->llvm_di_type = get_llvm_di_type(g, tag_type); - } - - union_type->data.unionation.gen_union_index = SIZE_MAX; - union_type->data.unionation.gen_tag_index = SIZE_MAX; - union_type->data.unionation.resolve_status = ResolveStatusLLVMFull; - return; - } - - AstNode *decl_node = union_type->data.unionation.decl_node; - - if (union_type->data.unionation.resolve_status < ResolveStatusLLVMFwdDecl) { - union_type->llvm_type = LLVMStructCreateNamed(LLVMGetGlobalContext(), buf_ptr(&union_type->name)); - unsigned line = decl_node ? node_line_onebased(decl_node) : 0; - unsigned dwarf_kind = ZigLLVMTag_DW_structure_type(); - union_type->llvm_di_type = ZigLLVMCreateReplaceableCompositeType(g->dbuilder, - dwarf_kind, buf_ptr(&union_type->name), - ZigLLVMFileToScope(import->data.structure.root_struct->di_file), - import->data.structure.root_struct->di_file, line); - - union_type->data.unionation.resolve_status = ResolveStatusLLVMFwdDecl; - if (ResolveStatusLLVMFwdDecl >= wanted_resolve_status) return; - } - - ZigLLVMDIType **union_inner_di_types = heap::c_allocator.allocate(gen_field_count); - uint32_t field_count = union_type->data.unionation.src_field_count; - for (uint32_t i = 0; i < field_count; i += 1) { - TypeUnionField *union_field = &union_type->data.unionation.fields[i]; - if (!type_has_bits(g, union_field->type_entry)) - continue; - - ZigLLVMDIType *field_di_type = get_llvm_di_type(g, union_field->type_entry); - if (union_type->data.unionation.resolve_status >= wanted_resolve_status) return; - - uint64_t store_size_in_bits = union_field->type_entry->size_in_bits; - uint64_t abi_align_in_bits = 8*union_field->type_entry->abi_align; - AstNode *field_node = union_field->decl_node; - union_inner_di_types[union_field->gen_index] = ZigLLVMCreateDebugMemberType(g->dbuilder, - ZigLLVMTypeToScope(union_type->llvm_di_type), buf_ptr(union_field->enum_field->name), - import->data.structure.root_struct->di_file, node_line_onebased(field_node), - store_size_in_bits, - abi_align_in_bits, - 0, - ZigLLVM_DIFlags_Zero, field_di_type); - - } - - if (tag_type == nullptr || !type_has_bits(g, tag_type)) { - assert(most_aligned_union_member != nullptr); - - size_t padding_bytes = union_type->data.unionation.union_abi_size - most_aligned_union_member->type_entry->abi_size; - if (padding_bytes > 0) { - ZigType *u8_type = get_int_type(g, false, 8); - ZigType *padding_array = get_array_type(g, u8_type, padding_bytes, nullptr); - LLVMTypeRef union_element_types[] = { - most_aligned_union_member->type_entry->llvm_type, - get_llvm_type(g, padding_array), - }; - LLVMStructSetBody(union_type->llvm_type, union_element_types, 2, packed); - } else { - LLVMStructSetBody(union_type->llvm_type, &most_aligned_union_member->type_entry->llvm_type, 1, packed); - } - union_type->data.unionation.union_llvm_type = union_type->llvm_type; - union_type->data.unionation.gen_tag_index = SIZE_MAX; - union_type->data.unionation.gen_union_index = SIZE_MAX; - - // create debug type for union - ZigLLVMDIType *replacement_di_type = ZigLLVMCreateDebugUnionType(g->dbuilder, - ZigLLVMFileToScope(import->data.structure.root_struct->di_file), buf_ptr(&union_type->name), - import->data.structure.root_struct->di_file, node_line_onebased(decl_node), - union_type->data.unionation.union_abi_size * 8, - most_aligned_union_member->align * 8, - ZigLLVM_DIFlags_Zero, union_inner_di_types, - gen_field_count, 0, ""); - - ZigLLVMReplaceTemporary(g->dbuilder, union_type->llvm_di_type, replacement_di_type); - union_type->llvm_di_type = replacement_di_type; - union_type->data.unionation.resolve_status = ResolveStatusLLVMFull; - return; - } - - LLVMTypeRef union_type_ref; - size_t padding_bytes = union_type->data.unionation.union_abi_size - most_aligned_union_member->type_entry->abi_size; - if (padding_bytes == 0) { - union_type_ref = get_llvm_type(g, most_aligned_union_member->type_entry); - } else { - ZigType *u8_type = get_int_type(g, false, 8); - ZigType *padding_array = get_array_type(g, u8_type, padding_bytes, nullptr); - LLVMTypeRef union_element_types[] = { - get_llvm_type(g, most_aligned_union_member->type_entry), - get_llvm_type(g, padding_array), - }; - union_type_ref = LLVMStructType(union_element_types, 2, false); - } - union_type->data.unionation.union_llvm_type = union_type_ref; - - LLVMTypeRef root_struct_element_types[2]; - root_struct_element_types[union_type->data.unionation.gen_tag_index] = get_llvm_type(g, tag_type); - root_struct_element_types[union_type->data.unionation.gen_union_index] = union_type_ref; - LLVMStructSetBody(union_type->llvm_type, root_struct_element_types, 2, packed); - - // create debug type for union - ZigLLVMDIType *union_di_type = ZigLLVMCreateDebugUnionType(g->dbuilder, - ZigLLVMTypeToScope(union_type->llvm_di_type), "AnonUnion", - import->data.structure.root_struct->di_file, node_line_onebased(decl_node), - most_aligned_union_member->type_entry->size_in_bits, 8*most_aligned_union_member->align, - ZigLLVM_DIFlags_Zero, union_inner_di_types, gen_field_count, 0, ""); - - uint64_t union_offset_in_bits = 8*LLVMOffsetOfElement(g->target_data_ref, union_type->llvm_type, - union_type->data.unionation.gen_union_index); - uint64_t tag_offset_in_bits = 8*LLVMOffsetOfElement(g->target_data_ref, union_type->llvm_type, - union_type->data.unionation.gen_tag_index); - - ZigLLVMDIType *union_member_di_type = ZigLLVMCreateDebugMemberType(g->dbuilder, - ZigLLVMTypeToScope(union_type->llvm_di_type), "payload", - import->data.structure.root_struct->di_file, node_line_onebased(decl_node), - most_aligned_union_member->type_entry->size_in_bits, - 8*most_aligned_union_member->align, - union_offset_in_bits, - ZigLLVM_DIFlags_Zero, union_di_type); - - uint64_t tag_debug_size_in_bits = tag_type->size_in_bits; - uint64_t tag_debug_align_in_bits = 8*tag_type->abi_align; - - ZigLLVMDIType *tag_member_di_type = ZigLLVMCreateDebugMemberType(g->dbuilder, - ZigLLVMTypeToScope(union_type->llvm_di_type), "tag", - import->data.structure.root_struct->di_file, node_line_onebased(decl_node), - tag_debug_size_in_bits, - tag_debug_align_in_bits, - tag_offset_in_bits, - ZigLLVM_DIFlags_Zero, get_llvm_di_type(g, tag_type)); - - ZigLLVMDIType *di_root_members[2]; - di_root_members[union_type->data.unionation.gen_tag_index] = tag_member_di_type; - di_root_members[union_type->data.unionation.gen_union_index] = union_member_di_type; - - uint64_t debug_size_in_bits = union_type->size_in_bits; - uint64_t debug_align_in_bits = 8*union_type->abi_align; - ZigLLVMDIType *replacement_di_type = ZigLLVMCreateDebugStructType(g->dbuilder, - ZigLLVMFileToScope(import->data.structure.root_struct->di_file), - buf_ptr(&union_type->name), - import->data.structure.root_struct->di_file, node_line_onebased(decl_node), - debug_size_in_bits, - debug_align_in_bits, - ZigLLVM_DIFlags_Zero, nullptr, di_root_members, 2, 0, nullptr, ""); - - ZigLLVMReplaceTemporary(g->dbuilder, union_type->llvm_di_type, replacement_di_type); - union_type->llvm_di_type = replacement_di_type; - union_type->data.unionation.resolve_status = ResolveStatusLLVMFull; -} - -static void resolve_llvm_types_pointer(CodeGen *g, ZigType *type, ResolveStatus wanted_resolve_status) { - if (type->llvm_di_type != nullptr) return; - - if (resolve_pointer_zero_bits(g, type) != ErrorNone) - zig_unreachable(); - - if (!type_has_bits(g, type)) { - type->llvm_type = g->builtin_types.entry_void->llvm_type; - type->llvm_di_type = g->builtin_types.entry_void->llvm_di_type; - return; - } - - ZigType *elem_type = type->data.pointer.child_type; - - if (type->data.pointer.is_const || type->data.pointer.is_volatile || - type->data.pointer.explicit_alignment != 0 || type->data.pointer.ptr_len != PtrLenSingle || - type->data.pointer.bit_offset_in_host != 0 || type->data.pointer.allow_zero || - type->data.pointer.vector_index != VECTOR_INDEX_NONE || type->data.pointer.sentinel != nullptr) - { - assertNoError(type_resolve(g, elem_type, ResolveStatusLLVMFwdDecl)); - ZigType *peer_type; - if (type->data.pointer.vector_index == VECTOR_INDEX_NONE) { - peer_type = get_pointer_to_type_extra2(g, elem_type, false, false, - PtrLenSingle, 0, 0, type->data.pointer.host_int_bytes, false, - VECTOR_INDEX_NONE, nullptr, nullptr); - } else { - uint32_t host_vec_len = type->data.pointer.host_int_bytes; - ZigType *host_vec_type = get_vector_type(g, host_vec_len, elem_type); - peer_type = get_pointer_to_type_extra2(g, host_vec_type, false, false, - PtrLenSingle, 0, 0, 0, false, VECTOR_INDEX_NONE, nullptr, nullptr); - } - type->llvm_type = get_llvm_type(g, peer_type); - type->llvm_di_type = get_llvm_di_type(g, peer_type); - assertNoError(type_resolve(g, elem_type, wanted_resolve_status)); - return; - } - - if (type->data.pointer.host_int_bytes == 0) { - assertNoError(type_resolve(g, elem_type, ResolveStatusLLVMFwdDecl)); - type->llvm_type = LLVMPointerType(elem_type->llvm_type, 0); - uint64_t debug_size_in_bits = 8*get_store_size_bytes(type->size_in_bits); - uint64_t debug_align_in_bits = 8*type->abi_align; - type->llvm_di_type = ZigLLVMCreateDebugPointerType(g->dbuilder, elem_type->llvm_di_type, - debug_size_in_bits, debug_align_in_bits, buf_ptr(&type->name)); - assertNoError(type_resolve(g, elem_type, wanted_resolve_status)); - } else { - ZigType *host_int_type = get_int_type(g, false, type->data.pointer.host_int_bytes * 8); - LLVMTypeRef host_int_llvm_type = get_llvm_type(g, host_int_type); - type->llvm_type = LLVMPointerType(host_int_llvm_type, 0); - uint64_t debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, host_int_llvm_type); - uint64_t debug_align_in_bits = 8*LLVMABIAlignmentOfType(g->target_data_ref, host_int_llvm_type); - type->llvm_di_type = ZigLLVMCreateDebugPointerType(g->dbuilder, get_llvm_di_type(g, host_int_type), - debug_size_in_bits, debug_align_in_bits, buf_ptr(&type->name)); - } -} - -static void resolve_llvm_types_integer(CodeGen *g, ZigType *type) { - if (type->llvm_di_type != nullptr) return; - - if (!type_has_bits(g, type)) { - type->llvm_type = g->builtin_types.entry_void->llvm_type; - type->llvm_di_type = g->builtin_types.entry_void->llvm_di_type; - return; - } - - unsigned dwarf_tag; - if (type->data.integral.is_signed) { - if (type->size_in_bits == 8) { - dwarf_tag = ZigLLVMEncoding_DW_ATE_signed_char(); - } else { - dwarf_tag = ZigLLVMEncoding_DW_ATE_signed(); - } - } else { - if (type->size_in_bits == 8) { - dwarf_tag = ZigLLVMEncoding_DW_ATE_unsigned_char(); - } else { - dwarf_tag = ZigLLVMEncoding_DW_ATE_unsigned(); - } - } - - type->llvm_di_type = ZigLLVMCreateDebugBasicType(g->dbuilder, buf_ptr(&type->name), - type->size_in_bits, dwarf_tag); - type->llvm_type = LLVMIntType(type->size_in_bits); -} - -static void resolve_llvm_types_optional(CodeGen *g, ZigType *type, ResolveStatus wanted_resolve_status) { - assert(type->id == ZigTypeIdOptional); - assert(type->data.maybe.resolve_status != ResolveStatusInvalid); - assert(type->data.maybe.resolve_status >= ResolveStatusSizeKnown); - if (type->data.maybe.resolve_status >= wanted_resolve_status) return; - - LLVMTypeRef bool_llvm_type = get_llvm_type(g, g->builtin_types.entry_bool); - ZigLLVMDIType *bool_llvm_di_type = get_llvm_di_type(g, g->builtin_types.entry_bool); - - ZigType *child_type = type->data.maybe.child_type; - if (!type_has_bits(g, child_type)) { - type->llvm_type = bool_llvm_type; - type->llvm_di_type = bool_llvm_di_type; - type->data.maybe.resolve_status = ResolveStatusLLVMFull; - return; - } - - if (type_is_nonnull_ptr(g, child_type) || child_type->id == ZigTypeIdErrorSet) { - type->llvm_type = get_llvm_type(g, child_type); - type->llvm_di_type = get_llvm_di_type(g, child_type); - type->data.maybe.resolve_status = ResolveStatusLLVMFull; - return; - } - - ZigLLVMDIScope *compile_unit_scope = ZigLLVMCompileUnitToScope(g->compile_unit); - ZigLLVMDIFile *di_file = nullptr; - unsigned line = 0; - - if (type->data.maybe.resolve_status < ResolveStatusLLVMFwdDecl) { - type->llvm_type = LLVMStructCreateNamed(LLVMGetGlobalContext(), buf_ptr(&type->name)); - unsigned dwarf_kind = ZigLLVMTag_DW_structure_type(); - type->llvm_di_type = ZigLLVMCreateReplaceableCompositeType(g->dbuilder, - dwarf_kind, buf_ptr(&type->name), - compile_unit_scope, di_file, line); - - type->data.maybe.resolve_status = ResolveStatusLLVMFwdDecl; - if (ResolveStatusLLVMFwdDecl >= wanted_resolve_status) return; - } - - ZigLLVMDIType *child_llvm_di_type = get_llvm_di_type(g, child_type); - if (type->data.maybe.resolve_status >= wanted_resolve_status) return; - - LLVMTypeRef elem_types[] = { - get_llvm_type(g, child_type), - LLVMInt1Type(), - }; - LLVMStructSetBody(type->llvm_type, elem_types, 2, false); - - uint64_t val_offset_in_bits = 8*LLVMOffsetOfElement(g->target_data_ref, type->llvm_type, maybe_child_index); - uint64_t maybe_offset_in_bits = 8*LLVMOffsetOfElement(g->target_data_ref, type->llvm_type, maybe_null_index); - - ZigLLVMDIType *di_element_types[2]; - di_element_types[maybe_child_index] = - ZigLLVMCreateDebugMemberType(g->dbuilder, ZigLLVMTypeToScope(type->llvm_di_type), - "val", di_file, line, - 8 * child_type->abi_size, - 8 * child_type->abi_align, - val_offset_in_bits, - ZigLLVM_DIFlags_Zero, child_llvm_di_type); - di_element_types[maybe_null_index] = - ZigLLVMCreateDebugMemberType(g->dbuilder, ZigLLVMTypeToScope(type->llvm_di_type), - "maybe", di_file, line, - 8*g->builtin_types.entry_bool->abi_size, - 8*g->builtin_types.entry_bool->abi_align, - maybe_offset_in_bits, - ZigLLVM_DIFlags_Zero, bool_llvm_di_type); - ZigLLVMDIType *replacement_di_type = ZigLLVMCreateDebugStructType(g->dbuilder, - compile_unit_scope, - buf_ptr(&type->name), - di_file, line, 8 * type->abi_size, 8 * type->abi_align, ZigLLVM_DIFlags_Zero, - nullptr, di_element_types, 2, 0, nullptr, ""); - - ZigLLVMReplaceTemporary(g->dbuilder, type->llvm_di_type, replacement_di_type); - type->llvm_di_type = replacement_di_type; - type->data.maybe.resolve_status = ResolveStatusLLVMFull; -} - -static void resolve_llvm_types_error_union(CodeGen *g, ZigType *type) { - if (type->llvm_di_type != nullptr) return; - - ZigType *payload_type = type->data.error_union.payload_type; - ZigType *err_set_type = type->data.error_union.err_set_type; - - if (!type_has_bits(g, payload_type)) { - assert(type_has_bits(g, err_set_type)); - type->llvm_type = get_llvm_type(g, err_set_type); - type->llvm_di_type = get_llvm_di_type(g, err_set_type); - } else if (!type_has_bits(g, err_set_type)) { - type->llvm_type = get_llvm_type(g, payload_type); - type->llvm_di_type = get_llvm_di_type(g, payload_type); - } else { - LLVMTypeRef err_set_llvm_type = get_llvm_type(g, err_set_type); - LLVMTypeRef payload_llvm_type = get_llvm_type(g, payload_type); - LLVMTypeRef elem_types[3]; - elem_types[err_union_err_index] = err_set_llvm_type; - elem_types[err_union_payload_index] = payload_llvm_type; - - type->llvm_type = LLVMStructType(elem_types, 2, false); - if (LLVMABISizeOfType(g->target_data_ref, type->llvm_type) != type->abi_size) { - // we need to do our own padding - type->data.error_union.pad_llvm_type = LLVMArrayType(LLVMInt8Type(), type->data.error_union.pad_bytes); - elem_types[2] = type->data.error_union.pad_llvm_type; - type->llvm_type = LLVMStructType(elem_types, 3, false); - } - - ZigLLVMDIScope *compile_unit_scope = ZigLLVMCompileUnitToScope(g->compile_unit); - ZigLLVMDIFile *di_file = nullptr; - unsigned line = 0; - type->llvm_di_type = ZigLLVMCreateReplaceableCompositeType(g->dbuilder, - ZigLLVMTag_DW_structure_type(), buf_ptr(&type->name), - compile_unit_scope, di_file, line); - - uint64_t tag_debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, err_set_llvm_type); - uint64_t tag_debug_align_in_bits = 8*LLVMABISizeOfType(g->target_data_ref, err_set_llvm_type); - uint64_t tag_offset_in_bits = 8*LLVMOffsetOfElement(g->target_data_ref, type->llvm_type, err_union_err_index); - - uint64_t value_debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, payload_llvm_type); - uint64_t value_debug_align_in_bits = 8*LLVMABISizeOfType(g->target_data_ref, payload_llvm_type); - uint64_t value_offset_in_bits = 8*LLVMOffsetOfElement(g->target_data_ref, type->llvm_type, - err_union_payload_index); - - uint64_t debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, type->llvm_type); - uint64_t debug_align_in_bits = 8*LLVMABISizeOfType(g->target_data_ref, type->llvm_type); - - ZigLLVMDIType *di_element_types[2]; - di_element_types[err_union_err_index] = ZigLLVMCreateDebugMemberType(g->dbuilder, - ZigLLVMTypeToScope(type->llvm_di_type), - "tag", di_file, line, - tag_debug_size_in_bits, - tag_debug_align_in_bits, - tag_offset_in_bits, - ZigLLVM_DIFlags_Zero, get_llvm_di_type(g, err_set_type)); - di_element_types[err_union_payload_index] = ZigLLVMCreateDebugMemberType(g->dbuilder, - ZigLLVMTypeToScope(type->llvm_di_type), - "value", di_file, line, - value_debug_size_in_bits, - value_debug_align_in_bits, - value_offset_in_bits, - ZigLLVM_DIFlags_Zero, get_llvm_di_type(g, payload_type)); - - ZigLLVMDIType *replacement_di_type = ZigLLVMCreateDebugStructType(g->dbuilder, - compile_unit_scope, - buf_ptr(&type->name), - di_file, line, - debug_size_in_bits, - debug_align_in_bits, - ZigLLVM_DIFlags_Zero, - nullptr, di_element_types, 2, 0, nullptr, ""); - - ZigLLVMReplaceTemporary(g->dbuilder, type->llvm_di_type, replacement_di_type); - type->llvm_di_type = replacement_di_type; - } -} - -static void resolve_llvm_types_array(CodeGen *g, ZigType *type) { - if (type->llvm_di_type != nullptr) return; - - if (!type_has_bits(g, type)) { - type->llvm_type = g->builtin_types.entry_void->llvm_type; - type->llvm_di_type = g->builtin_types.entry_void->llvm_di_type; - return; - } - - ZigType *elem_type = type->data.array.child_type; - - uint64_t extra_len_from_sentinel = (type->data.array.sentinel != nullptr) ? 1 : 0; - uint64_t full_len = type->data.array.len + extra_len_from_sentinel; - // TODO https://github.com/ziglang/zig/issues/1424 - type->llvm_type = LLVMArrayType(get_llvm_type(g, elem_type), (unsigned)full_len); - - uint64_t debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, type->llvm_type); - uint64_t debug_align_in_bits = 8*LLVMABISizeOfType(g->target_data_ref, type->llvm_type); - - type->llvm_di_type = ZigLLVMCreateDebugArrayType(g->dbuilder, debug_size_in_bits, - debug_align_in_bits, get_llvm_di_type(g, elem_type), (int)full_len); -} - -static void resolve_llvm_types_fn_type(CodeGen *g, ZigType *fn_type) { - if (fn_type->llvm_di_type != nullptr) return; - - FnTypeId *fn_type_id = &fn_type->data.fn.fn_type_id; - bool first_arg_return = want_first_arg_sret(g, fn_type_id); - bool is_async = fn_type_id->cc == CallingConventionAsync; - bool is_c_abi = !calling_convention_allows_zig_types(fn_type_id->cc); - bool prefix_arg_error_return_trace = g->have_err_ret_tracing && fn_type_can_fail(fn_type_id); - // +1 for maybe making the first argument the return value - // +1 for maybe first argument the error return trace - // +2 for maybe arguments async allocator and error code pointer - ZigList gen_param_types = {}; - // +1 because 0 is the return type and - // +1 for maybe making first arg ret val and - // +1 for maybe first argument the error return trace - // +2 for maybe arguments async allocator and error code pointer - ZigList param_di_types = {}; - ZigType *gen_return_type; - if (is_async) { - gen_return_type = g->builtin_types.entry_void; - param_di_types.append(nullptr); - } else if (!type_has_bits(g, fn_type_id->return_type)) { - gen_return_type = g->builtin_types.entry_void; - param_di_types.append(nullptr); - } else if (first_arg_return) { - gen_return_type = g->builtin_types.entry_void; - param_di_types.append(nullptr); - ZigType *gen_type = get_pointer_to_type(g, fn_type_id->return_type, false); - gen_param_types.append(get_llvm_type(g, gen_type)); - param_di_types.append(get_llvm_di_type(g, gen_type)); - } else { - gen_return_type = fn_type_id->return_type; - param_di_types.append(get_llvm_di_type(g, gen_return_type)); - } - fn_type->data.fn.gen_return_type = gen_return_type; - - if (prefix_arg_error_return_trace && !is_async) { - ZigType *gen_type = get_pointer_to_type(g, get_stack_trace_type(g), false); - gen_param_types.append(get_llvm_type(g, gen_type)); - param_di_types.append(get_llvm_di_type(g, gen_type)); - } - if (is_async) { - fn_type->data.fn.gen_param_info = heap::c_allocator.allocate(2); - - ZigType *frame_type = get_any_frame_type(g, fn_type_id->return_type); - gen_param_types.append(get_llvm_type(g, frame_type)); - param_di_types.append(get_llvm_di_type(g, frame_type)); - - fn_type->data.fn.gen_param_info[0].src_index = 0; - fn_type->data.fn.gen_param_info[0].gen_index = 0; - fn_type->data.fn.gen_param_info[0].type = frame_type; - - gen_param_types.append(get_llvm_type(g, g->builtin_types.entry_usize)); - param_di_types.append(get_llvm_di_type(g, g->builtin_types.entry_usize)); - - fn_type->data.fn.gen_param_info[1].src_index = 1; - fn_type->data.fn.gen_param_info[1].gen_index = 1; - fn_type->data.fn.gen_param_info[1].type = g->builtin_types.entry_usize; - } else { - fn_type->data.fn.gen_param_info = heap::c_allocator.allocate(fn_type_id->param_count); - for (size_t i = 0; i < fn_type_id->param_count; i += 1) { - FnTypeParamInfo *src_param_info = &fn_type->data.fn.fn_type_id.param_info[i]; - ZigType *type_entry = src_param_info->type; - FnGenParamInfo *gen_param_info = &fn_type->data.fn.gen_param_info[i]; - - gen_param_info->src_index = i; - gen_param_info->gen_index = SIZE_MAX; - - if (is_c_abi || !type_has_bits(g, type_entry)) - continue; - - ZigType *gen_type; - if (handle_is_ptr(g, type_entry)) { - gen_type = get_pointer_to_type(g, type_entry, true); - gen_param_info->is_byval = true; - } else { - gen_type = type_entry; - } - gen_param_info->gen_index = gen_param_types.length; - gen_param_info->type = gen_type; - gen_param_types.append(get_llvm_type(g, gen_type)); - - param_di_types.append(get_llvm_di_type(g, gen_type)); - } - } - - if (is_c_abi) { - FnWalk fn_walk = {}; - fn_walk.id = FnWalkIdTypes; - fn_walk.data.types.param_di_types = ¶m_di_types; - fn_walk.data.types.gen_param_types = &gen_param_types; - walk_function_params(g, fn_type, &fn_walk); - } - - fn_type->data.fn.gen_param_count = gen_param_types.length; - - for (size_t i = 0; i < gen_param_types.length; i += 1) { - assert(gen_param_types.items[i] != nullptr); - } - - if (!first_arg_return && fn_returns_c_abi_small_struct(fn_type_id)) { - fn_type->data.fn.raw_type_ref = LLVMFunctionType(get_llvm_c_abi_type(g, gen_return_type), - gen_param_types.items, (unsigned int)gen_param_types.length, fn_type_id->is_var_args); - } else { - fn_type->data.fn.raw_type_ref = LLVMFunctionType(get_llvm_type(g, gen_return_type), - gen_param_types.items, (unsigned int)gen_param_types.length, fn_type_id->is_var_args); - } - const unsigned fn_addrspace = ZigLLVMDataLayoutGetProgramAddressSpace(g->target_data_ref); - fn_type->llvm_type = LLVMPointerType(fn_type->data.fn.raw_type_ref, fn_addrspace); - fn_type->data.fn.raw_di_type = ZigLLVMCreateSubroutineType(g->dbuilder, param_di_types.items, (int)param_di_types.length, 0); - fn_type->llvm_di_type = ZigLLVMCreateDebugPointerType(g->dbuilder, fn_type->data.fn.raw_di_type, - LLVMStoreSizeOfType(g->target_data_ref, fn_type->llvm_type), - LLVMABIAlignmentOfType(g->target_data_ref, fn_type->llvm_type), ""); - - gen_param_types.deinit(); - param_di_types.deinit(); -} - -void resolve_llvm_types_fn(CodeGen *g, ZigFn *fn) { - Error err; - if (fn->raw_di_type != nullptr) return; - - ZigType *fn_type = fn->type_entry; - if (!fn_is_async(fn)) { - resolve_llvm_types_fn_type(g, fn_type); - fn->raw_type_ref = fn_type->data.fn.raw_type_ref; - fn->raw_di_type = fn_type->data.fn.raw_di_type; - return; - } - - ZigType *gen_return_type = g->builtin_types.entry_void; - ZigList param_di_types = {}; - ZigList gen_param_types = {}; - // first "parameter" is return value - param_di_types.append(nullptr); - - ZigType *frame_type = get_fn_frame_type(g, fn); - ZigType *ptr_type = get_pointer_to_type(g, frame_type, false); - if ((err = type_resolve(g, ptr_type, ResolveStatusLLVMFwdDecl))) - zig_unreachable(); - gen_param_types.append(ptr_type->llvm_type); - param_di_types.append(ptr_type->llvm_di_type); - - // this parameter is used to pass the result pointer when await completes - gen_param_types.append(get_llvm_type(g, g->builtin_types.entry_usize)); - param_di_types.append(get_llvm_di_type(g, g->builtin_types.entry_usize)); - - fn->raw_type_ref = LLVMFunctionType(get_llvm_type(g, gen_return_type), - gen_param_types.items, gen_param_types.length, false); - fn->raw_di_type = ZigLLVMCreateSubroutineType(g->dbuilder, param_di_types.items, (int)param_di_types.length, 0); - - param_di_types.deinit(); - gen_param_types.deinit(); -} - -static void resolve_llvm_types_anyerror(CodeGen *g) { - ZigType *entry = g->builtin_types.entry_global_error_set; - entry->llvm_type = get_llvm_type(g, g->err_tag_type); - ZigList err_enumerators = {}; - // reserve index 0 to indicate no error - err_enumerators.append(ZigLLVMCreateDebugEnumerator(g->dbuilder, "(none)", 0, false)); - for (size_t i = 1; i < g->errors_by_index.length; i += 1) { - ErrorTableEntry *error_entry = g->errors_by_index.at(i); - err_enumerators.append(ZigLLVMCreateDebugEnumerator(g->dbuilder, buf_ptr(&error_entry->name), i, false)); - } - - // create debug type for error sets - uint64_t tag_debug_size_in_bits = g->err_tag_type->size_in_bits; - uint64_t tag_debug_align_in_bits = 8*g->err_tag_type->abi_align; - ZigLLVMDIFile *err_set_di_file = nullptr; - entry->llvm_di_type = ZigLLVMCreateDebugEnumerationType(g->dbuilder, - ZigLLVMCompileUnitToScope(g->compile_unit), buf_ptr(&entry->name), - err_set_di_file, 0, - tag_debug_size_in_bits, - tag_debug_align_in_bits, - err_enumerators.items, err_enumerators.length, - get_llvm_di_type(g, g->err_tag_type), ""); - - err_enumerators.deinit(); -} - -static void resolve_llvm_types_async_frame(CodeGen *g, ZigType *frame_type, ResolveStatus wanted_resolve_status) { - Error err; - if ((err = type_resolve(g, frame_type, ResolveStatusSizeKnown))) - zig_unreachable(); - - ZigType *passed_frame_type = fn_is_async(frame_type->data.frame.fn) ? frame_type : nullptr; - resolve_llvm_types_struct(g, frame_type->data.frame.locals_struct, wanted_resolve_status, passed_frame_type); - frame_type->llvm_type = frame_type->data.frame.locals_struct->llvm_type; - frame_type->llvm_di_type = frame_type->data.frame.locals_struct->llvm_di_type; -} - -static void resolve_llvm_types_any_frame(CodeGen *g, ZigType *any_frame_type, ResolveStatus wanted_resolve_status) { - if (any_frame_type->llvm_di_type != nullptr) return; - - Buf *name = buf_sprintf("(%s header)", buf_ptr(&any_frame_type->name)); - LLVMTypeRef frame_header_type = LLVMStructCreateNamed(LLVMGetGlobalContext(), buf_ptr(name)); - any_frame_type->llvm_type = LLVMPointerType(frame_header_type, 0); - any_frame_type->data.any_frame.struct_llvm_ty = frame_header_type; - - unsigned dwarf_kind = ZigLLVMTag_DW_structure_type(); - ZigLLVMDIFile *di_file = nullptr; - ZigLLVMDIScope *di_scope = ZigLLVMCompileUnitToScope(g->compile_unit); - unsigned line = 0; - ZigLLVMDIType *frame_header_di_type = ZigLLVMCreateReplaceableCompositeType(g->dbuilder, - dwarf_kind, buf_ptr(name), di_scope, di_file, line); - any_frame_type->llvm_di_type = ZigLLVMCreateDebugPointerType(g->dbuilder, frame_header_di_type, - 8*g->pointer_size_bytes, 8*g->builtin_types.entry_usize->abi_align, buf_ptr(&any_frame_type->name)); - - LLVMTypeRef llvm_void = LLVMVoidType(); - LLVMTypeRef arg_types[] = {any_frame_type->llvm_type, g->builtin_types.entry_usize->llvm_type}; - LLVMTypeRef fn_type = LLVMFunctionType(llvm_void, arg_types, 2, false); - LLVMTypeRef usize_type_ref = get_llvm_type(g, g->builtin_types.entry_usize); - ZigLLVMDIType *usize_di_type = get_llvm_di_type(g, g->builtin_types.entry_usize); - ZigLLVMDIScope *compile_unit_scope = ZigLLVMCompileUnitToScope(g->compile_unit); - - ZigType *result_type = any_frame_type->data.any_frame.result_type; - ZigType *ptr_result_type = (result_type == nullptr) ? nullptr : get_pointer_to_type(g, result_type, false); - const unsigned fn_addrspace = ZigLLVMDataLayoutGetProgramAddressSpace(g->target_data_ref); - LLVMTypeRef ptr_fn_llvm_type = LLVMPointerType(fn_type, fn_addrspace); - if (result_type == nullptr) { - g->any_frame_header_llvm_ty = frame_header_type; - g->anyframe_fn_type = fn_type; - } - - ZigList field_types = {}; - ZigList di_element_types = {}; - - // label (grep this): [fn_frame_struct_layout] - field_types.append(ptr_fn_llvm_type); // fn_ptr - field_types.append(usize_type_ref); // resume_index - field_types.append(usize_type_ref); // awaiter - - bool have_result_type = result_type != nullptr && type_has_bits(g, result_type); - if (have_result_type) { - field_types.append(get_llvm_type(g, ptr_result_type)); // result_ptr_callee - field_types.append(get_llvm_type(g, ptr_result_type)); // result_ptr_awaiter - field_types.append(get_llvm_type(g, result_type)); // result - if (codegen_fn_has_err_ret_tracing_arg(g, result_type)) { - ZigType *ptr_stack_trace = get_pointer_to_type(g, get_stack_trace_type(g), false); - field_types.append(get_llvm_type(g, ptr_stack_trace)); // ptr_stack_trace_callee - field_types.append(get_llvm_type(g, ptr_stack_trace)); // ptr_stack_trace_awaiter - } - } - LLVMStructSetBody(frame_header_type, field_types.items, field_types.length, false); - - di_element_types.append( - ZigLLVMCreateDebugMemberType(g->dbuilder, - ZigLLVMTypeToScope(any_frame_type->llvm_di_type), "fn_ptr", - di_file, line, - 8*LLVMABISizeOfType(g->target_data_ref, field_types.at(di_element_types.length)), - 8*LLVMABIAlignmentOfType(g->target_data_ref, field_types.at(di_element_types.length)), - 8*LLVMOffsetOfElement(g->target_data_ref, frame_header_type, di_element_types.length), - ZigLLVM_DIFlags_Zero, usize_di_type)); - di_element_types.append( - ZigLLVMCreateDebugMemberType(g->dbuilder, - ZigLLVMTypeToScope(any_frame_type->llvm_di_type), "resume_index", - di_file, line, - 8*LLVMABISizeOfType(g->target_data_ref, field_types.at(di_element_types.length)), - 8*LLVMABIAlignmentOfType(g->target_data_ref, field_types.at(di_element_types.length)), - 8*LLVMOffsetOfElement(g->target_data_ref, frame_header_type, di_element_types.length), - ZigLLVM_DIFlags_Zero, usize_di_type)); - di_element_types.append( - ZigLLVMCreateDebugMemberType(g->dbuilder, - ZigLLVMTypeToScope(any_frame_type->llvm_di_type), "awaiter", - di_file, line, - 8*LLVMABISizeOfType(g->target_data_ref, field_types.at(di_element_types.length)), - 8*LLVMABIAlignmentOfType(g->target_data_ref, field_types.at(di_element_types.length)), - 8*LLVMOffsetOfElement(g->target_data_ref, frame_header_type, di_element_types.length), - ZigLLVM_DIFlags_Zero, usize_di_type)); - - if (have_result_type) { - di_element_types.append( - ZigLLVMCreateDebugMemberType(g->dbuilder, - ZigLLVMTypeToScope(any_frame_type->llvm_di_type), "result_ptr_callee", - di_file, line, - 8*LLVMABISizeOfType(g->target_data_ref, field_types.at(di_element_types.length)), - 8*LLVMABIAlignmentOfType(g->target_data_ref, field_types.at(di_element_types.length)), - 8*LLVMOffsetOfElement(g->target_data_ref, frame_header_type, di_element_types.length), - ZigLLVM_DIFlags_Zero, get_llvm_di_type(g, ptr_result_type))); - di_element_types.append( - ZigLLVMCreateDebugMemberType(g->dbuilder, - ZigLLVMTypeToScope(any_frame_type->llvm_di_type), "result_ptr_awaiter", - di_file, line, - 8*LLVMABISizeOfType(g->target_data_ref, field_types.at(di_element_types.length)), - 8*LLVMABIAlignmentOfType(g->target_data_ref, field_types.at(di_element_types.length)), - 8*LLVMOffsetOfElement(g->target_data_ref, frame_header_type, di_element_types.length), - ZigLLVM_DIFlags_Zero, get_llvm_di_type(g, ptr_result_type))); - di_element_types.append( - ZigLLVMCreateDebugMemberType(g->dbuilder, - ZigLLVMTypeToScope(any_frame_type->llvm_di_type), "result", - di_file, line, - 8*LLVMABISizeOfType(g->target_data_ref, field_types.at(di_element_types.length)), - 8*LLVMABIAlignmentOfType(g->target_data_ref, field_types.at(di_element_types.length)), - 8*LLVMOffsetOfElement(g->target_data_ref, frame_header_type, di_element_types.length), - ZigLLVM_DIFlags_Zero, get_llvm_di_type(g, result_type))); - - if (codegen_fn_has_err_ret_tracing_arg(g, result_type)) { - ZigType *ptr_stack_trace = get_pointer_to_type(g, get_stack_trace_type(g), false); - di_element_types.append( - ZigLLVMCreateDebugMemberType(g->dbuilder, - ZigLLVMTypeToScope(any_frame_type->llvm_di_type), "ptr_stack_trace_callee", - di_file, line, - 8*LLVMABISizeOfType(g->target_data_ref, field_types.at(di_element_types.length)), - 8*LLVMABIAlignmentOfType(g->target_data_ref, field_types.at(di_element_types.length)), - 8*LLVMOffsetOfElement(g->target_data_ref, frame_header_type, di_element_types.length), - ZigLLVM_DIFlags_Zero, get_llvm_di_type(g, ptr_stack_trace))); - di_element_types.append( - ZigLLVMCreateDebugMemberType(g->dbuilder, - ZigLLVMTypeToScope(any_frame_type->llvm_di_type), "ptr_stack_trace_awaiter", - di_file, line, - 8*LLVMABISizeOfType(g->target_data_ref, field_types.at(di_element_types.length)), - 8*LLVMABIAlignmentOfType(g->target_data_ref, field_types.at(di_element_types.length)), - 8*LLVMOffsetOfElement(g->target_data_ref, frame_header_type, di_element_types.length), - ZigLLVM_DIFlags_Zero, get_llvm_di_type(g, ptr_stack_trace))); - } - }; - - ZigLLVMDIType *replacement_di_type = ZigLLVMCreateDebugStructType(g->dbuilder, - compile_unit_scope, buf_ptr(name), - di_file, line, - 8*LLVMABISizeOfType(g->target_data_ref, frame_header_type), - 8*LLVMABIAlignmentOfType(g->target_data_ref, frame_header_type), - ZigLLVM_DIFlags_Zero, - nullptr, di_element_types.items, di_element_types.length, 0, nullptr, ""); - - ZigLLVMReplaceTemporary(g->dbuilder, frame_header_di_type, replacement_di_type); - - field_types.deinit(); - di_element_types.deinit(); -} - -static void resolve_llvm_types(CodeGen *g, ZigType *type, ResolveStatus wanted_resolve_status) { - assert(wanted_resolve_status > ResolveStatusSizeKnown); - switch (type->id) { - case ZigTypeIdInvalid: - case ZigTypeIdMetaType: - case ZigTypeIdComptimeFloat: - case ZigTypeIdComptimeInt: - case ZigTypeIdEnumLiteral: - case ZigTypeIdUndefined: - case ZigTypeIdNull: - case ZigTypeIdBoundFn: - zig_unreachable(); - case ZigTypeIdFloat: - case ZigTypeIdOpaque: - case ZigTypeIdVoid: - case ZigTypeIdBool: - case ZigTypeIdUnreachable: - assert(type->llvm_di_type != nullptr); - return; - case ZigTypeIdStruct: - if (type->data.structure.special == StructSpecialSlice) - return resolve_llvm_types_slice(g, type, wanted_resolve_status); - else - return resolve_llvm_types_struct(g, type, wanted_resolve_status, nullptr); - case ZigTypeIdEnum: - return resolve_llvm_types_enum(g, type, wanted_resolve_status); - case ZigTypeIdUnion: - return resolve_llvm_types_union(g, type, wanted_resolve_status); - case ZigTypeIdPointer: - return resolve_llvm_types_pointer(g, type, wanted_resolve_status); - case ZigTypeIdInt: - return resolve_llvm_types_integer(g, type); - case ZigTypeIdOptional: - return resolve_llvm_types_optional(g, type, wanted_resolve_status); - case ZigTypeIdErrorUnion: - return resolve_llvm_types_error_union(g, type); - case ZigTypeIdArray: - return resolve_llvm_types_array(g, type); - case ZigTypeIdFn: - return resolve_llvm_types_fn_type(g, type); - case ZigTypeIdErrorSet: { - if (type->llvm_di_type != nullptr) return; - - if (g->builtin_types.entry_global_error_set->llvm_type == nullptr) { - resolve_llvm_types_anyerror(g); - } - type->llvm_type = g->builtin_types.entry_global_error_set->llvm_type; - type->llvm_di_type = g->builtin_types.entry_global_error_set->llvm_di_type; - return; - } - case ZigTypeIdVector: { - if (type->llvm_di_type != nullptr) return; - - type->llvm_type = LLVMVectorType(get_llvm_type(g, type->data.vector.elem_type), - type->data.vector.len); - - type->llvm_di_type = ZigLLVMDIBuilderCreateVectorType(g->dbuilder, - 8 * type->abi_size, - 8 * type->abi_align, - get_llvm_di_type(g, type->data.vector.elem_type), - type->data.vector.len); - return; - } - case ZigTypeIdFnFrame: - return resolve_llvm_types_async_frame(g, type, wanted_resolve_status); - case ZigTypeIdAnyFrame: - return resolve_llvm_types_any_frame(g, type, wanted_resolve_status); - } - zig_unreachable(); -} - -LLVMTypeRef get_llvm_c_abi_type(CodeGen *g, ZigType *type) { - assertNoError(type_resolve(g, type, ResolveStatusLLVMFull)); - assert(type->abi_size == 0 || type->abi_size >= LLVMABISizeOfType(g->target_data_ref, type->llvm_type)); - assert(type->abi_align == 0 || type->abi_align >= LLVMABIAlignmentOfType(g->target_data_ref, type->llvm_type)); - return type->llvm_c_abi_type; -} - -LLVMTypeRef get_llvm_type(CodeGen *g, ZigType *type) { - assertNoError(type_resolve(g, type, ResolveStatusLLVMFull)); - assert(type->abi_size == 0 || type->abi_size >= LLVMABISizeOfType(g->target_data_ref, type->llvm_type)); - assert(type->abi_align == 0 || type->abi_align >= LLVMABIAlignmentOfType(g->target_data_ref, type->llvm_type)); - return type->llvm_type; -} - -ZigLLVMDIType *get_llvm_di_type(CodeGen *g, ZigType *type) { - assertNoError(type_resolve(g, type, ResolveStatusLLVMFull)); - return type->llvm_di_type; -} - -void src_assert_impl(bool ok, AstNode *source_node, char const *file, unsigned int line) { - if (ok) return; - if (source_node == nullptr) { - fprintf(stderr, "when analyzing (unknown source location) "); - } else { - RootStruct *root_struct = source_node->owner->data.structure.root_struct; - fprintf(stderr, "when analyzing %s:%u:%u ", buf_ptr(root_struct->path), - node_line_onebased(source_node), node_column_onebased(source_node)); - } - fprintf(stderr, "in compiler source at %s:%u: ", file, line); - const char *msg = "assertion failed. This is a bug in the Zig compiler."; - stage2_panic(msg, strlen(msg)); -} - -Error analyze_import(CodeGen *g, ZigType *source_import, Buf *import_target_str, - ZigType **out_import, Buf **out_import_target_path, Buf *out_full_path) -{ - Error err; - - Buf *search_dir; - ZigPackage *cur_scope_pkg = source_import->data.structure.root_struct->package; - assert(cur_scope_pkg); - ZigPackage *target_package; - auto package_entry = cur_scope_pkg->package_table.maybe_get(import_target_str); - SourceKind source_kind; - if (package_entry) { - target_package = package_entry->value; - *out_import_target_path = &target_package->root_src_path; - search_dir = &target_package->root_src_dir; - source_kind = SourceKindPkgMain; - } else { - // try it as a filename - target_package = cur_scope_pkg; - *out_import_target_path = import_target_str; - - // search relative to importing file - search_dir = buf_alloc(); - os_path_dirname(source_import->data.structure.root_struct->path, search_dir); - - source_kind = SourceKindNonRoot; - } - - buf_resize(out_full_path, 0); - os_path_join(search_dir, *out_import_target_path, out_full_path); - - Buf *import_code = buf_alloc(); - Buf *resolved_path = buf_alloc(); - - Buf *resolve_paths[] = { out_full_path, }; - *resolved_path = os_path_resolve(resolve_paths, 1); - - auto import_entry = g->import_table.maybe_get(resolved_path); - if (import_entry) { - *out_import = import_entry->value; - return ErrorNone; - } - - if (source_kind == SourceKindNonRoot) { - Buf *pkg_root_src_dir = &cur_scope_pkg->root_src_dir; - Buf resolved_root_src_dir = os_path_resolve(&pkg_root_src_dir, 1); - if (!buf_starts_with_buf(resolved_path, &resolved_root_src_dir)) { - return ErrorImportOutsidePkgPath; - } - } - - if ((err = file_fetch(g, resolved_path, import_code))) { - return err; - } - - *out_import = add_source_file(g, target_package, resolved_path, import_code, source_kind); - return ErrorNone; -} - -void AstNode::src() { - RootStruct *root_struct = this->owner->data.structure.root_struct; - uint32_t line = root_struct->token_locs[this->main_token].line + 1; - uint32_t column = root_struct->token_locs[this->main_token].column + 1; - fprintf(stderr, "%s:%" PRIu32 ":%" PRIu32 "\n", - buf_ptr(root_struct->path), - line, column); -} - -void Stage1Air::src() { - Stage1Air *it; - for (it = this; it != nullptr && it->source_node != nullptr; it = it->parent_exec) { - it->source_node->src(); - } -} - -bool is_anon_container(ZigType *ty) { - return ty->id == ZigTypeIdStruct && ( - ty->data.structure.special == StructSpecialInferredTuple || - ty->data.structure.special == StructSpecialInferredStruct); -} - -bool is_opt_err_set(ZigType *ty) { - return ty->id == ZigTypeIdErrorSet || - (ty->id == ZigTypeIdOptional && ty->data.maybe.child_type->id == ZigTypeIdErrorSet); -} - -// Returns whether the x_optional field of ZigValue is active. -bool type_has_optional_repr(ZigType *ty) { - if (ty->id != ZigTypeIdOptional) { - return false; - } else if (get_src_ptr_type(ty) != nullptr) { - return false; - } else if (is_opt_err_set(ty)) { - return false; - } else { - return true; - } -} - -void copy_const_val(CodeGen *g, ZigValue *dest, ZigValue *src) { - uint32_t prev_align = dest->llvm_align; - ConstParent prev_parent = dest->parent; - memcpy(dest, src, sizeof(ZigValue)); - dest->llvm_align = prev_align; - if (src->special != ConstValSpecialStatic) - return; - dest->parent = prev_parent; - if (dest->type->id == ZigTypeIdStruct) { - dest->data.x_struct.fields = alloc_const_vals_ptrs(g, dest->type->data.structure.src_field_count); - for (size_t i = 0; i < dest->type->data.structure.src_field_count; i += 1) { - TypeStructField *type_struct_field = dest->type->data.structure.fields[i]; - if (type_struct_field->is_comptime) { - // comptime-known values are stored in the field init_val inside - // the struct type. The data stored here is not supposed to be read - // at all; the code should look at the type system and notice the field - // is comptime and look at the type to learn the value. - continue; - } - copy_const_val(g, dest->data.x_struct.fields[i], src->data.x_struct.fields[i]); - dest->data.x_struct.fields[i]->parent.id = ConstParentIdStruct; - dest->data.x_struct.fields[i]->parent.data.p_struct.struct_val = dest; - dest->data.x_struct.fields[i]->parent.data.p_struct.field_index = i; - } - } else if (dest->type->id == ZigTypeIdArray) { - switch (dest->data.x_array.special) { - case ConstArraySpecialNone: { - dest->data.x_array.data.s_none.elements = g->pass1_arena->allocate(dest->type->data.array.len); - for (uint64_t i = 0; i < dest->type->data.array.len; i += 1) { - copy_const_val(g, &dest->data.x_array.data.s_none.elements[i], &src->data.x_array.data.s_none.elements[i]); - dest->data.x_array.data.s_none.elements[i].parent.id = ConstParentIdArray; - dest->data.x_array.data.s_none.elements[i].parent.data.p_array.array_val = dest; - dest->data.x_array.data.s_none.elements[i].parent.data.p_array.elem_index = i; - } - break; - } - case ConstArraySpecialUndef: { - // Nothing to copy; the above memcpy did everything we needed. - break; - } - case ConstArraySpecialBuf: { - dest->data.x_array.data.s_buf = buf_create_from_buf(src->data.x_array.data.s_buf); - break; - } - } - } else if (dest->type->id == ZigTypeIdUnion) { - bigint_init_bigint(&dest->data.x_union.tag, &src->data.x_union.tag); - dest->data.x_union.payload = g->pass1_arena->create(); - copy_const_val(g, dest->data.x_union.payload, src->data.x_union.payload); - dest->data.x_union.payload->parent.id = ConstParentIdUnion; - dest->data.x_union.payload->parent.data.p_union.union_val = dest; - } else if (type_has_optional_repr(dest->type) && dest->data.x_optional != nullptr) { - dest->data.x_optional = g->pass1_arena->create(); - copy_const_val(g, dest->data.x_optional, src->data.x_optional); - dest->data.x_optional->parent.id = ConstParentIdOptionalPayload; - dest->data.x_optional->parent.data.p_optional_payload.optional_val = dest; - } -} - -bool optional_value_is_null(ZigValue *val) { - assert(val->special == ConstValSpecialStatic); - if (get_src_ptr_type(val->type) != nullptr) { - if (val->data.x_ptr.special == ConstPtrSpecialNull) { - return true; - } else if (val->data.x_ptr.special == ConstPtrSpecialHardCodedAddr) { - return val->data.x_ptr.data.hard_coded_addr.addr == 0; - } else { - return false; - } - } else if (is_opt_err_set(val->type)) { - return val->data.x_err_set == nullptr; - } else { - return val->data.x_optional == nullptr; - } -} - -bool type_is_numeric(ZigType *ty) { - switch (ty->id) { - case ZigTypeIdInvalid: - zig_unreachable(); - case ZigTypeIdComptimeFloat: - case ZigTypeIdComptimeInt: - case ZigTypeIdInt: - case ZigTypeIdFloat: - case ZigTypeIdUndefined: - return true; - - case ZigTypeIdVector: - return type_is_numeric(ty->data.vector.elem_type); - - case ZigTypeIdMetaType: - case ZigTypeIdVoid: - case ZigTypeIdBool: - case ZigTypeIdUnreachable: - case ZigTypeIdPointer: - case ZigTypeIdArray: - case ZigTypeIdStruct: - case ZigTypeIdNull: - case ZigTypeIdOptional: - case ZigTypeIdErrorUnion: - case ZigTypeIdErrorSet: - case ZigTypeIdEnum: - case ZigTypeIdUnion: - case ZigTypeIdFn: - case ZigTypeIdBoundFn: - case ZigTypeIdOpaque: - case ZigTypeIdFnFrame: - case ZigTypeIdAnyFrame: - case ZigTypeIdEnumLiteral: - return false; - } - zig_unreachable(); -} - -static void dump_value_indent_error_set(ZigValue *val, int indent) { - fprintf(stderr, "\n"); -} - -static void dump_value_indent(ZigValue *val, int indent); - -static void dump_value_indent_ptr(ZigValue *val, int indent) { - switch (val->data.x_ptr.special) { - case ConstPtrSpecialInvalid: - fprintf(stderr, "\n"); - return; - case ConstPtrSpecialNull: - fprintf(stderr, "\n"); - return; - case ConstPtrSpecialRef: - fprintf(stderr, "data.x_ptr.data.ref.pointee, indent + 1); - break; - case ConstPtrSpecialBaseStruct: { - ZigValue *struct_val = val->data.x_ptr.data.base_struct.struct_val; - size_t field_index = val->data.x_ptr.data.base_struct.field_index; - fprintf(stderr, "data.x_struct.fields[field_index]; - if (field_val != nullptr) { - dump_value_indent(field_val, indent + 1); - } else { - for (int i = 0; i < indent; i += 1) { - fprintf(stderr, " "); - } - fprintf(stderr, "(invalid null field)\n"); - } - } - break; - } - case ConstPtrSpecialBaseOptionalPayload: { - ZigValue *optional_val = val->data.x_ptr.data.base_optional_payload.optional_val; - fprintf(stderr, "\n"); -} - -static void dump_value_indent(ZigValue *val, int indent) { - for (int i = 0; i < indent; i += 1) { - fprintf(stderr, " "); - } - fprintf(stderr, "Value@%p(", val); - if (val->type != nullptr) { - fprintf(stderr, "%s)", buf_ptr(&val->type->name)); - } else { - fprintf(stderr, "type=nullptr)"); - } - switch (val->special) { - case ConstValSpecialUndef: - fprintf(stderr, "[undefined]\n"); - return; - case ConstValSpecialLazy: - fprintf(stderr, "[lazy]\n"); - return; - case ConstValSpecialRuntime: - fprintf(stderr, "[runtime]\n"); - return; - case ConstValSpecialStatic: - break; - } - if (val->type == nullptr) - return; - switch (val->type->id) { - case ZigTypeIdInvalid: - fprintf(stderr, "\n"); - return; - case ZigTypeIdUnreachable: - fprintf(stderr, "\n"); - return; - case ZigTypeIdUndefined: - fprintf(stderr, "\n"); - return; - case ZigTypeIdVoid: - fprintf(stderr, "<{}>\n"); - return; - case ZigTypeIdMetaType: - fprintf(stderr, "<%s>\n", buf_ptr(&val->data.x_type->name)); - return; - case ZigTypeIdBool: - fprintf(stderr, "<%s>\n", val->data.x_bool ? "true" : "false"); - return; - case ZigTypeIdComptimeInt: - case ZigTypeIdInt: { - Buf *tmp_buf = buf_alloc(); - bigint_append_buf(tmp_buf, &val->data.x_bigint, 10); - fprintf(stderr, "<%s>\n", buf_ptr(tmp_buf)); - buf_destroy(tmp_buf); - return; - } - case ZigTypeIdComptimeFloat: - case ZigTypeIdFloat: - fprintf(stderr, "\n"); - return; - - case ZigTypeIdStruct: - fprintf(stderr, "type->data.structure.src_field_count; i += 1) { - for (int j = 0; j < indent; j += 1) { - fprintf(stderr, " "); - } - TypeStructField *field = val->type->data.structure.fields[i]; - fprintf(stderr, "%s: ", buf_ptr(field->name)); - if (field->is_comptime) { - fprintf(stderr, ""); - } else if (val->data.x_struct.fields == nullptr) { - fprintf(stderr, "\n"); - } else { - dump_value_indent(val->data.x_struct.fields[i], 1); - } - } - for (int i = 0; i < indent; i += 1) { - fprintf(stderr, " "); - } - fprintf(stderr, ">\n"); - return; - - case ZigTypeIdOptional: - if (get_src_ptr_type(val->type) != nullptr) { - return dump_value_indent_ptr(val, indent); - } else if (val->type->data.maybe.child_type->id == ZigTypeIdErrorSet) { - return dump_value_indent_error_set(val, indent); - } else { - fprintf(stderr, "<\n"); - dump_value_indent(val->data.x_optional, indent + 1); - - for (int i = 0; i < indent; i += 1) { - fprintf(stderr, " "); - } - fprintf(stderr, ">\n"); - return; - } - case ZigTypeIdErrorUnion: - if (val->data.x_err_union.payload != nullptr) { - fprintf(stderr, "<\n"); - dump_value_indent(val->data.x_err_union.payload, indent + 1); - } else { - fprintf(stderr, "<\n"); - dump_value_indent(val->data.x_err_union.error_set, 0); - } - for (int i = 0; i < indent; i += 1) { - fprintf(stderr, " "); - } - fprintf(stderr, ">\n"); - return; - - case ZigTypeIdPointer: - return dump_value_indent_ptr(val, indent); - - case ZigTypeIdErrorSet: - return dump_value_indent_error_set(val, indent); - - case ZigTypeIdVector: - case ZigTypeIdArray: - case ZigTypeIdNull: - case ZigTypeIdEnum: - case ZigTypeIdUnion: - case ZigTypeIdFn: - case ZigTypeIdBoundFn: - case ZigTypeIdOpaque: - case ZigTypeIdFnFrame: - case ZigTypeIdAnyFrame: - case ZigTypeIdEnumLiteral: - fprintf(stderr, "\n"); - return; - } - zig_unreachable(); -} - -void ZigValue::dump() { - dump_value_indent(this, 0); -} - -// float ops that take a single argument -//TODO Powi, Pow, minnum, maxnum, maximum, minimum, copysign, lround, llround, lrint, llrint -const char *float_un_op_to_name(BuiltinFnId op) { - switch (op) { - case BuiltinFnIdSqrt: - return "sqrt"; - case BuiltinFnIdSin: - return "sin"; - case BuiltinFnIdCos: - return "cos"; - case BuiltinFnIdTan: - return "tan"; - case BuiltinFnIdExp: - return "exp"; - case BuiltinFnIdExp2: - return "exp2"; - case BuiltinFnIdLog: - return "log"; - case BuiltinFnIdLog10: - return "log10"; - case BuiltinFnIdLog2: - return "log2"; - case BuiltinFnIdFabs: - return "fabs"; - case BuiltinFnIdFloor: - return "floor"; - case BuiltinFnIdCeil: - return "ceil"; - case BuiltinFnIdTrunc: - return "trunc"; - case BuiltinFnIdNearbyInt: - return "nearbyint"; - case BuiltinFnIdRound: - return "round"; - case BuiltinFnIdMulAdd: - return "fma"; - default: - zig_unreachable(); - } -} diff --git a/src/stage1/analyze.hpp b/src/stage1/analyze.hpp deleted file mode 100644 index 64e0e199f877..000000000000 --- a/src/stage1/analyze.hpp +++ /dev/null @@ -1,314 +0,0 @@ -/* - * Copyright (c) 2015 Andrew Kelley - * - * This file is part of zig, which is MIT licensed. - * See http://opensource.org/licenses/MIT - */ - -#ifndef ZIG_ANALYZE_HPP -#define ZIG_ANALYZE_HPP - -#include "all_types.hpp" - -void semantic_analyze(CodeGen *g); -ErrorMsg *add_node_error(CodeGen *g, AstNode *node, Buf *msg); -ErrorMsg *add_token_error(CodeGen *g, ZigType *owner, TokenIndex token, Buf *msg); -ErrorMsg *add_token_error_offset(CodeGen *g, ZigType *owner, TokenIndex token, Buf *msg, - uint32_t bad_index); -ErrorMsg *add_error_note(CodeGen *g, ErrorMsg *parent_msg, const AstNode *node, Buf *msg); -ZigType *new_type_table_entry(ZigTypeId id); -ZigType *get_fn_frame_type(CodeGen *g, ZigFn *fn); -ZigType *get_pointer_to_type(CodeGen *g, ZigType *child_type, bool is_const); -ZigType *get_pointer_to_type_extra(CodeGen *g, ZigType *child_type, - bool is_const, bool is_volatile, PtrLen ptr_len, - uint32_t byte_alignment, uint32_t bit_offset, uint32_t unaligned_bit_count, - bool allow_zero); -ZigType *get_pointer_to_type_extra2(CodeGen *g, ZigType *child_type, - bool is_const, bool is_volatile, PtrLen ptr_len, - uint32_t byte_alignment, uint32_t bit_offset, uint32_t unaligned_bit_count, - bool allow_zero, uint32_t vector_index, InferredStructField *inferred_struct_field, - ZigValue *sentinel); -uint64_t type_size(CodeGen *g, ZigType *type_entry); -uint64_t type_size_bits(CodeGen *g, ZigType *type_entry); -ZigType *get_int_type(CodeGen *g, bool is_signed, uint32_t size_in_bits); -ZigType *get_vector_type(CodeGen *g, uint32_t len, ZigType *elem_type); -ZigType **get_c_int_type_ptr(CodeGen *g, CIntType c_int_type); -ZigType *get_c_int_type(CodeGen *g, CIntType c_int_type); -ZigType *get_fn_type(CodeGen *g, FnTypeId *fn_type_id); -ZigType *get_optional_type(CodeGen *g, ZigType *child_type); -ZigType *get_optional_type2(CodeGen *g, ZigType *child_type); -ZigType *get_array_type(CodeGen *g, ZigType *child_type, uint64_t array_size, ZigValue *sentinel); -ZigType *get_slice_type(CodeGen *g, ZigType *ptr_type); -ZigType *get_partial_container_type(CodeGen *g, Scope *scope, ContainerKind kind, - AstNode *decl_node, const char *full_name, Buf *bare_name, ContainerLayout layout); -ZigType *get_smallest_unsigned_int_type(CodeGen *g, uint64_t x); -ZigType *get_error_union_type(CodeGen *g, ZigType *err_set_type, ZigType *payload_type); -ZigType *get_bound_fn_type(CodeGen *g, ZigFn *fn_entry); -ZigType *get_opaque_type(CodeGen *g, Scope *scope, AstNode *source_node, const char *full_name, Buf *bare_name); -ZigType *get_test_fn_type(CodeGen *g); -ZigType *get_any_frame_type(CodeGen *g, ZigType *result_type); -bool handle_is_ptr(CodeGen *g, ZigType *type_entry); -Error emit_error_unless_callconv_allowed_for_target(CodeGen *g, AstNode *source_node, CallingConvention cc); -uint32_t get_async_frame_align_bytes(CodeGen *g); - -bool type_has_bits(CodeGen *g, ZigType *type_entry); -Error type_has_bits2(CodeGen *g, ZigType *type_entry, bool *result); - -bool fn_returns_c_abi_small_struct(FnTypeId *fn_type_id); - -enum ExternPosition { - ExternPositionFunctionParameter, - ExternPositionFunctionReturn, - ExternPositionOther, // array element, struct field, optional element, etc -}; - -Error type_allowed_in_extern(CodeGen *g, ZigType *type_entry, ExternPosition position, bool *result); -bool ptr_allows_addr_zero(ZigType *ptr_type); - -// Deprecated, use `type_is_nonnull_ptr2` -bool type_is_nonnull_ptr(CodeGen *g, ZigType *type); -Error type_is_nonnull_ptr2(CodeGen *g, ZigType *type, bool *result); - -ZigType *get_codegen_ptr_type_bail(CodeGen *g, ZigType *type); -Error get_codegen_ptr_type(CodeGen *g, ZigType *type, ZigType **result); - -enum SourceKind { - SourceKindRoot, - SourceKindPkgMain, - SourceKindNonRoot, - SourceKindCImport, -}; -ZigType *add_source_file(CodeGen *g, ZigPackage *package, Buf *abs_full_path, Buf *source_code, - SourceKind source_kind); - -ZigVar *find_variable(CodeGen *g, Scope *orig_context, Buf *name, ScopeFnDef **crossed_fndef_scope); -Tld *find_decl(CodeGen *g, Scope *scope, Buf *name); -Tld *find_container_decl(CodeGen *g, ScopeDecls *decls_scope, Buf *name); -void resolve_top_level_decl(CodeGen *g, Tld *tld, AstNode *source_node, bool allow_lazy); -void resolve_container_usingnamespace_decls(CodeGen *g, ScopeDecls *decls_scope); - -ZigType *get_src_ptr_type(ZigType *type); -uint32_t get_ptr_align(CodeGen *g, ZigType *type); -bool get_ptr_const(CodeGen *g, ZigType *type); -ZigType *validate_var_type(CodeGen *g, AstNodeVariableDeclaration *source_node, ZigType *type_entry); -ZigType *container_ref_type(ZigType *type_entry); -bool type_is_complete(ZigType *type_entry); -bool type_is_resolved(ZigType *type_entry, ResolveStatus status); -bool type_is_invalid(ZigType *type_entry); -bool type_is_global_error_set(ZigType *err_set_type); -ScopeDecls *get_container_scope(ZigType *type_entry); -TypeStructField *find_struct_type_field(ZigType *type_entry, Buf *name); -TypeEnumField *find_enum_type_field(ZigType *enum_type, Buf *name); -TypeUnionField *find_union_type_field(ZigType *type_entry, Buf *name); -TypeEnumField *find_enum_field_by_tag(ZigType *enum_type, const BigInt *tag); -TypeUnionField *find_union_field_by_tag(ZigType *type_entry, const BigInt *tag); - -bool is_ref(ZigType *type_entry); -bool is_array_ref(ZigType *type_entry); -bool is_container_ref(ZigType *type_entry); -Error is_valid_vector_elem_type(CodeGen *g, ZigType *elem_type, bool *result); -void scan_decls(CodeGen *g, ScopeDecls *decls_scope, AstNode *node); -ZigFn *scope_fn_entry(Scope *scope); -ZigPackage *scope_package(Scope *scope); -ZigType *get_scope_import(Scope *scope); -ScopeTypeOf *get_scope_typeof(Scope *scope); -void init_tld(Tld *tld, TldId id, Buf *name, VisibMod visib_mod, AstNode *source_node, Scope *parent_scope); -ZigVar *add_variable(CodeGen *g, AstNode *source_node, Scope *parent_scope, Buf *name, - bool is_const, ZigValue *init_value, Tld *src_tld, ZigType *var_type); -ZigType *analyze_type_expr(CodeGen *g, Scope *scope, AstNode *node); -void append_namespace_qualification(CodeGen *g, Buf *buf, ZigType *container_type); -ZigFn *create_fn(CodeGen *g, AstNode *proto_node); -void init_fn_type_id(FnTypeId *fn_type_id, AstNode *proto_node, CallingConvention cc, size_t param_count_alloc); -AstNode *get_param_decl_node(ZigFn *fn_entry, size_t index); -Error ATTRIBUTE_MUST_USE type_resolve(CodeGen *g, ZigType *type_entry, ResolveStatus status); -void complete_enum(CodeGen *g, ZigType *enum_type); -bool ir_get_var_is_comptime(ZigVar *var); -bool const_values_equal(CodeGen *g, ZigValue *a, ZigValue *b); -void eval_min_max_value(CodeGen *g, ZigType *type_entry, ZigValue *const_val, bool is_max); -void eval_min_max_value_int(CodeGen *g, ZigType *int_type, BigInt *bigint, bool is_max); - -void render_const_value(CodeGen *g, Buf *buf, ZigValue *const_val); - -ScopeDecls *create_decls_scope(CodeGen *g, AstNode *node, Scope *parent, ZigType *container_type, ZigType *import, Buf *bare_name); -ScopeBlock *create_block_scope(CodeGen *g, AstNode *node, Scope *parent); -ScopeDefer *create_defer_scope(CodeGen *g, AstNode *node, Scope *parent); -ScopeDeferExpr *create_defer_expr_scope(CodeGen *g, AstNode *node, Scope *parent); -Scope *create_var_scope(CodeGen *g, AstNode *node, Scope *parent, ZigVar *var); -ScopeCImport *create_cimport_scope(CodeGen *g, AstNode *node, Scope *parent); -ScopeLoop *create_loop_scope(CodeGen *g, AstNode *node, Scope *parent); -ScopeSuspend *create_suspend_scope(CodeGen *g, AstNode *node, Scope *parent); -ScopeFnDef *create_fndef_scope(CodeGen *g, AstNode *node, Scope *parent, ZigFn *fn_entry); -Scope *create_comptime_scope(CodeGen *g, AstNode *node, Scope *parent); -Scope *create_nosuspend_scope(CodeGen *g, AstNode *node, Scope *parent); -Scope *create_runtime_scope(CodeGen *g, AstNode *node, Scope *parent, Stage1ZirInst *is_comptime); -Scope *create_typeof_scope(CodeGen *g, AstNode *node, Scope *parent); -ScopeExpr *create_expr_scope(CodeGen *g, AstNode *node, Scope *parent); - -void init_const_str_lit(CodeGen *g, ZigValue *const_val, Buf *str, bool move_str); -ZigValue *create_const_str_lit(CodeGen *g, Buf *str); -ZigValue *create_sentineled_str_lit(CodeGen *g, Buf *str, ZigValue *sentinel); - -void init_const_bigint(ZigValue *const_val, ZigType *type, const BigInt *bigint); -ZigValue *create_const_bigint(CodeGen *g, ZigType *type, const BigInt *bigint); - -void init_const_unsigned_negative(ZigValue *const_val, ZigType *type, uint64_t x, bool negative); -ZigValue *create_const_unsigned_negative(CodeGen *g, ZigType *type, uint64_t x, bool negative); - -void init_const_signed(ZigValue *const_val, ZigType *type, int64_t x); -ZigValue *create_const_signed(CodeGen *g, ZigType *type, int64_t x); - -void init_const_usize(CodeGen *g, ZigValue *const_val, uint64_t x); -ZigValue *create_const_usize(CodeGen *g, uint64_t x); - -void init_const_float(ZigValue *const_val, ZigType *type, double value); -ZigValue *create_const_float(CodeGen *g, ZigType *type, double value); - -void init_const_enum(ZigValue *const_val, ZigType *type, const BigInt *tag); -ZigValue *create_const_enum(CodeGen *g, ZigType *type, const BigInt *tag); - -void init_const_bool(CodeGen *g, ZigValue *const_val, bool value); -ZigValue *create_const_bool(CodeGen *g, bool value); - -void init_const_type(CodeGen *g, ZigValue *const_val, ZigType *type_value); -ZigValue *create_const_type(CodeGen *g, ZigType *type_value); - -void init_const_runtime(ZigValue *const_val, ZigType *type); -ZigValue *create_const_runtime(CodeGen *g, ZigType *type); - -void init_const_ptr_ref(CodeGen *g, ZigValue *const_val, ZigValue *pointee_val, bool is_const); -ZigValue *create_const_ptr_ref(CodeGen *g, ZigValue *pointee_val, bool is_const); - -void init_const_ptr_hard_coded_addr(CodeGen *g, ZigValue *const_val, ZigType *pointee_type, - size_t addr, bool is_const); -ZigValue *create_const_ptr_hard_coded_addr(CodeGen *g, ZigType *pointee_type, - size_t addr, bool is_const); - -void init_const_ptr_array(CodeGen *g, ZigValue *const_val, ZigValue *array_val, - size_t elem_index, bool is_const, PtrLen ptr_len); -ZigValue *create_const_ptr_array(CodeGen *g, ZigValue *array_val, size_t elem_index, - bool is_const, PtrLen ptr_len); - -void init_const_slice(CodeGen *g, ZigValue *const_val, ZigValue *array_val, - size_t start, size_t len, bool is_const, ZigValue *sentinel); -ZigValue *create_const_slice(CodeGen *g, ZigValue *array_val, size_t start, size_t len, bool is_const, ZigValue *sentinel); - -void init_const_null(ZigValue *const_val, ZigType *type); -ZigValue *create_const_null(CodeGen *g, ZigType *type); - -void init_const_fn(ZigValue *const_val, ZigFn *fn); -ZigValue *create_const_fn(CodeGen *g, ZigFn *fn); - -ZigValue **alloc_const_vals_ptrs(CodeGen *g, size_t count); -ZigValue **realloc_const_vals_ptrs(CodeGen *g, ZigValue **ptr, size_t old_count, size_t new_count); - -TypeStructField **alloc_type_struct_fields(size_t count); -TypeStructField **realloc_type_struct_fields(TypeStructField **ptr, size_t old_count, size_t new_count); - -ZigType *make_int_type(CodeGen *g, bool is_signed, uint32_t size_in_bits); -void expand_undef_array(CodeGen *g, ZigValue *const_val); -void expand_undef_struct(CodeGen *g, ZigValue *const_val); -void update_compile_var(CodeGen *g, Buf *name, ZigValue *value); - -const char *type_id_name(ZigTypeId id); -ZigTypeId type_id_at_index(size_t index); -size_t type_id_len(); -size_t type_id_index(ZigType *entry); -ZigType *get_generic_fn_type(CodeGen *g, FnTypeId *fn_type_id); -bool optional_value_is_null(ZigValue *val); - -uint32_t get_abi_alignment(CodeGen *g, ZigType *type_entry); -ZigType *get_align_amt_type(CodeGen *g); -ZigPackage *new_anonymous_package(void); - -Buf *const_value_to_buffer(ZigValue *const_val); -void add_fn_export(CodeGen *g, ZigFn *fn_table_entry, const char *symbol_name, GlobalLinkageId linkage, CallingConvention cc); -void add_var_export(CodeGen *g, ZigVar *fn_table_entry, const char *symbol_name, GlobalLinkageId linkage); - - -ZigValue *get_builtin_value(CodeGen *codegen, const char *name); -ZigType *get_builtin_type(CodeGen *codegen, const char *name); -ZigType *get_stack_trace_type(CodeGen *g); -bool resolve_inferred_error_set(CodeGen *g, ZigType *err_set_type, AstNode *source_node); - -ZigType *get_auto_err_set_type(CodeGen *g, ZigFn *fn_entry); - -bool fn_type_can_fail(FnTypeId *fn_type_id); -bool type_can_fail(ZigType *type_entry); -bool fn_eval_cacheable(Scope *scope, ZigType *return_type); -AstNode *type_decl_node(ZigType *type_entry); - -Error get_primitive_type(CodeGen *g, Buf *name, ZigType **result); - -bool calling_convention_allows_zig_types(CallingConvention cc); -const char *calling_convention_name(CallingConvention cc); - -const char *address_space_name(AddressSpace as); - -Error ATTRIBUTE_MUST_USE file_fetch(CodeGen *g, Buf *resolved_path, Buf *contents); - -void walk_function_params(CodeGen *g, ZigType *fn_type, FnWalk *fn_walk); -X64CABIClass type_c_abi_x86_64_class(CodeGen *g, ZigType *ty); -bool type_is_c_abi_int_bail(CodeGen *g, ZigType *ty); -Error type_is_c_abi_int(CodeGen *g, ZigType *ty, bool *result); -bool want_first_arg_sret(CodeGen *g, FnTypeId *fn_type_id); -const char *container_string(ContainerKind kind); - -uint32_t get_host_int_bytes(CodeGen *g, ZigType *struct_type, TypeStructField *field); - -enum ReqCompTime { - ReqCompTimeInvalid, - ReqCompTimeNo, - ReqCompTimeYes, -}; -ReqCompTime type_requires_comptime(CodeGen *g, ZigType *type_entry); - -OnePossibleValue type_has_one_possible_value(CodeGen *g, ZigType *type_entry); - -Error ensure_const_val_repr(IrAnalyze *ira, CodeGen *codegen, AstNode *source_node, - ZigValue *const_val, ZigType *wanted_type); - -void typecheck_panic_fn(CodeGen *g, TldFn *tld_fn, ZigFn *panic_fn); -Buf *type_bare_name(ZigType *t); -Buf *type_h_name(ZigType *t); - -LLVMTypeRef get_llvm_type(CodeGen *g, ZigType *type); -LLVMTypeRef get_llvm_c_abi_type(CodeGen *g, ZigType *type); -ZigLLVMDIType *get_llvm_di_type(CodeGen *g, ZigType *type); - -void add_cc_args(CodeGen *g, ZigList &args, const char *out_dep_path, bool translate_c, - FileExt source_kind); - -void src_assert_impl(bool ok, AstNode *source_node, const char *file, unsigned int line); -bool is_container(ZigType *type_entry); -ZigValue *analyze_const_value(CodeGen *g, Scope *scope, AstNode *node, ZigType *type_entry, - Buf *type_name, UndefAllowed undef); - -void resolve_llvm_types_fn(CodeGen *g, ZigFn *fn); -bool fn_is_async(ZigFn *fn); -CallingConvention cc_from_fn_proto(AstNodeFnProto *fn_proto); -bool is_valid_return_type(ZigType* type); -bool is_valid_param_type(ZigType* type); - -Error type_val_resolve_abi_align(CodeGen *g, AstNode *source_node, ZigValue *type_val, uint32_t *abi_align); -Error type_val_resolve_abi_size(CodeGen *g, AstNode *source_node, ZigValue *type_val, - size_t *abi_size, size_t *size_in_bits); -Error type_val_resolve_zero_bits(CodeGen *g, ZigValue *type_val, ZigType *parent_type, - ZigValue *parent_type_val, bool *is_zero_bits); -ZigType *resolve_union_field_type(CodeGen *g, TypeUnionField *union_field); -ZigType *resolve_struct_field_type(CodeGen *g, TypeStructField *struct_field); - -void add_async_error_notes(CodeGen *g, ErrorMsg *msg, ZigFn *fn); - -Error analyze_import(CodeGen *codegen, ZigType *source_import, Buf *import_target_str, - ZigType **out_import, Buf **out_import_target_path, Buf *out_full_path); -ZigValue *get_the_one_possible_value(CodeGen *g, ZigType *type_entry); -bool is_anon_container(ZigType *ty); -void copy_const_val(CodeGen *g, ZigValue *dest, ZigValue *src); -bool type_has_optional_repr(ZigType *ty); -bool is_opt_err_set(ZigType *ty); -bool type_is_numeric(ZigType *ty); -const char *float_un_op_to_name(BuiltinFnId op); - -#define src_assert(OK, SOURCE_NODE) src_assert_impl((OK), (SOURCE_NODE), __FILE__, __LINE__) - -#endif diff --git a/src/stage1/astgen.cpp b/src/stage1/astgen.cpp deleted file mode 100644 index 12d1239e82f7..000000000000 --- a/src/stage1/astgen.cpp +++ /dev/null @@ -1,8339 +0,0 @@ -/* - * Copyright (c) 2021 Andrew Kelley - * - * This file is part of zig, which is MIT licensed. - * See http://opensource.org/licenses/MIT - */ - -#include "astgen.hpp" -#include "analyze.hpp" -#include "util.hpp" -#include "os.hpp" -#include "parser.hpp" - -struct Stage1AstGen { - CodeGen *codegen; - Stage1Zir *exec; - Stage1ZirBasicBlock *current_basic_block; - AstNode *main_block_node; - size_t next_debug_id; - ZigFn *fn; - bool in_c_import_scope; -}; - -static Stage1ZirInst *astgen_node(Stage1AstGen *ag, AstNode *node, Scope *scope); -static Stage1ZirInst *astgen_node_extra(Stage1AstGen *ag, AstNode *node, Scope *scope, LVal lval, - ResultLoc *result_loc); - -static Stage1ZirInst *ir_lval_wrap(Stage1AstGen *ag, Scope *scope, Stage1ZirInst *value, LVal lval, - ResultLoc *result_loc); -static Stage1ZirInst *ir_expr_wrap(Stage1AstGen *ag, Scope *scope, Stage1ZirInst *inst, - ResultLoc *result_loc); -static Stage1ZirInst *astgen_union_init_expr(Stage1AstGen *ag, Scope *scope, AstNode *source_node, - Stage1ZirInst *union_type, Stage1ZirInst *field_name, AstNode *expr_node, - LVal lval, ResultLoc *parent_result_loc); -static ResultLocCast *ir_build_cast_result_loc(Stage1AstGen *ag, Stage1ZirInst *dest_type, - ResultLoc *parent_result_loc); -static ZigVar *ir_create_var(Stage1AstGen *ag, AstNode *node, Scope *scope, Buf *name, - bool src_is_const, bool gen_is_const, bool is_shadowable, Stage1ZirInst *is_comptime); -static void build_decl_var_and_init(Stage1AstGen *ag, Scope *scope, AstNode *source_node, - ZigVar *var, Stage1ZirInst *init, const char *name_hint, Stage1ZirInst *is_comptime); - -static void ir_assert_impl(bool ok, Stage1ZirInst *source_instruction, char const *file, unsigned int line) { - if (ok) return; - src_assert_impl(ok, source_instruction->source_node, file, line); -} - -static ErrorMsg *exec_add_error_node(CodeGen *codegen, Stage1Zir *exec, AstNode *source_node, Buf *msg) { - ErrorMsg *err_msg = add_node_error(codegen, source_node, msg); - invalidate_exec(exec, err_msg); - return err_msg; -} - - -#define ir_assert(OK, SOURCE_INSTRUCTION) ir_assert_impl((OK), (SOURCE_INSTRUCTION), __FILE__, __LINE__) - - -static bool instr_is_unreachable(Stage1ZirInst *instruction) { - switch (instruction->id) { - case Stage1ZirInstIdCondBr: - case Stage1ZirInstIdReturn: - case Stage1ZirInstIdBr: - case Stage1ZirInstIdUnreachable: - case Stage1ZirInstIdSwitchBr: - case Stage1ZirInstIdPanic: - return true; - default: - return false; - } -} - -void destroy_instruction_src(Stage1ZirInst *inst) { - switch (inst->id) { - case Stage1ZirInstIdInvalid: - zig_unreachable(); - case Stage1ZirInstIdReturn: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdConst: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdBinOp: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdMergeErrSets: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdDeclVar: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdCall: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdCallExtra: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdAsyncCallExtra: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdUnOp: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdCondBr: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdBr: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdPhi: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdContainerInitList: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdContainerInitFields: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdUnreachable: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdElemPtr: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdVarPtr: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdLoadPtr: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdStorePtr: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdTypeOf: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdFieldPtr: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdSetCold: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdSetRuntimeSafety: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdSetFloatMode: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdArrayType: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdSliceType: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdAnyFrameType: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdAsm: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdSizeOf: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdTestNonNull: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdOptionalUnwrapPtr: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdPopCount: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdClz: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdCtz: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdBswap: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdBitReverse: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdSwitchBr: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdSwitchVar: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdSwitchElseVar: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdSwitchTarget: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdImport: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdRef: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdCompileErr: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdCompileLog: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdErrName: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdCImport: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdCInclude: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdCDefine: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdCUndef: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdEmbedFile: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdCmpxchg: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdFence: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdReduce: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdTruncate: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdIntCast: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdFloatCast: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdErrSetCast: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdIntToFloat: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdFloatToInt: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdBoolToInt: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdVectorType: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdShuffleVector: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdSelect: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdSplat: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdBoolNot: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdMemset: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdMemcpy: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdSlice: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdBreakpoint: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdReturnAddress: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdFrameAddress: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdFrameHandle: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdFrameType: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdFrameSize: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdAlignOf: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdOverflowOp: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdTestErr: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdUnwrapErrCode: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdUnwrapErrPayload: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdFnProto: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdTestComptime: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdPtrCast: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdBitCast: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdPtrToInt: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdIntToPtr: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdIntToEnum: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdIntToErr: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdErrToInt: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdCheckSwitchProngsUnderNo: - case Stage1ZirInstIdCheckSwitchProngsUnderYes: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdCheckStatementIsVoid: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdTypeName: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdTagName: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdPtrType: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdPtrTypeSimple: - case Stage1ZirInstIdPtrTypeSimpleConst: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdDeclRef: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdPanic: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdFieldParentPtr: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdOffsetOf: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdBitOffsetOf: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdTypeInfo: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdType: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdHasField: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdSetEvalBranchQuota: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdAlignCast: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdImplicitCast: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdResolveResult: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdResetResult: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdSetAlignStack: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdArgTypeAllowVarFalse: - case Stage1ZirInstIdArgTypeAllowVarTrue: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdExport: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdExtern: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdErrorReturnTrace: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdErrorUnion: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdAtomicRmw: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdSaveErrRetAddr: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdAddImplicitReturnType: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdFloatOp: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdMulAdd: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdAtomicLoad: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdAtomicStore: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdEnumToInt: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdCheckRuntimeScope: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdHasDecl: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdUndeclaredIdent: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdAlloca: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdEndExpr: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdUnionInitNamedField: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdSuspendBegin: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdSuspendFinish: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdResume: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdAwait: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdSpillBegin: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdSpillEnd: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdCallArgs: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdWasmMemorySize: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdWasmMemoryGrow: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdSrc: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdPrefetch: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1ZirInstIdAddrSpaceCast: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - } - zig_unreachable(); -} - - -bool ir_should_inline(Stage1Zir *exec, Scope *scope) { - if (exec->is_inline) - return true; - - while (scope != nullptr) { - if (scope->id == ScopeIdCompTime) - return true; - if (scope->id == ScopeIdTypeOf) - return false; - if (scope->id == ScopeIdFnDef) - break; - scope = scope->parent; - } - return false; -} - -static void ir_instruction_append(Stage1ZirBasicBlock *basic_block, Stage1ZirInst *instruction) { - assert(basic_block); - assert(instruction); - basic_block->instruction_list.append(instruction); -} - -static size_t irb_next_debug_id(Stage1AstGen *ag) { - size_t result = ag->next_debug_id; - ag->next_debug_id += 1; - return result; -} - -static void ir_ref_bb(Stage1ZirBasicBlock *bb) { - bb->ref_count += 1; -} - -static void ir_ref_instruction(Stage1ZirInst *instruction, Stage1ZirBasicBlock *cur_bb) { - assert(instruction->id != Stage1ZirInstIdInvalid); - instruction->ref_count += 1; - if (instruction->owner_bb != cur_bb && !instr_is_unreachable(instruction) - && instruction->id != Stage1ZirInstIdConst) - { - ir_ref_bb(instruction->owner_bb); - } -} - -static Stage1ZirBasicBlock *ir_create_basic_block(Stage1AstGen *ag, Scope *scope, const char *name_hint) { - Stage1ZirBasicBlock *result = heap::c_allocator.create(); - result->scope = scope; - result->name_hint = name_hint; - result->debug_id = irb_next_debug_id(ag); - result->index = UINT32_MAX; // set later - return result; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstDeclVar *) { - return Stage1ZirInstIdDeclVar; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstBr *) { - return Stage1ZirInstIdBr; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstCondBr *) { - return Stage1ZirInstIdCondBr; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstSwitchBr *) { - return Stage1ZirInstIdSwitchBr; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstSwitchVar *) { - return Stage1ZirInstIdSwitchVar; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstSwitchElseVar *) { - return Stage1ZirInstIdSwitchElseVar; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstSwitchTarget *) { - return Stage1ZirInstIdSwitchTarget; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstPhi *) { - return Stage1ZirInstIdPhi; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstUnOp *) { - return Stage1ZirInstIdUnOp; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstBinOp *) { - return Stage1ZirInstIdBinOp; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstMergeErrSets *) { - return Stage1ZirInstIdMergeErrSets; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstLoadPtr *) { - return Stage1ZirInstIdLoadPtr; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstStorePtr *) { - return Stage1ZirInstIdStorePtr; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstFieldPtr *) { - return Stage1ZirInstIdFieldPtr; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstElemPtr *) { - return Stage1ZirInstIdElemPtr; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstVarPtr *) { - return Stage1ZirInstIdVarPtr; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstCall *) { - return Stage1ZirInstIdCall; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstCallArgs *) { - return Stage1ZirInstIdCallArgs; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstCallExtra *) { - return Stage1ZirInstIdCallExtra; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstAsyncCallExtra *) { - return Stage1ZirInstIdAsyncCallExtra; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstConst *) { - return Stage1ZirInstIdConst; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstReturn *) { - return Stage1ZirInstIdReturn; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstContainerInitList *) { - return Stage1ZirInstIdContainerInitList; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstContainerInitFields *) { - return Stage1ZirInstIdContainerInitFields; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstUnreachable *) { - return Stage1ZirInstIdUnreachable; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstTypeOf *) { - return Stage1ZirInstIdTypeOf; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstSetCold *) { - return Stage1ZirInstIdSetCold; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstSetRuntimeSafety *) { - return Stage1ZirInstIdSetRuntimeSafety; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstSetFloatMode *) { - return Stage1ZirInstIdSetFloatMode; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstArrayType *) { - return Stage1ZirInstIdArrayType; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstAnyFrameType *) { - return Stage1ZirInstIdAnyFrameType; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstSliceType *) { - return Stage1ZirInstIdSliceType; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstAsm *) { - return Stage1ZirInstIdAsm; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstSizeOf *) { - return Stage1ZirInstIdSizeOf; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstTestNonNull *) { - return Stage1ZirInstIdTestNonNull; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstOptionalUnwrapPtr *) { - return Stage1ZirInstIdOptionalUnwrapPtr; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstClz *) { - return Stage1ZirInstIdClz; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstCtz *) { - return Stage1ZirInstIdCtz; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstPopCount *) { - return Stage1ZirInstIdPopCount; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstBswap *) { - return Stage1ZirInstIdBswap; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstBitReverse *) { - return Stage1ZirInstIdBitReverse; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstImport *) { - return Stage1ZirInstIdImport; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstCImport *) { - return Stage1ZirInstIdCImport; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstCInclude *) { - return Stage1ZirInstIdCInclude; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstCDefine *) { - return Stage1ZirInstIdCDefine; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstCUndef *) { - return Stage1ZirInstIdCUndef; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstRef *) { - return Stage1ZirInstIdRef; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstCompileErr *) { - return Stage1ZirInstIdCompileErr; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstCompileLog *) { - return Stage1ZirInstIdCompileLog; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstErrName *) { - return Stage1ZirInstIdErrName; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstEmbedFile *) { - return Stage1ZirInstIdEmbedFile; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstCmpxchg *) { - return Stage1ZirInstIdCmpxchg; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstFence *) { - return Stage1ZirInstIdFence; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstReduce *) { - return Stage1ZirInstIdReduce; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstTruncate *) { - return Stage1ZirInstIdTruncate; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstIntCast *) { - return Stage1ZirInstIdIntCast; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstFloatCast *) { - return Stage1ZirInstIdFloatCast; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstIntToFloat *) { - return Stage1ZirInstIdIntToFloat; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstFloatToInt *) { - return Stage1ZirInstIdFloatToInt; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstBoolToInt *) { - return Stage1ZirInstIdBoolToInt; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstVectorType *) { - return Stage1ZirInstIdVectorType; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstShuffleVector *) { - return Stage1ZirInstIdShuffleVector; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstSelect *) { - return Stage1ZirInstIdSelect; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstSplat *) { - return Stage1ZirInstIdSplat; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstBoolNot *) { - return Stage1ZirInstIdBoolNot; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstMemset *) { - return Stage1ZirInstIdMemset; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstMemcpy *) { - return Stage1ZirInstIdMemcpy; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstSlice *) { - return Stage1ZirInstIdSlice; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstBreakpoint *) { - return Stage1ZirInstIdBreakpoint; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstReturnAddress *) { - return Stage1ZirInstIdReturnAddress; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstFrameAddress *) { - return Stage1ZirInstIdFrameAddress; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstFrameHandle *) { - return Stage1ZirInstIdFrameHandle; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstFrameType *) { - return Stage1ZirInstIdFrameType; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstFrameSize *) { - return Stage1ZirInstIdFrameSize; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstAlignOf *) { - return Stage1ZirInstIdAlignOf; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstOverflowOp *) { - return Stage1ZirInstIdOverflowOp; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstTestErr *) { - return Stage1ZirInstIdTestErr; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstMulAdd *) { - return Stage1ZirInstIdMulAdd; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstFloatOp *) { - return Stage1ZirInstIdFloatOp; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstUnwrapErrCode *) { - return Stage1ZirInstIdUnwrapErrCode; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstUnwrapErrPayload *) { - return Stage1ZirInstIdUnwrapErrPayload; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstFnProto *) { - return Stage1ZirInstIdFnProto; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstTestComptime *) { - return Stage1ZirInstIdTestComptime; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstPtrCast *) { - return Stage1ZirInstIdPtrCast; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstBitCast *) { - return Stage1ZirInstIdBitCast; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstIntToPtr *) { - return Stage1ZirInstIdIntToPtr; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstPtrToInt *) { - return Stage1ZirInstIdPtrToInt; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstIntToEnum *) { - return Stage1ZirInstIdIntToEnum; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstEnumToInt *) { - return Stage1ZirInstIdEnumToInt; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstIntToErr *) { - return Stage1ZirInstIdIntToErr; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstErrToInt *) { - return Stage1ZirInstIdErrToInt; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstCheckStatementIsVoid *) { - return Stage1ZirInstIdCheckStatementIsVoid; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstTypeName *) { - return Stage1ZirInstIdTypeName; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstDeclRef *) { - return Stage1ZirInstIdDeclRef; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstPanic *) { - return Stage1ZirInstIdPanic; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstTagName *) { - return Stage1ZirInstIdTagName; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstFieldParentPtr *) { - return Stage1ZirInstIdFieldParentPtr; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstOffsetOf *) { - return Stage1ZirInstIdOffsetOf; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstBitOffsetOf *) { - return Stage1ZirInstIdBitOffsetOf; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstTypeInfo *) { - return Stage1ZirInstIdTypeInfo; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstType *) { - return Stage1ZirInstIdType; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstHasField *) { - return Stage1ZirInstIdHasField; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstSetEvalBranchQuota *) { - return Stage1ZirInstIdSetEvalBranchQuota; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstPtrType *) { - return Stage1ZirInstIdPtrType; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstAlignCast *) { - return Stage1ZirInstIdAlignCast; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstImplicitCast *) { - return Stage1ZirInstIdImplicitCast; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstResolveResult *) { - return Stage1ZirInstIdResolveResult; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstResetResult *) { - return Stage1ZirInstIdResetResult; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstSetAlignStack *) { - return Stage1ZirInstIdSetAlignStack; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstExport *) { - return Stage1ZirInstIdExport; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstExtern *) { - return Stage1ZirInstIdExtern; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstErrorReturnTrace *) { - return Stage1ZirInstIdErrorReturnTrace; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstErrorUnion *) { - return Stage1ZirInstIdErrorUnion; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstAtomicRmw *) { - return Stage1ZirInstIdAtomicRmw; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstAtomicLoad *) { - return Stage1ZirInstIdAtomicLoad; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstAtomicStore *) { - return Stage1ZirInstIdAtomicStore; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstSaveErrRetAddr *) { - return Stage1ZirInstIdSaveErrRetAddr; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstAddImplicitReturnType *) { - return Stage1ZirInstIdAddImplicitReturnType; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstErrSetCast *) { - return Stage1ZirInstIdErrSetCast; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstCheckRuntimeScope *) { - return Stage1ZirInstIdCheckRuntimeScope; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstHasDecl *) { - return Stage1ZirInstIdHasDecl; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstUndeclaredIdent *) { - return Stage1ZirInstIdUndeclaredIdent; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstAlloca *) { - return Stage1ZirInstIdAlloca; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstEndExpr *) { - return Stage1ZirInstIdEndExpr; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstUnionInitNamedField *) { - return Stage1ZirInstIdUnionInitNamedField; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstSuspendBegin *) { - return Stage1ZirInstIdSuspendBegin; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstSuspendFinish *) { - return Stage1ZirInstIdSuspendFinish; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstAwait *) { - return Stage1ZirInstIdAwait; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstResume *) { - return Stage1ZirInstIdResume; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstSpillBegin *) { - return Stage1ZirInstIdSpillBegin; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstSpillEnd *) { - return Stage1ZirInstIdSpillEnd; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstWasmMemorySize *) { - return Stage1ZirInstIdWasmMemorySize; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstWasmMemoryGrow *) { - return Stage1ZirInstIdWasmMemoryGrow; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstSrc *) { - return Stage1ZirInstIdSrc; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstPrefetch *) { - return Stage1ZirInstIdPrefetch; -} - -static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstAddrSpaceCast *) { - return Stage1ZirInstIdAddrSpaceCast; -} - -template -static T *ir_create_instruction(Stage1AstGen *ag, Scope *scope, AstNode *source_node) { - T *special_instruction = heap::c_allocator.create(); - special_instruction->base.id = ir_inst_id(special_instruction); - special_instruction->base.scope = scope; - special_instruction->base.source_node = source_node; - special_instruction->base.debug_id = irb_next_debug_id(ag); - special_instruction->base.owner_bb = ag->current_basic_block; - return special_instruction; -} - -template -static T *ir_build_instruction(Stage1AstGen *ag, Scope *scope, AstNode *source_node) { - T *special_instruction = ir_create_instruction(ag, scope, source_node); - ir_instruction_append(ag->current_basic_block, &special_instruction->base); - return special_instruction; -} - -static Stage1ZirInst *ir_build_cond_br(Stage1AstGen *ag, Scope *scope, AstNode *source_node, Stage1ZirInst *condition, - Stage1ZirBasicBlock *then_block, Stage1ZirBasicBlock *else_block, Stage1ZirInst *is_comptime) -{ - Stage1ZirInstCondBr *inst = ir_build_instruction(ag, scope, source_node); - inst->condition = condition; - inst->then_block = then_block; - inst->else_block = else_block; - inst->is_comptime = is_comptime; - - ir_ref_instruction(condition, ag->current_basic_block); - ir_ref_bb(then_block); - ir_ref_bb(else_block); - if (is_comptime != nullptr) ir_ref_instruction(is_comptime, ag->current_basic_block); - - return &inst->base; -} - -static Stage1ZirInst *ir_build_return_src(Stage1AstGen *ag, Scope *scope, AstNode *source_node, Stage1ZirInst *operand) { - Stage1ZirInstReturn *inst = ir_build_instruction(ag, scope, source_node); - inst->operand = operand; - - if (operand != nullptr) ir_ref_instruction(operand, ag->current_basic_block); - - return &inst->base; -} - -static Stage1ZirInst *ir_build_const_void(Stage1AstGen *ag, Scope *scope, AstNode *source_node) { - Stage1ZirInstConst *const_instruction = ir_create_instruction(ag, scope, source_node); - ir_instruction_append(ag->current_basic_block, &const_instruction->base); - const_instruction->value = ag->codegen->intern.for_void(); - return &const_instruction->base; -} - -static Stage1ZirInst *ir_build_const_undefined(Stage1AstGen *ag, Scope *scope, AstNode *source_node) { - Stage1ZirInstConst *const_instruction = ir_create_instruction(ag, scope, source_node); - ir_instruction_append(ag->current_basic_block, &const_instruction->base); - const_instruction->value = ag->codegen->intern.for_undefined(); - const_instruction->value->special = ConstValSpecialUndef; - return &const_instruction->base; -} - -static Stage1ZirInst *ir_build_const_uint(Stage1AstGen *ag, Scope *scope, AstNode *source_node, uint64_t value) { - Stage1ZirInstConst *const_instruction = ir_build_instruction(ag, scope, source_node); - const_instruction->value = ag->codegen->pass1_arena->create(); - const_instruction->value->type = ag->codegen->builtin_types.entry_num_lit_int; - const_instruction->value->special = ConstValSpecialStatic; - bigint_init_unsigned(&const_instruction->value->data.x_bigint, value); - return &const_instruction->base; -} - -static Stage1ZirInst *ir_build_const_bigint(Stage1AstGen *ag, Scope *scope, AstNode *source_node, - BigInt bigint) -{ - Stage1ZirInstConst *const_instruction = ir_build_instruction(ag, scope, source_node); - const_instruction->value = ag->codegen->pass1_arena->create(); - const_instruction->value->type = ag->codegen->builtin_types.entry_num_lit_int; - const_instruction->value->special = ConstValSpecialStatic; - const_instruction->value->data.x_bigint = bigint; - return &const_instruction->base; -} - -static Stage1ZirInst *ir_build_const_bigfloat(Stage1AstGen *ag, Scope *scope, AstNode *source_node, - BigFloat bigfloat) -{ - Stage1ZirInstConst *const_instruction = ir_build_instruction(ag, scope, source_node); - const_instruction->value = ag->codegen->pass1_arena->create(); - const_instruction->value->type = ag->codegen->builtin_types.entry_num_lit_float; - const_instruction->value->special = ConstValSpecialStatic; - const_instruction->value->data.x_bigfloat = bigfloat; - return &const_instruction->base; -} - -static Stage1ZirInst *ir_build_const_null(Stage1AstGen *ag, Scope *scope, AstNode *source_node) { - Stage1ZirInstConst *const_instruction = ir_create_instruction(ag, scope, source_node); - ir_instruction_append(ag->current_basic_block, &const_instruction->base); - const_instruction->value = ag->codegen->intern.for_null(); - return &const_instruction->base; -} - -static Stage1ZirInst *ir_build_const_usize(Stage1AstGen *ag, Scope *scope, AstNode *source_node, uint64_t value) { - Stage1ZirInstConst *const_instruction = ir_build_instruction(ag, scope, source_node); - const_instruction->value = ag->codegen->pass1_arena->create(); - const_instruction->value->type = ag->codegen->builtin_types.entry_usize; - const_instruction->value->special = ConstValSpecialStatic; - bigint_init_unsigned(&const_instruction->value->data.x_bigint, value); - return &const_instruction->base; -} - -static Stage1ZirInst *ir_create_const_type(Stage1AstGen *ag, Scope *scope, AstNode *source_node, - ZigType *type_entry) -{ - Stage1ZirInstConst *const_instruction = ir_create_instruction(ag, scope, source_node); - const_instruction->value = ag->codegen->pass1_arena->create(); - const_instruction->value->type = ag->codegen->builtin_types.entry_type; - const_instruction->value->special = ConstValSpecialStatic; - const_instruction->value->data.x_type = type_entry; - return &const_instruction->base; -} - -static Stage1ZirInst *ir_build_const_type(Stage1AstGen *ag, Scope *scope, AstNode *source_node, - ZigType *type_entry) -{ - Stage1ZirInst *instruction = ir_create_const_type(ag, scope, source_node, type_entry); - ir_instruction_append(ag->current_basic_block, instruction); - return instruction; -} - -static Stage1ZirInst *ir_build_const_import(Stage1AstGen *ag, Scope *scope, AstNode *source_node, ZigType *import) { - Stage1ZirInstConst *const_instruction = ir_build_instruction(ag, scope, source_node); - const_instruction->value = ag->codegen->pass1_arena->create(); - const_instruction->value->type = ag->codegen->builtin_types.entry_type; - const_instruction->value->special = ConstValSpecialStatic; - const_instruction->value->data.x_type = import; - return &const_instruction->base; -} - -static Stage1ZirInst *ir_build_const_bool(Stage1AstGen *ag, Scope *scope, AstNode *source_node, bool value) { - Stage1ZirInstConst *const_instruction = ir_build_instruction(ag, scope, source_node); - const_instruction->value = ag->codegen->pass1_arena->create(); - const_instruction->value->type = ag->codegen->builtin_types.entry_bool; - const_instruction->value->special = ConstValSpecialStatic; - const_instruction->value->data.x_bool = value; - return &const_instruction->base; -} - -static Stage1ZirInst *ir_build_const_enum_literal(Stage1AstGen *ag, Scope *scope, AstNode *source_node, Buf *name) { - Stage1ZirInstConst *const_instruction = ir_build_instruction(ag, scope, source_node); - const_instruction->value = ag->codegen->pass1_arena->create(); - const_instruction->value->type = ag->codegen->builtin_types.entry_enum_literal; - const_instruction->value->special = ConstValSpecialStatic; - const_instruction->value->data.x_enum_literal = name; - return &const_instruction->base; -} - -// Consumes `str`. -static Stage1ZirInst *ir_create_const_str_lit(Stage1AstGen *ag, Scope *scope, AstNode *source_node, Buf *str) { - Stage1ZirInstConst *const_instruction = ir_create_instruction(ag, scope, source_node); - const_instruction->value = ag->codegen->pass1_arena->create(); - init_const_str_lit(ag->codegen, const_instruction->value, str, true); - - return &const_instruction->base; -} - -// Consumes `str`. -static Stage1ZirInst *ir_build_const_str_lit(Stage1AstGen *ag, Scope *scope, AstNode *source_node, Buf *str) { - Stage1ZirInst *instruction = ir_create_const_str_lit(ag, scope, source_node, str); - ir_instruction_append(ag->current_basic_block, instruction); - return instruction; -} - -static Stage1ZirInst *ir_build_bin_op(Stage1AstGen *ag, Scope *scope, AstNode *source_node, IrBinOp op_id, - Stage1ZirInst *op1, Stage1ZirInst *op2, bool safety_check_on) -{ - Stage1ZirInstBinOp *inst = ir_build_instruction(ag, scope, source_node); - inst->op_id = op_id; - inst->op1 = op1; - inst->op2 = op2; - inst->safety_check_on = safety_check_on; - - ir_ref_instruction(op1, ag->current_basic_block); - ir_ref_instruction(op2, ag->current_basic_block); - - return &inst->base; -} - -static Stage1ZirInst *ir_build_merge_err_sets(Stage1AstGen *ag, Scope *scope, AstNode *source_node, - Stage1ZirInst *op1, Stage1ZirInst *op2, Buf *type_name) -{ - Stage1ZirInstMergeErrSets *inst = ir_build_instruction(ag, scope, source_node); - inst->op1 = op1; - inst->op2 = op2; - inst->type_name = type_name; - - ir_ref_instruction(op1, ag->current_basic_block); - ir_ref_instruction(op2, ag->current_basic_block); - - return &inst->base; -} - -static Stage1ZirInst *ir_build_var_ptr_x(Stage1AstGen *ag, Scope *scope, AstNode *source_node, ZigVar *var, - ScopeFnDef *crossed_fndef_scope) -{ - Stage1ZirInstVarPtr *instruction = ir_build_instruction(ag, scope, source_node); - instruction->var = var; - instruction->crossed_fndef_scope = crossed_fndef_scope; - - var->ref_count += 1; - - return &instruction->base; -} - -static Stage1ZirInst *ir_build_var_ptr(Stage1AstGen *ag, Scope *scope, AstNode *source_node, ZigVar *var) { - return ir_build_var_ptr_x(ag, scope, source_node, var, nullptr); -} - -static Stage1ZirInst *ir_build_elem_ptr(Stage1AstGen *ag, Scope *scope, AstNode *source_node, - Stage1ZirInst *array_ptr, Stage1ZirInst *elem_index, bool safety_check_on, PtrLen ptr_len, - AstNode *init_array_type_source_node) -{ - Stage1ZirInstElemPtr *instruction = ir_build_instruction(ag, scope, source_node); - instruction->array_ptr = array_ptr; - instruction->elem_index = elem_index; - instruction->safety_check_on = safety_check_on; - instruction->ptr_len = ptr_len; - instruction->init_array_type_source_node = init_array_type_source_node; - - ir_ref_instruction(array_ptr, ag->current_basic_block); - ir_ref_instruction(elem_index, ag->current_basic_block); - - return &instruction->base; -} - -static Stage1ZirInst *ir_build_field_ptr_instruction(Stage1AstGen *ag, Scope *scope, AstNode *source_node, - Stage1ZirInst *container_ptr, Stage1ZirInst *field_name_expr, bool initializing) -{ - Stage1ZirInstFieldPtr *instruction = ir_build_instruction(ag, scope, source_node); - instruction->container_ptr = container_ptr; - instruction->field_name_buffer = nullptr; - instruction->field_name_expr = field_name_expr; - instruction->initializing = initializing; - - ir_ref_instruction(container_ptr, ag->current_basic_block); - ir_ref_instruction(field_name_expr, ag->current_basic_block); - - return &instruction->base; -} - -static Stage1ZirInst *ir_build_field_ptr(Stage1AstGen *ag, Scope *scope, AstNode *source_node, - Stage1ZirInst *container_ptr, Buf *field_name, bool initializing) -{ - Stage1ZirInstFieldPtr *instruction = ir_build_instruction(ag, scope, source_node); - instruction->container_ptr = container_ptr; - instruction->field_name_buffer = field_name; - instruction->field_name_expr = nullptr; - instruction->initializing = initializing; - - ir_ref_instruction(container_ptr, ag->current_basic_block); - - return &instruction->base; -} - -static Stage1ZirInst *ir_build_has_field(Stage1AstGen *ag, Scope *scope, AstNode *source_node, - Stage1ZirInst *container_type, Stage1ZirInst *field_name) -{ - Stage1ZirInstHasField *instruction = ir_build_instruction(ag, scope, source_node); - instruction->container_type = container_type; - instruction->field_name = field_name; - - ir_ref_instruction(container_type, ag->current_basic_block); - ir_ref_instruction(field_name, ag->current_basic_block); - - return &instruction->base; -} - -static Stage1ZirInst *ir_build_call_extra(Stage1AstGen *ag, Scope *scope, AstNode *source_node, - Stage1ZirInst *options, Stage1ZirInst *fn_ref, Stage1ZirInst *args, ResultLoc *result_loc) -{ - Stage1ZirInstCallExtra *call_instruction = ir_build_instruction(ag, scope, source_node); - call_instruction->options = options; - call_instruction->fn_ref = fn_ref; - call_instruction->args = args; - call_instruction->result_loc = result_loc; - - ir_ref_instruction(options, ag->current_basic_block); - ir_ref_instruction(fn_ref, ag->current_basic_block); - ir_ref_instruction(args, ag->current_basic_block); - - return &call_instruction->base; -} - -static Stage1ZirInst *ir_build_async_call_extra(Stage1AstGen *ag, Scope *scope, AstNode *source_node, - CallModifier modifier, Stage1ZirInst *fn_ref, Stage1ZirInst *ret_ptr, Stage1ZirInst *new_stack, Stage1ZirInst *args, ResultLoc *result_loc) -{ - Stage1ZirInstAsyncCallExtra *call_instruction = ir_build_instruction(ag, scope, source_node); - call_instruction->modifier = modifier; - call_instruction->fn_ref = fn_ref; - call_instruction->ret_ptr = ret_ptr; - call_instruction->new_stack = new_stack; - call_instruction->args = args; - call_instruction->result_loc = result_loc; - - ir_ref_instruction(fn_ref, ag->current_basic_block); - if (ret_ptr != nullptr) ir_ref_instruction(ret_ptr, ag->current_basic_block); - ir_ref_instruction(new_stack, ag->current_basic_block); - ir_ref_instruction(args, ag->current_basic_block); - - return &call_instruction->base; -} - -static Stage1ZirInst *ir_build_call_args(Stage1AstGen *ag, Scope *scope, AstNode *source_node, - Stage1ZirInst *options, Stage1ZirInst *fn_ref, Stage1ZirInst **args_ptr, size_t args_len, - ResultLoc *result_loc) -{ - Stage1ZirInstCallArgs *call_instruction = ir_build_instruction(ag, scope, source_node); - call_instruction->options = options; - call_instruction->fn_ref = fn_ref; - call_instruction->args_ptr = args_ptr; - call_instruction->args_len = args_len; - call_instruction->result_loc = result_loc; - - ir_ref_instruction(options, ag->current_basic_block); - ir_ref_instruction(fn_ref, ag->current_basic_block); - for (size_t i = 0; i < args_len; i += 1) - ir_ref_instruction(args_ptr[i], ag->current_basic_block); - - return &call_instruction->base; -} - -static Stage1ZirInst *ir_build_call_src(Stage1AstGen *ag, Scope *scope, AstNode *source_node, - ZigFn *fn_entry, Stage1ZirInst *fn_ref, size_t arg_count, Stage1ZirInst **args, - Stage1ZirInst *ret_ptr, CallModifier modifier, bool is_async_call_builtin, - Stage1ZirInst *new_stack, ResultLoc *result_loc) -{ - Stage1ZirInstCall *call_instruction = ir_build_instruction(ag, scope, source_node); - call_instruction->fn_entry = fn_entry; - call_instruction->fn_ref = fn_ref; - call_instruction->args = args; - call_instruction->arg_count = arg_count; - call_instruction->modifier = modifier; - call_instruction->is_async_call_builtin = is_async_call_builtin; - call_instruction->new_stack = new_stack; - call_instruction->result_loc = result_loc; - call_instruction->ret_ptr = ret_ptr; - - if (fn_ref != nullptr) ir_ref_instruction(fn_ref, ag->current_basic_block); - for (size_t i = 0; i < arg_count; i += 1) - ir_ref_instruction(args[i], ag->current_basic_block); - if (ret_ptr != nullptr) ir_ref_instruction(ret_ptr, ag->current_basic_block); - if (new_stack != nullptr) ir_ref_instruction(new_stack, ag->current_basic_block); - - return &call_instruction->base; -} - -static Stage1ZirInst *ir_build_phi(Stage1AstGen *ag, Scope *scope, AstNode *source_node, bool merge_comptime, - size_t incoming_count, Stage1ZirBasicBlock **incoming_blocks, Stage1ZirInst **incoming_values, - ResultLocPeerParent *peer_parent) -{ - assert(incoming_count != 0); - assert(incoming_count != SIZE_MAX); - - Stage1ZirInstPhi *phi_instruction = ir_build_instruction(ag, scope, source_node); - phi_instruction->incoming_count = incoming_count; - phi_instruction->incoming_blocks = incoming_blocks; - phi_instruction->incoming_values = incoming_values; - phi_instruction->peer_parent = peer_parent; - phi_instruction->merge_comptime = merge_comptime; - - for (size_t i = 0; i < incoming_count; i += 1) { - ir_ref_bb(incoming_blocks[i]); - ir_ref_instruction(incoming_values[i], ag->current_basic_block); - } - - return &phi_instruction->base; -} - -static Stage1ZirInst *ir_build_br(Stage1AstGen *ag, Scope *scope, AstNode *source_node, - Stage1ZirBasicBlock *dest_block, Stage1ZirInst *is_comptime) -{ - Stage1ZirInstBr *inst = ir_build_instruction(ag, scope, source_node); - inst->dest_block = dest_block; - inst->is_comptime = is_comptime; - - ir_ref_bb(dest_block); - if (is_comptime) ir_ref_instruction(is_comptime, ag->current_basic_block); - - return &inst->base; -} - -static Stage1ZirInst *ir_build_ptr_type_simple(Stage1AstGen *ag, Scope *scope, AstNode *source_node, - Stage1ZirInst *child_type, bool is_const) -{ - Stage1ZirInstPtrTypeSimple *inst = heap::c_allocator.create(); - inst->base.id = is_const ? Stage1ZirInstIdPtrTypeSimpleConst : Stage1ZirInstIdPtrTypeSimple; - inst->base.scope = scope; - inst->base.source_node = source_node; - inst->base.debug_id = irb_next_debug_id(ag); - inst->base.owner_bb = ag->current_basic_block; - ir_instruction_append(ag->current_basic_block, &inst->base); - - inst->child_type = child_type; - - ir_ref_instruction(child_type, ag->current_basic_block); - - return &inst->base; -} - -static Stage1ZirInst *ir_build_ptr_type(Stage1AstGen *ag, Scope *scope, AstNode *source_node, - Stage1ZirInst *child_type, bool is_const, bool is_volatile, PtrLen ptr_len, - Stage1ZirInst *sentinel, Stage1ZirInst *align_value, - uint32_t bit_offset_start, uint32_t host_int_bytes, bool is_allow_zero) -{ - if (!is_volatile && ptr_len == PtrLenSingle && sentinel == nullptr && align_value == nullptr && - bit_offset_start == 0 && host_int_bytes == 0 && is_allow_zero == 0) - { - return ir_build_ptr_type_simple(ag, scope, source_node, child_type, is_const); - } - - Stage1ZirInstPtrType *inst = ir_build_instruction(ag, scope, source_node); - inst->sentinel = sentinel; - inst->align_value = align_value; - inst->child_type = child_type; - inst->is_const = is_const; - inst->is_volatile = is_volatile; - inst->ptr_len = ptr_len; - inst->bit_offset_start = bit_offset_start; - inst->host_int_bytes = host_int_bytes; - inst->is_allow_zero = is_allow_zero; - - if (sentinel) ir_ref_instruction(sentinel, ag->current_basic_block); - if (align_value) ir_ref_instruction(align_value, ag->current_basic_block); - ir_ref_instruction(child_type, ag->current_basic_block); - - return &inst->base; -} - -static Stage1ZirInst *ir_build_un_op_lval(Stage1AstGen *ag, Scope *scope, AstNode *source_node, IrUnOp op_id, - Stage1ZirInst *value, LVal lval, ResultLoc *result_loc) -{ - Stage1ZirInstUnOp *instruction = ir_build_instruction(ag, scope, source_node); - instruction->op_id = op_id; - instruction->value = value; - instruction->lval = lval; - instruction->result_loc = result_loc; - - ir_ref_instruction(value, ag->current_basic_block); - - return &instruction->base; -} - -static Stage1ZirInst *ir_build_un_op(Stage1AstGen *ag, Scope *scope, AstNode *source_node, IrUnOp op_id, - Stage1ZirInst *value) -{ - return ir_build_un_op_lval(ag, scope, source_node, op_id, value, LValNone, nullptr); -} - -static Stage1ZirInst *ir_build_container_init_list(Stage1AstGen *ag, Scope *scope, AstNode *source_node, - size_t item_count, Stage1ZirInst **elem_result_loc_list, Stage1ZirInst *result_loc, - AstNode *init_array_type_source_node) -{ - Stage1ZirInstContainerInitList *container_init_list_instruction = - ir_build_instruction(ag, scope, source_node); - container_init_list_instruction->item_count = item_count; - container_init_list_instruction->elem_result_loc_list = elem_result_loc_list; - container_init_list_instruction->result_loc = result_loc; - container_init_list_instruction->init_array_type_source_node = init_array_type_source_node; - - for (size_t i = 0; i < item_count; i += 1) { - ir_ref_instruction(elem_result_loc_list[i], ag->current_basic_block); - } - if (result_loc != nullptr) ir_ref_instruction(result_loc, ag->current_basic_block); - - return &container_init_list_instruction->base; -} - -static Stage1ZirInst *ir_build_container_init_fields(Stage1AstGen *ag, Scope *scope, AstNode *source_node, - size_t field_count, Stage1ZirInstContainerInitFieldsField *fields, Stage1ZirInst *result_loc) -{ - Stage1ZirInstContainerInitFields *container_init_fields_instruction = - ir_build_instruction(ag, scope, source_node); - container_init_fields_instruction->field_count = field_count; - container_init_fields_instruction->fields = fields; - container_init_fields_instruction->result_loc = result_loc; - - for (size_t i = 0; i < field_count; i += 1) { - ir_ref_instruction(fields[i].result_loc, ag->current_basic_block); - } - if (result_loc != nullptr) ir_ref_instruction(result_loc, ag->current_basic_block); - - return &container_init_fields_instruction->base; -} - -static Stage1ZirInst *ir_build_unreachable(Stage1AstGen *ag, Scope *scope, AstNode *source_node) { - Stage1ZirInstUnreachable *inst = ir_build_instruction(ag, scope, source_node); - return &inst->base; -} - -static Stage1ZirInstStorePtr *ir_build_store_ptr(Stage1AstGen *ag, Scope *scope, AstNode *source_node, - Stage1ZirInst *ptr, Stage1ZirInst *value) -{ - Stage1ZirInstStorePtr *instruction = ir_build_instruction(ag, scope, source_node); - instruction->ptr = ptr; - instruction->value = value; - - ir_ref_instruction(ptr, ag->current_basic_block); - ir_ref_instruction(value, ag->current_basic_block); - - return instruction; -} - -static Stage1ZirInst *ir_build_var_decl_src(Stage1AstGen *ag, Scope *scope, AstNode *source_node, - ZigVar *var, Stage1ZirInst *align_value, Stage1ZirInst *ptr) -{ - Stage1ZirInstDeclVar *inst = ir_build_instruction(ag, scope, source_node); - inst->var = var; - inst->align_value = align_value; - inst->ptr = ptr; - - if (align_value != nullptr) ir_ref_instruction(align_value, ag->current_basic_block); - ir_ref_instruction(ptr, ag->current_basic_block); - - return &inst->base; -} - -static Stage1ZirInst *ir_build_export(Stage1AstGen *ag, Scope *scope, AstNode *source_node, - Stage1ZirInst *target, Stage1ZirInst *options) -{ - Stage1ZirInstExport *export_instruction = ir_build_instruction( - ag, scope, source_node); - export_instruction->target = target; - export_instruction->options = options; - - ir_ref_instruction(target, ag->current_basic_block); - ir_ref_instruction(options, ag->current_basic_block); - - return &export_instruction->base; -} - -static Stage1ZirInst *ir_build_extern(Stage1AstGen *ag, Scope *scope, AstNode *source_node, - Stage1ZirInst *type, Stage1ZirInst *options) -{ - Stage1ZirInstExtern *extern_instruction = ir_build_instruction( - ag, scope, source_node); - extern_instruction->type = type; - extern_instruction->options = options; - - ir_ref_instruction(type, ag->current_basic_block); - ir_ref_instruction(options, ag->current_basic_block); - - return &extern_instruction->base; -} - -static Stage1ZirInst *ir_build_load_ptr(Stage1AstGen *ag, Scope *scope, AstNode *source_node, Stage1ZirInst *ptr) { - Stage1ZirInstLoadPtr *instruction = ir_build_instruction(ag, scope, source_node); - instruction->ptr = ptr; - - ir_ref_instruction(ptr, ag->current_basic_block); - - return &instruction->base; -} - -static Stage1ZirInst *ir_build_typeof_n(Stage1AstGen *ag, Scope *scope, AstNode *source_node, - Stage1ZirInst **values, size_t value_count) -{ - assert(value_count >= 2); - - Stage1ZirInstTypeOf *instruction = ir_build_instruction(ag, scope, source_node); - instruction->value.list = values; - instruction->value_count = value_count; - - for (size_t i = 0; i < value_count; i++) - ir_ref_instruction(values[i], ag->current_basic_block); - - return &instruction->base; -} - -static Stage1ZirInst *ir_build_typeof_1(Stage1AstGen *ag, Scope *scope, AstNode *source_node, Stage1ZirInst *value) { - Stage1ZirInstTypeOf *instruction = ir_build_instruction(ag, scope, source_node); - instruction->value.scalar = value; - - ir_ref_instruction(value, ag->current_basic_block); - - return &instruction->base; -} - -static Stage1ZirInst *ir_build_set_cold(Stage1AstGen *ag, Scope *scope, AstNode *source_node, Stage1ZirInst *is_cold) { - Stage1ZirInstSetCold *instruction = ir_build_instruction(ag, scope, source_node); - instruction->is_cold = is_cold; - - ir_ref_instruction(is_cold, ag->current_basic_block); - - return &instruction->base; -} - -static Stage1ZirInst *ir_build_set_runtime_safety(Stage1AstGen *ag, Scope *scope, AstNode *source_node, - Stage1ZirInst *safety_on) -{ - Stage1ZirInstSetRuntimeSafety *inst = ir_build_instruction(ag, scope, source_node); - inst->safety_on = safety_on; - - ir_ref_instruction(safety_on, ag->current_basic_block); - - return &inst->base; -} - -static Stage1ZirInst *ir_build_set_float_mode(Stage1AstGen *ag, Scope *scope, AstNode *source_node, - Stage1ZirInst *mode_value) -{ - Stage1ZirInstSetFloatMode *instruction = ir_build_instruction(ag, scope, source_node); - instruction->mode_value = mode_value; - - ir_ref_instruction(mode_value, ag->current_basic_block); - - return &instruction->base; -} - -static Stage1ZirInst *ir_build_array_type(Stage1AstGen *ag, Scope *scope, AstNode *source_node, Stage1ZirInst *size, - Stage1ZirInst *sentinel, Stage1ZirInst *child_type) -{ - Stage1ZirInstArrayType *instruction = ir_build_instruction(ag, scope, source_node); - instruction->size = size; - instruction->sentinel = sentinel; - instruction->child_type = child_type; - - ir_ref_instruction(size, ag->current_basic_block); - if (sentinel != nullptr) ir_ref_instruction(sentinel, ag->current_basic_block); - ir_ref_instruction(child_type, ag->current_basic_block); - - return &instruction->base; -} - -static Stage1ZirInst *ir_build_anyframe_type(Stage1AstGen *ag, Scope *scope, AstNode *source_node, - Stage1ZirInst *payload_type) -{ - Stage1ZirInstAnyFrameType *instruction = ir_build_instruction(ag, scope, source_node); - instruction->payload_type = payload_type; - - if (payload_type != nullptr) ir_ref_instruction(payload_type, ag->current_basic_block); - - return &instruction->base; -} - -static Stage1ZirInst *ir_build_slice_type(Stage1AstGen *ag, Scope *scope, AstNode *source_node, - Stage1ZirInst *child_type, bool is_const, bool is_volatile, - Stage1ZirInst *sentinel, Stage1ZirInst *align_value, bool is_allow_zero) -{ - Stage1ZirInstSliceType *instruction = ir_build_instruction(ag, scope, source_node); - instruction->is_const = is_const; - instruction->is_volatile = is_volatile; - instruction->child_type = child_type; - instruction->sentinel = sentinel; - instruction->align_value = align_value; - instruction->is_allow_zero = is_allow_zero; - - if (sentinel != nullptr) ir_ref_instruction(sentinel, ag->current_basic_block); - if (align_value != nullptr) ir_ref_instruction(align_value, ag->current_basic_block); - ir_ref_instruction(child_type, ag->current_basic_block); - - return &instruction->base; -} - -static Stage1ZirInst *ir_build_asm_src(Stage1AstGen *ag, Scope *scope, AstNode *source_node, - Stage1ZirInst *asm_template, Stage1ZirInst **input_list, Stage1ZirInst **output_types, - ZigVar **output_vars, size_t return_count, bool has_side_effects, bool is_global) -{ - Stage1ZirInstAsm *instruction = ir_build_instruction(ag, scope, source_node); - instruction->asm_template = asm_template; - instruction->input_list = input_list; - instruction->output_types = output_types; - instruction->output_vars = output_vars; - instruction->return_count = return_count; - instruction->has_side_effects = has_side_effects; - instruction->is_global = is_global; - - assert(source_node->type == NodeTypeAsmExpr); - for (size_t i = 0; i < source_node->data.asm_expr.output_list.length; i += 1) { - Stage1ZirInst *output_type = output_types[i]; - if (output_type) ir_ref_instruction(output_type, ag->current_basic_block); - } - - for (size_t i = 0; i < source_node->data.asm_expr.input_list.length; i += 1) { - Stage1ZirInst *input_value = input_list[i]; - ir_ref_instruction(input_value, ag->current_basic_block); - } - - return &instruction->base; -} - -static Stage1ZirInst *ir_build_size_of(Stage1AstGen *ag, Scope *scope, AstNode *source_node, Stage1ZirInst *type_value, - bool bit_size) -{ - Stage1ZirInstSizeOf *instruction = ir_build_instruction(ag, scope, source_node); - instruction->type_value = type_value; - instruction->bit_size = bit_size; - - ir_ref_instruction(type_value, ag->current_basic_block); - - return &instruction->base; -} - -static Stage1ZirInst *ir_build_test_non_null_src(Stage1AstGen *ag, Scope *scope, AstNode *source_node, - Stage1ZirInst *value) -{ - Stage1ZirInstTestNonNull *instruction = ir_build_instruction(ag, scope, source_node); - instruction->value = value; - - ir_ref_instruction(value, ag->current_basic_block); - - return &instruction->base; -} - -static Stage1ZirInst *ir_build_optional_unwrap_ptr(Stage1AstGen *ag, Scope *scope, AstNode *source_node, - Stage1ZirInst *base_ptr, bool safety_check_on) -{ - Stage1ZirInstOptionalUnwrapPtr *instruction = ir_build_instruction(ag, scope, source_node); - instruction->base_ptr = base_ptr; - instruction->safety_check_on = safety_check_on; - - ir_ref_instruction(base_ptr, ag->current_basic_block); - - return &instruction->base; -} - -static Stage1ZirInst *ir_build_clz(Stage1AstGen *ag, Scope *scope, AstNode *source_node, Stage1ZirInst *type, - Stage1ZirInst *op) -{ - Stage1ZirInstClz *instruction = ir_build_instruction(ag, scope, source_node); - instruction->type = type; - instruction->op = op; - - ir_ref_instruction(type, ag->current_basic_block); - ir_ref_instruction(op, ag->current_basic_block); - - return &instruction->base; -} - -static Stage1ZirInst *ir_build_ctz(Stage1AstGen *ag, Scope *scope, AstNode *source_node, Stage1ZirInst *type, - Stage1ZirInst *op) -{ - Stage1ZirInstCtz *instruction = ir_build_instruction(ag, scope, source_node); - instruction->type = type; - instruction->op = op; - - ir_ref_instruction(type, ag->current_basic_block); - ir_ref_instruction(op, ag->current_basic_block); - - return &instruction->base; -} - -static Stage1ZirInst *ir_build_pop_count(Stage1AstGen *ag, Scope *scope, AstNode *source_node, Stage1ZirInst *type, - Stage1ZirInst *op) -{ - Stage1ZirInstPopCount *instruction = ir_build_instruction(ag, scope, source_node); - instruction->type = type; - instruction->op = op; - - ir_ref_instruction(type, ag->current_basic_block); - ir_ref_instruction(op, ag->current_basic_block); - - return &instruction->base; -} - -static Stage1ZirInst *ir_build_bswap(Stage1AstGen *ag, Scope *scope, AstNode *source_node, Stage1ZirInst *type, - Stage1ZirInst *op) -{ - Stage1ZirInstBswap *instruction = ir_build_instruction(ag, scope, source_node); - instruction->type = type; - instruction->op = op; - - ir_ref_instruction(type, ag->current_basic_block); - ir_ref_instruction(op, ag->current_basic_block); - - return &instruction->base; -} - -static Stage1ZirInst *ir_build_bit_reverse(Stage1AstGen *ag, Scope *scope, AstNode *source_node, Stage1ZirInst *type, - Stage1ZirInst *op) -{ - Stage1ZirInstBitReverse *instruction = ir_build_instruction(ag, scope, source_node); - instruction->type = type; - instruction->op = op; - - ir_ref_instruction(type, ag->current_basic_block); - ir_ref_instruction(op, ag->current_basic_block); - - return &instruction->base; -} - -static Stage1ZirInstSwitchBr *ir_build_switch_br_src(Stage1AstGen *ag, Scope *scope, AstNode *source_node, - Stage1ZirInst *target_value, Stage1ZirBasicBlock *else_block, size_t case_count, Stage1ZirInstSwitchBrCase *cases, - Stage1ZirInst *is_comptime, Stage1ZirInst *switch_prongs_void) -{ - Stage1ZirInstSwitchBr *instruction = ir_build_instruction(ag, scope, source_node); - instruction->target_value = target_value; - instruction->else_block = else_block; - instruction->case_count = case_count; - instruction->cases = cases; - instruction->is_comptime = is_comptime; - instruction->switch_prongs_void = switch_prongs_void; - - ir_ref_instruction(target_value, ag->current_basic_block); - ir_ref_instruction(is_comptime, ag->current_basic_block); - ir_ref_bb(else_block); - ir_ref_instruction(switch_prongs_void, ag->current_basic_block); - - for (size_t i = 0; i < case_count; i += 1) { - ir_ref_instruction(cases[i].value, ag->current_basic_block); - ir_ref_bb(cases[i].block); - } - - return instruction; -} - -static Stage1ZirInst *ir_build_switch_target(Stage1AstGen *ag, Scope *scope, AstNode *source_node, - Stage1ZirInst *target_value_ptr) -{ - Stage1ZirInstSwitchTarget *instruction = ir_build_instruction(ag, scope, source_node); - instruction->target_value_ptr = target_value_ptr; - - ir_ref_instruction(target_value_ptr, ag->current_basic_block); - - return &instruction->base; -} - -static Stage1ZirInst *ir_build_switch_var(Stage1AstGen *ag, Scope *scope, AstNode *source_node, - Stage1ZirInst *target_value_ptr, Stage1ZirInst **prongs_ptr, size_t prongs_len) -{ - Stage1ZirInstSwitchVar *instruction = ir_build_instruction(ag, scope, source_node); - instruction->target_value_ptr = target_value_ptr; - instruction->prongs_ptr = prongs_ptr; - instruction->prongs_len = prongs_len; - - ir_ref_instruction(target_value_ptr, ag->current_basic_block); - for (size_t i = 0; i < prongs_len; i += 1) { - ir_ref_instruction(prongs_ptr[i], ag->current_basic_block); - } - - return &instruction->base; -} - -// For this instruction the switch_br must be set later. -static Stage1ZirInstSwitchElseVar *ir_build_switch_else_var(Stage1AstGen *ag, Scope *scope, AstNode *source_node, - Stage1ZirInst *target_value_ptr) -{ - Stage1ZirInstSwitchElseVar *instruction = ir_build_instruction(ag, scope, source_node); - instruction->target_value_ptr = target_value_ptr; - - ir_ref_instruction(target_value_ptr, ag->current_basic_block); - - return instruction; -} - -static Stage1ZirInst *ir_build_import(Stage1AstGen *ag, Scope *scope, AstNode *source_node, Stage1ZirInst *name) { - Stage1ZirInstImport *instruction = ir_build_instruction(ag, scope, source_node); - instruction->name = name; - - ir_ref_instruction(name, ag->current_basic_block); - - return &instruction->base; -} - -static Stage1ZirInst *ir_build_ref_src(Stage1AstGen *ag, Scope *scope, AstNode *source_node, Stage1ZirInst *value) { - Stage1ZirInstRef *instruction = ir_build_instruction(ag, scope, source_node); - instruction->value = value; - - ir_ref_instruction(value, ag->current_basic_block); - - return &instruction->base; -} - -static Stage1ZirInst *ir_build_compile_err(Stage1AstGen *ag, Scope *scope, AstNode *source_node, Stage1ZirInst *msg) { - Stage1ZirInstCompileErr *instruction = ir_build_instruction(ag, scope, source_node); - instruction->msg = msg; - - ir_ref_instruction(msg, ag->current_basic_block); - - return &instruction->base; -} - -static Stage1ZirInst *ir_build_compile_log(Stage1AstGen *ag, Scope *scope, AstNode *source_node, - size_t msg_count, Stage1ZirInst **msg_list) -{ - Stage1ZirInstCompileLog *instruction = ir_build_instruction(ag, scope, source_node); - instruction->msg_count = msg_count; - instruction->msg_list = msg_list; - - for (size_t i = 0; i < msg_count; i += 1) { - ir_ref_instruction(msg_list[i], ag->current_basic_block); - } - - return &instruction->base; -} - -static Stage1ZirInst *ir_build_err_name(Stage1AstGen *ag, Scope *scope, AstNode *source_node, Stage1ZirInst *value) { - Stage1ZirInstErrName *instruction = ir_build_instruction(ag, scope, source_node); - instruction->value = value; - - ir_ref_instruction(value, ag->current_basic_block); - - return &instruction->base; -} - -static Stage1ZirInst *ir_build_c_import(Stage1AstGen *ag, Scope *scope, AstNode *source_node) { - Stage1ZirInstCImport *instruction = ir_build_instruction(ag, scope, source_node); - return &instruction->base; -} - -static Stage1ZirInst *ir_build_c_include(Stage1AstGen *ag, Scope *scope, AstNode *source_node, Stage1ZirInst *name) { - Stage1ZirInstCInclude *instruction = ir_build_instruction(ag, scope, source_node); - instruction->name = name; - - ir_ref_instruction(name, ag->current_basic_block); - - return &instruction->base; -} - -static Stage1ZirInst *ir_build_c_define(Stage1AstGen *ag, Scope *scope, AstNode *source_node, Stage1ZirInst *name, Stage1ZirInst *value) { - Stage1ZirInstCDefine *instruction = ir_build_instruction(ag, scope, source_node); - instruction->name = name; - instruction->value = value; - - ir_ref_instruction(name, ag->current_basic_block); - ir_ref_instruction(value, ag->current_basic_block); - - return &instruction->base; -} - -static Stage1ZirInst *ir_build_c_undef(Stage1AstGen *ag, Scope *scope, AstNode *source_node, Stage1ZirInst *name) { - Stage1ZirInstCUndef *instruction = ir_build_instruction(ag, scope, source_node); - instruction->name = name; - - ir_ref_instruction(name, ag->current_basic_block); - - return &instruction->base; -} - -static Stage1ZirInst *ir_build_embed_file(Stage1AstGen *ag, Scope *scope, AstNode *source_node, Stage1ZirInst *name) { - Stage1ZirInstEmbedFile *instruction = ir_build_instruction(ag, scope, source_node); - instruction->name = name; - - ir_ref_instruction(name, ag->current_basic_block); - - return &instruction->base; -} - -static Stage1ZirInst *ir_build_cmpxchg_src(Stage1AstGen *ag, Scope *scope, AstNode *source_node, - Stage1ZirInst *type_value, Stage1ZirInst *ptr, Stage1ZirInst *cmp_value, Stage1ZirInst *new_value, - Stage1ZirInst *success_order_value, Stage1ZirInst *failure_order_value, bool is_weak, ResultLoc *result_loc) -{ - Stage1ZirInstCmpxchg *instruction = ir_build_instruction(ag, scope, source_node); - instruction->type_value = type_value; - instruction->ptr = ptr; - instruction->cmp_value = cmp_value; - instruction->new_value = new_value; - instruction->success_order_value = success_order_value; - instruction->failure_order_value = failure_order_value; - instruction->is_weak = is_weak; - instruction->result_loc = result_loc; - - ir_ref_instruction(type_value, ag->current_basic_block); - ir_ref_instruction(ptr, ag->current_basic_block); - ir_ref_instruction(cmp_value, ag->current_basic_block); - ir_ref_instruction(new_value, ag->current_basic_block); - ir_ref_instruction(success_order_value, ag->current_basic_block); - ir_ref_instruction(failure_order_value, ag->current_basic_block); - - return &instruction->base; -} - -static Stage1ZirInst *ir_build_fence(Stage1AstGen *ag, Scope *scope, AstNode *source_node, Stage1ZirInst *order) { - Stage1ZirInstFence *instruction = ir_build_instruction(ag, scope, source_node); - instruction->order = order; - - ir_ref_instruction(order, ag->current_basic_block); - - return &instruction->base; -} - -static Stage1ZirInst *ir_build_reduce(Stage1AstGen *ag, Scope *scope, AstNode *source_node, Stage1ZirInst *op, Stage1ZirInst *value) { - Stage1ZirInstReduce *instruction = ir_build_instruction(ag, scope, source_node); - instruction->op = op; - instruction->value = value; - - ir_ref_instruction(op, ag->current_basic_block); - ir_ref_instruction(value, ag->current_basic_block); - - return &instruction->base; -} - -static Stage1ZirInst *ir_build_truncate(Stage1AstGen *ag, Scope *scope, AstNode *source_node, - Stage1ZirInst *dest_type, Stage1ZirInst *target) -{ - Stage1ZirInstTruncate *instruction = ir_build_instruction(ag, scope, source_node); - instruction->dest_type = dest_type; - instruction->target = target; - - ir_ref_instruction(dest_type, ag->current_basic_block); - ir_ref_instruction(target, ag->current_basic_block); - - return &instruction->base; -} - -static Stage1ZirInst *ir_build_int_cast(Stage1AstGen *ag, Scope *scope, AstNode *source_node, Stage1ZirInst *dest_type, - Stage1ZirInst *target) -{ - Stage1ZirInstIntCast *instruction = ir_build_instruction(ag, scope, source_node); - instruction->dest_type = dest_type; - instruction->target = target; - - ir_ref_instruction(dest_type, ag->current_basic_block); - ir_ref_instruction(target, ag->current_basic_block); - - return &instruction->base; -} - -static Stage1ZirInst *ir_build_float_cast(Stage1AstGen *ag, Scope *scope, AstNode *source_node, Stage1ZirInst *dest_type, - Stage1ZirInst *target) -{ - Stage1ZirInstFloatCast *instruction = ir_build_instruction(ag, scope, source_node); - instruction->dest_type = dest_type; - instruction->target = target; - - ir_ref_instruction(dest_type, ag->current_basic_block); - ir_ref_instruction(target, ag->current_basic_block); - - return &instruction->base; -} - -static Stage1ZirInst *ir_build_err_set_cast(Stage1AstGen *ag, Scope *scope, AstNode *source_node, - Stage1ZirInst *dest_type, Stage1ZirInst *target) -{ - Stage1ZirInstErrSetCast *instruction = ir_build_instruction(ag, scope, source_node); - instruction->dest_type = dest_type; - instruction->target = target; - - ir_ref_instruction(dest_type, ag->current_basic_block); - ir_ref_instruction(target, ag->current_basic_block); - - return &instruction->base; -} - -static Stage1ZirInst *ir_build_int_to_float(Stage1AstGen *ag, Scope *scope, AstNode *source_node, - Stage1ZirInst *dest_type, Stage1ZirInst *target) -{ - Stage1ZirInstIntToFloat *instruction = ir_build_instruction(ag, scope, source_node); - instruction->dest_type = dest_type; - instruction->target = target; - - ir_ref_instruction(dest_type, ag->current_basic_block); - ir_ref_instruction(target, ag->current_basic_block); - - return &instruction->base; -} - -static Stage1ZirInst *ir_build_float_to_int(Stage1AstGen *ag, Scope *scope, AstNode *source_node, - Stage1ZirInst *dest_type, Stage1ZirInst *target) -{ - Stage1ZirInstFloatToInt *instruction = ir_build_instruction(ag, scope, source_node); - instruction->dest_type = dest_type; - instruction->target = target; - - ir_ref_instruction(dest_type, ag->current_basic_block); - ir_ref_instruction(target, ag->current_basic_block); - - return &instruction->base; -} - -static Stage1ZirInst *ir_build_bool_to_int(Stage1AstGen *ag, Scope *scope, AstNode *source_node, Stage1ZirInst *target) { - Stage1ZirInstBoolToInt *instruction = ir_build_instruction(ag, scope, source_node); - instruction->target = target; - - ir_ref_instruction(target, ag->current_basic_block); - - return &instruction->base; -} - -static Stage1ZirInst *ir_build_vector_type(Stage1AstGen *ag, Scope *scope, AstNode *source_node, Stage1ZirInst *len, - Stage1ZirInst *elem_type) -{ - Stage1ZirInstVectorType *instruction = ir_build_instruction(ag, scope, source_node); - instruction->len = len; - instruction->elem_type = elem_type; - - ir_ref_instruction(len, ag->current_basic_block); - ir_ref_instruction(elem_type, ag->current_basic_block); - - return &instruction->base; -} - -static Stage1ZirInst *ir_build_shuffle_vector(Stage1AstGen *ag, Scope *scope, AstNode *source_node, - Stage1ZirInst *scalar_type, Stage1ZirInst *a, Stage1ZirInst *b, Stage1ZirInst *mask) -{ - Stage1ZirInstShuffleVector *instruction = ir_build_instruction(ag, scope, source_node); - instruction->scalar_type = scalar_type; - instruction->a = a; - instruction->b = b; - instruction->mask = mask; - - if (scalar_type != nullptr) ir_ref_instruction(scalar_type, ag->current_basic_block); - ir_ref_instruction(a, ag->current_basic_block); - ir_ref_instruction(b, ag->current_basic_block); - ir_ref_instruction(mask, ag->current_basic_block); - - return &instruction->base; -} - -static Stage1ZirInst *ir_build_select(Stage1AstGen *ag, Scope *scope, AstNode *source_node, - Stage1ZirInst *scalar_type, Stage1ZirInst *pred, Stage1ZirInst *a, Stage1ZirInst *b) -{ - Stage1ZirInstSelect *instruction = ir_build_instruction(ag, scope, source_node); - instruction->scalar_type = scalar_type; - instruction->pred = pred; - instruction->a = a; - instruction->b = b; - - ir_ref_instruction(pred, ag->current_basic_block); - ir_ref_instruction(a, ag->current_basic_block); - ir_ref_instruction(b, ag->current_basic_block); - - return &instruction->base; -} - -static Stage1ZirInst *ir_build_splat_src(Stage1AstGen *ag, Scope *scope, AstNode *source_node, - Stage1ZirInst *len, Stage1ZirInst *scalar) -{ - Stage1ZirInstSplat *instruction = ir_build_instruction(ag, scope, source_node); - instruction->len = len; - instruction->scalar = scalar; - - ir_ref_instruction(len, ag->current_basic_block); - ir_ref_instruction(scalar, ag->current_basic_block); - - return &instruction->base; -} - -static Stage1ZirInst *ir_build_bool_not(Stage1AstGen *ag, Scope *scope, AstNode *source_node, Stage1ZirInst *value) { - Stage1ZirInstBoolNot *instruction = ir_build_instruction(ag, scope, source_node); - instruction->value = value; - - ir_ref_instruction(value, ag->current_basic_block); - - return &instruction->base; -} - -static Stage1ZirInst *ir_build_memset_src(Stage1AstGen *ag, Scope *scope, AstNode *source_node, - Stage1ZirInst *dest_ptr, Stage1ZirInst *byte, Stage1ZirInst *count) -{ - Stage1ZirInstMemset *instruction = ir_build_instruction(ag, scope, source_node); - instruction->dest_ptr = dest_ptr; - instruction->byte = byte; - instruction->count = count; - - ir_ref_instruction(dest_ptr, ag->current_basic_block); - ir_ref_instruction(byte, ag->current_basic_block); - ir_ref_instruction(count, ag->current_basic_block); - - return &instruction->base; -} - -static Stage1ZirInst *ir_build_memcpy_src(Stage1AstGen *ag, Scope *scope, AstNode *source_node, - Stage1ZirInst *dest_ptr, Stage1ZirInst *src_ptr, Stage1ZirInst *count) -{ - Stage1ZirInstMemcpy *instruction = ir_build_instruction(ag, scope, source_node); - instruction->dest_ptr = dest_ptr; - instruction->src_ptr = src_ptr; - instruction->count = count; - - ir_ref_instruction(dest_ptr, ag->current_basic_block); - ir_ref_instruction(src_ptr, ag->current_basic_block); - ir_ref_instruction(count, ag->current_basic_block); - - return &instruction->base; -} - -static Stage1ZirInst *ir_build_slice_src(Stage1AstGen *ag, Scope *scope, AstNode *source_node, - Stage1ZirInst *ptr, Stage1ZirInst *start, Stage1ZirInst *end, Stage1ZirInst *sentinel, - bool safety_check_on, ResultLoc *result_loc) -{ - Stage1ZirInstSlice *instruction = ir_build_instruction(ag, scope, source_node); - instruction->ptr = ptr; - instruction->start = start; - instruction->end = end; - instruction->sentinel = sentinel; - instruction->safety_check_on = safety_check_on; - instruction->result_loc = result_loc; - - ir_ref_instruction(ptr, ag->current_basic_block); - ir_ref_instruction(start, ag->current_basic_block); - if (end) ir_ref_instruction(end, ag->current_basic_block); - if (sentinel) ir_ref_instruction(sentinel, ag->current_basic_block); - - return &instruction->base; -} - -static Stage1ZirInst *ir_build_breakpoint(Stage1AstGen *ag, Scope *scope, AstNode *source_node) { - Stage1ZirInstBreakpoint *instruction = ir_build_instruction(ag, scope, source_node); - return &instruction->base; -} - -static Stage1ZirInst *ir_build_return_address_src(Stage1AstGen *ag, Scope *scope, AstNode *source_node) { - Stage1ZirInstReturnAddress *instruction = ir_build_instruction(ag, scope, source_node); - return &instruction->base; -} - -static Stage1ZirInst *ir_build_frame_address_src(Stage1AstGen *ag, Scope *scope, AstNode *source_node) { - Stage1ZirInstFrameAddress *inst = ir_build_instruction(ag, scope, source_node); - return &inst->base; -} - -static Stage1ZirInst *ir_build_handle_src(Stage1AstGen *ag, Scope *scope, AstNode *source_node) { - Stage1ZirInstFrameHandle *inst = ir_build_instruction(ag, scope, source_node); - return &inst->base; -} - -static Stage1ZirInst *ir_build_frame_type(Stage1AstGen *ag, Scope *scope, AstNode *source_node, Stage1ZirInst *fn) { - Stage1ZirInstFrameType *inst = ir_build_instruction(ag, scope, source_node); - inst->fn = fn; - - ir_ref_instruction(fn, ag->current_basic_block); - - return &inst->base; -} - -static Stage1ZirInst *ir_build_frame_size_src(Stage1AstGen *ag, Scope *scope, AstNode *source_node, Stage1ZirInst *fn) { - Stage1ZirInstFrameSize *inst = ir_build_instruction(ag, scope, source_node); - inst->fn = fn; - - ir_ref_instruction(fn, ag->current_basic_block); - - return &inst->base; -} - -static Stage1ZirInst *ir_build_overflow_op_src(Stage1AstGen *ag, Scope *scope, AstNode *source_node, - IrOverflowOp op, Stage1ZirInst *type_value, Stage1ZirInst *op1, Stage1ZirInst *op2, Stage1ZirInst *result_ptr) -{ - Stage1ZirInstOverflowOp *instruction = ir_build_instruction(ag, scope, source_node); - instruction->op = op; - instruction->type_value = type_value; - instruction->op1 = op1; - instruction->op2 = op2; - instruction->result_ptr = result_ptr; - - ir_ref_instruction(type_value, ag->current_basic_block); - ir_ref_instruction(op1, ag->current_basic_block); - ir_ref_instruction(op2, ag->current_basic_block); - ir_ref_instruction(result_ptr, ag->current_basic_block); - - return &instruction->base; -} - -static Stage1ZirInst *ir_build_float_op_src(Stage1AstGen *ag, Scope *scope, AstNode *source_node, Stage1ZirInst *operand, - BuiltinFnId fn_id) -{ - Stage1ZirInstFloatOp *instruction = ir_build_instruction(ag, scope, source_node); - instruction->operand = operand; - instruction->fn_id = fn_id; - - ir_ref_instruction(operand, ag->current_basic_block); - - return &instruction->base; -} - -static Stage1ZirInst *ir_build_mul_add_src(Stage1AstGen *ag, Scope *scope, AstNode *source_node, - Stage1ZirInst *type_value, Stage1ZirInst *op1, Stage1ZirInst *op2, Stage1ZirInst *op3) -{ - Stage1ZirInstMulAdd *instruction = ir_build_instruction(ag, scope, source_node); - instruction->type_value = type_value; - instruction->op1 = op1; - instruction->op2 = op2; - instruction->op3 = op3; - - ir_ref_instruction(type_value, ag->current_basic_block); - ir_ref_instruction(op1, ag->current_basic_block); - ir_ref_instruction(op2, ag->current_basic_block); - ir_ref_instruction(op3, ag->current_basic_block); - - return &instruction->base; -} - -static Stage1ZirInst *ir_build_align_of(Stage1AstGen *ag, Scope *scope, AstNode *source_node, Stage1ZirInst *type_value) { - Stage1ZirInstAlignOf *instruction = ir_build_instruction(ag, scope, source_node); - instruction->type_value = type_value; - - ir_ref_instruction(type_value, ag->current_basic_block); - - return &instruction->base; -} - -static Stage1ZirInst *ir_build_test_err_src(Stage1AstGen *ag, Scope *scope, AstNode *source_node, - Stage1ZirInst *base_ptr, bool resolve_err_set, bool base_ptr_is_payload) -{ - Stage1ZirInstTestErr *instruction = ir_build_instruction(ag, scope, source_node); - instruction->base_ptr = base_ptr; - instruction->resolve_err_set = resolve_err_set; - instruction->base_ptr_is_payload = base_ptr_is_payload; - - ir_ref_instruction(base_ptr, ag->current_basic_block); - - return &instruction->base; -} - -static Stage1ZirInst *ir_build_unwrap_err_code_src(Stage1AstGen *ag, Scope *scope, AstNode *source_node, - Stage1ZirInst *err_union_ptr) -{ - Stage1ZirInstUnwrapErrCode *inst = ir_build_instruction(ag, scope, source_node); - inst->err_union_ptr = err_union_ptr; - - ir_ref_instruction(err_union_ptr, ag->current_basic_block); - - return &inst->base; -} - -static Stage1ZirInst *ir_build_unwrap_err_payload_src(Stage1AstGen *ag, Scope *scope, AstNode *source_node, - Stage1ZirInst *value, bool safety_check_on, bool initializing) -{ - Stage1ZirInstUnwrapErrPayload *inst = ir_build_instruction(ag, scope, source_node); - inst->value = value; - inst->safety_check_on = safety_check_on; - inst->initializing = initializing; - - ir_ref_instruction(value, ag->current_basic_block); - - return &inst->base; -} - -static Stage1ZirInst *ir_build_fn_proto(Stage1AstGen *ag, Scope *scope, AstNode *source_node, - Stage1ZirInst **param_types, Stage1ZirInst *align_value, Stage1ZirInst *callconv_value, - Stage1ZirInst *return_type, bool is_var_args) -{ - Stage1ZirInstFnProto *instruction = ir_build_instruction(ag, scope, source_node); - instruction->param_types = param_types; - instruction->align_value = align_value; - instruction->callconv_value = callconv_value; - instruction->return_type = return_type; - instruction->is_var_args = is_var_args; - - assert(source_node->type == NodeTypeFnProto); - size_t param_count = source_node->data.fn_proto.params.length; - if (is_var_args) param_count -= 1; - for (size_t i = 0; i < param_count; i += 1) { - if (param_types[i] != nullptr) ir_ref_instruction(param_types[i], ag->current_basic_block); - } - if (align_value != nullptr) ir_ref_instruction(align_value, ag->current_basic_block); - if (callconv_value != nullptr) ir_ref_instruction(callconv_value, ag->current_basic_block); - ir_ref_instruction(return_type, ag->current_basic_block); - - return &instruction->base; -} - -static Stage1ZirInst *ir_build_test_comptime(Stage1AstGen *ag, Scope *scope, AstNode *source_node, Stage1ZirInst *value) { - Stage1ZirInstTestComptime *instruction = ir_build_instruction(ag, scope, source_node); - instruction->value = value; - - ir_ref_instruction(value, ag->current_basic_block); - - return &instruction->base; -} - -static Stage1ZirInst *ir_build_ptr_cast_src(Stage1AstGen *ag, Scope *scope, AstNode *source_node, - Stage1ZirInst *dest_type, Stage1ZirInst *ptr, bool safety_check_on) -{ - Stage1ZirInstPtrCast *instruction = ir_build_instruction( - ag, scope, source_node); - instruction->dest_type = dest_type; - instruction->ptr = ptr; - instruction->safety_check_on = safety_check_on; - - ir_ref_instruction(dest_type, ag->current_basic_block); - ir_ref_instruction(ptr, ag->current_basic_block); - - return &instruction->base; -} - -static Stage1ZirInst *ir_build_implicit_cast(Stage1AstGen *ag, Scope *scope, AstNode *source_node, - Stage1ZirInst *operand, ResultLocCast *result_loc_cast) -{ - Stage1ZirInstImplicitCast *instruction = ir_build_instruction(ag, scope, source_node); - instruction->operand = operand; - instruction->result_loc_cast = result_loc_cast; - - ir_ref_instruction(operand, ag->current_basic_block); - - return &instruction->base; -} - -static Stage1ZirInst *ir_build_bit_cast_src(Stage1AstGen *ag, Scope *scope, AstNode *source_node, - Stage1ZirInst *operand, ResultLocBitCast *result_loc_bit_cast) -{ - Stage1ZirInstBitCast *instruction = ir_build_instruction(ag, scope, source_node); - instruction->operand = operand; - instruction->result_loc_bit_cast = result_loc_bit_cast; - - ir_ref_instruction(operand, ag->current_basic_block); - - return &instruction->base; -} - -static Stage1ZirInst *ir_build_int_to_ptr_src(Stage1AstGen *ag, Scope *scope, AstNode *source_node, - Stage1ZirInst *dest_type, Stage1ZirInst *target) -{ - Stage1ZirInstIntToPtr *instruction = ir_build_instruction(ag, scope, source_node); - instruction->dest_type = dest_type; - instruction->target = target; - - ir_ref_instruction(dest_type, ag->current_basic_block); - ir_ref_instruction(target, ag->current_basic_block); - - return &instruction->base; -} - -static Stage1ZirInst *ir_build_ptr_to_int_src(Stage1AstGen *ag, Scope *scope, AstNode *source_node, - Stage1ZirInst *target) -{ - Stage1ZirInstPtrToInt *inst = ir_build_instruction(ag, scope, source_node); - inst->target = target; - - ir_ref_instruction(target, ag->current_basic_block); - - return &inst->base; -} - -static Stage1ZirInst *ir_build_int_to_enum_src(Stage1AstGen *ag, Scope *scope, AstNode *source_node, - Stage1ZirInst *dest_type, Stage1ZirInst *target) -{ - Stage1ZirInstIntToEnum *instruction = ir_build_instruction(ag, scope, source_node); - instruction->dest_type = dest_type; - instruction->target = target; - - if (dest_type) ir_ref_instruction(dest_type, ag->current_basic_block); - ir_ref_instruction(target, ag->current_basic_block); - - return &instruction->base; -} - -static Stage1ZirInst *ir_build_enum_to_int(Stage1AstGen *ag, Scope *scope, AstNode *source_node, - Stage1ZirInst *target) -{ - Stage1ZirInstEnumToInt *instruction = ir_build_instruction( - ag, scope, source_node); - instruction->target = target; - - ir_ref_instruction(target, ag->current_basic_block); - - return &instruction->base; -} - -static Stage1ZirInst *ir_build_int_to_err_src(Stage1AstGen *ag, Scope *scope, AstNode *source_node, - Stage1ZirInst *target) -{ - Stage1ZirInstIntToErr *instruction = ir_build_instruction(ag, scope, source_node); - instruction->target = target; - - ir_ref_instruction(target, ag->current_basic_block); - - return &instruction->base; -} - -static Stage1ZirInst *ir_build_err_to_int_src(Stage1AstGen *ag, Scope *scope, AstNode *source_node, - Stage1ZirInst *target) -{ - Stage1ZirInstErrToInt *instruction = ir_build_instruction( - ag, scope, source_node); - instruction->target = target; - - ir_ref_instruction(target, ag->current_basic_block); - - return &instruction->base; -} - -static Stage1ZirInst *ir_build_check_switch_prongs(Stage1AstGen *ag, Scope *scope, AstNode *source_node, - Stage1ZirInst *target_value, Stage1ZirInstCheckSwitchProngsRange *ranges, size_t range_count, - AstNode* else_prong, bool have_underscore_prong) -{ - Stage1ZirInstCheckSwitchProngs *instruction = heap::c_allocator.create(); - instruction->base.id = have_underscore_prong ? - Stage1ZirInstIdCheckSwitchProngsUnderYes : Stage1ZirInstIdCheckSwitchProngsUnderNo; - instruction->base.scope = scope; - instruction->base.source_node = source_node; - instruction->base.debug_id = irb_next_debug_id(ag); - instruction->base.owner_bb = ag->current_basic_block; - ir_instruction_append(ag->current_basic_block, &instruction->base); - - instruction->target_value = target_value; - instruction->ranges = ranges; - instruction->range_count = range_count; - instruction->else_prong = else_prong; - - ir_ref_instruction(target_value, ag->current_basic_block); - for (size_t i = 0; i < range_count; i += 1) { - ir_ref_instruction(ranges[i].start, ag->current_basic_block); - ir_ref_instruction(ranges[i].end, ag->current_basic_block); - } - - return &instruction->base; -} - -static Stage1ZirInst *ir_build_check_statement_is_void(Stage1AstGen *ag, Scope *scope, AstNode *source_node, - Stage1ZirInst* statement_value) -{ - Stage1ZirInstCheckStatementIsVoid *instruction = ir_build_instruction( - ag, scope, source_node); - instruction->statement_value = statement_value; - - ir_ref_instruction(statement_value, ag->current_basic_block); - - return &instruction->base; -} - -static Stage1ZirInst *ir_build_type_name(Stage1AstGen *ag, Scope *scope, AstNode *source_node, - Stage1ZirInst *type_value) -{ - Stage1ZirInstTypeName *instruction = ir_build_instruction(ag, scope, source_node); - instruction->type_value = type_value; - - ir_ref_instruction(type_value, ag->current_basic_block); - - return &instruction->base; -} - -static Stage1ZirInst *ir_build_decl_ref(Stage1AstGen *ag, Scope *scope, AstNode *source_node, Tld *tld, LVal lval) { - Stage1ZirInstDeclRef *instruction = ir_build_instruction(ag, scope, source_node); - instruction->tld = tld; - instruction->lval = lval; - - return &instruction->base; -} - -static Stage1ZirInst *ir_build_panic_src(Stage1AstGen *ag, Scope *scope, AstNode *source_node, Stage1ZirInst *msg) { - Stage1ZirInstPanic *instruction = ir_build_instruction(ag, scope, source_node); - instruction->msg = msg; - - ir_ref_instruction(msg, ag->current_basic_block); - - return &instruction->base; -} - -static Stage1ZirInst *ir_build_tag_name_src(Stage1AstGen *ag, Scope *scope, AstNode *source_node, Stage1ZirInst *target) { - Stage1ZirInstTagName *instruction = ir_build_instruction(ag, scope, source_node); - instruction->target = target; - - ir_ref_instruction(target, ag->current_basic_block); - - return &instruction->base; -} - -static Stage1ZirInst *ir_build_field_parent_ptr_src(Stage1AstGen *ag, Scope *scope, AstNode *source_node, - Stage1ZirInst *type_value, Stage1ZirInst *field_name, Stage1ZirInst *field_ptr) -{ - Stage1ZirInstFieldParentPtr *inst = ir_build_instruction( - ag, scope, source_node); - inst->type_value = type_value; - inst->field_name = field_name; - inst->field_ptr = field_ptr; - - ir_ref_instruction(type_value, ag->current_basic_block); - ir_ref_instruction(field_name, ag->current_basic_block); - ir_ref_instruction(field_ptr, ag->current_basic_block); - - return &inst->base; -} - -static Stage1ZirInst *ir_build_offset_of(Stage1AstGen *ag, Scope *scope, AstNode *source_node, - Stage1ZirInst *type_value, Stage1ZirInst *field_name) -{ - Stage1ZirInstOffsetOf *instruction = ir_build_instruction(ag, scope, source_node); - instruction->type_value = type_value; - instruction->field_name = field_name; - - ir_ref_instruction(type_value, ag->current_basic_block); - ir_ref_instruction(field_name, ag->current_basic_block); - - return &instruction->base; -} - -static Stage1ZirInst *ir_build_bit_offset_of(Stage1AstGen *ag, Scope *scope, AstNode *source_node, - Stage1ZirInst *type_value, Stage1ZirInst *field_name) -{ - Stage1ZirInstBitOffsetOf *instruction = ir_build_instruction(ag, scope, source_node); - instruction->type_value = type_value; - instruction->field_name = field_name; - - ir_ref_instruction(type_value, ag->current_basic_block); - ir_ref_instruction(field_name, ag->current_basic_block); - - return &instruction->base; -} - -static Stage1ZirInst *ir_build_type_info(Stage1AstGen *ag, Scope *scope, AstNode *source_node, Stage1ZirInst *type_value) { - Stage1ZirInstTypeInfo *instruction = ir_build_instruction(ag, scope, source_node); - instruction->type_value = type_value; - - ir_ref_instruction(type_value, ag->current_basic_block); - - return &instruction->base; -} - -static Stage1ZirInst *ir_build_type(Stage1AstGen *ag, Scope *scope, AstNode *source_node, Stage1ZirInst *type_info) { - Stage1ZirInstType *instruction = ir_build_instruction(ag, scope, source_node); - instruction->type_info = type_info; - - ir_ref_instruction(type_info, ag->current_basic_block); - - return &instruction->base; -} - -static Stage1ZirInst *ir_build_set_eval_branch_quota(Stage1AstGen *ag, Scope *scope, AstNode *source_node, - Stage1ZirInst *new_quota) -{ - Stage1ZirInstSetEvalBranchQuota *instruction = ir_build_instruction(ag, scope, source_node); - instruction->new_quota = new_quota; - - ir_ref_instruction(new_quota, ag->current_basic_block); - - return &instruction->base; -} - -static Stage1ZirInst *ir_build_align_cast_src(Stage1AstGen *ag, Scope *scope, AstNode *source_node, - Stage1ZirInst *align_bytes, Stage1ZirInst *target) -{ - Stage1ZirInstAlignCast *instruction = ir_build_instruction(ag, scope, source_node); - instruction->align_bytes = align_bytes; - instruction->target = target; - - ir_ref_instruction(align_bytes, ag->current_basic_block); - ir_ref_instruction(target, ag->current_basic_block); - - return &instruction->base; -} - -static Stage1ZirInst *ir_build_addrspace_cast(Stage1AstGen *ag, Scope *scope, AstNode *source_node, - Stage1ZirInst *addrspace, Stage1ZirInst *ptr) -{ - Stage1ZirInstAddrSpaceCast *instruction = ir_build_instruction(ag, scope, source_node); - instruction->addrspace = addrspace; - instruction->ptr = ptr; - - ir_ref_instruction(addrspace, ag->current_basic_block); - ir_ref_instruction(ptr, ag->current_basic_block); - - return &instruction->base; -} - -static Stage1ZirInst *ir_build_resolve_result(Stage1AstGen *ag, Scope *scope, AstNode *source_node, - ResultLoc *result_loc, Stage1ZirInst *ty) -{ - Stage1ZirInstResolveResult *instruction = ir_build_instruction(ag, scope, source_node); - instruction->result_loc = result_loc; - instruction->ty = ty; - - if (ty != nullptr) ir_ref_instruction(ty, ag->current_basic_block); - - return &instruction->base; -} - -static Stage1ZirInst *ir_build_reset_result(Stage1AstGen *ag, Scope *scope, AstNode *source_node, - ResultLoc *result_loc) -{ - Stage1ZirInstResetResult *instruction = ir_build_instruction(ag, scope, source_node); - instruction->result_loc = result_loc; - - return &instruction->base; -} - -static Stage1ZirInst *ir_build_set_align_stack(Stage1AstGen *ag, Scope *scope, AstNode *source_node, - Stage1ZirInst *align_bytes) -{ - Stage1ZirInstSetAlignStack *instruction = ir_build_instruction(ag, scope, source_node); - instruction->align_bytes = align_bytes; - - ir_ref_instruction(align_bytes, ag->current_basic_block); - - return &instruction->base; -} - -static Stage1ZirInst *ir_build_arg_type(Stage1AstGen *ag, Scope *scope, AstNode *source_node, - Stage1ZirInst *fn_type, Stage1ZirInst *arg_index, bool allow_var) -{ - Stage1ZirInstArgType *instruction = heap::c_allocator.create(); - instruction->base.id = allow_var ? - Stage1ZirInstIdArgTypeAllowVarTrue : Stage1ZirInstIdArgTypeAllowVarFalse; - instruction->base.scope = scope; - instruction->base.source_node = source_node; - instruction->base.debug_id = irb_next_debug_id(ag); - instruction->base.owner_bb = ag->current_basic_block; - ir_instruction_append(ag->current_basic_block, &instruction->base); - - instruction->fn_type = fn_type; - instruction->arg_index = arg_index; - - ir_ref_instruction(fn_type, ag->current_basic_block); - ir_ref_instruction(arg_index, ag->current_basic_block); - - return &instruction->base; -} - -static Stage1ZirInst *ir_build_error_return_trace_src(Stage1AstGen *ag, Scope *scope, AstNode *source_node, - IrInstErrorReturnTraceOptional optional) -{ - Stage1ZirInstErrorReturnTrace *inst = ir_build_instruction(ag, scope, source_node); - inst->optional = optional; - - return &inst->base; -} - -static Stage1ZirInst *ir_build_error_union(Stage1AstGen *ag, Scope *scope, AstNode *source_node, - Stage1ZirInst *err_set, Stage1ZirInst *payload) -{ - Stage1ZirInstErrorUnion *instruction = ir_build_instruction(ag, scope, source_node); - instruction->err_set = err_set; - instruction->payload = payload; - - ir_ref_instruction(err_set, ag->current_basic_block); - ir_ref_instruction(payload, ag->current_basic_block); - - return &instruction->base; -} - -static Stage1ZirInst *ir_build_atomic_rmw_src(Stage1AstGen *ag, Scope *scope, AstNode *source_node, - Stage1ZirInst *operand_type, Stage1ZirInst *ptr, Stage1ZirInst *op, Stage1ZirInst *operand, - Stage1ZirInst *ordering) -{ - Stage1ZirInstAtomicRmw *instruction = ir_build_instruction(ag, scope, source_node); - instruction->operand_type = operand_type; - instruction->ptr = ptr; - instruction->op = op; - instruction->operand = operand; - instruction->ordering = ordering; - - ir_ref_instruction(operand_type, ag->current_basic_block); - ir_ref_instruction(ptr, ag->current_basic_block); - ir_ref_instruction(op, ag->current_basic_block); - ir_ref_instruction(operand, ag->current_basic_block); - ir_ref_instruction(ordering, ag->current_basic_block); - - return &instruction->base; -} - -static Stage1ZirInst *ir_build_atomic_load_src(Stage1AstGen *ag, Scope *scope, AstNode *source_node, - Stage1ZirInst *operand_type, Stage1ZirInst *ptr, Stage1ZirInst *ordering) -{ - Stage1ZirInstAtomicLoad *instruction = ir_build_instruction(ag, scope, source_node); - instruction->operand_type = operand_type; - instruction->ptr = ptr; - instruction->ordering = ordering; - - ir_ref_instruction(operand_type, ag->current_basic_block); - ir_ref_instruction(ptr, ag->current_basic_block); - ir_ref_instruction(ordering, ag->current_basic_block); - - return &instruction->base; -} - -static Stage1ZirInst *ir_build_atomic_store_src(Stage1AstGen *ag, Scope *scope, AstNode *source_node, - Stage1ZirInst *operand_type, Stage1ZirInst *ptr, Stage1ZirInst *value, Stage1ZirInst *ordering) -{ - Stage1ZirInstAtomicStore *instruction = ir_build_instruction(ag, scope, source_node); - instruction->operand_type = operand_type; - instruction->ptr = ptr; - instruction->value = value; - instruction->ordering = ordering; - - ir_ref_instruction(operand_type, ag->current_basic_block); - ir_ref_instruction(ptr, ag->current_basic_block); - ir_ref_instruction(value, ag->current_basic_block); - ir_ref_instruction(ordering, ag->current_basic_block); - - return &instruction->base; -} - -static Stage1ZirInst *ir_build_save_err_ret_addr_src(Stage1AstGen *ag, Scope *scope, AstNode *source_node) { - Stage1ZirInstSaveErrRetAddr *inst = ir_build_instruction(ag, scope, source_node); - return &inst->base; -} - -static Stage1ZirInst *ir_build_add_implicit_return_type(Stage1AstGen *ag, Scope *scope, AstNode *source_node, - Stage1ZirInst *value, ResultLocReturn *result_loc_ret) -{ - Stage1ZirInstAddImplicitReturnType *inst = ir_build_instruction(ag, scope, source_node); - inst->value = value; - inst->result_loc_ret = result_loc_ret; - - ir_ref_instruction(value, ag->current_basic_block); - - return &inst->base; -} - -static Stage1ZirInst *ir_build_has_decl(Stage1AstGen *ag, Scope *scope, AstNode *source_node, - Stage1ZirInst *container, Stage1ZirInst *name) -{ - Stage1ZirInstHasDecl *instruction = ir_build_instruction(ag, scope, source_node); - instruction->container = container; - instruction->name = name; - - ir_ref_instruction(container, ag->current_basic_block); - ir_ref_instruction(name, ag->current_basic_block); - - return &instruction->base; -} - -static Stage1ZirInst *ir_build_undeclared_identifier(Stage1AstGen *ag, Scope *scope, AstNode *source_node, Buf *name) { - Stage1ZirInstUndeclaredIdent *instruction = ir_build_instruction(ag, scope, source_node); - instruction->name = name; - - return &instruction->base; -} - -static Stage1ZirInst *ir_build_check_runtime_scope(Stage1AstGen *ag, Scope *scope, AstNode *source_node, Stage1ZirInst *scope_is_comptime, Stage1ZirInst *is_comptime) { - Stage1ZirInstCheckRuntimeScope *instruction = ir_build_instruction(ag, scope, source_node); - instruction->scope_is_comptime = scope_is_comptime; - instruction->is_comptime = is_comptime; - - ir_ref_instruction(scope_is_comptime, ag->current_basic_block); - ir_ref_instruction(is_comptime, ag->current_basic_block); - - return &instruction->base; -} - -static Stage1ZirInst *ir_build_union_init_named_field(Stage1AstGen *ag, Scope *scope, AstNode *source_node, - Stage1ZirInst *union_type, Stage1ZirInst *field_name, Stage1ZirInst *field_result_loc, Stage1ZirInst *result_loc) -{ - Stage1ZirInstUnionInitNamedField *instruction = ir_build_instruction(ag, scope, source_node); - instruction->union_type = union_type; - instruction->field_name = field_name; - instruction->field_result_loc = field_result_loc; - instruction->result_loc = result_loc; - - ir_ref_instruction(union_type, ag->current_basic_block); - ir_ref_instruction(field_name, ag->current_basic_block); - ir_ref_instruction(field_result_loc, ag->current_basic_block); - if (result_loc != nullptr) ir_ref_instruction(result_loc, ag->current_basic_block); - - return &instruction->base; -} - -static Stage1ZirInst *ir_build_alloca_src(Stage1AstGen *ag, Scope *scope, AstNode *source_node, - Stage1ZirInst *align, const char *name_hint, Stage1ZirInst *is_comptime) -{ - Stage1ZirInstAlloca *instruction = ir_build_instruction(ag, scope, source_node); - instruction->align = align; - instruction->name_hint = name_hint; - instruction->is_comptime = is_comptime; - - if (align != nullptr) ir_ref_instruction(align, ag->current_basic_block); - if (is_comptime != nullptr) ir_ref_instruction(is_comptime, ag->current_basic_block); - - return &instruction->base; -} - -static Stage1ZirInst *ir_build_end_expr(Stage1AstGen *ag, Scope *scope, AstNode *source_node, - Stage1ZirInst *value, ResultLoc *result_loc) -{ - Stage1ZirInstEndExpr *instruction = ir_build_instruction(ag, scope, source_node); - instruction->value = value; - instruction->result_loc = result_loc; - - ir_ref_instruction(value, ag->current_basic_block); - - return &instruction->base; -} - -static Stage1ZirInstSuspendBegin *ir_build_suspend_begin_src(Stage1AstGen *ag, Scope *scope, AstNode *source_node) { - return ir_build_instruction(ag, scope, source_node); -} - -static Stage1ZirInst *ir_build_suspend_finish_src(Stage1AstGen *ag, Scope *scope, AstNode *source_node, - Stage1ZirInstSuspendBegin *begin) -{ - Stage1ZirInstSuspendFinish *inst = ir_build_instruction(ag, scope, source_node); - inst->begin = begin; - - ir_ref_instruction(&begin->base, ag->current_basic_block); - - return &inst->base; -} - -static Stage1ZirInst *ir_build_await_src(Stage1AstGen *ag, Scope *scope, AstNode *source_node, - Stage1ZirInst *frame, ResultLoc *result_loc, bool is_nosuspend) -{ - Stage1ZirInstAwait *instruction = ir_build_instruction(ag, scope, source_node); - instruction->frame = frame; - instruction->result_loc = result_loc; - instruction->is_nosuspend = is_nosuspend; - - ir_ref_instruction(frame, ag->current_basic_block); - - return &instruction->base; -} - -static Stage1ZirInst *ir_build_resume_src(Stage1AstGen *ag, Scope *scope, AstNode *source_node, Stage1ZirInst *frame) { - Stage1ZirInstResume *instruction = ir_build_instruction(ag, scope, source_node); - instruction->frame = frame; - - ir_ref_instruction(frame, ag->current_basic_block); - - return &instruction->base; -} - -static Stage1ZirInstSpillBegin *ir_build_spill_begin_src(Stage1AstGen *ag, Scope *scope, AstNode *source_node, - Stage1ZirInst *operand, SpillId spill_id) -{ - Stage1ZirInstSpillBegin *instruction = ir_build_instruction(ag, scope, source_node); - instruction->operand = operand; - instruction->spill_id = spill_id; - - ir_ref_instruction(operand, ag->current_basic_block); - - return instruction; -} - -static Stage1ZirInst *ir_build_spill_end_src(Stage1AstGen *ag, Scope *scope, AstNode *source_node, - Stage1ZirInstSpillBegin *begin) -{ - Stage1ZirInstSpillEnd *instruction = ir_build_instruction(ag, scope, source_node); - instruction->begin = begin; - - ir_ref_instruction(&begin->base, ag->current_basic_block); - - return &instruction->base; -} - -static Stage1ZirInst *ir_build_wasm_memory_size_src(Stage1AstGen *ag, Scope *scope, AstNode *source_node, Stage1ZirInst *index) { - Stage1ZirInstWasmMemorySize *instruction = ir_build_instruction(ag, scope, source_node); - instruction->index = index; - - ir_ref_instruction(index, ag->current_basic_block); - - return &instruction->base; -} - -static Stage1ZirInst *ir_build_wasm_memory_grow_src(Stage1AstGen *ag, Scope *scope, AstNode *source_node, Stage1ZirInst *index, Stage1ZirInst *delta) { - Stage1ZirInstWasmMemoryGrow *instruction = ir_build_instruction(ag, scope, source_node); - instruction->index = index; - instruction->delta = delta; - - ir_ref_instruction(index, ag->current_basic_block); - ir_ref_instruction(delta, ag->current_basic_block); - - return &instruction->base; -} - -static Stage1ZirInst *ir_build_src(Stage1AstGen *ag, Scope *scope, AstNode *source_node) { - Stage1ZirInstSrc *instruction = ir_build_instruction(ag, scope, source_node); - - return &instruction->base; -} - -static Stage1ZirInst *ir_build_prefetch(Stage1AstGen *ag, Scope *scope, AstNode *source_node, - Stage1ZirInst *ptr, Stage1ZirInst *options) -{ - Stage1ZirInstPrefetch *prefetch_instruction = ir_build_instruction( - ag, scope, source_node); - prefetch_instruction->ptr = ptr; - prefetch_instruction->options = options; - - ir_ref_instruction(ptr, ag->current_basic_block); - ir_ref_instruction(options, ag->current_basic_block); - - return &prefetch_instruction->base; -} - - -static void ir_count_defers(Stage1AstGen *ag, Scope *inner_scope, Scope *outer_scope, size_t *results) { - results[ReturnKindUnconditional] = 0; - results[ReturnKindError] = 0; - - Scope *scope = inner_scope; - - while (scope != outer_scope) { - assert(scope); - switch (scope->id) { - case ScopeIdDefer: { - AstNode *defer_node = scope->source_node; - assert(defer_node->type == NodeTypeDefer); - ReturnKind defer_kind = defer_node->data.defer.kind; - results[defer_kind] += 1; - scope = scope->parent; - continue; - } - case ScopeIdDecls: - case ScopeIdFnDef: - return; - case ScopeIdBlock: - case ScopeIdVarDecl: - case ScopeIdLoop: - case ScopeIdSuspend: - case ScopeIdCompTime: - case ScopeIdNoSuspend: - case ScopeIdRuntime: - case ScopeIdTypeOf: - case ScopeIdExpr: - scope = scope->parent; - continue; - case ScopeIdDeferExpr: - case ScopeIdCImport: - zig_unreachable(); - } - } -} - -static bool astgen_defers_for_block(Stage1AstGen *ag, Scope *inner_scope, Scope *outer_scope, bool *is_noreturn, Stage1ZirInst *err_value) { - Scope *scope = inner_scope; - if (is_noreturn != nullptr) *is_noreturn = false; - while (scope != outer_scope) { - if (!scope) - return true; - - switch (scope->id) { - case ScopeIdDefer: { - AstNode *defer_node = scope->source_node; - assert(defer_node->type == NodeTypeDefer); - ReturnKind defer_kind = defer_node->data.defer.kind; - AstNode *defer_expr_node = defer_node->data.defer.expr; - AstNode *defer_var_node = defer_node->data.defer.err_payload; - - if (defer_kind == ReturnKindError && err_value == nullptr) { - // This is an `errdefer` but we're generating code for a - // `return` that doesn't return an error, skip it - scope = scope->parent; - continue; - } - - Scope *defer_expr_scope = defer_node->data.defer.expr_scope; - if (defer_var_node != nullptr) { - assert(defer_kind == ReturnKindError); - assert(defer_var_node->type == NodeTypeIdentifier); - Buf *var_name = node_identifier_buf(defer_var_node); - - if (defer_expr_node->type == NodeTypeUnreachable) { - add_node_error(ag->codegen, defer_var_node, - buf_sprintf("unused variable: '%s'", buf_ptr(var_name))); - return false; - } - - Stage1ZirInst *is_comptime; - if (ir_should_inline(ag->exec, defer_expr_scope)) { - is_comptime = ir_build_const_bool(ag, defer_expr_scope, - defer_expr_node, true); - } else { - is_comptime = ir_build_test_comptime(ag, defer_expr_scope, - defer_expr_node, err_value); - } - - ZigVar *err_var = ir_create_var(ag, defer_var_node, defer_expr_scope, - var_name, true, true, false, is_comptime); - build_decl_var_and_init(ag, defer_expr_scope, defer_var_node, err_var, err_value, - buf_ptr(var_name), is_comptime); - - defer_expr_scope = err_var->child_scope; - } - - Stage1ZirInst *defer_expr_value = astgen_node(ag, defer_expr_node, defer_expr_scope); - if (defer_expr_value == ag->codegen->invalid_inst_src) - return ag->codegen->invalid_inst_src; - - if (instr_is_unreachable(defer_expr_value)) { - if (is_noreturn != nullptr) *is_noreturn = true; - } else { - ir_build_check_statement_is_void(ag, defer_expr_scope, defer_expr_node, - defer_expr_value); - } - scope = scope->parent; - continue; - } - case ScopeIdDecls: - case ScopeIdFnDef: - return true; - case ScopeIdBlock: - case ScopeIdVarDecl: - case ScopeIdLoop: - case ScopeIdSuspend: - case ScopeIdCompTime: - case ScopeIdNoSuspend: - case ScopeIdRuntime: - case ScopeIdTypeOf: - case ScopeIdExpr: - scope = scope->parent; - continue; - case ScopeIdDeferExpr: - case ScopeIdCImport: - zig_unreachable(); - } - } - return true; -} - -static void ir_set_cursor_at_end(Stage1AstGen *ag, Stage1ZirBasicBlock *basic_block) { - assert(basic_block); - ag->current_basic_block = basic_block; -} - -static void ir_set_cursor_at_end_and_append_block(Stage1AstGen *ag, Stage1ZirBasicBlock *basic_block) { - basic_block->index = ag->exec->basic_block_list.length; - ag->exec->basic_block_list.append(basic_block); - ir_set_cursor_at_end(ag, basic_block); -} - -static ScopeSuspend *get_scope_suspend(Scope *scope) { - while (scope) { - if (scope->id == ScopeIdSuspend) - return (ScopeSuspend *)scope; - if (scope->id == ScopeIdFnDef) - return nullptr; - - scope = scope->parent; - } - return nullptr; -} - -static ScopeDeferExpr *get_scope_defer_expr(Scope *scope) { - while (scope) { - if (scope->id == ScopeIdDeferExpr) - return (ScopeDeferExpr *)scope; - if (scope->id == ScopeIdFnDef) - return nullptr; - - scope = scope->parent; - } - return nullptr; -} - -static Stage1ZirInst *astgen_return(Stage1AstGen *ag, Scope *scope, AstNode *node, LVal lval, ResultLoc *result_loc) { - assert(node->type == NodeTypeReturnExpr); - - ScopeDeferExpr *scope_defer_expr = get_scope_defer_expr(scope); - if (scope_defer_expr) { - if (!scope_defer_expr->reported_err) { - add_node_error(ag->codegen, node, buf_sprintf("cannot return from defer expression")); - scope_defer_expr->reported_err = true; - } - return ag->codegen->invalid_inst_src; - } - - Scope *outer_scope = ag->exec->begin_scope; - - AstNode *expr_node = node->data.return_expr.expr; - switch (node->data.return_expr.kind) { - case ReturnKindUnconditional: - { - ResultLocReturn *result_loc_ret = heap::c_allocator.create(); - result_loc_ret->base.id = ResultLocIdReturn; - ir_build_reset_result(ag, scope, node, &result_loc_ret->base); - - Stage1ZirInst *return_value; - if (expr_node) { - // Temporarily set this so that if we return a type it gets the name of the function - ZigFn *prev_name_fn = ag->exec->name_fn; - ag->exec->name_fn = ag->fn; - return_value = astgen_node_extra(ag, expr_node, scope, LValNone, &result_loc_ret->base); - ag->exec->name_fn = prev_name_fn; - if (return_value == ag->codegen->invalid_inst_src) - return ag->codegen->invalid_inst_src; - } else { - return_value = ir_build_const_void(ag, scope, node); - ir_build_end_expr(ag, scope, node, return_value, &result_loc_ret->base); - } - - ir_build_add_implicit_return_type(ag, scope, node, return_value, result_loc_ret); - - size_t defer_counts[2]; - ir_count_defers(ag, scope, outer_scope, defer_counts); - bool have_err_defers = defer_counts[ReturnKindError] > 0; - if (!have_err_defers && !ag->codegen->have_err_ret_tracing) { - // only generate unconditional defers - if (!astgen_defers_for_block(ag, scope, outer_scope, nullptr, nullptr)) - return ag->codegen->invalid_inst_src; - Stage1ZirInst *result = ir_build_return_src(ag, scope, node, nullptr); - result_loc_ret->base.source_instruction = result; - return result; - } - bool should_inline = ir_should_inline(ag->exec, scope); - - Stage1ZirBasicBlock *err_block = ir_create_basic_block(ag, scope, "ErrRetErr"); - Stage1ZirBasicBlock *ok_block = ir_create_basic_block(ag, scope, "ErrRetOk"); - - Stage1ZirInst *is_err = ir_build_test_err_src(ag, scope, node, return_value, false, true); - - Stage1ZirInst *is_comptime; - if (should_inline) { - is_comptime = ir_build_const_bool(ag, scope, node, should_inline); - } else { - is_comptime = ir_build_test_comptime(ag, scope, node, is_err); - } - - ir_build_cond_br(ag, scope, node, is_err, err_block, ok_block, is_comptime); - Stage1ZirBasicBlock *ret_stmt_block = ir_create_basic_block(ag, scope, "RetStmt"); - - ir_set_cursor_at_end_and_append_block(ag, err_block); - if (!astgen_defers_for_block(ag, scope, outer_scope, nullptr, return_value)) - return ag->codegen->invalid_inst_src; - if (ag->codegen->have_err_ret_tracing && !should_inline) { - ir_build_save_err_ret_addr_src(ag, scope, node); - } - ir_build_br(ag, scope, node, ret_stmt_block, is_comptime); - - ir_set_cursor_at_end_and_append_block(ag, ok_block); - if (!astgen_defers_for_block(ag, scope, outer_scope, nullptr, nullptr)) - return ag->codegen->invalid_inst_src; - ir_build_br(ag, scope, node, ret_stmt_block, is_comptime); - - ir_set_cursor_at_end_and_append_block(ag, ret_stmt_block); - Stage1ZirInst *result = ir_build_return_src(ag, scope, node, nullptr); - result_loc_ret->base.source_instruction = result; - return result; - } - case ReturnKindError: - { - assert(expr_node); - Stage1ZirInst *err_union_ptr = astgen_node_extra(ag, expr_node, scope, LValPtr, nullptr); - if (err_union_ptr == ag->codegen->invalid_inst_src) - return ag->codegen->invalid_inst_src; - Stage1ZirInst *is_err_val = ir_build_test_err_src(ag, scope, node, err_union_ptr, true, false); - - Stage1ZirBasicBlock *return_block = ir_create_basic_block(ag, scope, "ErrRetReturn"); - Stage1ZirBasicBlock *continue_block = ir_create_basic_block(ag, scope, "ErrRetContinue"); - Stage1ZirInst *is_comptime; - bool should_inline = ir_should_inline(ag->exec, scope); - if (should_inline) { - is_comptime = ir_build_const_bool(ag, scope, node, true); - } else { - is_comptime = ir_build_test_comptime(ag, scope, node, is_err_val); - } - ir_build_cond_br(ag, scope, node, is_err_val, return_block, continue_block, is_comptime); - - ir_set_cursor_at_end_and_append_block(ag, return_block); - Stage1ZirInst *err_val_ptr = ir_build_unwrap_err_code_src(ag, scope, node, err_union_ptr); - Stage1ZirInst *err_val = ir_build_load_ptr(ag, scope, node, err_val_ptr); - ir_build_add_implicit_return_type(ag, scope, node, err_val, nullptr); - Stage1ZirInstSpillBegin *spill_begin = ir_build_spill_begin_src(ag, scope, node, err_val, - SpillIdRetErrCode); - ResultLocReturn *result_loc_ret = heap::c_allocator.create(); - result_loc_ret->base.id = ResultLocIdReturn; - ir_build_reset_result(ag, scope, node, &result_loc_ret->base); - ir_build_end_expr(ag, scope, node, err_val, &result_loc_ret->base); - - bool is_noreturn = false; - if (!astgen_defers_for_block(ag, scope, outer_scope, &is_noreturn, err_val)) { - return ag->codegen->invalid_inst_src; - } - if (!is_noreturn) { - if (ag->codegen->have_err_ret_tracing && !should_inline) { - ir_build_save_err_ret_addr_src(ag, scope, node); - } - err_val = ir_build_spill_end_src(ag, scope, node, spill_begin); - Stage1ZirInst *ret_inst = ir_build_return_src(ag, scope, node, err_val); - result_loc_ret->base.source_instruction = ret_inst; - } - - ir_set_cursor_at_end_and_append_block(ag, continue_block); - Stage1ZirInst *unwrapped_ptr = ir_build_unwrap_err_payload_src(ag, scope, node, err_union_ptr, false, false); - if (lval == LValPtr) - return unwrapped_ptr; - else - return ir_expr_wrap(ag, scope, ir_build_load_ptr(ag, scope, node, unwrapped_ptr), result_loc); - } - } - zig_unreachable(); -} - -ZigVar *create_local_var(CodeGen *codegen, AstNode *node, Scope *parent_scope, - Buf *name, bool src_is_const, bool gen_is_const, bool is_shadowable, Stage1ZirInst *is_comptime, - bool skip_name_check) -{ - ZigVar *variable_entry = heap::c_allocator.create(); - variable_entry->parent_scope = parent_scope; - variable_entry->shadowable = is_shadowable; - variable_entry->is_comptime = is_comptime; - variable_entry->src_arg_index = SIZE_MAX; - variable_entry->const_value = codegen->pass1_arena->create(); - - if (is_comptime != nullptr) { - is_comptime->ref_count += 1; - } - - if (name) { - variable_entry->name = strdup(buf_ptr(name)); - - if (!skip_name_check) { - ZigVar *existing_var = find_variable(codegen, parent_scope, name, nullptr); - if (existing_var && !existing_var->shadowable) { - if (existing_var->var_type == nullptr || !type_is_invalid(existing_var->var_type)) { - ErrorMsg *msg = add_node_error(codegen, node, - buf_sprintf("redeclaration of variable '%s'", buf_ptr(name))); - add_error_note(codegen, msg, existing_var->decl_node, buf_sprintf("previous declaration here")); - } - variable_entry->var_type = codegen->builtin_types.entry_invalid; - } - } - } else { - assert(is_shadowable); - // TODO make this name not actually be in scope. user should be able to make a variable called "_anon" - // might already be solved, let's just make sure it has test coverage - // maybe we put a prefix on this so the debug info doesn't clobber user debug info for same named variables - variable_entry->name = "_anon"; - } - - variable_entry->src_is_const = src_is_const; - variable_entry->gen_is_const = gen_is_const; - variable_entry->decl_node = node; - variable_entry->child_scope = create_var_scope(codegen, node, parent_scope, variable_entry); - - return variable_entry; -} - - -// Set name to nullptr to make the variable anonymous (not visible to programmer). -// After you call this function var->child_scope has the variable in scope -static ZigVar *ir_create_var(Stage1AstGen *ag, AstNode *node, Scope *scope, Buf *name, - bool src_is_const, bool gen_is_const, bool is_shadowable, Stage1ZirInst *is_comptime) -{ - bool is_underscored = name ? buf_eql_str(name, "_") : false; - ZigVar *var = create_local_var(ag->codegen, node, scope, - (is_underscored ? nullptr : name), src_is_const, gen_is_const, - (is_underscored ? true : is_shadowable), is_comptime, false); - assert(var->child_scope); - return var; -} - -static ResultLocPeer *create_peer_result(ResultLocPeerParent *peer_parent) { - ResultLocPeer *result = heap::c_allocator.create(); - result->base.id = ResultLocIdPeer; - result->base.source_instruction = peer_parent->base.source_instruction; - result->parent = peer_parent; - result->base.allow_write_through_const = peer_parent->parent->allow_write_through_const; - return result; -} - -static bool is_duplicate_label(CodeGen *g, Scope *scope, AstNode *node, Buf *name) { - if (name == nullptr) return false; - - for (;;) { - if (scope == nullptr || scope->id == ScopeIdFnDef) { - break; - } else if (scope->id == ScopeIdBlock || scope->id == ScopeIdLoop) { - Buf *this_block_name = scope->id == ScopeIdBlock ? ((ScopeBlock *)scope)->name : ((ScopeLoop *)scope)->name; - if (this_block_name != nullptr && buf_eql_buf(name, this_block_name)) { - ErrorMsg *msg = add_node_error(g, node, buf_sprintf("redeclaration of label '%s'", buf_ptr(name))); - add_error_note(g, msg, scope->source_node, buf_sprintf("previous declaration here")); - return true; - } - } - scope = scope->parent; - } - return false; -} - -static Stage1ZirInst *astgen_block(Stage1AstGen *ag, Scope *parent_scope, AstNode *block_node, LVal lval, - ResultLoc *result_loc) -{ - assert(block_node->type == NodeTypeBlock); - - ZigList incoming_values = {0}; - ZigList incoming_blocks = {0}; - - if (is_duplicate_label(ag->codegen, parent_scope, block_node, block_node->data.block.name)) - return ag->codegen->invalid_inst_src; - - ScopeBlock *scope_block = create_block_scope(ag->codegen, block_node, parent_scope); - - Scope *outer_block_scope = &scope_block->base; - Scope *child_scope = outer_block_scope; - - ZigFn *fn_entry = scope_fn_entry(parent_scope); - if (fn_entry && fn_entry->child_scope == parent_scope) { - fn_entry->def_scope = scope_block; - } - - if (block_node->data.block.statements.length == 0) { - if (scope_block->name != nullptr) { - add_node_error(ag->codegen, block_node, buf_sprintf("unused block label")); - } - // {} - return ir_lval_wrap(ag, parent_scope, ir_build_const_void(ag, child_scope, block_node), lval, result_loc); - } - - if (block_node->data.block.name != nullptr) { - scope_block->lval = lval; - scope_block->incoming_blocks = &incoming_blocks; - scope_block->incoming_values = &incoming_values; - scope_block->end_block = ir_create_basic_block(ag, parent_scope, "BlockEnd"); - scope_block->is_comptime = ir_build_const_bool(ag, parent_scope, block_node, - ir_should_inline(ag->exec, parent_scope)); - - scope_block->peer_parent = heap::c_allocator.create(); - scope_block->peer_parent->base.id = ResultLocIdPeerParent; - scope_block->peer_parent->base.source_instruction = scope_block->is_comptime; - scope_block->peer_parent->base.allow_write_through_const = result_loc->allow_write_through_const; - scope_block->peer_parent->end_bb = scope_block->end_block; - scope_block->peer_parent->is_comptime = scope_block->is_comptime; - scope_block->peer_parent->parent = result_loc; - ir_build_reset_result(ag, parent_scope, block_node, &scope_block->peer_parent->base); - } - - bool is_continuation_unreachable = false; - bool found_invalid_inst = false; - Stage1ZirInst *noreturn_return_value = nullptr; - for (size_t i = 0; i < block_node->data.block.statements.length; i += 1) { - AstNode *statement_node = block_node->data.block.statements.at(i); - - Stage1ZirInst *statement_value = astgen_node(ag, statement_node, child_scope); - if (statement_value == ag->codegen->invalid_inst_src) { - // keep generating all the elements of the block in case of error, - // we want to collect other compile errors - found_invalid_inst = true; - continue; - } - - is_continuation_unreachable = instr_is_unreachable(statement_value); - if (is_continuation_unreachable) { - // keep the last noreturn statement value around in case we need to return it - noreturn_return_value = statement_value; - } - // This logic must be kept in sync with - // [STMT_EXPR_TEST_THING] <--- (search this token) - if (statement_node->type == NodeTypeDefer) { - // defer starts a new scope - child_scope = statement_node->data.defer.child_scope; - assert(child_scope); - } else if (statement_value->id == Stage1ZirInstIdDeclVar) { - // variable declarations start a new scope - Stage1ZirInstDeclVar *decl_var_instruction = (Stage1ZirInstDeclVar *)statement_value; - child_scope = decl_var_instruction->var->child_scope; - } else if (!is_continuation_unreachable) { - // this statement's value must be void - ir_build_check_statement_is_void(ag, child_scope, statement_node, statement_value); - } - } - - if (scope_block->name != nullptr && scope_block->name_used == false) { - add_node_error(ag->codegen, block_node, buf_sprintf("unused block label")); - } - - if (found_invalid_inst) - return ag->codegen->invalid_inst_src; - - if (is_continuation_unreachable) { - assert(noreturn_return_value != nullptr); - if (block_node->data.block.name == nullptr || incoming_blocks.length == 0) { - return noreturn_return_value; - } - - if (scope_block->peer_parent != nullptr && scope_block->peer_parent->peers.length != 0) { - scope_block->peer_parent->peers.last()->next_bb = scope_block->end_block; - } - ir_set_cursor_at_end_and_append_block(ag, scope_block->end_block); - Stage1ZirInst *phi = ir_build_phi(ag, parent_scope, block_node, false, incoming_blocks.length, - incoming_blocks.items, incoming_values.items, scope_block->peer_parent); - return ir_expr_wrap(ag, parent_scope, phi, result_loc); - } else { - incoming_blocks.append(ag->current_basic_block); - Stage1ZirInst *else_expr_result = ir_build_const_void(ag, parent_scope, block_node); - - if (scope_block->peer_parent != nullptr) { - ResultLocPeer *peer_result = create_peer_result(scope_block->peer_parent); - scope_block->peer_parent->peers.append(peer_result); - ir_build_end_expr(ag, parent_scope, block_node, else_expr_result, &peer_result->base); - - if (scope_block->peer_parent->peers.length != 0) { - scope_block->peer_parent->peers.last()->next_bb = scope_block->end_block; - } - } - - incoming_values.append(else_expr_result); - } - - bool is_return_from_fn = block_node == ag->main_block_node; - if (!is_return_from_fn) { - if (!astgen_defers_for_block(ag, child_scope, outer_block_scope, nullptr, nullptr)) - return ag->codegen->invalid_inst_src; - } - - Stage1ZirInst *result; - if (block_node->data.block.name != nullptr) { - ir_build_br(ag, parent_scope, block_node, scope_block->end_block, scope_block->is_comptime); - ir_set_cursor_at_end_and_append_block(ag, scope_block->end_block); - Stage1ZirInst *phi = ir_build_phi(ag, parent_scope, block_node, false, incoming_blocks.length, - incoming_blocks.items, incoming_values.items, scope_block->peer_parent); - result = ir_expr_wrap(ag, parent_scope, phi, result_loc); - } else { - Stage1ZirInst *void_inst = ir_build_const_void(ag, child_scope, block_node); - result = ir_lval_wrap(ag, parent_scope, void_inst, lval, result_loc); - } - if (!is_return_from_fn) - return result; - - // no need for save_err_ret_addr because this cannot return error - // only generate unconditional defers - - ir_build_add_implicit_return_type(ag, child_scope, block_node, result, nullptr); - ResultLocReturn *result_loc_ret = heap::c_allocator.create(); - result_loc_ret->base.id = ResultLocIdReturn; - ir_build_reset_result(ag, parent_scope, block_node, &result_loc_ret->base); - ir_build_end_expr(ag, parent_scope, block_node, result, &result_loc_ret->base); - if (!astgen_defers_for_block(ag, child_scope, outer_block_scope, nullptr, nullptr)) - return ag->codegen->invalid_inst_src; - return ir_build_return_src(ag, child_scope, result->source_node, result); -} - -static Stage1ZirInst *astgen_bin_op_id(Stage1AstGen *ag, Scope *scope, AstNode *node, IrBinOp op_id) { - Scope *inner_scope = scope; - if (op_id == IrBinOpArrayCat || op_id == IrBinOpArrayMult) { - inner_scope = create_comptime_scope(ag->codegen, node, scope); - } - - Stage1ZirInst *op1 = astgen_node(ag, node->data.bin_op_expr.op1, inner_scope); - Stage1ZirInst *op2 = astgen_node(ag, node->data.bin_op_expr.op2, inner_scope); - - if (op1 == ag->codegen->invalid_inst_src || op2 == ag->codegen->invalid_inst_src) - return ag->codegen->invalid_inst_src; - - return ir_build_bin_op(ag, scope, node, op_id, op1, op2, true); -} - -static Stage1ZirInst *astgen_merge_err_sets(Stage1AstGen *ag, Scope *scope, AstNode *node) { - Stage1ZirInst *op1 = astgen_node(ag, node->data.bin_op_expr.op1, scope); - Stage1ZirInst *op2 = astgen_node(ag, node->data.bin_op_expr.op2, scope); - - if (op1 == ag->codegen->invalid_inst_src || op2 == ag->codegen->invalid_inst_src) - return ag->codegen->invalid_inst_src; - - // TODO only pass type_name when the || operator is the top level AST node in the var decl expr - Buf bare_name = BUF_INIT; - Buf *type_name = get_anon_type_name(ag->codegen, ag->exec, "error", scope, node, &bare_name, nullptr); - - return ir_build_merge_err_sets(ag, scope, node, op1, op2, type_name); -} - -static Stage1ZirInst *astgen_assign(Stage1AstGen *ag, Scope *scope, AstNode *node) { - Stage1ZirInst *lvalue = astgen_node_extra(ag, node->data.bin_op_expr.op1, scope, LValAssign, nullptr); - if (lvalue == ag->codegen->invalid_inst_src) - return ag->codegen->invalid_inst_src; - - ResultLocInstruction *result_loc_inst = heap::c_allocator.create(); - result_loc_inst->base.id = ResultLocIdInstruction; - result_loc_inst->base.source_instruction = lvalue; - ir_ref_instruction(lvalue, ag->current_basic_block); - ir_build_reset_result(ag, scope, node, &result_loc_inst->base); - - Stage1ZirInst *rvalue = astgen_node_extra(ag, node->data.bin_op_expr.op2, scope, LValNone, - &result_loc_inst->base); - if (rvalue == ag->codegen->invalid_inst_src) - return ag->codegen->invalid_inst_src; - - return ir_build_const_void(ag, scope, node); -} - -static Stage1ZirInst *astgen_assign_op(Stage1AstGen *ag, Scope *scope, AstNode *node, IrBinOp op_id) { - Stage1ZirInst *lvalue = astgen_node_extra(ag, node->data.bin_op_expr.op1, scope, LValAssign, nullptr); - if (lvalue == ag->codegen->invalid_inst_src) - return lvalue; - Stage1ZirInst *op1 = ir_build_load_ptr(ag, scope, node->data.bin_op_expr.op1, lvalue); - Stage1ZirInst *op2 = astgen_node(ag, node->data.bin_op_expr.op2, scope); - if (op2 == ag->codegen->invalid_inst_src) - return op2; - Stage1ZirInst *result = ir_build_bin_op(ag, scope, node, op_id, op1, op2, true); - ir_build_store_ptr(ag, scope, node, lvalue, result); - return ir_build_const_void(ag, scope, node); -} - -static Stage1ZirInst *astgen_bool_or(Stage1AstGen *ag, Scope *scope, AstNode *node) { - assert(node->type == NodeTypeBinOpExpr); - - Stage1ZirInst *val1 = astgen_node(ag, node->data.bin_op_expr.op1, scope); - if (val1 == ag->codegen->invalid_inst_src) - return ag->codegen->invalid_inst_src; - Stage1ZirBasicBlock *post_val1_block = ag->current_basic_block; - - Stage1ZirInst *is_comptime; - if (ir_should_inline(ag->exec, scope)) { - is_comptime = ir_build_const_bool(ag, scope, node, true); - } else { - is_comptime = ir_build_test_comptime(ag, scope, node, val1); - } - - // block for when val1 == false - Stage1ZirBasicBlock *false_block = ir_create_basic_block(ag, scope, "BoolOrFalse"); - // block for when val1 == true (don't even evaluate the second part) - Stage1ZirBasicBlock *true_block = ir_create_basic_block(ag, scope, "BoolOrTrue"); - - Stage1ZirInst *val1_true = ir_build_const_bool(ag, scope, node, true); - ir_build_cond_br(ag, scope, node, val1, true_block, false_block, is_comptime); - - ir_set_cursor_at_end_and_append_block(ag, false_block); - Stage1ZirInst *val2 = astgen_node(ag, node->data.bin_op_expr.op2, scope); - if (val2 == ag->codegen->invalid_inst_src) - return ag->codegen->invalid_inst_src; - Stage1ZirBasicBlock *post_val2_block = ag->current_basic_block; - - ir_build_br(ag, scope, node, true_block, is_comptime); - - ir_set_cursor_at_end_and_append_block(ag, true_block); - - Stage1ZirInst **incoming_values = heap::c_allocator.allocate(2); - incoming_values[0] = val1_true; - incoming_values[1] = val2; - Stage1ZirBasicBlock **incoming_blocks = heap::c_allocator.allocate(2); - incoming_blocks[0] = post_val1_block; - incoming_blocks[1] = post_val2_block; - - const bool merge_comptime = true; - return ir_build_phi(ag, scope, node, merge_comptime, 2, incoming_blocks, incoming_values, nullptr); -} - -static Stage1ZirInst *astgen_bool_and(Stage1AstGen *ag, Scope *scope, AstNode *node) { - assert(node->type == NodeTypeBinOpExpr); - - Stage1ZirInst *val1 = astgen_node(ag, node->data.bin_op_expr.op1, scope); - if (val1 == ag->codegen->invalid_inst_src) - return ag->codegen->invalid_inst_src; - Stage1ZirBasicBlock *post_val1_block = ag->current_basic_block; - - Stage1ZirInst *is_comptime; - if (ir_should_inline(ag->exec, scope)) { - is_comptime = ir_build_const_bool(ag, scope, node, true); - } else { - is_comptime = ir_build_test_comptime(ag, scope, node, val1); - } - - // block for when val1 == true - Stage1ZirBasicBlock *true_block = ir_create_basic_block(ag, scope, "BoolAndTrue"); - // block for when val1 == false (don't even evaluate the second part) - Stage1ZirBasicBlock *false_block = ir_create_basic_block(ag, scope, "BoolAndFalse"); - - Stage1ZirInst *val1_false = ir_build_const_bool(ag, scope, node, false); - ir_build_cond_br(ag, scope, node, val1, true_block, false_block, is_comptime); - - ir_set_cursor_at_end_and_append_block(ag, true_block); - Stage1ZirInst *val2 = astgen_node(ag, node->data.bin_op_expr.op2, scope); - if (val2 == ag->codegen->invalid_inst_src) - return ag->codegen->invalid_inst_src; - Stage1ZirBasicBlock *post_val2_block = ag->current_basic_block; - - ir_build_br(ag, scope, node, false_block, is_comptime); - - ir_set_cursor_at_end_and_append_block(ag, false_block); - - Stage1ZirInst **incoming_values = heap::c_allocator.allocate(2); - incoming_values[0] = val1_false; - incoming_values[1] = val2; - Stage1ZirBasicBlock **incoming_blocks = heap::c_allocator.allocate(2); - incoming_blocks[0] = post_val1_block; - incoming_blocks[1] = post_val2_block; - - const bool merge_comptime = true; - return ir_build_phi(ag, scope, node, merge_comptime, 2, incoming_blocks, incoming_values, nullptr); -} - -static ResultLocPeerParent *ir_build_result_peers(Stage1AstGen *ag, Stage1ZirInst *cond_br_inst, - Stage1ZirBasicBlock *end_block, ResultLoc *parent, Stage1ZirInst *is_comptime) -{ - ResultLocPeerParent *peer_parent = heap::c_allocator.create(); - peer_parent->base.id = ResultLocIdPeerParent; - peer_parent->base.source_instruction = cond_br_inst; - peer_parent->base.allow_write_through_const = parent->allow_write_through_const; - peer_parent->end_bb = end_block; - peer_parent->is_comptime = is_comptime; - peer_parent->parent = parent; - - Stage1ZirInst *popped_inst = ag->current_basic_block->instruction_list.pop(); - ir_assert(popped_inst == cond_br_inst, cond_br_inst); - - ir_build_reset_result(ag, cond_br_inst->scope, cond_br_inst->source_node, &peer_parent->base); - ag->current_basic_block->instruction_list.append(popped_inst); - - return peer_parent; -} - -static ResultLocPeerParent *ir_build_binary_result_peers(Stage1AstGen *ag, Stage1ZirInst *cond_br_inst, - Stage1ZirBasicBlock *else_block, Stage1ZirBasicBlock *end_block, ResultLoc *parent, Stage1ZirInst *is_comptime) -{ - ResultLocPeerParent *peer_parent = ir_build_result_peers(ag, cond_br_inst, end_block, parent, is_comptime); - - peer_parent->peers.append(create_peer_result(peer_parent)); - peer_parent->peers.last()->next_bb = else_block; - - peer_parent->peers.append(create_peer_result(peer_parent)); - peer_parent->peers.last()->next_bb = end_block; - - return peer_parent; -} - -static Stage1ZirInst *astgen_orelse(Stage1AstGen *ag, Scope *parent_scope, AstNode *node, LVal lval, - ResultLoc *result_loc) -{ - assert(node->type == NodeTypeBinOpExpr); - - AstNode *op1_node = node->data.bin_op_expr.op1; - AstNode *op2_node = node->data.bin_op_expr.op2; - - Stage1ZirInst *maybe_ptr = astgen_node_extra(ag, op1_node, parent_scope, LValPtr, nullptr); - if (maybe_ptr == ag->codegen->invalid_inst_src) - return ag->codegen->invalid_inst_src; - - Stage1ZirInst *maybe_val = ir_build_load_ptr(ag, parent_scope, node, maybe_ptr); - Stage1ZirInst *is_non_null = ir_build_test_non_null_src(ag, parent_scope, node, maybe_val); - - Stage1ZirInst *is_comptime; - if (ir_should_inline(ag->exec, parent_scope)) { - is_comptime = ir_build_const_bool(ag, parent_scope, node, true); - } else { - is_comptime = ir_build_test_comptime(ag, parent_scope, node, is_non_null); - } - - Stage1ZirBasicBlock *ok_block = ir_create_basic_block(ag, parent_scope, "OptionalNonNull"); - Stage1ZirBasicBlock *null_block = ir_create_basic_block(ag, parent_scope, "OptionalNull"); - Stage1ZirBasicBlock *end_block = ir_create_basic_block(ag, parent_scope, "OptionalEnd"); - Stage1ZirInst *cond_br_inst = ir_build_cond_br(ag, parent_scope, node, is_non_null, ok_block, null_block, is_comptime); - - ResultLocPeerParent *peer_parent = ir_build_binary_result_peers(ag, cond_br_inst, ok_block, end_block, - result_loc, is_comptime); - - ir_set_cursor_at_end_and_append_block(ag, null_block); - Stage1ZirInst *null_result = astgen_node_extra(ag, op2_node, parent_scope, LValNone, - &peer_parent->peers.at(0)->base); - if (null_result == ag->codegen->invalid_inst_src) - return ag->codegen->invalid_inst_src; - Stage1ZirBasicBlock *after_null_block = ag->current_basic_block; - if (!instr_is_unreachable(null_result)) - ir_build_br(ag, parent_scope, node, end_block, is_comptime); - - ir_set_cursor_at_end_and_append_block(ag, ok_block); - Stage1ZirInst *unwrapped_ptr = ir_build_optional_unwrap_ptr(ag, parent_scope, node, maybe_ptr, false); - Stage1ZirInst *unwrapped_payload = ir_build_load_ptr(ag, parent_scope, node, unwrapped_ptr); - ir_build_end_expr(ag, parent_scope, node, unwrapped_payload, &peer_parent->peers.at(1)->base); - Stage1ZirBasicBlock *after_ok_block = ag->current_basic_block; - ir_build_br(ag, parent_scope, node, end_block, is_comptime); - - ir_set_cursor_at_end_and_append_block(ag, end_block); - Stage1ZirInst **incoming_values = heap::c_allocator.allocate(2); - incoming_values[0] = null_result; - incoming_values[1] = unwrapped_payload; - Stage1ZirBasicBlock **incoming_blocks = heap::c_allocator.allocate(2); - incoming_blocks[0] = after_null_block; - incoming_blocks[1] = after_ok_block; - Stage1ZirInst *phi = ir_build_phi(ag, parent_scope, node, false, 2, incoming_blocks, incoming_values, peer_parent); - return ir_lval_wrap(ag, parent_scope, phi, lval, result_loc); -} - -static Stage1ZirInst *astgen_error_union(Stage1AstGen *ag, Scope *parent_scope, AstNode *node) { - assert(node->type == NodeTypeBinOpExpr); - - AstNode *op1_node = node->data.bin_op_expr.op1; - AstNode *op2_node = node->data.bin_op_expr.op2; - - Stage1ZirInst *err_set = astgen_node(ag, op1_node, parent_scope); - if (err_set == ag->codegen->invalid_inst_src) - return ag->codegen->invalid_inst_src; - - Stage1ZirInst *payload = astgen_node(ag, op2_node, parent_scope); - if (payload == ag->codegen->invalid_inst_src) - return ag->codegen->invalid_inst_src; - - return ir_build_error_union(ag, parent_scope, node, err_set, payload); -} - -static Stage1ZirInst *astgen_bin_op(Stage1AstGen *ag, Scope *scope, AstNode *node, LVal lval, ResultLoc *result_loc) { - assert(node->type == NodeTypeBinOpExpr); - - BinOpType bin_op_type = node->data.bin_op_expr.bin_op; - switch (bin_op_type) { - case BinOpTypeInvalid: - zig_unreachable(); - case BinOpTypeAssign: - return ir_lval_wrap(ag, scope, astgen_assign(ag, scope, node), lval, result_loc); - case BinOpTypeAssignTimes: - return ir_lval_wrap(ag, scope, astgen_assign_op(ag, scope, node, IrBinOpMult), lval, result_loc); - case BinOpTypeAssignTimesWrap: - return ir_lval_wrap(ag, scope, astgen_assign_op(ag, scope, node, IrBinOpMultWrap), lval, result_loc); - case BinOpTypeAssignTimesSat: - return ir_lval_wrap(ag, scope, astgen_assign_op(ag, scope, node, IrBinOpMultSat), lval, result_loc); - case BinOpTypeAssignDiv: - return ir_lval_wrap(ag, scope, astgen_assign_op(ag, scope, node, IrBinOpDivUnspecified), lval, result_loc); - case BinOpTypeAssignMod: - return ir_lval_wrap(ag, scope, astgen_assign_op(ag, scope, node, IrBinOpRemUnspecified), lval, result_loc); - case BinOpTypeAssignPlus: - return ir_lval_wrap(ag, scope, astgen_assign_op(ag, scope, node, IrBinOpAdd), lval, result_loc); - case BinOpTypeAssignPlusWrap: - return ir_lval_wrap(ag, scope, astgen_assign_op(ag, scope, node, IrBinOpAddWrap), lval, result_loc); - case BinOpTypeAssignPlusSat: - return ir_lval_wrap(ag, scope, astgen_assign_op(ag, scope, node, IrBinOpAddSat), lval, result_loc); - case BinOpTypeAssignMinus: - return ir_lval_wrap(ag, scope, astgen_assign_op(ag, scope, node, IrBinOpSub), lval, result_loc); - case BinOpTypeAssignMinusWrap: - return ir_lval_wrap(ag, scope, astgen_assign_op(ag, scope, node, IrBinOpSubWrap), lval, result_loc); - case BinOpTypeAssignMinusSat: - return ir_lval_wrap(ag, scope, astgen_assign_op(ag, scope, node, IrBinOpSubSat), lval, result_loc); - case BinOpTypeAssignBitShiftLeft: - return ir_lval_wrap(ag, scope, astgen_assign_op(ag, scope, node, IrBinOpBitShiftLeftLossy), lval, result_loc); - case BinOpTypeAssignBitShiftLeftSat: - return ir_lval_wrap(ag, scope, astgen_assign_op(ag, scope, node, IrBinOpShlSat), lval, result_loc); - case BinOpTypeAssignBitShiftRight: - return ir_lval_wrap(ag, scope, astgen_assign_op(ag, scope, node, IrBinOpBitShiftRightLossy), lval, result_loc); - case BinOpTypeAssignBitAnd: - return ir_lval_wrap(ag, scope, astgen_assign_op(ag, scope, node, IrBinOpBinAnd), lval, result_loc); - case BinOpTypeAssignBitXor: - return ir_lval_wrap(ag, scope, astgen_assign_op(ag, scope, node, IrBinOpBinXor), lval, result_loc); - case BinOpTypeAssignBitOr: - return ir_lval_wrap(ag, scope, astgen_assign_op(ag, scope, node, IrBinOpBinOr), lval, result_loc); - case BinOpTypeBoolOr: - return ir_lval_wrap(ag, scope, astgen_bool_or(ag, scope, node), lval, result_loc); - case BinOpTypeBoolAnd: - return ir_lval_wrap(ag, scope, astgen_bool_and(ag, scope, node), lval, result_loc); - case BinOpTypeCmpEq: - return ir_lval_wrap(ag, scope, astgen_bin_op_id(ag, scope, node, IrBinOpCmpEq), lval, result_loc); - case BinOpTypeCmpNotEq: - return ir_lval_wrap(ag, scope, astgen_bin_op_id(ag, scope, node, IrBinOpCmpNotEq), lval, result_loc); - case BinOpTypeCmpLessThan: - return ir_lval_wrap(ag, scope, astgen_bin_op_id(ag, scope, node, IrBinOpCmpLessThan), lval, result_loc); - case BinOpTypeCmpGreaterThan: - return ir_lval_wrap(ag, scope, astgen_bin_op_id(ag, scope, node, IrBinOpCmpGreaterThan), lval, result_loc); - case BinOpTypeCmpLessOrEq: - return ir_lval_wrap(ag, scope, astgen_bin_op_id(ag, scope, node, IrBinOpCmpLessOrEq), lval, result_loc); - case BinOpTypeCmpGreaterOrEq: - return ir_lval_wrap(ag, scope, astgen_bin_op_id(ag, scope, node, IrBinOpCmpGreaterOrEq), lval, result_loc); - case BinOpTypeBinOr: - return ir_lval_wrap(ag, scope, astgen_bin_op_id(ag, scope, node, IrBinOpBinOr), lval, result_loc); - case BinOpTypeBinXor: - return ir_lval_wrap(ag, scope, astgen_bin_op_id(ag, scope, node, IrBinOpBinXor), lval, result_loc); - case BinOpTypeBinAnd: - return ir_lval_wrap(ag, scope, astgen_bin_op_id(ag, scope, node, IrBinOpBinAnd), lval, result_loc); - case BinOpTypeBitShiftLeft: - return ir_lval_wrap(ag, scope, astgen_bin_op_id(ag, scope, node, IrBinOpBitShiftLeftLossy), lval, result_loc); - case BinOpTypeBitShiftLeftSat: - return ir_lval_wrap(ag, scope, astgen_bin_op_id(ag, scope, node, IrBinOpShlSat), lval, result_loc); - case BinOpTypeBitShiftRight: - return ir_lval_wrap(ag, scope, astgen_bin_op_id(ag, scope, node, IrBinOpBitShiftRightLossy), lval, result_loc); - case BinOpTypeAdd: - return ir_lval_wrap(ag, scope, astgen_bin_op_id(ag, scope, node, IrBinOpAdd), lval, result_loc); - case BinOpTypeAddWrap: - return ir_lval_wrap(ag, scope, astgen_bin_op_id(ag, scope, node, IrBinOpAddWrap), lval, result_loc); - case BinOpTypeAddSat: - return ir_lval_wrap(ag, scope, astgen_bin_op_id(ag, scope, node, IrBinOpAddSat), lval, result_loc); - case BinOpTypeSub: - return ir_lval_wrap(ag, scope, astgen_bin_op_id(ag, scope, node, IrBinOpSub), lval, result_loc); - case BinOpTypeSubWrap: - return ir_lval_wrap(ag, scope, astgen_bin_op_id(ag, scope, node, IrBinOpSubWrap), lval, result_loc); - case BinOpTypeSubSat: - return ir_lval_wrap(ag, scope, astgen_bin_op_id(ag, scope, node, IrBinOpSubSat), lval, result_loc); - case BinOpTypeMult: - return ir_lval_wrap(ag, scope, astgen_bin_op_id(ag, scope, node, IrBinOpMult), lval, result_loc); - case BinOpTypeMultWrap: - return ir_lval_wrap(ag, scope, astgen_bin_op_id(ag, scope, node, IrBinOpMultWrap), lval, result_loc); - case BinOpTypeMultSat: - return ir_lval_wrap(ag, scope, astgen_bin_op_id(ag, scope, node, IrBinOpMultSat), lval, result_loc); - case BinOpTypeDiv: - return ir_lval_wrap(ag, scope, astgen_bin_op_id(ag, scope, node, IrBinOpDivUnspecified), lval, result_loc); - case BinOpTypeMod: - return ir_lval_wrap(ag, scope, astgen_bin_op_id(ag, scope, node, IrBinOpRemUnspecified), lval, result_loc); - case BinOpTypeArrayCat: - return ir_lval_wrap(ag, scope, astgen_bin_op_id(ag, scope, node, IrBinOpArrayCat), lval, result_loc); - case BinOpTypeArrayMult: - return ir_lval_wrap(ag, scope, astgen_bin_op_id(ag, scope, node, IrBinOpArrayMult), lval, result_loc); - case BinOpTypeMergeErrorSets: - return ir_lval_wrap(ag, scope, astgen_merge_err_sets(ag, scope, node), lval, result_loc); - case BinOpTypeUnwrapOptional: - return astgen_orelse(ag, scope, node, lval, result_loc); - case BinOpTypeErrorUnion: - return ir_lval_wrap(ag, scope, astgen_error_union(ag, scope, node), lval, result_loc); - } - zig_unreachable(); -} - -static Stage1ZirInst *astgen_int_lit(Stage1AstGen *ag, Scope *scope, AstNode *node) { - assert(node->type == NodeTypeIntLiteral); - - RootStruct *root_struct = node->owner->data.structure.root_struct; - BigInt bigint; - token_number_literal_bigint(root_struct, &bigint, node->main_token); - return ir_build_const_bigint(ag, scope, node, bigint); -} - -static Stage1ZirInst *astgen_float_lit(Stage1AstGen *ag, Scope *scope, AstNode *node) { - Error err; - assert(node->type == NodeTypeFloatLiteral); - - RootStruct *root_struct = node->owner->data.structure.root_struct; - const char *source = buf_ptr(root_struct->source_code); - uint32_t byte_offset = root_struct->token_locs[node->main_token].offset; - - BigFloat bigfloat; - if ((err = bigfloat_init_buf(&bigfloat, (const uint8_t *)source + byte_offset))) { - add_node_error(ag->codegen, node, buf_sprintf("float literal out of range of any type")); - return ag->codegen->invalid_inst_src; - } - - return ir_build_const_bigfloat(ag, scope, node, bigfloat); -} - -static Stage1ZirInst *astgen_char_lit(Stage1AstGen *ag, Scope *scope, AstNode *node) { - Error err; - assert(node->type == NodeTypeCharLiteral); - - RootStruct *root_struct = node->owner->data.structure.root_struct; - const char *source = buf_ptr(root_struct->source_code); - uint32_t byte_offset = root_struct->token_locs[node->main_token].offset; - - src_assert(source[byte_offset] == '\'', node); - byte_offset += 1; - - uint32_t codepoint; - size_t bad_index; - if ((err = source_char_literal(source + byte_offset, &codepoint, &bad_index))) { - add_node_error(ag->codegen, node, buf_sprintf("invalid character")); - return ag->codegen->invalid_inst_src; - } - return ir_build_const_uint(ag, scope, node, codepoint); -} - -static Stage1ZirInst *astgen_identifier(Stage1AstGen *ag, Scope *scope, AstNode *node, LVal lval, - ResultLoc *result_loc) -{ - Error err; - assert(node->type == NodeTypeIdentifier); - - bool is_at_syntax; - Buf *variable_name = node_identifier_buf2(node, &is_at_syntax); - - if (!is_at_syntax) { - if (buf_eql_str(variable_name, "_")) { - if (lval == LValAssign) { - Stage1ZirInstConst *const_instruction = ir_build_instruction(ag, scope, node); - const_instruction->value = ag->codegen->pass1_arena->create(); - const_instruction->value->type = get_pointer_to_type(ag->codegen, - ag->codegen->builtin_types.entry_void, false); - const_instruction->value->special = ConstValSpecialStatic; - const_instruction->value->data.x_ptr.special = ConstPtrSpecialDiscard; - return &const_instruction->base; - } - } - - { - Stage1ZirInst *value = nullptr; - if (buf_eql_str(variable_name, "null")) { - value = ir_build_const_null(ag, scope, node); - } else if (buf_eql_str(variable_name, "true")) { - value = ir_build_const_bool(ag, scope, node, true); - } else if (buf_eql_str(variable_name, "false")) { - value = ir_build_const_bool(ag, scope, node, false); - } else if (buf_eql_str(variable_name, "undefined")) { - value = ir_build_const_undefined(ag, scope, node); - } - - if (value != nullptr) { - if (lval == LValPtr || lval == LValAssign) { - return ir_build_ref_src(ag, scope, node, value); - } else { - return ir_expr_wrap(ag, scope, value, result_loc); - } - } - } - - ZigType *primitive_type; - if ((err = get_primitive_type(ag->codegen, variable_name, &primitive_type))) { - if (err == ErrorOverflow) { - add_node_error(ag->codegen, node, - buf_sprintf("primitive integer type '%s' exceeds maximum bit width of 65535", - buf_ptr(variable_name))); - return ag->codegen->invalid_inst_src; - } - assert(err == ErrorPrimitiveTypeNotFound); - } else { - Stage1ZirInst *value = ir_build_const_type(ag, scope, node, primitive_type); - if (lval == LValPtr || lval == LValAssign) { - return ir_build_ref_src(ag, scope, node, value); - } else { - return ir_expr_wrap(ag, scope, value, result_loc); - } - } - } - - ScopeFnDef *crossed_fndef_scope; - ZigVar *var = find_variable(ag->codegen, scope, variable_name, &crossed_fndef_scope); - if (var) { - Stage1ZirInst *var_ptr = ir_build_var_ptr_x(ag, scope, node, var, crossed_fndef_scope); - if (lval == LValPtr || lval == LValAssign) { - return var_ptr; - } else { - return ir_expr_wrap(ag, scope, ir_build_load_ptr(ag, scope, node, var_ptr), result_loc); - } - } - - Tld *tld = nullptr; - { - Scope *s = scope; - while (s) { - if (s->id == ScopeIdDecls) { - ScopeDecls *decls_scope = (ScopeDecls *)s; - - Tld *result = find_container_decl(ag->codegen, decls_scope, variable_name); - if (result != nullptr) { - if (tld != nullptr && tld != result) { - ErrorMsg *msg = add_node_error(ag->codegen, node, - buf_sprintf("ambiguous reference")); - add_error_note(ag->codegen, msg, tld->source_node, - buf_sprintf("declared here")); - add_error_note(ag->codegen, msg, result->source_node, - buf_sprintf("also declared here")); - return ag->codegen->invalid_inst_src; - } - tld = result; - } - } - s = s->parent; - } - } - - if (tld) { - Stage1ZirInst *decl_ref = ir_build_decl_ref(ag, scope, node, tld, lval); - if (lval == LValPtr || lval == LValAssign) { - return decl_ref; - } else { - return ir_expr_wrap(ag, scope, decl_ref, result_loc); - } - } - - if (get_container_scope(node->owner)->any_imports_failed) { - // skip the error message since we had a failing import in this file - // if an import breaks we don't need redundant undeclared identifier errors - return ag->codegen->invalid_inst_src; - } - - return ir_build_undeclared_identifier(ag, scope, node, variable_name); -} - -static Stage1ZirInst *astgen_array_access(Stage1AstGen *ag, Scope *scope, AstNode *node, LVal lval, - ResultLoc *result_loc) -{ - assert(node->type == NodeTypeArrayAccessExpr); - - AstNode *array_ref_node = node->data.array_access_expr.array_ref_expr; - Stage1ZirInst *array_ref_instruction = astgen_node_extra(ag, array_ref_node, scope, LValPtr, nullptr); - if (array_ref_instruction == ag->codegen->invalid_inst_src) - return array_ref_instruction; - - // Create an usize-typed result location to hold the subscript value, this - // makes it possible for the compiler to infer the subscript expression type - // if needed - Stage1ZirInst *usize_type_inst = ir_build_const_type(ag, scope, node, ag->codegen->builtin_types.entry_usize); - ResultLocCast *result_loc_cast = ir_build_cast_result_loc(ag, usize_type_inst, no_result_loc()); - - AstNode *subscript_node = node->data.array_access_expr.subscript; - Stage1ZirInst *subscript_value = astgen_node_extra(ag, subscript_node, scope, LValNone, &result_loc_cast->base); - if (subscript_value == ag->codegen->invalid_inst_src) - return ag->codegen->invalid_inst_src; - - Stage1ZirInst *subscript_instruction = ir_build_implicit_cast(ag, scope, subscript_node, subscript_value, result_loc_cast); - - Stage1ZirInst *ptr_instruction = ir_build_elem_ptr(ag, scope, node, array_ref_instruction, - subscript_instruction, true, PtrLenSingle, nullptr); - if (lval == LValPtr || lval == LValAssign) - return ptr_instruction; - - Stage1ZirInst *load_ptr = ir_build_load_ptr(ag, scope, node, ptr_instruction); - return ir_expr_wrap(ag, scope, load_ptr, result_loc); -} - -static Stage1ZirInst *astgen_field_access(Stage1AstGen *ag, Scope *scope, AstNode *node) { - assert(node->type == NodeTypeFieldAccessExpr); - - AstNode *container_ref_node = node->data.field_access_expr.struct_expr; - Buf *field_name = node->data.field_access_expr.field_name; - - Stage1ZirInst *container_ref_instruction = astgen_node_extra(ag, container_ref_node, scope, LValPtr, nullptr); - if (container_ref_instruction == ag->codegen->invalid_inst_src) - return container_ref_instruction; - - return ir_build_field_ptr(ag, scope, node, container_ref_instruction, field_name, false); -} - -static Stage1ZirInst *astgen_overflow_op(Stage1AstGen *ag, Scope *scope, AstNode *node, IrOverflowOp op) { - assert(node->type == NodeTypeFnCallExpr); - - AstNode *type_node = node->data.fn_call_expr.params.at(0); - AstNode *op1_node = node->data.fn_call_expr.params.at(1); - AstNode *op2_node = node->data.fn_call_expr.params.at(2); - AstNode *result_ptr_node = node->data.fn_call_expr.params.at(3); - - - Stage1ZirInst *type_value = astgen_node(ag, type_node, scope); - if (type_value == ag->codegen->invalid_inst_src) - return ag->codegen->invalid_inst_src; - - Stage1ZirInst *op1 = astgen_node(ag, op1_node, scope); - if (op1 == ag->codegen->invalid_inst_src) - return ag->codegen->invalid_inst_src; - - Stage1ZirInst *op2 = astgen_node(ag, op2_node, scope); - if (op2 == ag->codegen->invalid_inst_src) - return ag->codegen->invalid_inst_src; - - Stage1ZirInst *result_ptr = astgen_node(ag, result_ptr_node, scope); - if (result_ptr == ag->codegen->invalid_inst_src) - return ag->codegen->invalid_inst_src; - - return ir_build_overflow_op_src(ag, scope, node, op, type_value, op1, op2, result_ptr); -} - -static Stage1ZirInst *astgen_mul_add(Stage1AstGen *ag, Scope *scope, AstNode *node) { - assert(node->type == NodeTypeFnCallExpr); - - AstNode *type_node = node->data.fn_call_expr.params.at(0); - AstNode *op1_node = node->data.fn_call_expr.params.at(1); - AstNode *op2_node = node->data.fn_call_expr.params.at(2); - AstNode *op3_node = node->data.fn_call_expr.params.at(3); - - Stage1ZirInst *type_value = astgen_node(ag, type_node, scope); - if (type_value == ag->codegen->invalid_inst_src) - return ag->codegen->invalid_inst_src; - - Stage1ZirInst *op1 = astgen_node(ag, op1_node, scope); - if (op1 == ag->codegen->invalid_inst_src) - return ag->codegen->invalid_inst_src; - - Stage1ZirInst *op2 = astgen_node(ag, op2_node, scope); - if (op2 == ag->codegen->invalid_inst_src) - return ag->codegen->invalid_inst_src; - - Stage1ZirInst *op3 = astgen_node(ag, op3_node, scope); - if (op3 == ag->codegen->invalid_inst_src) - return ag->codegen->invalid_inst_src; - - return ir_build_mul_add_src(ag, scope, node, type_value, op1, op2, op3); -} - -static Stage1ZirInst *astgen_this(Stage1AstGen *ag, Scope *orig_scope, AstNode *node) { - for (Scope *it_scope = orig_scope; it_scope != nullptr; it_scope = it_scope->parent) { - if (it_scope->id == ScopeIdDecls) { - ScopeDecls *decls_scope = (ScopeDecls *)it_scope; - ZigType *container_type = decls_scope->container_type; - if (container_type != nullptr) { - return ir_build_const_type(ag, orig_scope, node, container_type); - } else { - return ir_build_const_import(ag, orig_scope, node, decls_scope->import); - } - } - } - zig_unreachable(); -} - -static Stage1ZirInst *astgen_async_call(Stage1AstGen *ag, Scope *scope, AstNode *await_node, AstNode *call_node, - LVal lval, ResultLoc *result_loc) -{ - if (call_node->data.fn_call_expr.params.length != 4) { - add_node_error(ag->codegen, call_node, - buf_sprintf("expected 4 arguments, found %" ZIG_PRI_usize, - call_node->data.fn_call_expr.params.length)); - return ag->codegen->invalid_inst_src; - } - - AstNode *bytes_node = call_node->data.fn_call_expr.params.at(0); - Stage1ZirInst *bytes = astgen_node(ag, bytes_node, scope); - if (bytes == ag->codegen->invalid_inst_src) - return bytes; - - AstNode *ret_ptr_node = call_node->data.fn_call_expr.params.at(1); - Stage1ZirInst *ret_ptr = astgen_node(ag, ret_ptr_node, scope); - if (ret_ptr == ag->codegen->invalid_inst_src) - return ret_ptr; - - AstNode *fn_ref_node = call_node->data.fn_call_expr.params.at(2); - Stage1ZirInst *fn_ref = astgen_node(ag, fn_ref_node, scope); - if (fn_ref == ag->codegen->invalid_inst_src) - return fn_ref; - - CallModifier modifier = (await_node == nullptr) ? CallModifierAsync : CallModifierNone; - bool is_async_call_builtin = true; - AstNode *args_node = call_node->data.fn_call_expr.params.at(3); - if (args_node->type == NodeTypeContainerInitExpr) { - if (args_node->data.container_init_expr.kind == ContainerInitKindArray || - args_node->data.container_init_expr.entries.length == 0) - { - size_t arg_count = args_node->data.container_init_expr.entries.length; - Stage1ZirInst **args = heap::c_allocator.allocate(arg_count); - for (size_t i = 0; i < arg_count; i += 1) { - AstNode *arg_node = args_node->data.container_init_expr.entries.at(i); - Stage1ZirInst *arg = astgen_node(ag, arg_node, scope); - if (arg == ag->codegen->invalid_inst_src) - return arg; - args[i] = arg; - } - - Stage1ZirInst *call = ir_build_call_src(ag, scope, call_node, nullptr, fn_ref, arg_count, args, - ret_ptr, modifier, is_async_call_builtin, bytes, result_loc); - return ir_lval_wrap(ag, scope, call, lval, result_loc); - } else { - exec_add_error_node(ag->codegen, ag->exec, args_node, - buf_sprintf("TODO: @asyncCall with anon struct literal")); - return ag->codegen->invalid_inst_src; - } - } - Stage1ZirInst *args = astgen_node(ag, args_node, scope); - if (args == ag->codegen->invalid_inst_src) - return args; - - Stage1ZirInst *call = ir_build_async_call_extra(ag, scope, call_node, modifier, fn_ref, ret_ptr, bytes, args, result_loc); - return ir_lval_wrap(ag, scope, call, lval, result_loc); -} - -static Stage1ZirInst *astgen_fn_call_with_args(Stage1AstGen *ag, Scope *scope, AstNode *source_node, - AstNode *fn_ref_node, CallModifier modifier, Stage1ZirInst *options, - AstNode **args_ptr, size_t args_len, LVal lval, ResultLoc *result_loc) -{ - Stage1ZirInst *fn_ref = astgen_node(ag, fn_ref_node, scope); - if (fn_ref == ag->codegen->invalid_inst_src) - return fn_ref; - - Stage1ZirInst *fn_type = ir_build_typeof_1(ag, scope, source_node, fn_ref); - - Stage1ZirInst **args = heap::c_allocator.allocate(args_len); - for (size_t i = 0; i < args_len; i += 1) { - AstNode *arg_node = args_ptr[i]; - - Stage1ZirInst *arg_index = ir_build_const_usize(ag, scope, arg_node, i); - Stage1ZirInst *arg_type = ir_build_arg_type(ag, scope, source_node, fn_type, arg_index, true); - ResultLoc *no_result = no_result_loc(); - ir_build_reset_result(ag, scope, source_node, no_result); - ResultLocCast *result_loc_cast = ir_build_cast_result_loc(ag, arg_type, no_result); - - Stage1ZirInst *arg = astgen_node_extra(ag, arg_node, scope, LValNone, &result_loc_cast->base); - if (arg == ag->codegen->invalid_inst_src) - return arg; - - args[i] = ir_build_implicit_cast(ag, scope, arg_node, arg, result_loc_cast); - } - - Stage1ZirInst *fn_call; - if (options != nullptr) { - fn_call = ir_build_call_args(ag, scope, source_node, options, fn_ref, args, args_len, result_loc); - } else { - fn_call = ir_build_call_src(ag, scope, source_node, nullptr, fn_ref, args_len, args, nullptr, - modifier, false, nullptr, result_loc); - } - return ir_lval_wrap(ag, scope, fn_call, lval, result_loc); -} - -static Stage1ZirInst *astgen_builtin_fn_call(Stage1AstGen *ag, Scope *scope, AstNode *node, LVal lval, - ResultLoc *result_loc) -{ - assert(node->type == NodeTypeFnCallExpr); - - AstNode *fn_ref_expr = node->data.fn_call_expr.fn_ref_expr; - Buf *name = node_identifier_buf(fn_ref_expr); - auto entry = ag->codegen->builtin_fn_table.maybe_get(name); - - if (!entry) { - add_node_error(ag->codegen, node, - buf_sprintf("invalid builtin function: '%s'", buf_ptr(name))); - return ag->codegen->invalid_inst_src; - } - - BuiltinFnEntry *builtin_fn = entry->value; - size_t actual_param_count = node->data.fn_call_expr.params.length; - - if (builtin_fn->param_count != SIZE_MAX && builtin_fn->param_count != actual_param_count) { - add_node_error(ag->codegen, node, - buf_sprintf("expected %" ZIG_PRI_usize " argument(s), found %" ZIG_PRI_usize, - builtin_fn->param_count, actual_param_count)); - return ag->codegen->invalid_inst_src; - } - - switch (builtin_fn->id) { - case BuiltinFnIdInvalid: - zig_unreachable(); - case BuiltinFnIdTypeof: - { - Scope *sub_scope = create_typeof_scope(ag->codegen, node, scope); - - size_t arg_count = node->data.fn_call_expr.params.length; - - Stage1ZirInst *type_of; - - if (arg_count == 0) { - add_node_error(ag->codegen, node, - buf_sprintf("expected at least 1 argument, found 0")); - return ag->codegen->invalid_inst_src; - } else if (arg_count == 1) { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - Stage1ZirInst *arg0_value = astgen_node(ag, arg0_node, sub_scope); - if (arg0_value == ag->codegen->invalid_inst_src) - return arg0_value; - - type_of = ir_build_typeof_1(ag, scope, node, arg0_value); - } else { - Stage1ZirInst **args = heap::c_allocator.allocate(arg_count); - for (size_t i = 0; i < arg_count; i += 1) { - AstNode *arg_node = node->data.fn_call_expr.params.at(i); - Stage1ZirInst *arg = astgen_node(ag, arg_node, sub_scope); - if (arg == ag->codegen->invalid_inst_src) - return ag->codegen->invalid_inst_src; - args[i] = arg; - } - - type_of = ir_build_typeof_n(ag, scope, node, args, arg_count); - } - return ir_lval_wrap(ag, scope, type_of, lval, result_loc); - } - case BuiltinFnIdSetCold: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - Stage1ZirInst *arg0_value = astgen_node(ag, arg0_node, scope); - if (arg0_value == ag->codegen->invalid_inst_src) - return arg0_value; - - Stage1ZirInst *set_cold = ir_build_set_cold(ag, scope, node, arg0_value); - return ir_lval_wrap(ag, scope, set_cold, lval, result_loc); - } - case BuiltinFnIdSetRuntimeSafety: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - Stage1ZirInst *arg0_value = astgen_node(ag, arg0_node, scope); - if (arg0_value == ag->codegen->invalid_inst_src) - return arg0_value; - - Stage1ZirInst *set_safety = ir_build_set_runtime_safety(ag, scope, node, arg0_value); - return ir_lval_wrap(ag, scope, set_safety, lval, result_loc); - } - case BuiltinFnIdSetFloatMode: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - Stage1ZirInst *arg0_value = astgen_node(ag, arg0_node, scope); - if (arg0_value == ag->codegen->invalid_inst_src) - return arg0_value; - - Stage1ZirInst *set_float_mode = ir_build_set_float_mode(ag, scope, node, arg0_value); - return ir_lval_wrap(ag, scope, set_float_mode, lval, result_loc); - } - case BuiltinFnIdSizeof: - case BuiltinFnIdBitSizeof: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - Stage1ZirInst *arg0_value = astgen_node(ag, arg0_node, scope); - if (arg0_value == ag->codegen->invalid_inst_src) - return arg0_value; - - Stage1ZirInst *size_of = ir_build_size_of(ag, scope, node, arg0_value, builtin_fn->id == BuiltinFnIdBitSizeof); - return ir_lval_wrap(ag, scope, size_of, lval, result_loc); - } - case BuiltinFnIdImport: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - Stage1ZirInst *arg0_value = astgen_node(ag, arg0_node, scope); - if (arg0_value == ag->codegen->invalid_inst_src) - return arg0_value; - - Stage1ZirInst *import = ir_build_import(ag, scope, node, arg0_value); - return ir_lval_wrap(ag, scope, import, lval, result_loc); - } - case BuiltinFnIdCImport: - { - Stage1ZirInst *c_import = ir_build_c_import(ag, scope, node); - return ir_lval_wrap(ag, scope, c_import, lval, result_loc); - } - case BuiltinFnIdCInclude: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - Stage1ZirInst *arg0_value = astgen_node(ag, arg0_node, scope); - if (arg0_value == ag->codegen->invalid_inst_src) - return arg0_value; - - if (!ag->in_c_import_scope) { - add_node_error(ag->codegen, node, buf_sprintf("C include valid only inside C import block")); - return ag->codegen->invalid_inst_src; - } - - Stage1ZirInst *c_include = ir_build_c_include(ag, scope, node, arg0_value); - return ir_lval_wrap(ag, scope, c_include, lval, result_loc); - } - case BuiltinFnIdCDefine: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - Stage1ZirInst *arg0_value = astgen_node(ag, arg0_node, scope); - if (arg0_value == ag->codegen->invalid_inst_src) - return arg0_value; - - AstNode *arg1_node = node->data.fn_call_expr.params.at(1); - Stage1ZirInst *arg1_value = astgen_node(ag, arg1_node, scope); - if (arg1_value == ag->codegen->invalid_inst_src) - return arg1_value; - - if (!ag->in_c_import_scope) { - add_node_error(ag->codegen, node, buf_sprintf("C define valid only inside C import block")); - return ag->codegen->invalid_inst_src; - } - - Stage1ZirInst *c_define = ir_build_c_define(ag, scope, node, arg0_value, arg1_value); - return ir_lval_wrap(ag, scope, c_define, lval, result_loc); - } - case BuiltinFnIdCUndef: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - Stage1ZirInst *arg0_value = astgen_node(ag, arg0_node, scope); - if (arg0_value == ag->codegen->invalid_inst_src) - return arg0_value; - - if (!ag->in_c_import_scope) { - add_node_error(ag->codegen, node, buf_sprintf("C undef valid only inside C import block")); - return ag->codegen->invalid_inst_src; - } - - Stage1ZirInst *c_undef = ir_build_c_undef(ag, scope, node, arg0_value); - return ir_lval_wrap(ag, scope, c_undef, lval, result_loc); - } - case BuiltinFnIdCompileErr: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - Stage1ZirInst *arg0_value = astgen_node(ag, arg0_node, scope); - if (arg0_value == ag->codegen->invalid_inst_src) - return arg0_value; - - Stage1ZirInst *compile_err = ir_build_compile_err(ag, scope, node, arg0_value); - return ir_lval_wrap(ag, scope, compile_err, lval, result_loc); - } - case BuiltinFnIdCompileLog: - { - Stage1ZirInst **args = heap::c_allocator.allocate(actual_param_count); - - for (size_t i = 0; i < actual_param_count; i += 1) { - AstNode *arg_node = node->data.fn_call_expr.params.at(i); - args[i] = astgen_node(ag, arg_node, scope); - if (args[i] == ag->codegen->invalid_inst_src) - return ag->codegen->invalid_inst_src; - } - - Stage1ZirInst *compile_log = ir_build_compile_log(ag, scope, node, actual_param_count, args); - return ir_lval_wrap(ag, scope, compile_log, lval, result_loc); - } - case BuiltinFnIdErrName: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - Stage1ZirInst *arg0_value = astgen_node(ag, arg0_node, scope); - if (arg0_value == ag->codegen->invalid_inst_src) - return arg0_value; - - Stage1ZirInst *err_name = ir_build_err_name(ag, scope, node, arg0_value); - return ir_lval_wrap(ag, scope, err_name, lval, result_loc); - } - case BuiltinFnIdEmbedFile: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - Stage1ZirInst *arg0_value = astgen_node(ag, arg0_node, scope); - if (arg0_value == ag->codegen->invalid_inst_src) - return arg0_value; - - Stage1ZirInst *embed_file = ir_build_embed_file(ag, scope, node, arg0_value); - return ir_lval_wrap(ag, scope, embed_file, lval, result_loc); - } - case BuiltinFnIdCmpxchgWeak: - case BuiltinFnIdCmpxchgStrong: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - Stage1ZirInst *arg0_value = astgen_node(ag, arg0_node, scope); - if (arg0_value == ag->codegen->invalid_inst_src) - return arg0_value; - - AstNode *arg1_node = node->data.fn_call_expr.params.at(1); - Stage1ZirInst *arg1_value = astgen_node(ag, arg1_node, scope); - if (arg1_value == ag->codegen->invalid_inst_src) - return arg1_value; - - AstNode *arg2_node = node->data.fn_call_expr.params.at(2); - Stage1ZirInst *arg2_value = astgen_node(ag, arg2_node, scope); - if (arg2_value == ag->codegen->invalid_inst_src) - return arg2_value; - - AstNode *arg3_node = node->data.fn_call_expr.params.at(3); - Stage1ZirInst *arg3_value = astgen_node(ag, arg3_node, scope); - if (arg3_value == ag->codegen->invalid_inst_src) - return arg3_value; - - AstNode *arg4_node = node->data.fn_call_expr.params.at(4); - Stage1ZirInst *arg4_value = astgen_node(ag, arg4_node, scope); - if (arg4_value == ag->codegen->invalid_inst_src) - return arg4_value; - - AstNode *arg5_node = node->data.fn_call_expr.params.at(5); - Stage1ZirInst *arg5_value = astgen_node(ag, arg5_node, scope); - if (arg5_value == ag->codegen->invalid_inst_src) - return arg5_value; - - Stage1ZirInst *cmpxchg = ir_build_cmpxchg_src(ag, scope, node, arg0_value, arg1_value, - arg2_value, arg3_value, arg4_value, arg5_value, (builtin_fn->id == BuiltinFnIdCmpxchgWeak), - result_loc); - return ir_lval_wrap(ag, scope, cmpxchg, lval, result_loc); - } - case BuiltinFnIdFence: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - Stage1ZirInst *arg0_value = astgen_node(ag, arg0_node, scope); - if (arg0_value == ag->codegen->invalid_inst_src) - return arg0_value; - - Stage1ZirInst *fence = ir_build_fence(ag, scope, node, arg0_value); - return ir_lval_wrap(ag, scope, fence, lval, result_loc); - } - case BuiltinFnIdReduce: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - Stage1ZirInst *arg0_value = astgen_node(ag, arg0_node, scope); - if (arg0_value == ag->codegen->invalid_inst_src) - return arg0_value; - - AstNode *arg1_node = node->data.fn_call_expr.params.at(1); - Stage1ZirInst *arg1_value = astgen_node(ag, arg1_node, scope); - if (arg1_value == ag->codegen->invalid_inst_src) - return arg1_value; - - Stage1ZirInst *reduce = ir_build_reduce(ag, scope, node, arg0_value, arg1_value); - return ir_lval_wrap(ag, scope, reduce, lval, result_loc); - } - case BuiltinFnIdDivExact: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - Stage1ZirInst *arg0_value = astgen_node(ag, arg0_node, scope); - if (arg0_value == ag->codegen->invalid_inst_src) - return arg0_value; - - AstNode *arg1_node = node->data.fn_call_expr.params.at(1); - Stage1ZirInst *arg1_value = astgen_node(ag, arg1_node, scope); - if (arg1_value == ag->codegen->invalid_inst_src) - return arg1_value; - - Stage1ZirInst *bin_op = ir_build_bin_op(ag, scope, node, IrBinOpDivExact, arg0_value, arg1_value, true); - return ir_lval_wrap(ag, scope, bin_op, lval, result_loc); - } - case BuiltinFnIdDivTrunc: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - Stage1ZirInst *arg0_value = astgen_node(ag, arg0_node, scope); - if (arg0_value == ag->codegen->invalid_inst_src) - return arg0_value; - - AstNode *arg1_node = node->data.fn_call_expr.params.at(1); - Stage1ZirInst *arg1_value = astgen_node(ag, arg1_node, scope); - if (arg1_value == ag->codegen->invalid_inst_src) - return arg1_value; - - Stage1ZirInst *bin_op = ir_build_bin_op(ag, scope, node, IrBinOpDivTrunc, arg0_value, arg1_value, true); - return ir_lval_wrap(ag, scope, bin_op, lval, result_loc); - } - case BuiltinFnIdDivFloor: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - Stage1ZirInst *arg0_value = astgen_node(ag, arg0_node, scope); - if (arg0_value == ag->codegen->invalid_inst_src) - return arg0_value; - - AstNode *arg1_node = node->data.fn_call_expr.params.at(1); - Stage1ZirInst *arg1_value = astgen_node(ag, arg1_node, scope); - if (arg1_value == ag->codegen->invalid_inst_src) - return arg1_value; - - Stage1ZirInst *bin_op = ir_build_bin_op(ag, scope, node, IrBinOpDivFloor, arg0_value, arg1_value, true); - return ir_lval_wrap(ag, scope, bin_op, lval, result_loc); - } - case BuiltinFnIdRem: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - Stage1ZirInst *arg0_value = astgen_node(ag, arg0_node, scope); - if (arg0_value == ag->codegen->invalid_inst_src) - return arg0_value; - - AstNode *arg1_node = node->data.fn_call_expr.params.at(1); - Stage1ZirInst *arg1_value = astgen_node(ag, arg1_node, scope); - if (arg1_value == ag->codegen->invalid_inst_src) - return arg1_value; - - Stage1ZirInst *bin_op = ir_build_bin_op(ag, scope, node, IrBinOpRemRem, arg0_value, arg1_value, true); - return ir_lval_wrap(ag, scope, bin_op, lval, result_loc); - } - case BuiltinFnIdMod: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - Stage1ZirInst *arg0_value = astgen_node(ag, arg0_node, scope); - if (arg0_value == ag->codegen->invalid_inst_src) - return arg0_value; - - AstNode *arg1_node = node->data.fn_call_expr.params.at(1); - Stage1ZirInst *arg1_value = astgen_node(ag, arg1_node, scope); - if (arg1_value == ag->codegen->invalid_inst_src) - return arg1_value; - - Stage1ZirInst *bin_op = ir_build_bin_op(ag, scope, node, IrBinOpRemMod, arg0_value, arg1_value, true); - return ir_lval_wrap(ag, scope, bin_op, lval, result_loc); - } - case BuiltinFnIdSqrt: - case BuiltinFnIdSin: - case BuiltinFnIdCos: - case BuiltinFnIdTan: - case BuiltinFnIdExp: - case BuiltinFnIdExp2: - case BuiltinFnIdLog: - case BuiltinFnIdLog2: - case BuiltinFnIdLog10: - case BuiltinFnIdFabs: - case BuiltinFnIdFloor: - case BuiltinFnIdCeil: - case BuiltinFnIdTrunc: - case BuiltinFnIdNearbyInt: - case BuiltinFnIdRound: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - Stage1ZirInst *arg0_value = astgen_node(ag, arg0_node, scope); - if (arg0_value == ag->codegen->invalid_inst_src) - return arg0_value; - - Stage1ZirInst *inst = ir_build_float_op_src(ag, scope, node, arg0_value, builtin_fn->id); - return ir_lval_wrap(ag, scope, inst, lval, result_loc); - } - case BuiltinFnIdTruncate: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - Stage1ZirInst *arg0_value = astgen_node(ag, arg0_node, scope); - if (arg0_value == ag->codegen->invalid_inst_src) - return arg0_value; - - AstNode *arg1_node = node->data.fn_call_expr.params.at(1); - Stage1ZirInst *arg1_value = astgen_node(ag, arg1_node, scope); - if (arg1_value == ag->codegen->invalid_inst_src) - return arg1_value; - - Stage1ZirInst *truncate = ir_build_truncate(ag, scope, node, arg0_value, arg1_value); - return ir_lval_wrap(ag, scope, truncate, lval, result_loc); - } - case BuiltinFnIdIntCast: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - Stage1ZirInst *arg0_value = astgen_node(ag, arg0_node, scope); - if (arg0_value == ag->codegen->invalid_inst_src) - return arg0_value; - - AstNode *arg1_node = node->data.fn_call_expr.params.at(1); - Stage1ZirInst *arg1_value = astgen_node(ag, arg1_node, scope); - if (arg1_value == ag->codegen->invalid_inst_src) - return arg1_value; - - Stage1ZirInst *result = ir_build_int_cast(ag, scope, node, arg0_value, arg1_value); - return ir_lval_wrap(ag, scope, result, lval, result_loc); - } - case BuiltinFnIdFloatCast: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - Stage1ZirInst *arg0_value = astgen_node(ag, arg0_node, scope); - if (arg0_value == ag->codegen->invalid_inst_src) - return arg0_value; - - AstNode *arg1_node = node->data.fn_call_expr.params.at(1); - Stage1ZirInst *arg1_value = astgen_node(ag, arg1_node, scope); - if (arg1_value == ag->codegen->invalid_inst_src) - return arg1_value; - - Stage1ZirInst *result = ir_build_float_cast(ag, scope, node, arg0_value, arg1_value); - return ir_lval_wrap(ag, scope, result, lval, result_loc); - } - case BuiltinFnIdErrSetCast: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - Stage1ZirInst *arg0_value = astgen_node(ag, arg0_node, scope); - if (arg0_value == ag->codegen->invalid_inst_src) - return arg0_value; - - AstNode *arg1_node = node->data.fn_call_expr.params.at(1); - Stage1ZirInst *arg1_value = astgen_node(ag, arg1_node, scope); - if (arg1_value == ag->codegen->invalid_inst_src) - return arg1_value; - - Stage1ZirInst *result = ir_build_err_set_cast(ag, scope, node, arg0_value, arg1_value); - return ir_lval_wrap(ag, scope, result, lval, result_loc); - } - case BuiltinFnIdIntToFloat: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - Stage1ZirInst *arg0_value = astgen_node(ag, arg0_node, scope); - if (arg0_value == ag->codegen->invalid_inst_src) - return arg0_value; - - AstNode *arg1_node = node->data.fn_call_expr.params.at(1); - Stage1ZirInst *arg1_value = astgen_node(ag, arg1_node, scope); - if (arg1_value == ag->codegen->invalid_inst_src) - return arg1_value; - - Stage1ZirInst *result = ir_build_int_to_float(ag, scope, node, arg0_value, arg1_value); - return ir_lval_wrap(ag, scope, result, lval, result_loc); - } - case BuiltinFnIdFloatToInt: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - Stage1ZirInst *arg0_value = astgen_node(ag, arg0_node, scope); - if (arg0_value == ag->codegen->invalid_inst_src) - return arg0_value; - - AstNode *arg1_node = node->data.fn_call_expr.params.at(1); - Stage1ZirInst *arg1_value = astgen_node(ag, arg1_node, scope); - if (arg1_value == ag->codegen->invalid_inst_src) - return arg1_value; - - Stage1ZirInst *result = ir_build_float_to_int(ag, scope, node, arg0_value, arg1_value); - return ir_lval_wrap(ag, scope, result, lval, result_loc); - } - case BuiltinFnIdErrToInt: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - Stage1ZirInst *arg0_value = astgen_node(ag, arg0_node, scope); - if (arg0_value == ag->codegen->invalid_inst_src) - return arg0_value; - - Stage1ZirInst *result = ir_build_err_to_int_src(ag, scope, node, arg0_value); - return ir_lval_wrap(ag, scope, result, lval, result_loc); - } - case BuiltinFnIdIntToErr: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - Stage1ZirInst *arg0_value = astgen_node(ag, arg0_node, scope); - if (arg0_value == ag->codegen->invalid_inst_src) - return arg0_value; - - Stage1ZirInst *result = ir_build_int_to_err_src(ag, scope, node, arg0_value); - return ir_lval_wrap(ag, scope, result, lval, result_loc); - } - case BuiltinFnIdBoolToInt: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - Stage1ZirInst *arg0_value = astgen_node(ag, arg0_node, scope); - if (arg0_value == ag->codegen->invalid_inst_src) - return arg0_value; - - Stage1ZirInst *result = ir_build_bool_to_int(ag, scope, node, arg0_value); - return ir_lval_wrap(ag, scope, result, lval, result_loc); - } - case BuiltinFnIdVectorType: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - Stage1ZirInst *arg0_value = astgen_node(ag, arg0_node, scope); - if (arg0_value == ag->codegen->invalid_inst_src) - return arg0_value; - - AstNode *arg1_node = node->data.fn_call_expr.params.at(1); - Stage1ZirInst *arg1_value = astgen_node(ag, arg1_node, scope); - if (arg1_value == ag->codegen->invalid_inst_src) - return arg1_value; - - Stage1ZirInst *vector_type = ir_build_vector_type(ag, scope, node, arg0_value, arg1_value); - return ir_lval_wrap(ag, scope, vector_type, lval, result_loc); - } - case BuiltinFnIdShuffle: - { - // Used for the type expr and the mask expr - Scope *comptime_scope = create_comptime_scope(ag->codegen, node, scope); - - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - Stage1ZirInst *arg0_value = astgen_node(ag, arg0_node, comptime_scope); - if (arg0_value == ag->codegen->invalid_inst_src) - return arg0_value; - - AstNode *arg1_node = node->data.fn_call_expr.params.at(1); - Stage1ZirInst *arg1_value = astgen_node(ag, arg1_node, scope); - if (arg1_value == ag->codegen->invalid_inst_src) - return arg1_value; - - AstNode *arg2_node = node->data.fn_call_expr.params.at(2); - Stage1ZirInst *arg2_value = astgen_node(ag, arg2_node, scope); - if (arg2_value == ag->codegen->invalid_inst_src) - return arg2_value; - - AstNode *arg3_node = node->data.fn_call_expr.params.at(3); - Stage1ZirInst *arg3_value = astgen_node(ag, arg3_node, comptime_scope); - if (arg3_value == ag->codegen->invalid_inst_src) - return arg3_value; - - Stage1ZirInst *shuffle_vector = ir_build_shuffle_vector(ag, scope, node, - arg0_value, arg1_value, arg2_value, arg3_value); - return ir_lval_wrap(ag, scope, shuffle_vector, lval, result_loc); - } - case BuiltinFnIdSelect: - { - // Used for the type expr - Scope *comptime_scope = create_comptime_scope(ag->codegen, node, scope); - - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - Stage1ZirInst *arg0_value = astgen_node(ag, arg0_node, comptime_scope); - if (arg0_value == ag->codegen->invalid_inst_src) - return arg0_value; - - AstNode *arg1_node = node->data.fn_call_expr.params.at(1); - Stage1ZirInst *arg1_value = astgen_node(ag, arg1_node, scope); - if (arg1_value == ag->codegen->invalid_inst_src) - return arg1_value; - - AstNode *arg2_node = node->data.fn_call_expr.params.at(2); - Stage1ZirInst *arg2_value = astgen_node(ag, arg2_node, scope); - if (arg2_value == ag->codegen->invalid_inst_src) - return arg2_value; - - AstNode *arg3_node = node->data.fn_call_expr.params.at(3); - Stage1ZirInst *arg3_value = astgen_node(ag, arg3_node, scope); - if (arg3_value == ag->codegen->invalid_inst_src) - return arg3_value; - - Stage1ZirInst *select = ir_build_select(ag, scope, node, - arg0_value, arg1_value, arg2_value, arg3_value); - return ir_lval_wrap(ag, scope, select, lval, result_loc); - } - case BuiltinFnIdSplat: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - Stage1ZirInst *arg0_value = astgen_node(ag, arg0_node, scope); - if (arg0_value == ag->codegen->invalid_inst_src) - return arg0_value; - - AstNode *arg1_node = node->data.fn_call_expr.params.at(1); - Stage1ZirInst *arg1_value = astgen_node(ag, arg1_node, scope); - if (arg1_value == ag->codegen->invalid_inst_src) - return arg1_value; - - Stage1ZirInst *splat = ir_build_splat_src(ag, scope, node, - arg0_value, arg1_value); - return ir_lval_wrap(ag, scope, splat, lval, result_loc); - } - case BuiltinFnIdMaximum: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - Stage1ZirInst *arg0_value = astgen_node(ag, arg0_node, scope); - if (arg0_value == ag->codegen->invalid_inst_src) - return arg0_value; - - AstNode *arg1_node = node->data.fn_call_expr.params.at(1); - Stage1ZirInst *arg1_value = astgen_node(ag, arg1_node, scope); - if (arg1_value == ag->codegen->invalid_inst_src) - return arg1_value; - - Stage1ZirInst *bin_op = ir_build_bin_op(ag, scope, node, IrBinOpMax, arg0_value, arg1_value, true); - return ir_lval_wrap(ag, scope, bin_op, lval, result_loc); - } - case BuiltinFnIdMemcpy: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - Stage1ZirInst *arg0_value = astgen_node(ag, arg0_node, scope); - if (arg0_value == ag->codegen->invalid_inst_src) - return arg0_value; - - AstNode *arg1_node = node->data.fn_call_expr.params.at(1); - Stage1ZirInst *arg1_value = astgen_node(ag, arg1_node, scope); - if (arg1_value == ag->codegen->invalid_inst_src) - return arg1_value; - - AstNode *arg2_node = node->data.fn_call_expr.params.at(2); - Stage1ZirInst *arg2_value = astgen_node(ag, arg2_node, scope); - if (arg2_value == ag->codegen->invalid_inst_src) - return arg2_value; - - Stage1ZirInst *ir_memcpy = ir_build_memcpy_src(ag, scope, node, arg0_value, arg1_value, arg2_value); - return ir_lval_wrap(ag, scope, ir_memcpy, lval, result_loc); - } - case BuiltinFnIdMemset: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - Stage1ZirInst *arg0_value = astgen_node(ag, arg0_node, scope); - if (arg0_value == ag->codegen->invalid_inst_src) - return arg0_value; - - AstNode *arg1_node = node->data.fn_call_expr.params.at(1); - Stage1ZirInst *arg1_value = astgen_node(ag, arg1_node, scope); - if (arg1_value == ag->codegen->invalid_inst_src) - return arg1_value; - - AstNode *arg2_node = node->data.fn_call_expr.params.at(2); - Stage1ZirInst *arg2_value = astgen_node(ag, arg2_node, scope); - if (arg2_value == ag->codegen->invalid_inst_src) - return arg2_value; - - Stage1ZirInst *ir_memset = ir_build_memset_src(ag, scope, node, arg0_value, arg1_value, arg2_value); - return ir_lval_wrap(ag, scope, ir_memset, lval, result_loc); - } - case BuiltinFnIdMinimum: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - Stage1ZirInst *arg0_value = astgen_node(ag, arg0_node, scope); - if (arg0_value == ag->codegen->invalid_inst_src) - return arg0_value; - - AstNode *arg1_node = node->data.fn_call_expr.params.at(1); - Stage1ZirInst *arg1_value = astgen_node(ag, arg1_node, scope); - if (arg1_value == ag->codegen->invalid_inst_src) - return arg1_value; - - Stage1ZirInst *bin_op = ir_build_bin_op(ag, scope, node, IrBinOpMin, arg0_value, arg1_value, true); - return ir_lval_wrap(ag, scope, bin_op, lval, result_loc); - } - case BuiltinFnIdWasmMemorySize: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - Stage1ZirInst *arg0_value = astgen_node(ag, arg0_node, scope); - if (arg0_value == ag->codegen->invalid_inst_src) - return arg0_value; - - Stage1ZirInst *ir_wasm_memory_size = ir_build_wasm_memory_size_src(ag, scope, node, arg0_value); - return ir_lval_wrap(ag, scope, ir_wasm_memory_size, lval, result_loc); - } - case BuiltinFnIdWasmMemoryGrow: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - Stage1ZirInst *arg0_value = astgen_node(ag, arg0_node, scope); - if (arg0_value == ag->codegen->invalid_inst_src) - return arg0_value; - - AstNode *arg1_node = node->data.fn_call_expr.params.at(1); - Stage1ZirInst *arg1_value = astgen_node(ag, arg1_node, scope); - if (arg1_value == ag->codegen->invalid_inst_src) - return arg1_value; - - Stage1ZirInst *ir_wasm_memory_grow = ir_build_wasm_memory_grow_src(ag, scope, node, arg0_value, arg1_value); - return ir_lval_wrap(ag, scope, ir_wasm_memory_grow, lval, result_loc); - } - case BuiltinFnIdField: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - Stage1ZirInst *arg0_value = astgen_node_extra(ag, arg0_node, scope, LValPtr, nullptr); - if (arg0_value == ag->codegen->invalid_inst_src) - return arg0_value; - - AstNode *arg1_node = node->data.fn_call_expr.params.at(1); - Stage1ZirInst *arg1_value = astgen_node(ag, arg1_node, scope); - if (arg1_value == ag->codegen->invalid_inst_src) - return arg1_value; - - Stage1ZirInst *ptr_instruction = ir_build_field_ptr_instruction(ag, scope, node, - arg0_value, arg1_value, false); - - if (lval == LValPtr || lval == LValAssign) - return ptr_instruction; - - Stage1ZirInst *load_ptr = ir_build_load_ptr(ag, scope, node, ptr_instruction); - return ir_expr_wrap(ag, scope, load_ptr, result_loc); - } - case BuiltinFnIdHasField: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - Stage1ZirInst *arg0_value = astgen_node(ag, arg0_node, scope); - if (arg0_value == ag->codegen->invalid_inst_src) - return arg0_value; - - AstNode *arg1_node = node->data.fn_call_expr.params.at(1); - Stage1ZirInst *arg1_value = astgen_node(ag, arg1_node, scope); - if (arg1_value == ag->codegen->invalid_inst_src) - return arg1_value; - - Stage1ZirInst *type_info = ir_build_has_field(ag, scope, node, arg0_value, arg1_value); - return ir_lval_wrap(ag, scope, type_info, lval, result_loc); - } - case BuiltinFnIdTypeInfo: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - Stage1ZirInst *arg0_value = astgen_node(ag, arg0_node, scope); - if (arg0_value == ag->codegen->invalid_inst_src) - return arg0_value; - - Stage1ZirInst *type_info = ir_build_type_info(ag, scope, node, arg0_value); - return ir_lval_wrap(ag, scope, type_info, lval, result_loc); - } - case BuiltinFnIdType: - { - AstNode *arg_node = node->data.fn_call_expr.params.at(0); - Stage1ZirInst *arg = astgen_node(ag, arg_node, scope); - if (arg == ag->codegen->invalid_inst_src) - return arg; - - Stage1ZirInst *type = ir_build_type(ag, scope, node, arg); - return ir_lval_wrap(ag, scope, type, lval, result_loc); - } - case BuiltinFnIdBreakpoint: - return ir_lval_wrap(ag, scope, ir_build_breakpoint(ag, scope, node), lval, result_loc); - case BuiltinFnIdReturnAddress: - return ir_lval_wrap(ag, scope, ir_build_return_address_src(ag, scope, node), lval, result_loc); - case BuiltinFnIdFrameAddress: - return ir_lval_wrap(ag, scope, ir_build_frame_address_src(ag, scope, node), lval, result_loc); - case BuiltinFnIdFrameHandle: - if (ag->fn == nullptr) { - add_node_error(ag->codegen, node, - buf_sprintf("@frame() called outside of function definition")); - return ag->codegen->invalid_inst_src; - } - return ir_lval_wrap(ag, scope, ir_build_handle_src(ag, scope, node), lval, result_loc); - case BuiltinFnIdFrameType: { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - Stage1ZirInst *arg0_value = astgen_node(ag, arg0_node, scope); - if (arg0_value == ag->codegen->invalid_inst_src) - return arg0_value; - - Stage1ZirInst *frame_type = ir_build_frame_type(ag, scope, node, arg0_value); - return ir_lval_wrap(ag, scope, frame_type, lval, result_loc); - } - case BuiltinFnIdFrameSize: { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - Stage1ZirInst *arg0_value = astgen_node(ag, arg0_node, scope); - if (arg0_value == ag->codegen->invalid_inst_src) - return arg0_value; - - Stage1ZirInst *frame_size = ir_build_frame_size_src(ag, scope, node, arg0_value); - return ir_lval_wrap(ag, scope, frame_size, lval, result_loc); - } - case BuiltinFnIdAlignOf: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - Stage1ZirInst *arg0_value = astgen_node(ag, arg0_node, scope); - if (arg0_value == ag->codegen->invalid_inst_src) - return arg0_value; - - Stage1ZirInst *align_of = ir_build_align_of(ag, scope, node, arg0_value); - return ir_lval_wrap(ag, scope, align_of, lval, result_loc); - } - case BuiltinFnIdAddWithOverflow: - return ir_lval_wrap(ag, scope, astgen_overflow_op(ag, scope, node, IrOverflowOpAdd), lval, result_loc); - case BuiltinFnIdSubWithOverflow: - return ir_lval_wrap(ag, scope, astgen_overflow_op(ag, scope, node, IrOverflowOpSub), lval, result_loc); - case BuiltinFnIdMulWithOverflow: - return ir_lval_wrap(ag, scope, astgen_overflow_op(ag, scope, node, IrOverflowOpMul), lval, result_loc); - case BuiltinFnIdShlWithOverflow: - return ir_lval_wrap(ag, scope, astgen_overflow_op(ag, scope, node, IrOverflowOpShl), lval, result_loc); - case BuiltinFnIdMulAdd: - return ir_lval_wrap(ag, scope, astgen_mul_add(ag, scope, node), lval, result_loc); - case BuiltinFnIdTypeName: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - Stage1ZirInst *arg0_value = astgen_node(ag, arg0_node, scope); - if (arg0_value == ag->codegen->invalid_inst_src) - return arg0_value; - - Stage1ZirInst *type_name = ir_build_type_name(ag, scope, node, arg0_value); - return ir_lval_wrap(ag, scope, type_name, lval, result_loc); - } - case BuiltinFnIdPanic: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - Stage1ZirInst *arg0_value = astgen_node(ag, arg0_node, scope); - if (arg0_value == ag->codegen->invalid_inst_src) - return arg0_value; - - Stage1ZirInst *panic = ir_build_panic_src(ag, scope, node, arg0_value); - return ir_lval_wrap(ag, scope, panic, lval, result_loc); - } - case BuiltinFnIdPtrCast: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - Stage1ZirInst *arg0_value = astgen_node(ag, arg0_node, scope); - if (arg0_value == ag->codegen->invalid_inst_src) - return arg0_value; - - AstNode *arg1_node = node->data.fn_call_expr.params.at(1); - Stage1ZirInst *arg1_value = astgen_node(ag, arg1_node, scope); - if (arg1_value == ag->codegen->invalid_inst_src) - return arg1_value; - - Stage1ZirInst *ptr_cast = ir_build_ptr_cast_src(ag, scope, node, arg0_value, arg1_value, true); - return ir_lval_wrap(ag, scope, ptr_cast, lval, result_loc); - } - case BuiltinFnIdBitCast: - { - AstNode *dest_type_node = node->data.fn_call_expr.params.at(0); - Stage1ZirInst *dest_type = astgen_node(ag, dest_type_node, scope); - if (dest_type == ag->codegen->invalid_inst_src) - return dest_type; - - ResultLocBitCast *result_loc_bit_cast = heap::c_allocator.create(); - result_loc_bit_cast->base.id = ResultLocIdBitCast; - result_loc_bit_cast->base.source_instruction = dest_type; - result_loc_bit_cast->base.allow_write_through_const = result_loc->allow_write_through_const; - ir_ref_instruction(dest_type, ag->current_basic_block); - result_loc_bit_cast->parent = result_loc; - - ir_build_reset_result(ag, scope, node, &result_loc_bit_cast->base); - - AstNode *arg1_node = node->data.fn_call_expr.params.at(1); - Stage1ZirInst *arg1_value = astgen_node_extra(ag, arg1_node, scope, LValNone, - &result_loc_bit_cast->base); - if (arg1_value == ag->codegen->invalid_inst_src) - return arg1_value; - - Stage1ZirInst *bitcast = ir_build_bit_cast_src(ag, scope, arg1_node, arg1_value, result_loc_bit_cast); - return ir_lval_wrap(ag, scope, bitcast, lval, result_loc); - } - case BuiltinFnIdAs: - { - AstNode *dest_type_node = node->data.fn_call_expr.params.at(0); - Stage1ZirInst *dest_type = astgen_node(ag, dest_type_node, scope); - if (dest_type == ag->codegen->invalid_inst_src) - return dest_type; - - ResultLocCast *result_loc_cast = ir_build_cast_result_loc(ag, dest_type, result_loc); - - AstNode *arg1_node = node->data.fn_call_expr.params.at(1); - Stage1ZirInst *arg1_value = astgen_node_extra(ag, arg1_node, scope, LValNone, - &result_loc_cast->base); - if (arg1_value == ag->codegen->invalid_inst_src) - return arg1_value; - - Stage1ZirInst *result = ir_build_implicit_cast(ag, scope, node, arg1_value, result_loc_cast); - return ir_lval_wrap(ag, scope, result, lval, result_loc); - } - case BuiltinFnIdIntToPtr: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - Stage1ZirInst *arg0_value = astgen_node(ag, arg0_node, scope); - if (arg0_value == ag->codegen->invalid_inst_src) - return arg0_value; - - AstNode *arg1_node = node->data.fn_call_expr.params.at(1); - Stage1ZirInst *arg1_value = astgen_node(ag, arg1_node, scope); - if (arg1_value == ag->codegen->invalid_inst_src) - return arg1_value; - - Stage1ZirInst *int_to_ptr = ir_build_int_to_ptr_src(ag, scope, node, arg0_value, arg1_value); - return ir_lval_wrap(ag, scope, int_to_ptr, lval, result_loc); - } - case BuiltinFnIdPtrToInt: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - Stage1ZirInst *arg0_value = astgen_node(ag, arg0_node, scope); - if (arg0_value == ag->codegen->invalid_inst_src) - return arg0_value; - - Stage1ZirInst *ptr_to_int = ir_build_ptr_to_int_src(ag, scope, node, arg0_value); - return ir_lval_wrap(ag, scope, ptr_to_int, lval, result_loc); - } - case BuiltinFnIdTagName: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - Stage1ZirInst *arg0_value = astgen_node(ag, arg0_node, scope); - if (arg0_value == ag->codegen->invalid_inst_src) - return arg0_value; - - Stage1ZirInst *tag_name = ir_build_tag_name_src(ag, scope, node, arg0_value); - return ir_lval_wrap(ag, scope, tag_name, lval, result_loc); - } - case BuiltinFnIdFieldParentPtr: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - Stage1ZirInst *arg0_value = astgen_node(ag, arg0_node, scope); - if (arg0_value == ag->codegen->invalid_inst_src) - return arg0_value; - - AstNode *arg1_node = node->data.fn_call_expr.params.at(1); - Stage1ZirInst *arg1_value = astgen_node(ag, arg1_node, scope); - if (arg1_value == ag->codegen->invalid_inst_src) - return arg1_value; - - AstNode *arg2_node = node->data.fn_call_expr.params.at(2); - Stage1ZirInst *arg2_value = astgen_node(ag, arg2_node, scope); - if (arg2_value == ag->codegen->invalid_inst_src) - return arg2_value; - - Stage1ZirInst *field_parent_ptr = ir_build_field_parent_ptr_src(ag, scope, node, - arg0_value, arg1_value, arg2_value); - return ir_lval_wrap(ag, scope, field_parent_ptr, lval, result_loc); - } - case BuiltinFnIdOffsetOf: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - Stage1ZirInst *arg0_value = astgen_node(ag, arg0_node, scope); - if (arg0_value == ag->codegen->invalid_inst_src) - return arg0_value; - - AstNode *arg1_node = node->data.fn_call_expr.params.at(1); - Stage1ZirInst *arg1_value = astgen_node(ag, arg1_node, scope); - if (arg1_value == ag->codegen->invalid_inst_src) - return arg1_value; - - Stage1ZirInst *offset_of = ir_build_offset_of(ag, scope, node, arg0_value, arg1_value); - return ir_lval_wrap(ag, scope, offset_of, lval, result_loc); - } - case BuiltinFnIdBitOffsetOf: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - Stage1ZirInst *arg0_value = astgen_node(ag, arg0_node, scope); - if (arg0_value == ag->codegen->invalid_inst_src) - return arg0_value; - - AstNode *arg1_node = node->data.fn_call_expr.params.at(1); - Stage1ZirInst *arg1_value = astgen_node(ag, arg1_node, scope); - if (arg1_value == ag->codegen->invalid_inst_src) - return arg1_value; - - Stage1ZirInst *offset_of = ir_build_bit_offset_of(ag, scope, node, arg0_value, arg1_value); - return ir_lval_wrap(ag, scope, offset_of, lval, result_loc); - } - case BuiltinFnIdCall: { - // Cast the options parameter to the options type - ZigType *options_type = get_builtin_type(ag->codegen, "CallOptions"); - Stage1ZirInst *options_type_inst = ir_build_const_type(ag, scope, node, options_type); - ResultLocCast *result_loc_cast = ir_build_cast_result_loc(ag, options_type_inst, no_result_loc()); - - AstNode *options_node = node->data.fn_call_expr.params.at(0); - Stage1ZirInst *options_inner = astgen_node_extra(ag, options_node, scope, - LValNone, &result_loc_cast->base); - if (options_inner == ag->codegen->invalid_inst_src) - return options_inner; - Stage1ZirInst *options = ir_build_implicit_cast(ag, scope, options_node, options_inner, result_loc_cast); - - AstNode *fn_ref_node = node->data.fn_call_expr.params.at(1); - AstNode *args_node = node->data.fn_call_expr.params.at(2); - if (args_node->type == NodeTypeContainerInitExpr) { - if (args_node->data.container_init_expr.kind == ContainerInitKindArray || - args_node->data.container_init_expr.entries.length == 0) - { - return astgen_fn_call_with_args(ag, scope, node, - fn_ref_node, CallModifierNone, options, - args_node->data.container_init_expr.entries.items, - args_node->data.container_init_expr.entries.length, - lval, result_loc); - } else { - exec_add_error_node(ag->codegen, ag->exec, args_node, - buf_sprintf("TODO: @call with anon struct literal")); - return ag->codegen->invalid_inst_src; - } - } else { - Stage1ZirInst *fn_ref = astgen_node(ag, fn_ref_node, scope); - if (fn_ref == ag->codegen->invalid_inst_src) - return fn_ref; - - Stage1ZirInst *args = astgen_node(ag, args_node, scope); - if (args == ag->codegen->invalid_inst_src) - return args; - - Stage1ZirInst *call = ir_build_call_extra(ag, scope, node, options, fn_ref, args, result_loc); - return ir_lval_wrap(ag, scope, call, lval, result_loc); - } - } - case BuiltinFnIdAsyncCall: - return astgen_async_call(ag, scope, nullptr, node, lval, result_loc); - case BuiltinFnIdShlExact: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - Stage1ZirInst *arg0_value = astgen_node(ag, arg0_node, scope); - if (arg0_value == ag->codegen->invalid_inst_src) - return arg0_value; - - AstNode *arg1_node = node->data.fn_call_expr.params.at(1); - Stage1ZirInst *arg1_value = astgen_node(ag, arg1_node, scope); - if (arg1_value == ag->codegen->invalid_inst_src) - return arg1_value; - - Stage1ZirInst *bin_op = ir_build_bin_op(ag, scope, node, IrBinOpBitShiftLeftExact, arg0_value, arg1_value, true); - return ir_lval_wrap(ag, scope, bin_op, lval, result_loc); - } - case BuiltinFnIdShrExact: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - Stage1ZirInst *arg0_value = astgen_node(ag, arg0_node, scope); - if (arg0_value == ag->codegen->invalid_inst_src) - return arg0_value; - - AstNode *arg1_node = node->data.fn_call_expr.params.at(1); - Stage1ZirInst *arg1_value = astgen_node(ag, arg1_node, scope); - if (arg1_value == ag->codegen->invalid_inst_src) - return arg1_value; - - Stage1ZirInst *bin_op = ir_build_bin_op(ag, scope, node, IrBinOpBitShiftRightExact, arg0_value, arg1_value, true); - return ir_lval_wrap(ag, scope, bin_op, lval, result_loc); - } - case BuiltinFnIdSetEvalBranchQuota: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - Stage1ZirInst *arg0_value = astgen_node(ag, arg0_node, scope); - if (arg0_value == ag->codegen->invalid_inst_src) - return arg0_value; - - Stage1ZirInst *set_eval_branch_quota = ir_build_set_eval_branch_quota(ag, scope, node, arg0_value); - return ir_lval_wrap(ag, scope, set_eval_branch_quota, lval, result_loc); - } - case BuiltinFnIdAlignCast: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - Stage1ZirInst *arg0_value = astgen_node(ag, arg0_node, scope); - if (arg0_value == ag->codegen->invalid_inst_src) - return arg0_value; - - AstNode *arg1_node = node->data.fn_call_expr.params.at(1); - Stage1ZirInst *arg1_value = astgen_node(ag, arg1_node, scope); - if (arg1_value == ag->codegen->invalid_inst_src) - return arg1_value; - - Stage1ZirInst *align_cast = ir_build_align_cast_src(ag, scope, node, arg0_value, arg1_value); - return ir_lval_wrap(ag, scope, align_cast, lval, result_loc); - } - case BuiltinFnIdThis: - { - Stage1ZirInst *this_inst = astgen_this(ag, scope, node); - return ir_lval_wrap(ag, scope, this_inst, lval, result_loc); - } - case BuiltinFnIdSetAlignStack: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - Stage1ZirInst *arg0_value = astgen_node(ag, arg0_node, scope); - if (arg0_value == ag->codegen->invalid_inst_src) - return arg0_value; - - Stage1ZirInst *set_align_stack = ir_build_set_align_stack(ag, scope, node, arg0_value); - return ir_lval_wrap(ag, scope, set_align_stack, lval, result_loc); - } - case BuiltinFnIdExport: - { - // Cast the options parameter to the options type - ZigType *options_type = get_builtin_type(ag->codegen, "ExportOptions"); - Stage1ZirInst *options_type_inst = ir_build_const_type(ag, scope, node, options_type); - ResultLocCast *result_loc_cast = ir_build_cast_result_loc(ag, options_type_inst, no_result_loc()); - - AstNode *target_node = node->data.fn_call_expr.params.at(0); - Stage1ZirInst *target_value = astgen_node(ag, target_node, scope); - if (target_value == ag->codegen->invalid_inst_src) - return target_value; - - AstNode *options_node = node->data.fn_call_expr.params.at(1); - Stage1ZirInst *options_value = astgen_node_extra(ag, options_node, - scope, LValNone, &result_loc_cast->base); - if (options_value == ag->codegen->invalid_inst_src) - return options_value; - - Stage1ZirInst *casted_options_value = ir_build_implicit_cast( - ag, scope, options_node, options_value, result_loc_cast); - - Stage1ZirInst *ir_export = ir_build_export(ag, scope, node, target_value, casted_options_value); - return ir_lval_wrap(ag, scope, ir_export, lval, result_loc); - } - case BuiltinFnIdExtern: - { - // Cast the options parameter to the options type - ZigType *options_type = get_builtin_type(ag->codegen, "ExternOptions"); - Stage1ZirInst *options_type_inst = ir_build_const_type(ag, scope, node, options_type); - ResultLocCast *result_loc_cast = ir_build_cast_result_loc(ag, options_type_inst, no_result_loc()); - - AstNode *type_node = node->data.fn_call_expr.params.at(0); - Stage1ZirInst *type_value = astgen_node(ag, type_node, scope); - if (type_value == ag->codegen->invalid_inst_src) - return type_value; - - AstNode *options_node = node->data.fn_call_expr.params.at(1); - Stage1ZirInst *options_value = astgen_node_extra(ag, options_node, - scope, LValNone, &result_loc_cast->base); - if (options_value == ag->codegen->invalid_inst_src) - return options_value; - - Stage1ZirInst *casted_options_value = ir_build_implicit_cast( - ag, scope, options_node, options_value, result_loc_cast); - - Stage1ZirInst *ir_extern = ir_build_extern(ag, scope, node, type_value, casted_options_value); - return ir_lval_wrap(ag, scope, ir_extern, lval, result_loc); - } - case BuiltinFnIdErrorReturnTrace: - { - Stage1ZirInst *error_return_trace = ir_build_error_return_trace_src(ag, scope, node, - IrInstErrorReturnTraceNull); - return ir_lval_wrap(ag, scope, error_return_trace, lval, result_loc); - } - case BuiltinFnIdAtomicRmw: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - Stage1ZirInst *arg0_value = astgen_node(ag, arg0_node, scope); - if (arg0_value == ag->codegen->invalid_inst_src) - return arg0_value; - - AstNode *arg1_node = node->data.fn_call_expr.params.at(1); - Stage1ZirInst *arg1_value = astgen_node(ag, arg1_node, scope); - if (arg1_value == ag->codegen->invalid_inst_src) - return arg1_value; - - AstNode *arg2_node = node->data.fn_call_expr.params.at(2); - Stage1ZirInst *arg2_value = astgen_node(ag, arg2_node, scope); - if (arg2_value == ag->codegen->invalid_inst_src) - return arg2_value; - - AstNode *arg3_node = node->data.fn_call_expr.params.at(3); - Stage1ZirInst *arg3_value = astgen_node(ag, arg3_node, scope); - if (arg3_value == ag->codegen->invalid_inst_src) - return arg3_value; - - AstNode *arg4_node = node->data.fn_call_expr.params.at(4); - Stage1ZirInst *arg4_value = astgen_node(ag, arg4_node, scope); - if (arg4_value == ag->codegen->invalid_inst_src) - return arg4_value; - - Stage1ZirInst *inst = ir_build_atomic_rmw_src(ag, scope, node, - arg0_value, arg1_value, arg2_value, arg3_value, arg4_value); - return ir_lval_wrap(ag, scope, inst, lval, result_loc); - } - case BuiltinFnIdAtomicLoad: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - Stage1ZirInst *arg0_value = astgen_node(ag, arg0_node, scope); - if (arg0_value == ag->codegen->invalid_inst_src) - return arg0_value; - - AstNode *arg1_node = node->data.fn_call_expr.params.at(1); - Stage1ZirInst *arg1_value = astgen_node(ag, arg1_node, scope); - if (arg1_value == ag->codegen->invalid_inst_src) - return arg1_value; - - AstNode *arg2_node = node->data.fn_call_expr.params.at(2); - Stage1ZirInst *arg2_value = astgen_node(ag, arg2_node, scope); - if (arg2_value == ag->codegen->invalid_inst_src) - return arg2_value; - - Stage1ZirInst *inst = ir_build_atomic_load_src(ag, scope, node, arg0_value, arg1_value, arg2_value); - return ir_lval_wrap(ag, scope, inst, lval, result_loc); - } - case BuiltinFnIdAtomicStore: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - Stage1ZirInst *arg0_value = astgen_node(ag, arg0_node, scope); - if (arg0_value == ag->codegen->invalid_inst_src) - return arg0_value; - - AstNode *arg1_node = node->data.fn_call_expr.params.at(1); - Stage1ZirInst *arg1_value = astgen_node(ag, arg1_node, scope); - if (arg1_value == ag->codegen->invalid_inst_src) - return arg1_value; - - AstNode *arg2_node = node->data.fn_call_expr.params.at(2); - Stage1ZirInst *arg2_value = astgen_node(ag, arg2_node, scope); - if (arg2_value == ag->codegen->invalid_inst_src) - return arg2_value; - - AstNode *arg3_node = node->data.fn_call_expr.params.at(3); - Stage1ZirInst *arg3_value = astgen_node(ag, arg3_node, scope); - if (arg3_value == ag->codegen->invalid_inst_src) - return arg3_value; - - Stage1ZirInst *inst = ir_build_atomic_store_src(ag, scope, node, arg0_value, arg1_value, - arg2_value, arg3_value); - return ir_lval_wrap(ag, scope, inst, lval, result_loc); - } - case BuiltinFnIdIntToEnum: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - Stage1ZirInst *arg0_value = astgen_node(ag, arg0_node, scope); - if (arg0_value == ag->codegen->invalid_inst_src) - return arg0_value; - - AstNode *arg1_node = node->data.fn_call_expr.params.at(1); - Stage1ZirInst *arg1_value = astgen_node(ag, arg1_node, scope); - if (arg1_value == ag->codegen->invalid_inst_src) - return arg1_value; - - Stage1ZirInst *result = ir_build_int_to_enum_src(ag, scope, node, arg0_value, arg1_value); - return ir_lval_wrap(ag, scope, result, lval, result_loc); - } - case BuiltinFnIdEnumToInt: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - Stage1ZirInst *arg0_value = astgen_node(ag, arg0_node, scope); - if (arg0_value == ag->codegen->invalid_inst_src) - return arg0_value; - - Stage1ZirInst *result = ir_build_enum_to_int(ag, scope, node, arg0_value); - return ir_lval_wrap(ag, scope, result, lval, result_loc); - } - case BuiltinFnIdCtz: - case BuiltinFnIdPopCount: - case BuiltinFnIdClz: - case BuiltinFnIdBswap: - case BuiltinFnIdBitReverse: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - Stage1ZirInst *arg0_value = astgen_node(ag, arg0_node, scope); - if (arg0_value == ag->codegen->invalid_inst_src) - return arg0_value; - - Stage1ZirInst *arg1_value = arg0_value; - arg0_value = ir_build_typeof_1(ag, scope, arg0_node, arg1_value); - - Stage1ZirInst *result; - switch (builtin_fn->id) { - case BuiltinFnIdCtz: - result = ir_build_ctz(ag, scope, node, arg0_value, arg1_value); - break; - case BuiltinFnIdPopCount: - result = ir_build_pop_count(ag, scope, node, arg0_value, arg1_value); - break; - case BuiltinFnIdClz: - result = ir_build_clz(ag, scope, node, arg0_value, arg1_value); - break; - case BuiltinFnIdBswap: - result = ir_build_bswap(ag, scope, node, arg0_value, arg1_value); - break; - case BuiltinFnIdBitReverse: - result = ir_build_bit_reverse(ag, scope, node, arg0_value, arg1_value); - break; - default: - zig_unreachable(); - } - return ir_lval_wrap(ag, scope, result, lval, result_loc); - } - case BuiltinFnIdHasDecl: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - Stage1ZirInst *arg0_value = astgen_node(ag, arg0_node, scope); - if (arg0_value == ag->codegen->invalid_inst_src) - return arg0_value; - - AstNode *arg1_node = node->data.fn_call_expr.params.at(1); - Stage1ZirInst *arg1_value = astgen_node(ag, arg1_node, scope); - if (arg1_value == ag->codegen->invalid_inst_src) - return arg1_value; - - Stage1ZirInst *has_decl = ir_build_has_decl(ag, scope, node, arg0_value, arg1_value); - return ir_lval_wrap(ag, scope, has_decl, lval, result_loc); - } - case BuiltinFnIdUnionInit: - { - AstNode *union_type_node = node->data.fn_call_expr.params.at(0); - Stage1ZirInst *union_type_inst = astgen_node(ag, union_type_node, scope); - if (union_type_inst == ag->codegen->invalid_inst_src) - return union_type_inst; - - AstNode *name_node = node->data.fn_call_expr.params.at(1); - Stage1ZirInst *name_inst = astgen_node(ag, name_node, scope); - if (name_inst == ag->codegen->invalid_inst_src) - return name_inst; - - AstNode *init_node = node->data.fn_call_expr.params.at(2); - - return astgen_union_init_expr(ag, scope, node, union_type_inst, name_inst, init_node, - lval, result_loc); - } - case BuiltinFnIdSrc: - { - Stage1ZirInst *src_inst = ir_build_src(ag, scope, node); - return ir_lval_wrap(ag, scope, src_inst, lval, result_loc); - } - case BuiltinFnIdPrefetch: - { - ZigType *options_type = get_builtin_type(ag->codegen, "PrefetchOptions"); - Stage1ZirInst *options_type_inst = ir_build_const_type(ag, scope, node, options_type); - ResultLocCast *result_loc_cast = ir_build_cast_result_loc(ag, options_type_inst, no_result_loc()); - - AstNode *ptr_node = node->data.fn_call_expr.params.at(0); - Stage1ZirInst *ptr_value = astgen_node(ag, ptr_node, scope); - if (ptr_value == ag->codegen->invalid_inst_src) - return ptr_value; - - AstNode *options_node = node->data.fn_call_expr.params.at(1); - Stage1ZirInst *options_value = astgen_node_extra(ag, options_node, - scope, LValNone, &result_loc_cast->base); - if (options_value == ag->codegen->invalid_inst_src) - return options_value; - - Stage1ZirInst *casted_options_value = ir_build_implicit_cast( - ag, scope, options_node, options_value, result_loc_cast); - - Stage1ZirInst *ir_extern = ir_build_prefetch(ag, scope, node, ptr_value, casted_options_value); - return ir_lval_wrap(ag, scope, ir_extern, lval, result_loc); - } - case BuiltinFnIdAddrSpaceCast: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - Stage1ZirInst *arg0_value = astgen_node(ag, arg0_node, scope); - if (arg0_value == ag->codegen->invalid_inst_src) - return arg0_value; - - AstNode* arg1_node = node->data.fn_call_expr.params.at(1); - Stage1ZirInst *arg1_value = astgen_node(ag, arg1_node, scope); - if (arg1_value == ag->codegen->invalid_inst_src) - return arg1_value; - - Stage1ZirInst *addrspace_cast = ir_build_addrspace_cast(ag, scope, node, arg0_value, arg1_value); - return ir_lval_wrap(ag, scope, addrspace_cast, lval, result_loc); - } - } - zig_unreachable(); -} - -static ScopeNoSuspend *get_scope_nosuspend(Scope *scope) { - while (scope) { - if (scope->id == ScopeIdNoSuspend) - return (ScopeNoSuspend *)scope; - if (scope->id == ScopeIdFnDef) - return nullptr; - - scope = scope->parent; - } - return nullptr; -} - -static Stage1ZirInst *astgen_fn_call(Stage1AstGen *ag, Scope *scope, AstNode *node, LVal lval, - ResultLoc *result_loc) -{ - assert(node->type == NodeTypeFnCallExpr); - - if (node->data.fn_call_expr.modifier == CallModifierBuiltin) - return astgen_builtin_fn_call(ag, scope, node, lval, result_loc); - - bool is_nosuspend = get_scope_nosuspend(scope) != nullptr; - CallModifier modifier = node->data.fn_call_expr.modifier; - if (is_nosuspend && modifier != CallModifierAsync) { - modifier = CallModifierNoSuspend; - } - - AstNode *fn_ref_node = node->data.fn_call_expr.fn_ref_expr; - return astgen_fn_call_with_args(ag, scope, node, fn_ref_node, modifier, - nullptr, node->data.fn_call_expr.params.items, node->data.fn_call_expr.params.length, lval, result_loc); -} - -static Stage1ZirInst *astgen_if_bool_expr(Stage1AstGen *ag, Scope *scope, AstNode *node, LVal lval, - ResultLoc *result_loc) -{ - assert(node->type == NodeTypeIfBoolExpr); - - Stage1ZirInst *condition = astgen_node(ag, node->data.if_bool_expr.condition, scope); - if (condition == ag->codegen->invalid_inst_src) - return ag->codegen->invalid_inst_src; - - Stage1ZirInst *is_comptime; - if (ir_should_inline(ag->exec, scope)) { - is_comptime = ir_build_const_bool(ag, scope, node, true); - } else { - is_comptime = ir_build_test_comptime(ag, scope, node, condition); - } - - AstNode *then_node = node->data.if_bool_expr.then_block; - AstNode *else_node = node->data.if_bool_expr.else_node; - - Stage1ZirBasicBlock *then_block = ir_create_basic_block(ag, scope, "Then"); - Stage1ZirBasicBlock *else_block = ir_create_basic_block(ag, scope, "Else"); - Stage1ZirBasicBlock *endif_block = ir_create_basic_block(ag, scope, "EndIf"); - - Stage1ZirInst *cond_br_inst = ir_build_cond_br(ag, scope, node, condition, - then_block, else_block, is_comptime); - ResultLocPeerParent *peer_parent = ir_build_binary_result_peers(ag, cond_br_inst, else_block, endif_block, - result_loc, is_comptime); - - ir_set_cursor_at_end_and_append_block(ag, then_block); - - Scope *subexpr_scope = create_runtime_scope(ag->codegen, node, scope, is_comptime); - Stage1ZirInst *then_expr_result = astgen_node_extra(ag, then_node, subexpr_scope, lval, - &peer_parent->peers.at(0)->base); - if (then_expr_result == ag->codegen->invalid_inst_src) - return ag->codegen->invalid_inst_src; - Stage1ZirBasicBlock *after_then_block = ag->current_basic_block; - if (!instr_is_unreachable(then_expr_result)) - ir_build_br(ag, scope, node, endif_block, is_comptime); - - ir_set_cursor_at_end_and_append_block(ag, else_block); - Stage1ZirInst *else_expr_result; - if (else_node) { - else_expr_result = astgen_node_extra(ag, else_node, subexpr_scope, lval, &peer_parent->peers.at(1)->base); - if (else_expr_result == ag->codegen->invalid_inst_src) - return ag->codegen->invalid_inst_src; - } else { - else_expr_result = ir_build_const_void(ag, scope, node); - ir_build_end_expr(ag, scope, node, else_expr_result, &peer_parent->peers.at(1)->base); - } - Stage1ZirBasicBlock *after_else_block = ag->current_basic_block; - if (!instr_is_unreachable(else_expr_result)) - ir_build_br(ag, scope, node, endif_block, is_comptime); - - ir_set_cursor_at_end_and_append_block(ag, endif_block); - Stage1ZirInst **incoming_values = heap::c_allocator.allocate(2); - incoming_values[0] = then_expr_result; - incoming_values[1] = else_expr_result; - Stage1ZirBasicBlock **incoming_blocks = heap::c_allocator.allocate(2); - incoming_blocks[0] = after_then_block; - incoming_blocks[1] = after_else_block; - - Stage1ZirInst *phi = ir_build_phi(ag, scope, node, false, 2, incoming_blocks, incoming_values, peer_parent); - return ir_expr_wrap(ag, scope, phi, result_loc); -} - -static Stage1ZirInst *astgen_prefix_op_id_lval(Stage1AstGen *ag, Scope *scope, AstNode *node, IrUnOp op_id, LVal lval) { - assert(node->type == NodeTypePrefixOpExpr); - AstNode *expr_node = node->data.prefix_op_expr.primary_expr; - - Stage1ZirInst *value = astgen_node_extra(ag, expr_node, scope, lval, nullptr); - if (value == ag->codegen->invalid_inst_src) - return value; - - return ir_build_un_op(ag, scope, node, op_id, value); -} - -static Stage1ZirInst *astgen_prefix_op_id(Stage1AstGen *ag, Scope *scope, AstNode *node, IrUnOp op_id) { - return astgen_prefix_op_id_lval(ag, scope, node, op_id, LValNone); -} - -static Stage1ZirInst *ir_expr_wrap(Stage1AstGen *ag, Scope *scope, Stage1ZirInst *inst, ResultLoc *result_loc) { - if (inst == ag->codegen->invalid_inst_src) return inst; - ir_build_end_expr(ag, scope, inst->source_node, inst, result_loc); - return inst; -} - -static Stage1ZirInst *ir_lval_wrap(Stage1AstGen *ag, Scope *scope, Stage1ZirInst *value, LVal lval, - ResultLoc *result_loc) -{ - // This logic must be kept in sync with - // [STMT_EXPR_TEST_THING] <--- (search this token) - if (value == ag->codegen->invalid_inst_src || - instr_is_unreachable(value) || - value->source_node->type == NodeTypeDefer || - value->id == Stage1ZirInstIdDeclVar) - { - return value; - } - - assert(lval != LValAssign); - if (lval == LValPtr) { - // We needed a pointer to a value, but we got a value. So we create - // an instruction which just makes a pointer of it. - return ir_build_ref_src(ag, scope, value->source_node, value); - } else if (result_loc != nullptr) { - return ir_expr_wrap(ag, scope, value, result_loc); - } else { - return value; - } - -} - -static PtrLen star_token_to_ptr_len(TokenId token_id) { - switch (token_id) { - case TokenIdStar: - case TokenIdStarStar: - return PtrLenSingle; - case TokenIdLBracket: - return PtrLenUnknown; - case TokenIdIdentifier: - return PtrLenC; - default: - zig_unreachable(); - } -} - -static Error token_number_literal_u32(Stage1AstGen *ag, AstNode *source_node, - RootStruct *root_struct, uint32_t *result, TokenIndex token) -{ - BigInt bigint; - token_number_literal_bigint(root_struct, &bigint, token); - - if (!bigint_fits_in_bits(&bigint, 32, false)) { - Buf *val_buf = buf_alloc(); - bigint_append_buf(val_buf, &bigint, 10); - exec_add_error_node(ag->codegen, ag->exec, source_node, - buf_sprintf("value %s too large for u32", buf_ptr(val_buf))); - bigint_deinit(&bigint); - return ErrorSemanticAnalyzeFail; - } - *result = bigint_as_u32(&bigint); - bigint_deinit(&bigint); - return ErrorNone; - -} - -static Stage1ZirInst *astgen_pointer_type(Stage1AstGen *ag, Scope *scope, AstNode *node) { - Error err; - assert(node->type == NodeTypePointerType); - - RootStruct *root_struct = node->owner->data.structure.root_struct; - TokenId star_tok_id = root_struct->token_ids[node->data.pointer_type.star_token]; - PtrLen ptr_len = star_token_to_ptr_len(star_tok_id); - - bool is_const = node->data.pointer_type.is_const; - bool is_volatile = node->data.pointer_type.is_volatile; - bool is_allow_zero = node->data.pointer_type.allow_zero_token != 0; - AstNode *sentinel_expr = node->data.pointer_type.sentinel; - AstNode *expr_node = node->data.pointer_type.op_expr; - AstNode *align_expr = node->data.pointer_type.align_expr; - - Stage1ZirInst *sentinel; - if (sentinel_expr != nullptr) { - sentinel = astgen_node(ag, sentinel_expr, scope); - if (sentinel == ag->codegen->invalid_inst_src) - return sentinel; - } else { - sentinel = nullptr; - } - - Stage1ZirInst *align_value; - if (align_expr != nullptr) { - align_value = astgen_node(ag, align_expr, scope); - if (align_value == ag->codegen->invalid_inst_src) - return align_value; - } else { - align_value = nullptr; - } - - Stage1ZirInst *child_type = astgen_node(ag, expr_node, scope); - if (child_type == ag->codegen->invalid_inst_src) - return child_type; - - uint32_t bit_offset_start = 0; - if (node->data.pointer_type.bit_offset_start != 0) { - if ((err = token_number_literal_u32(ag, node, root_struct, &bit_offset_start, - node->data.pointer_type.bit_offset_start))) - { - return ag->codegen->invalid_inst_src; - } - } - - uint32_t host_int_bytes = 0; - if (node->data.pointer_type.host_int_bytes != 0) { - if ((err = token_number_literal_u32(ag, node, root_struct, &host_int_bytes, - node->data.pointer_type.host_int_bytes))) - { - return ag->codegen->invalid_inst_src; - } - } - - if (host_int_bytes != 0 && bit_offset_start >= host_int_bytes * 8) { - exec_add_error_node(ag->codegen, ag->exec, node, - buf_sprintf("bit offset starts after end of host integer")); - return ag->codegen->invalid_inst_src; - } - - return ir_build_ptr_type(ag, scope, node, child_type, is_const, is_volatile, - ptr_len, sentinel, align_value, bit_offset_start, host_int_bytes, is_allow_zero); -} - -static Stage1ZirInst *astgen_catch_unreachable(Stage1AstGen *ag, Scope *scope, AstNode *source_node, - AstNode *expr_node, LVal lval, ResultLoc *result_loc) -{ - Stage1ZirInst *err_union_ptr = astgen_node_extra(ag, expr_node, scope, LValPtr, nullptr); - if (err_union_ptr == ag->codegen->invalid_inst_src) - return ag->codegen->invalid_inst_src; - - Stage1ZirInst *payload_ptr = ir_build_unwrap_err_payload_src(ag, scope, source_node, err_union_ptr, true, false); - if (payload_ptr == ag->codegen->invalid_inst_src) - return ag->codegen->invalid_inst_src; - - if (lval == LValPtr) - return payload_ptr; - - Stage1ZirInst *load_ptr = ir_build_load_ptr(ag, scope, source_node, payload_ptr); - return ir_expr_wrap(ag, scope, load_ptr, result_loc); -} - -static Stage1ZirInst *astgen_bool_not(Stage1AstGen *ag, Scope *scope, AstNode *node) { - assert(node->type == NodeTypePrefixOpExpr); - AstNode *expr_node = node->data.prefix_op_expr.primary_expr; - - Stage1ZirInst *value = astgen_node(ag, expr_node, scope); - if (value == ag->codegen->invalid_inst_src) - return ag->codegen->invalid_inst_src; - - return ir_build_bool_not(ag, scope, node, value); -} - -static Stage1ZirInst *astgen_prefix_op_expr(Stage1AstGen *ag, Scope *scope, AstNode *node, LVal lval, - ResultLoc *result_loc) -{ - assert(node->type == NodeTypePrefixOpExpr); - - PrefixOp prefix_op = node->data.prefix_op_expr.prefix_op; - - switch (prefix_op) { - case PrefixOpInvalid: - zig_unreachable(); - case PrefixOpBoolNot: - return ir_lval_wrap(ag, scope, astgen_bool_not(ag, scope, node), lval, result_loc); - case PrefixOpBinNot: - return ir_lval_wrap(ag, scope, astgen_prefix_op_id(ag, scope, node, IrUnOpBinNot), lval, result_loc); - case PrefixOpNegation: - return ir_lval_wrap(ag, scope, astgen_prefix_op_id(ag, scope, node, IrUnOpNegation), lval, result_loc); - case PrefixOpNegationWrap: - return ir_lval_wrap(ag, scope, astgen_prefix_op_id(ag, scope, node, IrUnOpNegationWrap), lval, result_loc); - case PrefixOpOptional: - return ir_lval_wrap(ag, scope, astgen_prefix_op_id(ag, scope, node, IrUnOpOptional), lval, result_loc); - case PrefixOpAddrOf: { - AstNode *expr_node = node->data.prefix_op_expr.primary_expr; - return ir_lval_wrap(ag, scope, astgen_node_extra(ag, expr_node, scope, LValPtr, nullptr), lval, result_loc); - } - } - zig_unreachable(); -} - -static Stage1ZirInst *astgen_union_init_expr(Stage1AstGen *ag, Scope *scope, AstNode *source_node, - Stage1ZirInst *union_type, Stage1ZirInst *field_name, AstNode *expr_node, - LVal lval, ResultLoc *parent_result_loc) -{ - Stage1ZirInst *container_ptr = ir_build_resolve_result(ag, scope, source_node, parent_result_loc, union_type); - Stage1ZirInst *field_ptr = ir_build_field_ptr_instruction(ag, scope, source_node, container_ptr, - field_name, true); - - ResultLocInstruction *result_loc_inst = heap::c_allocator.create(); - result_loc_inst->base.id = ResultLocIdInstruction; - result_loc_inst->base.source_instruction = field_ptr; - ir_ref_instruction(field_ptr, ag->current_basic_block); - ir_build_reset_result(ag, scope, expr_node, &result_loc_inst->base); - - Stage1ZirInst *expr_value = astgen_node_extra(ag, expr_node, scope, LValNone, - &result_loc_inst->base); - if (expr_value == ag->codegen->invalid_inst_src) - return expr_value; - - Stage1ZirInst *init_union = ir_build_union_init_named_field(ag, scope, source_node, union_type, - field_name, field_ptr, container_ptr); - - return ir_lval_wrap(ag, scope, init_union, lval, parent_result_loc); -} - -static Stage1ZirInst *astgen_container_init_expr(Stage1AstGen *ag, Scope *scope, AstNode *node, LVal lval, - ResultLoc *parent_result_loc) -{ - assert(node->type == NodeTypeContainerInitExpr); - - AstNodeContainerInitExpr *container_init_expr = &node->data.container_init_expr; - ContainerInitKind kind = container_init_expr->kind; - - ResultLocCast *result_loc_cast = nullptr; - ResultLoc *child_result_loc; - AstNode *init_array_type_source_node; - if (container_init_expr->type != nullptr) { - Stage1ZirInst *container_type; - if (container_init_expr->type->type == NodeTypeInferredArrayType) { - if (kind == ContainerInitKindStruct) { - add_node_error(ag->codegen, container_init_expr->type, - buf_sprintf("initializing array with struct syntax")); - return ag->codegen->invalid_inst_src; - } - Stage1ZirInst *sentinel; - if (container_init_expr->type->data.inferred_array_type.sentinel != nullptr) { - sentinel = astgen_node(ag, container_init_expr->type->data.inferred_array_type.sentinel, scope); - if (sentinel == ag->codegen->invalid_inst_src) - return sentinel; - } else { - sentinel = nullptr; - } - - Stage1ZirInst *elem_type = astgen_node(ag, - container_init_expr->type->data.inferred_array_type.child_type, scope); - if (elem_type == ag->codegen->invalid_inst_src) - return elem_type; - size_t item_count = container_init_expr->entries.length; - Stage1ZirInst *item_count_inst = ir_build_const_usize(ag, scope, node, item_count); - container_type = ir_build_array_type(ag, scope, node, item_count_inst, sentinel, elem_type); - } else { - container_type = astgen_node(ag, container_init_expr->type, scope); - if (container_type == ag->codegen->invalid_inst_src) - return container_type; - } - - result_loc_cast = ir_build_cast_result_loc(ag, container_type, parent_result_loc); - child_result_loc = &result_loc_cast->base; - init_array_type_source_node = container_type->source_node; - } else { - child_result_loc = parent_result_loc; - if (parent_result_loc->source_instruction != nullptr) { - init_array_type_source_node = parent_result_loc->source_instruction->source_node; - } else { - init_array_type_source_node = node; - } - } - - switch (kind) { - case ContainerInitKindStruct: { - Stage1ZirInst *container_ptr = ir_build_resolve_result(ag, scope, node, child_result_loc, - nullptr); - - size_t field_count = container_init_expr->entries.length; - Stage1ZirInstContainerInitFieldsField *fields = heap::c_allocator.allocate(field_count); - for (size_t i = 0; i < field_count; i += 1) { - AstNode *entry_node = container_init_expr->entries.at(i); - assert(entry_node->type == NodeTypeStructValueField); - - Buf *name = entry_node->data.struct_val_field.name; - AstNode *expr_node = entry_node->data.struct_val_field.expr; - - Stage1ZirInst *field_ptr = ir_build_field_ptr(ag, scope, entry_node, container_ptr, name, true); - ResultLocInstruction *result_loc_inst = heap::c_allocator.create(); - result_loc_inst->base.id = ResultLocIdInstruction; - result_loc_inst->base.source_instruction = field_ptr; - result_loc_inst->base.allow_write_through_const = true; - ir_ref_instruction(field_ptr, ag->current_basic_block); - ir_build_reset_result(ag, scope, expr_node, &result_loc_inst->base); - - Stage1ZirInst *expr_value = astgen_node_extra(ag, expr_node, scope, LValNone, - &result_loc_inst->base); - if (expr_value == ag->codegen->invalid_inst_src) - return expr_value; - - fields[i].name = name; - fields[i].source_node = entry_node; - fields[i].result_loc = field_ptr; - } - Stage1ZirInst *result = ir_build_container_init_fields(ag, scope, node, field_count, - fields, container_ptr); - - if (result_loc_cast != nullptr) { - result = ir_build_implicit_cast(ag, scope, node, result, result_loc_cast); - } - return ir_lval_wrap(ag, scope, result, lval, parent_result_loc); - } - case ContainerInitKindArray: { - size_t item_count = container_init_expr->entries.length; - - Stage1ZirInst *container_ptr = ir_build_resolve_result(ag, scope, node, child_result_loc, - nullptr); - - Stage1ZirInst **result_locs = heap::c_allocator.allocate(item_count); - for (size_t i = 0; i < item_count; i += 1) { - AstNode *expr_node = container_init_expr->entries.at(i); - - Stage1ZirInst *elem_index = ir_build_const_usize(ag, scope, expr_node, i); - Stage1ZirInst *elem_ptr = ir_build_elem_ptr(ag, scope, expr_node, container_ptr, - elem_index, false, PtrLenSingle, init_array_type_source_node); - ResultLocInstruction *result_loc_inst = heap::c_allocator.create(); - result_loc_inst->base.id = ResultLocIdInstruction; - result_loc_inst->base.source_instruction = elem_ptr; - result_loc_inst->base.allow_write_through_const = true; - ir_ref_instruction(elem_ptr, ag->current_basic_block); - ir_build_reset_result(ag, scope, expr_node, &result_loc_inst->base); - - Stage1ZirInst *expr_value = astgen_node_extra(ag, expr_node, scope, LValNone, - &result_loc_inst->base); - if (expr_value == ag->codegen->invalid_inst_src) - return expr_value; - - result_locs[i] = elem_ptr; - } - Stage1ZirInst *result = ir_build_container_init_list(ag, scope, node, item_count, - result_locs, container_ptr, init_array_type_source_node); - if (result_loc_cast != nullptr) { - result = ir_build_implicit_cast(ag, scope, node, result, result_loc_cast); - } - return ir_lval_wrap(ag, scope, result, lval, parent_result_loc); - } - } - zig_unreachable(); -} - -static ResultLocVar *ir_build_var_result_loc(Stage1AstGen *ag, Stage1ZirInst *alloca, ZigVar *var) { - ResultLocVar *result_loc_var = heap::c_allocator.create(); - result_loc_var->base.id = ResultLocIdVar; - result_loc_var->base.source_instruction = alloca; - result_loc_var->base.allow_write_through_const = true; - result_loc_var->var = var; - - ir_build_reset_result(ag, alloca->scope, alloca->source_node, &result_loc_var->base); - - return result_loc_var; -} - -static ResultLocCast *ir_build_cast_result_loc(Stage1AstGen *ag, Stage1ZirInst *dest_type, - ResultLoc *parent_result_loc) -{ - ResultLocCast *result_loc_cast = heap::c_allocator.create(); - result_loc_cast->base.id = ResultLocIdCast; - result_loc_cast->base.source_instruction = dest_type; - result_loc_cast->base.allow_write_through_const = parent_result_loc->allow_write_through_const; - ir_ref_instruction(dest_type, ag->current_basic_block); - result_loc_cast->parent = parent_result_loc; - - ir_build_reset_result(ag, dest_type->scope, dest_type->source_node, &result_loc_cast->base); - - return result_loc_cast; -} - -static void build_decl_var_and_init(Stage1AstGen *ag, Scope *scope, AstNode *source_node, ZigVar *var, - Stage1ZirInst *init, const char *name_hint, Stage1ZirInst *is_comptime) -{ - Stage1ZirInst *alloca = ir_build_alloca_src(ag, scope, source_node, nullptr, name_hint, is_comptime); - ResultLocVar *var_result_loc = ir_build_var_result_loc(ag, alloca, var); - ir_build_end_expr(ag, scope, source_node, init, &var_result_loc->base); - ir_build_var_decl_src(ag, scope, source_node, var, nullptr, alloca); -} - -static Stage1ZirInst *astgen_var_decl(Stage1AstGen *ag, Scope *scope, AstNode *node) { - assert(node->type == NodeTypeVariableDeclaration); - - AstNodeVariableDeclaration *variable_declaration = &node->data.variable_declaration; - - if (buf_eql_str(variable_declaration->symbol, "_")) { - add_node_error(ag->codegen, node, buf_sprintf("`_` is not a declarable symbol")); - return ag->codegen->invalid_inst_src; - } - - // Used for the type expr and the align expr - Scope *comptime_scope = create_comptime_scope(ag->codegen, node, scope); - - Stage1ZirInst *type_instruction; - if (variable_declaration->type != nullptr) { - type_instruction = astgen_node(ag, variable_declaration->type, comptime_scope); - if (type_instruction == ag->codegen->invalid_inst_src) - return type_instruction; - } else { - type_instruction = nullptr; - } - - bool is_shadowable = false; - bool is_const = variable_declaration->is_const; - bool is_extern = variable_declaration->is_extern; - - bool is_comptime_scalar = ir_should_inline(ag->exec, scope) || variable_declaration->is_comptime; - Stage1ZirInst *is_comptime = ir_build_const_bool(ag, scope, node, is_comptime_scalar); - ZigVar *var = ir_create_var(ag, node, scope, variable_declaration->symbol, - is_const, is_const, is_shadowable, is_comptime); - // we detect Stage1ZirInstDeclVar in gen_block to make sure the next node - // is inside var->child_scope - - if (!is_extern && !variable_declaration->expr) { - var->var_type = ag->codegen->builtin_types.entry_invalid; - add_node_error(ag->codegen, node, buf_sprintf("variables must be initialized")); - return ag->codegen->invalid_inst_src; - } - - Stage1ZirInst *align_value = nullptr; - if (variable_declaration->align_expr != nullptr) { - align_value = astgen_node(ag, variable_declaration->align_expr, comptime_scope); - if (align_value == ag->codegen->invalid_inst_src) - return align_value; - } - - if (variable_declaration->section_expr != nullptr) { - add_node_error(ag->codegen, variable_declaration->section_expr, - buf_sprintf("cannot set section of local variable '%s'", buf_ptr(variable_declaration->symbol))); - } - - // Parser should ensure that this never happens - assert(variable_declaration->threadlocal_tok == 0); - - Stage1ZirInst *alloca = ir_build_alloca_src(ag, scope, node, align_value, - buf_ptr(variable_declaration->symbol), is_comptime); - - // Create a result location for the initialization expression. - ResultLocVar *result_loc_var = ir_build_var_result_loc(ag, alloca, var); - ResultLoc *init_result_loc; - ResultLocCast *result_loc_cast; - if (type_instruction != nullptr) { - result_loc_cast = ir_build_cast_result_loc(ag, type_instruction, &result_loc_var->base); - init_result_loc = &result_loc_cast->base; - } else { - result_loc_cast = nullptr; - init_result_loc = &result_loc_var->base; - } - - Scope *init_scope = is_comptime_scalar ? - create_comptime_scope(ag->codegen, variable_declaration->expr, scope) : scope; - - // Temporarily set the name of the Stage1Zir to the VariableDeclaration - // so that the struct or enum from the init expression inherits the name. - Buf *old_exec_name = ag->exec->name; - ag->exec->name = variable_declaration->symbol; - Stage1ZirInst *init_value = astgen_node_extra(ag, variable_declaration->expr, init_scope, - LValNone, init_result_loc); - ag->exec->name = old_exec_name; - - if (init_value == ag->codegen->invalid_inst_src) - return ag->codegen->invalid_inst_src; - - if (result_loc_cast != nullptr) { - Stage1ZirInst *implicit_cast = ir_build_implicit_cast(ag, scope, init_value->source_node, - init_value, result_loc_cast); - ir_build_end_expr(ag, scope, node, implicit_cast, &result_loc_var->base); - } - - return ir_build_var_decl_src(ag, scope, node, var, align_value, alloca); -} - -static Stage1ZirInst *astgen_while_expr(Stage1AstGen *ag, Scope *scope, AstNode *node, LVal lval, - ResultLoc *result_loc) -{ - assert(node->type == NodeTypeWhileExpr); - - AstNode *continue_expr_node = node->data.while_expr.continue_expr; - AstNode *else_node = node->data.while_expr.else_node; - - Stage1ZirBasicBlock *cond_block = ir_create_basic_block(ag, scope, "WhileCond"); - Stage1ZirBasicBlock *body_block = ir_create_basic_block(ag, scope, "WhileBody"); - Stage1ZirBasicBlock *continue_block = continue_expr_node ? - ir_create_basic_block(ag, scope, "WhileContinue") : cond_block; - Stage1ZirBasicBlock *end_block = ir_create_basic_block(ag, scope, "WhileEnd"); - Stage1ZirBasicBlock *else_block = else_node ? - ir_create_basic_block(ag, scope, "WhileElse") : end_block; - - Stage1ZirInst *is_comptime = ir_build_const_bool(ag, scope, node, - ir_should_inline(ag->exec, scope) || node->data.while_expr.is_inline); - ir_build_br(ag, scope, node, cond_block, is_comptime); - - Scope *subexpr_scope = create_runtime_scope(ag->codegen, node, scope, is_comptime); - Buf *var_symbol = node->data.while_expr.var_symbol; - Buf *err_symbol = node->data.while_expr.err_symbol; - if (err_symbol != nullptr) { - ir_set_cursor_at_end_and_append_block(ag, cond_block); - - Scope *payload_scope; - AstNode *symbol_node = node; // TODO make more accurate - ZigVar *payload_var; - if (var_symbol) { - // TODO make it an error to write to payload variable - payload_var = ir_create_var(ag, symbol_node, subexpr_scope, var_symbol, - true, false, false, is_comptime); - payload_scope = payload_var->child_scope; - } else { - payload_scope = subexpr_scope; - } - ScopeExpr *spill_scope = create_expr_scope(ag->codegen, node, payload_scope); - Stage1ZirInst *err_val_ptr = astgen_node_extra(ag, node->data.while_expr.condition, subexpr_scope, - LValPtr, nullptr); - if (err_val_ptr == ag->codegen->invalid_inst_src) - return err_val_ptr; - Stage1ZirInst *is_err = ir_build_test_err_src(ag, scope, node->data.while_expr.condition, err_val_ptr, - true, false); - Stage1ZirBasicBlock *after_cond_block = ag->current_basic_block; - Stage1ZirInst *void_else_result = else_node ? nullptr : ir_build_const_void(ag, scope, node); - Stage1ZirInst *cond_br_inst; - if (!instr_is_unreachable(is_err)) { - cond_br_inst = ir_build_cond_br(ag, scope, node->data.while_expr.condition, is_err, - else_block, body_block, is_comptime); - } else { - // for the purposes of the source instruction to ir_build_result_peers - cond_br_inst = ag->current_basic_block->instruction_list.last(); - } - - ResultLocPeerParent *peer_parent = ir_build_result_peers(ag, cond_br_inst, end_block, result_loc, - is_comptime); - - ir_set_cursor_at_end_and_append_block(ag, body_block); - if (var_symbol) { - Stage1ZirInst *payload_ptr = ir_build_unwrap_err_payload_src(ag, &spill_scope->base, symbol_node, - err_val_ptr, false, false); - Stage1ZirInst *var_value = node->data.while_expr.var_is_ptr ? - payload_ptr : ir_build_load_ptr(ag, &spill_scope->base, symbol_node, payload_ptr); - build_decl_var_and_init(ag, payload_scope, symbol_node, payload_var, var_value, buf_ptr(var_symbol), is_comptime); - } - - ZigList incoming_values = {0}; - ZigList incoming_blocks = {0}; - - if (is_duplicate_label(ag->codegen, payload_scope, node, node->data.while_expr.name)) - return ag->codegen->invalid_inst_src; - - ScopeLoop *loop_scope = create_loop_scope(ag->codegen, node, payload_scope); - loop_scope->break_block = end_block; - loop_scope->continue_block = continue_block; - loop_scope->is_comptime = is_comptime; - loop_scope->incoming_blocks = &incoming_blocks; - loop_scope->incoming_values = &incoming_values; - loop_scope->lval = lval; - loop_scope->peer_parent = peer_parent; - loop_scope->spill_scope = spill_scope; - - // Note the body block of the loop is not the place that lval and result_loc are used - - // it's actually in break statements, handled similarly to return statements. - // That is why we set those values in loop_scope above and not in this astgen_node call. - Stage1ZirInst *body_result = astgen_node(ag, node->data.while_expr.body, &loop_scope->base); - if (body_result == ag->codegen->invalid_inst_src) - return body_result; - - if (loop_scope->name != nullptr && loop_scope->name_used == false) { - add_node_error(ag->codegen, node, buf_sprintf("unused while label")); - } - - if (!instr_is_unreachable(body_result)) { - ir_build_check_statement_is_void(ag, payload_scope, node->data.while_expr.body, body_result); - ir_build_br(ag, payload_scope, node, continue_block, is_comptime); - } - - if (continue_expr_node) { - ir_set_cursor_at_end_and_append_block(ag, continue_block); - Stage1ZirInst *expr_result = astgen_node(ag, continue_expr_node, payload_scope); - if (expr_result == ag->codegen->invalid_inst_src) - return expr_result; - if (!instr_is_unreachable(expr_result)) { - ir_build_check_statement_is_void(ag, payload_scope, continue_expr_node, expr_result); - ir_build_br(ag, payload_scope, node, cond_block, is_comptime); - } - } - - ir_set_cursor_at_end_and_append_block(ag, else_block); - assert(else_node != nullptr); - - // TODO make it an error to write to error variable - AstNode *err_symbol_node = else_node; // TODO make more accurate - ZigVar *err_var = ir_create_var(ag, err_symbol_node, scope, err_symbol, - true, false, false, is_comptime); - Scope *err_scope = err_var->child_scope; - Stage1ZirInst *err_ptr = ir_build_unwrap_err_code_src(ag, err_scope, err_symbol_node, err_val_ptr); - Stage1ZirInst *err_value = ir_build_load_ptr(ag, err_scope, err_symbol_node, err_ptr); - build_decl_var_and_init(ag, err_scope, err_symbol_node, err_var, err_value, buf_ptr(err_symbol), is_comptime); - - if (peer_parent->peers.length != 0) { - peer_parent->peers.last()->next_bb = else_block; - } - ResultLocPeer *peer_result = create_peer_result(peer_parent); - peer_parent->peers.append(peer_result); - Stage1ZirInst *else_result = astgen_node_extra(ag, else_node, err_scope, lval, &peer_result->base); - if (else_result == ag->codegen->invalid_inst_src) - return else_result; - if (!instr_is_unreachable(else_result)) - ir_build_br(ag, scope, node, end_block, is_comptime); - Stage1ZirBasicBlock *after_else_block = ag->current_basic_block; - ir_set_cursor_at_end_and_append_block(ag, end_block); - if (else_result) { - incoming_blocks.append(after_else_block); - incoming_values.append(else_result); - } else { - incoming_blocks.append(after_cond_block); - incoming_values.append(void_else_result); - } - if (peer_parent->peers.length != 0) { - peer_parent->peers.last()->next_bb = end_block; - } - - Stage1ZirInst *phi = ir_build_phi(ag, scope, node, false, incoming_blocks.length, - incoming_blocks.items, incoming_values.items, peer_parent); - return ir_expr_wrap(ag, scope, phi, result_loc); - } else if (var_symbol != nullptr) { - ir_set_cursor_at_end_and_append_block(ag, cond_block); - Scope *subexpr_scope = create_runtime_scope(ag->codegen, node, scope, is_comptime); - // TODO make it an error to write to payload variable - AstNode *symbol_node = node; // TODO make more accurate - - ZigVar *payload_var = ir_create_var(ag, symbol_node, subexpr_scope, var_symbol, - true, false, false, is_comptime); - Scope *child_scope = payload_var->child_scope; - ScopeExpr *spill_scope = create_expr_scope(ag->codegen, node, child_scope); - Stage1ZirInst *maybe_val_ptr = astgen_node_extra(ag, node->data.while_expr.condition, subexpr_scope, - LValPtr, nullptr); - if (maybe_val_ptr == ag->codegen->invalid_inst_src) - return maybe_val_ptr; - Stage1ZirInst *maybe_val = ir_build_load_ptr(ag, scope, node->data.while_expr.condition, maybe_val_ptr); - Stage1ZirInst *is_non_null = ir_build_test_non_null_src(ag, scope, node->data.while_expr.condition, maybe_val); - Stage1ZirBasicBlock *after_cond_block = ag->current_basic_block; - Stage1ZirInst *void_else_result = else_node ? nullptr : ir_build_const_void(ag, scope, node); - Stage1ZirInst *cond_br_inst; - if (!instr_is_unreachable(is_non_null)) { - cond_br_inst = ir_build_cond_br(ag, scope, node->data.while_expr.condition, is_non_null, - body_block, else_block, is_comptime); - } else { - // for the purposes of the source instruction to ir_build_result_peers - cond_br_inst = ag->current_basic_block->instruction_list.last(); - } - - ResultLocPeerParent *peer_parent = ir_build_result_peers(ag, cond_br_inst, end_block, result_loc, - is_comptime); - - ir_set_cursor_at_end_and_append_block(ag, body_block); - Stage1ZirInst *payload_ptr = ir_build_optional_unwrap_ptr(ag, &spill_scope->base, symbol_node, maybe_val_ptr, false); - Stage1ZirInst *var_value = node->data.while_expr.var_is_ptr ? - payload_ptr : ir_build_load_ptr(ag, &spill_scope->base, symbol_node, payload_ptr); - build_decl_var_and_init(ag, child_scope, symbol_node, payload_var, var_value, buf_ptr(var_symbol), is_comptime); - - ZigList incoming_values = {0}; - ZigList incoming_blocks = {0}; - - if (is_duplicate_label(ag->codegen, child_scope, node, node->data.while_expr.name)) - return ag->codegen->invalid_inst_src; - - ScopeLoop *loop_scope = create_loop_scope(ag->codegen, node, child_scope); - loop_scope->break_block = end_block; - loop_scope->continue_block = continue_block; - loop_scope->is_comptime = is_comptime; - loop_scope->incoming_blocks = &incoming_blocks; - loop_scope->incoming_values = &incoming_values; - loop_scope->lval = lval; - loop_scope->peer_parent = peer_parent; - loop_scope->spill_scope = spill_scope; - - // Note the body block of the loop is not the place that lval and result_loc are used - - // it's actually in break statements, handled similarly to return statements. - // That is why we set those values in loop_scope above and not in this astgen_node call. - Stage1ZirInst *body_result = astgen_node(ag, node->data.while_expr.body, &loop_scope->base); - if (body_result == ag->codegen->invalid_inst_src) - return body_result; - - if (loop_scope->name != nullptr && loop_scope->name_used == false) { - add_node_error(ag->codegen, node, buf_sprintf("unused while label")); - } - - if (!instr_is_unreachable(body_result)) { - ir_build_check_statement_is_void(ag, child_scope, node->data.while_expr.body, body_result); - ir_build_br(ag, child_scope, node, continue_block, is_comptime); - } - - if (continue_expr_node) { - ir_set_cursor_at_end_and_append_block(ag, continue_block); - Stage1ZirInst *expr_result = astgen_node(ag, continue_expr_node, child_scope); - if (expr_result == ag->codegen->invalid_inst_src) - return expr_result; - if (!instr_is_unreachable(expr_result)) { - ir_build_check_statement_is_void(ag, child_scope, continue_expr_node, expr_result); - ir_build_br(ag, child_scope, node, cond_block, is_comptime); - } - } - - Stage1ZirInst *else_result = nullptr; - if (else_node) { - ir_set_cursor_at_end_and_append_block(ag, else_block); - - if (peer_parent->peers.length != 0) { - peer_parent->peers.last()->next_bb = else_block; - } - ResultLocPeer *peer_result = create_peer_result(peer_parent); - peer_parent->peers.append(peer_result); - else_result = astgen_node_extra(ag, else_node, scope, lval, &peer_result->base); - if (else_result == ag->codegen->invalid_inst_src) - return else_result; - if (!instr_is_unreachable(else_result)) - ir_build_br(ag, scope, node, end_block, is_comptime); - } - Stage1ZirBasicBlock *after_else_block = ag->current_basic_block; - ir_set_cursor_at_end_and_append_block(ag, end_block); - if (else_result) { - incoming_blocks.append(after_else_block); - incoming_values.append(else_result); - } else { - incoming_blocks.append(after_cond_block); - incoming_values.append(void_else_result); - } - if (peer_parent->peers.length != 0) { - peer_parent->peers.last()->next_bb = end_block; - } - - Stage1ZirInst *phi = ir_build_phi(ag, scope, node, false, incoming_blocks.length, - incoming_blocks.items, incoming_values.items, peer_parent); - return ir_expr_wrap(ag, scope, phi, result_loc); - } else { - ir_set_cursor_at_end_and_append_block(ag, cond_block); - Stage1ZirInst *cond_val = astgen_node(ag, node->data.while_expr.condition, scope); - if (cond_val == ag->codegen->invalid_inst_src) - return cond_val; - Stage1ZirBasicBlock *after_cond_block = ag->current_basic_block; - Stage1ZirInst *void_else_result = else_node ? nullptr : ir_build_const_void(ag, scope, node); - Stage1ZirInst *cond_br_inst; - if (!instr_is_unreachable(cond_val)) { - cond_br_inst = ir_build_cond_br(ag, scope, node->data.while_expr.condition, cond_val, - body_block, else_block, is_comptime); - } else { - // for the purposes of the source instruction to ir_build_result_peers - cond_br_inst = ag->current_basic_block->instruction_list.last(); - } - - ResultLocPeerParent *peer_parent = ir_build_result_peers(ag, cond_br_inst, end_block, result_loc, - is_comptime); - ir_set_cursor_at_end_and_append_block(ag, body_block); - - ZigList incoming_values = {0}; - ZigList incoming_blocks = {0}; - - Scope *subexpr_scope = create_runtime_scope(ag->codegen, node, scope, is_comptime); - - if (is_duplicate_label(ag->codegen, subexpr_scope, node, node->data.while_expr.name)) - return ag->codegen->invalid_inst_src; - - ScopeLoop *loop_scope = create_loop_scope(ag->codegen, node, subexpr_scope); - loop_scope->break_block = end_block; - loop_scope->continue_block = continue_block; - loop_scope->is_comptime = is_comptime; - loop_scope->incoming_blocks = &incoming_blocks; - loop_scope->incoming_values = &incoming_values; - loop_scope->lval = lval; - loop_scope->peer_parent = peer_parent; - - // Note the body block of the loop is not the place that lval and result_loc are used - - // it's actually in break statements, handled similarly to return statements. - // That is why we set those values in loop_scope above and not in this astgen_node call. - Stage1ZirInst *body_result = astgen_node(ag, node->data.while_expr.body, &loop_scope->base); - if (body_result == ag->codegen->invalid_inst_src) - return body_result; - - if (loop_scope->name != nullptr && loop_scope->name_used == false) { - add_node_error(ag->codegen, node, buf_sprintf("unused while label")); - } - - if (!instr_is_unreachable(body_result)) { - ir_build_check_statement_is_void(ag, scope, node->data.while_expr.body, body_result); - ir_build_br(ag, scope, node, continue_block, is_comptime); - } - - if (continue_expr_node) { - ir_set_cursor_at_end_and_append_block(ag, continue_block); - Stage1ZirInst *expr_result = astgen_node(ag, continue_expr_node, subexpr_scope); - if (expr_result == ag->codegen->invalid_inst_src) - return expr_result; - if (!instr_is_unreachable(expr_result)) { - ir_build_check_statement_is_void(ag, scope, continue_expr_node, expr_result); - ir_build_br(ag, scope, node, cond_block, is_comptime); - } - } - - Stage1ZirInst *else_result = nullptr; - if (else_node) { - ir_set_cursor_at_end_and_append_block(ag, else_block); - - if (peer_parent->peers.length != 0) { - peer_parent->peers.last()->next_bb = else_block; - } - ResultLocPeer *peer_result = create_peer_result(peer_parent); - peer_parent->peers.append(peer_result); - - else_result = astgen_node_extra(ag, else_node, subexpr_scope, lval, &peer_result->base); - if (else_result == ag->codegen->invalid_inst_src) - return else_result; - if (!instr_is_unreachable(else_result)) - ir_build_br(ag, scope, node, end_block, is_comptime); - } - Stage1ZirBasicBlock *after_else_block = ag->current_basic_block; - ir_set_cursor_at_end_and_append_block(ag, end_block); - if (else_result) { - incoming_blocks.append(after_else_block); - incoming_values.append(else_result); - } else { - incoming_blocks.append(after_cond_block); - incoming_values.append(void_else_result); - } - if (peer_parent->peers.length != 0) { - peer_parent->peers.last()->next_bb = end_block; - } - - Stage1ZirInst *phi = ir_build_phi(ag, scope, node, false, incoming_blocks.length, - incoming_blocks.items, incoming_values.items, peer_parent); - return ir_expr_wrap(ag, scope, phi, result_loc); - } -} - -static Stage1ZirInst *astgen_for_expr(Stage1AstGen *ag, Scope *parent_scope, AstNode *node, LVal lval, - ResultLoc *result_loc) -{ - assert(node->type == NodeTypeForExpr); - - AstNode *array_node = node->data.for_expr.array_expr; - AstNode *elem_node = node->data.for_expr.elem_node; - AstNode *index_node = node->data.for_expr.index_node; - AstNode *body_node = node->data.for_expr.body; - AstNode *else_node = node->data.for_expr.else_node; - - if (!elem_node) { - add_node_error(ag->codegen, node, buf_sprintf("for loop expression missing element parameter")); - return ag->codegen->invalid_inst_src; - } - assert(elem_node->type == NodeTypeIdentifier); - - ScopeExpr *spill_scope = create_expr_scope(ag->codegen, node, parent_scope); - - Stage1ZirInst *array_val_ptr = astgen_node_extra(ag, array_node, &spill_scope->base, LValPtr, nullptr); - if (array_val_ptr == ag->codegen->invalid_inst_src) - return array_val_ptr; - - Stage1ZirInst *is_comptime = ir_build_const_bool(ag, parent_scope, node, - ir_should_inline(ag->exec, parent_scope) || node->data.for_expr.is_inline); - - AstNode *index_var_source_node; - ZigVar *index_var; - const char *index_var_name; - if (index_node) { - index_var_source_node = index_node; - Buf *index_var_name_buf = node_identifier_buf(index_node); - index_var = ir_create_var(ag, index_node, parent_scope, index_var_name_buf, true, false, false, is_comptime); - index_var_name = buf_ptr(index_var_name_buf); - } else { - index_var_source_node = node; - index_var = ir_create_var(ag, node, parent_scope, nullptr, true, false, true, is_comptime); - index_var_name = "i"; - } - - Stage1ZirInst *zero = ir_build_const_usize(ag, parent_scope, node, 0); - build_decl_var_and_init(ag, parent_scope, index_var_source_node, index_var, zero, index_var_name, is_comptime); - parent_scope = index_var->child_scope; - - Stage1ZirInst *one = ir_build_const_usize(ag, parent_scope, node, 1); - Stage1ZirInst *index_ptr = ir_build_var_ptr(ag, parent_scope, node, index_var); - - - Stage1ZirBasicBlock *cond_block = ir_create_basic_block(ag, parent_scope, "ForCond"); - Stage1ZirBasicBlock *body_block = ir_create_basic_block(ag, parent_scope, "ForBody"); - Stage1ZirBasicBlock *end_block = ir_create_basic_block(ag, parent_scope, "ForEnd"); - Stage1ZirBasicBlock *else_block = else_node ? ir_create_basic_block(ag, parent_scope, "ForElse") : end_block; - Stage1ZirBasicBlock *continue_block = ir_create_basic_block(ag, parent_scope, "ForContinue"); - - Buf *len_field_name = buf_create_from_str("len"); - Stage1ZirInst *len_ref = ir_build_field_ptr(ag, parent_scope, node, array_val_ptr, len_field_name, false); - Stage1ZirInst *len_val = ir_build_load_ptr(ag, &spill_scope->base, node, len_ref); - ir_build_br(ag, parent_scope, node, cond_block, is_comptime); - - ir_set_cursor_at_end_and_append_block(ag, cond_block); - Stage1ZirInst *index_val = ir_build_load_ptr(ag, &spill_scope->base, node, index_ptr); - Stage1ZirInst *cond = ir_build_bin_op(ag, parent_scope, node, IrBinOpCmpLessThan, index_val, len_val, false); - Stage1ZirBasicBlock *after_cond_block = ag->current_basic_block; - Stage1ZirInst *void_else_value = else_node ? nullptr : ir_build_const_void(ag, parent_scope, node); - Stage1ZirInst *cond_br_inst = ir_build_cond_br(ag, parent_scope, node, cond, - body_block, else_block, is_comptime); - - ResultLocPeerParent *peer_parent = ir_build_result_peers(ag, cond_br_inst, end_block, result_loc, is_comptime); - - ir_set_cursor_at_end_and_append_block(ag, body_block); - Stage1ZirInst *elem_ptr = ir_build_elem_ptr(ag, &spill_scope->base, node, array_val_ptr, index_val, - false, PtrLenSingle, nullptr); - // TODO make it an error to write to element variable or i variable. - Buf *elem_var_name = node_identifier_buf(elem_node); - ZigVar *elem_var = ir_create_var(ag, elem_node, parent_scope, elem_var_name, true, false, false, is_comptime); - Scope *child_scope = elem_var->child_scope; - - Stage1ZirInst *elem_value = node->data.for_expr.elem_is_ptr ? - elem_ptr : ir_build_load_ptr(ag, &spill_scope->base, elem_node, elem_ptr); - build_decl_var_and_init(ag, parent_scope, elem_node, elem_var, elem_value, buf_ptr(elem_var_name), is_comptime); - - if (is_duplicate_label(ag->codegen, child_scope, node, node->data.for_expr.name)) - return ag->codegen->invalid_inst_src; - - ZigList incoming_values = {0}; - ZigList incoming_blocks = {0}; - ScopeLoop *loop_scope = create_loop_scope(ag->codegen, node, child_scope); - loop_scope->break_block = end_block; - loop_scope->continue_block = continue_block; - loop_scope->is_comptime = is_comptime; - loop_scope->incoming_blocks = &incoming_blocks; - loop_scope->incoming_values = &incoming_values; - loop_scope->lval = LValNone; - loop_scope->peer_parent = peer_parent; - loop_scope->spill_scope = spill_scope; - - // Note the body block of the loop is not the place that lval and result_loc are used - - // it's actually in break statements, handled similarly to return statements. - // That is why we set those values in loop_scope above and not in this astgen_node call. - Stage1ZirInst *body_result = astgen_node(ag, body_node, &loop_scope->base); - if (body_result == ag->codegen->invalid_inst_src) - return ag->codegen->invalid_inst_src; - - if (loop_scope->name != nullptr && loop_scope->name_used == false) { - add_node_error(ag->codegen, node, buf_sprintf("unused for label")); - } - - if (!instr_is_unreachable(body_result)) { - ir_build_check_statement_is_void(ag, child_scope, node->data.for_expr.body, body_result); - ir_build_br(ag, child_scope, node, continue_block, is_comptime); - } - - ir_set_cursor_at_end_and_append_block(ag, continue_block); - Stage1ZirInst *new_index_val = ir_build_bin_op(ag, child_scope, node, IrBinOpAdd, index_val, one, false); - ir_build_store_ptr(ag, child_scope, node, index_ptr, new_index_val)->allow_write_through_const = true; - ir_build_br(ag, child_scope, node, cond_block, is_comptime); - - Stage1ZirInst *else_result = nullptr; - if (else_node) { - ir_set_cursor_at_end_and_append_block(ag, else_block); - - if (peer_parent->peers.length != 0) { - peer_parent->peers.last()->next_bb = else_block; - } - ResultLocPeer *peer_result = create_peer_result(peer_parent); - peer_parent->peers.append(peer_result); - else_result = astgen_node_extra(ag, else_node, parent_scope, LValNone, &peer_result->base); - if (else_result == ag->codegen->invalid_inst_src) - return else_result; - if (!instr_is_unreachable(else_result)) - ir_build_br(ag, parent_scope, node, end_block, is_comptime); - } - Stage1ZirBasicBlock *after_else_block = ag->current_basic_block; - ir_set_cursor_at_end_and_append_block(ag, end_block); - - if (else_result) { - incoming_blocks.append(after_else_block); - incoming_values.append(else_result); - } else { - incoming_blocks.append(after_cond_block); - incoming_values.append(void_else_value); - } - if (peer_parent->peers.length != 0) { - peer_parent->peers.last()->next_bb = end_block; - } - - Stage1ZirInst *phi = ir_build_phi(ag, parent_scope, node, false, incoming_blocks.length, - incoming_blocks.items, incoming_values.items, peer_parent); - return ir_lval_wrap(ag, parent_scope, phi, lval, result_loc); -} - -static Stage1ZirInst *astgen_enum_literal(Stage1AstGen *ag, Scope *scope, AstNode *node) { - assert(node->type == NodeTypeEnumLiteral); - // Currently, stage1 runs astgen for every comptime function call, - // resulting the allocation here wasting memory. As a workaround until - // the code is adjusted to make astgen run only once per source node, - // we memoize the result into the AST here. - if (node->data.enum_literal.name == nullptr) { - RootStruct *root_struct = node->owner->data.structure.root_struct; - node->data.enum_literal.name = token_identifier_buf(root_struct, node->main_token + 1); - } - return ir_build_const_enum_literal(ag, scope, node, node->data.enum_literal.name); -} - -static Stage1ZirInst *astgen_string_literal(Stage1AstGen *ag, Scope *scope, AstNode *node) { - Error err; - assert(node->type == NodeTypeStringLiteral); - - RootStruct *root_struct = node->owner->data.structure.root_struct; - const char *source = buf_ptr(root_struct->source_code); - - TokenId *token_ids = root_struct->token_ids; - - Buf *str = buf_alloc(); - if (token_ids[node->main_token] == TokenIdStringLiteral) { - size_t byte_offset = root_struct->token_locs[node->main_token].offset; - size_t bad_index; - if ((err = source_string_literal_buf(source + byte_offset, str, &bad_index))) { - add_token_error_offset(ag->codegen, node->owner, node->main_token, - buf_create_from_str("invalid string literal character"), bad_index); - } - src_assert(source[byte_offset] == '"', node); - byte_offset += 1; - } else if (token_ids[node->main_token] == TokenIdMultilineStringLiteralLine) { - TokenIndex tok_index = node->main_token; - bool first = true; - for (;token_ids[tok_index] == TokenIdMultilineStringLiteralLine; tok_index += 1) { - size_t byte_offset = root_struct->token_locs[tok_index].offset; - size_t end = byte_offset; - while (source[end] != 0 && source[end] != '\n') { - end += 1; - } - if (!first) { - buf_append_char(str, '\n'); - } else { - first = false; - } - buf_append_mem(str, source + byte_offset + 2, end - byte_offset - 2); - } - } else { - zig_unreachable(); - } - - return ir_build_const_str_lit(ag, scope, node, str); -} - -static Stage1ZirInst *astgen_array_type(Stage1AstGen *ag, Scope *scope, AstNode *node) { - assert(node->type == NodeTypeArrayType); - - AstNode *size_node = node->data.array_type.size; - AstNode *child_type_node = node->data.array_type.child_type; - bool is_const = node->data.array_type.is_const; - bool is_volatile = node->data.array_type.is_volatile; - bool is_allow_zero = node->data.array_type.allow_zero_token != 0; - AstNode *sentinel_expr = node->data.array_type.sentinel; - AstNode *align_expr = node->data.array_type.align_expr; - - Scope *comptime_scope = create_comptime_scope(ag->codegen, node, scope); - - Stage1ZirInst *sentinel; - if (sentinel_expr != nullptr) { - sentinel = astgen_node(ag, sentinel_expr, comptime_scope); - if (sentinel == ag->codegen->invalid_inst_src) - return sentinel; - } else { - sentinel = nullptr; - } - - if (size_node) { - if (is_const) { - add_node_error(ag->codegen, node, buf_create_from_str("const qualifier invalid on array type")); - return ag->codegen->invalid_inst_src; - } - if (is_volatile) { - add_node_error(ag->codegen, node, buf_create_from_str("volatile qualifier invalid on array type")); - return ag->codegen->invalid_inst_src; - } - if (is_allow_zero) { - add_node_error(ag->codegen, node, buf_create_from_str("allowzero qualifier invalid on array type")); - return ag->codegen->invalid_inst_src; - } - if (align_expr != nullptr) { - add_node_error(ag->codegen, node, buf_create_from_str("align qualifier invalid on array type")); - return ag->codegen->invalid_inst_src; - } - - Stage1ZirInst *size_value = astgen_node(ag, size_node, comptime_scope); - if (size_value == ag->codegen->invalid_inst_src) - return size_value; - - Stage1ZirInst *child_type = astgen_node(ag, child_type_node, comptime_scope); - if (child_type == ag->codegen->invalid_inst_src) - return child_type; - - return ir_build_array_type(ag, scope, node, size_value, sentinel, child_type); - } else { - Stage1ZirInst *align_value; - if (align_expr != nullptr) { - align_value = astgen_node(ag, align_expr, comptime_scope); - if (align_value == ag->codegen->invalid_inst_src) - return align_value; - } else { - align_value = nullptr; - } - - Stage1ZirInst *child_type = astgen_node(ag, child_type_node, comptime_scope); - if (child_type == ag->codegen->invalid_inst_src) - return child_type; - - return ir_build_slice_type(ag, scope, node, child_type, is_const, is_volatile, sentinel, - align_value, is_allow_zero); - } -} - -static Stage1ZirInst *astgen_anyframe_type(Stage1AstGen *ag, Scope *scope, AstNode *node) { - assert(node->type == NodeTypeAnyFrameType); - - AstNode *payload_type_node = node->data.anyframe_type.payload_type; - Stage1ZirInst *payload_type_value = nullptr; - - if (payload_type_node != nullptr) { - payload_type_value = astgen_node(ag, payload_type_node, scope); - if (payload_type_value == ag->codegen->invalid_inst_src) - return payload_type_value; - - } - - return ir_build_anyframe_type(ag, scope, node, payload_type_value); -} - -static Stage1ZirInst *astgen_asm_expr(Stage1AstGen *ag, Scope *scope, AstNode *node) { - assert(node->type == NodeTypeAsmExpr); - AstNodeAsmExpr *asm_expr = &node->data.asm_expr; - - Stage1ZirInst *asm_template = astgen_node(ag, asm_expr->asm_template, scope); - if (asm_template == ag->codegen->invalid_inst_src) - return ag->codegen->invalid_inst_src; - - bool is_volatile = asm_expr->volatile_token != 0; - bool in_fn_scope = (scope_fn_entry(scope) != nullptr); - - if (!in_fn_scope) { - if (is_volatile) { - add_token_error(ag->codegen, node->owner, asm_expr->volatile_token, - buf_sprintf("volatile is meaningless on global assembly")); - return ag->codegen->invalid_inst_src; - } - - if (asm_expr->output_list.length != 0 || asm_expr->input_list.length != 0 || - asm_expr->clobber_list.length != 0) - { - add_node_error(ag->codegen, node, - buf_sprintf("global assembly cannot have inputs, outputs, or clobbers")); - return ag->codegen->invalid_inst_src; - } - - return ir_build_asm_src(ag, scope, node, asm_template, nullptr, nullptr, - nullptr, 0, is_volatile, true); - } - - Stage1ZirInst **input_list = heap::c_allocator.allocate(asm_expr->input_list.length); - Stage1ZirInst **output_types = heap::c_allocator.allocate(asm_expr->output_list.length); - ZigVar **output_vars = heap::c_allocator.allocate(asm_expr->output_list.length); - size_t return_count = 0; - if (!is_volatile && asm_expr->output_list.length == 0) { - add_node_error(ag->codegen, node, - buf_sprintf("assembly expression with no output must be marked volatile")); - return ag->codegen->invalid_inst_src; - } - for (size_t i = 0; i < asm_expr->output_list.length; i += 1) { - AsmOutput *asm_output = asm_expr->output_list.at(i); - if (asm_output->return_type) { - return_count += 1; - - Stage1ZirInst *return_type = astgen_node(ag, asm_output->return_type, scope); - if (return_type == ag->codegen->invalid_inst_src) - return ag->codegen->invalid_inst_src; - if (return_count > 1) { - add_node_error(ag->codegen, node, - buf_sprintf("inline assembly allows up to one output value")); - return ag->codegen->invalid_inst_src; - } - output_types[i] = return_type; - } else { - Buf *variable_name = asm_output->variable_name; - // TODO there is some duplication here with astgen_identifier. I need to do a full audit of how - // inline assembly works. https://github.com/ziglang/zig/issues/215 - ZigVar *var = find_variable(ag->codegen, scope, variable_name, nullptr); - if (var) { - output_vars[i] = var; - } else { - add_node_error(ag->codegen, node, - buf_sprintf("use of undeclared identifier '%s'", buf_ptr(variable_name))); - return ag->codegen->invalid_inst_src; - } - } - - const char modifier = *buf_ptr(asm_output->constraint); - if (modifier != '=') { - add_node_error(ag->codegen, node, - buf_sprintf("invalid modifier starting output constraint for '%s': '%c', only '=' is supported." - " Compiler TODO: see https://github.com/ziglang/zig/issues/215", - buf_ptr(asm_output->asm_symbolic_name), modifier)); - return ag->codegen->invalid_inst_src; - } - } - for (size_t i = 0; i < asm_expr->input_list.length; i += 1) { - AsmInput *asm_input = asm_expr->input_list.at(i); - Stage1ZirInst *input_value = astgen_node(ag, asm_input->expr, scope); - if (input_value == ag->codegen->invalid_inst_src) - return ag->codegen->invalid_inst_src; - - input_list[i] = input_value; - } - - return ir_build_asm_src(ag, scope, node, asm_template, input_list, output_types, - output_vars, return_count, is_volatile, false); -} - -static Stage1ZirInst *astgen_if_optional_expr(Stage1AstGen *ag, Scope *scope, AstNode *node, LVal lval, - ResultLoc *result_loc) -{ - assert(node->type == NodeTypeIfOptional); - - Buf *var_symbol = node->data.test_expr.var_symbol; - AstNode *expr_node = node->data.test_expr.target_node; - AstNode *then_node = node->data.test_expr.then_node; - AstNode *else_node = node->data.test_expr.else_node; - bool var_is_ptr = node->data.test_expr.var_is_ptr; - - ScopeExpr *spill_scope = create_expr_scope(ag->codegen, expr_node, scope); - spill_scope->spill_harder = true; - - Stage1ZirInst *maybe_val_ptr = astgen_node_extra(ag, expr_node, &spill_scope->base, LValPtr, nullptr); - if (maybe_val_ptr == ag->codegen->invalid_inst_src) - return maybe_val_ptr; - - Stage1ZirInst *maybe_val = ir_build_load_ptr(ag, scope, node, maybe_val_ptr); - Stage1ZirInst *is_non_null = ir_build_test_non_null_src(ag, scope, node, maybe_val); - - Stage1ZirBasicBlock *then_block = ir_create_basic_block(ag, scope, "OptionalThen"); - Stage1ZirBasicBlock *else_block = ir_create_basic_block(ag, scope, "OptionalElse"); - Stage1ZirBasicBlock *endif_block = ir_create_basic_block(ag, scope, "OptionalEndIf"); - - Stage1ZirInst *is_comptime; - if (ir_should_inline(ag->exec, scope)) { - is_comptime = ir_build_const_bool(ag, scope, node, true); - } else { - is_comptime = ir_build_test_comptime(ag, scope, node, is_non_null); - } - Stage1ZirInst *cond_br_inst = ir_build_cond_br(ag, scope, node, is_non_null, - then_block, else_block, is_comptime); - - ResultLocPeerParent *peer_parent = ir_build_binary_result_peers(ag, cond_br_inst, else_block, endif_block, - result_loc, is_comptime); - - ir_set_cursor_at_end_and_append_block(ag, then_block); - - Scope *subexpr_scope = create_runtime_scope(ag->codegen, node, &spill_scope->base, is_comptime); - Scope *var_scope; - if (var_symbol) { - bool is_shadowable = false; - bool is_const = true; - ZigVar *var = ir_create_var(ag, node, subexpr_scope, - var_symbol, is_const, is_const, is_shadowable, is_comptime); - - Stage1ZirInst *payload_ptr = ir_build_optional_unwrap_ptr(ag, subexpr_scope, node, maybe_val_ptr, false); - Stage1ZirInst *var_value = var_is_ptr ? - payload_ptr : ir_build_load_ptr(ag, &spill_scope->base, node, payload_ptr); - build_decl_var_and_init(ag, subexpr_scope, node, var, var_value, buf_ptr(var_symbol), is_comptime); - var_scope = var->child_scope; - } else { - var_scope = subexpr_scope; - } - Stage1ZirInst *then_expr_result = astgen_node_extra(ag, then_node, var_scope, lval, - &peer_parent->peers.at(0)->base); - if (then_expr_result == ag->codegen->invalid_inst_src) - return then_expr_result; - Stage1ZirBasicBlock *after_then_block = ag->current_basic_block; - if (!instr_is_unreachable(then_expr_result)) - ir_build_br(ag, scope, node, endif_block, is_comptime); - - ir_set_cursor_at_end_and_append_block(ag, else_block); - Stage1ZirInst *else_expr_result; - if (else_node) { - else_expr_result = astgen_node_extra(ag, else_node, subexpr_scope, lval, &peer_parent->peers.at(1)->base); - if (else_expr_result == ag->codegen->invalid_inst_src) - return else_expr_result; - } else { - else_expr_result = ir_build_const_void(ag, scope, node); - ir_build_end_expr(ag, scope, node, else_expr_result, &peer_parent->peers.at(1)->base); - } - Stage1ZirBasicBlock *after_else_block = ag->current_basic_block; - if (!instr_is_unreachable(else_expr_result)) - ir_build_br(ag, scope, node, endif_block, is_comptime); - - ir_set_cursor_at_end_and_append_block(ag, endif_block); - Stage1ZirInst **incoming_values = heap::c_allocator.allocate(2); - incoming_values[0] = then_expr_result; - incoming_values[1] = else_expr_result; - Stage1ZirBasicBlock **incoming_blocks = heap::c_allocator.allocate(2); - incoming_blocks[0] = after_then_block; - incoming_blocks[1] = after_else_block; - - Stage1ZirInst *phi = ir_build_phi(ag, scope, node, false, 2, incoming_blocks, incoming_values, peer_parent); - return ir_expr_wrap(ag, scope, phi, result_loc); -} - -static Stage1ZirInst *astgen_if_err_expr(Stage1AstGen *ag, Scope *scope, AstNode *node, LVal lval, - ResultLoc *result_loc) -{ - assert(node->type == NodeTypeIfErrorExpr); - - AstNode *target_node = node->data.if_err_expr.target_node; - AstNode *then_node = node->data.if_err_expr.then_node; - AstNode *else_node = node->data.if_err_expr.else_node; - bool var_is_ptr = node->data.if_err_expr.var_is_ptr; - bool var_is_const = true; - Buf *var_symbol = node->data.if_err_expr.var_symbol; - Buf *err_symbol = node->data.if_err_expr.err_symbol; - - Stage1ZirInst *err_val_ptr = astgen_node_extra(ag, target_node, scope, LValPtr, nullptr); - if (err_val_ptr == ag->codegen->invalid_inst_src) - return err_val_ptr; - - Stage1ZirInst *err_val = ir_build_load_ptr(ag, scope, node, err_val_ptr); - Stage1ZirInst *is_err = ir_build_test_err_src(ag, scope, node, err_val_ptr, true, false); - - Stage1ZirBasicBlock *ok_block = ir_create_basic_block(ag, scope, "TryOk"); - Stage1ZirBasicBlock *else_block = ir_create_basic_block(ag, scope, "TryElse"); - Stage1ZirBasicBlock *endif_block = ir_create_basic_block(ag, scope, "TryEnd"); - - bool force_comptime = ir_should_inline(ag->exec, scope); - Stage1ZirInst *is_comptime = force_comptime ? ir_build_const_bool(ag, scope, node, true) : ir_build_test_comptime(ag, scope, node, is_err); - Stage1ZirInst *cond_br_inst = ir_build_cond_br(ag, scope, node, is_err, else_block, ok_block, is_comptime); - - ResultLocPeerParent *peer_parent = ir_build_binary_result_peers(ag, cond_br_inst, else_block, endif_block, - result_loc, is_comptime); - - ir_set_cursor_at_end_and_append_block(ag, ok_block); - - Scope *subexpr_scope = create_runtime_scope(ag->codegen, node, scope, is_comptime); - Scope *var_scope; - if (var_symbol) { - bool is_shadowable = false; - Stage1ZirInst *var_is_comptime = force_comptime ? ir_build_const_bool(ag, subexpr_scope, node, true) : ir_build_test_comptime(ag, subexpr_scope, node, err_val); - ZigVar *var = ir_create_var(ag, node, subexpr_scope, - var_symbol, var_is_const, var_is_const, is_shadowable, var_is_comptime); - - Stage1ZirInst *payload_ptr = ir_build_unwrap_err_payload_src(ag, subexpr_scope, node, err_val_ptr, false, false); - Stage1ZirInst *var_value = var_is_ptr ? - payload_ptr : ir_build_load_ptr(ag, subexpr_scope, node, payload_ptr); - build_decl_var_and_init(ag, subexpr_scope, node, var, var_value, buf_ptr(var_symbol), var_is_comptime); - var_scope = var->child_scope; - } else { - var_scope = subexpr_scope; - } - Stage1ZirInst *then_expr_result = astgen_node_extra(ag, then_node, var_scope, lval, - &peer_parent->peers.at(0)->base); - if (then_expr_result == ag->codegen->invalid_inst_src) - return then_expr_result; - Stage1ZirBasicBlock *after_then_block = ag->current_basic_block; - if (!instr_is_unreachable(then_expr_result)) - ir_build_br(ag, scope, node, endif_block, is_comptime); - - ir_set_cursor_at_end_and_append_block(ag, else_block); - - Stage1ZirInst *else_expr_result; - if (else_node) { - Scope *err_var_scope; - if (err_symbol) { - bool is_shadowable = false; - bool is_const = true; - ZigVar *var = ir_create_var(ag, node, subexpr_scope, - err_symbol, is_const, is_const, is_shadowable, is_comptime); - - Stage1ZirInst *err_ptr = ir_build_unwrap_err_code_src(ag, subexpr_scope, node, err_val_ptr); - Stage1ZirInst *err_value = ir_build_load_ptr(ag, subexpr_scope, node, err_ptr); - build_decl_var_and_init(ag, subexpr_scope, node, var, err_value, buf_ptr(err_symbol), is_comptime); - err_var_scope = var->child_scope; - } else { - err_var_scope = subexpr_scope; - } - else_expr_result = astgen_node_extra(ag, else_node, err_var_scope, lval, &peer_parent->peers.at(1)->base); - if (else_expr_result == ag->codegen->invalid_inst_src) - return else_expr_result; - } else { - else_expr_result = ir_build_const_void(ag, scope, node); - ir_build_end_expr(ag, scope, node, else_expr_result, &peer_parent->peers.at(1)->base); - } - Stage1ZirBasicBlock *after_else_block = ag->current_basic_block; - if (!instr_is_unreachable(else_expr_result)) - ir_build_br(ag, scope, node, endif_block, is_comptime); - - ir_set_cursor_at_end_and_append_block(ag, endif_block); - Stage1ZirInst **incoming_values = heap::c_allocator.allocate(2); - incoming_values[0] = then_expr_result; - incoming_values[1] = else_expr_result; - Stage1ZirBasicBlock **incoming_blocks = heap::c_allocator.allocate(2); - incoming_blocks[0] = after_then_block; - incoming_blocks[1] = after_else_block; - - Stage1ZirInst *phi = ir_build_phi(ag, scope, node, false, 2, incoming_blocks, incoming_values, peer_parent); - return ir_expr_wrap(ag, scope, phi, result_loc); -} - -static bool astgen_switch_prong_expr(Stage1AstGen *ag, Scope *scope, AstNode *switch_node, AstNode *prong_node, - Stage1ZirBasicBlock *end_block, Stage1ZirInst *is_comptime, Stage1ZirInst *var_is_comptime, - Stage1ZirInst *target_value_ptr, Stage1ZirInst **prong_values, size_t prong_values_len, - ZigList *incoming_blocks, ZigList *incoming_values, - Stage1ZirInstSwitchElseVar **out_switch_else_var, LVal lval, ResultLoc *result_loc) -{ - assert(switch_node->type == NodeTypeSwitchExpr); - assert(prong_node->type == NodeTypeSwitchProng); - - if (prong_node->data.switch_prong.is_inline) { - exec_add_error_node(ag->codegen, ag->exec, prong_node, - buf_sprintf("inline switch cases not supported by stage1")); - return ag->codegen->invalid_inst_src; - } - - AstNode *expr_node = prong_node->data.switch_prong.expr; - AstNode *var_symbol_node = prong_node->data.switch_prong.var_symbol; - Scope *child_scope; - if (var_symbol_node) { - assert(var_symbol_node->type == NodeTypeIdentifier); - Buf *var_name = node_identifier_buf(var_symbol_node); - bool var_is_ptr = prong_node->data.switch_prong.var_is_ptr; - - bool is_shadowable = false; - bool is_const = true; - ZigVar *var = ir_create_var(ag, var_symbol_node, scope, - var_name, is_const, is_const, is_shadowable, var_is_comptime); - child_scope = var->child_scope; - Stage1ZirInst *var_value; - if (out_switch_else_var != nullptr) { - Stage1ZirInstSwitchElseVar *switch_else_var = ir_build_switch_else_var(ag, scope, var_symbol_node, - target_value_ptr); - *out_switch_else_var = switch_else_var; - Stage1ZirInst *payload_ptr = &switch_else_var->base; - var_value = var_is_ptr ? - payload_ptr : ir_build_load_ptr(ag, scope, var_symbol_node, payload_ptr); - } else if (prong_values != nullptr) { - Stage1ZirInst *payload_ptr = ir_build_switch_var(ag, scope, var_symbol_node, target_value_ptr, - prong_values, prong_values_len); - var_value = var_is_ptr ? - payload_ptr : ir_build_load_ptr(ag, scope, var_symbol_node, payload_ptr); - } else { - var_value = var_is_ptr ? - target_value_ptr : ir_build_load_ptr(ag, scope, var_symbol_node, target_value_ptr); - } - build_decl_var_and_init(ag, scope, var_symbol_node, var, var_value, buf_ptr(var_name), var_is_comptime); - } else { - child_scope = scope; - } - - Stage1ZirInst *expr_result = astgen_node_extra(ag, expr_node, child_scope, lval, result_loc); - if (expr_result == ag->codegen->invalid_inst_src) - return false; - if (!instr_is_unreachable(expr_result)) - ir_build_br(ag, scope, switch_node, end_block, is_comptime); - incoming_blocks->append(ag->current_basic_block); - incoming_values->append(expr_result); - return true; -} - -static Stage1ZirInst *astgen_switch_expr(Stage1AstGen *ag, Scope *scope, AstNode *node, LVal lval, - ResultLoc *result_loc) -{ - assert(node->type == NodeTypeSwitchExpr); - - AstNode *target_node = node->data.switch_expr.expr; - Stage1ZirInst *target_value_ptr = astgen_node_extra(ag, target_node, scope, LValPtr, nullptr); - if (target_value_ptr == ag->codegen->invalid_inst_src) - return target_value_ptr; - Stage1ZirInst *target_value = ir_build_switch_target(ag, scope, node, target_value_ptr); - - Stage1ZirBasicBlock *else_block = ir_create_basic_block(ag, scope, "SwitchElse"); - Stage1ZirBasicBlock *end_block = ir_create_basic_block(ag, scope, "SwitchEnd"); - - size_t prong_count = node->data.switch_expr.prongs.length; - ZigList cases = {0}; - - Stage1ZirInst *is_comptime; - Stage1ZirInst *var_is_comptime; - if (ir_should_inline(ag->exec, scope)) { - is_comptime = ir_build_const_bool(ag, scope, node, true); - var_is_comptime = is_comptime; - } else { - is_comptime = ir_build_test_comptime(ag, scope, node, target_value); - var_is_comptime = ir_build_test_comptime(ag, scope, node, target_value_ptr); - } - - ZigList incoming_values = {0}; - ZigList incoming_blocks = {0}; - ZigList check_ranges = {0}; - - Stage1ZirInstSwitchElseVar *switch_else_var = nullptr; - - ResultLocPeerParent *peer_parent = heap::c_allocator.create(); - peer_parent->base.id = ResultLocIdPeerParent; - peer_parent->base.allow_write_through_const = result_loc->allow_write_through_const; - peer_parent->end_bb = end_block; - peer_parent->is_comptime = is_comptime; - peer_parent->parent = result_loc; - - ir_build_reset_result(ag, scope, node, &peer_parent->base); - - // First do the else and the ranges - Scope *subexpr_scope = create_runtime_scope(ag->codegen, node, scope, is_comptime); - Scope *comptime_scope = create_comptime_scope(ag->codegen, node, scope); - AstNode *else_prong = nullptr; - AstNode *underscore_prong = nullptr; - for (size_t prong_i = 0; prong_i < prong_count; prong_i += 1) { - AstNode *prong_node = node->data.switch_expr.prongs.at(prong_i); - size_t prong_item_count = prong_node->data.switch_prong.items.length; - if (prong_node->data.switch_prong.any_items_are_range) { - ResultLocPeer *this_peer_result_loc = create_peer_result(peer_parent); - - Stage1ZirInst *ok_bit = nullptr; - AstNode *last_item_node = nullptr; - for (size_t item_i = 0; item_i < prong_item_count; item_i += 1) { - AstNode *item_node = prong_node->data.switch_prong.items.at(item_i); - last_item_node = item_node; - if (item_node->type == NodeTypeSwitchRange) { - AstNode *start_node = item_node->data.switch_range.start; - AstNode *end_node = item_node->data.switch_range.end; - - Stage1ZirInst *start_value = astgen_node(ag, start_node, comptime_scope); - if (start_value == ag->codegen->invalid_inst_src) - return ag->codegen->invalid_inst_src; - - Stage1ZirInst *end_value = astgen_node(ag, end_node, comptime_scope); - if (end_value == ag->codegen->invalid_inst_src) - return ag->codegen->invalid_inst_src; - - Stage1ZirInstCheckSwitchProngsRange *check_range = check_ranges.add_one(); - check_range->start = start_value; - check_range->end = end_value; - - Stage1ZirInst *lower_range_ok = ir_build_bin_op(ag, scope, item_node, IrBinOpCmpGreaterOrEq, - target_value, start_value, false); - Stage1ZirInst *upper_range_ok = ir_build_bin_op(ag, scope, item_node, IrBinOpCmpLessOrEq, - target_value, end_value, false); - Stage1ZirInst *both_ok = ir_build_bin_op(ag, scope, item_node, IrBinOpBoolAnd, - lower_range_ok, upper_range_ok, false); - if (ok_bit) { - ok_bit = ir_build_bin_op(ag, scope, item_node, IrBinOpBoolOr, both_ok, ok_bit, false); - } else { - ok_bit = both_ok; - } - } else { - Stage1ZirInst *item_value = astgen_node(ag, item_node, comptime_scope); - if (item_value == ag->codegen->invalid_inst_src) - return ag->codegen->invalid_inst_src; - - Stage1ZirInstCheckSwitchProngsRange *check_range = check_ranges.add_one(); - check_range->start = item_value; - check_range->end = item_value; - - Stage1ZirInst *cmp_ok = ir_build_bin_op(ag, scope, item_node, IrBinOpCmpEq, - item_value, target_value, false); - if (ok_bit) { - ok_bit = ir_build_bin_op(ag, scope, item_node, IrBinOpBoolOr, cmp_ok, ok_bit, false); - } else { - ok_bit = cmp_ok; - } - } - } - - Stage1ZirBasicBlock *range_block_yes = ir_create_basic_block(ag, scope, "SwitchRangeYes"); - Stage1ZirBasicBlock *range_block_no = ir_create_basic_block(ag, scope, "SwitchRangeNo"); - - assert(ok_bit); - assert(last_item_node); - Stage1ZirInst *br_inst = ir_build_cond_br(ag, scope, last_item_node, ok_bit, - range_block_yes, range_block_no, is_comptime); - if (peer_parent->base.source_instruction == nullptr) { - peer_parent->base.source_instruction = br_inst; - } - - if (peer_parent->peers.length > 0) { - peer_parent->peers.last()->next_bb = range_block_yes; - } - peer_parent->peers.append(this_peer_result_loc); - ir_set_cursor_at_end_and_append_block(ag, range_block_yes); - if (!astgen_switch_prong_expr(ag, subexpr_scope, node, prong_node, end_block, - is_comptime, var_is_comptime, target_value_ptr, nullptr, 0, - &incoming_blocks, &incoming_values, nullptr, LValNone, &this_peer_result_loc->base)) - { - return ag->codegen->invalid_inst_src; - } - - ir_set_cursor_at_end_and_append_block(ag, range_block_no); - } else { - if (prong_item_count == 0) { - if (else_prong) { - ErrorMsg *msg = add_node_error(ag->codegen, prong_node, - buf_sprintf("multiple else prongs in switch expression")); - add_error_note(ag->codegen, msg, else_prong, - buf_sprintf("previous else prong here")); - return ag->codegen->invalid_inst_src; - } - else_prong = prong_node; - } else if (prong_item_count == 1 && - prong_node->data.switch_prong.items.at(0)->type == NodeTypeIdentifier && - buf_eql_str(node_identifier_buf(prong_node->data.switch_prong.items.at(0)), "_")) { - if (underscore_prong) { - ErrorMsg *msg = add_node_error(ag->codegen, prong_node, - buf_sprintf("multiple '_' prongs in switch expression")); - add_error_note(ag->codegen, msg, underscore_prong, - buf_sprintf("previous '_' prong here")); - return ag->codegen->invalid_inst_src; - } - underscore_prong = prong_node; - } else { - continue; - } - if (underscore_prong && else_prong) { - ErrorMsg *msg = add_node_error(ag->codegen, prong_node, - buf_sprintf("else and '_' prong in switch expression")); - if (underscore_prong == prong_node) - add_error_note(ag->codegen, msg, else_prong, - buf_sprintf("else prong here")); - else - add_error_note(ag->codegen, msg, underscore_prong, - buf_sprintf("'_' prong here")); - return ag->codegen->invalid_inst_src; - } - ResultLocPeer *this_peer_result_loc = create_peer_result(peer_parent); - - Stage1ZirBasicBlock *prev_block = ag->current_basic_block; - if (peer_parent->peers.length > 0) { - peer_parent->peers.last()->next_bb = else_block; - } - peer_parent->peers.append(this_peer_result_loc); - ir_set_cursor_at_end_and_append_block(ag, else_block); - if (!astgen_switch_prong_expr(ag, subexpr_scope, node, prong_node, end_block, - is_comptime, var_is_comptime, target_value_ptr, nullptr, 0, &incoming_blocks, &incoming_values, - &switch_else_var, LValNone, &this_peer_result_loc->base)) - { - return ag->codegen->invalid_inst_src; - } - ir_set_cursor_at_end(ag, prev_block); - } - } - - // next do the non-else non-ranges - for (size_t prong_i = 0; prong_i < prong_count; prong_i += 1) { - AstNode *prong_node = node->data.switch_expr.prongs.at(prong_i); - size_t prong_item_count = prong_node->data.switch_prong.items.length; - if (prong_item_count == 0) - continue; - if (prong_node->data.switch_prong.any_items_are_range) - continue; - if (underscore_prong == prong_node) - continue; - - ResultLocPeer *this_peer_result_loc = create_peer_result(peer_parent); - - Stage1ZirBasicBlock *prong_block = ir_create_basic_block(ag, scope, "SwitchProng"); - Stage1ZirInst **items = heap::c_allocator.allocate(prong_item_count); - - for (size_t item_i = 0; item_i < prong_item_count; item_i += 1) { - AstNode *item_node = prong_node->data.switch_prong.items.at(item_i); - assert(item_node->type != NodeTypeSwitchRange); - - Stage1ZirInst *item_value = astgen_node(ag, item_node, comptime_scope); - if (item_value == ag->codegen->invalid_inst_src) - return ag->codegen->invalid_inst_src; - - Stage1ZirInstCheckSwitchProngsRange *check_range = check_ranges.add_one(); - check_range->start = item_value; - check_range->end = item_value; - - Stage1ZirInstSwitchBrCase *this_case = cases.add_one(); - this_case->value = item_value; - this_case->block = prong_block; - - items[item_i] = item_value; - } - - Stage1ZirBasicBlock *prev_block = ag->current_basic_block; - if (peer_parent->peers.length > 0) { - peer_parent->peers.last()->next_bb = prong_block; - } - peer_parent->peers.append(this_peer_result_loc); - ir_set_cursor_at_end_and_append_block(ag, prong_block); - if (!astgen_switch_prong_expr(ag, subexpr_scope, node, prong_node, end_block, - is_comptime, var_is_comptime, target_value_ptr, items, prong_item_count, - &incoming_blocks, &incoming_values, nullptr, LValNone, &this_peer_result_loc->base)) - { - return ag->codegen->invalid_inst_src; - } - - ir_set_cursor_at_end(ag, prev_block); - - } - - Stage1ZirInst *switch_prongs_void = ir_build_check_switch_prongs(ag, scope, node, target_value, - check_ranges.items, check_ranges.length, else_prong, underscore_prong != nullptr); - - Stage1ZirInst *br_instruction; - if (cases.length == 0) { - br_instruction = ir_build_br(ag, scope, node, else_block, is_comptime); - } else { - Stage1ZirInstSwitchBr *switch_br = ir_build_switch_br_src(ag, scope, node, target_value, else_block, - cases.length, cases.items, is_comptime, switch_prongs_void); - if (switch_else_var != nullptr) { - switch_else_var->switch_br = switch_br; - } - br_instruction = &switch_br->base; - } - if (peer_parent->base.source_instruction == nullptr) { - peer_parent->base.source_instruction = br_instruction; - } - for (size_t i = 0; i < peer_parent->peers.length; i += 1) { - peer_parent->peers.at(i)->base.source_instruction = peer_parent->base.source_instruction; - } - - if (!else_prong && !underscore_prong) { - if (peer_parent->peers.length != 0) { - peer_parent->peers.last()->next_bb = else_block; - } - ir_set_cursor_at_end_and_append_block(ag, else_block); - ir_build_unreachable(ag, scope, node); - } else { - if (peer_parent->peers.length != 0) { - peer_parent->peers.last()->next_bb = end_block; - } - } - - ir_set_cursor_at_end_and_append_block(ag, end_block); - assert(incoming_blocks.length == incoming_values.length); - Stage1ZirInst *result_instruction; - if (incoming_blocks.length == 0) { - result_instruction = ir_build_const_void(ag, scope, node); - } else { - result_instruction = ir_build_phi(ag, scope, node, false, incoming_blocks.length, - incoming_blocks.items, incoming_values.items, peer_parent); - } - return ir_lval_wrap(ag, scope, result_instruction, lval, result_loc); -} - -static Stage1ZirInst *astgen_comptime(Stage1AstGen *ag, Scope *parent_scope, AstNode *node, LVal lval) { - assert(node->type == NodeTypeCompTime); - - Scope *child_scope = create_comptime_scope(ag->codegen, node, parent_scope); - // purposefully pass null for result_loc and let EndExpr handle it - return astgen_node_extra(ag, node->data.comptime_expr.expr, child_scope, lval, nullptr); -} - -static Stage1ZirInst *astgen_nosuspend(Stage1AstGen *ag, Scope *parent_scope, AstNode *node, LVal lval) { - assert(node->type == NodeTypeNoSuspend); - - Scope *child_scope = create_nosuspend_scope(ag->codegen, node, parent_scope); - // purposefully pass null for result_loc and let EndExpr handle it - return astgen_node_extra(ag, node->data.nosuspend_expr.expr, child_scope, lval, nullptr); -} - -static Stage1ZirInst *astgen_return_from_block(Stage1AstGen *ag, Scope *break_scope, AstNode *node, ScopeBlock *block_scope) { - Stage1ZirInst *is_comptime; - if (ir_should_inline(ag->exec, break_scope)) { - is_comptime = ir_build_const_bool(ag, break_scope, node, true); - } else { - is_comptime = block_scope->is_comptime; - } - - Stage1ZirInst *result_value; - if (node->data.break_expr.expr) { - ResultLocPeer *peer_result = create_peer_result(block_scope->peer_parent); - block_scope->peer_parent->peers.append(peer_result); - - result_value = astgen_node_extra(ag, node->data.break_expr.expr, break_scope, block_scope->lval, - &peer_result->base); - if (result_value == ag->codegen->invalid_inst_src) - return ag->codegen->invalid_inst_src; - } else { - result_value = ir_build_const_void(ag, break_scope, node); - } - - Stage1ZirBasicBlock *dest_block = block_scope->end_block; - if (!astgen_defers_for_block(ag, break_scope, dest_block->scope, nullptr, nullptr)) - return ag->codegen->invalid_inst_src; - - block_scope->incoming_blocks->append(ag->current_basic_block); - block_scope->incoming_values->append(result_value); - return ir_build_br(ag, break_scope, node, dest_block, is_comptime); -} - -static Stage1ZirInst *astgen_break(Stage1AstGen *ag, Scope *break_scope, AstNode *node) { - assert(node->type == NodeTypeBreak); - - // Search up the scope. We'll find one of these things first: - // * function definition scope or global scope => error, break outside loop - // * defer expression scope => error, cannot break out of defer expression - // * loop scope => OK - // * (if it's a labeled break) labeled block => OK - - Scope *search_scope = break_scope; - ScopeLoop *loop_scope; - for (;;) { - if (search_scope == nullptr || search_scope->id == ScopeIdFnDef) { - if (node->data.break_expr.name != nullptr) { - add_node_error(ag->codegen, node, buf_sprintf("label not found: '%s'", buf_ptr(node->data.break_expr.name))); - return ag->codegen->invalid_inst_src; - } else { - add_node_error(ag->codegen, node, buf_sprintf("break expression outside loop")); - return ag->codegen->invalid_inst_src; - } - } else if (search_scope->id == ScopeIdDeferExpr) { - add_node_error(ag->codegen, node, buf_sprintf("cannot break out of defer expression")); - return ag->codegen->invalid_inst_src; - } else if (search_scope->id == ScopeIdLoop) { - ScopeLoop *this_loop_scope = (ScopeLoop *)search_scope; - if (node->data.break_expr.name == nullptr || - (this_loop_scope->name != nullptr && buf_eql_buf(node->data.break_expr.name, this_loop_scope->name))) - { - this_loop_scope->name_used = true; - loop_scope = this_loop_scope; - break; - } - } else if (search_scope->id == ScopeIdBlock) { - ScopeBlock *this_block_scope = (ScopeBlock *)search_scope; - if (node->data.break_expr.name != nullptr && - (this_block_scope->name != nullptr && buf_eql_buf(node->data.break_expr.name, this_block_scope->name))) - { - assert(this_block_scope->end_block != nullptr); - this_block_scope->name_used = true; - return astgen_return_from_block(ag, break_scope, node, this_block_scope); - } - } else if (search_scope->id == ScopeIdSuspend) { - add_node_error(ag->codegen, node, buf_sprintf("cannot break out of suspend block")); - return ag->codegen->invalid_inst_src; - } - search_scope = search_scope->parent; - } - - Stage1ZirInst *is_comptime; - if (ir_should_inline(ag->exec, break_scope)) { - is_comptime = ir_build_const_bool(ag, break_scope, node, true); - } else { - is_comptime = loop_scope->is_comptime; - } - - Stage1ZirInst *result_value; - if (node->data.break_expr.expr) { - ResultLocPeer *peer_result = create_peer_result(loop_scope->peer_parent); - loop_scope->peer_parent->peers.append(peer_result); - - result_value = astgen_node_extra(ag, node->data.break_expr.expr, break_scope, - loop_scope->lval, &peer_result->base); - if (result_value == ag->codegen->invalid_inst_src) - return ag->codegen->invalid_inst_src; - } else { - result_value = ir_build_const_void(ag, break_scope, node); - } - - Stage1ZirBasicBlock *dest_block = loop_scope->break_block; - if (!astgen_defers_for_block(ag, break_scope, dest_block->scope, nullptr, nullptr)) - return ag->codegen->invalid_inst_src; - - loop_scope->incoming_blocks->append(ag->current_basic_block); - loop_scope->incoming_values->append(result_value); - return ir_build_br(ag, break_scope, node, dest_block, is_comptime); -} - -static Stage1ZirInst *astgen_continue(Stage1AstGen *ag, Scope *continue_scope, AstNode *node) { - assert(node->type == NodeTypeContinue); - - // Search up the scope. We'll find one of these things first: - // * function definition scope or global scope => error, break outside loop - // * defer expression scope => error, cannot break out of defer expression - // * loop scope => OK - - ZigList runtime_scopes = {}; - - Scope *search_scope = continue_scope; - ScopeLoop *loop_scope; - for (;;) { - if (search_scope == nullptr || search_scope->id == ScopeIdFnDef) { - if (node->data.continue_expr.name != nullptr) { - add_node_error(ag->codegen, node, buf_sprintf("labeled loop not found: '%s'", buf_ptr(node->data.continue_expr.name))); - return ag->codegen->invalid_inst_src; - } else { - add_node_error(ag->codegen, node, buf_sprintf("continue expression outside loop")); - return ag->codegen->invalid_inst_src; - } - } else if (search_scope->id == ScopeIdDeferExpr) { - add_node_error(ag->codegen, node, buf_sprintf("cannot continue out of defer expression")); - return ag->codegen->invalid_inst_src; - } else if (search_scope->id == ScopeIdLoop) { - ScopeLoop *this_loop_scope = (ScopeLoop *)search_scope; - if (node->data.continue_expr.name == nullptr || - (this_loop_scope->name != nullptr && buf_eql_buf(node->data.continue_expr.name, this_loop_scope->name))) - { - this_loop_scope->name_used = true; - loop_scope = this_loop_scope; - break; - } - } else if (search_scope->id == ScopeIdRuntime) { - ScopeRuntime *scope_runtime = (ScopeRuntime *)search_scope; - runtime_scopes.append(scope_runtime); - } - search_scope = search_scope->parent; - } - - Stage1ZirInst *is_comptime; - if (ir_should_inline(ag->exec, continue_scope)) { - is_comptime = ir_build_const_bool(ag, continue_scope, node, true); - } else { - is_comptime = loop_scope->is_comptime; - } - - for (size_t i = 0; i < runtime_scopes.length; i += 1) { - ScopeRuntime *scope_runtime = runtime_scopes.at(i); - ir_build_check_runtime_scope(ag, continue_scope, node, scope_runtime->is_comptime, is_comptime); - } - runtime_scopes.deinit(); - - Stage1ZirBasicBlock *dest_block = loop_scope->continue_block; - if (!astgen_defers_for_block(ag, continue_scope, dest_block->scope, nullptr, nullptr)) - return ag->codegen->invalid_inst_src; - return ir_build_br(ag, continue_scope, node, dest_block, is_comptime); -} - -static Stage1ZirInst *astgen_error_type(Stage1AstGen *ag, Scope *scope, AstNode *node) { - assert(node->type == NodeTypeErrorType); - return ir_build_const_type(ag, scope, node, ag->codegen->builtin_types.entry_global_error_set); -} - -static Stage1ZirInst *astgen_defer(Stage1AstGen *ag, Scope *parent_scope, AstNode *node) { - assert(node->type == NodeTypeDefer); - - ScopeDefer *defer_child_scope = create_defer_scope(ag->codegen, node, parent_scope); - node->data.defer.child_scope = &defer_child_scope->base; - - ScopeDeferExpr *defer_expr_scope = create_defer_expr_scope(ag->codegen, node, parent_scope); - node->data.defer.expr_scope = &defer_expr_scope->base; - - return ir_build_const_void(ag, parent_scope, node); -} - -static Stage1ZirInst *astgen_slice(Stage1AstGen *ag, Scope *scope, AstNode *node, LVal lval, ResultLoc *result_loc) { - assert(node->type == NodeTypeSliceExpr); - - AstNodeSliceExpr *slice_expr = &node->data.slice_expr; - AstNode *array_node = slice_expr->array_ref_expr; - AstNode *start_node = slice_expr->start; - AstNode *end_node = slice_expr->end; - AstNode *sentinel_node = slice_expr->sentinel; - - Stage1ZirInst *ptr_value = astgen_node_extra(ag, array_node, scope, LValPtr, nullptr); - if (ptr_value == ag->codegen->invalid_inst_src) - return ag->codegen->invalid_inst_src; - - Stage1ZirInst *start_value = astgen_node(ag, start_node, scope); - if (start_value == ag->codegen->invalid_inst_src) - return ag->codegen->invalid_inst_src; - - Stage1ZirInst *end_value; - if (end_node) { - end_value = astgen_node(ag, end_node, scope); - if (end_value == ag->codegen->invalid_inst_src) - return ag->codegen->invalid_inst_src; - } else { - end_value = nullptr; - } - - Stage1ZirInst *sentinel_value; - if (sentinel_node) { - sentinel_value = astgen_node(ag, sentinel_node, scope); - if (sentinel_value == ag->codegen->invalid_inst_src) - return ag->codegen->invalid_inst_src; - } else { - sentinel_value = nullptr; - } - - Stage1ZirInst *slice = ir_build_slice_src(ag, scope, node, ptr_value, start_value, end_value, - sentinel_value, true, result_loc); - return ir_lval_wrap(ag, scope, slice, lval, result_loc); -} - -static Stage1ZirInst *astgen_catch(Stage1AstGen *ag, Scope *parent_scope, AstNode *node, LVal lval, - ResultLoc *result_loc) -{ - assert(node->type == NodeTypeCatchExpr); - - AstNode *op1_node = node->data.unwrap_err_expr.op1; - AstNode *op2_node = node->data.unwrap_err_expr.op2; - AstNode *var_node = node->data.unwrap_err_expr.symbol; - - if (op2_node->type == NodeTypeUnreachable) { - if (var_node != nullptr) { - assert(var_node->type == NodeTypeIdentifier); - Buf *var_name = node_identifier_buf(var_node); - add_node_error(ag->codegen, var_node, buf_sprintf("unused variable: '%s'", buf_ptr(var_name))); - return ag->codegen->invalid_inst_src; - } - return astgen_catch_unreachable(ag, parent_scope, node, op1_node, lval, result_loc); - } - - - ScopeExpr *spill_scope = create_expr_scope(ag->codegen, op1_node, parent_scope); - spill_scope->spill_harder = true; - - Stage1ZirInst *err_union_ptr = astgen_node_extra(ag, op1_node, &spill_scope->base, LValPtr, nullptr); - if (err_union_ptr == ag->codegen->invalid_inst_src) - return ag->codegen->invalid_inst_src; - - Stage1ZirInst *is_err = ir_build_test_err_src(ag, parent_scope, node, err_union_ptr, true, false); - - Stage1ZirInst *is_comptime; - if (ir_should_inline(ag->exec, parent_scope)) { - is_comptime = ir_build_const_bool(ag, parent_scope, node, true); - } else { - is_comptime = ir_build_test_comptime(ag, parent_scope, node, is_err); - } - - Stage1ZirBasicBlock *ok_block = ir_create_basic_block(ag, parent_scope, "UnwrapErrOk"); - Stage1ZirBasicBlock *err_block = ir_create_basic_block(ag, parent_scope, "UnwrapErrError"); - Stage1ZirBasicBlock *end_block = ir_create_basic_block(ag, parent_scope, "UnwrapErrEnd"); - Stage1ZirInst *cond_br_inst = ir_build_cond_br(ag, parent_scope, node, is_err, err_block, ok_block, is_comptime); - - ResultLocPeerParent *peer_parent = ir_build_binary_result_peers(ag, cond_br_inst, ok_block, end_block, result_loc, - is_comptime); - - ir_set_cursor_at_end_and_append_block(ag, err_block); - Scope *subexpr_scope = create_runtime_scope(ag->codegen, node, &spill_scope->base, is_comptime); - Scope *err_scope; - if (var_node) { - assert(var_node->type == NodeTypeIdentifier); - Buf *var_name = node_identifier_buf(var_node); - bool is_const = true; - bool is_shadowable = false; - ZigVar *var = ir_create_var(ag, node, subexpr_scope, var_name, - is_const, is_const, is_shadowable, is_comptime); - err_scope = var->child_scope; - Stage1ZirInst *err_ptr = ir_build_unwrap_err_code_src(ag, err_scope, node, err_union_ptr); - Stage1ZirInst *err_value = ir_build_load_ptr(ag, err_scope, var_node, err_ptr); - build_decl_var_and_init(ag, err_scope, var_node, var, err_value, buf_ptr(var_name), is_comptime); - } else { - err_scope = subexpr_scope; - } - Stage1ZirInst *err_result = astgen_node_extra(ag, op2_node, err_scope, LValNone, &peer_parent->peers.at(0)->base); - if (err_result == ag->codegen->invalid_inst_src) - return ag->codegen->invalid_inst_src; - Stage1ZirBasicBlock *after_err_block = ag->current_basic_block; - if (!instr_is_unreachable(err_result)) - ir_build_br(ag, parent_scope, node, end_block, is_comptime); - - ir_set_cursor_at_end_and_append_block(ag, ok_block); - Stage1ZirInst *unwrapped_ptr = ir_build_unwrap_err_payload_src(ag, parent_scope, node, err_union_ptr, false, false); - Stage1ZirInst *unwrapped_payload = ir_build_load_ptr(ag, parent_scope, node, unwrapped_ptr); - ir_build_end_expr(ag, parent_scope, node, unwrapped_payload, &peer_parent->peers.at(1)->base); - Stage1ZirBasicBlock *after_ok_block = ag->current_basic_block; - ir_build_br(ag, parent_scope, node, end_block, is_comptime); - - ir_set_cursor_at_end_and_append_block(ag, end_block); - Stage1ZirInst **incoming_values = heap::c_allocator.allocate(2); - incoming_values[0] = err_result; - incoming_values[1] = unwrapped_payload; - Stage1ZirBasicBlock **incoming_blocks = heap::c_allocator.allocate(2); - incoming_blocks[0] = after_err_block; - incoming_blocks[1] = after_ok_block; - Stage1ZirInst *phi = ir_build_phi(ag, parent_scope, node, false, 2, incoming_blocks, incoming_values, peer_parent); - return ir_lval_wrap(ag, parent_scope, phi, lval, result_loc); -} - -static bool render_instance_name_recursive(CodeGen *codegen, Buf *name, Scope *outer_scope, Scope *inner_scope) { - if (inner_scope == nullptr || inner_scope == outer_scope) return false; - bool need_comma = render_instance_name_recursive(codegen, name, outer_scope, inner_scope->parent); - if (inner_scope->id != ScopeIdVarDecl) - return need_comma; - - ScopeVarDecl *var_scope = (ScopeVarDecl *)inner_scope; - if (need_comma) - buf_append_char(name, ','); - // TODO: const ptr reinterpret here to make the var type agree with the value? - render_const_value(codegen, name, var_scope->var->const_value); - return true; -} - -Buf *get_anon_type_name(CodeGen *codegen, Stage1Zir *exec, const char *kind_name, - Scope *scope, AstNode *source_node, Buf *out_bare_name, ResultLoc *result_loc) -{ - // See https://ziglang.org/documentation/master/#Struct-Naming . - bool force_generic = false; - if (result_loc != nullptr - && result_loc->source_instruction != nullptr - && result_loc->source_instruction->source_node != nullptr - ) { - switch (result_loc->source_instruction->source_node->type) { - case NodeTypeVariableDeclaration: { - ZigType *import = get_scope_import(scope); - Buf *name = buf_alloc(); - append_namespace_qualification(codegen, name, import); - const auto &basename = result_loc->source_instruction->source_node->data.variable_declaration.symbol; - buf_append_buf(name, basename); - buf_init_from_buf(out_bare_name, basename); - return name; - } - case NodeTypeFnCallExpr: - case NodeTypeStructValueField: - force_generic = true; - break; - default: - break; - } - } - - if (!force_generic) { - if (exec != nullptr && exec->name != nullptr) { - buf_resize(out_bare_name, 0); - if (scope->id == ScopeIdDecls) { - ScopeDecls *decls_scope = reinterpret_cast(scope); - append_namespace_qualification(codegen, out_bare_name, decls_scope->container_type); - } - buf_append_buf(out_bare_name, exec->name); - Buf *namespace_name = buf_alloc(); - buf_append_buf(namespace_name, out_bare_name); - return namespace_name; - } - if (exec != nullptr && exec->name_fn != nullptr) { - Buf *name = buf_alloc(); - buf_append_buf(name, &exec->name_fn->symbol_name); - buf_appendf(name, "("); - render_instance_name_recursive(codegen, name, &exec->name_fn->fndef_scope->base, exec->begin_scope); - buf_appendf(name, ")"); - buf_init_from_buf(out_bare_name, name); - return name; - } - } - - ZigType *import = get_scope_import(scope); - Buf *namespace_name = buf_alloc(); - append_namespace_qualification(codegen, namespace_name, import); - RootStruct *root_struct = source_node->owner->data.structure.root_struct; - TokenLoc tok_loc = root_struct->token_locs[source_node->main_token]; - buf_appendf(namespace_name, "%s:%u:%u", kind_name, - tok_loc.line + 1, tok_loc.column + 1); - buf_init_from_buf(out_bare_name, namespace_name); - return namespace_name; -} - -static Stage1ZirInst *astgen_container_decl(Stage1AstGen *ag, Scope *parent_scope, - AstNode *node, ResultLoc *result_loc) -{ - assert(node->type == NodeTypeContainerDecl); - - ContainerKind kind = node->data.container_decl.kind; - Buf *bare_name = buf_alloc(); - Buf *name = get_anon_type_name(ag->codegen, - ag->exec, container_string(kind), parent_scope, node, bare_name, result_loc); - - ContainerLayout layout = node->data.container_decl.layout; - ZigType *container_type = get_partial_container_type(ag->codegen, parent_scope, - kind, node, buf_ptr(name), bare_name, layout); - ScopeDecls *child_scope = get_container_scope(container_type); - - for (size_t i = 0; i < node->data.container_decl.decls.length; i += 1) { - AstNode *child_node = node->data.container_decl.decls.at(i); - scan_decls(ag->codegen, child_scope, child_node); - } - - TldContainer *tld_container = heap::c_allocator.create(); - init_tld(&tld_container->base, TldIdContainer, bare_name, VisibModPub, node, parent_scope); - tld_container->type_entry = container_type; - tld_container->decls_scope = child_scope; - ag->codegen->resolve_queue.append(&tld_container->base); - - // Add this to the list to mark as invalid if analyzing this exec fails. - ag->exec->tld_list.append(&tld_container->base); - - return ir_build_const_type(ag, parent_scope, node, container_type); -} - -static Stage1ZirInst *astgen_err_set_decl(Stage1AstGen *ag, Scope *parent_scope, AstNode *node) { - assert(node->type == NodeTypeErrorSetDecl); - - uint32_t err_count = node->data.err_set_decl.decls.length; - - Buf bare_name = BUF_INIT; - Buf *type_name = get_anon_type_name(ag->codegen, ag->exec, "error", parent_scope, node, &bare_name, nullptr); - ZigType *err_set_type = new_type_table_entry(ZigTypeIdErrorSet); - buf_init_from_buf(&err_set_type->name, type_name); - err_set_type->data.error_set.err_count = err_count; - err_set_type->size_in_bits = ag->codegen->builtin_types.entry_global_error_set->size_in_bits; - err_set_type->abi_align = ag->codegen->builtin_types.entry_global_error_set->abi_align; - err_set_type->abi_size = ag->codegen->builtin_types.entry_global_error_set->abi_size; - err_set_type->data.error_set.errors = heap::c_allocator.allocate(err_count); - - size_t errors_count = ag->codegen->errors_by_index.length + err_count; - ErrorTableEntry **errors = heap::c_allocator.allocate(errors_count); - - for (uint32_t i = 0; i < err_count; i += 1) { - AstNode *field_node = node->data.err_set_decl.decls.at(i); - AstNode *symbol_node = ast_field_to_symbol_node(field_node); - Buf *err_name = node_identifier_buf(symbol_node); - ErrorTableEntry *err = heap::c_allocator.create(); - err->decl_node = field_node; - buf_init_from_buf(&err->name, err_name); - - auto existing_entry = ag->codegen->error_table.put_unique(err_name, err); - if (existing_entry) { - err->value = existing_entry->value->value; - } else { - size_t error_value_count = ag->codegen->errors_by_index.length; - assert((uint32_t)error_value_count < (((uint32_t)1) << (uint32_t)ag->codegen->err_tag_type->data.integral.bit_count)); - err->value = error_value_count; - ag->codegen->errors_by_index.append(err); - } - err_set_type->data.error_set.errors[i] = err; - - ErrorTableEntry *prev_err = errors[err->value]; - if (prev_err != nullptr) { - ErrorMsg *msg = add_node_error(ag->codegen, ast_field_to_symbol_node(err->decl_node), - buf_sprintf("duplicate error: '%s'", buf_ptr(&err->name))); - add_error_note(ag->codegen, msg, ast_field_to_symbol_node(prev_err->decl_node), - buf_sprintf("other error here")); - return ag->codegen->invalid_inst_src; - } - errors[err->value] = err; - } - heap::c_allocator.deallocate(errors, errors_count); - return ir_build_const_type(ag, parent_scope, node, err_set_type); -} - -static Stage1ZirInst *astgen_fn_proto(Stage1AstGen *ag, Scope *parent_scope, AstNode *node) { - assert(node->type == NodeTypeFnProto); - - size_t param_count = node->data.fn_proto.params.length; - Stage1ZirInst **param_types = heap::c_allocator.allocate(param_count); - - bool is_var_args = false; - for (size_t i = 0; i < param_count; i += 1) { - AstNode *param_node = node->data.fn_proto.params.at(i); - if (param_node->data.param_decl.is_var_args) { - is_var_args = true; - break; - } - if (param_node->data.param_decl.anytype_token == 0) { - AstNode *type_node = param_node->data.param_decl.type; - Stage1ZirInst *type_value = astgen_node(ag, type_node, parent_scope); - if (type_value == ag->codegen->invalid_inst_src) - return ag->codegen->invalid_inst_src; - param_types[i] = type_value; - } else { - param_types[i] = nullptr; - } - } - - Stage1ZirInst *align_value = nullptr; - if (node->data.fn_proto.align_expr != nullptr) { - align_value = astgen_node(ag, node->data.fn_proto.align_expr, parent_scope); - if (align_value == ag->codegen->invalid_inst_src) - return ag->codegen->invalid_inst_src; - } - - Stage1ZirInst *callconv_value = nullptr; - if (node->data.fn_proto.callconv_expr != nullptr) { - callconv_value = astgen_node(ag, node->data.fn_proto.callconv_expr, parent_scope); - if (callconv_value == ag->codegen->invalid_inst_src) - return ag->codegen->invalid_inst_src; - } - - Stage1ZirInst *return_type; - if (node->data.fn_proto.return_type == nullptr) { - return_type = ir_build_const_type(ag, parent_scope, node, ag->codegen->builtin_types.entry_void); - } else { - return_type = astgen_node(ag, node->data.fn_proto.return_type, parent_scope); - if (return_type == ag->codegen->invalid_inst_src) - return ag->codegen->invalid_inst_src; - } - - return ir_build_fn_proto(ag, parent_scope, node, param_types, align_value, callconv_value, return_type, is_var_args); -} - -static Stage1ZirInst *astgen_resume(Stage1AstGen *ag, Scope *scope, AstNode *node) { - assert(node->type == NodeTypeResume); - - Stage1ZirInst *target_inst = astgen_node_extra(ag, node->data.resume_expr.expr, scope, LValPtr, nullptr); - if (target_inst == ag->codegen->invalid_inst_src) - return ag->codegen->invalid_inst_src; - - return ir_build_resume_src(ag, scope, node, target_inst); -} - -static Stage1ZirInst *astgen_await_expr(Stage1AstGen *ag, Scope *scope, AstNode *node, LVal lval, - ResultLoc *result_loc) -{ - assert(node->type == NodeTypeAwaitExpr); - - bool is_nosuspend = get_scope_nosuspend(scope) != nullptr; - - AstNode *expr_node = node->data.await_expr.expr; - if (expr_node->type == NodeTypeFnCallExpr && expr_node->data.fn_call_expr.modifier == CallModifierBuiltin) { - AstNode *fn_ref_expr = expr_node->data.fn_call_expr.fn_ref_expr; - Buf *name = node_identifier_buf(fn_ref_expr); - auto entry = ag->codegen->builtin_fn_table.maybe_get(name); - if (entry != nullptr) { - BuiltinFnEntry *builtin_fn = entry->value; - if (builtin_fn->id == BuiltinFnIdAsyncCall) { - return astgen_async_call(ag, scope, node, expr_node, lval, result_loc); - } - } - } - - if (!ag->fn) { - add_node_error(ag->codegen, node, buf_sprintf("await outside function definition")); - return ag->codegen->invalid_inst_src; - } - ScopeSuspend *existing_suspend_scope = get_scope_suspend(scope); - if (existing_suspend_scope) { - if (!existing_suspend_scope->reported_err) { - ErrorMsg *msg = add_node_error(ag->codegen, node, buf_sprintf("cannot await inside suspend block")); - add_error_note(ag->codegen, msg, existing_suspend_scope->base.source_node, buf_sprintf("suspend block here")); - existing_suspend_scope->reported_err = true; - } - return ag->codegen->invalid_inst_src; - } - - Stage1ZirInst *target_inst = astgen_node_extra(ag, expr_node, scope, LValPtr, nullptr); - if (target_inst == ag->codegen->invalid_inst_src) - return ag->codegen->invalid_inst_src; - - Stage1ZirInst *await_inst = ir_build_await_src(ag, scope, node, target_inst, result_loc, is_nosuspend); - return ir_lval_wrap(ag, scope, await_inst, lval, result_loc); -} - -static Stage1ZirInst *astgen_suspend(Stage1AstGen *ag, Scope *parent_scope, AstNode *node) { - assert(node->type == NodeTypeSuspend); - - if (!ag->fn) { - add_node_error(ag->codegen, node, buf_sprintf("suspend outside function definition")); - return ag->codegen->invalid_inst_src; - } - if (get_scope_nosuspend(parent_scope) != nullptr) { - add_node_error(ag->codegen, node, buf_sprintf("suspend in nosuspend scope")); - return ag->codegen->invalid_inst_src; - } - - ScopeSuspend *existing_suspend_scope = get_scope_suspend(parent_scope); - if (existing_suspend_scope) { - if (!existing_suspend_scope->reported_err) { - ErrorMsg *msg = add_node_error(ag->codegen, node, buf_sprintf("cannot suspend inside suspend block")); - add_error_note(ag->codegen, msg, existing_suspend_scope->base.source_node, buf_sprintf("other suspend block here")); - existing_suspend_scope->reported_err = true; - } - return ag->codegen->invalid_inst_src; - } - - Stage1ZirInstSuspendBegin *begin = ir_build_suspend_begin_src(ag, parent_scope, node); - ScopeSuspend *suspend_scope = create_suspend_scope(ag->codegen, node, parent_scope); - Scope *child_scope = &suspend_scope->base; - Stage1ZirInst *susp_res = astgen_node(ag, node->data.suspend.block, child_scope); - if (susp_res == ag->codegen->invalid_inst_src) - return ag->codegen->invalid_inst_src; - ir_build_check_statement_is_void(ag, child_scope, node->data.suspend.block, susp_res); - - return ir_build_suspend_finish_src(ag, parent_scope, node, begin); -} - -static Stage1ZirInst *astgen_node_raw(Stage1AstGen *ag, AstNode *node, Scope *scope, - LVal lval, ResultLoc *result_loc) -{ - assert(scope); - switch (node->type) { - case NodeTypeStructValueField: - case NodeTypeParamDecl: - case NodeTypeUsingNamespace: - case NodeTypeSwitchProng: - case NodeTypeSwitchRange: - case NodeTypeStructField: - case NodeTypeErrorSetField: - case NodeTypeFnDef: - case NodeTypeTestDecl: - zig_unreachable(); - case NodeTypeBlock: - return astgen_block(ag, scope, node, lval, result_loc); - case NodeTypeGroupedExpr: - return astgen_node_raw(ag, node->data.grouped_expr, scope, lval, result_loc); - case NodeTypeBinOpExpr: - return astgen_bin_op(ag, scope, node, lval, result_loc); - case NodeTypeIntLiteral: - return ir_lval_wrap(ag, scope, astgen_int_lit(ag, scope, node), lval, result_loc); - case NodeTypeFloatLiteral: - return ir_lval_wrap(ag, scope, astgen_float_lit(ag, scope, node), lval, result_loc); - case NodeTypeCharLiteral: - return ir_lval_wrap(ag, scope, astgen_char_lit(ag, scope, node), lval, result_loc); - case NodeTypeIdentifier: - return astgen_identifier(ag, scope, node, lval, result_loc); - case NodeTypeFnCallExpr: - return astgen_fn_call(ag, scope, node, lval, result_loc); - case NodeTypeIfBoolExpr: - return astgen_if_bool_expr(ag, scope, node, lval, result_loc); - case NodeTypePrefixOpExpr: - return astgen_prefix_op_expr(ag, scope, node, lval, result_loc); - case NodeTypeContainerInitExpr: - return astgen_container_init_expr(ag, scope, node, lval, result_loc); - case NodeTypeVariableDeclaration: - return astgen_var_decl(ag, scope, node); - case NodeTypeWhileExpr: - return astgen_while_expr(ag, scope, node, lval, result_loc); - case NodeTypeForExpr: - return astgen_for_expr(ag, scope, node, lval, result_loc); - case NodeTypeArrayAccessExpr: - return astgen_array_access(ag, scope, node, lval, result_loc); - case NodeTypeReturnExpr: - return astgen_return(ag, scope, node, lval, result_loc); - case NodeTypeFieldAccessExpr: - { - Stage1ZirInst *ptr_instruction = astgen_field_access(ag, scope, node); - if (ptr_instruction == ag->codegen->invalid_inst_src) - return ptr_instruction; - if (lval == LValPtr || lval == LValAssign) - return ptr_instruction; - - Stage1ZirInst *load_ptr = ir_build_load_ptr(ag, scope, node, ptr_instruction); - return ir_expr_wrap(ag, scope, load_ptr, result_loc); - } - case NodeTypePtrDeref: { - AstNode *expr_node = node->data.ptr_deref_expr.target; - - LVal child_lval = lval; - if (child_lval == LValAssign) - child_lval = LValPtr; - - Stage1ZirInst *value = astgen_node_extra(ag, expr_node, scope, child_lval, nullptr); - if (value == ag->codegen->invalid_inst_src) - return value; - - // We essentially just converted any lvalue from &(x.*) to (&x).*; - // this inhibits checking that x is a pointer later, so we directly - // record whether the pointer check is needed - Stage1ZirInst *un_op = ir_build_un_op_lval(ag, scope, node, IrUnOpDereference, value, lval, result_loc); - return ir_expr_wrap(ag, scope, un_op, result_loc); - } - case NodeTypeUnwrapOptional: { - AstNode *expr_node = node->data.unwrap_optional.expr; - - Stage1ZirInst *maybe_ptr = astgen_node_extra(ag, expr_node, scope, LValPtr, nullptr); - if (maybe_ptr == ag->codegen->invalid_inst_src) - return ag->codegen->invalid_inst_src; - - Stage1ZirInst *unwrapped_ptr = ir_build_optional_unwrap_ptr(ag, scope, node, maybe_ptr, true ); - if (lval == LValPtr || lval == LValAssign) - return unwrapped_ptr; - - Stage1ZirInst *load_ptr = ir_build_load_ptr(ag, scope, node, unwrapped_ptr); - return ir_expr_wrap(ag, scope, load_ptr, result_loc); - } - case NodeTypeArrayType: - return ir_lval_wrap(ag, scope, astgen_array_type(ag, scope, node), lval, result_loc); - case NodeTypePointerType: - return ir_lval_wrap(ag, scope, astgen_pointer_type(ag, scope, node), lval, result_loc); - case NodeTypeAnyFrameType: - return ir_lval_wrap(ag, scope, astgen_anyframe_type(ag, scope, node), lval, result_loc); - case NodeTypeStringLiteral: - return ir_lval_wrap(ag, scope, astgen_string_literal(ag, scope, node), lval, result_loc); - case NodeTypeAsmExpr: - return ir_lval_wrap(ag, scope, astgen_asm_expr(ag, scope, node), lval, result_loc); - case NodeTypeIfErrorExpr: - return astgen_if_err_expr(ag, scope, node, lval, result_loc); - case NodeTypeIfOptional: - return astgen_if_optional_expr(ag, scope, node, lval, result_loc); - case NodeTypeSwitchExpr: - return astgen_switch_expr(ag, scope, node, lval, result_loc); - case NodeTypeCompTime: - return ir_expr_wrap(ag, scope, astgen_comptime(ag, scope, node, lval), result_loc); - case NodeTypeNoSuspend: - return ir_expr_wrap(ag, scope, astgen_nosuspend(ag, scope, node, lval), result_loc); - case NodeTypeErrorType: - return ir_lval_wrap(ag, scope, astgen_error_type(ag, scope, node), lval, result_loc); - case NodeTypeBreak: - return ir_lval_wrap(ag, scope, astgen_break(ag, scope, node), lval, result_loc); - case NodeTypeContinue: - return ir_lval_wrap(ag, scope, astgen_continue(ag, scope, node), lval, result_loc); - case NodeTypeUnreachable: - return ir_build_unreachable(ag, scope, node); - case NodeTypeDefer: - return ir_lval_wrap(ag, scope, astgen_defer(ag, scope, node), lval, result_loc); - case NodeTypeSliceExpr: - return astgen_slice(ag, scope, node, lval, result_loc); - case NodeTypeCatchExpr: - return astgen_catch(ag, scope, node, lval, result_loc); - case NodeTypeContainerDecl: - return ir_lval_wrap(ag, scope, astgen_container_decl(ag, scope, node, result_loc), lval, result_loc); - case NodeTypeFnProto: - return ir_lval_wrap(ag, scope, astgen_fn_proto(ag, scope, node), lval, result_loc); - case NodeTypeErrorSetDecl: - return ir_lval_wrap(ag, scope, astgen_err_set_decl(ag, scope, node), lval, result_loc); - case NodeTypeResume: - return ir_lval_wrap(ag, scope, astgen_resume(ag, scope, node), lval, result_loc); - case NodeTypeAwaitExpr: - return astgen_await_expr(ag, scope, node, lval, result_loc); - case NodeTypeSuspend: - return ir_lval_wrap(ag, scope, astgen_suspend(ag, scope, node), lval, result_loc); - case NodeTypeEnumLiteral: - return ir_lval_wrap(ag, scope, astgen_enum_literal(ag, scope, node), lval, result_loc); - case NodeTypeInferredArrayType: - add_node_error(ag->codegen, node, - buf_sprintf("inferred array size invalid here")); - return ag->codegen->invalid_inst_src; - case NodeTypeAnyTypeField: - return ir_lval_wrap(ag, scope, - ir_build_const_type(ag, scope, node, ag->codegen->builtin_types.entry_anytype), lval, result_loc); - } - zig_unreachable(); -} - -ResultLoc *no_result_loc(void) { - ResultLocNone *result_loc_none = heap::c_allocator.create(); - result_loc_none->base.id = ResultLocIdNone; - return &result_loc_none->base; -} - -static Stage1ZirInst *astgen_node_extra(Stage1AstGen *ag, AstNode *node, Scope *scope, LVal lval, - ResultLoc *result_loc) -{ - if (lval == LValAssign) { - switch (node->type) { - case NodeTypeStructValueField: - case NodeTypeParamDecl: - case NodeTypeUsingNamespace: - case NodeTypeSwitchProng: - case NodeTypeSwitchRange: - case NodeTypeStructField: - case NodeTypeErrorSetField: - case NodeTypeFnDef: - case NodeTypeTestDecl: - zig_unreachable(); - - // cannot be assigned to - case NodeTypeBlock: - case NodeTypeGroupedExpr: - case NodeTypeBinOpExpr: - case NodeTypeIntLiteral: - case NodeTypeFloatLiteral: - case NodeTypeCharLiteral: - case NodeTypeIfBoolExpr: - case NodeTypeContainerInitExpr: - case NodeTypeVariableDeclaration: - case NodeTypeWhileExpr: - case NodeTypeForExpr: - case NodeTypeReturnExpr: - case NodeTypeArrayType: - case NodeTypePointerType: - case NodeTypeAnyFrameType: - case NodeTypeStringLiteral: - case NodeTypeAsmExpr: - case NodeTypeIfErrorExpr: - case NodeTypeIfOptional: - case NodeTypeSwitchExpr: - case NodeTypeCompTime: - case NodeTypeNoSuspend: - case NodeTypeErrorType: - case NodeTypeBreak: - case NodeTypeContinue: - case NodeTypeUnreachable: - case NodeTypeDefer: - case NodeTypeSliceExpr: - case NodeTypeCatchExpr: - case NodeTypeContainerDecl: - case NodeTypeFnProto: - case NodeTypeErrorSetDecl: - case NodeTypeResume: - case NodeTypeAwaitExpr: - case NodeTypeSuspend: - case NodeTypeEnumLiteral: - case NodeTypeInferredArrayType: - case NodeTypeAnyTypeField: - case NodeTypePrefixOpExpr: - add_node_error(ag->codegen, node, - buf_sprintf("invalid left-hand side to assignment")); - return ag->codegen->invalid_inst_src; - - // @field can be assigned to - case NodeTypeFnCallExpr: - if (node->data.fn_call_expr.modifier == CallModifierBuiltin) { - AstNode *fn_ref_expr = node->data.fn_call_expr.fn_ref_expr; - Buf *name = node_identifier_buf(fn_ref_expr); - auto entry = ag->codegen->builtin_fn_table.maybe_get(name); - - if (!entry) { - add_node_error(ag->codegen, node, - buf_sprintf("invalid builtin function: '%s'", buf_ptr(name))); - return ag->codegen->invalid_inst_src; - } - - if (entry->value->id == BuiltinFnIdField) { - break; - } - } - add_node_error(ag->codegen, node, - buf_sprintf("invalid left-hand side to assignment")); - return ag->codegen->invalid_inst_src; - - - // can be assigned to - case NodeTypeUnwrapOptional: - case NodeTypePtrDeref: - case NodeTypeFieldAccessExpr: - case NodeTypeArrayAccessExpr: - case NodeTypeIdentifier: - break; - } - } - if (result_loc == nullptr) { - // Create a result location indicating there is none - but if one gets created - // it will be properly distributed. - result_loc = no_result_loc(); - ir_build_reset_result(ag, scope, node, result_loc); - } - Scope *child_scope; - if (ag->exec->is_inline || - (ag->fn != nullptr && ag->fn->child_scope == scope)) - { - child_scope = scope; - } else { - child_scope = &create_expr_scope(ag->codegen, node, scope)->base; - } - Stage1ZirInst *result = astgen_node_raw(ag, node, child_scope, lval, result_loc); - if (result == ag->codegen->invalid_inst_src) { - if (ag->exec->first_err_trace_msg == nullptr) { - ag->exec->first_err_trace_msg = ag->codegen->trace_err; - } - } - return result; -} - -static Stage1ZirInst *astgen_node(Stage1AstGen *ag, AstNode *node, Scope *scope) { - return astgen_node_extra(ag, node, scope, LValNone, nullptr); -} - -bool stage1_astgen(CodeGen *codegen, AstNode *node, Scope *scope, Stage1Zir *stage1_zir, - ZigFn *fn, bool in_c_import_scope) -{ - assert(node->owner); - - Stage1AstGen ir_builder = {0}; - Stage1AstGen *ag = &ir_builder; - - ag->codegen = codegen; - ag->fn = fn; - ag->in_c_import_scope = in_c_import_scope; - ag->exec = stage1_zir; - ag->main_block_node = node; - - Stage1ZirBasicBlock *entry_block = ir_create_basic_block(ag, scope, "Entry"); - ir_set_cursor_at_end_and_append_block(ag, entry_block); - // Entry block gets a reference because we enter it to begin. - ir_ref_bb(ag->current_basic_block); - - Stage1ZirInst *result = astgen_node_extra(ag, node, scope, LValNone, nullptr); - - if (result == ag->codegen->invalid_inst_src) - return false; - - if (ag->exec->first_err_trace_msg != nullptr) { - codegen->trace_err = ag->exec->first_err_trace_msg; - return false; - } - - if (!instr_is_unreachable(result)) { - ir_build_add_implicit_return_type(ag, scope, result->source_node, result, nullptr); - // no need for save_err_ret_addr because this cannot return error - ResultLocReturn *result_loc_ret = heap::c_allocator.create(); - result_loc_ret->base.id = ResultLocIdReturn; - ir_build_reset_result(ag, scope, node, &result_loc_ret->base); - ir_build_end_expr(ag, scope, node, result, &result_loc_ret->base); - ir_build_return_src(ag, scope, result->source_node, result); - } - - return true; -} - -bool stage1_astgen_fn(CodeGen *codegen, ZigFn *fn) { - assert(fn != nullptr); - assert(fn->child_scope != nullptr); - return stage1_astgen(codegen, fn->body_node, fn->child_scope, fn->stage1_zir, fn, false); -} - -void invalidate_exec(Stage1Zir *exec, ErrorMsg *msg) { - if (exec->first_err_trace_msg != nullptr) - return; - - exec->first_err_trace_msg = msg; - - for (size_t i = 0; i < exec->tld_list.length; i += 1) { - exec->tld_list.items[i]->resolution = TldResolutionInvalid; - } -} - -AstNode *ast_field_to_symbol_node(AstNode *err_set_field_node) { - if (err_set_field_node->type == NodeTypeIdentifier) { - return err_set_field_node; - } else if (err_set_field_node->type == NodeTypeErrorSetField) { - assert(err_set_field_node->data.err_set_field.field_name->type == NodeTypeIdentifier); - return err_set_field_node->data.err_set_field.field_name; - } else { - return err_set_field_node; - } -} - -void ir_add_call_stack_errors_gen(CodeGen *codegen, Stage1Air *exec, ErrorMsg *err_msg, int limit) { - if (!exec || !exec->source_node || limit < 0) return; - add_error_note(codegen, err_msg, exec->source_node, buf_sprintf("called from here")); - - ir_add_call_stack_errors_gen(codegen, exec->parent_exec, err_msg, limit - 1); -} - -void Stage1ZirInst::src() { - Stage1ZirInst *inst = this; - if (inst->source_node != nullptr) { - inst->source_node->src(); - } else { - fprintf(stderr, "(null source node)\n"); - } -} - diff --git a/src/stage1/astgen.hpp b/src/stage1/astgen.hpp deleted file mode 100644 index c0ca583f56ef..000000000000 --- a/src/stage1/astgen.hpp +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (c) 2021 Andrew Kelley - * - * This file is part of zig, which is MIT licensed. - * See http://opensource.org/licenses/MIT - */ - -#ifndef ZIG_ASTGEN_HPP -#define ZIG_ASTGEN_HPP - -#include "all_types.hpp" - -bool stage1_astgen(CodeGen *g, AstNode *node, Scope *scope, Stage1Zir *stage1_zir, - ZigFn *fn, bool in_c_import_scope); -bool stage1_astgen_fn(CodeGen *g, ZigFn *fn_entry); - -bool ir_inst_src_has_side_effects(Stage1ZirInst *inst); - -ZigVar *create_local_var(CodeGen *codegen, AstNode *node, Scope *parent_scope, - Buf *name, bool src_is_const, bool gen_is_const, bool is_shadowable, Stage1ZirInst *is_comptime, - bool skip_name_check); - -ResultLoc *no_result_loc(void); - -void invalidate_exec(Stage1Zir *exec, ErrorMsg *msg); - -AstNode *ast_field_to_symbol_node(AstNode *err_set_field_node); -void ir_add_call_stack_errors_gen(CodeGen *codegen, Stage1Air *exec, ErrorMsg *err_msg, - int limit); - -void destroy_instruction_src(Stage1ZirInst *inst); - -bool ir_should_inline(Stage1Zir *exec, Scope *scope); -Buf *get_anon_type_name(CodeGen *codegen, Stage1Zir *exec, const char *kind_name, - Scope *scope, AstNode *source_node, Buf *out_bare_name, ResultLoc *result_loc); - -#endif diff --git a/src/stage1/bigfloat.cpp b/src/stage1/bigfloat.cpp deleted file mode 100644 index e5f21e34ea11..000000000000 --- a/src/stage1/bigfloat.cpp +++ /dev/null @@ -1,220 +0,0 @@ -/* - * Copyright (c) 2017 Andrew Kelley - * - * This file is part of zig, which is MIT licensed. - * See http://opensource.org/licenses/MIT - */ - -#include "bigfloat.hpp" -#include "bigint.hpp" -#include "buffer.hpp" -#include "softfloat.hpp" -#include "softfloat_ext.hpp" -#include "parse_f128.h" -#include -#include -#include - - -void bigfloat_init_128(BigFloat *dest, float128_t x) { - dest->value = x; -} - -void bigfloat_init_16(BigFloat *dest, float16_t x) { - f16_to_f128M(x, &dest->value); -} - -void bigfloat_init_32(BigFloat *dest, float x) { - float32_t f32_val; - memcpy(&f32_val, &x, sizeof(float)); - f32_to_f128M(f32_val, &dest->value); -} - -void bigfloat_init_64(BigFloat *dest, double x) { - float64_t f64_val; - memcpy(&f64_val, &x, sizeof(double)); - f64_to_f128M(f64_val, &dest->value); -} - -void bigfloat_init_bigfloat(BigFloat *dest, const BigFloat *x) { - memcpy(&dest->value, &x->value, sizeof(float128_t)); -} - -void bigfloat_init_bigint(BigFloat *dest, const BigInt *op) { - ui32_to_f128M(0, &dest->value); - if (op->digit_count == 0) - return; - - float128_t base; - ui64_to_f128M(UINT64_MAX, &base); - float128_t one_f128; - ui32_to_f128M(1, &one_f128); - f128M_add(&base, &one_f128, &base); - - const uint64_t *digits = bigint_ptr(op); - - for (size_t i = op->digit_count - 1;;) { - float128_t digit_f128; - ui64_to_f128M(digits[i], &digit_f128); - - f128M_mulAdd(&dest->value, &base, &digit_f128, &dest->value); - - if (i == 0) { - if (op->is_negative) { - f128M_neg(&dest->value, &dest->value); - } - return; - } - i -= 1; - } -} - -Error bigfloat_init_buf(BigFloat *dest, const uint8_t *buf_ptr) { - char *str_begin = (char *)buf_ptr; - char *str_end; - - errno = 0; - dest->value = parse_f128(str_begin, &str_end); - if (errno) { - return ErrorOverflow; - } - - return ErrorNone; -} - -void bigfloat_add(BigFloat *dest, const BigFloat *op1, const BigFloat *op2) { - f128M_add(&op1->value, &op2->value, &dest->value); -} - -void bigfloat_negate(BigFloat *dest, const BigFloat *op) { - f128M_neg(&op->value, &dest->value); -} - -void bigfloat_sub(BigFloat *dest, const BigFloat *op1, const BigFloat *op2) { - f128M_sub(&op1->value, &op2->value, &dest->value); -} - -void bigfloat_mul(BigFloat *dest, const BigFloat *op1, const BigFloat *op2) { - f128M_mul(&op1->value, &op2->value, &dest->value); -} - -void bigfloat_div(BigFloat *dest, const BigFloat *op1, const BigFloat *op2) { - f128M_div(&op1->value, &op2->value, &dest->value); -} - -void bigfloat_div_trunc(BigFloat *dest, const BigFloat *op1, const BigFloat *op2) { - f128M_div(&op1->value, &op2->value, &dest->value); - f128M_roundToInt(&dest->value, softfloat_round_minMag, false, &dest->value); -} - -void bigfloat_div_floor(BigFloat *dest, const BigFloat *op1, const BigFloat *op2) { - f128M_div(&op1->value, &op2->value, &dest->value); - f128M_roundToInt(&dest->value, softfloat_round_min, false, &dest->value); -} - -void bigfloat_rem(BigFloat *dest, const BigFloat *op1, const BigFloat *op2) { - f128M_rem(&op1->value, &op2->value, &dest->value); -} - -void bigfloat_mod(BigFloat *dest, const BigFloat *op1, const BigFloat *op2) { - f128M_rem(&op1->value, &op2->value, &dest->value); - f128M_add(&dest->value, &op2->value, &dest->value); - f128M_rem(&dest->value, &op2->value, &dest->value); -} - -void bigfloat_append_buf(Buf *buf, const BigFloat *op) { - const size_t extra_len = 100; - size_t old_len = buf_len(buf); - buf_resize(buf, old_len + extra_len); - - // TODO actually print f128 - float64_t f64_value = f128M_to_f64(&op->value); - double double_value; - memcpy(&double_value, &f64_value, sizeof(double)); - - int len = snprintf(buf_ptr(buf) + old_len, extra_len, "%f", double_value); - assert(len > 0); - buf_resize(buf, old_len + len); -} - -Cmp bigfloat_cmp(const BigFloat *op1, const BigFloat *op2) { - if (f128M_lt(&op1->value, &op2->value)) { - return CmpLT; - } else if (f128M_eq(&op1->value, &op2->value)) { - return CmpEQ; - } else { - return CmpGT; - } -} - -float16_t bigfloat_to_f16(const BigFloat *bigfloat) { - return f128M_to_f16(&bigfloat->value); -} - -float bigfloat_to_f32(const BigFloat *bigfloat) { - float32_t f32_value = f128M_to_f32(&bigfloat->value); - float result; - memcpy(&result, &f32_value, sizeof(float)); - return result; -} - -double bigfloat_to_f64(const BigFloat *bigfloat) { - float64_t f64_value = f128M_to_f64(&bigfloat->value); - double result; - memcpy(&result, &f64_value, sizeof(double)); - return result; -} - -float128_t bigfloat_to_f128(const BigFloat *bigfloat) { - return bigfloat->value; -} - -Cmp bigfloat_cmp_zero(const BigFloat *bigfloat) { - float128_t zero_float; - ui32_to_f128M(0, &zero_float); - if (f128M_lt(&bigfloat->value, &zero_float)) { - return CmpLT; - } else if (f128M_eq(&bigfloat->value, &zero_float)) { - return CmpEQ; - } else { - return CmpGT; - } -} - -bool bigfloat_has_fraction(const BigFloat *bigfloat) { - float128_t floored; - f128M_roundToInt(&bigfloat->value, softfloat_round_minMag, false, &floored); - return !f128M_eq(&floored, &bigfloat->value); -} - -void bigfloat_sqrt(BigFloat *dest, const BigFloat *op) { - f128M_sqrt(&op->value, &dest->value); -} - -void bigfloat_min(BigFloat *dest, const BigFloat *op1, const BigFloat *op2) { - if (bigfloat_is_nan(op1)) { - bigfloat_init_bigfloat(dest, op2); - } else if (bigfloat_is_nan(op2)) { - bigfloat_init_bigfloat(dest, op1); - } else if (f128M_lt(&op1->value, &op2->value)) { - bigfloat_init_bigfloat(dest, op1); - } else { - bigfloat_init_bigfloat(dest, op2); - } -} - -void bigfloat_max(BigFloat *dest, const BigFloat *op1, const BigFloat *op2) { - if (bigfloat_is_nan(op1)) { - bigfloat_init_bigfloat(dest, op2); - } else if (bigfloat_is_nan(op2)) { - bigfloat_init_bigfloat(dest, op1); - } else if (f128M_lt(&op1->value, &op2->value)) { - bigfloat_init_bigfloat(dest, op2); - } else { - bigfloat_init_bigfloat(dest, op1); - } -} - -bool bigfloat_is_nan(const BigFloat *op) { - return f128M_isSignalingNaN(&op->value); -} diff --git a/src/stage1/bigfloat.hpp b/src/stage1/bigfloat.hpp deleted file mode 100644 index ffaff320e995..000000000000 --- a/src/stage1/bigfloat.hpp +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright (c) 2017 Andrew Kelley - * - * This file is part of zig, which is MIT licensed. - * See http://opensource.org/licenses/MIT - */ - -#ifndef ZIG_BIGFLOAT_HPP -#define ZIG_BIGFLOAT_HPP - -#include "bigint.hpp" -#include "error.hpp" -#include -#include - -#include "softfloat_types.h" - - -struct BigFloat { - float128_t value; -}; - -struct Buf; - -void bigfloat_init_16(BigFloat *dest, float16_t x); -void bigfloat_init_32(BigFloat *dest, float x); -void bigfloat_init_64(BigFloat *dest, double x); -void bigfloat_init_128(BigFloat *dest, float128_t x); -void bigfloat_init_bigfloat(BigFloat *dest, const BigFloat *x); -void bigfloat_init_bigint(BigFloat *dest, const BigInt *op); -Error bigfloat_init_buf(BigFloat *dest, const uint8_t *buf_ptr); - -float16_t bigfloat_to_f16(const BigFloat *bigfloat); -float bigfloat_to_f32(const BigFloat *bigfloat); -double bigfloat_to_f64(const BigFloat *bigfloat); -float128_t bigfloat_to_f128(const BigFloat *bigfloat); - -void bigfloat_add(BigFloat *dest, const BigFloat *op1, const BigFloat *op2); -void bigfloat_negate(BigFloat *dest, const BigFloat *op); -void bigfloat_sub(BigFloat *dest, const BigFloat *op1, const BigFloat *op2); -void bigfloat_mul(BigFloat *dest, const BigFloat *op1, const BigFloat *op2); -void bigfloat_div(BigFloat *dest, const BigFloat *op1, const BigFloat *op2); -void bigfloat_div_trunc(BigFloat *dest, const BigFloat *op1, const BigFloat *op2); -void bigfloat_div_floor(BigFloat *dest, const BigFloat *op1, const BigFloat *op2); -void bigfloat_rem(BigFloat *dest, const BigFloat *op1, const BigFloat *op2); -void bigfloat_mod(BigFloat *dest, const BigFloat *op1, const BigFloat *op2); -void bigfloat_sqrt(BigFloat *dest, const BigFloat *op); -void bigfloat_min(BigFloat *dest, const BigFloat *op1, const BigFloat *op2); -void bigfloat_max(BigFloat *dest, const BigFloat *op1, const BigFloat *op2); -void bigfloat_append_buf(Buf *buf, const BigFloat *op); -Cmp bigfloat_cmp(const BigFloat *op1, const BigFloat *op2); - - -bool bigfloat_is_nan(const BigFloat *op); - -// convenience functions -Cmp bigfloat_cmp_zero(const BigFloat *bigfloat); -bool bigfloat_has_fraction(const BigFloat *bigfloat); - -#endif diff --git a/src/stage1/bigint.cpp b/src/stage1/bigint.cpp deleted file mode 100644 index 3180095be647..000000000000 --- a/src/stage1/bigint.cpp +++ /dev/null @@ -1,1895 +0,0 @@ -/* - * Copyright (c) 2017 Andrew Kelley - * - * This file is part of zig, which is MIT licensed. - * See http://opensource.org/licenses/MIT - */ - -#include "bigfloat.hpp" -#include "bigint.hpp" -#include "buffer.hpp" -#include "list.hpp" -#include "os.hpp" -#include "softfloat.hpp" - -#include -#include - -static uint64_t bigint_as_unsigned(const BigInt *bigint); - -static void bigint_normalize(BigInt *dest) { - const uint64_t *digits = bigint_ptr(dest); - - size_t last_nonzero_digit = SIZE_MAX; - for (size_t i = 0; i < dest->digit_count; i += 1) { - uint64_t digit = digits[i]; - if (digit != 0) { - last_nonzero_digit = i; - } - } - if (last_nonzero_digit == SIZE_MAX) { - dest->is_negative = false; - dest->digit_count = 0; - } else { - dest->digit_count = last_nonzero_digit + 1; - if (last_nonzero_digit == 0) { - dest->data.digit = digits[0]; - } - } -} - -static uint8_t digit_to_char(uint8_t digit, bool uppercase) { - if (digit <= 9) { - return digit + '0'; - } else if (digit <= 35) { - return (digit - 10) + (uppercase ? 'A' : 'a'); - } else { - zig_unreachable(); - } -} - -size_t bigint_bits_needed(const BigInt *op) { - size_t full_bits = op->digit_count * 64; - size_t leading_zero_count = bigint_clz(op, full_bits); - size_t bits_needed = full_bits - leading_zero_count; - return bits_needed + op->is_negative; -} - -static void to_twos_complement(BigInt *dest, const BigInt *op, size_t bit_count) { - if (bit_count == 0 || op->digit_count == 0) { - bigint_init_unsigned(dest, 0); - return; - } - - BigInt pos_op = {0}; - - if (op->is_negative) { - BigInt negated = {0}; - bigint_negate(&negated, op); - - BigInt inverted = {0}; - bigint_not(&inverted, &negated, bit_count, false); - - BigInt one = {0}; - bigint_init_unsigned(&one, 1); - - bigint_add(&pos_op, &inverted, &one); - } else { - bigint_init_bigint(&pos_op, op); - } - - dest->is_negative = false; - const uint64_t *op_digits = bigint_ptr(&pos_op); - if (pos_op.digit_count == 1) { - dest->data.digit = op_digits[0]; - if (bit_count < 64) { - dest->data.digit &= (1ULL << bit_count) - 1; - } - dest->digit_count = 1; - bigint_normalize(dest); - return; - } - size_t digits_to_copy = bit_count / 64; - size_t leftover_bits = bit_count % 64; - dest->digit_count = digits_to_copy + ((leftover_bits == 0) ? 0 : 1); - if (dest->digit_count == 1) { - dest->data.digit = op_digits[0]; - if (leftover_bits != 0) { - dest->data.digit &= (1ULL << leftover_bits) - 1; - } - if (dest->data.digit == 0) dest->digit_count = 0; - return; - } - dest->data.digits = heap::c_allocator.allocate_nonzero(dest->digit_count); - for (size_t i = 0; i < digits_to_copy; i += 1) { - uint64_t digit = (i < pos_op.digit_count) ? op_digits[i] : 0; - dest->data.digits[i] = digit; - } - if (leftover_bits != 0) { - uint64_t digit = (digits_to_copy < pos_op.digit_count) ? op_digits[digits_to_copy] : 0; - dest->data.digits[digits_to_copy] = digit & ((1ULL << leftover_bits) - 1); - } - bigint_normalize(dest); -} - -static bool bit_at_index(const BigInt *bi, size_t index) { - size_t digit_index = index / 64; - if (digit_index >= bi->digit_count) - return false; - size_t digit_bit_index = index % 64; - const uint64_t *digits = bigint_ptr(bi); - uint64_t digit = digits[digit_index]; - return ((digit >> digit_bit_index) & 0x1) == 0x1; -} - -static void from_twos_complement(BigInt *dest, const BigInt *src, size_t bit_count, bool is_signed) { - assert(!src->is_negative); - - if (bit_count == 0 || src->digit_count == 0) { - bigint_init_unsigned(dest, 0); - return; - } - - if (is_signed && bit_at_index(src, bit_count - 1)) { - BigInt negative_one = {0}; - bigint_init_signed(&negative_one, -1); - - BigInt minus_one = {0}; - bigint_add(&minus_one, src, &negative_one); - - BigInt inverted = {0}; - bigint_not(&inverted, &minus_one, bit_count, false); - - bigint_negate(dest, &inverted); - return; - - } - - bigint_init_bigint(dest, src); -} - -void bigint_init_unsigned(BigInt *dest, uint64_t x) { - if (x == 0) { - dest->digit_count = 0; - dest->is_negative = false; - return; - } - dest->digit_count = 1; - dest->data.digit = x; - dest->is_negative = false; -} - -void bigint_init_signed(BigInt *dest, int64_t x) { - if (x >= 0) { - return bigint_init_unsigned(dest, x); - } - dest->is_negative = true; - dest->digit_count = 1; - dest->data.digit = ((uint64_t)(-(x + 1))) + 1; -} - -void bigint_init_data(BigInt *dest, const uint64_t *digits, size_t digit_count, bool is_negative) { - if (digit_count == 0) { - return bigint_init_unsigned(dest, 0); - } else if (digit_count == 1) { - dest->digit_count = 1; - dest->data.digit = digits[0]; - dest->is_negative = is_negative; - bigint_normalize(dest); - return; - } - - dest->digit_count = digit_count; - dest->is_negative = is_negative; - dest->data.digits = heap::c_allocator.allocate_nonzero(digit_count); - memcpy(dest->data.digits, digits, sizeof(uint64_t) * digit_count); - - bigint_normalize(dest); -} - -void bigint_init_bigint(BigInt *dest, const BigInt *src) { - if (src->digit_count == 0) { - return bigint_init_unsigned(dest, 0); - } else if (src->digit_count == 1) { - dest->digit_count = 1; - dest->data.digit = src->data.digit; - dest->is_negative = src->is_negative; - return; - } - dest->is_negative = src->is_negative; - dest->digit_count = src->digit_count; - dest->data.digits = heap::c_allocator.allocate_nonzero(dest->digit_count); - memcpy(dest->data.digits, src->data.digits, sizeof(uint64_t) * dest->digit_count); -} - -void bigint_deinit(BigInt *bi) { - if (bi->digit_count > 1) - heap::c_allocator.deallocate(bi->data.digits, bi->digit_count); -} - -void bigint_init_bigfloat(BigInt *dest, const BigFloat *op) { - float128_t zero; - ui32_to_f128M(0, &zero); - - dest->is_negative = f128M_lt(&op->value, &zero); - float128_t abs_val; - if (dest->is_negative) { - f128M_sub(&zero, &op->value, &abs_val); - } else { - memcpy(&abs_val, &op->value, sizeof(float128_t)); - } - - float128_t max_u64; - ui64_to_f128M(UINT64_MAX, &max_u64); - if (f128M_le(&abs_val, &max_u64)) { - dest->digit_count = 1; - dest->data.digit = f128M_to_ui64(&abs_val, softfloat_round_minMag, false); - bigint_normalize(dest); - return; - } - - float128_t amt; - f128M_div(&abs_val, &max_u64, &amt); - float128_t remainder; - f128M_rem(&abs_val, &max_u64, &remainder); - - dest->digit_count = 2; - dest->data.digits = heap::c_allocator.allocate_nonzero(dest->digit_count); - dest->data.digits[0] = f128M_to_ui64(&remainder, softfloat_round_minMag, false); - dest->data.digits[1] = f128M_to_ui64(&amt, softfloat_round_minMag, false); - bigint_normalize(dest); -} - -bool bigint_fits_in_bits(const BigInt *bn, size_t bit_count, bool is_signed) { - assert(bn->digit_count != 1 || bn->data.digit != 0); - if (bit_count == 0) { - return bigint_cmp_zero(bn) == CmpEQ; - } - if (bn->digit_count == 0) { - return true; - } - - if (!is_signed) { - if(bn->is_negative) return false; - size_t full_bits = bn->digit_count * 64; - size_t leading_zero_count = bigint_clz(bn, full_bits); - return bit_count >= full_bits - leading_zero_count; - } - - BigInt one = {0}; - bigint_init_unsigned(&one, 1); - - BigInt shl_amt = {0}; - bigint_init_unsigned(&shl_amt, bit_count - 1); - - BigInt max_value_plus_one = {0}; - bigint_shl(&max_value_plus_one, &one, &shl_amt); - - BigInt max_value = {0}; - bigint_sub(&max_value, &max_value_plus_one, &one); - - BigInt min_value = {0}; - bigint_negate(&min_value, &max_value_plus_one); - - Cmp min_cmp = bigint_cmp(bn, &min_value); - Cmp max_cmp = bigint_cmp(bn, &max_value); - - return (min_cmp == CmpGT || min_cmp == CmpEQ) && (max_cmp == CmpLT || max_cmp == CmpEQ); -} - -void bigint_write_twos_complement(const BigInt *big_int, uint8_t *buf, size_t bit_count, bool is_big_endian) { - if (bit_count == 0) - return; - - BigInt twos_comp = {0}; - to_twos_complement(&twos_comp, big_int, bit_count); - - const uint64_t *twos_comp_digits = bigint_ptr(&twos_comp); - - size_t bits_in_last_digit = bit_count % 64; - if (bits_in_last_digit == 0) bits_in_last_digit = 64; - size_t bytes_in_last_digit = (bits_in_last_digit + 7) / 8; - size_t unwritten_byte_count = 8 - bytes_in_last_digit; - - if (is_big_endian) { - size_t last_digit_index = (bit_count - 1) / 64; - size_t digit_index = last_digit_index; - size_t buf_index = 0; - for (;;) { - uint64_t x = (digit_index < twos_comp.digit_count) ? twos_comp_digits[digit_index] : 0; - - for (size_t byte_index = 7;;) { - uint8_t byte = x & 0xff; - if (digit_index == last_digit_index) { - buf[buf_index + byte_index - unwritten_byte_count] = byte; - if (byte_index == unwritten_byte_count) break; - } else { - buf[buf_index + byte_index] = byte; - } - - if (byte_index == 0) break; - byte_index -= 1; - x >>= 8; - } - - if (digit_index == 0) break; - if (digit_index == last_digit_index) { - buf_index += bytes_in_last_digit; - } else { - buf_index += 8; - } - digit_index -= 1; - } - } else { - size_t digit_count = (bit_count + 63) / 64; - size_t buf_index = 0; - for (size_t digit_index = 0; digit_index < digit_count; digit_index += 1) { - uint64_t x = (digit_index < twos_comp.digit_count) ? twos_comp_digits[digit_index] : 0; - - for (size_t byte_index = 0; - byte_index < 8 && (digit_index + 1 < digit_count || byte_index < bytes_in_last_digit); - byte_index += 1) - { - uint8_t byte = x & 0xff; - buf[buf_index] = byte; - buf_index += 1; - x >>= 8; - } - } - } -} - - -void bigint_read_twos_complement(BigInt *dest, const uint8_t *buf, size_t bit_count, bool is_big_endian, - bool is_signed) -{ - if (bit_count == 0) { - bigint_init_unsigned(dest, 0); - return; - } - - dest->digit_count = (bit_count + 63) / 64; - uint64_t *digits; - if (dest->digit_count == 1) { - digits = &dest->data.digit; - } else { - digits = heap::c_allocator.allocate_nonzero(dest->digit_count); - dest->data.digits = digits; - } - - size_t bits_in_last_digit = bit_count % 64; - if (bits_in_last_digit == 0) { - bits_in_last_digit = 64; - } - size_t bytes_in_last_digit = (bits_in_last_digit + 7) / 8; - size_t unread_byte_count = 8 - bytes_in_last_digit; - - if (is_big_endian) { - size_t buf_index = 0; - uint64_t digit = 0; - for (size_t byte_index = unread_byte_count; byte_index < 8; byte_index += 1) { - uint8_t byte = buf[buf_index]; - buf_index += 1; - digit <<= 8; - digit |= byte; - } - digits[dest->digit_count - 1] = digit; - for (size_t digit_index = 1; digit_index < dest->digit_count; digit_index += 1) { - digit = 0; - for (size_t byte_index = 0; byte_index < 8; byte_index += 1) { - uint8_t byte = buf[buf_index]; - buf_index += 1; - digit <<= 8; - digit |= byte; - } - digits[dest->digit_count - 1 - digit_index] = digit; - } - } else { - size_t buf_index = 0; - for (size_t digit_index = 0; digit_index < dest->digit_count; digit_index += 1) { - uint64_t digit = 0; - size_t end_byte_index = (digit_index == dest->digit_count - 1) ? bytes_in_last_digit : 8; - for (size_t byte_index = 0; byte_index < end_byte_index; byte_index += 1) { - uint64_t byte = buf[buf_index]; - buf_index += 1; - - digit |= byte << (8 * byte_index); - } - digits[digit_index] = digit; - } - } - - if (is_signed) { - bigint_normalize(dest); - BigInt tmp = {0}; - bigint_init_bigint(&tmp, dest); - from_twos_complement(dest, &tmp, bit_count, true); - } else { - dest->is_negative = false; - bigint_normalize(dest); - } -} - -#if defined(_MSC_VER) -static bool add_u64_overflow(uint64_t op1, uint64_t op2, uint64_t *result) { - *result = op1 + op2; - return *result < op1 || *result < op2; -} - -static bool sub_u64_overflow(uint64_t op1, uint64_t op2, uint64_t *result) { - *result = op1 - op2; - return *result > op1; -} - -bool mul_u64_overflow(uint64_t op1, uint64_t op2, uint64_t *result) { - *result = op1 * op2; - - if (op1 == 0 || op2 == 0) - return false; - - if (op1 > UINT64_MAX / op2) - return true; - - if (op2 > UINT64_MAX / op1) - return true; - - return false; -} -#else -static bool add_u64_overflow(uint64_t op1, uint64_t op2, uint64_t *result) { - return __builtin_uaddll_overflow((unsigned long long)op1, (unsigned long long)op2, - (unsigned long long *)result); -} - -static bool sub_u64_overflow(uint64_t op1, uint64_t op2, uint64_t *result) { - return __builtin_usubll_overflow((unsigned long long)op1, (unsigned long long)op2, - (unsigned long long *)result); -} - -bool mul_u64_overflow(uint64_t op1, uint64_t op2, uint64_t *result) { - return __builtin_umulll_overflow((unsigned long long)op1, (unsigned long long)op2, - (unsigned long long *)result); -} -#endif - -void bigint_max(BigInt* dest, const BigInt *op1, const BigInt *op2) { - switch (bigint_cmp(op1, op2)) { - case CmpEQ: - case CmpLT: - return bigint_init_bigint(dest, op2); - case CmpGT: - return bigint_init_bigint(dest, op1); - } -} - -void bigint_min(BigInt* dest, const BigInt *op1, const BigInt *op2) { - switch (bigint_cmp(op1, op2)) { - case CmpEQ: - case CmpLT: - return bigint_init_bigint(dest, op1); - case CmpGT: - return bigint_init_bigint(dest, op2); - } -} - -/// clamps op within bit_count/signedness boundaries -/// signed bounds are [-2^(bit_count-1)..2^(bit_count-1)-1] -/// unsigned bounds are [0..2^bit_count-1] -void bigint_clamp_by_bitcount(BigInt* dest, uint32_t bit_count, bool is_signed) { - bool is_negative = dest->is_negative; - // unsigned and dest->is_negative => clamp to 0 - if (is_negative && !is_signed) { - bigint_deinit(dest); - bigint_init_unsigned(dest, 0); - return; - } - // compute the number of bits required to store the value, and use that - // to decide whether to clamp the result - // to workaround the fact this bits_needed calculation would yield 65 or more for - // all negative numbers, set is_negative to false. this is a cheap way to find - // bits_needed(abs(dest)). - dest->is_negative = false; - // because we've set is_negative to false, we have to account for the extra bit here - // by adding 1 additional bit_needed when (is_negative && !is_signed). - size_t full_bits = dest->digit_count * 64; - size_t leading_zero_count = bigint_clz(dest, full_bits); - size_t bits_needed = full_bits - leading_zero_count + (is_negative && !is_signed); - - bit_count -= is_signed; - if(bits_needed > bit_count) { - BigInt one; - bigint_init_unsigned(&one, 1); - BigInt bit_count_big; - bigint_init_unsigned(&bit_count_big, bit_count); - - if(is_signed) { - if(is_negative) { - BigInt bound; - bigint_shl(&bound, &one, &bit_count_big); - bigint_deinit(dest); - *dest = bound; - } else { - BigInt bound; - bigint_shl(&bound, &one, &bit_count_big); - BigInt bound_sub_one; - bigint_sub(&bound_sub_one, &bound, &one); - bigint_deinit(&bound); - bigint_deinit(dest); - *dest = bound_sub_one; - } - } else { - BigInt bound; - bigint_shl(&bound, &one, &bit_count_big); - BigInt bound_sub_one; - bigint_sub(&bound_sub_one, &bound, &one); - bigint_deinit(&bound); - bigint_deinit(dest); - *dest = bound_sub_one; - } - } - dest->is_negative = is_negative; -} - -void bigint_add_sat(BigInt* dest, const BigInt *op1, const BigInt *op2, uint32_t bit_count, bool is_signed) { - bigint_add(dest, op1, op2); - bigint_clamp_by_bitcount(dest, bit_count, is_signed); -} - -void bigint_sub_sat(BigInt* dest, const BigInt *op1, const BigInt *op2, uint32_t bit_count, bool is_signed) { - bigint_sub(dest, op1, op2); - bigint_clamp_by_bitcount(dest, bit_count, is_signed); -} - -void bigint_mul_sat(BigInt* dest, const BigInt *op1, const BigInt *op2, uint32_t bit_count, bool is_signed) { - bigint_mul(dest, op1, op2); - bigint_clamp_by_bitcount(dest, bit_count, is_signed); -} - -void bigint_shl_sat(BigInt* dest, const BigInt *op1, const BigInt *op2, uint32_t bit_count, bool is_signed) { - bigint_shl(dest, op1, op2); - bigint_clamp_by_bitcount(dest, bit_count, is_signed); -} - -void bigint_add(BigInt *dest, const BigInt *op1, const BigInt *op2) { - if (op1->digit_count == 0) { - return bigint_init_bigint(dest, op2); - } - if (op2->digit_count == 0) { - return bigint_init_bigint(dest, op1); - } - if (op1->is_negative == op2->is_negative) { - dest->is_negative = op1->is_negative; - - const uint64_t *op1_digits = bigint_ptr(op1); - const uint64_t *op2_digits = bigint_ptr(op2); - bool overflow = add_u64_overflow(op1_digits[0], op2_digits[0], &dest->data.digit); - if (overflow == 0 && op1->digit_count == 1 && op2->digit_count == 1) { - dest->digit_count = 1; - bigint_normalize(dest); - return; - } - size_t i = 1; - uint64_t first_digit = dest->data.digit; - dest->data.digits = heap::c_allocator.allocate_nonzero(max(op1->digit_count, op2->digit_count) + 1); - dest->data.digits[0] = first_digit; - - for (;;) { - bool found_digit = false; - uint64_t x = overflow; - overflow = 0; - - if (i < op1->digit_count) { - found_digit = true; - uint64_t digit = op1_digits[i]; - overflow += add_u64_overflow(x, digit, &x); - } - - if (i < op2->digit_count) { - found_digit = true; - uint64_t digit = op2_digits[i]; - overflow += add_u64_overflow(x, digit, &x); - } - - dest->data.digits[i] = x; - i += 1; - - if (!found_digit) { - dest->digit_count = i; - bigint_normalize(dest); - return; - } - } - } - const BigInt *op_pos; - const BigInt *op_neg; - if (op1->is_negative) { - op_neg = op1; - op_pos = op2; - } else { - op_pos = op1; - op_neg = op2; - } - - BigInt op_neg_abs = {0}; - bigint_negate(&op_neg_abs, op_neg); - const BigInt *bigger_op; - const BigInt *smaller_op; - switch (bigint_cmp(op_pos, &op_neg_abs)) { - case CmpEQ: - bigint_init_unsigned(dest, 0); - return; - case CmpLT: - bigger_op = &op_neg_abs; - smaller_op = op_pos; - dest->is_negative = true; - break; - case CmpGT: - bigger_op = op_pos; - smaller_op = &op_neg_abs; - dest->is_negative = false; - break; - } - const uint64_t *bigger_op_digits = bigint_ptr(bigger_op); - const uint64_t *smaller_op_digits = bigint_ptr(smaller_op); - uint64_t overflow = sub_u64_overflow(bigger_op_digits[0], smaller_op_digits[0], &dest->data.digit); - if (overflow == 0 && bigger_op->digit_count == 1 && smaller_op->digit_count == 1) { - dest->digit_count = 1; - bigint_normalize(dest); - return; - } - uint64_t first_digit = dest->data.digit; - dest->data.digits = heap::c_allocator.allocate_nonzero(bigger_op->digit_count); - dest->data.digits[0] = first_digit; - size_t i = 1; - - for (;;) { - uint64_t x = bigger_op_digits[i]; - uint64_t prev_overflow = overflow; - overflow = 0; - - if (i < smaller_op->digit_count) { - uint64_t digit = smaller_op_digits[i]; - overflow += sub_u64_overflow(x, digit, &x); - } - - overflow += sub_u64_overflow(x, prev_overflow, &x); - dest->data.digits[i] = x; - i += 1; - - if (i >= bigger_op->digit_count) { - break; - } - } - assert(overflow == 0); - dest->digit_count = i; - bigint_normalize(dest); -} - -void bigint_add_wrap(BigInt *dest, const BigInt *op1, const BigInt *op2, size_t bit_count, bool is_signed) { - BigInt unwrapped = {0}; - bigint_add(&unwrapped, op1, op2); - bigint_truncate(dest, &unwrapped, bit_count, is_signed); -} - -void bigint_sub(BigInt *dest, const BigInt *op1, const BigInt *op2) { - BigInt op2_negated = {0}; - bigint_negate(&op2_negated, op2); - return bigint_add(dest, op1, &op2_negated); -} - -void bigint_sub_wrap(BigInt *dest, const BigInt *op1, const BigInt *op2, size_t bit_count, bool is_signed) { - BigInt op2_negated = {0}; - bigint_negate(&op2_negated, op2); - return bigint_add_wrap(dest, op1, &op2_negated, bit_count, is_signed); -} - -static void mul_overflow(uint64_t op1, uint64_t op2, uint64_t *lo, uint64_t *hi) { - uint64_t u1 = (op1 & 0xffffffff); - uint64_t v1 = (op2 & 0xffffffff); - uint64_t t = (u1 * v1); - uint64_t w3 = (t & 0xffffffff); - uint64_t k = (t >> 32); - - op1 >>= 32; - t = (op1 * v1) + k; - k = (t & 0xffffffff); - uint64_t w1 = (t >> 32); - - op2 >>= 32; - t = (u1 * op2) + k; - k = (t >> 32); - - *hi = (op1 * op2) + w1 + k; - *lo = (t << 32) + w3; -} - -static void mul_scalar(BigInt *dest, const BigInt *op, uint64_t scalar) { - bigint_init_unsigned(dest, 0); - - BigInt bi_64; - bigint_init_unsigned(&bi_64, 64); - - const uint64_t *op_digits = bigint_ptr(op); - size_t i = op->digit_count - 1; - - for (;;) { - BigInt shifted; - bigint_shl(&shifted, dest, &bi_64); - - uint64_t result_scalar; - uint64_t carry_scalar; - mul_overflow(scalar, op_digits[i], &result_scalar, &carry_scalar); - - BigInt result; - bigint_init_unsigned(&result, result_scalar); - - BigInt carry; - bigint_init_unsigned(&carry, carry_scalar); - - BigInt carry_shifted; - bigint_shl(&carry_shifted, &carry, &bi_64); - - BigInt tmp; - bigint_add(&tmp, &shifted, &carry_shifted); - - bigint_add(dest, &tmp, &result); - - if (i == 0) { - break; - } - i -= 1; - } -} - -void bigint_mul(BigInt *dest, const BigInt *op1, const BigInt *op2) { - if (op1->digit_count == 0 || op2->digit_count == 0) { - return bigint_init_unsigned(dest, 0); - } - const uint64_t *op1_digits = bigint_ptr(op1); - const uint64_t *op2_digits = bigint_ptr(op2); - - uint64_t carry; - mul_overflow(op1_digits[0], op2_digits[0], &dest->data.digit, &carry); - if (carry == 0 && op1->digit_count == 1 && op2->digit_count == 1) { - dest->is_negative = (op1->is_negative != op2->is_negative); - dest->digit_count = 1; - bigint_normalize(dest); - return; - } - - bigint_init_unsigned(dest, 0); - - BigInt bi_64; - bigint_init_unsigned(&bi_64, 64); - - size_t i = op2->digit_count - 1; - for (;;) { - BigInt shifted; - bigint_shl(&shifted, dest, &bi_64); - - BigInt scalar_result; - mul_scalar(&scalar_result, op1, op2_digits[i]); - - bigint_add(dest, &scalar_result, &shifted); - - if (i == 0) { - break; - } - i -= 1; - } - - dest->is_negative = (op1->is_negative != op2->is_negative); - bigint_normalize(dest); -} - -void bigint_mul_wrap(BigInt *dest, const BigInt *op1, const BigInt *op2, size_t bit_count, bool is_signed) { - BigInt unwrapped = {0}; - bigint_mul(&unwrapped, op1, op2); - bigint_truncate(dest, &unwrapped, bit_count, is_signed); -} - -enum ZeroBehavior { - /// \brief The returned value is undefined. - ZB_Undefined, - /// \brief The returned value is numeric_limits::max() - ZB_Max, - /// \brief The returned value is numeric_limits::digits - ZB_Width -}; - -template struct LeadingZerosCounter { - static std::size_t count(T Val, ZeroBehavior) { - if (!Val) - return std::numeric_limits::digits; - - // Bisection method. - std::size_t ZeroBits = 0; - for (T Shift = std::numeric_limits::digits >> 1; Shift; Shift >>= 1) { - T Tmp = Val >> Shift; - if (Tmp) - Val = Tmp; - else - ZeroBits |= Shift; - } - return ZeroBits; - } -}; - -#if __GNUC__ >= 4 || defined(_MSC_VER) -template struct LeadingZerosCounter { - static std::size_t count(T Val, ZeroBehavior ZB) { - if (ZB != ZB_Undefined && Val == 0) - return 32; - -#if defined(_MSC_VER) - unsigned long Index; - _BitScanReverse(&Index, Val); - return Index ^ 31; -#else - return __builtin_clz(Val); -#endif - } -}; - -#if !defined(_MSC_VER) || defined(_M_X64) -template struct LeadingZerosCounter { - static std::size_t count(T Val, ZeroBehavior ZB) { - if (ZB != ZB_Undefined && Val == 0) - return 64; - -#if defined(_MSC_VER) - unsigned long Index; - _BitScanReverse64(&Index, Val); - return Index ^ 63; -#else - return __builtin_clzll(Val); -#endif - } -}; -#endif -#endif - -/// \brief Count number of 0's from the most significant bit to the least -/// stopping at the first 1. -/// -/// Only unsigned integral types are allowed. -/// -/// \param ZB the behavior on an input of 0. Only ZB_Width and ZB_Undefined are -/// valid arguments. -template -std::size_t countLeadingZeros(T Val, ZeroBehavior ZB = ZB_Width) { - static_assert(std::numeric_limits::is_integer && - !std::numeric_limits::is_signed, - "Only unsigned integral types are allowed."); - return LeadingZerosCounter::count(Val, ZB); -} - -/// Make a 64-bit integer from a high / low pair of 32-bit integers. -constexpr inline uint64_t Make_64(uint32_t High, uint32_t Low) { - return ((uint64_t)High << 32) | (uint64_t)Low; -} - -/// Return the high 32 bits of a 64 bit value. -constexpr inline uint32_t Hi_32(uint64_t Value) { - return static_cast(Value >> 32); -} - -/// Return the low 32 bits of a 64 bit value. -constexpr inline uint32_t Lo_32(uint64_t Value) { - return static_cast(Value); -} - -/// Implementation of Knuth's Algorithm D (Division of nonnegative integers) -/// from "Art of Computer Programming, Volume 2", section 4.3.1, p. 272. The -/// variables here have the same names as in the algorithm. Comments explain -/// the algorithm and any deviation from it. -static void KnuthDiv(uint32_t *u, uint32_t *v, uint32_t *q, uint32_t* r, - unsigned m, unsigned n) -{ - assert(u && "Must provide dividend"); - assert(v && "Must provide divisor"); - assert(q && "Must provide quotient"); - assert(u != v && u != q && v != q && "Must use different memory"); - assert(n>1 && "n must be > 1"); - - // b denotes the base of the number system. In our case b is 2^32. - const uint64_t b = uint64_t(1) << 32; - - // D1. [Normalize.] Set d = b / (v[n-1] + 1) and multiply all the digits of - // u and v by d. Note that we have taken Knuth's advice here to use a power - // of 2 value for d such that d * v[n-1] >= b/2 (b is the base). A power of - // 2 allows us to shift instead of multiply and it is easy to determine the - // shift amount from the leading zeros. We are basically normalizing the u - // and v so that its high bits are shifted to the top of v's range without - // overflow. Note that this can require an extra word in u so that u must - // be of length m+n+1. - unsigned shift = countLeadingZeros(v[n-1]); - uint32_t v_carry = 0; - uint32_t u_carry = 0; - if (shift) { - for (unsigned i = 0; i < m+n; ++i) { - uint32_t u_tmp = u[i] >> (32 - shift); - u[i] = (u[i] << shift) | u_carry; - u_carry = u_tmp; - } - for (unsigned i = 0; i < n; ++i) { - uint32_t v_tmp = v[i] >> (32 - shift); - v[i] = (v[i] << shift) | v_carry; - v_carry = v_tmp; - } - } - u[m+n] = u_carry; - - // D2. [Initialize j.] Set j to m. This is the loop counter over the places. - int j = m; - do { - // D3. [Calculate q'.]. - // Set qp = (u[j+n]*b + u[j+n-1]) / v[n-1]. (qp=qprime=q') - // Set rp = (u[j+n]*b + u[j+n-1]) % v[n-1]. (rp=rprime=r') - // Now test if qp == b or qp*v[n-2] > b*rp + u[j+n-2]; if so, decrease - // qp by 1, increase rp by v[n-1], and repeat this test if rp < b. The test - // on v[n-2] determines at high speed most of the cases in which the trial - // value qp is one too large, and it eliminates all cases where qp is two - // too large. - uint64_t dividend = Make_64(u[j+n], u[j+n-1]); - uint64_t qp = dividend / v[n-1]; - uint64_t rp = dividend % v[n-1]; - if (qp == b || qp*v[n-2] > b*rp + u[j+n-2]) { - qp--; - rp += v[n-1]; - if (rp < b && (qp == b || qp*v[n-2] > b*rp + u[j+n-2])) - qp--; - } - - // D4. [Multiply and subtract.] Replace (u[j+n]u[j+n-1]...u[j]) with - // (u[j+n]u[j+n-1]..u[j]) - qp * (v[n-1]...v[1]v[0]). This computation - // consists of a simple multiplication by a one-place number, combined with - // a subtraction. - // The digits (u[j+n]...u[j]) should be kept positive; if the result of - // this step is actually negative, (u[j+n]...u[j]) should be left as the - // true value plus b**(n+1), namely as the b's complement of - // the true value, and a "borrow" to the left should be remembered. - int64_t borrow = 0; - for (unsigned i = 0; i < n; ++i) { - uint64_t p = uint64_t(qp) * uint64_t(v[i]); - int64_t subres = int64_t(u[j+i]) - borrow - Lo_32(p); - u[j+i] = Lo_32(subres); - borrow = Hi_32(p) - Hi_32(subres); - } - bool isNeg = u[j+n] < borrow; - u[j+n] -= Lo_32(borrow); - - // D5. [Test remainder.] Set q[j] = qp. If the result of step D4 was - // negative, go to step D6; otherwise go on to step D7. - q[j] = Lo_32(qp); - if (isNeg) { - // D6. [Add back]. The probability that this step is necessary is very - // small, on the order of only 2/b. Make sure that test data accounts for - // this possibility. Decrease q[j] by 1 - q[j]--; - // and add (0v[n-1]...v[1]v[0]) to (u[j+n]u[j+n-1]...u[j+1]u[j]). - // A carry will occur to the left of u[j+n], and it should be ignored - // since it cancels with the borrow that occurred in D4. - bool carry = false; - for (unsigned i = 0; i < n; i++) { - uint32_t limit = std::min(u[j+i],v[i]); - u[j+i] += v[i] + carry; - carry = u[j+i] < limit || (carry && u[j+i] == limit); - } - u[j+n] += carry; - } - - // D7. [Loop on j.] Decrease j by one. Now if j >= 0, go back to D3. - } while (--j >= 0); - - // D8. [Unnormalize]. Now q[...] is the desired quotient, and the desired - // remainder may be obtained by dividing u[...] by d. If r is non-null we - // compute the remainder (urem uses this). - if (r) { - // The value d is expressed by the "shift" value above since we avoided - // multiplication by d by using a shift left. So, all we have to do is - // shift right here. - if (shift) { - uint32_t carry = 0; - for (int i = n-1; i >= 0; i--) { - r[i] = (u[i] >> shift) | carry; - carry = u[i] << (32 - shift); - } - } else { - for (int i = n-1; i >= 0; i--) { - r[i] = u[i]; - } - } - } -} - -// Implementation ported from LLVM/lib/Support/APInt.cpp -static void bigint_unsigned_division(const BigInt *op1, const BigInt *op2, BigInt *Quotient, BigInt *Remainder) { - Cmp cmp = bigint_cmp(op1, op2); - if (cmp == CmpLT) { - if (Quotient != nullptr) { - bigint_init_unsigned(Quotient, 0); - } - if (Remainder != nullptr) { - bigint_init_bigint(Remainder, op1); - } - return; - } - if (cmp == CmpEQ) { - if (Quotient != nullptr) { - bigint_init_unsigned(Quotient, 1); - } - if (Remainder != nullptr) { - bigint_init_unsigned(Remainder, 0); - } - return; - } - - const uint64_t *LHS = bigint_ptr(op1); - const uint64_t *RHS = bigint_ptr(op2); - unsigned lhsWords = op1->digit_count; - unsigned rhsWords = op2->digit_count; - - // First, compose the values into an array of 32-bit words instead of - // 64-bit words. This is a necessity of both the "short division" algorithm - // and the Knuth "classical algorithm" which requires there to be native - // operations for +, -, and * on an m bit value with an m*2 bit result. We - // can't use 64-bit operands here because we don't have native results of - // 128-bits. Furthermore, casting the 64-bit values to 32-bit values won't - // work on large-endian machines. - unsigned n = rhsWords * 2; - unsigned m = (lhsWords * 2) - n; - - // Allocate space for the temporary values we need either on the stack, if - // it will fit, or on the heap if it won't. - uint32_t SPACE[128]; - uint32_t *U = nullptr; - uint32_t *V = nullptr; - uint32_t *Q = nullptr; - uint32_t *R = nullptr; - if ((Remainder?4:3)*n+2*m+1 <= 128) { - U = &SPACE[0]; - V = &SPACE[m+n+1]; - Q = &SPACE[(m+n+1) + n]; - if (Remainder) - R = &SPACE[(m+n+1) + n + (m+n)]; - } else { - U = new uint32_t[m + n + 1]; - V = new uint32_t[n]; - Q = new uint32_t[m+n]; - if (Remainder) - R = new uint32_t[n]; - } - - // Initialize the dividend - memset(U, 0, (m+n+1)*sizeof(uint32_t)); - for (unsigned i = 0; i < lhsWords; ++i) { - uint64_t tmp = LHS[i]; - U[i * 2] = Lo_32(tmp); - U[i * 2 + 1] = Hi_32(tmp); - } - U[m+n] = 0; // this extra word is for "spill" in the Knuth algorithm. - - // Initialize the divisor - memset(V, 0, (n)*sizeof(uint32_t)); - for (unsigned i = 0; i < rhsWords; ++i) { - uint64_t tmp = RHS[i]; - V[i * 2] = Lo_32(tmp); - V[i * 2 + 1] = Hi_32(tmp); - } - - // initialize the quotient and remainder - memset(Q, 0, (m+n) * sizeof(uint32_t)); - if (Remainder) - memset(R, 0, n * sizeof(uint32_t)); - - // Now, adjust m and n for the Knuth division. n is the number of words in - // the divisor. m is the number of words by which the dividend exceeds the - // divisor (i.e. m+n is the length of the dividend). These sizes must not - // contain any zero words or the Knuth algorithm fails. - for (unsigned i = n; i > 0 && V[i-1] == 0; i--) { - n--; - m++; - } - for (unsigned i = m+n; i > 0 && U[i-1] == 0; i--) - m--; - - // If we're left with only a single word for the divisor, Knuth doesn't work - // so we implement the short division algorithm here. This is much simpler - // and faster because we are certain that we can divide a 64-bit quantity - // by a 32-bit quantity at hardware speed and short division is simply a - // series of such operations. This is just like doing short division but we - // are using base 2^32 instead of base 10. - assert(n != 0 && "Divide by zero?"); - if (n == 1) { - uint32_t divisor = V[0]; - uint32_t remainder = 0; - for (int i = m; i >= 0; i--) { - uint64_t partial_dividend = Make_64(remainder, U[i]); - if (partial_dividend == 0) { - Q[i] = 0; - remainder = 0; - } else if (partial_dividend < divisor) { - Q[i] = 0; - remainder = Lo_32(partial_dividend); - } else if (partial_dividend == divisor) { - Q[i] = 1; - remainder = 0; - } else { - Q[i] = Lo_32(partial_dividend / divisor); - remainder = Lo_32(partial_dividend - (Q[i] * divisor)); - } - } - if (R) - R[0] = remainder; - } else { - // Now we're ready to invoke the Knuth classical divide algorithm. In this - // case n > 1. - KnuthDiv(U, V, Q, R, m, n); - } - - // If the caller wants the quotient - if (Quotient) { - Quotient->is_negative = false; - Quotient->digit_count = lhsWords; - if (lhsWords == 1) { - Quotient->data.digit = Make_64(Q[1], Q[0]); - } else { - Quotient->data.digits = heap::c_allocator.allocate(lhsWords); - for (size_t i = 0; i < lhsWords; i += 1) { - Quotient->data.digits[i] = Make_64(Q[i*2+1], Q[i*2]); - } - } - } - - // If the caller wants the remainder - if (Remainder) { - Remainder->is_negative = false; - Remainder->digit_count = rhsWords; - if (rhsWords == 1) { - Remainder->data.digit = Make_64(R[1], R[0]); - } else { - Remainder->data.digits = heap::c_allocator.allocate(rhsWords); - for (size_t i = 0; i < rhsWords; i += 1) { - Remainder->data.digits[i] = Make_64(R[i*2+1], R[i*2]); - } - } - } -} - -void bigint_div_trunc(BigInt *dest, const BigInt *op1, const BigInt *op2) { - assert(op2->digit_count != 0); // division by zero - if (op1->digit_count == 0) { - bigint_init_unsigned(dest, 0); - return; - } - const uint64_t *op1_digits = bigint_ptr(op1); - const uint64_t *op2_digits = bigint_ptr(op2); - if (op1->digit_count == 1 && op2->digit_count == 1) { - dest->data.digit = op1_digits[0] / op2_digits[0]; - dest->digit_count = 1; - dest->is_negative = op1->is_negative != op2->is_negative; - bigint_normalize(dest); - return; - } - if (op2->digit_count == 1 && op2_digits[0] == 1) { - // X / 1 == X - bigint_init_bigint(dest, op1); - dest->is_negative = op1->is_negative != op2->is_negative; - bigint_normalize(dest); - return; - } - - const BigInt *op1_positive; - BigInt op1_positive_data; - if (op1->is_negative) { - bigint_negate(&op1_positive_data, op1); - op1_positive = &op1_positive_data; - } else { - op1_positive = op1; - } - - const BigInt *op2_positive; - BigInt op2_positive_data; - if (op2->is_negative) { - bigint_negate(&op2_positive_data, op2); - op2_positive = &op2_positive_data; - } else { - op2_positive = op2; - } - - bigint_unsigned_division(op1_positive, op2_positive, dest, nullptr); - dest->is_negative = op1->is_negative != op2->is_negative; - bigint_normalize(dest); -} - -void bigint_div_floor(BigInt *dest, const BigInt *op1, const BigInt *op2) { - if (op1->is_negative != op2->is_negative) { - bigint_div_trunc(dest, op1, op2); - BigInt mult_again = {0}; - bigint_mul(&mult_again, dest, op2); - mult_again.is_negative = op1->is_negative; - if (bigint_cmp(&mult_again, op1) != CmpEQ) { - BigInt tmp = {0}; - bigint_init_bigint(&tmp, dest); - BigInt neg_one = {0}; - bigint_init_signed(&neg_one, -1); - bigint_add(dest, &tmp, &neg_one); - } - bigint_normalize(dest); - } else { - bigint_div_trunc(dest, op1, op2); - } -} - -void bigint_rem(BigInt *dest, const BigInt *op1, const BigInt *op2) { - assert(op2->digit_count != 0); // division by zero - if (op1->digit_count == 0) { - bigint_init_unsigned(dest, 0); - return; - } - const uint64_t *op1_digits = bigint_ptr(op1); - const uint64_t *op2_digits = bigint_ptr(op2); - - if (op1->digit_count == 1 && op2->digit_count == 1) { - dest->data.digit = op1_digits[0] % op2_digits[0]; - dest->digit_count = 1; - dest->is_negative = op1->is_negative; - bigint_normalize(dest); - return; - } - if (op2->digit_count == 2 && op2_digits[0] == 0 && op2_digits[1] == 1) { - // special case this divisor - bigint_init_unsigned(dest, op1_digits[0]); - dest->is_negative = op1->is_negative; - bigint_normalize(dest); - return; - } - - if (op2->digit_count == 1 && op2_digits[0] == 1) { - // X % 1 == 0 - bigint_init_unsigned(dest, 0); - return; - } - - const BigInt *op1_positive; - BigInt op1_positive_data; - if (op1->is_negative) { - bigint_negate(&op1_positive_data, op1); - op1_positive = &op1_positive_data; - } else { - op1_positive = op1; - } - - const BigInt *op2_positive; - BigInt op2_positive_data; - if (op2->is_negative) { - bigint_negate(&op2_positive_data, op2); - op2_positive = &op2_positive_data; - } else { - op2_positive = op2; - } - - bigint_unsigned_division(op1_positive, op2_positive, nullptr, dest); - dest->is_negative = op1->is_negative; - bigint_normalize(dest); -} - -void bigint_mod(BigInt *dest, const BigInt *op1, const BigInt *op2) { - if (op1->is_negative) { - BigInt first_rem; - bigint_rem(&first_rem, op1, op2); - first_rem.is_negative = !op2->is_negative; - BigInt op2_minus_rem; - bigint_add(&op2_minus_rem, op2, &first_rem); - bigint_rem(dest, &op2_minus_rem, op2); - dest->is_negative = false; - } else { - bigint_rem(dest, op1, op2); - dest->is_negative = false; - } -} - -void bigint_or(BigInt *dest, const BigInt *op1, const BigInt *op2) { - if (op1->digit_count == 0) { - return bigint_init_bigint(dest, op2); - } - if (op2->digit_count == 0) { - return bigint_init_bigint(dest, op1); - } - if (op1->is_negative || op2->is_negative) { - size_t big_bit_count = max(bigint_bits_needed(op1), bigint_bits_needed(op2)); - - BigInt twos_comp_op1 = {0}; - to_twos_complement(&twos_comp_op1, op1, big_bit_count); - - BigInt twos_comp_op2 = {0}; - to_twos_complement(&twos_comp_op2, op2, big_bit_count); - - BigInt twos_comp_dest = {0}; - bigint_or(&twos_comp_dest, &twos_comp_op1, &twos_comp_op2); - - from_twos_complement(dest, &twos_comp_dest, big_bit_count, true); - } else { - dest->is_negative = false; - const uint64_t *op1_digits = bigint_ptr(op1); - const uint64_t *op2_digits = bigint_ptr(op2); - if (op1->digit_count == 1 && op2->digit_count == 1) { - dest->digit_count = 1; - dest->data.digit = op1_digits[0] | op2_digits[0]; - bigint_normalize(dest); - return; - } - dest->digit_count = max(op1->digit_count, op2->digit_count); - dest->data.digits = heap::c_allocator.allocate_nonzero(dest->digit_count); - for (size_t i = 0; i < dest->digit_count; i += 1) { - uint64_t digit = 0; - if (i < op1->digit_count) { - digit |= op1_digits[i]; - } - if (i < op2->digit_count) { - digit |= op2_digits[i]; - } - dest->data.digits[i] = digit; - } - bigint_normalize(dest); - } -} - -void bigint_and(BigInt *dest, const BigInt *op1, const BigInt *op2) { - if (op1->digit_count == 0 || op2->digit_count == 0) { - return bigint_init_unsigned(dest, 0); - } - if (op1->is_negative || op2->is_negative) { - size_t big_bit_count = max(bigint_bits_needed(op1), bigint_bits_needed(op2)); - - BigInt twos_comp_op1 = {0}; - to_twos_complement(&twos_comp_op1, op1, big_bit_count); - - BigInt twos_comp_op2 = {0}; - to_twos_complement(&twos_comp_op2, op2, big_bit_count); - - BigInt twos_comp_dest = {0}; - bigint_and(&twos_comp_dest, &twos_comp_op1, &twos_comp_op2); - - from_twos_complement(dest, &twos_comp_dest, big_bit_count, true); - } else { - dest->is_negative = false; - const uint64_t *op1_digits = bigint_ptr(op1); - const uint64_t *op2_digits = bigint_ptr(op2); - if (op1->digit_count == 1 && op2->digit_count == 1) { - dest->digit_count = 1; - dest->data.digit = op1_digits[0] & op2_digits[0]; - bigint_normalize(dest); - return; - } - - dest->digit_count = max(op1->digit_count, op2->digit_count); - dest->data.digits = heap::c_allocator.allocate_nonzero(dest->digit_count); - - size_t i = 0; - for (; i < op1->digit_count && i < op2->digit_count; i += 1) { - dest->data.digits[i] = op1_digits[i] & op2_digits[i]; - } - for (; i < dest->digit_count; i += 1) { - dest->data.digits[i] = 0; - } - bigint_normalize(dest); - } -} - -void bigint_xor(BigInt *dest, const BigInt *op1, const BigInt *op2) { - if (op1->digit_count == 0) { - return bigint_init_bigint(dest, op2); - } - if (op2->digit_count == 0) { - return bigint_init_bigint(dest, op1); - } - if (op1->is_negative || op2->is_negative) { - size_t big_bit_count = max(bigint_bits_needed(op1), bigint_bits_needed(op2)); - - BigInt twos_comp_op1 = {0}; - to_twos_complement(&twos_comp_op1, op1, big_bit_count); - - BigInt twos_comp_op2 = {0}; - to_twos_complement(&twos_comp_op2, op2, big_bit_count); - - BigInt twos_comp_dest = {0}; - bigint_xor(&twos_comp_dest, &twos_comp_op1, &twos_comp_op2); - - from_twos_complement(dest, &twos_comp_dest, big_bit_count, true); - } else { - dest->is_negative = false; - const uint64_t *op1_digits = bigint_ptr(op1); - const uint64_t *op2_digits = bigint_ptr(op2); - - assert(op1->digit_count > 0 && op2->digit_count > 0); - if (op1->digit_count == 1 && op2->digit_count == 1) { - dest->digit_count = 1; - dest->data.digit = op1_digits[0] ^ op2_digits[0]; - bigint_normalize(dest); - return; - } - dest->digit_count = max(op1->digit_count, op2->digit_count); - dest->data.digits = heap::c_allocator.allocate_nonzero(dest->digit_count); - size_t i = 0; - for (; i < op1->digit_count && i < op2->digit_count; i += 1) { - dest->data.digits[i] = op1_digits[i] ^ op2_digits[i]; - } - for (; i < dest->digit_count; i += 1) { - if (i < op1->digit_count) { - dest->data.digits[i] = op1_digits[i]; - } else if (i < op2->digit_count) { - dest->data.digits[i] = op2_digits[i]; - } else { - zig_unreachable(); - } - } - bigint_normalize(dest); - } -} - -void bigint_shl(BigInt *dest, const BigInt *op1, const BigInt *op2) { - assert(!op2->is_negative); - - if (op2->digit_count == 0) { - bigint_init_bigint(dest, op1); - return; - } - - if (op1->digit_count == 0) { - bigint_init_unsigned(dest, 0); - return; - } - - if (op2->digit_count != 1) { - zig_panic("TODO shift left by amount greater than 64 bit integer"); - } - - const uint64_t *op1_digits = bigint_ptr(op1); - uint64_t shift_amt = bigint_as_unsigned(op2); - - if (op1->digit_count == 1 && shift_amt < 64) { - dest->data.digit = op1_digits[0] << shift_amt; - if (dest->data.digit >> shift_amt == op1_digits[0]) { - dest->digit_count = 1; - dest->is_negative = op1->is_negative; - return; - } - } - - uint64_t digit_shift_count = shift_amt / 64; - uint64_t leftover_shift_count = shift_amt % 64; - - dest->data.digits = heap::c_allocator.allocate(op1->digit_count + digit_shift_count + 1); - dest->digit_count = digit_shift_count; - uint64_t carry = 0; - for (size_t i = 0; i < op1->digit_count; i += 1) { - uint64_t digit = op1_digits[i]; - dest->data.digits[dest->digit_count] = carry | (digit << leftover_shift_count); - dest->digit_count += 1; - if (leftover_shift_count > 0) { - carry = digit >> (64 - leftover_shift_count); - } else { - carry = 0; - } - } - dest->data.digits[dest->digit_count] = carry; - dest->digit_count += 1; - dest->is_negative = op1->is_negative; - bigint_normalize(dest); -} - -void bigint_shl_trunc(BigInt *dest, const BigInt *op1, const BigInt *op2, size_t bit_count, bool is_signed) { - BigInt unwrapped = {0}; - bigint_shl(&unwrapped, op1, op2); - bigint_truncate(dest, &unwrapped, bit_count, is_signed); -} - -void bigint_shr(BigInt *dest, const BigInt *op1, const BigInt *op2) { - assert(!op2->is_negative); - - if (op1->digit_count == 0) { - return bigint_init_unsigned(dest, 0); - } - - if (op2->digit_count == 0) { - return bigint_init_bigint(dest, op1); - } - - if (op2->digit_count != 1) { - zig_panic("TODO shift right by amount greater than 64 bit integer"); - } - - const uint64_t *op1_digits = bigint_ptr(op1); - uint64_t shift_amt = bigint_as_unsigned(op2); - - if (op1->digit_count == 1) { - dest->data.digit = (shift_amt < 64) ? op1_digits[0] >> shift_amt : 0; - dest->digit_count = 1; - dest->is_negative = op1->is_negative; - bigint_normalize(dest); - return; - } - - size_t digit_shift_count = shift_amt / 64; - size_t leftover_shift_count = shift_amt % 64; - - if (digit_shift_count >= op1->digit_count) { - return bigint_init_unsigned(dest, 0); - } - - dest->digit_count = op1->digit_count - digit_shift_count; - uint64_t *digits; - if (dest->digit_count == 1) { - digits = &dest->data.digit; - } else { - digits = heap::c_allocator.allocate(dest->digit_count); - dest->data.digits = digits; - } - - uint64_t carry = 0; - for (size_t op_digit_index = op1->digit_count - 1;;) { - uint64_t digit = op1_digits[op_digit_index]; - size_t dest_digit_index = op_digit_index - digit_shift_count; - digits[dest_digit_index] = carry | (digit >> leftover_shift_count); - carry = (leftover_shift_count != 0) ? (digit << (64 - leftover_shift_count)) : 0; - - if (dest_digit_index == 0) { break; } - op_digit_index -= 1; - } - dest->is_negative = op1->is_negative; - bigint_normalize(dest); -} - -void bigint_negate(BigInt *dest, const BigInt *op) { - bigint_init_bigint(dest, op); - dest->is_negative = !dest->is_negative; - bigint_normalize(dest); -} - -void bigint_negate_wrap(BigInt *dest, const BigInt *op, size_t bit_count, bool is_signed) { - BigInt zero; - bigint_init_unsigned(&zero, 0); - bigint_sub_wrap(dest, &zero, op, bit_count, is_signed); -} - -void bigint_not(BigInt *dest, const BigInt *op, size_t bit_count, bool is_signed) { - if (bit_count == 0) { - bigint_init_unsigned(dest, 0); - return; - } - - if (is_signed) { - BigInt twos_comp = {0}; - to_twos_complement(&twos_comp, op, bit_count); - - BigInt inverted = {0}; - bigint_not(&inverted, &twos_comp, bit_count, false); - - from_twos_complement(dest, &inverted, bit_count, true); - return; - } - - assert(!op->is_negative); - - dest->is_negative = false; - const uint64_t *op_digits = bigint_ptr(op); - if (bit_count <= 64) { - dest->digit_count = 1; - if (op->digit_count == 0) { - if (bit_count == 64) { - dest->data.digit = UINT64_MAX; - } else { - dest->data.digit = (1ULL << bit_count) - 1; - } - } else if (op->digit_count == 1) { - dest->data.digit = ~op_digits[0]; - if (bit_count != 64) { - uint64_t mask = (1ULL << bit_count) - 1; - dest->data.digit &= mask; - } - } - bigint_normalize(dest); - return; - } - dest->digit_count = (bit_count + 63) / 64; - assert(dest->digit_count >= op->digit_count); - dest->data.digits = heap::c_allocator.allocate_nonzero(dest->digit_count); - size_t i = 0; - for (; i < op->digit_count; i += 1) { - dest->data.digits[i] = ~op_digits[i]; - } - for (; i < dest->digit_count; i += 1) { - dest->data.digits[i] = 0xffffffffffffffffULL; - } - size_t digit_index = dest->digit_count - 1; - size_t digit_bit_index = bit_count % 64; - if (digit_bit_index != 0) { - uint64_t mask = (1ULL << digit_bit_index) - 1; - dest->data.digits[digit_index] &= mask; - } - bigint_normalize(dest); -} - -void bigint_truncate(BigInt *dest, const BigInt *op, size_t bit_count, bool is_signed) { - BigInt twos_comp; - to_twos_complement(&twos_comp, op, bit_count); - from_twos_complement(dest, &twos_comp, bit_count, is_signed); -} - -Cmp bigint_cmp(const BigInt *op1, const BigInt *op2) { - if (op1->is_negative && !op2->is_negative) { - return CmpLT; - } else if (!op1->is_negative && op2->is_negative) { - return CmpGT; - } else if (op1->digit_count > op2->digit_count) { - return op1->is_negative ? CmpLT : CmpGT; - } else if (op2->digit_count > op1->digit_count) { - return op1->is_negative ? CmpGT : CmpLT; - } else if (op1->digit_count == 0) { - return CmpEQ; - } - const uint64_t *op1_digits = bigint_ptr(op1); - const uint64_t *op2_digits = bigint_ptr(op2); - for (size_t i = op1->digit_count - 1; ;) { - uint64_t op1_digit = op1_digits[i]; - uint64_t op2_digit = op2_digits[i]; - - if (op1_digit > op2_digit) { - return op1->is_negative ? CmpLT : CmpGT; - } - if (op1_digit < op2_digit) { - return op1->is_negative ? CmpGT : CmpLT; - } - - if (i == 0) { - return CmpEQ; - } - i -= 1; - } -} - -void bigint_append_buf(Buf *buf, const BigInt *op, uint64_t base) { - if (op->digit_count == 0) { - buf_append_char(buf, '0'); - return; - } - if (op->is_negative) { - buf_append_char(buf, '-'); - } - if (op->digit_count == 1 && base == 10) { - buf_appendf(buf, "%" ZIG_PRI_u64, op->data.digit); - return; - } - if (op->digit_count == 1 && base == 16) { - buf_appendf(buf, "%" ZIG_PRI_x64, op->data.digit); - return; - } - size_t first_digit_index = buf_len(buf); - - BigInt digit_bi = {0}; - BigInt a1 = {0}; - BigInt a2 = {0}; - - BigInt *a = &a1; - BigInt *other_a = &a2; - bigint_init_bigint(a, op); - - BigInt base_bi = {0}; - bigint_init_unsigned(&base_bi, base); - - for (;;) { - bigint_rem(&digit_bi, a, &base_bi); - uint8_t digit = bigint_as_unsigned(&digit_bi); - buf_append_char(buf, digit_to_char(digit, false)); - bigint_div_trunc(other_a, a, &base_bi); - { - BigInt *tmp = a; - a = other_a; - other_a = tmp; - } - if (bigint_cmp_zero(a) == CmpEQ) { - break; - } - } - - // reverse - for (size_t i = first_digit_index; i < buf_len(buf) / 2; i += 1) { - size_t other_i = buf_len(buf) + first_digit_index - i - 1; - uint8_t tmp = buf_ptr(buf)[i]; - buf_ptr(buf)[i] = buf_ptr(buf)[other_i]; - buf_ptr(buf)[other_i] = tmp; - } -} - -size_t bigint_popcount_unsigned(const BigInt *bi) { - assert(!bi->is_negative); - if (bi->digit_count == 0) - return 0; - - size_t count = 0; - size_t bit_count = bi->digit_count * 64; - for (size_t i = 0; i < bit_count; i += 1) { - if (bit_at_index(bi, i)) - count += 1; - } - return count; -} - -size_t bigint_popcount_signed(const BigInt *bi, size_t bit_count) { - if (bit_count == 0) - return 0; - if (bi->digit_count == 0) - return 0; - - BigInt twos_comp = {0}; - to_twos_complement(&twos_comp, bi, bit_count); - - size_t count = 0; - for (size_t i = 0; i < bit_count; i += 1) { - if (bit_at_index(&twos_comp, i)) - count += 1; - } - return count; -} - -size_t bigint_ctz(const BigInt *bi, size_t bit_count) { - if (bit_count == 0) - return 0; - if (bi->digit_count == 0) - return bit_count; - - BigInt twos_comp = {0}; - to_twos_complement(&twos_comp, bi, bit_count); - - size_t count = 0; - for (size_t i = 0; i < bit_count; i += 1) { - if (bit_at_index(&twos_comp, i)) - return count; - count += 1; - } - return count; -} - -size_t bigint_clz(const BigInt *bi, size_t bit_count) { - if (bi->is_negative || bit_count == 0) - return 0; - if (bi->digit_count == 0) - return bit_count; - - size_t count = 0; - for (size_t i = bit_count - 1;;) { - if (bit_at_index(bi, i)) - return count; - count += 1; - - if (i == 0) break; - i -= 1; - } - return count; -} - -static uint64_t bigint_as_unsigned(const BigInt *bigint) { - assert(!bigint->is_negative); - if (bigint->digit_count == 0) { - return 0; - } else if (bigint->digit_count == 1) { - return bigint->data.digit; - } else { - zig_unreachable(); - } -} - -uint64_t bigint_as_u64(const BigInt *bigint) -{ - return bigint_as_unsigned(bigint); -} - -uint32_t bigint_as_u32(const BigInt *bigint) { - uint64_t value64 = bigint_as_unsigned(bigint); - uint32_t value32 = (uint32_t)value64; - assert (value64 == value32); - return value32; -} - -uint8_t bigint_as_u8(const BigInt *bigint) { - uint64_t value64 = bigint_as_unsigned(bigint); - uint8_t value8 = (uint8_t)value64; - assert (value64 == value8); - return value8; -} - -size_t bigint_as_usize(const BigInt *bigint) { - uint64_t value64 = bigint_as_unsigned(bigint); - size_t valueUsize = (size_t)value64; - assert (value64 == valueUsize); - return valueUsize; -} - -int64_t bigint_as_signed(const BigInt *bigint) { - if (bigint->digit_count == 0) { - return 0; - } else if (bigint->digit_count == 1) { - if (bigint->is_negative) { - if (bigint->data.digit <= 9223372036854775808ULL) { - return (-((int64_t)(bigint->data.digit - 1))) - 1; - } else { - zig_unreachable(); - } - } else { - return bigint->data.digit; - } - } else { - zig_unreachable(); - } -} - -Cmp bigint_cmp_zero(const BigInt *op) { - if (op->digit_count == 0) { - return CmpEQ; - } - return op->is_negative ? CmpLT : CmpGT; -} - -uint32_t bigint_hash(BigInt const *x) { - if (x->digit_count == 0) { - return 0; - } else { - return bigint_ptr(x)[0]; - } -} - -bool bigint_eql(BigInt const *a, BigInt const *b) { - return bigint_cmp(a, b) == CmpEQ; -} - -void bigint_incr(BigInt *x) { - if (x->digit_count == 0) { - bigint_init_unsigned(x, 1); - return; - } - - if (x->digit_count == 1) { - if (x->is_negative && x->data.digit != 0) { - x->data.digit -= 1; - return; - } else if (!x->is_negative && x->data.digit != UINT64_MAX) { - x->data.digit += 1; - return; - } - } - - BigInt copy; - bigint_init_bigint(©, x); - - BigInt one; - bigint_init_unsigned(&one, 1); - - bigint_add(x, ©, &one); -} - -void bigint_decr(BigInt *x) { - if (x->digit_count == 0) { - bigint_init_signed(x, -1); - return; - } - - if (x->digit_count == 1) { - if (x->is_negative && x->data.digit != UINT64_MAX) { - x->data.digit += 1; - return; - } else if (!x->is_negative && x->data.digit != 0) { - x->data.digit -= 1; - return; - } - } - - BigInt copy; - bigint_init_bigint(©, x); - - BigInt neg_one; - bigint_init_signed(&neg_one, -1); - - bigint_add(x, ©, &neg_one); -} diff --git a/src/stage1/bigint.hpp b/src/stage1/bigint.hpp deleted file mode 100644 index 7d30fb168970..000000000000 --- a/src/stage1/bigint.hpp +++ /dev/null @@ -1,112 +0,0 @@ -/* - * Copyright (c) 2017 Andrew Kelley - * - * This file is part of zig, which is MIT licensed. - * See http://opensource.org/licenses/MIT - */ - -#ifndef ZIG_BIGINT_HPP -#define ZIG_BIGINT_HPP - -#include -#include - -struct BigInt { - size_t digit_count; - union { - uint64_t digit; - uint64_t *digits; // Least significant digit first - } data; - bool is_negative; -}; - -struct Buf; -struct BigFloat; - -enum Cmp { - CmpLT, - CmpGT, - CmpEQ, -}; - -void bigint_init_unsigned(BigInt *dest, uint64_t x); -void bigint_init_signed(BigInt *dest, int64_t x); -void bigint_init_bigint(BigInt *dest, const BigInt *src); -void bigint_init_bigfloat(BigInt *dest, const BigFloat *op); -void bigint_init_data(BigInt *dest, const uint64_t *digits, size_t digit_count, bool is_negative); -void bigint_deinit(BigInt *bi); - -// panics if number won't fit -uint64_t bigint_as_u64(const BigInt *bigint); -uint32_t bigint_as_u32(const BigInt *bigint); -uint8_t bigint_as_u8(const BigInt *bigint); -size_t bigint_as_usize(const BigInt *bigint); - -int64_t bigint_as_signed(const BigInt *bigint); - -static inline const uint64_t *bigint_ptr(const BigInt *bigint) { - if (bigint->digit_count == 1) { - return &bigint->data.digit; - } else { - return bigint->data.digits; - } -} - -bool bigint_fits_in_bits(const BigInt *bn, size_t bit_count, bool is_signed); -void bigint_write_twos_complement(const BigInt *big_int, uint8_t *buf, size_t bit_count, bool is_big_endian); -void bigint_read_twos_complement(BigInt *dest, const uint8_t *buf, size_t bit_count, bool is_big_endian, - bool is_signed); -void bigint_max(BigInt* dest, const BigInt *op1, const BigInt *op2); -void bigint_min(BigInt* dest, const BigInt *op1, const BigInt *op2); -void bigint_add(BigInt *dest, const BigInt *op1, const BigInt *op2); -void bigint_add_wrap(BigInt *dest, const BigInt *op1, const BigInt *op2, size_t bit_count, bool is_signed); -void bigint_sub(BigInt *dest, const BigInt *op1, const BigInt *op2); -void bigint_sub_wrap(BigInt *dest, const BigInt *op1, const BigInt *op2, size_t bit_count, bool is_signed); -void bigint_mul(BigInt *dest, const BigInt *op1, const BigInt *op2); -void bigint_mul_wrap(BigInt *dest, const BigInt *op1, const BigInt *op2, size_t bit_count, bool is_signed); -void bigint_div_trunc(BigInt *dest, const BigInt *op1, const BigInt *op2); -void bigint_div_floor(BigInt *dest, const BigInt *op1, const BigInt *op2); -void bigint_rem(BigInt *dest, const BigInt *op1, const BigInt *op2); -void bigint_mod(BigInt *dest, const BigInt *op1, const BigInt *op2); - -void bigint_or(BigInt *dest, const BigInt *op1, const BigInt *op2); -void bigint_and(BigInt *dest, const BigInt *op1, const BigInt *op2); -void bigint_xor(BigInt *dest, const BigInt *op1, const BigInt *op2); - -void bigint_shl(BigInt *dest, const BigInt *op1, const BigInt *op2); -void bigint_shl_trunc(BigInt *dest, const BigInt *op1, const BigInt *op2, size_t bit_count, bool is_signed); -void bigint_shr(BigInt *dest, const BigInt *op1, const BigInt *op2); - -void bigint_negate(BigInt *dest, const BigInt *op); -void bigint_negate_wrap(BigInt *dest, const BigInt *op, size_t bit_count, bool is_signed); -void bigint_not(BigInt *dest, const BigInt *op, size_t bit_count, bool is_signed); -void bigint_truncate(BigInt *dest, const BigInt *op, size_t bit_count, bool is_signed); - -Cmp bigint_cmp(const BigInt *op1, const BigInt *op2); - -void bigint_append_buf(Buf *buf, const BigInt *op, uint64_t base); - -size_t bigint_ctz(const BigInt *bi, size_t bit_count); -size_t bigint_clz(const BigInt *bi, size_t bit_count); -size_t bigint_popcount_signed(const BigInt *bi, size_t bit_count); -size_t bigint_popcount_unsigned(const BigInt *bi); - -size_t bigint_bits_needed(const BigInt *op); - - -// convenience functions -Cmp bigint_cmp_zero(const BigInt *op); - -void bigint_incr(BigInt *value); -void bigint_decr(BigInt *value); - -bool mul_u64_overflow(uint64_t op1, uint64_t op2, uint64_t *result); - -uint32_t bigint_hash(BigInt const *x); -bool bigint_eql(BigInt const *a, BigInt const *b); - -void bigint_add_sat(BigInt* dest, const BigInt *op1, const BigInt *op2, uint32_t bit_count, bool is_signed); -void bigint_sub_sat(BigInt* dest, const BigInt *op1, const BigInt *op2, uint32_t bit_count, bool is_signed); -void bigint_mul_sat(BigInt* dest, const BigInt *op1, const BigInt *op2, uint32_t bit_count, bool is_signed); -void bigint_shl_sat(BigInt* dest, const BigInt *op1, const BigInt *op2, uint32_t bit_count, bool is_signed); -#endif diff --git a/src/stage1/buffer.cpp b/src/stage1/buffer.cpp deleted file mode 100644 index 86435e0f1496..000000000000 --- a/src/stage1/buffer.cpp +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright (c) 2016 Andrew Kelley - * - * This file is part of zig, which is MIT licensed. - * See http://opensource.org/licenses/MIT - */ - -#include "buffer.hpp" -#include -#include -#include - -Buf *buf_vprintf(const char *format, va_list ap) { - va_list ap2; - va_copy(ap2, ap); - - int len1 = vsnprintf(nullptr, 0, format, ap); - assert(len1 >= 0); - - size_t required_size = len1 + 1; - - Buf *buf = buf_alloc_fixed(len1); - - int len2 = vsnprintf(buf_ptr(buf), required_size, format, ap2); - assert(len2 == len1); - - va_end(ap2); - - return buf; -} - -Buf *buf_sprintf(const char *format, ...) { - va_list ap; - va_start(ap, format); - Buf *result = buf_vprintf(format, ap); - va_end(ap); - return result; -} - -void buf_appendf(Buf *buf, const char *format, ...) { - assert(buf->list.length); - va_list ap, ap2; - va_start(ap, format); - va_copy(ap2, ap); - - int len1 = vsnprintf(nullptr, 0, format, ap); - assert(len1 >= 0); - - size_t required_size = len1 + 1; - - size_t orig_len = buf_len(buf); - - buf_resize(buf, orig_len + len1); - - int len2 = vsnprintf(buf_ptr(buf) + orig_len, required_size, format, ap2); - assert(len2 == len1); - - va_end(ap2); - va_end(ap); -} - -// these functions are not static inline so they can be better used as template parameters -bool buf_eql_buf(Buf *buf, Buf *other) { - return buf_eql_mem(buf, buf_ptr(other), buf_len(other)); -} - -uint32_t buf_hash(Buf *buf) { - assert(buf->list.length); - size_t interval = buf->list.length / 256; - if (interval == 0) - interval = 1; - // FNV 32-bit hash - uint32_t h = 2166136261; - for (size_t i = 0; i < buf_len(buf); i += interval) { - h = h ^ ((uint8_t)buf->list.at(i)); - h = h * 16777619; - } - return h; -} diff --git a/src/stage1/buffer.hpp b/src/stage1/buffer.hpp deleted file mode 100644 index d8a31b1bf416..000000000000 --- a/src/stage1/buffer.hpp +++ /dev/null @@ -1,211 +0,0 @@ -/* - * Copyright (c) 2015 Andrew Kelley - * - * This file is part of zig, which is MIT licensed. - * See http://opensource.org/licenses/MIT - */ - -#ifndef ZIG_BUFFER_HPP -#define ZIG_BUFFER_HPP - -#include "list.hpp" - -#include -#include -#include - -#define BUF_INIT {{0}} - -// Note, you must call one of the alloc, init, or resize functions to have an -// initialized buffer. The assertions should help with this. -struct Buf { - ZigList list; -}; - -Buf *buf_sprintf(const char *format, ...) - ATTRIBUTE_PRINTF(1, 2); -Buf *buf_vprintf(const char *format, va_list ap); - -static inline size_t buf_len(const Buf *buf) { - assert(buf); - assert(buf->list.length); - return buf->list.length - 1; -} - -static inline char *buf_ptr(Buf *buf) { - assert(buf); - assert(buf->list.length); - return buf->list.items; -} - -static inline const char *buf_ptr(const Buf *buf) { - assert(buf); - assert(buf->list.length); - return buf->list.items; -} - -static inline void buf_resize(Buf *buf, size_t new_len) { - buf->list.resize(new_len + 1); - buf->list.at(buf_len(buf)) = 0; -} - -static inline Buf *buf_alloc_fixed(size_t size) { - Buf *buf = heap::c_allocator.create(); - buf_resize(buf, size); - return buf; -} - -static inline Buf *buf_alloc(void) { - return buf_alloc_fixed(0); -} - -static inline void buf_deinit(Buf *buf) { - buf->list.deinit(); -} - -static inline void buf_destroy(Buf *buf) { - buf_deinit(buf); - heap::c_allocator.destroy(buf); -} - -static inline void buf_init_from_mem(Buf *buf, const char *ptr, size_t len) { - assert(len != SIZE_MAX); - buf->list.resize(len + 1); - memcpy(buf_ptr(buf), ptr, len); - buf->list.at(buf_len(buf)) = 0; -} - -static inline void buf_init_from_str(Buf *buf, const char *str) { - buf_init_from_mem(buf, str, strlen(str)); -} - -static inline void buf_init_from_buf(Buf *buf, Buf *other) { - buf_init_from_mem(buf, buf_ptr(other), buf_len(other)); -} - -static inline Buf *buf_create_from_mem(const char *ptr, size_t len) { - assert(len != SIZE_MAX); - Buf *buf = heap::c_allocator.create(); - buf_init_from_mem(buf, ptr, len); - return buf; -} - -static inline Buf *buf_create_from_slice(Slice slice) { - return buf_create_from_mem((const char *)slice.ptr, slice.len); -} - -static inline Buf *buf_create_from_str(const char *str) { - return buf_create_from_mem(str, strlen(str)); -} - -static inline Buf *buf_create_from_buf(Buf *buf) { - return buf_create_from_mem(buf_ptr(buf), buf_len(buf)); -} - -static inline Buf *buf_slice(Buf *in_buf, size_t start, size_t end) { - assert(in_buf->list.length); - assert(start != SIZE_MAX); - assert(end != SIZE_MAX); - assert(start < buf_len(in_buf)); - assert(end <= buf_len(in_buf)); - Buf *out_buf = heap::c_allocator.create(); - out_buf->list.resize(end - start + 1); - memcpy(buf_ptr(out_buf), buf_ptr(in_buf) + start, end - start); - out_buf->list.at(buf_len(out_buf)) = 0; - return out_buf; -} - -static inline void buf_append_mem(Buf *buf, const char *mem, size_t mem_len) { - assert(buf->list.length); - assert(mem_len != SIZE_MAX); - size_t old_len = buf_len(buf); - buf_resize(buf, old_len + mem_len); - memcpy(buf_ptr(buf) + old_len, mem, mem_len); - buf->list.at(buf_len(buf)) = 0; -} - -static inline void buf_append_str(Buf *buf, const char *str) { - assert(buf->list.length); - buf_append_mem(buf, str, strlen(str)); -} - -static inline void buf_append_buf(Buf *buf, Buf *append_buf) { - assert(buf->list.length); - buf_append_mem(buf, buf_ptr(append_buf), buf_len(append_buf)); -} - -static inline void buf_append_char(Buf *buf, uint8_t c) { - assert(buf->list.length); - buf_append_mem(buf, (const char *)&c, 1); -} - -void buf_appendf(Buf *buf, const char *format, ...) - ATTRIBUTE_PRINTF(2, 3); - -static inline bool buf_eql_mem(Buf *buf, const char *mem, size_t mem_len) { - assert(buf->list.length); - return mem_eql_mem(buf_ptr(buf), buf_len(buf), mem, mem_len); -} - -static inline bool buf_eql_mem_ignore_case(Buf *buf, const char *mem, size_t mem_len) { - assert(buf->list.length); - return mem_eql_mem_ignore_case(buf_ptr(buf), buf_len(buf), mem, mem_len); -} - -static inline bool buf_eql_str(Buf *buf, const char *str) { - assert(buf->list.length); - return buf_eql_mem(buf, str, strlen(str)); -} - -static inline bool buf_eql_str_ignore_case(Buf *buf, const char *str) { - assert(buf->list.length); - return buf_eql_mem_ignore_case(buf, str, strlen(str)); -} - -static inline bool buf_starts_with_mem(Buf *buf, const char *mem, size_t mem_len) { - if (buf_len(buf) < mem_len) { - return false; - } - return memcmp(buf_ptr(buf), mem, mem_len) == 0; -} - -static inline bool buf_starts_with_buf(Buf *buf, Buf *sub) { - return buf_starts_with_mem(buf, buf_ptr(sub), buf_len(sub)); -} - -static inline bool buf_starts_with_str(Buf *buf, const char *str) { - return buf_starts_with_mem(buf, str, strlen(str)); -} - -static inline bool buf_ends_with_mem(Buf *buf, const char *mem, size_t mem_len) { - return mem_ends_with_mem(buf_ptr(buf), buf_len(buf), mem, mem_len); -} - -static inline bool buf_ends_with_str(Buf *buf, const char *str) { - return buf_ends_with_mem(buf, str, strlen(str)); -} - -bool buf_eql_buf(Buf *buf, Buf *other); -uint32_t buf_hash(Buf *buf); - -static inline void buf_upcase(Buf *buf) { - for (size_t i = 0; i < buf_len(buf); i += 1) { - buf_ptr(buf)[i] = (char)toupper(buf_ptr(buf)[i]); - } -} - -static inline Slice buf_to_slice(Buf *buf) { - return Slice{reinterpret_cast(buf_ptr(buf)), buf_len(buf)}; -} - -static inline void buf_replace(Buf* buf, char from, char to) { - const size_t count = buf_len(buf); - char* ptr = buf_ptr(buf); - for (size_t i = 0; i < count; ++i) { - char& l = ptr[i]; - if (l == from) - l = to; - } -} - -#endif diff --git a/src/stage1/codegen.cpp b/src/stage1/codegen.cpp deleted file mode 100644 index 0b6523edec40..000000000000 --- a/src/stage1/codegen.cpp +++ /dev/null @@ -1,11034 +0,0 @@ -/* - * Copyright (c) 2015 Andrew Kelley - * - * This file is part of zig, which is MIT licensed. - * See http://opensource.org/licenses/MIT - */ - -#include "analyze.hpp" -#include "codegen.hpp" -#include "errmsg.hpp" -#include "error.hpp" -#include "hash_map.hpp" -#include "ir.hpp" -#include "os.hpp" -#include "target.hpp" -#include "util.hpp" -#include "zig_llvm.h" -#include "stage2.h" -#include "softfloat.hpp" -#include "zigendian.h" - -#include -#include -#include -#include - -enum ResumeId { - ResumeIdManual, - ResumeIdReturn, - ResumeIdCall, -}; - -static ZigPackage *new_package(const char *root_src_dir, const char *root_src_path, const char *pkg_path) { - ZigPackage *entry = heap::c_allocator.create(); - entry->package_table.init(4); - buf_init_from_str(&entry->root_src_dir, root_src_dir); - buf_init_from_str(&entry->root_src_path, root_src_path); - buf_init_from_str(&entry->pkg_path, pkg_path); - return entry; -} - -ZigPackage *new_anonymous_package() { - return new_package("", "", ""); -} - -static const char *symbols_that_llvm_depends_on[] = { - "memcpy", - "memset", - "sqrt", - "powi", - "sin", - "cos", - "pow", - "exp", - "exp2", - "log", - "log10", - "log2", - "fma", - "fmaf", - "fmal", - "fmaq", - "fabs", - "minnum", - "maxnum", - "copysign", - "floor", - "ceil", - "trunc", - "rint", - "nearbyint", - "round", - // TODO probably all of compiler-rt needs to go here -}; - -void codegen_set_strip(CodeGen *g, bool strip) { - g->strip_debug_symbols = strip; - if (!target_has_debug_info(g->zig_target)) { - g->strip_debug_symbols = true; - } -} - -static LLVMValueRef get_soft_float_fn(CodeGen *g, const char *name, int param_count, LLVMTypeRef param_type, LLVMTypeRef return_type); -static void render_const_val(CodeGen *g, ZigValue *const_val, const char *name); -static void render_const_val_global(CodeGen *g, ZigValue *const_val, const char *name); -static LLVMValueRef gen_const_val(CodeGen *g, ZigValue *const_val, const char *name); -static void generate_error_name_table(CodeGen *g); -static bool value_is_all_undef(CodeGen *g, ZigValue *const_val); -static void gen_undef_init(CodeGen *g, ZigType *ptr_type, ZigType *value_type, LLVMValueRef ptr); -static LLVMValueRef build_alloca(CodeGen *g, ZigType *type_entry, const char *name, uint32_t alignment); -static LLVMValueRef gen_await_early_return(CodeGen *g, Stage1AirInst *source_instr, - LLVMTypeRef target_frame_struct_llvm_ty, LLVMValueRef target_frame_ptr, - ZigType *result_type, ZigType *ptr_result_type, LLVMValueRef result_loc, bool non_async); - -static void addLLVMAttr(LLVMValueRef val, LLVMAttributeIndex attr_index, const char *attr_name) { - unsigned kind_id = LLVMGetEnumAttributeKindForName(attr_name, strlen(attr_name)); - assert(kind_id != 0); - LLVMAttributeRef llvm_attr = LLVMCreateEnumAttribute(LLVMGetGlobalContext(), kind_id, 0); - LLVMAddAttributeAtIndex(val, attr_index, llvm_attr); -} - -static void addLLVMAttrStr(LLVMValueRef val, LLVMAttributeIndex attr_index, - const char *attr_name, const char *attr_val) -{ - LLVMAttributeRef llvm_attr = LLVMCreateStringAttribute(LLVMGetGlobalContext(), - attr_name, (unsigned)strlen(attr_name), attr_val, (unsigned)strlen(attr_val)); - LLVMAddAttributeAtIndex(val, attr_index, llvm_attr); -} - -static void addLLVMAttrInt(LLVMValueRef val, LLVMAttributeIndex attr_index, - const char *attr_name, uint64_t attr_val) -{ - unsigned kind_id = LLVMGetEnumAttributeKindForName(attr_name, strlen(attr_name)); - assert(kind_id != 0); - LLVMAttributeRef llvm_attr = LLVMCreateEnumAttribute(LLVMGetGlobalContext(), kind_id, attr_val); - LLVMAddAttributeAtIndex(val, attr_index, llvm_attr); -} - -static void addLLVMFnAttr(LLVMValueRef fn_val, const char *attr_name) { - return addLLVMAttr(fn_val, -1, attr_name); -} - -static void addLLVMFnAttrStr(LLVMValueRef fn_val, const char *attr_name, const char *attr_val) { - return addLLVMAttrStr(fn_val, -1, attr_name, attr_val); -} - -static void addLLVMFnAttrInt(LLVMValueRef fn_val, const char *attr_name, uint64_t attr_val) { - return addLLVMAttrInt(fn_val, -1, attr_name, attr_val); -} - -static void addLLVMArgAttr(LLVMValueRef fn_val, unsigned param_index, const char *attr_name) { - return addLLVMAttr(fn_val, param_index + 1, attr_name); -} - -static void addLLVMArgAttrInt(LLVMValueRef fn_val, unsigned param_index, const char *attr_name, uint64_t attr_val) { - return addLLVMAttrInt(fn_val, param_index + 1, attr_name, attr_val); -} - -static bool is_symbol_available(CodeGen *g, const char *name) { - Buf *buf_name = buf_create_from_str(name); - bool result = - g->exported_symbol_names.maybe_get(buf_name) == nullptr && - g->external_symbol_names.maybe_get(buf_name) == nullptr; - buf_destroy(buf_name); - return result; -} - -static const char *get_mangled_name(CodeGen *g, const char *original_name) { - if (is_symbol_available(g, original_name)) - return original_name; - - int n = 0; - for (;; n += 1) { - const char *new_name = buf_ptr(buf_sprintf("%s.%d", original_name, n)); - if (is_symbol_available(g, new_name)) { - return new_name; - } - } -} - -// Sync this with emit_error_unless_callconv_allowed_for_target in analyze.cpp -static ZigLLVM_CallingConv get_llvm_cc(CodeGen *g, CallingConvention cc) { - switch (cc) { - case CallingConventionUnspecified: - case CallingConventionInline: - return ZigLLVM_Fast; - case CallingConventionC: - return ZigLLVM_C; - case CallingConventionNaked: - zig_unreachable(); - case CallingConventionStdcall: - assert(g->zig_target->arch == ZigLLVM_x86); - return ZigLLVM_X86_StdCall; - case CallingConventionFastcall: - assert(g->zig_target->arch == ZigLLVM_x86); - return ZigLLVM_X86_FastCall; - case CallingConventionVectorcall: - if (g->zig_target->arch == ZigLLVM_x86) - return ZigLLVM_X86_VectorCall; - if (target_is_arm(g->zig_target) && - target_arch_pointer_bit_width(g->zig_target->arch) == 64) - return ZigLLVM_AArch64_VectorCall; - zig_unreachable(); - case CallingConventionThiscall: - assert(g->zig_target->arch == ZigLLVM_x86); - return ZigLLVM_X86_ThisCall; - case CallingConventionAsync: - return ZigLLVM_Fast; - case CallingConventionAPCS: - assert(target_is_arm(g->zig_target)); - return ZigLLVM_ARM_APCS; - case CallingConventionAAPCS: - assert(target_is_arm(g->zig_target)); - return ZigLLVM_ARM_AAPCS; - case CallingConventionAAPCSVFP: - assert(target_is_arm(g->zig_target)); - return ZigLLVM_ARM_AAPCS_VFP; - case CallingConventionInterrupt: - if (g->zig_target->arch == ZigLLVM_x86 || - g->zig_target->arch == ZigLLVM_x86_64) - return ZigLLVM_X86_INTR; - if (g->zig_target->arch == ZigLLVM_avr) - return ZigLLVM_AVR_INTR; - if (g->zig_target->arch == ZigLLVM_msp430) - return ZigLLVM_MSP430_INTR; - zig_unreachable(); - case CallingConventionSignal: - assert(g->zig_target->arch == ZigLLVM_avr); - return ZigLLVM_AVR_SIGNAL; - case CallingConventionSysV: - assert(g->zig_target->arch == ZigLLVM_x86_64); - return ZigLLVM_X86_64_SysV; - case CallingConventionWin64: - assert(g->zig_target->arch == ZigLLVM_x86_64); - return ZigLLVM_Win64; - case CallingConventionPtxKernel: - assert(g->zig_target->arch == ZigLLVM_nvptx || - g->zig_target->arch == ZigLLVM_nvptx64); - return ZigLLVM_PTX_Kernel; - case CallingConventionAmdgpuKernel: - assert(g->zig_target->arch == ZigLLVM_amdgcn); - return ZigLLVM_AMDGPU_KERNEL; - - } - zig_unreachable(); -} - -static void add_uwtable_attr(CodeGen *g, LLVMValueRef fn_val) { - if (g->unwind_tables) { - addLLVMFnAttrInt(fn_val, "uwtable", 2); - } -} - -static LLVMLinkage to_llvm_linkage(GlobalLinkageId id, bool is_extern) { - switch (id) { - case GlobalLinkageIdInternal: - return LLVMInternalLinkage; - case GlobalLinkageIdStrong: - return LLVMExternalLinkage; - case GlobalLinkageIdWeak: - if (is_extern) return LLVMExternalWeakLinkage; - return LLVMWeakODRLinkage; - case GlobalLinkageIdLinkOnce: - return LLVMLinkOnceODRLinkage; - } - zig_unreachable(); -} - -struct CalcLLVMFieldIndex { - uint32_t offset; - uint32_t field_index; -}; - -static void calc_llvm_field_index_add(CodeGen *g, CalcLLVMFieldIndex *calc, ZigType *ty) { - if (!type_has_bits(g, ty)) return; - uint32_t ty_align = get_abi_alignment(g, ty); - - if (calc->offset % ty_align != 0) { - uint32_t llvm_align = LLVMABIAlignmentOfType(g->target_data_ref, get_llvm_type(g, ty)); - - // Alignment according to Zig. - uint32_t adj_offset = calc->offset + (ty_align - (calc->offset % ty_align)); - // Alignment according to LLVM. - uint32_t adj_llvm_offset = (calc->offset % llvm_align) ? - calc->offset + (llvm_align - (calc->offset % llvm_align)) : - calc->offset; - // Cannot under-align structure fields. - assert(adj_offset >= adj_llvm_offset); - - // Zig will insert an extra padding field here. - if (adj_offset != adj_llvm_offset) - calc->field_index += 1; - - calc->offset = adj_offset; - } - calc->offset += ty->abi_size; - calc->field_index += 1; -} - -// label (grep this): [fn_frame_struct_layout] -static void frame_index_trace_arg_calc(CodeGen *g, CalcLLVMFieldIndex *calc, ZigType *return_type) { - calc_llvm_field_index_add(g, calc, g->builtin_types.entry_usize); // function pointer - calc_llvm_field_index_add(g, calc, g->builtin_types.entry_usize); // resume index - calc_llvm_field_index_add(g, calc, g->builtin_types.entry_usize); // awaiter index - - if (type_has_bits(g, return_type)) { - calc_llvm_field_index_add(g, calc, g->builtin_types.entry_usize); // *ReturnType (callee's) - calc_llvm_field_index_add(g, calc, g->builtin_types.entry_usize); // *ReturnType (awaiter's) - calc_llvm_field_index_add(g, calc, return_type); // ReturnType - } -} - -static uint32_t frame_index_trace_arg(CodeGen *g, ZigType *return_type) { - CalcLLVMFieldIndex calc = {0}; - frame_index_trace_arg_calc(g, &calc, return_type); - return calc.field_index; -} - -// label (grep this): [fn_frame_struct_layout] -static void frame_index_arg_calc(CodeGen *g, CalcLLVMFieldIndex *calc, ZigType *return_type) { - frame_index_trace_arg_calc(g, calc, return_type); - - if (codegen_fn_has_err_ret_tracing_arg(g, return_type)) { - calc_llvm_field_index_add(g, calc, g->builtin_types.entry_usize); // *StackTrace (callee's) - calc_llvm_field_index_add(g, calc, g->builtin_types.entry_usize); // *StackTrace (awaiter's) - } -} - -// label (grep this): [fn_frame_struct_layout] -static uint32_t frame_index_trace_stack(CodeGen *g, ZigFn *fn) { - size_t field_index = 6; - bool have_stack_trace = codegen_fn_has_err_ret_tracing_arg(g, fn->type_entry->data.fn.fn_type_id.return_type); - if (have_stack_trace) { - field_index += 2; - } - field_index += fn->type_entry->data.fn.fn_type_id.param_count; - ZigType *locals_struct = fn->frame_type->data.frame.locals_struct; - TypeStructField *field = locals_struct->data.structure.fields[field_index]; - return field->gen_index; -} - - -static uint32_t get_err_ret_trace_arg_index(CodeGen *g, ZigFn *fn_table_entry) { - if (!g->have_err_ret_tracing) { - return UINT32_MAX; - } - if (fn_is_async(fn_table_entry)) { - return UINT32_MAX; - } - ZigType *fn_type = fn_table_entry->type_entry; - if (!fn_type_can_fail(&fn_type->data.fn.fn_type_id)) { - return UINT32_MAX; - } - ZigType *return_type = fn_type->data.fn.fn_type_id.return_type; - bool first_arg_ret = type_has_bits(g, return_type) && handle_is_ptr(g, return_type); - return first_arg_ret ? 1 : 0; -} - -static void maybe_export_dll(CodeGen *g, LLVMValueRef global_value, GlobalLinkageId linkage) { - if (linkage != GlobalLinkageIdInternal && g->zig_target->os == OsWindows && g->dll_export_fns) { - LLVMSetDLLStorageClass(global_value, LLVMDLLExportStorageClass); - } -} - -static void maybe_import_dll(CodeGen *g, LLVMValueRef global_value, GlobalLinkageId linkage) { - if (linkage != GlobalLinkageIdInternal && g->zig_target->os == OsWindows) { - // TODO come up with a good explanation/understanding for why we never do - // DLLImportStorageClass. Empirically it only causes problems. But let's have - // this documented and then clean up the code accordingly. - //LLVMSetDLLStorageClass(global_value, LLVMDLLImportStorageClass); - } -} - -static bool cc_want_sret_attr(CallingConvention cc) { - switch (cc) { - case CallingConventionNaked: - zig_unreachable(); - case CallingConventionC: - case CallingConventionInterrupt: - case CallingConventionSignal: - case CallingConventionStdcall: - case CallingConventionFastcall: - case CallingConventionVectorcall: - case CallingConventionThiscall: - case CallingConventionAPCS: - case CallingConventionAAPCS: - case CallingConventionAAPCSVFP: - case CallingConventionSysV: - case CallingConventionWin64: - case CallingConventionPtxKernel: - case CallingConventionAmdgpuKernel: - return true; - case CallingConventionAsync: - case CallingConventionUnspecified: - case CallingConventionInline: - return false; - } - zig_unreachable(); -} - -static void add_common_fn_attributes(CodeGen *g, LLVMValueRef llvm_fn) { - if (!g->red_zone) { - addLLVMFnAttr(llvm_fn, "noredzone"); - } - - addLLVMFnAttr(llvm_fn, "nounwind"); - add_uwtable_attr(g, llvm_fn); - addLLVMFnAttr(llvm_fn, "nobuiltin"); - - if (g->build_mode == BuildModeSmallRelease) { - // Optimize for small code size. - addLLVMFnAttr(llvm_fn, "minsize"); - addLLVMFnAttr(llvm_fn, "optsize"); - } - - if (g->zig_target->llvm_cpu_name != nullptr) { - ZigLLVMAddFunctionAttr(llvm_fn, "target-cpu", g->zig_target->llvm_cpu_name); - } - if (g->zig_target->llvm_cpu_features != nullptr) { - ZigLLVMAddFunctionAttr(llvm_fn, "target-features", g->zig_target->llvm_cpu_features); - } -} - -static LLVMValueRef make_fn_llvm_value(CodeGen *g, ZigFn *fn) { - const char *unmangled_name = buf_ptr(&fn->symbol_name); - const char *symbol_name; - GlobalLinkageId linkage; - if (fn->body_node == nullptr) { - symbol_name = unmangled_name; - linkage = GlobalLinkageIdStrong; - } else if (fn->export_list.length == 0) { - symbol_name = get_mangled_name(g, unmangled_name); - linkage = GlobalLinkageIdInternal; - } else { - GlobalExport *fn_export = &fn->export_list.items[0]; - symbol_name = buf_ptr(&fn_export->name); - linkage = fn_export->linkage; - } - - CallingConvention cc = fn->type_entry->data.fn.fn_type_id.cc; - bool is_async = fn_is_async(fn); - - ZigType *fn_type = fn->type_entry; - // Make the raw_type_ref populated - resolve_llvm_types_fn(g, fn); - LLVMTypeRef fn_llvm_type = fn->raw_type_ref; - LLVMValueRef llvm_fn = nullptr; - if (fn->body_node == nullptr) { - assert(fn->proto_node->type == NodeTypeFnProto); - AstNodeFnProto *fn_proto = &fn->proto_node->data.fn_proto; - - const unsigned fn_addrspace = ZigLLVMDataLayoutGetProgramAddressSpace(g->target_data_ref); - - // The compiler tries to deduplicate extern definitions by looking up - // their name, this was introduced to allow the declaration of the same - // extern function with differing prototypes. - // When Wasm is targeted this check becomes a problem as the user may - // declare two (or more) extern functions sharing the same name but - // imported from different modules! - // To overcome this problem we generate a mangled identifier out of the - // import and the function name, this name is only visible within the - // compiler as we're telling LLVM (using 'wasm-import-name' and - // 'wasm-import-name') what the real function name is and where to find - // it. - bool use_mangled_name = target_is_wasm(g->zig_target) && - fn_proto->is_extern && fn_proto->lib_name != nullptr; - // This is subtle but important to match libc symbols at static link time correctly. - // We treat "c" lib_name as a special library indicating that it should be defined - // in libc. But if we mangle a libc symbol name here with "c" module name, then wasm-ld cannot resolve - // the symbol. This is because at the static link time with wasm-ld, the linker does not - // take module names into account, and instead looking for a pure symbol name (i.e. function name) - // written into the ".linking" custom section (i.e. it does not use import section). - // This is the intended behavior of wasm-ld, because Wasm has a concept of host functions, - // which are undefined functions supposed to be resolved by host runtimes *with module names* - // at load times even if it is "static linked" with the linker. - use_mangled_name = use_mangled_name && (strcmp(buf_ptr(fn_proto->lib_name), "c") != 0); - // Pick a weird name to avoid collisions... - // This whole function should be burned to the ground. - Buf *mangled_symbol_buf = use_mangled_name ? - buf_sprintf("%s|%s", unmangled_name, buf_ptr(fn_proto->lib_name)) : - nullptr; - symbol_name = use_mangled_name ? - buf_ptr(mangled_symbol_buf) : unmangled_name; - - LLVMValueRef existing_llvm_fn = LLVMGetNamedFunction(g->module, symbol_name); - - if (existing_llvm_fn) { - if (mangled_symbol_buf) buf_destroy(mangled_symbol_buf); - return LLVMConstBitCast(existing_llvm_fn, LLVMPointerType(fn_llvm_type, fn_addrspace)); - } else { - Buf *buf_symbol_name = buf_create_from_str(symbol_name); - auto entry = g->exported_symbol_names.maybe_get(buf_symbol_name); - buf_destroy(buf_symbol_name); - - if (entry == nullptr) { - llvm_fn = LLVMAddFunction(g->module, symbol_name, fn_llvm_type); - - if (use_mangled_name) { - // Note that "wasm-import-module"ed symbols will not be resolved - // in the future version of wasm-ld since the attribute basically means that - // "the symbol should be resolved at load time by runtimes", though - // the symbol is already mangled here and it is written into "linking" section - // used by wasm-ld to match symbols, so it should not be expected by users. - // tl;dr is that users should not put the lib_name specifier on extern statements - // if they want to link symbols with wasm-ld. - addLLVMFnAttrStr(llvm_fn, "wasm-import-name", unmangled_name); - addLLVMFnAttrStr(llvm_fn, "wasm-import-module", buf_ptr(fn_proto->lib_name)); - } - } else { - assert(entry->value->id == TldIdFn); - TldFn *tld_fn = reinterpret_cast(entry->value); - // Make the raw_type_ref populated - resolve_llvm_types_fn(g, tld_fn->fn_entry); - tld_fn->fn_entry->llvm_value = LLVMAddFunction(g->module, symbol_name, - tld_fn->fn_entry->raw_type_ref); - llvm_fn = LLVMConstBitCast(tld_fn->fn_entry->llvm_value, LLVMPointerType(fn_llvm_type, fn_addrspace)); - if (mangled_symbol_buf) buf_destroy(mangled_symbol_buf); - return llvm_fn; - } - - if (mangled_symbol_buf) buf_destroy(mangled_symbol_buf); - } - } else { - llvm_fn = LLVMAddFunction(g->module, symbol_name, fn_llvm_type); - - for (size_t i = 1; i < fn->export_list.length; i += 1) { - GlobalExport *fn_export = &fn->export_list.items[i]; - LLVMAddAlias2(g->module, LLVMTypeOf(llvm_fn), 0, llvm_fn, buf_ptr(&fn_export->name)); - } - } - - if (cc == CallingConventionInline) - addLLVMFnAttr(llvm_fn, "alwaysinline"); - - if (fn->is_noinline || (cc != CallingConventionInline && fn->alignstack_value != 0)) - addLLVMFnAttr(llvm_fn, "noinline"); - - if (cc == CallingConventionNaked) { - addLLVMFnAttr(llvm_fn, "naked"); - } else { - ZigLLVMFunctionSetCallingConv(llvm_fn, get_llvm_cc(g, cc)); - } - - if (g->tsan_enabled) { - addLLVMFnAttr(llvm_fn, "sanitize_thread"); - } - - bool want_cold = fn->is_cold; - if (want_cold) { - ZigLLVMAddFunctionAttrCold(llvm_fn); - } - - - LLVMSetLinkage(llvm_fn, to_llvm_linkage(linkage, fn->body_node == nullptr)); - - if (linkage == GlobalLinkageIdInternal) { - LLVMSetUnnamedAddr(llvm_fn, true); - } - - ZigType *return_type = fn_type->data.fn.fn_type_id.return_type; - if (return_type->id == ZigTypeIdUnreachable) { - addLLVMFnAttr(llvm_fn, "noreturn"); - } - - if (!calling_convention_allows_zig_types(cc)) { - // A simplistic and desperate attempt at making the compiler respect the - // target ABI for return types. - // This is just enough to avoid miscompiling the test suite, it will be - // better in stage2. - ZigType *int_type = return_type->id == ZigTypeIdInt ? return_type : - return_type->id == ZigTypeIdEnum ? return_type->data.enumeration.tag_int_type : - nullptr; - - if (int_type != nullptr) { - const bool is_signed = int_type->data.integral.is_signed; - const uint32_t bit_width = int_type->data.integral.bit_count; - bool should_extend = false; - - // Rough equivalent of Clang's isPromotableIntegerType. - switch (bit_width) { - case 1: // bool - case 8: // {un,}signed char - case 16: // {un,}signed short - should_extend = true; - break; - default: - break; - } - - switch (g->zig_target->arch) { - case ZigLLVM_sparcv9: - case ZigLLVM_riscv64: - case ZigLLVM_ppc64: - case ZigLLVM_ppc64le: - // Always extend to the register width. - should_extend = bit_width < 64; - break; - default: - break; - } - - // {zero,sign}-extend the result. - if (should_extend) { - if (is_signed) - addLLVMAttr(llvm_fn, 0, "signext"); - else - addLLVMAttr(llvm_fn, 0, "zeroext"); - } - } - } - - if (fn->body_node != nullptr) { - maybe_export_dll(g, llvm_fn, linkage); - - bool want_ssp_attrs = g->build_mode != BuildModeFastRelease && - g->build_mode != BuildModeSmallRelease && - g->link_libc && - // WASI-libc does not support stack-protector yet. - !target_is_wasm(g->zig_target); - if (want_ssp_attrs) { - addLLVMFnAttr(llvm_fn, "sspstrong"); - addLLVMFnAttrStr(llvm_fn, "stack-protector-buffer-size", "4"); - } - if (g->have_stack_probing && !fn->def_scope->safety_off) { - addLLVMFnAttrStr(llvm_fn, "probe-stack", "__zig_probe_stack"); - } else if (g->zig_target->os == OsUefi) { - addLLVMFnAttrStr(llvm_fn, "no-stack-arg-probe", ""); - } - } else { - maybe_import_dll(g, llvm_fn, linkage); - } - - if (fn->alignstack_value != 0) { - addLLVMFnAttrInt(llvm_fn, "alignstack", fn->alignstack_value); - } - - if (!g->omit_frame_pointer && cc != CallingConventionInline) { - ZigLLVMAddFunctionAttr(llvm_fn, "frame-pointer", "all"); - } - if (fn->section_name) { - LLVMSetSection(llvm_fn, buf_ptr(fn->section_name)); - } - if (fn->align_bytes > 0) { - LLVMSetAlignment(llvm_fn, (unsigned)fn->align_bytes); - } else { - // We'd like to set the best alignment for the function here, but on Darwin LLVM gives - // "Cannot getTypeInfo() on a type that is unsized!" assertion failure when calling - // any of the functions for getting alignment. Not specifying the alignment should - // use the ABI alignment, which is fine. - } - - add_common_fn_attributes(g, llvm_fn); - - if (is_async) { - addLLVMArgAttr(llvm_fn, 0, "nonnull"); - } else { - unsigned init_gen_i = 0; - if (!type_has_bits(g, return_type)) { - // nothing to do - } else if (type_is_nonnull_ptr(g, return_type)) { - addLLVMAttr(llvm_fn, 0, "nonnull"); - } else if (want_first_arg_sret(g, &fn_type->data.fn.fn_type_id)) { - // Sret pointers must not be address 0 - addLLVMArgAttr(llvm_fn, 0, "nonnull"); - ZigLLVMAddSretAttr(llvm_fn, get_llvm_type(g, return_type)); - if (cc_want_sret_attr(cc)) { - addLLVMArgAttr(llvm_fn, 0, "noalias"); - } - init_gen_i = 1; - } - - // set parameter attributes - FnWalk fn_walk = {}; - fn_walk.id = FnWalkIdAttrs; - fn_walk.data.attrs.fn = fn; - fn_walk.data.attrs.llvm_fn = llvm_fn; - fn_walk.data.attrs.gen_i = init_gen_i; - walk_function_params(g, fn_type, &fn_walk); - - uint32_t err_ret_trace_arg_index = get_err_ret_trace_arg_index(g, fn); - if (err_ret_trace_arg_index != UINT32_MAX) { - // Error return trace memory is in the stack, which is impossible to be at address 0 - // on any architecture. - addLLVMArgAttr(llvm_fn, (unsigned)err_ret_trace_arg_index, "nonnull"); - } - } - - return llvm_fn; -} - -static LLVMValueRef fn_llvm_value(CodeGen *g, ZigFn *fn) { - if (fn->llvm_value) - return fn->llvm_value; - - fn->llvm_value = make_fn_llvm_value(g, fn); - fn->llvm_name = strdup(LLVMGetValueName(fn->llvm_value)); - return fn->llvm_value; -} - -static uint32_t node_line_onebased(AstNode *node) { - RootStruct *root_struct = node->owner->data.structure.root_struct; - assert(node->main_token < root_struct->token_count); - return root_struct->token_locs[node->main_token].line + 1; -} - -static uint32_t node_column_onebased(AstNode *node) { - RootStruct *root_struct = node->owner->data.structure.root_struct; - assert(node->main_token < root_struct->token_count); - return root_struct->token_locs[node->main_token].column + 1; -} - -static ZigLLVMDIScope *get_di_scope(CodeGen *g, Scope *scope) { - if (scope->di_scope) - return scope->di_scope; - - ZigType *import = get_scope_import(scope); - switch (scope->id) { - case ScopeIdCImport: - zig_unreachable(); - case ScopeIdFnDef: - { - assert(scope->parent); - ScopeFnDef *fn_scope = (ScopeFnDef *)scope; - ZigFn *fn_table_entry = fn_scope->fn_entry; - if (!fn_table_entry->proto_node) - return get_di_scope(g, scope->parent); - unsigned line_number = node_line_onebased(fn_table_entry->proto_node); - unsigned scope_line = line_number; - bool is_definition = fn_table_entry->body_node != nullptr; - bool is_optimized = g->build_mode != BuildModeDebug; - bool is_internal_linkage = (fn_table_entry->body_node != nullptr && - fn_table_entry->export_list.length == 0); - unsigned flags = ZigLLVM_DIFlags_StaticMember; - ZigLLVMDIScope *fn_di_scope = get_di_scope(g, scope->parent); - assert(fn_di_scope != nullptr); - assert(fn_table_entry->raw_di_type != nullptr); - ZigLLVMDISubprogram *subprogram = ZigLLVMCreateFunction(g->dbuilder, - fn_di_scope, buf_ptr(&fn_table_entry->symbol_name), "", - import->data.structure.root_struct->di_file, line_number, - fn_table_entry->raw_di_type, is_internal_linkage, - is_definition, scope_line, flags, is_optimized, nullptr); - - scope->di_scope = ZigLLVMSubprogramToScope(subprogram); - if (!g->strip_debug_symbols) { - ZigLLVMFnSetSubprogram(fn_llvm_value(g, fn_table_entry), subprogram); - } - return scope->di_scope; - } - case ScopeIdDecls: - if (scope->parent) { - ScopeDecls *decls_scope = (ScopeDecls *)scope; - assert(decls_scope->container_type); - scope->di_scope = ZigLLVMTypeToScope(get_llvm_di_type(g, decls_scope->container_type)); - } else { - scope->di_scope = ZigLLVMFileToScope(import->data.structure.root_struct->di_file); - } - return scope->di_scope; - case ScopeIdBlock: - case ScopeIdDefer: - { - assert(scope->parent); - ZigLLVMDILexicalBlock *di_block = ZigLLVMCreateLexicalBlock(g->dbuilder, - get_di_scope(g, scope->parent), - import->data.structure.root_struct->di_file, - node_line_onebased(scope->source_node), - node_column_onebased(scope->source_node)); - scope->di_scope = ZigLLVMLexicalBlockToScope(di_block); - return scope->di_scope; - } - case ScopeIdVarDecl: - case ScopeIdDeferExpr: - case ScopeIdLoop: - case ScopeIdSuspend: - case ScopeIdCompTime: - case ScopeIdNoSuspend: - case ScopeIdRuntime: - case ScopeIdTypeOf: - case ScopeIdExpr: - return get_di_scope(g, scope->parent); - } - zig_unreachable(); -} - -static void clear_debug_source_node(CodeGen *g) { - ZigLLVMClearCurrentDebugLocation(g->builder); -} - -static LLVMValueRef get_arithmetic_overflow_fn(CodeGen *g, ZigType *operand_type, - const char *signed_name, const char *unsigned_name) -{ - ZigType *int_type = (operand_type->id == ZigTypeIdVector) ? operand_type->data.vector.elem_type : operand_type; - char fn_name[64]; - - assert(int_type->id == ZigTypeIdInt); - const char *signed_str = int_type->data.integral.is_signed ? signed_name : unsigned_name; - - LLVMTypeRef param_types[] = { - get_llvm_type(g, operand_type), - get_llvm_type(g, operand_type), - }; - - if (operand_type->id == ZigTypeIdVector) { - snprintf(fn_name, sizeof(fn_name), "llvm.%s.with.overflow.v%" PRIu64 "i%" PRIu32, signed_str, - operand_type->data.vector.len, int_type->data.integral.bit_count); - - LLVMTypeRef return_elem_types[] = { - get_llvm_type(g, operand_type), - LLVMVectorType(LLVMInt1Type(), operand_type->data.vector.len), - }; - LLVMTypeRef return_struct_type = LLVMStructType(return_elem_types, 2, false); - LLVMTypeRef fn_type = LLVMFunctionType(return_struct_type, param_types, 2, false); - LLVMValueRef fn_val = LLVMAddFunction(g->module, fn_name, fn_type); - assert(LLVMGetIntrinsicID(fn_val)); - return fn_val; - } else { - snprintf(fn_name, sizeof(fn_name), "llvm.%s.with.overflow.i%" PRIu32, signed_str, int_type->data.integral.bit_count); - - LLVMTypeRef return_elem_types[] = { - get_llvm_type(g, operand_type), - LLVMInt1Type(), - }; - LLVMTypeRef return_struct_type = LLVMStructType(return_elem_types, 2, false); - LLVMTypeRef fn_type = LLVMFunctionType(return_struct_type, param_types, 2, false); - LLVMValueRef fn_val = LLVMAddFunction(g->module, fn_name, fn_type); - assert(LLVMGetIntrinsicID(fn_val)); - return fn_val; - } -} - -static LLVMValueRef get_int_overflow_fn(CodeGen *g, ZigType *operand_type, AddSubMul add_sub_mul) { - ZigType *int_type = (operand_type->id == ZigTypeIdVector) ? operand_type->data.vector.elem_type : operand_type; - assert(int_type->id == ZigTypeIdInt); - - ZigLLVMFnKey key = {}; - key.id = ZigLLVMFnIdOverflowArithmetic; - key.data.overflow_arithmetic.is_signed = int_type->data.integral.is_signed; - key.data.overflow_arithmetic.add_sub_mul = add_sub_mul; - key.data.overflow_arithmetic.bit_count = (uint32_t)int_type->data.integral.bit_count; - key.data.overflow_arithmetic.vector_len = (operand_type->id == ZigTypeIdVector) ? - operand_type->data.vector.len : 0; - - auto existing_entry = g->llvm_fn_table.maybe_get(key); - if (existing_entry) - return existing_entry->value; - - LLVMValueRef fn_val; - switch (add_sub_mul) { - case AddSubMulAdd: - fn_val = get_arithmetic_overflow_fn(g, operand_type, "sadd", "uadd"); - break; - case AddSubMulSub: - fn_val = get_arithmetic_overflow_fn(g, operand_type, "ssub", "usub"); - break; - case AddSubMulMul: - fn_val = get_arithmetic_overflow_fn(g, operand_type, "smul", "umul"); - break; - } - - g->llvm_fn_table.put(key, fn_val); - return fn_val; -} - -static LLVMValueRef get_float_fn(CodeGen *g, ZigType *type_entry, ZigLLVMFnId fn_id, BuiltinFnId op) { - assert(type_entry->id == ZigTypeIdFloat || - type_entry->id == ZigTypeIdVector); - - bool is_vector = (type_entry->id == ZigTypeIdVector); - ZigType *float_type = is_vector ? type_entry->data.vector.elem_type : type_entry; - uint32_t float_bits = float_type->data.floating.bit_count; - - // LLVM incorrectly lowers the fma builtin for f128 to fmal, which is for - // `long double`. On some targets this will be correct; on others it will be incorrect. - if (fn_id == ZigLLVMFnIdFMA && float_bits == 128 && - !target_long_double_is_f128(g->zig_target)) - { - LLVMValueRef existing_llvm_fn = LLVMGetNamedFunction(g->module, "fmaq"); - if (existing_llvm_fn != nullptr) return existing_llvm_fn; - - LLVMTypeRef float_type_ref = get_llvm_type(g, type_entry); - LLVMTypeRef return_elem_types[3] = { float_type_ref, float_type_ref, float_type_ref }; - LLVMTypeRef fn_type = LLVMFunctionType(float_type_ref, return_elem_types, 3, false); - return LLVMAddFunction(g->module, "fmaq", fn_type); - } - - ZigLLVMFnKey key = {}; - key.id = fn_id; - key.data.floating.bit_count = float_bits; - key.data.floating.vector_len = is_vector ? (uint32_t)type_entry->data.vector.len : 0; - key.data.floating.op = op; - - auto existing_entry = g->llvm_fn_table.maybe_get(key); - if (existing_entry) - return existing_entry->value; - - const char *name; - uint32_t num_args; - if (fn_id == ZigLLVMFnIdFMA) { - name = "fma"; - num_args = 3; - } else if (fn_id == ZigLLVMFnIdFloatOp) { - name = float_un_op_to_name(op); - num_args = 1; - } else { - zig_unreachable(); - } - - char fn_name[64]; - if (is_vector) - snprintf(fn_name, sizeof(fn_name), "llvm.%s.v%" PRIu32 "f%" PRIu32, name, key.data.floating.vector_len, key.data.floating.bit_count); - else - snprintf(fn_name, sizeof(fn_name), "llvm.%s.f%" PRIu32, name, key.data.floating.bit_count); - LLVMTypeRef float_type_ref = get_llvm_type(g, type_entry); - LLVMTypeRef return_elem_types[3] = { float_type_ref, float_type_ref, float_type_ref }; - LLVMTypeRef fn_type = LLVMFunctionType(float_type_ref, return_elem_types, num_args, false); - LLVMValueRef fn_val = LLVMAddFunction(g->module, fn_name, fn_type); - assert(LLVMGetIntrinsicID(fn_val)); - - g->llvm_fn_table.put(key, fn_val); - return fn_val; -} - -static LLVMValueRef gen_store_untyped(CodeGen *g, LLVMValueRef value, LLVMValueRef ptr, - uint32_t alignment, bool is_volatile) -{ - LLVMValueRef instruction = LLVMBuildStore(g->builder, value, ptr); - if (is_volatile) LLVMSetVolatile(instruction, true); - if (alignment != 0) { - LLVMSetAlignment(instruction, alignment); - } - return instruction; -} - -static LLVMValueRef gen_store(CodeGen *g, LLVMValueRef value, LLVMValueRef ptr, ZigType *ptr_type) { - assert(ptr_type->id == ZigTypeIdPointer); - uint32_t alignment = get_ptr_align(g, ptr_type); - return gen_store_untyped(g, value, ptr, alignment, ptr_type->data.pointer.is_volatile); -} - -static LLVMValueRef gen_load_untyped(CodeGen *g, LLVMTypeRef elem_llvm_ty, LLVMValueRef ptr, - uint32_t alignment, bool is_volatile, const char *name) -{ - LLVMValueRef result = LLVMBuildLoad2(g->builder, elem_llvm_ty, ptr, name); - if (is_volatile) LLVMSetVolatile(result, true); - if (alignment != 0) { - LLVMSetAlignment(result, alignment); - } - return result; -} - -static LLVMValueRef gen_load(CodeGen *g, LLVMValueRef ptr, ZigType *ptr_type, const char *name) { - assert(ptr_type->id == ZigTypeIdPointer); - uint32_t alignment = get_ptr_align(g, ptr_type); - LLVMTypeRef elem_llvm_ty = get_llvm_type(g, ptr_type->data.pointer.child_type); - bool is_volatile = ptr_type->data.pointer.is_volatile; - return gen_load_untyped(g, elem_llvm_ty, ptr, alignment, is_volatile, name); -} - -static LLVMValueRef get_handle_value(CodeGen *g, LLVMValueRef ptr, ZigType *type, ZigType *ptr_type) { - if (type_has_bits(g, type)) { - if (handle_is_ptr(g, type)) { - return ptr; - } else { - assert(ptr_type->id == ZigTypeIdPointer); - return gen_load(g, ptr, ptr_type, ""); - } - } else { - return nullptr; - } -} - -static void ir_assert_impl(bool ok, Stage1AirInst *source_instruction, const char *file, unsigned int line) { - if (ok) return; - src_assert_impl(ok, source_instruction->source_node, file, line); -} - -#define ir_assert(OK, SOURCE_INSTRUCTION) ir_assert_impl((OK), (SOURCE_INSTRUCTION), __FILE__, __LINE__) - -static bool ir_want_fast_math(CodeGen *g, Stage1AirInst *instruction) { - // TODO memoize - Scope *scope = instruction->scope; - while (scope) { - if (scope->id == ScopeIdBlock) { - ScopeBlock *block_scope = (ScopeBlock *)scope; - if (block_scope->fast_math_set_node) - return block_scope->fast_math_on; - } else if (scope->id == ScopeIdDecls) { - ScopeDecls *decls_scope = (ScopeDecls *)scope; - if (decls_scope->fast_math_set_node) - return decls_scope->fast_math_on; - } - scope = scope->parent; - } - return false; -} - -static bool ir_want_runtime_safety_scope(CodeGen *g, Scope *scope) { - // TODO memoize - while (scope) { - if (scope->id == ScopeIdBlock) { - ScopeBlock *block_scope = (ScopeBlock *)scope; - if (block_scope->safety_set_node) - return !block_scope->safety_off; - } else if (scope->id == ScopeIdDecls) { - ScopeDecls *decls_scope = (ScopeDecls *)scope; - if (decls_scope->safety_set_node) - return !decls_scope->safety_off; - } - scope = scope->parent; - } - - return (g->build_mode != BuildModeFastRelease && - g->build_mode != BuildModeSmallRelease); -} - -static bool ir_want_runtime_safety(CodeGen *g, Stage1AirInst *instruction) { - return ir_want_runtime_safety_scope(g, instruction->scope); -} - -static Buf *panic_msg_buf(PanicMsgId msg_id) { - switch (msg_id) { - case PanicMsgIdCount: - zig_unreachable(); - case PanicMsgIdBoundsCheckFailure: - return buf_create_from_str("index out of bounds"); - case PanicMsgIdCastNegativeToUnsigned: - return buf_create_from_str("attempt to cast negative value to unsigned integer"); - case PanicMsgIdCastTruncatedData: - return buf_create_from_str("integer cast truncated bits"); - case PanicMsgIdIntegerOverflow: - return buf_create_from_str("integer overflow"); - case PanicMsgIdShlOverflowedBits: - return buf_create_from_str("left shift overflowed bits"); - case PanicMsgIdShrOverflowedBits: - return buf_create_from_str("right shift overflowed bits"); - case PanicMsgIdDivisionByZero: - return buf_create_from_str("division by zero"); - case PanicMsgIdRemainderDivisionByZero: - return buf_create_from_str("remainder division by zero or negative value"); - case PanicMsgIdExactDivisionRemainder: - return buf_create_from_str("exact division produced remainder"); - case PanicMsgIdUnwrapOptionalFail: - return buf_create_from_str("attempt to use null value"); - case PanicMsgIdUnreachable: - return buf_create_from_str("reached unreachable code"); - case PanicMsgIdInvalidErrorCode: - return buf_create_from_str("invalid error code"); - case PanicMsgIdIncorrectAlignment: - return buf_create_from_str("incorrect alignment"); - case PanicMsgIdBadUnionField: - return buf_create_from_str("access of inactive union field"); - case PanicMsgIdBadEnumValue: - return buf_create_from_str("invalid enum value"); - case PanicMsgIdFloatToInt: - return buf_create_from_str("integer part of floating point value out of bounds"); - case PanicMsgIdPtrCastNull: - return buf_create_from_str("cast causes pointer to be null"); - case PanicMsgIdBadResume: - return buf_create_from_str("resumed an async function which already returned"); - case PanicMsgIdBadAwait: - return buf_create_from_str("async function awaited twice"); - case PanicMsgIdBadReturn: - return buf_create_from_str("async function returned twice"); - case PanicMsgIdResumedAnAwaitingFn: - return buf_create_from_str("awaiting function resumed"); - case PanicMsgIdFrameTooSmall: - return buf_create_from_str("frame too small"); - case PanicMsgIdResumedFnPendingAwait: - return buf_create_from_str("resumed an async function which can only be awaited"); - case PanicMsgIdBadNoSuspendCall: - return buf_create_from_str("async function called in nosuspend scope suspended"); - case PanicMsgIdResumeNotSuspendedFn: - return buf_create_from_str("resumed a non-suspended function"); - case PanicMsgIdBadSentinel: - return buf_create_from_str("sentinel mismatch"); - case PanicMsgIdShxTooBigRhs: - return buf_create_from_str("shift amount is greater than the type size"); - } - zig_unreachable(); -} - -static LLVMValueRef get_panic_msg_ptr_val(CodeGen *g, PanicMsgId msg_id) { - ZigValue *val = &g->panic_msg_vals[msg_id]; - if (!val->llvm_global) { - - Buf *buf_msg = panic_msg_buf(msg_id); - ZigValue *array_val = create_const_str_lit(g, buf_msg)->data.x_ptr.data.ref.pointee; - init_const_slice(g, val, array_val, 0, buf_len(buf_msg), true, nullptr); - - render_const_val(g, val, ""); - render_const_val_global(g, val, ""); - - assert(val->llvm_global); - } - - ZigType *u8_ptr_type = get_pointer_to_type_extra(g, g->builtin_types.entry_u8, true, false, - PtrLenUnknown, get_abi_alignment(g, g->builtin_types.entry_u8), 0, 0, false); - ZigType *str_type = get_slice_type(g, u8_ptr_type); - return LLVMConstBitCast(val->llvm_global, LLVMPointerType(get_llvm_type(g, str_type), 0)); -} - -static ZigType *ptr_to_stack_trace_type(CodeGen *g) { - return get_pointer_to_type(g, get_stack_trace_type(g), false); -} - -static void gen_panic(CodeGen *g, LLVMValueRef msg_arg, LLVMValueRef stack_trace_arg, - bool stack_trace_is_llvm_alloca) -{ - assert(g->panic_fn != nullptr); - LLVMValueRef fn_val = fn_llvm_value(g, g->panic_fn); - ZigLLVM_CallingConv llvm_cc = get_llvm_cc(g, g->panic_fn->type_entry->data.fn.fn_type_id.cc); - if (stack_trace_arg == nullptr) { - stack_trace_arg = LLVMConstNull(get_llvm_type(g, ptr_to_stack_trace_type(g))); - } - LLVMValueRef null_ret_alloc; - { - ZigValue null_val = {}; - null_val.special = ConstValSpecialStatic; - null_val.data.x_optional = nullptr; - null_val.type = get_optional_type2(g, g->builtin_types.entry_usize); - LLVMValueRef null_ret_val = gen_const_val(g, &null_val, ""); - null_ret_alloc = build_alloca(g, null_val.type, "ret_addr", 0); - LLVMBuildStore(g->builder, null_ret_val, null_ret_alloc); - } - - LLVMValueRef args[] = { - msg_arg, - stack_trace_arg, - null_ret_alloc, - }; - ZigLLVMBuildCall(g->builder, LLVMGlobalGetValueType(fn_val), fn_val, args, 3, llvm_cc, ZigLLVM_CallAttrAuto, ""); - if (!stack_trace_is_llvm_alloca) { - // The stack trace argument is not in the stack of the caller, so - // we'd like to set tail call here, but because slices (the type of msg_arg) are - // still passed as pointers (see https://github.com/ziglang/zig/issues/561) we still - // cannot make this a tail call. - //LLVMSetTailCall(call_instruction, true); - } - LLVMBuildUnreachable(g->builder); -} - -// TODO update most callsites to call gen_assertion instead of this -static void gen_safety_crash(CodeGen *g, PanicMsgId msg_id) { - gen_panic(g, get_panic_msg_ptr_val(g, msg_id), nullptr, false); -} - -static void gen_assertion_scope(CodeGen *g, PanicMsgId msg_id, Scope *source_scope) { - if (ir_want_runtime_safety_scope(g, source_scope)) { - gen_safety_crash(g, msg_id); - } else { - LLVMBuildUnreachable(g->builder); - } -} - -static void gen_assertion(CodeGen *g, PanicMsgId msg_id, Stage1AirInst *source_instruction) { - return gen_assertion_scope(g, msg_id, source_instruction->scope); -} - -static LLVMValueRef gen_wasm_memory_size(CodeGen *g) { - if (g->wasm_memory_size) - return g->wasm_memory_size; - - // TODO adjust for wasm64 as well - // declare i32 @llvm.wasm.memory.size.i32(i32) nounwind readonly - LLVMTypeRef param_type = LLVMInt32Type(); - LLVMTypeRef fn_type = LLVMFunctionType(LLVMInt32Type(), ¶m_type, 1, false); - g->wasm_memory_size = LLVMAddFunction(g->module, "llvm.wasm.memory.size.i32", fn_type); - assert(LLVMGetIntrinsicID(g->wasm_memory_size)); - - return g->wasm_memory_size; -} - -static LLVMValueRef gen_wasm_memory_grow(CodeGen *g) { - if (g->wasm_memory_grow) - return g->wasm_memory_grow; - - // TODO adjust for wasm64 as well - // declare i32 @llvm.wasm.memory.grow.i32(i32, i32) nounwind - LLVMTypeRef param_types[] = { - LLVMInt32Type(), - LLVMInt32Type(), - }; - LLVMTypeRef fn_type = LLVMFunctionType(LLVMInt32Type(), param_types, 2, false); - g->wasm_memory_grow = LLVMAddFunction(g->module, "llvm.wasm.memory.grow.i32", fn_type); - assert(LLVMGetIntrinsicID(g->wasm_memory_grow)); - - return g->wasm_memory_grow; -} - -static LLVMValueRef gen_prefetch(CodeGen *g) { - if (g->prefetch) - return g->prefetch; - - // declare void @llvm.prefetch(i8*, i32, i32, i32) - LLVMTypeRef param_types[] = { - LLVMPointerType(LLVMInt8Type(), 0), - LLVMInt32Type(), - LLVMInt32Type(), - LLVMInt32Type(), - }; - LLVMTypeRef fn_type = LLVMFunctionType(LLVMVoidType(), param_types, 4, false); - g->prefetch = LLVMAddFunction(g->module, "llvm.prefetch.p0", fn_type); - assert(LLVMGetIntrinsicID(g->prefetch)); - - return g->prefetch; -} - -static LLVMValueRef get_stacksave_fn_val(CodeGen *g) { - if (g->stacksave_fn_val) - return g->stacksave_fn_val; - - // declare i8* @llvm.stacksave() - - LLVMTypeRef fn_type = LLVMFunctionType(LLVMPointerType(LLVMInt8Type(), 0), nullptr, 0, false); - g->stacksave_fn_val = LLVMAddFunction(g->module, "llvm.stacksave", fn_type); - assert(LLVMGetIntrinsicID(g->stacksave_fn_val)); - - return g->stacksave_fn_val; -} - -static LLVMValueRef get_stackrestore_fn_val(CodeGen *g) { - if (g->stackrestore_fn_val) - return g->stackrestore_fn_val; - - // declare void @llvm.stackrestore(i8* %ptr) - - LLVMTypeRef param_type = LLVMPointerType(LLVMInt8Type(), 0); - LLVMTypeRef fn_type = LLVMFunctionType(LLVMVoidType(), ¶m_type, 1, false); - g->stackrestore_fn_val = LLVMAddFunction(g->module, "llvm.stackrestore", fn_type); - assert(LLVMGetIntrinsicID(g->stackrestore_fn_val)); - - return g->stackrestore_fn_val; -} - -static LLVMValueRef get_write_register_fn_val(CodeGen *g) { - if (g->write_register_fn_val) - return g->write_register_fn_val; - - // declare void @llvm.write_register.i64(metadata, i64 @value) - // !0 = !{!"sp\00"} - - LLVMTypeRef param_types[] = { - LLVMMetadataTypeInContext(LLVMGetGlobalContext()), - LLVMIntType(g->pointer_size_bytes * 8), - }; - - LLVMTypeRef fn_type = LLVMFunctionType(LLVMVoidType(), param_types, 2, false); - Buf *name = buf_sprintf("llvm.write_register.i%d", g->pointer_size_bytes * 8); - g->write_register_fn_val = LLVMAddFunction(g->module, buf_ptr(name), fn_type); - assert(LLVMGetIntrinsicID(g->write_register_fn_val)); - - return g->write_register_fn_val; -} - -static LLVMValueRef get_return_address_fn_val(CodeGen *g) { - if (g->return_address_fn_val) - return g->return_address_fn_val; - - ZigType *return_type = get_pointer_to_type(g, g->builtin_types.entry_u8, true); - - LLVMTypeRef fn_type = LLVMFunctionType(get_llvm_type(g, return_type), - &g->builtin_types.entry_i32->llvm_type, 1, false); - g->return_address_fn_val = LLVMAddFunction(g->module, "llvm.returnaddress", fn_type); - assert(LLVMGetIntrinsicID(g->return_address_fn_val)); - - return g->return_address_fn_val; -} - -static LLVMValueRef get_add_error_return_trace_addr_fn(CodeGen *g) { - if (g->add_error_return_trace_addr_fn_val != nullptr) - return g->add_error_return_trace_addr_fn_val; - - LLVMTypeRef arg_types[] = { - get_llvm_type(g, ptr_to_stack_trace_type(g)), - g->builtin_types.entry_usize->llvm_type, - }; - LLVMTypeRef fn_type_ref = LLVMFunctionType(LLVMVoidType(), arg_types, 2, false); - - const char *fn_name = get_mangled_name(g, "__zig_add_err_ret_trace_addr"); - LLVMValueRef fn_val = LLVMAddFunction(g->module, fn_name, fn_type_ref); - addLLVMFnAttr(fn_val, "alwaysinline"); - LLVMSetLinkage(fn_val, LLVMInternalLinkage); - ZigLLVMFunctionSetCallingConv(fn_val, get_llvm_cc(g, CallingConventionUnspecified)); - add_common_fn_attributes(g, fn_val); - // Error return trace memory is in the stack, which is impossible to be at address 0 - // on any architecture. - addLLVMArgAttr(fn_val, (unsigned)0, "nonnull"); - if (!g->omit_frame_pointer) { - ZigLLVMAddFunctionAttr(fn_val, "frame-pointer", "all"); - } - - LLVMBasicBlockRef entry_block = LLVMAppendBasicBlock(fn_val, "Entry"); - LLVMBasicBlockRef prev_block = LLVMGetInsertBlock(g->builder); - LLVMValueRef prev_debug_location = LLVMGetCurrentDebugLocation(g->builder); - LLVMPositionBuilderAtEnd(g->builder, entry_block); - ZigLLVMClearCurrentDebugLocation(g->builder); - - LLVMTypeRef usize_type_ref = g->builtin_types.entry_usize->llvm_type; - - // stack_trace.instruction_addresses[stack_trace.index & (stack_trace.instruction_addresses.len - 1)] = return_address; - - LLVMValueRef err_ret_trace_ptr = LLVMGetParam(fn_val, 0); - LLVMValueRef address_value = LLVMGetParam(fn_val, 1); - - size_t index_field_index = g->stack_trace_type->data.structure.fields[0]->gen_index; - LLVMValueRef index_field_ptr = LLVMBuildStructGEP2(g->builder, - get_llvm_type(g, g->stack_trace_type), - err_ret_trace_ptr, (unsigned)index_field_index, ""); - size_t addresses_field_index = g->stack_trace_type->data.structure.fields[1]->gen_index; - LLVMValueRef addresses_field_ptr = LLVMBuildStructGEP2(g->builder, - get_llvm_type(g, g->stack_trace_type), - err_ret_trace_ptr, (unsigned)addresses_field_index, ""); - - ZigType *slice_type = g->stack_trace_type->data.structure.fields[1]->type_entry; - size_t ptr_field_index = slice_type->data.structure.fields[slice_ptr_index]->gen_index; - LLVMValueRef ptr_field_ptr = LLVMBuildStructGEP2(g->builder, - ZigLLVMGetGEPResultElementType(addresses_field_ptr), - addresses_field_ptr, (unsigned)ptr_field_index, ""); - size_t len_field_index = slice_type->data.structure.fields[slice_len_index]->gen_index; - LLVMValueRef len_field_ptr = LLVMBuildStructGEP2(g->builder, - ZigLLVMGetGEPResultElementType(addresses_field_ptr), - addresses_field_ptr, (unsigned)len_field_index, ""); - - LLVMValueRef len_value = gen_load_untyped(g, ZigLLVMGetGEPResultElementType(len_field_ptr), - len_field_ptr, 0, false, ""); - LLVMValueRef index_val = gen_load_untyped(g, ZigLLVMGetGEPResultElementType(index_field_ptr), - index_field_ptr, 0, false, ""); - LLVMValueRef len_val_minus_one = LLVMBuildSub(g->builder, len_value, LLVMConstInt(usize_type_ref, 1, false), ""); - LLVMValueRef masked_val = LLVMBuildAnd(g->builder, index_val, len_val_minus_one, ""); - LLVMValueRef address_indices[] = { - masked_val, - }; - - LLVMValueRef ptr_value = gen_load_untyped(g, ZigLLVMGetGEPResultElementType(ptr_field_ptr), - ptr_field_ptr, 0, false, ""); - LLVMValueRef address_slot = LLVMBuildInBoundsGEP2(g->builder, usize_type_ref, ptr_value, address_indices, 1, ""); - - gen_store_untyped(g, address_value, address_slot, 0, false); - - // stack_trace.index += 1; - LLVMValueRef index_plus_one_val = LLVMBuildNUWAdd(g->builder, index_val, LLVMConstInt(usize_type_ref, 1, false), ""); - gen_store_untyped(g, index_plus_one_val, index_field_ptr, 0, false); - - // return; - LLVMBuildRetVoid(g->builder); - - LLVMPositionBuilderAtEnd(g->builder, prev_block); - if (!g->strip_debug_symbols) { - LLVMSetCurrentDebugLocation(g->builder, prev_debug_location); - } - - g->add_error_return_trace_addr_fn_val = fn_val; - return fn_val; -} - -static LLVMValueRef get_return_err_fn(CodeGen *g) { - if (g->return_err_fn != nullptr) - return g->return_err_fn; - - assert(g->err_tag_type != nullptr); - - LLVMTypeRef arg_types[] = { - // error return trace pointer - get_llvm_type(g, ptr_to_stack_trace_type(g)), - }; - LLVMTypeRef fn_type_ref = LLVMFunctionType(LLVMVoidType(), arg_types, 1, false); - - const char *fn_name = get_mangled_name(g, "__zig_return_error"); - LLVMValueRef fn_val = LLVMAddFunction(g->module, fn_name, fn_type_ref); - addLLVMFnAttr(fn_val, "noinline"); // so that we can look at return address - addLLVMFnAttr(fn_val, "cold"); - LLVMSetLinkage(fn_val, LLVMInternalLinkage); - ZigLLVMFunctionSetCallingConv(fn_val, get_llvm_cc(g, CallingConventionUnspecified)); - add_common_fn_attributes(g, fn_val); - if (!g->omit_frame_pointer) { - ZigLLVMAddFunctionAttr(fn_val, "frame-pointer", "all"); - } - - // this is above the ZigLLVMClearCurrentDebugLocation - LLVMValueRef add_error_return_trace_addr_fn_val = get_add_error_return_trace_addr_fn(g); - - LLVMBasicBlockRef entry_block = LLVMAppendBasicBlock(fn_val, "Entry"); - LLVMBasicBlockRef prev_block = LLVMGetInsertBlock(g->builder); - LLVMValueRef prev_debug_location = LLVMGetCurrentDebugLocation(g->builder); - LLVMPositionBuilderAtEnd(g->builder, entry_block); - ZigLLVMClearCurrentDebugLocation(g->builder); - - LLVMValueRef err_ret_trace_ptr = LLVMGetParam(fn_val, 0); - - LLVMTypeRef usize_type_ref = g->builtin_types.entry_usize->llvm_type; - LLVMValueRef zero = LLVMConstNull(get_llvm_type(g, g->builtin_types.entry_i32)); - LLVMValueRef return_address_ptr = LLVMBuildCall2(g->builder, - LLVMGlobalGetValueType(get_return_address_fn_val(g)), get_return_address_fn_val(g), &zero, 1, ""); - LLVMValueRef return_address = LLVMBuildPtrToInt(g->builder, return_address_ptr, usize_type_ref, ""); - - LLVMBasicBlockRef return_block = LLVMAppendBasicBlock(fn_val, "Return"); - LLVMBasicBlockRef dest_non_null_block = LLVMAppendBasicBlock(fn_val, "DestNonNull"); - - LLVMValueRef null_dest_bit = LLVMBuildICmp(g->builder, LLVMIntEQ, err_ret_trace_ptr, - LLVMConstNull(LLVMTypeOf(err_ret_trace_ptr)), ""); - LLVMBuildCondBr(g->builder, null_dest_bit, return_block, dest_non_null_block); - - LLVMPositionBuilderAtEnd(g->builder, return_block); - LLVMBuildRetVoid(g->builder); - - LLVMPositionBuilderAtEnd(g->builder, dest_non_null_block); - LLVMValueRef args[] = { err_ret_trace_ptr, return_address }; - ZigLLVMBuildCall(g->builder, LLVMGlobalGetValueType(add_error_return_trace_addr_fn_val), - add_error_return_trace_addr_fn_val, args, 2, - get_llvm_cc(g, CallingConventionUnspecified), ZigLLVM_CallAttrAlwaysInline, ""); - LLVMBuildRetVoid(g->builder); - - LLVMPositionBuilderAtEnd(g->builder, prev_block); - if (!g->strip_debug_symbols) { - LLVMSetCurrentDebugLocation(g->builder, prev_debug_location); - } - - g->return_err_fn = fn_val; - return fn_val; -} - -static LLVMValueRef get_safety_crash_err_fn(CodeGen *g) { - if (g->safety_crash_err_fn != nullptr) - return g->safety_crash_err_fn; - - static const char *unwrap_err_msg_text = "attempt to unwrap error: "; - - g->generate_error_name_table = true; - generate_error_name_table(g); - assert(g->err_name_table != nullptr); - - // Generate the constant part of the error message - LLVMValueRef msg_prefix_init = LLVMConstString(unwrap_err_msg_text, strlen(unwrap_err_msg_text), 1); - LLVMValueRef msg_prefix = LLVMAddGlobal(g->module, LLVMTypeOf(msg_prefix_init), ""); - LLVMSetInitializer(msg_prefix, msg_prefix_init); - LLVMSetLinkage(msg_prefix, LLVMPrivateLinkage); - LLVMSetGlobalConstant(msg_prefix, true); - - const char *fn_name = get_mangled_name(g, "__zig_fail_unwrap"); - LLVMTypeRef fn_type_ref; - if (g->have_err_ret_tracing) { - LLVMTypeRef arg_types[] = { - get_llvm_type(g, get_pointer_to_type(g, get_stack_trace_type(g), false)), - get_llvm_type(g, g->err_tag_type), - }; - fn_type_ref = LLVMFunctionType(LLVMVoidType(), arg_types, 2, false); - } else { - LLVMTypeRef arg_types[] = { - get_llvm_type(g, g->err_tag_type), - }; - fn_type_ref = LLVMFunctionType(LLVMVoidType(), arg_types, 1, false); - } - LLVMValueRef fn_val = LLVMAddFunction(g->module, fn_name, fn_type_ref); - addLLVMFnAttr(fn_val, "noreturn"); - addLLVMFnAttr(fn_val, "cold"); - LLVMSetLinkage(fn_val, LLVMInternalLinkage); - ZigLLVMFunctionSetCallingConv(fn_val, get_llvm_cc(g, CallingConventionUnspecified)); - add_common_fn_attributes(g, fn_val); - if (!g->omit_frame_pointer) { - ZigLLVMAddFunctionAttr(fn_val, "frame-pointer", "all"); - } - // Not setting alignment here. See the comment above about - // "Cannot getTypeInfo() on a type that is unsized!" - // assertion failure on Darwin. - - LLVMBasicBlockRef entry_block = LLVMAppendBasicBlock(fn_val, "Entry"); - LLVMBasicBlockRef prev_block = LLVMGetInsertBlock(g->builder); - LLVMValueRef prev_debug_location = LLVMGetCurrentDebugLocation(g->builder); - LLVMPositionBuilderAtEnd(g->builder, entry_block); - ZigLLVMClearCurrentDebugLocation(g->builder); - - ZigType *usize_ty = g->builtin_types.entry_usize; - ZigType *u8_ptr_type = get_pointer_to_type_extra(g, g->builtin_types.entry_u8, true, false, - PtrLenUnknown, get_abi_alignment(g, g->builtin_types.entry_u8), 0, 0, false); - ZigType *str_type = get_slice_type(g, u8_ptr_type); - - // Allocate a buffer to hold the fully-formatted error message - const size_t err_buf_len = strlen(unwrap_err_msg_text) + g->largest_err_name_len; - LLVMValueRef max_msg_len = LLVMConstInt(usize_ty->llvm_type, err_buf_len, 0); - LLVMValueRef msg_buffer = LLVMBuildArrayAlloca(g->builder, LLVMInt8Type(), max_msg_len, "msg_buffer"); - - // Allocate a []u8 slice for the message - LLVMValueRef msg_slice = build_alloca(g, str_type, "msg_slice", 0); - - LLVMValueRef err_ret_trace_arg; - LLVMValueRef err_val; - if (g->have_err_ret_tracing) { - err_ret_trace_arg = LLVMGetParam(fn_val, 0); - err_val = LLVMGetParam(fn_val, 1); - } else { - err_ret_trace_arg = nullptr; - err_val = LLVMGetParam(fn_val, 0); - } - - // Fetch the error name from the global table - LLVMValueRef err_table_indices[] = { - LLVMConstNull(usize_ty->llvm_type), - err_val, - }; - LLVMValueRef err_name_val = LLVMBuildInBoundsGEP2(g->builder, - LLVMGlobalGetValueType(g->err_name_table), - g->err_name_table, err_table_indices, 2, ""); - - LLVMValueRef ptr_field_ptr = LLVMBuildStructGEP2(g->builder, - ZigLLVMGetGEPResultElementType(err_name_val), err_name_val, slice_ptr_index, ""); - LLVMValueRef err_name_ptr = gen_load_untyped(g, ZigLLVMGetGEPResultElementType(ptr_field_ptr), - ptr_field_ptr, 0, false, ""); - - LLVMValueRef len_field_ptr = LLVMBuildStructGEP2(g->builder, - ZigLLVMGetGEPResultElementType(err_name_val), err_name_val, slice_len_index, ""); - LLVMValueRef err_name_len = gen_load_untyped(g, ZigLLVMGetGEPResultElementType(len_field_ptr), - len_field_ptr, 0, false, ""); - - LLVMValueRef msg_prefix_len = LLVMConstInt(usize_ty->llvm_type, strlen(unwrap_err_msg_text), false); - // Points to the beginning of msg_buffer - LLVMValueRef msg_buffer_ptr_indices[] = { - LLVMConstNull(usize_ty->llvm_type), - }; - LLVMValueRef msg_buffer_ptr = LLVMBuildInBoundsGEP2(g->builder, LLVMInt8Type(), msg_buffer, - msg_buffer_ptr_indices, 1, ""); - // Points to the beginning of the constant prefix message - LLVMValueRef msg_prefix_ptr_indices[] = { - LLVMConstNull(usize_ty->llvm_type), - }; - LLVMValueRef msg_prefix_ptr = LLVMConstInBoundsGEP2(LLVMInt8Type(), msg_prefix, msg_prefix_ptr_indices, 1); - - // Build the message using the prefix... - ZigLLVMBuildMemCpy(g->builder, msg_buffer_ptr, 1, msg_prefix_ptr, 1, msg_prefix_len, false); - // ..and append the error name - LLVMValueRef msg_buffer_ptr_after_indices[] = { - msg_prefix_len, - }; - LLVMValueRef msg_buffer_ptr_after = LLVMBuildInBoundsGEP2(g->builder, LLVMInt8Type(), msg_buffer, msg_buffer_ptr_after_indices, 1, ""); - ZigLLVMBuildMemCpy(g->builder, msg_buffer_ptr_after, 1, err_name_ptr, 1, err_name_len, false); - - // Set the slice pointer - LLVMValueRef msg_slice_ptr_field_ptr = LLVMBuildStructGEP2(g->builder, - get_llvm_type(g, str_type), msg_slice, slice_ptr_index, ""); - gen_store_untyped(g, msg_buffer_ptr, msg_slice_ptr_field_ptr, 0, false); - - // Set the slice length - LLVMValueRef slice_len = LLVMBuildNUWAdd(g->builder, msg_prefix_len, err_name_len, ""); - LLVMValueRef msg_slice_len_field_ptr = LLVMBuildStructGEP2(g->builder, - get_llvm_type(g, str_type), msg_slice, slice_len_index, ""); - gen_store_untyped(g, slice_len, msg_slice_len_field_ptr, 0, false); - - // Call panic() - gen_panic(g, msg_slice, err_ret_trace_arg, false); - - LLVMPositionBuilderAtEnd(g->builder, prev_block); - if (!g->strip_debug_symbols) { - LLVMSetCurrentDebugLocation(g->builder, prev_debug_location); - } - - g->safety_crash_err_fn = fn_val; - return fn_val; -} - -static LLVMValueRef get_cur_err_ret_trace_val(CodeGen *g, Scope *scope, bool *is_llvm_alloca) { - if (!g->have_err_ret_tracing) { - *is_llvm_alloca = false; - return nullptr; - } - if (g->cur_err_ret_trace_val_stack != nullptr) { - *is_llvm_alloca = !fn_is_async(g->cur_fn); - return g->cur_err_ret_trace_val_stack; - } - *is_llvm_alloca = false; - return g->cur_err_ret_trace_val_arg; -} - -static void gen_safety_crash_for_err(CodeGen *g, LLVMValueRef err_val, Scope *scope) { - LLVMValueRef safety_crash_err_fn = get_safety_crash_err_fn(g); - LLVMValueRef call_instruction; - bool is_llvm_alloca = false; - if (g->have_err_ret_tracing) { - LLVMValueRef err_ret_trace_val = get_cur_err_ret_trace_val(g, scope, &is_llvm_alloca); - if (err_ret_trace_val == nullptr) { - err_ret_trace_val = LLVMConstNull(get_llvm_type(g, ptr_to_stack_trace_type(g))); - } - LLVMValueRef args[] = { - err_ret_trace_val, - err_val, - }; - call_instruction = ZigLLVMBuildCall(g->builder, LLVMGlobalGetValueType(safety_crash_err_fn), - safety_crash_err_fn, args, 2, - get_llvm_cc(g, CallingConventionUnspecified), ZigLLVM_CallAttrAuto, ""); - } else { - LLVMValueRef args[] = { - err_val, - }; - call_instruction = ZigLLVMBuildCall(g->builder, LLVMGlobalGetValueType(safety_crash_err_fn), - safety_crash_err_fn, args, 1, - get_llvm_cc(g, CallingConventionUnspecified), ZigLLVM_CallAttrAuto, ""); - } - if (!is_llvm_alloca) { - LLVMSetTailCall(call_instruction, true); - } - LLVMBuildUnreachable(g->builder); -} - -static void add_bounds_check(CodeGen *g, LLVMValueRef target_val, - LLVMIntPredicate lower_pred, LLVMValueRef lower_value, - LLVMIntPredicate upper_pred, LLVMValueRef upper_value) -{ - if (!lower_value && !upper_value) { - return; - } - if (upper_value && !lower_value) { - lower_value = upper_value; - lower_pred = upper_pred; - upper_value = nullptr; - } - - LLVMBasicBlockRef bounds_check_fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "BoundsCheckFail"); - LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "BoundsCheckOk"); - LLVMBasicBlockRef lower_ok_block = upper_value ? - LLVMAppendBasicBlock(g->cur_fn_val, "FirstBoundsCheckOk") : ok_block; - - LLVMValueRef lower_ok_val = LLVMBuildICmp(g->builder, lower_pred, target_val, lower_value, ""); - LLVMBuildCondBr(g->builder, lower_ok_val, lower_ok_block, bounds_check_fail_block); - - LLVMPositionBuilderAtEnd(g->builder, bounds_check_fail_block); - gen_safety_crash(g, PanicMsgIdBoundsCheckFailure); - - if (upper_value) { - LLVMPositionBuilderAtEnd(g->builder, lower_ok_block); - LLVMValueRef upper_ok_val = LLVMBuildICmp(g->builder, upper_pred, target_val, upper_value, ""); - LLVMBuildCondBr(g->builder, upper_ok_val, ok_block, bounds_check_fail_block); - } - - LLVMPositionBuilderAtEnd(g->builder, ok_block); -} - -static void add_sentinel_check(CodeGen *g, LLVMValueRef sentinel_elem_ptr, ZigValue *sentinel) { - LLVMValueRef expected_sentinel = gen_const_val(g, sentinel, ""); - - LLVMValueRef actual_sentinel = gen_load_untyped(g, LLVMTypeOf(expected_sentinel), sentinel_elem_ptr, 0, false, ""); - LLVMValueRef ok_bit; - if (sentinel->type->id == ZigTypeIdFloat) { - ok_bit = LLVMBuildFCmp(g->builder, LLVMRealOEQ, actual_sentinel, expected_sentinel, ""); - } else { - ok_bit = LLVMBuildICmp(g->builder, LLVMIntEQ, actual_sentinel, expected_sentinel, ""); - } - - LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "SentinelFail"); - LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "SentinelOk"); - LLVMBuildCondBr(g->builder, ok_bit, ok_block, fail_block); - - LLVMPositionBuilderAtEnd(g->builder, fail_block); - gen_safety_crash(g, PanicMsgIdBadSentinel); - - LLVMPositionBuilderAtEnd(g->builder, ok_block); -} - -static LLVMValueRef gen_assert_zero(CodeGen *g, LLVMValueRef expr_val, ZigType *int_type) { - LLVMValueRef zero = LLVMConstNull(get_llvm_type(g, int_type)); - LLVMValueRef ok_bit = LLVMBuildICmp(g->builder, LLVMIntEQ, expr_val, zero, ""); - if (int_type->id == ZigTypeIdVector) { - ok_bit = ZigLLVMBuildAndReduce(g->builder, ok_bit); - } - LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "CastShortenOk"); - LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "CastShortenFail"); - LLVMBuildCondBr(g->builder, ok_bit, ok_block, fail_block); - - LLVMPositionBuilderAtEnd(g->builder, fail_block); - gen_safety_crash(g, PanicMsgIdCastTruncatedData); - - LLVMPositionBuilderAtEnd(g->builder, ok_block); - return nullptr; -} - -static const char *get_compiler_rt_type_abbrev(ZigType *type) { - uint16_t bits; - if (type->id == ZigTypeIdFloat) { - bits = type->data.floating.bit_count; - } else if (type->id == ZigTypeIdInt) { - bits = type->data.integral.bit_count; - } else { - zig_unreachable(); - } - switch (bits) { - case 16: - return "h"; - case 32: - return "s"; - case 64: - return "d"; - case 80: - return "x"; - case 128: - return "t"; - default: - zig_unreachable(); - } -} - -static const char *libc_float_prefix(CodeGen *g, ZigType *float_type) { - switch (float_type->data.floating.bit_count) { - case 16: - case 80: - return "__"; - case 32: - case 64: - case 128: - return ""; - default: - zig_unreachable(); - } -} - -static const char *libc_float_suffix(CodeGen *g, ZigType *float_type) { - switch (float_type->size_in_bits) { - case 16: return "h"; // Non-standard - case 32: return "f"; - case 64: return ""; - case 80: return "x"; // Non-standard - case 128: return "q"; // Non-standard - default: zig_unreachable(); - } -} - -static LLVMValueRef gen_soft_float_widen_or_shorten(CodeGen *g, ZigType *actual_type, - ZigType *wanted_type, LLVMValueRef expr_val) -{ - ZigType *scalar_actual_type = (actual_type->id == ZigTypeIdVector) ? - actual_type->data.vector.elem_type : actual_type; - ZigType *scalar_wanted_type = (wanted_type->id == ZigTypeIdVector) ? - wanted_type->data.vector.elem_type : wanted_type; - uint64_t actual_bits = scalar_actual_type->data.floating.bit_count; - uint64_t wanted_bits = scalar_wanted_type->data.floating.bit_count; - - if (actual_bits == wanted_bits) - return expr_val; - - LLVMValueRef result; - bool castTruncatedToF16 = false; - - char fn_name[64]; - if (wanted_bits < actual_bits) { - snprintf(fn_name, sizeof(fn_name), "__trunc%sf%sf2", - get_compiler_rt_type_abbrev(scalar_actual_type), - get_compiler_rt_type_abbrev(scalar_wanted_type)); - } else { - snprintf(fn_name, sizeof(fn_name), "__extend%sf%sf2", - get_compiler_rt_type_abbrev(scalar_actual_type), - get_compiler_rt_type_abbrev(scalar_wanted_type)); - } - - LLVMTypeRef return_type = scalar_wanted_type->llvm_type; - LLVMTypeRef param_type = scalar_actual_type->llvm_type; - - if (!target_is_arm(g->zig_target)) { - // Only Arm has a native f16 type, other platforms soft-implement it using u16 instead. - if (scalar_wanted_type == g->builtin_types.entry_f16) { - return_type = g->builtin_types.entry_u16->llvm_type; - castTruncatedToF16 = true; - } - if (scalar_actual_type == g->builtin_types.entry_f16) { - param_type = g->builtin_types.entry_u16->llvm_type; - expr_val = LLVMBuildBitCast(g->builder, expr_val, param_type, ""); - } - } - - LLVMValueRef func_ref = get_soft_float_fn(g, fn_name, 1, param_type, return_type); - result = LLVMBuildCall2(g->builder, LLVMGlobalGetValueType(func_ref), func_ref, &expr_val, 1, ""); - - // On non-Arm platforms we need to bitcast __trunc<>fhf2 result back to f16 - if (castTruncatedToF16) { - result = LLVMBuildBitCast(g->builder, result, g->builtin_types.entry_f16->llvm_type, ""); - } - - return result; -} - -static LLVMValueRef gen_widen_or_shorten(CodeGen *g, bool want_runtime_safety, ZigType *actual_type, - ZigType *wanted_type, LLVMValueRef expr_val) -{ - assert(actual_type->id == wanted_type->id); - - ZigType *scalar_actual_type = (actual_type->id == ZigTypeIdVector) ? - actual_type->data.vector.elem_type : actual_type; - ZigType *scalar_wanted_type = (wanted_type->id == ZigTypeIdVector) ? - wanted_type->data.vector.elem_type : wanted_type; - - uint64_t actual_bits; - uint64_t wanted_bits; - if (scalar_actual_type->id == ZigTypeIdFloat) { - - if (((scalar_actual_type == g->builtin_types.entry_f80 - || scalar_wanted_type == g->builtin_types.entry_f80) - && !target_has_f80(g->zig_target)) || - ((scalar_actual_type == g->builtin_types.entry_f16 - || scalar_wanted_type == g->builtin_types.entry_f16) - && !target_is_arm(g->zig_target))) - { - return gen_soft_float_widen_or_shorten(g, actual_type, wanted_type, expr_val); - } - actual_bits = scalar_actual_type->data.floating.bit_count; - wanted_bits = scalar_wanted_type->data.floating.bit_count; - } else if (scalar_actual_type->id == ZigTypeIdInt) { - actual_bits = scalar_actual_type->data.integral.bit_count; - wanted_bits = scalar_wanted_type->data.integral.bit_count; - } else { - zig_unreachable(); - } - - if (expr_val == nullptr) { - if (scalar_actual_type->id == ZigTypeIdInt && actual_bits == 0) { - if (wanted_bits == 0) { - return expr_val; - } else { - LLVMValueRef zero = LLVMConstNull(get_llvm_type(g, wanted_type)); - return zero; - } - } else { - zig_unreachable(); - } - } - - if (scalar_actual_type->id == ZigTypeIdInt && want_runtime_safety && ( - // negative to unsigned - (!scalar_wanted_type->data.integral.is_signed && scalar_actual_type->data.integral.is_signed) || - // unsigned would become negative - (scalar_wanted_type->data.integral.is_signed && !scalar_actual_type->data.integral.is_signed && actual_bits == wanted_bits))) - { - LLVMValueRef zero = LLVMConstNull(get_llvm_type(g, actual_type)); - LLVMValueRef ok_bit = LLVMBuildICmp(g->builder, LLVMIntSGE, expr_val, zero, ""); - - LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "SignCastOk"); - LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "SignCastFail"); - if (actual_type->id == ZigTypeIdVector) { - ok_bit = ZigLLVMBuildAndReduce(g->builder, ok_bit); - } - LLVMBuildCondBr(g->builder, ok_bit, ok_block, fail_block); - - LLVMPositionBuilderAtEnd(g->builder, fail_block); - gen_safety_crash(g, scalar_actual_type->data.integral.is_signed ? PanicMsgIdCastNegativeToUnsigned : PanicMsgIdCastTruncatedData); - - LLVMPositionBuilderAtEnd(g->builder, ok_block); - } - - if (actual_bits == wanted_bits) { - return expr_val; - } else if (actual_bits < wanted_bits) { - if (scalar_actual_type->id == ZigTypeIdFloat) { - return LLVMBuildFPExt(g->builder, expr_val, get_llvm_type(g, wanted_type), ""); - } else if (scalar_actual_type->id == ZigTypeIdInt) { - if (scalar_actual_type->data.integral.is_signed) { - return LLVMBuildSExt(g->builder, expr_val, get_llvm_type(g, wanted_type), ""); - } else { - return LLVMBuildZExt(g->builder, expr_val, get_llvm_type(g, wanted_type), ""); - } - } else { - zig_unreachable(); - } - } else if (actual_bits > wanted_bits) { - if (scalar_actual_type->id == ZigTypeIdFloat) { - return LLVMBuildFPTrunc(g->builder, expr_val, get_llvm_type(g, wanted_type), ""); - } else if (scalar_actual_type->id == ZigTypeIdInt) { - if (wanted_bits == 0) { - if (!want_runtime_safety) - return nullptr; - - return gen_assert_zero(g, expr_val, actual_type); - } - LLVMValueRef trunc_val = LLVMBuildTrunc(g->builder, expr_val, get_llvm_type(g, wanted_type), ""); - if (!want_runtime_safety) { - return trunc_val; - } - LLVMValueRef orig_val; - if (scalar_wanted_type->data.integral.is_signed) { - orig_val = LLVMBuildSExt(g->builder, trunc_val, get_llvm_type(g, actual_type), ""); - } else { - orig_val = LLVMBuildZExt(g->builder, trunc_val, get_llvm_type(g, actual_type), ""); - } - LLVMValueRef ok_bit = LLVMBuildICmp(g->builder, LLVMIntEQ, expr_val, orig_val, ""); - if (actual_type->id == ZigTypeIdVector) { - ok_bit = ZigLLVMBuildAndReduce(g->builder, ok_bit); - } - LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "CastShortenOk"); - LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "CastShortenFail"); - LLVMBuildCondBr(g->builder, ok_bit, ok_block, fail_block); - - LLVMPositionBuilderAtEnd(g->builder, fail_block); - gen_safety_crash(g, PanicMsgIdCastTruncatedData); - - LLVMPositionBuilderAtEnd(g->builder, ok_block); - return trunc_val; - } else { - zig_unreachable(); - } - } else { - zig_unreachable(); - } -} - -typedef LLVMValueRef (*BuildBinOpFunc)(LLVMBuilderRef, LLVMValueRef, LLVMValueRef, const char *); -// These are lookup table using the AddSubMul enum as the lookup. -// If AddSubMul ever changes, then these tables will be out of -// date. -static const BuildBinOpFunc float_op[3] = { LLVMBuildFAdd, LLVMBuildFSub, LLVMBuildFMul }; -static const BuildBinOpFunc wrap_op[3] = { LLVMBuildAdd, LLVMBuildSub, LLVMBuildMul }; -static const BuildBinOpFunc signed_op[3] = { LLVMBuildNSWAdd, LLVMBuildNSWSub, LLVMBuildNSWMul }; -static const BuildBinOpFunc unsigned_op[3] = { LLVMBuildNUWAdd, LLVMBuildNUWSub, LLVMBuildNUWMul }; - -static LLVMValueRef gen_overflow_op(CodeGen *g, ZigType *operand_type, AddSubMul op, - LLVMValueRef val1, LLVMValueRef val2) -{ - LLVMValueRef fn_val = get_int_overflow_fn(g, operand_type, op); - LLVMValueRef params[] = { - val1, - val2, - }; - LLVMValueRef result_struct = LLVMBuildCall2(g->builder, LLVMGlobalGetValueType(fn_val), fn_val, params, 2, ""); - LLVMValueRef result = LLVMBuildExtractValue(g->builder, result_struct, 0, ""); - LLVMValueRef overflow_bit = LLVMBuildExtractValue(g->builder, result_struct, 1, ""); - if (operand_type->id == ZigTypeIdVector) { - overflow_bit = ZigLLVMBuildOrReduce(g->builder, overflow_bit); - } - - LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "OverflowFail"); - LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "OverflowOk"); - LLVMBuildCondBr(g->builder, overflow_bit, fail_block, ok_block); - - LLVMPositionBuilderAtEnd(g->builder, fail_block); - gen_safety_crash(g, PanicMsgIdIntegerOverflow); - - LLVMPositionBuilderAtEnd(g->builder, ok_block); - return result; -} - -static LLVMIntPredicate cmp_op_to_int_predicate(IrBinOp cmp_op, bool is_signed) { - switch (cmp_op) { - case IrBinOpCmpEq: - return LLVMIntEQ; - case IrBinOpCmpNotEq: - return LLVMIntNE; - case IrBinOpCmpLessThan: - return is_signed ? LLVMIntSLT : LLVMIntULT; - case IrBinOpCmpGreaterThan: - return is_signed ? LLVMIntSGT : LLVMIntUGT; - case IrBinOpCmpLessOrEq: - return is_signed ? LLVMIntSLE : LLVMIntULE; - case IrBinOpCmpGreaterOrEq: - return is_signed ? LLVMIntSGE : LLVMIntUGE; - default: - zig_unreachable(); - } -} - -static LLVMRealPredicate cmp_op_to_real_predicate(IrBinOp cmp_op) { - switch (cmp_op) { - case IrBinOpCmpEq: - return LLVMRealOEQ; - case IrBinOpCmpNotEq: - return LLVMRealUNE; - case IrBinOpCmpLessThan: - return LLVMRealOLT; - case IrBinOpCmpGreaterThan: - return LLVMRealOGT; - case IrBinOpCmpLessOrEq: - return LLVMRealOLE; - case IrBinOpCmpGreaterOrEq: - return LLVMRealOGE; - default: - zig_unreachable(); - } -} - -static void gen_assign_raw(CodeGen *g, LLVMValueRef ptr, ZigType *ptr_type, - LLVMValueRef value) -{ - assert(ptr_type->id == ZigTypeIdPointer); - ZigType *child_type = ptr_type->data.pointer.child_type; - - if (!type_has_bits(g, child_type)) - return; - - if (handle_is_ptr(g, child_type)) { - assert(LLVMGetTypeKind(LLVMTypeOf(value)) == LLVMPointerTypeKind); - assert(LLVMGetTypeKind(LLVMTypeOf(ptr)) == LLVMPointerTypeKind); - - LLVMTypeRef ptr_u8 = LLVMPointerType(LLVMInt8Type(), 0); - - LLVMValueRef src_ptr = LLVMBuildBitCast(g->builder, value, ptr_u8, ""); - LLVMValueRef dest_ptr = LLVMBuildBitCast(g->builder, ptr, ptr_u8, ""); - - ZigType *usize = g->builtin_types.entry_usize; - uint64_t size_bytes = LLVMStoreSizeOfType(g->target_data_ref, get_llvm_type(g, child_type)); - uint64_t src_align_bytes = get_abi_alignment(g, child_type); - uint64_t dest_align_bytes = get_ptr_align(g, ptr_type); - assert(size_bytes > 0); - assert(src_align_bytes > 0); - assert(dest_align_bytes > 0); - - ZigLLVMBuildMemCpy(g->builder, dest_ptr, dest_align_bytes, src_ptr, src_align_bytes, - LLVMConstInt(usize->llvm_type, size_bytes, false), - ptr_type->data.pointer.is_volatile); - return; - } - - assert(ptr_type->data.pointer.vector_index != VECTOR_INDEX_RUNTIME); - if (ptr_type->data.pointer.vector_index != VECTOR_INDEX_NONE) { - LLVMValueRef index_val = LLVMConstInt(LLVMInt32Type(), - ptr_type->data.pointer.vector_index, false); - uint32_t vec_len = ptr_type->data.pointer.host_int_bytes; - LLVMTypeRef vec_llvm_ty = LLVMVectorType(get_llvm_type(g, ptr_type->data.pointer.child_type), vec_len); - LLVMValueRef loaded_vector = gen_load_untyped(g, vec_llvm_ty, ptr, - get_ptr_align(g, ptr_type), ptr_type->data.pointer.is_volatile, ""); - LLVMValueRef new_vector = LLVMBuildInsertElement(g->builder, loaded_vector, value, - index_val, ""); - gen_store(g, new_vector, ptr, ptr_type); - return; - } - - uint32_t host_int_bytes = ptr_type->data.pointer.host_int_bytes; - if (host_int_bytes == 0) { - gen_store(g, value, ptr, ptr_type); - return; - } - - bool big_endian = g->is_big_endian; - - LLVMTypeRef int_ptr_ty = LLVMPointerType(LLVMIntType(host_int_bytes * 8), 0); - LLVMValueRef int_ptr = LLVMBuildBitCast(g->builder, ptr, int_ptr_ty, ""); - LLVMValueRef containing_int = gen_load_untyped(g, LLVMIntType(host_int_bytes * 8), int_ptr, - get_ptr_align(g, ptr_type), ptr_type->data.pointer.is_volatile, ""); - uint32_t host_bit_count = LLVMGetIntTypeWidth(LLVMTypeOf(containing_int)); - assert(host_bit_count == host_int_bytes * 8); - uint32_t size_in_bits = type_size_bits(g, child_type); - - uint32_t bit_offset = ptr_type->data.pointer.bit_offset_in_host; - uint32_t shift_amt = big_endian ? host_bit_count - bit_offset - size_in_bits : bit_offset; - LLVMValueRef shift_amt_val = LLVMConstInt(LLVMTypeOf(containing_int), shift_amt, false); - - // Convert to equally-sized integer type in order to perform the bit - // operations on the value to store - LLVMTypeRef value_bits_type = LLVMIntType(size_in_bits); - LLVMValueRef value_bits = LLVMBuildBitCast(g->builder, value, value_bits_type, ""); - - LLVMValueRef mask_val = LLVMConstAllOnes(value_bits_type); - mask_val = LLVMConstZExt(mask_val, LLVMTypeOf(containing_int)); - mask_val = LLVMConstShl(mask_val, shift_amt_val); - mask_val = LLVMConstNot(mask_val); - - LLVMValueRef anded_containing_int = LLVMBuildAnd(g->builder, containing_int, mask_val, ""); - LLVMValueRef extended_value = LLVMBuildZExt(g->builder, value_bits, LLVMTypeOf(containing_int), ""); - LLVMValueRef shifted_value = LLVMBuildShl(g->builder, extended_value, shift_amt_val, ""); - LLVMValueRef ored_value = LLVMBuildOr(g->builder, shifted_value, anded_containing_int, ""); - - gen_store(g, ored_value, int_ptr, ptr_type); -} - -static void gen_var_debug_decl(CodeGen *g, ZigVar *var) { - if (g->strip_debug_symbols) return; - assert(var->di_loc_var != nullptr); - AstNode *source_node = var->decl_node; - ZigLLVMDILocation *debug_loc = ZigLLVMGetDebugLoc(node_line_onebased(source_node), - node_column_onebased(source_node), get_di_scope(g, var->parent_scope)); - ZigLLVMInsertDeclareAtEnd(g->dbuilder, var->value_ref, var->di_loc_var, debug_loc, - LLVMGetInsertBlock(g->builder)); -} - -static LLVMValueRef ir_llvm_value(CodeGen *g, Stage1AirInst *instruction) { - Error err; - - bool value_has_bits; - if ((err = type_has_bits2(g, instruction->value->type, &value_has_bits))) - codegen_report_errors_and_exit(g); - - if (!value_has_bits) - return nullptr; - - if (!instruction->llvm_value) { - if (instruction->id == Stage1AirInstIdAwait) { - Stage1AirInstAwait *await = reinterpret_cast(instruction); - if (await->result_loc != nullptr) { - return get_handle_value(g, ir_llvm_value(g, await->result_loc), - await->result_loc->value->type->data.pointer.child_type, await->result_loc->value->type); - } - } - if (instruction->spill != nullptr) { - ZigType *ptr_type = instruction->spill->value->type; - ir_assert(ptr_type->id == ZigTypeIdPointer, instruction); - return get_handle_value(g, ir_llvm_value(g, instruction->spill), - ptr_type->data.pointer.child_type, instruction->spill->value->type); - } - ir_assert(instruction->value->special != ConstValSpecialRuntime, instruction); - assert(instruction->value->type); - render_const_val(g, instruction->value, ""); - // we might have to do some pointer casting here due to the way union - // values are rendered with a type other than the one we expect - if (handle_is_ptr(g, instruction->value->type)) { - render_const_val_global(g, instruction->value, ""); - ZigType *ptr_type = get_pointer_to_type(g, instruction->value->type, true); - instruction->llvm_value = LLVMBuildBitCast(g->builder, instruction->value->llvm_global, get_llvm_type(g, ptr_type), ""); - } else { - instruction->llvm_value = LLVMBuildBitCast(g->builder, instruction->value->llvm_value, - get_llvm_type(g, instruction->value->type), ""); - } - assert(instruction->llvm_value); - } - return instruction->llvm_value; -} - -void codegen_report_errors_and_exit(CodeGen *g) { - // Clear progress indicator before printing errors - if (g->sub_progress_node != nullptr) { - stage2_progress_end(g->sub_progress_node); - g->sub_progress_node = nullptr; - } - if (g->main_progress_node != nullptr) { - stage2_progress_end(g->main_progress_node); - g->main_progress_node = nullptr; - } - - assert(g->errors.length != 0); - for (size_t i = 0; i < g->errors.length; i += 1) { - ErrorMsg *err = g->errors.at(i); - print_err_msg(err, g->err_color); - } - exit(1); -} - -static void report_errors_and_maybe_exit(CodeGen *g) { - if (g->errors.length != 0) { - codegen_report_errors_and_exit(g); - } -} - -ATTRIBUTE_NORETURN -static void give_up_with_c_abi_error(CodeGen *g, AstNode *source_node) { - ErrorMsg *msg = add_node_error(g, source_node, - buf_sprintf("TODO: support C ABI for more targets. https://github.com/ziglang/zig/issues/1481")); - add_error_note(g, msg, source_node, - buf_sprintf("pointers, integers, floats, bools, and enums work on all targets")); - codegen_report_errors_and_exit(g); -} - -static LLVMValueRef build_alloca(CodeGen *g, ZigType *type_entry, const char *name, uint32_t alignment) { - LLVMValueRef result = LLVMBuildAlloca(g->builder, get_llvm_type(g, type_entry), name); - LLVMSetAlignment(result, (alignment == 0) ? get_abi_alignment(g, type_entry) : alignment); - return result; -} - -static bool iter_function_params_c_abi(CodeGen *g, ZigType *fn_type, FnWalk *fn_walk, size_t src_i) { - // Initialized from the type for some walks, but because of C var args, - // initialized based on callsite instructions for that one. - FnTypeParamInfo *param_info = nullptr; - ZigType *ty; - ZigType *dest_ty = nullptr; - AstNode *source_node = nullptr; - LLVMValueRef val; - LLVMValueRef llvm_fn; - unsigned di_arg_index; - ZigVar *var; - switch (fn_walk->id) { - case FnWalkIdAttrs: - if (src_i >= fn_type->data.fn.fn_type_id.param_count) - return false; - param_info = &fn_type->data.fn.fn_type_id.param_info[src_i]; - ty = param_info->type; - source_node = fn_walk->data.attrs.fn->proto_node; - llvm_fn = fn_walk->data.attrs.llvm_fn; - break; - case FnWalkIdCall: { - if (src_i >= fn_walk->data.call.inst->arg_count) - return false; - Stage1AirInst *arg = fn_walk->data.call.inst->args[src_i]; - ty = arg->value->type; - source_node = arg->source_node; - val = ir_llvm_value(g, arg); - break; - } - case FnWalkIdTypes: - if (src_i >= fn_type->data.fn.fn_type_id.param_count) - return false; - param_info = &fn_type->data.fn.fn_type_id.param_info[src_i]; - ty = param_info->type; - break; - case FnWalkIdVars: - assert(src_i < fn_type->data.fn.fn_type_id.param_count); - param_info = &fn_type->data.fn.fn_type_id.param_info[src_i]; - ty = param_info->type; - var = fn_walk->data.vars.var; - source_node = var->decl_node; - llvm_fn = fn_walk->data.vars.llvm_fn; - break; - case FnWalkIdInits: - if (src_i >= fn_type->data.fn.fn_type_id.param_count) - return false; - param_info = &fn_type->data.fn.fn_type_id.param_info[src_i]; - ty = param_info->type; - var = fn_walk->data.inits.fn->variable_list.at(src_i); - source_node = fn_walk->data.inits.fn->proto_node; - llvm_fn = fn_walk->data.inits.llvm_fn; - break; - } - - if (type_is_c_abi_int_bail(g, ty) || ty->id == ZigTypeIdFloat || ty->id == ZigTypeIdVector || - ty->id == ZigTypeIdInt // TODO investigate if we need to change this - ) { - switch (fn_walk->id) { - case FnWalkIdAttrs: { - ZigType *ptr_type = get_codegen_ptr_type_bail(g, ty); - if (ptr_type != nullptr) { - if (type_is_nonnull_ptr(g, ty)) { - addLLVMArgAttr(llvm_fn, fn_walk->data.attrs.gen_i, "nonnull"); - } - if (ptr_type->id == ZigTypeIdPointer && ptr_type->data.pointer.is_const) { - addLLVMArgAttr(llvm_fn, fn_walk->data.attrs.gen_i, "readonly"); - } - if (param_info->is_noalias) { - addLLVMArgAttr(llvm_fn, fn_walk->data.attrs.gen_i, "noalias"); - } - } - fn_walk->data.attrs.gen_i += 1; - break; - } - case FnWalkIdCall: - fn_walk->data.call.gen_param_values->append(val); - break; - case FnWalkIdTypes: - fn_walk->data.types.gen_param_types->append(get_llvm_type(g, ty)); - fn_walk->data.types.param_di_types->append(get_llvm_di_type(g, ty)); - break; - case FnWalkIdVars: { - var->value_ref = build_alloca(g, ty, var->name, var->align_bytes); - di_arg_index = fn_walk->data.vars.gen_i; - fn_walk->data.vars.gen_i += 1; - dest_ty = ty; - goto var_ok; - } - case FnWalkIdInits: - clear_debug_source_node(g); - gen_store_untyped(g, LLVMGetParam(llvm_fn, fn_walk->data.inits.gen_i), var->value_ref, var->align_bytes, false); - if (var->decl_node) { - gen_var_debug_decl(g, var); - } - fn_walk->data.inits.gen_i += 1; - break; - } - return true; - } - - { - // Arrays are just pointers - if (ty->id == ZigTypeIdArray) { - assert(handle_is_ptr(g, ty)); - switch (fn_walk->id) { - case FnWalkIdAttrs: - // arrays passed to C ABI functions may not be at address 0 - addLLVMArgAttr(llvm_fn, fn_walk->data.attrs.gen_i, "nonnull"); - addLLVMArgAttrInt(llvm_fn, fn_walk->data.attrs.gen_i, "align", get_abi_alignment(g, ty)); - fn_walk->data.attrs.gen_i += 1; - break; - case FnWalkIdCall: - fn_walk->data.call.gen_param_values->append(val); - break; - case FnWalkIdTypes: { - ZigType *gen_type = get_pointer_to_type(g, ty, true); - fn_walk->data.types.gen_param_types->append(get_llvm_type(g, gen_type)); - fn_walk->data.types.param_di_types->append(get_llvm_di_type(g, gen_type)); - break; - } - case FnWalkIdVars: { - var->value_ref = LLVMGetParam(llvm_fn, fn_walk->data.vars.gen_i); - di_arg_index = fn_walk->data.vars.gen_i; - dest_ty = get_pointer_to_type(g, ty, false); - fn_walk->data.vars.gen_i += 1; - goto var_ok; - } - case FnWalkIdInits: - if (var->decl_node) { - gen_var_debug_decl(g, var); - } - fn_walk->data.inits.gen_i += 1; - break; - } - return true; - } - - X64CABIClass abi_class = type_c_abi_x86_64_class(g, ty); - size_t ty_size = type_size(g, ty); - if (abi_class == X64CABIClass_MEMORY || abi_class == X64CABIClass_MEMORY_nobyval) { - assert(handle_is_ptr(g, ty)); - switch (fn_walk->id) { - case FnWalkIdAttrs: - if (abi_class != X64CABIClass_MEMORY_nobyval) { - ZigLLVMAddByValAttr(llvm_fn, fn_walk->data.attrs.gen_i, get_llvm_type(g, ty)); - addLLVMArgAttrInt(llvm_fn, fn_walk->data.attrs.gen_i, "align", get_abi_alignment(g, ty)); - } else if (g->zig_target->arch == ZigLLVM_aarch64 || - g->zig_target->arch == ZigLLVM_aarch64_be) - { - // no attrs needed - } else { - if (source_node != nullptr) { - give_up_with_c_abi_error(g, source_node); - } - // otherwise allow codegen code to report a compile error - return false; - } - - // Byvalue parameters must not have address 0 - addLLVMArgAttr(llvm_fn, fn_walk->data.attrs.gen_i, "nonnull"); - fn_walk->data.attrs.gen_i += 1; - break; - case FnWalkIdCall: - fn_walk->data.call.gen_param_values->append(val); - break; - case FnWalkIdTypes: { - ZigType *gen_type = get_pointer_to_type(g, ty, true); - fn_walk->data.types.gen_param_types->append(get_llvm_type(g, gen_type)); - fn_walk->data.types.param_di_types->append(get_llvm_di_type(g, gen_type)); - break; - } - case FnWalkIdVars: { - di_arg_index = fn_walk->data.vars.gen_i; - var->value_ref = LLVMGetParam(llvm_fn, fn_walk->data.vars.gen_i); - dest_ty = get_pointer_to_type(g, ty, false); - fn_walk->data.vars.gen_i += 1; - goto var_ok; - } - case FnWalkIdInits: - if (var->decl_node) { - gen_var_debug_decl(g, var); - } - fn_walk->data.inits.gen_i += 1; - break; - } - return true; - } else if (abi_class == X64CABIClass_INTEGER) { - switch (fn_walk->id) { - case FnWalkIdAttrs: - fn_walk->data.attrs.gen_i += 1; - break; - case FnWalkIdCall: { - LLVMTypeRef int_type_ref = LLVMIntType((unsigned)ty_size * 8); - LLVMValueRef bitcasted = LLVMBuildBitCast(g->builder, val, LLVMPointerType(int_type_ref, 0), ""); - LLVMValueRef loaded = LLVMBuildLoad2(g->builder, int_type_ref, bitcasted, ""); - fn_walk->data.call.gen_param_values->append(loaded); - break; - } - case FnWalkIdTypes: { - ZigType *gen_type = get_int_type(g, false, ty_size * 8); - fn_walk->data.types.gen_param_types->append(get_llvm_type(g, gen_type)); - fn_walk->data.types.param_di_types->append(get_llvm_di_type(g, gen_type)); - break; - } - case FnWalkIdVars: { - di_arg_index = fn_walk->data.vars.gen_i; - var->value_ref = build_alloca(g, ty, var->name, var->align_bytes); - fn_walk->data.vars.gen_i += 1; - dest_ty = ty; - goto var_ok; - } - case FnWalkIdInits: { - clear_debug_source_node(g); - if (!fn_is_async(fn_walk->data.inits.fn)) { - LLVMValueRef arg = LLVMGetParam(llvm_fn, fn_walk->data.inits.gen_i); - LLVMTypeRef ptr_to_int_type_ref = LLVMPointerType(LLVMIntType((unsigned)ty_size * 8), 0); - LLVMValueRef bitcasted = LLVMBuildBitCast(g->builder, var->value_ref, ptr_to_int_type_ref, ""); - gen_store_untyped(g, arg, bitcasted, var->align_bytes, false); - } - if (var->decl_node) { - gen_var_debug_decl(g, var); - } - fn_walk->data.inits.gen_i += 1; - break; - } - } - return true; - } else if (abi_class == X64CABIClass_AGG) { - // The SystemV ABI says that we have to setup 1 register per eightbyte. - // So two f32 can be passed in one f64, but 3 f32 have to be passed in 2 FP registers. - // Similarly, two i32 can be passed in one i64, but 3 i32 have to be passed in 2 registers. - // LLVM does not allow us to control registers in this way, nor to request specific - // ABI conventions. So we have to trick it into allocating the right registers, based - // on how clang does it. - - // First, we get the LLVM type corresponding to the C abi for the struct, then - // we pass each field as an argument. - - // Example: - // extern struct { - // x: f32, - // y: f32, - // z: i32, - // }; - // LLVM abi type: { double, i32 } - // const ptr = (*abi_type)*Struct; - // FP Register 1: abi_type[0] - // Register 1: abi_type[1] - - // However, if the struct fits in one register, then we'll pass it as such - size_t number_of_regs = (size_t)ceilf((float)ty_size / (float)8); - - LLVMTypeRef abi_type = get_llvm_c_abi_type(g, ty); - - assert(ty_size <= 16); - - switch (fn_walk->id) { - case FnWalkIdAttrs: { - fn_walk->data.attrs.gen_i += number_of_regs; - break; - } - case FnWalkIdCall: { - LLVMValueRef abi_ptr_to_struct = LLVMBuildBitCast(g->builder, val, LLVMPointerType(abi_type, 0), ""); - if (number_of_regs == 1) { - LLVMValueRef loaded = LLVMBuildLoad2(g->builder, abi_type, abi_ptr_to_struct, ""); - fn_walk->data.call.gen_param_values->append(loaded); - break; - } - for (uint32_t i = 0; i < number_of_regs; i += 1) { - LLVMValueRef adjusted_ptr_to_struct = LLVMBuildStructGEP2(g->builder, - abi_type, abi_ptr_to_struct, i, ""); - LLVMTypeRef field_llvm_ty = LLVMStructGetTypeAtIndex(abi_type, i); - LLVMValueRef loaded = LLVMBuildLoad2(g->builder, field_llvm_ty, - adjusted_ptr_to_struct, ""); - fn_walk->data.call.gen_param_values->append(loaded); - } - break; - } - case FnWalkIdTypes: { - if (number_of_regs == 1) { - fn_walk->data.types.gen_param_types->append(abi_type); - fn_walk->data.types.param_di_types->append(get_llvm_di_type(g, g->builtin_types.entry_f64)); - break; - } - for (uint32_t i = 0; i < number_of_regs; i += 1) { - fn_walk->data.types.gen_param_types->append(LLVMStructGetTypeAtIndex(abi_type, i)); - fn_walk->data.types.param_di_types->append(get_llvm_di_type(g, g->builtin_types.entry_f64)); - } - break; - } - case FnWalkIdVars: { - var->value_ref = build_alloca(g, ty, var->name, var->align_bytes); - di_arg_index = fn_walk->data.vars.gen_i; - fn_walk->data.vars.gen_i += 1; - dest_ty = ty; - goto var_ok; - } - case FnWalkIdInits: { - // since we're representing the struct differently as an arg, and potentially - // splitting it, we have to do some work to put it back together. - // the one reg case is straightforward, but if we used two registers we have - // to iterate through the struct abi repr fields and load them one by one. - if (number_of_regs == 1) { - LLVMValueRef arg = LLVMGetParam(llvm_fn, fn_walk->data.inits.gen_i); - LLVMTypeRef ptr_to_int_type_ref = LLVMPointerType(abi_type, 0); - LLVMValueRef bitcasted = LLVMBuildBitCast(g->builder, var->value_ref, ptr_to_int_type_ref, ""); - gen_store_untyped(g, arg, bitcasted, var->align_bytes, false); - } else { - LLVMValueRef abi_ptr_to_struct = LLVMBuildBitCast(g->builder, var->value_ref, LLVMPointerType(abi_type, 0), ""); - for (uint32_t i = 0; i < number_of_regs; i += 1) { - LLVMValueRef arg = LLVMGetParam(llvm_fn, fn_walk->data.inits.gen_i + i); - LLVMValueRef zero = LLVMConstInt(LLVMInt32Type(), 0, false); - LLVMValueRef index = LLVMConstInt(LLVMInt32Type(), i, false); - LLVMValueRef indices[] = { zero, index }; - LLVMValueRef adjusted_ptr_to_struct = LLVMBuildInBoundsGEP2(g->builder, - abi_type, abi_ptr_to_struct, indices, 2, ""); - LLVMBuildStore(g->builder, arg, adjusted_ptr_to_struct); - } - fn_walk->data.inits.gen_i += 1; - } - if (var->decl_node) { - gen_var_debug_decl(g, var); - } - fn_walk->data.inits.gen_i += 1; - break; - } - } - return true; - } - } - if (source_node != nullptr) { - give_up_with_c_abi_error(g, source_node); - } - // otherwise allow codegen code to report a compile error - return false; - -var_ok: - if (dest_ty != nullptr && var->decl_node) { - // arg index + 1 because the 0 index is return value - var->di_loc_var = ZigLLVMCreateParameterVariable(g->dbuilder, get_di_scope(g, var->parent_scope), - var->name, fn_walk->data.vars.import->data.structure.root_struct->di_file, - node_line_onebased(var->decl_node), - get_llvm_di_type(g, dest_ty), !g->strip_debug_symbols, 0, di_arg_index + 1); - } - return true; -} - -void walk_function_params(CodeGen *g, ZigType *fn_type, FnWalk *fn_walk) { - CallingConvention cc = fn_type->data.fn.fn_type_id.cc; - if (!calling_convention_allows_zig_types(cc)) { - size_t src_i = 0; - for (;;) { - if (!iter_function_params_c_abi(g, fn_type, fn_walk, src_i)) - break; - src_i += 1; - } - return; - } - if (fn_walk->id == FnWalkIdCall) { - Stage1AirInstCall *instruction = fn_walk->data.call.inst; - bool is_var_args = fn_walk->data.call.is_var_args; - for (size_t call_i = 0; call_i < instruction->arg_count; call_i += 1) { - Stage1AirInst *param_instruction = instruction->args[call_i]; - ZigType *param_type = param_instruction->value->type; - if (is_var_args || type_has_bits(g, param_type)) { - LLVMValueRef param_value = ir_llvm_value(g, param_instruction); - assert(param_value); - fn_walk->data.call.gen_param_values->append(param_value); - fn_walk->data.call.gen_param_types->append(param_type); - } - } - return; - } - size_t next_var_i = 0; - for (size_t param_i = 0; param_i < fn_type->data.fn.fn_type_id.param_count; param_i += 1) { - FnGenParamInfo *gen_info = &fn_type->data.fn.gen_param_info[param_i]; - size_t gen_index = gen_info->gen_index; - - if (gen_index == SIZE_MAX) { - continue; - } - - switch (fn_walk->id) { - case FnWalkIdAttrs: { - LLVMValueRef llvm_fn = fn_walk->data.attrs.llvm_fn; - bool is_byval = gen_info->is_byval; - FnTypeParamInfo *param_info = &fn_type->data.fn.fn_type_id.param_info[param_i]; - - ZigType *param_type = gen_info->type; - if (param_info->is_noalias) { - addLLVMArgAttr(llvm_fn, (unsigned)gen_index, "noalias"); - } - if ((param_type->id == ZigTypeIdPointer && param_type->data.pointer.is_const) || is_byval) { - addLLVMArgAttr(llvm_fn, (unsigned)gen_index, "readonly"); - } - if (get_codegen_ptr_type_bail(g, param_type) != nullptr) { - addLLVMArgAttrInt(llvm_fn, (unsigned)gen_index, "align", get_ptr_align(g, param_type)); - } - if (type_is_nonnull_ptr(g, param_type)) { - addLLVMArgAttr(llvm_fn, (unsigned)gen_index, "nonnull"); - } - break; - } - case FnWalkIdInits: { - ZigFn *fn_table_entry = fn_walk->data.inits.fn; - LLVMValueRef llvm_fn = fn_table_entry->llvm_value; - ZigVar *variable = fn_table_entry->variable_list.at(next_var_i); - assert(variable->src_arg_index != SIZE_MAX); - next_var_i += 1; - - assert(variable); - assert(variable->value_ref); - - if (!handle_is_ptr(g, variable->var_type) && !fn_is_async(fn_walk->data.inits.fn)) { - clear_debug_source_node(g); - ZigType *fn_type = fn_table_entry->type_entry; - unsigned gen_arg_index = fn_type->data.fn.gen_param_info[variable->src_arg_index].gen_index; - gen_store_untyped(g, LLVMGetParam(llvm_fn, gen_arg_index), - variable->value_ref, variable->align_bytes, false); - } - - if (variable->decl_node) { - gen_var_debug_decl(g, variable); - } - break; - } - case FnWalkIdCall: - // handled before for loop - zig_unreachable(); - case FnWalkIdTypes: - // Not called for non-c-abi - zig_unreachable(); - case FnWalkIdVars: - // iter_function_params_c_abi is called directly for this one - zig_unreachable(); - } - } -} - -static LLVMValueRef get_merge_err_ret_traces_fn_val(CodeGen *g) { - if (g->merge_err_ret_traces_fn_val) - return g->merge_err_ret_traces_fn_val; - - assert(g->stack_trace_type != nullptr); - - LLVMTypeRef param_types[] = { - get_llvm_type(g, ptr_to_stack_trace_type(g)), - get_llvm_type(g, ptr_to_stack_trace_type(g)), - }; - LLVMTypeRef fn_type_ref = LLVMFunctionType(LLVMVoidType(), param_types, 2, false); - - const char *fn_name = get_mangled_name(g, "__zig_merge_error_return_traces"); - LLVMValueRef fn_val = LLVMAddFunction(g->module, fn_name, fn_type_ref); - LLVMSetLinkage(fn_val, LLVMInternalLinkage); - ZigLLVMFunctionSetCallingConv(fn_val, get_llvm_cc(g, CallingConventionUnspecified)); - add_common_fn_attributes(g, fn_val); - addLLVMArgAttr(fn_val, (unsigned)0, "noalias"); - addLLVMArgAttr(fn_val, (unsigned)0, "writeonly"); - - addLLVMArgAttr(fn_val, (unsigned)1, "noalias"); - addLLVMArgAttr(fn_val, (unsigned)1, "readonly"); - if (!g->omit_frame_pointer) { - ZigLLVMAddFunctionAttr(fn_val, "frame-pointer", "all"); - } - - // this is above the ZigLLVMClearCurrentDebugLocation - LLVMValueRef add_error_return_trace_addr_fn_val = get_add_error_return_trace_addr_fn(g); - - LLVMBasicBlockRef entry_block = LLVMAppendBasicBlock(fn_val, "Entry"); - LLVMBasicBlockRef prev_block = LLVMGetInsertBlock(g->builder); - LLVMValueRef prev_debug_location = LLVMGetCurrentDebugLocation(g->builder); - LLVMPositionBuilderAtEnd(g->builder, entry_block); - ZigLLVMClearCurrentDebugLocation(g->builder); - - // if (dest_stack_trace == null or src_stack_trace == null) return; - // var frame_index: usize = undefined; - // var frames_left: usize = undefined; - // if (src_stack_trace.index < src_stack_trace.instruction_addresses.len) { - // frame_index = 0; - // frames_left = src_stack_trace.index; - // if (frames_left == 0) return; - // } else { - // frame_index = (src_stack_trace.index + 1) % src_stack_trace.instruction_addresses.len; - // frames_left = src_stack_trace.instruction_addresses.len; - // } - // while (true) { - // __zig_add_err_ret_trace_addr(dest_stack_trace, src_stack_trace.instruction_addresses[frame_index]); - // frames_left -= 1; - // if (frames_left == 0) return; - // frame_index = (frame_index + 1) % src_stack_trace.instruction_addresses.len; - // } - LLVMBasicBlockRef return_block = LLVMAppendBasicBlock(fn_val, "Return"); - LLVMBasicBlockRef non_null_block = LLVMAppendBasicBlock(fn_val, "NonNull"); - - LLVMTypeRef usize_type_ref = g->builtin_types.entry_usize->llvm_type; - LLVMValueRef frame_index_ptr = LLVMBuildAlloca(g->builder, usize_type_ref, "frame_index"); - LLVMValueRef frames_left_ptr = LLVMBuildAlloca(g->builder, usize_type_ref, "frames_left"); - - LLVMValueRef dest_stack_trace_ptr = LLVMGetParam(fn_val, 0); - LLVMValueRef src_stack_trace_ptr = LLVMGetParam(fn_val, 1); - - LLVMValueRef null_dest_bit = LLVMBuildICmp(g->builder, LLVMIntEQ, dest_stack_trace_ptr, - LLVMConstNull(LLVMTypeOf(dest_stack_trace_ptr)), ""); - LLVMValueRef null_src_bit = LLVMBuildICmp(g->builder, LLVMIntEQ, src_stack_trace_ptr, - LLVMConstNull(LLVMTypeOf(src_stack_trace_ptr)), ""); - LLVMValueRef null_bit = LLVMBuildOr(g->builder, null_dest_bit, null_src_bit, ""); - LLVMBuildCondBr(g->builder, null_bit, return_block, non_null_block); - - LLVMPositionBuilderAtEnd(g->builder, non_null_block); - size_t src_index_field_index = g->stack_trace_type->data.structure.fields[0]->gen_index; - size_t src_addresses_field_index = g->stack_trace_type->data.structure.fields[1]->gen_index; - LLVMValueRef src_index_field_ptr = LLVMBuildStructGEP2(g->builder, - get_llvm_type(g, g->stack_trace_type), src_stack_trace_ptr, - (unsigned)src_index_field_index, ""); - LLVMValueRef src_addresses_field_ptr = LLVMBuildStructGEP2(g->builder, - get_llvm_type(g, g->stack_trace_type), src_stack_trace_ptr, - (unsigned)src_addresses_field_index, ""); - ZigType *slice_type = g->stack_trace_type->data.structure.fields[1]->type_entry; - size_t ptr_field_index = slice_type->data.structure.fields[slice_ptr_index]->gen_index; - LLVMValueRef src_ptr_field_ptr = LLVMBuildStructGEP2(g->builder, - ZigLLVMGetGEPResultElementType(src_addresses_field_ptr), - src_addresses_field_ptr, (unsigned)ptr_field_index, ""); - size_t len_field_index = slice_type->data.structure.fields[slice_len_index]->gen_index; - LLVMValueRef src_len_field_ptr = LLVMBuildStructGEP2(g->builder, - ZigLLVMGetGEPResultElementType(src_addresses_field_ptr), - src_addresses_field_ptr, (unsigned)len_field_index, ""); - LLVMValueRef src_index_val = LLVMBuildLoad2(g->builder, - ZigLLVMGetGEPResultElementType(src_index_field_ptr), src_index_field_ptr, ""); - LLVMValueRef src_ptr_val = LLVMBuildLoad2(g->builder, - ZigLLVMGetGEPResultElementType(src_ptr_field_ptr), src_ptr_field_ptr, ""); - LLVMValueRef src_len_val = LLVMBuildLoad2(g->builder, - ZigLLVMGetGEPResultElementType(src_len_field_ptr), src_len_field_ptr, ""); - LLVMValueRef no_wrap_bit = LLVMBuildICmp(g->builder, LLVMIntULT, src_index_val, src_len_val, ""); - LLVMBasicBlockRef no_wrap_block = LLVMAppendBasicBlock(fn_val, "NoWrap"); - LLVMBasicBlockRef yes_wrap_block = LLVMAppendBasicBlock(fn_val, "YesWrap"); - LLVMBasicBlockRef loop_block = LLVMAppendBasicBlock(fn_val, "Loop"); - LLVMBuildCondBr(g->builder, no_wrap_bit, no_wrap_block, yes_wrap_block); - - LLVMPositionBuilderAtEnd(g->builder, no_wrap_block); - LLVMValueRef usize_zero = LLVMConstNull(usize_type_ref); - LLVMBuildStore(g->builder, usize_zero, frame_index_ptr); - LLVMBuildStore(g->builder, src_index_val, frames_left_ptr); - LLVMValueRef frames_left_eq_zero_bit = LLVMBuildICmp(g->builder, LLVMIntEQ, src_index_val, usize_zero, ""); - LLVMBuildCondBr(g->builder, frames_left_eq_zero_bit, return_block, loop_block); - - LLVMPositionBuilderAtEnd(g->builder, yes_wrap_block); - LLVMValueRef usize_one = LLVMConstInt(usize_type_ref, 1, false); - LLVMValueRef plus_one = LLVMBuildNUWAdd(g->builder, src_index_val, usize_one, ""); - LLVMValueRef mod_len = LLVMBuildURem(g->builder, plus_one, src_len_val, ""); - LLVMBuildStore(g->builder, mod_len, frame_index_ptr); - LLVMBuildStore(g->builder, src_len_val, frames_left_ptr); - LLVMBuildBr(g->builder, loop_block); - - LLVMPositionBuilderAtEnd(g->builder, loop_block); - LLVMValueRef ptr_index = LLVMBuildLoad2(g->builder, usize_type_ref, frame_index_ptr, ""); - LLVMValueRef addr_ptr = LLVMBuildInBoundsGEP2(g->builder, - usize_type_ref, src_ptr_val, &ptr_index, 1, ""); - LLVMValueRef this_addr_val = LLVMBuildLoad2(g->builder, ZigLLVMGetGEPResultElementType(addr_ptr), - addr_ptr, ""); - LLVMValueRef args[] = {dest_stack_trace_ptr, this_addr_val}; - ZigLLVMBuildCall(g->builder, LLVMGlobalGetValueType(add_error_return_trace_addr_fn_val), - add_error_return_trace_addr_fn_val, args, 2, get_llvm_cc(g, CallingConventionUnspecified), ZigLLVM_CallAttrAlwaysInline, ""); - LLVMValueRef prev_frames_left = LLVMBuildLoad2(g->builder, usize_type_ref, frames_left_ptr, ""); - LLVMValueRef new_frames_left = LLVMBuildNUWSub(g->builder, prev_frames_left, usize_one, ""); - LLVMValueRef done_bit = LLVMBuildICmp(g->builder, LLVMIntEQ, new_frames_left, usize_zero, ""); - LLVMBasicBlockRef continue_block = LLVMAppendBasicBlock(fn_val, "Continue"); - LLVMBuildCondBr(g->builder, done_bit, return_block, continue_block); - - LLVMPositionBuilderAtEnd(g->builder, return_block); - LLVMBuildRetVoid(g->builder); - - LLVMPositionBuilderAtEnd(g->builder, continue_block); - LLVMBuildStore(g->builder, new_frames_left, frames_left_ptr); - LLVMValueRef prev_index = LLVMBuildLoad2(g->builder, usize_type_ref, frame_index_ptr, ""); - LLVMValueRef index_plus_one = LLVMBuildNUWAdd(g->builder, prev_index, usize_one, ""); - LLVMValueRef index_mod_len = LLVMBuildURem(g->builder, index_plus_one, src_len_val, ""); - LLVMBuildStore(g->builder, index_mod_len, frame_index_ptr); - LLVMBuildBr(g->builder, loop_block); - - LLVMPositionBuilderAtEnd(g->builder, prev_block); - if (!g->strip_debug_symbols) { - LLVMSetCurrentDebugLocation(g->builder, prev_debug_location); - } - - g->merge_err_ret_traces_fn_val = fn_val; - return fn_val; - -} -static LLVMValueRef ir_render_save_err_ret_addr(CodeGen *g, Stage1Air *executable, - Stage1AirInstSaveErrRetAddr *save_err_ret_addr_instruction) -{ - assert(g->have_err_ret_tracing); - if ((target_is_wasm(g->zig_target) && g->zig_target->os != OsEmscripten) || target_is_bpf(g->zig_target)) { - return nullptr; - } - - LLVMValueRef return_err_fn = get_return_err_fn(g); - bool is_llvm_alloca; - LLVMValueRef my_err_trace_val = get_cur_err_ret_trace_val(g, save_err_ret_addr_instruction->base.scope, - &is_llvm_alloca); - ZigLLVMBuildCall(g->builder, LLVMGlobalGetValueType(return_err_fn), return_err_fn, &my_err_trace_val, 1, - get_llvm_cc(g, CallingConventionUnspecified), ZigLLVM_CallAttrAuto, ""); - - ZigType *ret_type = g->cur_fn->type_entry->data.fn.fn_type_id.return_type; - if (fn_is_async(g->cur_fn) && codegen_fn_has_err_ret_tracing_arg(g, ret_type)) { - ZigType *frame_type = get_fn_frame_type(g, g->cur_fn); - LLVMValueRef trace_ptr_ptr = LLVMBuildStructGEP2(g->builder, get_llvm_type(g, frame_type), - g->cur_frame_ptr, frame_index_trace_arg(g, ret_type), ""); - LLVMBuildStore(g->builder, my_err_trace_val, trace_ptr_ptr); - } - - return nullptr; -} - -static void gen_assert_resume_id(CodeGen *g, Stage1AirInst *source_instr, ResumeId resume_id, PanicMsgId msg_id, - LLVMBasicBlockRef end_bb) -{ - LLVMTypeRef usize_type_ref = g->builtin_types.entry_usize->llvm_type; - - if (ir_want_runtime_safety(g, source_instr)) { - // Write a value to the resume index which indicates the function was resumed while not suspended. - LLVMBuildStore(g->builder, g->cur_bad_not_suspended_index, g->cur_async_resume_index_ptr); - } - - LLVMBasicBlockRef bad_resume_block = LLVMAppendBasicBlock(g->cur_fn_val, "BadResume"); - if (end_bb == nullptr) end_bb = LLVMAppendBasicBlock(g->cur_fn_val, "OkResume"); - LLVMValueRef expected_value = LLVMConstSub(LLVMConstAllOnes(usize_type_ref), - LLVMConstInt(usize_type_ref, resume_id, false)); - LLVMValueRef ok_bit = LLVMBuildICmp(g->builder, LLVMIntEQ, LLVMGetParam(g->cur_fn_val, 1), expected_value, ""); - LLVMBuildCondBr(g->builder, ok_bit, end_bb, bad_resume_block); - - LLVMPositionBuilderAtEnd(g->builder, bad_resume_block); - gen_assertion(g, msg_id, source_instr); - - LLVMPositionBuilderAtEnd(g->builder, end_bb); -} - -static LLVMValueRef gen_resume(CodeGen *g, LLVMTypeRef fn_llvm_ty, LLVMValueRef fn_val, - LLVMValueRef target_frame_ptr, ResumeId resume_id) -{ - LLVMTypeRef usize_type_ref = g->builtin_types.entry_usize->llvm_type; - if (fn_val == nullptr) { - LLVMValueRef fn_ptr_ptr = LLVMBuildStructGEP2(g->builder, g->any_frame_header_llvm_ty, - target_frame_ptr, frame_fn_ptr_index, ""); - fn_val = LLVMBuildLoad2(g->builder, ZigLLVMGetGEPResultElementType(fn_ptr_ptr), - fn_ptr_ptr, ""); - } - LLVMValueRef arg_val = LLVMConstSub(LLVMConstAllOnes(usize_type_ref), - LLVMConstInt(usize_type_ref, resume_id, false)); - LLVMValueRef args[] = {target_frame_ptr, arg_val}; - return ZigLLVMBuildCall(g->builder, fn_llvm_ty, fn_val, args, 2, ZigLLVM_Fast, - ZigLLVM_CallAttrAuto, ""); -} - -static LLVMBasicBlockRef gen_suspend_begin(CodeGen *g, const char *name_hint) { - LLVMTypeRef usize_type_ref = g->builtin_types.entry_usize->llvm_type; - LLVMBasicBlockRef resume_bb = LLVMAppendBasicBlock(g->cur_fn_val, name_hint); - size_t new_block_index = g->cur_resume_block_count; - g->cur_resume_block_count += 1; - LLVMValueRef new_block_index_val = LLVMConstInt(usize_type_ref, new_block_index, false); - LLVMAddCase(g->cur_async_switch_instr, new_block_index_val, resume_bb); - LLVMBuildStore(g->builder, new_block_index_val, g->cur_async_resume_index_ptr); - return resume_bb; -} - -// Be careful setting tail call. According to LLVM lang ref, -// tail and musttail imply that the callee does not access allocas from the caller. -// This works for async functions since the locals are spilled. -// http://llvm.org/docs/LangRef.html#id320 -static void set_tail_call_if_appropriate(CodeGen *g, LLVMValueRef call_inst) { - LLVMSetTailCall(call_inst, true); -} - -static LLVMValueRef gen_maybe_atomic_op(CodeGen *g, LLVMAtomicRMWBinOp op, LLVMValueRef ptr, - LLVMValueRef val, LLVMAtomicOrdering order) -{ - if (g->is_single_threaded) { - LLVMValueRef loaded = LLVMBuildLoad2(g->builder, LLVMTypeOf(val), ptr, ""); - LLVMValueRef modified; - switch (op) { - case LLVMAtomicRMWBinOpXchg: - modified = val; - break; - case LLVMAtomicRMWBinOpXor: - modified = LLVMBuildXor(g->builder, loaded, val, ""); - break; - default: - zig_unreachable(); - } - LLVMBuildStore(g->builder, modified, ptr); - return loaded; - } else { - return LLVMBuildAtomicRMW(g->builder, op, ptr, val, order, false); - } -} - -static void gen_async_return(CodeGen *g, Stage1AirInstReturn *instruction) { - LLVMTypeRef usize_type_ref = g->builtin_types.entry_usize->llvm_type; - - ZigType *operand_type = (instruction->operand != nullptr) ? instruction->operand->value->type : nullptr; - bool operand_has_bits = (operand_type != nullptr) && type_has_bits(g, operand_type); - ZigType *ret_type = g->cur_fn->type_entry->data.fn.fn_type_id.return_type; - bool ret_type_has_bits = type_has_bits(g, ret_type); - - if (operand_has_bits && instruction->operand != nullptr) { - bool need_store = instruction->operand->value->special != ConstValSpecialRuntime || !handle_is_ptr(g, ret_type); - if (need_store) { - // It didn't get written to the result ptr. We do that now. - ZigType *ret_ptr_type = get_pointer_to_type(g, ret_type, true); - gen_assign_raw(g, g->cur_ret_ptr, ret_ptr_type, ir_llvm_value(g, instruction->operand)); - } - } - - // Whether we tail resume the awaiter, or do an early return, we are done and will not be resumed. - if (ir_want_runtime_safety(g, &instruction->base)) { - LLVMValueRef new_resume_index = LLVMConstAllOnes(usize_type_ref); - LLVMBuildStore(g->builder, new_resume_index, g->cur_async_resume_index_ptr); - } - - LLVMValueRef zero = LLVMConstNull(usize_type_ref); - LLVMValueRef all_ones = LLVMConstAllOnes(usize_type_ref); - - LLVMValueRef prev_val = gen_maybe_atomic_op(g, LLVMAtomicRMWBinOpXor, g->cur_async_awaiter_ptr, - all_ones, LLVMAtomicOrderingAcquire); - - LLVMBasicBlockRef bad_return_block = LLVMAppendBasicBlock(g->cur_fn_val, "BadReturn"); - LLVMBasicBlockRef early_return_block = LLVMAppendBasicBlock(g->cur_fn_val, "EarlyReturn"); - LLVMBasicBlockRef resume_them_block = LLVMAppendBasicBlock(g->cur_fn_val, "ResumeThem"); - - LLVMValueRef switch_instr = LLVMBuildSwitch(g->builder, prev_val, resume_them_block, 2); - - LLVMAddCase(switch_instr, zero, early_return_block); - LLVMAddCase(switch_instr, all_ones, bad_return_block); - - // Something has gone horribly wrong, and this is an invalid second return. - LLVMPositionBuilderAtEnd(g->builder, bad_return_block); - gen_assertion(g, PanicMsgIdBadReturn, &instruction->base); - - // There is no awaiter yet, but we're completely done. - LLVMPositionBuilderAtEnd(g->builder, early_return_block); - LLVMBuildRetVoid(g->builder); - - // We need to resume the caller by tail calling them, - // but first write through the result pointer and possibly - // error return trace pointer. - LLVMPositionBuilderAtEnd(g->builder, resume_them_block); - - if (ret_type_has_bits) { - // If the awaiter result pointer is non-null, we need to copy the result to there. - LLVMBasicBlockRef copy_block = LLVMAppendBasicBlock(g->cur_fn_val, "CopyResult"); - LLVMBasicBlockRef copy_end_block = LLVMAppendBasicBlock(g->cur_fn_val, "CopyResultEnd"); - LLVMValueRef awaiter_ret_ptr_ptr = LLVMBuildStructGEP2(g->builder, - get_llvm_type(g, get_fn_frame_type(g, g->cur_fn)), - g->cur_frame_ptr, frame_ret_start + 1, ""); - LLVMValueRef awaiter_ret_ptr = LLVMBuildLoad2(g->builder, - ZigLLVMGetGEPResultElementType(awaiter_ret_ptr_ptr), awaiter_ret_ptr_ptr, ""); - LLVMValueRef zero_ptr = LLVMConstNull(LLVMTypeOf(awaiter_ret_ptr)); - LLVMValueRef need_copy_bit = LLVMBuildICmp(g->builder, LLVMIntNE, awaiter_ret_ptr, zero_ptr, ""); - LLVMBuildCondBr(g->builder, need_copy_bit, copy_block, copy_end_block); - - LLVMPositionBuilderAtEnd(g->builder, copy_block); - LLVMTypeRef ptr_u8 = LLVMPointerType(LLVMInt8Type(), 0); - LLVMValueRef dest_ptr_casted = LLVMBuildBitCast(g->builder, awaiter_ret_ptr, ptr_u8, ""); - LLVMValueRef src_ptr_casted = LLVMBuildBitCast(g->builder, g->cur_ret_ptr, ptr_u8, ""); - bool is_volatile = false; - uint32_t abi_align = get_abi_alignment(g, ret_type); - LLVMValueRef byte_count_val = LLVMConstInt(usize_type_ref, type_size(g, ret_type), false); - ZigLLVMBuildMemCpy(g->builder, - dest_ptr_casted, abi_align, - src_ptr_casted, abi_align, byte_count_val, is_volatile); - LLVMBuildBr(g->builder, copy_end_block); - - LLVMPositionBuilderAtEnd(g->builder, copy_end_block); - if (codegen_fn_has_err_ret_tracing_arg(g, ret_type)) { - LLVMValueRef awaiter_trace_ptr_ptr = LLVMBuildStructGEP2(g->builder, - get_llvm_type(g, get_fn_frame_type(g, g->cur_fn)), - g->cur_frame_ptr, frame_index_trace_arg(g, ret_type) + 1, ""); - LLVMValueRef dest_trace_ptr = LLVMBuildLoad2(g->builder, - ZigLLVMGetGEPResultElementType(awaiter_trace_ptr_ptr), - awaiter_trace_ptr_ptr, ""); - bool is_llvm_alloca; - LLVMValueRef my_err_trace_val = get_cur_err_ret_trace_val(g, instruction->base.scope, &is_llvm_alloca); - LLVMValueRef args[] = { dest_trace_ptr, my_err_trace_val }; - ZigLLVMBuildCall(g->builder, LLVMGlobalGetValueType(get_merge_err_ret_traces_fn_val(g)), - get_merge_err_ret_traces_fn_val(g), args, 2, - get_llvm_cc(g, CallingConventionUnspecified), ZigLLVM_CallAttrAuto, ""); - } - } - - // Resume the caller by tail calling them. - ZigType *any_frame_type = get_any_frame_type(g, ret_type); - LLVMValueRef their_frame_ptr = LLVMBuildIntToPtr(g->builder, prev_val, - get_llvm_type(g, any_frame_type), ""); - LLVMValueRef call_inst = gen_resume(g, g->anyframe_fn_type, nullptr, their_frame_ptr, ResumeIdReturn); - set_tail_call_if_appropriate(g, call_inst); - LLVMBuildRetVoid(g->builder); -} - -static LLVMValueRef gen_convert_to_c_abi(CodeGen *g, LLVMValueRef location, LLVMValueRef value) { - ZigType *return_type = g->cur_fn->type_entry->data.fn.gen_return_type; - size_t size = type_size(g, return_type); - LLVMTypeRef abi_return_type = get_llvm_c_abi_type(g, return_type); - LLVMTypeRef abi_return_type_pointer = LLVMPointerType(abi_return_type, 0); - - if (size < 8) { - LLVMValueRef bitcast = LLVMBuildBitCast(g->builder, value, abi_return_type_pointer, ""); - return LLVMBuildLoad2(g->builder, abi_return_type, bitcast, ""); - } else { - LLVMTypeRef i8ptr = LLVMPointerType(LLVMInt8Type(), 0); - LLVMValueRef bc_location = LLVMBuildBitCast(g->builder, location, i8ptr, ""); - LLVMValueRef bc_value = LLVMBuildBitCast(g->builder, value, i8ptr, ""); - - LLVMValueRef len = LLVMConstInt(LLVMInt64Type(), size, false); - ZigLLVMBuildMemCpy(g->builder, bc_location, 8, bc_value, return_type->abi_align, len, false); - return LLVMBuildLoad2(g->builder, abi_return_type, location, ""); - } -} - -static LLVMValueRef ir_render_return(CodeGen *g, Stage1Air *executable, Stage1AirInstReturn *instruction) { - if (fn_is_async(g->cur_fn)) { - gen_async_return(g, instruction); - return nullptr; - } - - FnTypeId *fn_type_id = &g->cur_fn->type_entry->data.fn.fn_type_id; - - if (want_first_arg_sret(g, fn_type_id)) { - if (instruction->operand == nullptr) { - LLVMBuildRetVoid(g->builder); - return nullptr; - } - assert(g->cur_ret_ptr); - ir_assert(instruction->operand->value->special != ConstValSpecialRuntime, &instruction->base); - LLVMValueRef value = ir_llvm_value(g, instruction->operand); - ZigType *return_type = instruction->operand->value->type; - gen_assign_raw(g, g->cur_ret_ptr, get_pointer_to_type(g, return_type, false), value); - LLVMBuildRetVoid(g->builder); - } else if (fn_returns_c_abi_small_struct(fn_type_id)) { - LLVMValueRef location = g->cur_fn->abi_return_value; - if (instruction->operand == nullptr) { - LLVMValueRef converted = gen_convert_to_c_abi(g, location, g->cur_ret_ptr); - LLVMBuildRet(g->builder, converted); - } else { - LLVMValueRef value = ir_llvm_value(g, instruction->operand); - LLVMValueRef converted = gen_convert_to_c_abi(g, location, value); - LLVMBuildRet(g->builder, converted); - } - } else if (g->cur_fn->type_entry->data.fn.fn_type_id.cc != CallingConventionAsync && - handle_is_ptr(g, g->cur_fn->type_entry->data.fn.fn_type_id.return_type)) - { - LLVMTypeRef ret_llvm_ty = get_llvm_type(g, g->cur_fn->type_entry->data.fn.fn_type_id.return_type); - if (instruction->operand == nullptr) { - LLVMValueRef by_val_value = gen_load_untyped(g, ret_llvm_ty, g->cur_ret_ptr, 0, false, ""); - LLVMBuildRet(g->builder, by_val_value); - } else { - LLVMValueRef value = ir_llvm_value(g, instruction->operand); - LLVMValueRef by_val_value = gen_load_untyped(g, ret_llvm_ty, value, 0, false, ""); - LLVMBuildRet(g->builder, by_val_value); - } - } else if (instruction->operand == nullptr) { - if (g->cur_ret_ptr == nullptr) { - LLVMBuildRetVoid(g->builder); - } else { - LLVMTypeRef ret_llvm_ty = get_llvm_type(g, g->cur_fn->type_entry->data.fn.fn_type_id.return_type); - LLVMValueRef by_val_value = gen_load_untyped(g, ret_llvm_ty, g->cur_ret_ptr, 0, false, ""); - LLVMBuildRet(g->builder, by_val_value); - } - } else { - LLVMValueRef value = ir_llvm_value(g, instruction->operand); - LLVMBuildRet(g->builder, value); - } - return nullptr; -} - -static LLVMValueRef gen_overflow_shl_op(CodeGen *g, ZigType *operand_type, - LLVMValueRef val1, LLVMValueRef val2) -{ - // for unsigned left shifting, we do the lossy shift, then logically shift - // right the same number of bits - // if the values don't match, we have an overflow - // for signed left shifting we do the same except arithmetic shift right - ZigType *scalar_type = (operand_type->id == ZigTypeIdVector) ? - operand_type->data.vector.elem_type : operand_type; - - assert(scalar_type->id == ZigTypeIdInt); - - LLVMValueRef result = LLVMBuildShl(g->builder, val1, val2, ""); - LLVMValueRef orig_val; - if (scalar_type->data.integral.is_signed) { - orig_val = LLVMBuildAShr(g->builder, result, val2, ""); - } else { - orig_val = LLVMBuildLShr(g->builder, result, val2, ""); - } - LLVMValueRef ok_bit = LLVMBuildICmp(g->builder, LLVMIntEQ, val1, orig_val, ""); - - LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "OverflowOk"); - LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "OverflowFail"); - if (operand_type->id == ZigTypeIdVector) { - ok_bit = ZigLLVMBuildAndReduce(g->builder, ok_bit); - } - LLVMBuildCondBr(g->builder, ok_bit, ok_block, fail_block); - - LLVMPositionBuilderAtEnd(g->builder, fail_block); - gen_safety_crash(g, PanicMsgIdShlOverflowedBits); - - LLVMPositionBuilderAtEnd(g->builder, ok_block); - return result; -} - -static LLVMValueRef gen_overflow_shr_op(CodeGen *g, ZigType *operand_type, - LLVMValueRef val1, LLVMValueRef val2) -{ - ZigType *scalar_type = (operand_type->id == ZigTypeIdVector) ? - operand_type->data.vector.elem_type : operand_type; - - assert(scalar_type->id == ZigTypeIdInt); - - LLVMValueRef result; - if (scalar_type->data.integral.is_signed) { - result = LLVMBuildAShr(g->builder, val1, val2, ""); - } else { - result = LLVMBuildLShr(g->builder, val1, val2, ""); - } - LLVMValueRef orig_val = LLVMBuildShl(g->builder, result, val2, ""); - LLVMValueRef ok_bit = LLVMBuildICmp(g->builder, LLVMIntEQ, val1, orig_val, ""); - - LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "OverflowOk"); - LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "OverflowFail"); - if (operand_type->id == ZigTypeIdVector) { - ok_bit = ZigLLVMBuildAndReduce(g->builder, ok_bit); - } - LLVMBuildCondBr(g->builder, ok_bit, ok_block, fail_block); - - LLVMPositionBuilderAtEnd(g->builder, fail_block); - gen_safety_crash(g, PanicMsgIdShrOverflowedBits); - - LLVMPositionBuilderAtEnd(g->builder, ok_block); - return result; -} - -static LLVMValueRef get_soft_float_fn(CodeGen *g, const char *name, int param_count, LLVMTypeRef param_type, LLVMTypeRef return_type) { - LLVMValueRef existing_llvm_fn = LLVMGetNamedFunction(g->module, name); - if (existing_llvm_fn != nullptr) return existing_llvm_fn; - LLVMValueRef existing_llvm_alias = LLVMGetNamedGlobalAlias(g->module, name, strlen(name)); - if (existing_llvm_alias != nullptr) return LLVMAliasGetAliasee(existing_llvm_alias); - - LLVMTypeRef param_types[3] = { param_type, param_type, param_type }; - LLVMTypeRef fn_type = LLVMFunctionType(return_type, param_types, param_count, false); - return LLVMAddFunction(g->module, name, fn_type); -} - -static LLVMValueRef gen_soft_float_un_op(CodeGen *g, LLVMValueRef op, ZigType *operand_type, BuiltinFnId op_id) { - uint32_t vector_len = operand_type->id == ZigTypeIdVector ? operand_type->data.vector.len : 0; - ZigType *scalar_type = operand_type->id == ZigTypeIdVector ? operand_type->data.vector.elem_type : operand_type; - - char fn_name[64]; - snprintf(fn_name, sizeof(fn_name), "%s%s%s", libc_float_prefix(g, scalar_type), - float_un_op_to_name(op_id), libc_float_suffix(g, scalar_type)); - LLVMValueRef func_ref = get_soft_float_fn(g, fn_name, 1, scalar_type->llvm_type, scalar_type->llvm_type); - - if (vector_len == 0) { - return LLVMBuildCall2(g->builder, LLVMGlobalGetValueType(func_ref), func_ref, &op, 1, ""); - } else { - LLVMValueRef result = LLVMGetUndef(operand_type->llvm_type); - LLVMTypeRef usize_ref = g->builtin_types.entry_usize->llvm_type; - for (uint32_t i = 0; i < vector_len; i++) { - LLVMValueRef index_value = LLVMConstInt(usize_ref, i, false); - LLVMValueRef param = LLVMBuildExtractElement(g->builder, op, index_value, ""); - LLVMValueRef call_result = LLVMBuildCall2(g->builder, LLVMGlobalGetValueType(func_ref), func_ref, ¶m, 1, ""); - result = LLVMBuildInsertElement(g->builder, result, call_result, index_value, ""); - } - return result; - } -} - -static LLVMValueRef gen_float_un_op(CodeGen *g, LLVMValueRef operand, ZigType *operand_type, BuiltinFnId op) { - assert(operand_type->id == ZigTypeIdFloat || operand_type->id == ZigTypeIdVector); - ZigType *elem_type = operand_type->id == ZigTypeIdVector ? operand_type->data.vector.elem_type : operand_type; - if ((elem_type == g->builtin_types.entry_f80 && !target_has_f80(g->zig_target)) || - (elem_type == g->builtin_types.entry_f128 && !target_long_double_is_f128(g->zig_target)) || - (elem_type == g->builtin_types.entry_f16 && !target_is_arm(g->zig_target)) || - op == BuiltinFnIdTan) - { - return gen_soft_float_un_op(g, operand, operand_type, op); - } - LLVMValueRef float_op_fn = get_float_fn(g, operand_type, ZigLLVMFnIdFloatOp, op); - return LLVMBuildCall2(g->builder, LLVMGlobalGetValueType(float_op_fn), float_op_fn, &operand, 1, ""); -} - -enum DivKind { - DivKindFloat, - DivKindTrunc, - DivKindFloor, - DivKindExact, -}; - -static LLVMValueRef bigint_to_llvm_const(LLVMTypeRef type_ref, BigInt *bigint) { - if (bigint->digit_count == 0) { - return LLVMConstNull(type_ref); - } - - if (LLVMGetTypeKind(type_ref) == LLVMVectorTypeKind) { - const unsigned vector_len = LLVMGetVectorSize(type_ref); - LLVMTypeRef elem_type = LLVMGetElementType(type_ref); - - LLVMValueRef *values = heap::c_allocator.allocate_nonzero(vector_len); - // Create a vector with all the elements having the same value - for (unsigned i = 0; i < vector_len; i++) { - values[i] = bigint_to_llvm_const(elem_type, bigint); - } - LLVMValueRef result = LLVMConstVector(values, vector_len); - heap::c_allocator.deallocate(values, vector_len); - return result; - } - - LLVMValueRef unsigned_val; - if (bigint->digit_count == 1) { - unsigned_val = LLVMConstInt(type_ref, bigint_ptr(bigint)[0], false); - } else { - unsigned_val = LLVMConstIntOfArbitraryPrecision(type_ref, bigint->digit_count, bigint_ptr(bigint)); - } - if (bigint->is_negative) { - return LLVMConstNeg(unsigned_val); - } else { - return unsigned_val; - } -} - -static LLVMValueRef gen_div(CodeGen *g, bool want_runtime_safety, bool want_fast_math, - LLVMValueRef val1, LLVMValueRef val2, ZigType *operand_type, DivKind div_kind) -{ - ZigType *scalar_type = (operand_type->id == ZigTypeIdVector) ? - operand_type->data.vector.elem_type : operand_type; - - ZigLLVMSetFastMath(g->builder, want_fast_math); - - LLVMValueRef zero = LLVMConstNull(get_llvm_type(g, operand_type)); - if (want_runtime_safety && (want_fast_math || scalar_type->id != ZigTypeIdFloat)) { - // Safety check: divisor != 0 - LLVMValueRef is_zero_bit; - if (scalar_type->id == ZigTypeIdInt) { - is_zero_bit = LLVMBuildICmp(g->builder, LLVMIntEQ, val2, zero, ""); - } else if (scalar_type->id == ZigTypeIdFloat) { - is_zero_bit = LLVMBuildFCmp(g->builder, LLVMRealOEQ, val2, zero, ""); - } else { - zig_unreachable(); - } - - if (operand_type->id == ZigTypeIdVector) { - is_zero_bit = ZigLLVMBuildOrReduce(g->builder, is_zero_bit); - } - - LLVMBasicBlockRef div_zero_fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "DivZeroFail"); - LLVMBasicBlockRef div_zero_ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "DivZeroOk"); - LLVMBuildCondBr(g->builder, is_zero_bit, div_zero_fail_block, div_zero_ok_block); - - LLVMPositionBuilderAtEnd(g->builder, div_zero_fail_block); - gen_safety_crash(g, PanicMsgIdDivisionByZero); - - LLVMPositionBuilderAtEnd(g->builder, div_zero_ok_block); - - // Safety check: check for overflow (dividend = minInt and divisor = -1) - if (scalar_type->id == ZigTypeIdInt && scalar_type->data.integral.is_signed) { - LLVMValueRef neg_1_value = LLVMConstAllOnes(get_llvm_type(g, operand_type)); - BigInt int_min_bi = {0}; - eval_min_max_value_int(g, scalar_type, &int_min_bi, false); - LLVMValueRef int_min_value = bigint_to_llvm_const(get_llvm_type(g, operand_type), &int_min_bi); - - LLVMBasicBlockRef overflow_fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "DivOverflowFail"); - LLVMBasicBlockRef overflow_ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "DivOverflowOk"); - LLVMValueRef num_is_int_min = LLVMBuildICmp(g->builder, LLVMIntEQ, val1, int_min_value, ""); - LLVMValueRef den_is_neg_1 = LLVMBuildICmp(g->builder, LLVMIntEQ, val2, neg_1_value, ""); - LLVMValueRef overflow_fail_bit = LLVMBuildAnd(g->builder, num_is_int_min, den_is_neg_1, ""); - if (operand_type->id == ZigTypeIdVector) { - overflow_fail_bit = ZigLLVMBuildOrReduce(g->builder, overflow_fail_bit); - } - LLVMBuildCondBr(g->builder, overflow_fail_bit, overflow_fail_block, overflow_ok_block); - - LLVMPositionBuilderAtEnd(g->builder, overflow_fail_block); - gen_safety_crash(g, PanicMsgIdIntegerOverflow); - - LLVMPositionBuilderAtEnd(g->builder, overflow_ok_block); - } - } - - if (scalar_type->id == ZigTypeIdFloat) { - LLVMValueRef result = LLVMBuildFDiv(g->builder, val1, val2, ""); - switch (div_kind) { - case DivKindFloat: - return result; - case DivKindExact: - if (want_runtime_safety) { - // Safety check: a / b == floor(a / b) - LLVMValueRef floored = gen_float_un_op(g, result, operand_type, BuiltinFnIdFloor); - - LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "DivExactOk"); - LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "DivExactFail"); - LLVMValueRef ok_bit = LLVMBuildFCmp(g->builder, LLVMRealOEQ, floored, result, ""); - if (operand_type->id == ZigTypeIdVector) { - ok_bit = ZigLLVMBuildAndReduce(g->builder, ok_bit); - } - LLVMBuildCondBr(g->builder, ok_bit, ok_block, fail_block); - - LLVMPositionBuilderAtEnd(g->builder, fail_block); - gen_safety_crash(g, PanicMsgIdExactDivisionRemainder); - - LLVMPositionBuilderAtEnd(g->builder, ok_block); - } - return result; - case DivKindTrunc: - return gen_float_un_op(g, result, operand_type, BuiltinFnIdTrunc); - case DivKindFloor: - return gen_float_un_op(g, result, operand_type, BuiltinFnIdFloor); - } - zig_unreachable(); - } - - assert(scalar_type->id == ZigTypeIdInt); - - switch (div_kind) { - case DivKindFloat: - zig_unreachable(); - case DivKindTrunc: - if (scalar_type->data.integral.is_signed) { - return LLVMBuildSDiv(g->builder, val1, val2, ""); - } else { - return LLVMBuildUDiv(g->builder, val1, val2, ""); - } - case DivKindExact: - if (want_runtime_safety) { - // Safety check: a % b == 0 - LLVMValueRef remainder_val; - if (scalar_type->data.integral.is_signed) { - remainder_val = LLVMBuildSRem(g->builder, val1, val2, ""); - } else { - remainder_val = LLVMBuildURem(g->builder, val1, val2, ""); - } - - LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "DivExactOk"); - LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "DivExactFail"); - LLVMValueRef ok_bit = LLVMBuildICmp(g->builder, LLVMIntEQ, remainder_val, zero, ""); - if (operand_type->id == ZigTypeIdVector) { - ok_bit = ZigLLVMBuildAndReduce(g->builder, ok_bit); - } - LLVMBuildCondBr(g->builder, ok_bit, ok_block, fail_block); - - LLVMPositionBuilderAtEnd(g->builder, fail_block); - gen_safety_crash(g, PanicMsgIdExactDivisionRemainder); - - LLVMPositionBuilderAtEnd(g->builder, ok_block); - } - if (scalar_type->data.integral.is_signed) { - return LLVMBuildExactSDiv(g->builder, val1, val2, ""); - } else { - return LLVMBuildExactUDiv(g->builder, val1, val2, ""); - } - case DivKindFloor: - { - if (!scalar_type->data.integral.is_signed) { - return LLVMBuildUDiv(g->builder, val1, val2, ""); - } - // const d = @divTrunc(a, b); - // const r = @rem(a, b); - // return if (r == 0) d else d - ((a < 0) ^ (b < 0)); - - LLVMValueRef div_trunc = LLVMBuildSDiv(g->builder, val1, val2, ""); - LLVMValueRef rem = LLVMBuildSRem(g->builder, val1, val2, ""); - LLVMValueRef rem_eq_0 = LLVMBuildICmp(g->builder, LLVMIntEQ, rem, zero, ""); - LLVMValueRef a_lt_0 = LLVMBuildICmp(g->builder, LLVMIntSLT, val1, zero, ""); - LLVMValueRef b_lt_0 = LLVMBuildICmp(g->builder, LLVMIntSLT, val2, zero, ""); - LLVMValueRef a_b_xor = LLVMBuildXor(g->builder, a_lt_0, b_lt_0, ""); - LLVMValueRef a_b_xor_ext = LLVMBuildZExt(g->builder, a_b_xor, LLVMTypeOf(div_trunc), ""); - LLVMValueRef d_sub_xor = LLVMBuildSub(g->builder, div_trunc, a_b_xor_ext, ""); - return LLVMBuildSelect(g->builder, rem_eq_0, div_trunc, d_sub_xor, ""); - } - } - zig_unreachable(); -} - -enum RemKind { - RemKindRem, - RemKindMod, -}; - -static LLVMValueRef gen_rem(CodeGen *g, bool want_runtime_safety, bool want_fast_math, - LLVMValueRef val1, LLVMValueRef val2, ZigType *operand_type, RemKind rem_kind) -{ - ZigType *scalar_type = (operand_type->id == ZigTypeIdVector) ? - operand_type->data.vector.elem_type : operand_type; - - ZigLLVMSetFastMath(g->builder, want_fast_math); - - LLVMValueRef zero = LLVMConstNull(get_llvm_type(g, operand_type)); - if (want_runtime_safety) { - // Safety check: divisor != 0 - LLVMValueRef is_zero_bit; - if (scalar_type->id == ZigTypeIdInt) { - LLVMIntPredicate pred = scalar_type->data.integral.is_signed ? LLVMIntSLE : LLVMIntEQ; - is_zero_bit = LLVMBuildICmp(g->builder, pred, val2, zero, ""); - } else if (scalar_type->id == ZigTypeIdFloat) { - is_zero_bit = LLVMBuildFCmp(g->builder, LLVMRealOEQ, val2, zero, ""); - } else { - zig_unreachable(); - } - - if (operand_type->id == ZigTypeIdVector) { - is_zero_bit = ZigLLVMBuildOrReduce(g->builder, is_zero_bit); - } - - LLVMBasicBlockRef rem_zero_ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "RemZeroOk"); - LLVMBasicBlockRef rem_zero_fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "RemZeroFail"); - LLVMBuildCondBr(g->builder, is_zero_bit, rem_zero_fail_block, rem_zero_ok_block); - - LLVMPositionBuilderAtEnd(g->builder, rem_zero_fail_block); - gen_safety_crash(g, PanicMsgIdRemainderDivisionByZero); - - LLVMPositionBuilderAtEnd(g->builder, rem_zero_ok_block); - } - - if (scalar_type->id == ZigTypeIdFloat) { - if (rem_kind == RemKindRem) { - return LLVMBuildFRem(g->builder, val1, val2, ""); - } else { - LLVMValueRef a = LLVMBuildFRem(g->builder, val1, val2, ""); - LLVMValueRef b = LLVMBuildFAdd(g->builder, a, val2, ""); - LLVMValueRef c = LLVMBuildFRem(g->builder, b, val2, ""); - LLVMValueRef ltz = LLVMBuildFCmp(g->builder, LLVMRealOLT, val1, zero, ""); - return LLVMBuildSelect(g->builder, ltz, c, a, ""); - } - } else { - assert(scalar_type->id == ZigTypeIdInt); - if (scalar_type->data.integral.is_signed) { - if (rem_kind == RemKindRem) { - return LLVMBuildSRem(g->builder, val1, val2, ""); - } else { - LLVMValueRef a = LLVMBuildSRem(g->builder, val1, val2, ""); - LLVMValueRef b = LLVMBuildNSWAdd(g->builder, a, val2, ""); - LLVMValueRef c = LLVMBuildSRem(g->builder, b, val2, ""); - LLVMValueRef ltz = LLVMBuildICmp(g->builder, LLVMIntSLT, val1, zero, ""); - return LLVMBuildSelect(g->builder, ltz, c, a, ""); - } - } else { - return LLVMBuildURem(g->builder, val1, val2, ""); - } - } - -} - -static void gen_shift_rhs_check(CodeGen *g, ZigType *lhs_type, ZigType *rhs_type, LLVMValueRef value) { - // We only check if the rhs value of the shift expression is greater or - // equal to the number of bits of the lhs if it's not a power of two, - // otherwise the check is useful as the allowed values are limited by the - // operand type itself - if (!is_power_of_2(lhs_type->data.integral.bit_count)) { - BigInt bit_count_bi = {0}; - bigint_init_unsigned(&bit_count_bi, lhs_type->data.integral.bit_count); - LLVMValueRef bit_count_value = bigint_to_llvm_const(get_llvm_type(g, rhs_type), - &bit_count_bi); - - LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "CheckFail"); - LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "CheckOk"); - LLVMValueRef less_than_bit = LLVMBuildICmp(g->builder, LLVMIntULT, value, bit_count_value, ""); - if (rhs_type->id == ZigTypeIdVector) { - less_than_bit = ZigLLVMBuildOrReduce(g->builder, less_than_bit); - } - LLVMBuildCondBr(g->builder, less_than_bit, ok_block, fail_block); - - LLVMPositionBuilderAtEnd(g->builder, fail_block); - gen_safety_crash(g, PanicMsgIdShxTooBigRhs); - - LLVMPositionBuilderAtEnd(g->builder, ok_block); - } -} - -enum Icmp { - NONE, - EQ_ZERO, - NE_ZERO, - LE_ZERO, - EQ_NEG, - GE_ZERO, - EQ_ONE, -}; - -static LLVMValueRef add_icmp(CodeGen *g, LLVMValueRef val, Icmp kind) { - switch (kind) { - case NONE: - return val; - case EQ_ZERO: { - LLVMValueRef zero = LLVMConstInt(g->builtin_types.entry_i32->llvm_type, 0, true); - return LLVMBuildICmp(g->builder, LLVMIntEQ, val, zero, ""); - } - case NE_ZERO: { - LLVMValueRef zero = LLVMConstInt(g->builtin_types.entry_i32->llvm_type, 0, true); - return LLVMBuildICmp(g->builder, LLVMIntNE, val, zero, ""); - } - case LE_ZERO: { - LLVMValueRef zero = LLVMConstInt(g->builtin_types.entry_i32->llvm_type, 0, true); - return LLVMBuildICmp(g->builder, LLVMIntSLE, val, zero, ""); - } - case EQ_NEG: { - LLVMValueRef zero = LLVMConstInt(g->builtin_types.entry_i32->llvm_type, -1, true); - return LLVMBuildICmp(g->builder, LLVMIntEQ, val, zero, ""); - } - case GE_ZERO: { - LLVMValueRef zero = LLVMConstInt(g->builtin_types.entry_i32->llvm_type, 0, true); - return LLVMBuildICmp(g->builder, LLVMIntSGE, val, zero, ""); - } - case EQ_ONE: { - LLVMValueRef zero = LLVMConstInt(g->builtin_types.entry_i32->llvm_type, 1, true); - return LLVMBuildICmp(g->builder, LLVMIntEQ, val, zero, ""); - } - default: - zig_unreachable(); - } -} - -static LLVMValueRef gen_soft_int_to_float_op(CodeGen *g, LLVMValueRef value_ref, ZigType *operand_type, ZigType *result_type) { - // Handle integers of non-pot bitsize by widening them. - const size_t bitsize = operand_type->data.integral.bit_count; - const bool is_signed = operand_type->data.integral.is_signed; - if (bitsize < 32 || !is_power_of_2(bitsize)) { - const size_t wider_bitsize = bitsize < 32 ? 32 : round_to_next_power_of_2(bitsize); - ZigType *wider_type = get_int_type(g, is_signed, wider_bitsize); - value_ref = gen_widen_or_shorten(g, false, operand_type, wider_type, value_ref); - operand_type = wider_type; - } - assert(bitsize <= 128); - - const char *int_compiler_rt_type_abbrev = get_compiler_rt_type_abbrev(operand_type); - const char *float_compiler_rt_type_abbrev = get_compiler_rt_type_abbrev(result_type); - - char fn_name[64]; - if (is_signed) { - snprintf(fn_name, sizeof(fn_name), "__float%si%sf", int_compiler_rt_type_abbrev, float_compiler_rt_type_abbrev); - } else { - snprintf(fn_name, sizeof(fn_name), "__floatun%si%sf", int_compiler_rt_type_abbrev, float_compiler_rt_type_abbrev); - } - - int param_count = 1; - LLVMValueRef func_ref; - if ((operand_type->data.integral.bit_count == 128) && (g->zig_target->os == OsWindows) && (g->zig_target->arch == ZigLLVM_x86_64)) { - // On Windows x86-64, "ti" functions must use Vector(2, u64) instead of the standard i128 calling - // convention to adhere to the ABI that LLVM expects compiler-rt to have. - LLVMTypeRef v2i64 = LLVMVectorType(LLVMInt64Type(), 2); - value_ref = LLVMBuildBitCast(g->builder, value_ref, v2i64, ""); - func_ref = get_soft_float_fn(g, fn_name, param_count, v2i64, result_type->llvm_type); - } else { - func_ref = get_soft_float_fn(g, fn_name, param_count, operand_type->llvm_type, result_type->llvm_type); - } - - LLVMValueRef params[1] = {value_ref}; - return LLVMBuildCall2(g->builder, LLVMGlobalGetValueType(func_ref), func_ref, params, param_count, ""); -} - -static LLVMValueRef gen_soft_float_to_int_op(CodeGen *g, LLVMValueRef value_ref, ZigType *operand_type, ZigType *result_type) { - // Handle integers of non-pot bitsize by truncating a sufficiently wide pot integer - const size_t bitsize = result_type->data.integral.bit_count; - const bool is_signed = result_type->data.integral.is_signed; - ZigType * wider_type = result_type; - if (bitsize < 32 || !is_power_of_2(bitsize)) { - const size_t wider_bitsize = bitsize < 32 ? 32 : round_to_next_power_of_2(bitsize); - wider_type = get_int_type(g, is_signed, wider_bitsize); - } - assert(bitsize <= 128); - - const char *float_compiler_rt_type_abbrev = get_compiler_rt_type_abbrev(operand_type); - const char *int_compiler_rt_type_abbrev = get_compiler_rt_type_abbrev(wider_type); - - char fn_name[64]; - if (is_signed) { - snprintf(fn_name, sizeof(fn_name), "__fix%sf%si", float_compiler_rt_type_abbrev, int_compiler_rt_type_abbrev); - } else { - snprintf(fn_name, sizeof(fn_name), "__fixuns%sf%si", float_compiler_rt_type_abbrev, int_compiler_rt_type_abbrev); - } - - int param_count = 1; - LLVMValueRef func_ref; - if ((wider_type->data.integral.bit_count == 128) && (g->zig_target->os == OsWindows) && (g->zig_target->arch == ZigLLVM_x86_64)) { - // On Windows x86-64, "ti" functions must use Vector(2, u64) instead of the standard i128 calling - // convention to adhere to the ABI that LLVM expects compiler-rt to have. - LLVMTypeRef v2i64 = LLVMVectorType(LLVMInt64Type(), 2); - func_ref = get_soft_float_fn(g, fn_name, param_count, operand_type->llvm_type, v2i64); - } else { - func_ref = get_soft_float_fn(g, fn_name, param_count, operand_type->llvm_type, wider_type->llvm_type); - } - - LLVMValueRef params[1] = {value_ref}; - LLVMValueRef result = LLVMBuildCall2(g->builder, LLVMGlobalGetValueType(func_ref), func_ref, params, param_count, ""); - - if ((wider_type->data.integral.bit_count == 128) && (g->zig_target->os == OsWindows) && (g->zig_target->arch == ZigLLVM_x86_64)) { - result = LLVMBuildBitCast(g->builder, result, wider_type->llvm_type, ""); - } - - // Handle integers of non-pot bitsize by shortening them on the output - if (result_type != wider_type) { - result = gen_widen_or_shorten(g, false, wider_type, result_type, result); - } - - return result; -} - -static LLVMValueRef gen_soft_float_bin_op(CodeGen *g, LLVMValueRef op1_value, LLVMValueRef op2_value, ZigType *operand_type, IrBinOp op_id) { - uint32_t vector_len = operand_type->id == ZigTypeIdVector ? operand_type->data.vector.len : 0; - - int param_count = 2; - - ZigType *operand_scalar_type = (operand_type->id == ZigTypeIdVector) ? operand_type->data.vector.elem_type : operand_type; - LLVMTypeRef return_scalar_type = operand_scalar_type->llvm_type; - const char *compiler_rt_type_abbrev = get_compiler_rt_type_abbrev(operand_scalar_type); - const char *math_float_prefix = libc_float_prefix(g, operand_scalar_type); - const char *math_float_suffix = libc_float_suffix(g, operand_scalar_type); - - char fn_name[64]; - Icmp res_icmp = NONE; - switch (op_id) { - case IrBinOpInvalid: - case IrBinOpArrayCat: - case IrBinOpArrayMult: - case IrBinOpRemUnspecified: - case IrBinOpBitShiftLeftLossy: - case IrBinOpBitShiftLeftExact: - case IrBinOpBitShiftRightLossy: - case IrBinOpBitShiftRightExact: - case IrBinOpBoolOr: - case IrBinOpBoolAnd: - case IrBinOpMultWrap: - case IrBinOpAddWrap: - case IrBinOpSubWrap: - case IrBinOpBinOr: - case IrBinOpBinXor: - case IrBinOpBinAnd: - case IrBinOpAddSat: - case IrBinOpSubSat: - case IrBinOpMultSat: - case IrBinOpShlSat: - zig_unreachable(); - case IrBinOpCmpEq: - return_scalar_type = g->builtin_types.entry_i32->llvm_type; - snprintf(fn_name, sizeof(fn_name), "__eq%sf2", compiler_rt_type_abbrev); - res_icmp = EQ_ZERO; - break; - case IrBinOpCmpNotEq: - return_scalar_type = g->builtin_types.entry_i32->llvm_type; - snprintf(fn_name, sizeof(fn_name), "__ne%sf2", compiler_rt_type_abbrev); - res_icmp = NE_ZERO; - break; - case IrBinOpCmpLessOrEq: - return_scalar_type = g->builtin_types.entry_i32->llvm_type; - snprintf(fn_name, sizeof(fn_name), "__le%sf2", compiler_rt_type_abbrev); - res_icmp = LE_ZERO; - break; - case IrBinOpCmpLessThan: - return_scalar_type = g->builtin_types.entry_i32->llvm_type; - snprintf(fn_name, sizeof(fn_name), "__le%sf2", compiler_rt_type_abbrev); - res_icmp = EQ_NEG; - break; - case IrBinOpCmpGreaterOrEq: - return_scalar_type = g->builtin_types.entry_i32->llvm_type; - snprintf(fn_name, sizeof(fn_name), "__ge%sf2", compiler_rt_type_abbrev); - res_icmp = GE_ZERO; - break; - case IrBinOpCmpGreaterThan: - return_scalar_type = g->builtin_types.entry_i32->llvm_type; - snprintf(fn_name, sizeof(fn_name), "__ge%sf2", compiler_rt_type_abbrev); - res_icmp = EQ_ONE; - break; - case IrBinOpMax: - snprintf(fn_name, sizeof(fn_name), "%sfmax%s", math_float_prefix, math_float_suffix); - break; - case IrBinOpMin: - snprintf(fn_name, sizeof(fn_name), "%sfmin%s", math_float_prefix, math_float_suffix); - break; - case IrBinOpMult: - snprintf(fn_name, sizeof(fn_name), "__mul%sf3", compiler_rt_type_abbrev); - break; - case IrBinOpAdd: - snprintf(fn_name, sizeof(fn_name), "__add%sf3", compiler_rt_type_abbrev); - break; - case IrBinOpSub: - snprintf(fn_name, sizeof(fn_name), "__sub%sf3", compiler_rt_type_abbrev); - break; - case IrBinOpDivUnspecified: - case IrBinOpDivExact: - case IrBinOpDivTrunc: - case IrBinOpDivFloor: - snprintf(fn_name, sizeof(fn_name), "__div%sf3", compiler_rt_type_abbrev); - break; - case IrBinOpRemRem: - case IrBinOpRemMod: - snprintf(fn_name, sizeof(fn_name), "%sfmod%s", math_float_prefix, math_float_suffix); - break; - default: - zig_unreachable(); - } - - LLVMValueRef func_ref = get_soft_float_fn(g, fn_name, param_count, operand_scalar_type->llvm_type, return_scalar_type); - - LLVMValueRef result; - if (vector_len == 0) { - LLVMValueRef params[2] = {op1_value, op2_value}; - result = LLVMBuildCall2(g->builder, LLVMGlobalGetValueType(func_ref), func_ref, params, param_count, ""); - result = add_icmp(g, result, res_icmp); - } else { - ZigType *alloca_ty = operand_type; - if (res_icmp != NONE) alloca_ty = get_vector_type(g, vector_len, g->builtin_types.entry_bool); - result = LLVMGetUndef(alloca_ty->llvm_type); - - LLVMTypeRef usize_ref = g->builtin_types.entry_usize->llvm_type; - for (uint32_t i = 0; i < vector_len; i++) { - LLVMValueRef index_value = LLVMConstInt(usize_ref, i, false); - LLVMValueRef params[2] = { - LLVMBuildExtractElement(g->builder, op1_value, index_value, ""), - LLVMBuildExtractElement(g->builder, op2_value, index_value, ""), - }; - LLVMValueRef call_result = LLVMBuildCall2(g->builder, LLVMGlobalGetValueType(func_ref), func_ref, params, param_count, ""); - call_result = add_icmp(g, call_result, res_icmp); - result = LLVMBuildInsertElement(g->builder, result, call_result, index_value, ""); - } - } - - // Some operations are implemented as compound ops and require us to perform some - // more operations before we obtain the final result - switch (op_id) { - case IrBinOpDivTrunc: - return gen_float_un_op(g, result, operand_type, BuiltinFnIdTrunc); - case IrBinOpDivFloor: - return gen_float_un_op(g, result, operand_type, BuiltinFnIdFloor); - case IrBinOpRemMod: - { - LLVMValueRef b = gen_soft_float_bin_op(g, result, op2_value, operand_type, IrBinOpAdd); - LLVMValueRef wrapped_result = gen_soft_float_bin_op(g, b, op2_value, operand_type, IrBinOpRemRem); - LLVMValueRef zero = LLVMConstNull(operand_type->llvm_type); - LLVMValueRef ltz = gen_soft_float_bin_op(g, op1_value, zero, operand_type, IrBinOpCmpLessThan); - - return LLVMBuildSelect(g->builder, ltz, wrapped_result, result, ""); - } - case IrBinOpDivExact: - { - LLVMValueRef floored = gen_float_un_op(g, result, operand_type, BuiltinFnIdFloor); - LLVMValueRef ok_bit = gen_soft_float_bin_op(g, result, floored, operand_type, IrBinOpCmpEq); - if (vector_len != 0) { - ok_bit = ZigLLVMBuildAndReduce(g->builder, ok_bit); - } - - LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "DivExactOk"); - LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "DivExactFail"); - LLVMBuildCondBr(g->builder, ok_bit, ok_block, fail_block); - - LLVMPositionBuilderAtEnd(g->builder, fail_block); - gen_safety_crash(g, PanicMsgIdExactDivisionRemainder); - - LLVMPositionBuilderAtEnd(g->builder, ok_block); - } - return result; - default: - return result; - } - zig_unreachable(); -} - -static LLVMValueRef ir_render_bin_op(CodeGen *g, Stage1Air *executable, - Stage1AirInstBinOp *bin_op_instruction) -{ - IrBinOp op_id = bin_op_instruction->op_id; - Stage1AirInst *op1 = bin_op_instruction->op1; - Stage1AirInst *op2 = bin_op_instruction->op2; - - ZigType *operand_type = op1->value->type; - ZigType *scalar_type = (operand_type->id == ZigTypeIdVector) ? operand_type->data.vector.elem_type : operand_type; - if ((scalar_type == g->builtin_types.entry_f80 && !target_has_f80(g->zig_target)) || - (scalar_type == g->builtin_types.entry_f128 && !target_long_double_is_f128(g->zig_target)) || - (scalar_type == g->builtin_types.entry_f16 && !target_is_arm(g->zig_target))) { - // LLVM incorrectly lowers the soft float calls for f128 as if they operated on `long double`. - // On some targets this will be incorrect, so we manually lower the call ourselves. - LLVMValueRef op1_value = ir_llvm_value(g, op1); - LLVMValueRef op2_value = ir_llvm_value(g, op2); - return gen_soft_float_bin_op(g, op1_value, op2_value, operand_type, op_id); - } - - - bool want_runtime_safety = bin_op_instruction->safety_check_on && - ir_want_runtime_safety(g, &bin_op_instruction->base); - - LLVMValueRef op1_value = ir_llvm_value(g, op1); - LLVMValueRef op2_value = ir_llvm_value(g, op2); - - switch (op_id) { - case IrBinOpInvalid: - case IrBinOpArrayCat: - case IrBinOpArrayMult: - case IrBinOpRemUnspecified: - zig_unreachable(); - case IrBinOpBoolOr: - return LLVMBuildOr(g->builder, op1_value, op2_value, ""); - case IrBinOpBoolAnd: - return LLVMBuildAnd(g->builder, op1_value, op2_value, ""); - case IrBinOpCmpEq: - case IrBinOpCmpNotEq: - case IrBinOpCmpLessThan: - case IrBinOpCmpGreaterThan: - case IrBinOpCmpLessOrEq: - case IrBinOpCmpGreaterOrEq: - if (scalar_type->id == ZigTypeIdFloat) { - ZigLLVMSetFastMath(g->builder, ir_want_fast_math(g, &bin_op_instruction->base)); - LLVMRealPredicate pred = cmp_op_to_real_predicate(op_id); - return LLVMBuildFCmp(g->builder, pred, op1_value, op2_value, ""); - } else if (scalar_type->id == ZigTypeIdInt) { - LLVMIntPredicate pred = cmp_op_to_int_predicate(op_id, scalar_type->data.integral.is_signed); - return LLVMBuildICmp(g->builder, pred, op1_value, op2_value, ""); - } else if (scalar_type->id == ZigTypeIdEnum || - scalar_type->id == ZigTypeIdErrorSet || - scalar_type->id == ZigTypeIdBool || - get_codegen_ptr_type_bail(g, scalar_type) != nullptr) - { - LLVMIntPredicate pred = cmp_op_to_int_predicate(op_id, false); - return LLVMBuildICmp(g->builder, pred, op1_value, op2_value, ""); - } else { - zig_unreachable(); - } - case IrBinOpMult: - case IrBinOpMultWrap: - case IrBinOpAdd: - case IrBinOpAddWrap: - case IrBinOpSub: - case IrBinOpSubWrap: { - bool is_wrapping = (op_id == IrBinOpSubWrap || op_id == IrBinOpAddWrap || op_id == IrBinOpMultWrap); - AddSubMul add_sub_mul = - op_id == IrBinOpAdd || op_id == IrBinOpAddWrap ? AddSubMulAdd : - op_id == IrBinOpSub || op_id == IrBinOpSubWrap ? AddSubMulSub : - AddSubMulMul; - - if (scalar_type->id == ZigTypeIdPointer) { - LLVMValueRef subscript_value; - if (operand_type->id == ZigTypeIdVector) - zig_panic("TODO: Implement vector operations on pointers."); - - switch (add_sub_mul) { - case AddSubMulAdd: - subscript_value = op2_value; - break; - case AddSubMulSub: - subscript_value = LLVMBuildNeg(g->builder, op2_value, ""); - break; - case AddSubMulMul: - zig_unreachable(); - } - - // TODO runtime safety - LLVMTypeRef elem_llvm_ty = get_llvm_type(g, scalar_type->data.pointer.child_type); - return LLVMBuildInBoundsGEP2(g->builder, elem_llvm_ty, op1_value, - &subscript_value, 1, ""); - } else if (scalar_type->id == ZigTypeIdFloat) { - ZigLLVMSetFastMath(g->builder, ir_want_fast_math(g, &bin_op_instruction->base)); - return float_op[add_sub_mul](g->builder, op1_value, op2_value, ""); - } else if (scalar_type->id == ZigTypeIdInt) { - if (is_wrapping) { - return wrap_op[add_sub_mul](g->builder, op1_value, op2_value, ""); - } else if (want_runtime_safety) { - return gen_overflow_op(g, operand_type, add_sub_mul, op1_value, op2_value); - } else if (scalar_type->data.integral.is_signed) { - return signed_op[add_sub_mul](g->builder, op1_value, op2_value, ""); - } else { - return unsigned_op[add_sub_mul](g->builder, op1_value, op2_value, ""); - } - } else { - zig_unreachable(); - } - } - case IrBinOpBinOr: - return LLVMBuildOr(g->builder, op1_value, op2_value, ""); - case IrBinOpBinXor: - return LLVMBuildXor(g->builder, op1_value, op2_value, ""); - case IrBinOpBinAnd: - return LLVMBuildAnd(g->builder, op1_value, op2_value, ""); - case IrBinOpBitShiftLeftLossy: - case IrBinOpBitShiftLeftExact: - { - assert(scalar_type->id == ZigTypeIdInt); - LLVMValueRef op2_casted = LLVMBuildZExt(g->builder, op2_value, - LLVMTypeOf(op1_value), ""); - - if (want_runtime_safety) { - gen_shift_rhs_check(g, scalar_type, op2->value->type, op2_value); - } - - bool is_sloppy = (op_id == IrBinOpBitShiftLeftLossy); - if (is_sloppy) { - return LLVMBuildShl(g->builder, op1_value, op2_casted, ""); - } else if (want_runtime_safety) { - return gen_overflow_shl_op(g, operand_type, op1_value, op2_casted); - } else if (scalar_type->data.integral.is_signed) { - return ZigLLVMBuildNSWShl(g->builder, op1_value, op2_casted, ""); - } else { - return ZigLLVMBuildNUWShl(g->builder, op1_value, op2_casted, ""); - } - } - case IrBinOpBitShiftRightLossy: - case IrBinOpBitShiftRightExact: - { - assert(scalar_type->id == ZigTypeIdInt); - LLVMValueRef op2_casted = LLVMBuildZExt(g->builder, op2_value, - LLVMTypeOf(op1_value), ""); - - if (want_runtime_safety) { - gen_shift_rhs_check(g, scalar_type, op2->value->type, op2_value); - } - - bool is_sloppy = (op_id == IrBinOpBitShiftRightLossy); - if (is_sloppy) { - if (scalar_type->data.integral.is_signed) { - return LLVMBuildAShr(g->builder, op1_value, op2_casted, ""); - } else { - return LLVMBuildLShr(g->builder, op1_value, op2_casted, ""); - } - } else if (want_runtime_safety) { - return gen_overflow_shr_op(g, operand_type, op1_value, op2_casted); - } else if (scalar_type->data.integral.is_signed) { - return ZigLLVMBuildAShrExact(g->builder, op1_value, op2_casted, ""); - } else { - return ZigLLVMBuildLShrExact(g->builder, op1_value, op2_casted, ""); - } - } - case IrBinOpDivUnspecified: - return gen_div(g, want_runtime_safety, ir_want_fast_math(g, &bin_op_instruction->base), - op1_value, op2_value, operand_type, DivKindFloat); - case IrBinOpDivExact: - return gen_div(g, want_runtime_safety, ir_want_fast_math(g, &bin_op_instruction->base), - op1_value, op2_value, operand_type, DivKindExact); - case IrBinOpDivTrunc: - return gen_div(g, want_runtime_safety, ir_want_fast_math(g, &bin_op_instruction->base), - op1_value, op2_value, operand_type, DivKindTrunc); - case IrBinOpDivFloor: - return gen_div(g, want_runtime_safety, ir_want_fast_math(g, &bin_op_instruction->base), - op1_value, op2_value, operand_type, DivKindFloor); - case IrBinOpRemRem: - return gen_rem(g, want_runtime_safety, ir_want_fast_math(g, &bin_op_instruction->base), - op1_value, op2_value, operand_type, RemKindRem); - case IrBinOpRemMod: - return gen_rem(g, want_runtime_safety, ir_want_fast_math(g, &bin_op_instruction->base), - op1_value, op2_value, operand_type, RemKindMod); - case IrBinOpMax: - if (scalar_type->id == ZigTypeIdFloat) { - return ZigLLVMBuildMaxNum(g->builder, op1_value, op2_value, ""); - } else if (scalar_type->id == ZigTypeIdInt) { - if (scalar_type->data.integral.is_signed) { - return ZigLLVMBuildSMax(g->builder, op1_value, op2_value, ""); - } else { - return ZigLLVMBuildUMax(g->builder, op1_value, op2_value, ""); - } - } else { - zig_unreachable(); - } - case IrBinOpMin: - if (scalar_type->id == ZigTypeIdFloat) { - return ZigLLVMBuildMinNum(g->builder, op1_value, op2_value, ""); - } else if (scalar_type->id == ZigTypeIdInt) { - if (scalar_type->data.integral.is_signed) { - return ZigLLVMBuildSMin(g->builder, op1_value, op2_value, ""); - } else { - return ZigLLVMBuildUMin(g->builder, op1_value, op2_value, ""); - } - } else { - zig_unreachable(); - } - case IrBinOpAddSat: - if (scalar_type->id == ZigTypeIdInt) { - if (scalar_type->data.integral.is_signed) { - return ZigLLVMBuildSAddSat(g->builder, op1_value, op2_value, ""); - } else { - return ZigLLVMBuildUAddSat(g->builder, op1_value, op2_value, ""); - } - } else { - zig_unreachable(); - } - case IrBinOpSubSat: - if (scalar_type->id == ZigTypeIdInt) { - if (scalar_type->data.integral.is_signed) { - return ZigLLVMBuildSSubSat(g->builder, op1_value, op2_value, ""); - } else { - return ZigLLVMBuildUSubSat(g->builder, op1_value, op2_value, ""); - } - } else { - zig_unreachable(); - } - case IrBinOpMultSat: - if (scalar_type->id == ZigTypeIdInt) { - if (scalar_type->data.integral.is_signed) { - return ZigLLVMBuildSMulFixSat(g->builder, op1_value, op2_value, ""); - } else { - return ZigLLVMBuildUMulFixSat(g->builder, op1_value, op2_value, ""); - } - } else { - zig_unreachable(); - } - case IrBinOpShlSat: { - if (scalar_type->id != ZigTypeIdInt) { - zig_unreachable(); - } - LLVMValueRef result = scalar_type->data.integral.is_signed ? - ZigLLVMBuildSShlSat(g->builder, op1_value, op2_value, "") : - ZigLLVMBuildUShlSat(g->builder, op1_value, op2_value, ""); - // LLVM langref says "If b is (statically or dynamically) equal to or - // larger than the integer bit width of the arguments, the result is a - // poison value." - // However Zig semantics says that saturating shift left can never produce - // undefined; instead it saturates. - LLVMTypeRef lhs_scalar_llvm_ty = get_llvm_type(g, scalar_type); - LLVMValueRef bits = LLVMConstInt(lhs_scalar_llvm_ty, - scalar_type->data.integral.bit_count, false); - LLVMValueRef lhs_max = LLVMConstAllOnes(lhs_scalar_llvm_ty); - if (operand_type->id == ZigTypeIdVector) { - uint64_t vec_len = operand_type->data.vector.len; - LLVMValueRef bits_vec = LLVMBuildVectorSplat(g->builder, vec_len, bits, ""); - LLVMValueRef lhs_max_vec = LLVMBuildVectorSplat(g->builder, vec_len, lhs_max, ""); - LLVMValueRef in_range = LLVMBuildICmp(g->builder, LLVMIntULT, op2_value, bits_vec, ""); - return LLVMBuildSelect(g->builder, in_range, result, lhs_max_vec, ""); - } else { - LLVMValueRef in_range = LLVMBuildICmp(g->builder, LLVMIntULT, op2_value, bits, ""); - return LLVMBuildSelect(g->builder, in_range, result, lhs_max, ""); - } - } - } - zig_unreachable(); -} - -static void add_error_range_check(CodeGen *g, ZigType *err_set_type, ZigType *int_type, LLVMValueRef target_val) { - assert(err_set_type->id == ZigTypeIdErrorSet); - - if (type_is_global_error_set(err_set_type)) { - LLVMValueRef zero = LLVMConstNull(get_llvm_type(g, int_type)); - LLVMValueRef neq_zero_bit = LLVMBuildICmp(g->builder, LLVMIntNE, target_val, zero, ""); - LLVMValueRef ok_bit; - - BigInt biggest_possible_err_val = {0}; - eval_min_max_value_int(g, int_type, &biggest_possible_err_val, true); - - if (bigint_fits_in_bits(&biggest_possible_err_val, 64, false) && - bigint_as_usize(&biggest_possible_err_val) < g->errors_by_index.length) - { - ok_bit = neq_zero_bit; - } else { - LLVMValueRef error_value_count = LLVMConstInt(get_llvm_type(g, int_type), g->errors_by_index.length, false); - LLVMValueRef in_bounds_bit = LLVMBuildICmp(g->builder, LLVMIntULT, target_val, error_value_count, ""); - ok_bit = LLVMBuildAnd(g->builder, neq_zero_bit, in_bounds_bit, ""); - } - - LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "IntToErrOk"); - LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "IntToErrFail"); - - LLVMBuildCondBr(g->builder, ok_bit, ok_block, fail_block); - - LLVMPositionBuilderAtEnd(g->builder, fail_block); - gen_safety_crash(g, PanicMsgIdInvalidErrorCode); - - LLVMPositionBuilderAtEnd(g->builder, ok_block); - } else { - LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "IntToErrOk"); - LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "IntToErrFail"); - - uint32_t err_count = err_set_type->data.error_set.err_count; - LLVMValueRef switch_instr = LLVMBuildSwitch(g->builder, target_val, fail_block, err_count); - for (uint32_t i = 0; i < err_count; i += 1) { - LLVMValueRef case_value = LLVMConstInt(get_llvm_type(g, g->err_tag_type), - err_set_type->data.error_set.errors[i]->value, false); - LLVMAddCase(switch_instr, case_value, ok_block); - } - - LLVMPositionBuilderAtEnd(g->builder, fail_block); - gen_safety_crash(g, PanicMsgIdInvalidErrorCode); - - LLVMPositionBuilderAtEnd(g->builder, ok_block); - } -} - -static LLVMValueRef ir_render_cast(CodeGen *g, Stage1Air *executable, - Stage1AirInstCast *cast_instruction) -{ - Error err; - ZigType *actual_type = cast_instruction->value->value->type; - ZigType *wanted_type = cast_instruction->base.value->type; - bool wanted_type_has_bits; - if ((err = type_has_bits2(g, wanted_type, &wanted_type_has_bits))) - codegen_report_errors_and_exit(g); - if (!wanted_type_has_bits) - return nullptr; - LLVMValueRef expr_val = ir_llvm_value(g, cast_instruction->value); - ir_assert(expr_val, &cast_instruction->base); - - switch (cast_instruction->cast_op) { - case CastOpNoCast: - case CastOpNumLitToConcrete: - zig_unreachable(); - case CastOpNoop: - if (actual_type->id == ZigTypeIdPointer && wanted_type->id == ZigTypeIdPointer && - actual_type->data.pointer.child_type->id == ZigTypeIdArray && - wanted_type->data.pointer.child_type->id == ZigTypeIdArray) - { - return LLVMBuildBitCast(g->builder, expr_val, get_llvm_type(g, wanted_type), ""); - } else { - return expr_val; - } - case CastOpIntToFloat: - assert(actual_type->id == ZigTypeIdInt); - { - if ((wanted_type == g->builtin_types.entry_f80 && !target_has_f80(g->zig_target)) || - (wanted_type == g->builtin_types.entry_f128 && !target_long_double_is_f128(g->zig_target)) || - (wanted_type == g->builtin_types.entry_f16 && !target_is_arm(g->zig_target))) { - return gen_soft_int_to_float_op(g, expr_val, actual_type, wanted_type); - } else { - if (actual_type->data.integral.is_signed) { - return LLVMBuildSIToFP(g->builder, expr_val, get_llvm_type(g, wanted_type), ""); - } else { - return LLVMBuildUIToFP(g->builder, expr_val, get_llvm_type(g, wanted_type), ""); - } - } - } - case CastOpFloatToInt: { - assert(wanted_type->id == ZigTypeIdInt); - ZigLLVMSetFastMath(g->builder, ir_want_fast_math(g, &cast_instruction->base)); - - bool want_safety = ir_want_runtime_safety(g, &cast_instruction->base); - - LLVMValueRef result; - if ((actual_type == g->builtin_types.entry_f80 && !target_has_f80(g->zig_target)) || - (actual_type == g->builtin_types.entry_f128 && !target_long_double_is_f128(g->zig_target)) || - (actual_type == g->builtin_types.entry_f16 && !target_is_arm(g->zig_target))) { - result = gen_soft_float_to_int_op(g, expr_val, actual_type, wanted_type); - } else { - if (wanted_type->data.integral.is_signed) { - result = LLVMBuildFPToSI(g->builder, expr_val, get_llvm_type(g, wanted_type), ""); - } else { - result = LLVMBuildFPToUI(g->builder, expr_val, get_llvm_type(g, wanted_type), ""); - } - } - - if (want_safety) { - LLVMValueRef back_to_float; - if ((actual_type == g->builtin_types.entry_f80 && !target_has_f80(g->zig_target)) || - (actual_type == g->builtin_types.entry_f128 && !target_long_double_is_f128(g->zig_target))) { - back_to_float = gen_soft_int_to_float_op(g, result, wanted_type, actual_type); - } else { - if (wanted_type->data.integral.is_signed) { - back_to_float = LLVMBuildSIToFP(g->builder, result, LLVMTypeOf(expr_val), ""); - } else { - back_to_float = LLVMBuildUIToFP(g->builder, result, LLVMTypeOf(expr_val), ""); - } - } - LLVMValueRef difference = LLVMBuildFSub(g->builder, expr_val, back_to_float, ""); - LLVMValueRef one_pos = LLVMConstReal(LLVMTypeOf(expr_val), 1.0f); - LLVMValueRef one_neg = LLVMConstReal(LLVMTypeOf(expr_val), -1.0f); - LLVMValueRef ok_bit_pos = LLVMBuildFCmp(g->builder, LLVMRealOLT, difference, one_pos, ""); - LLVMValueRef ok_bit_neg = LLVMBuildFCmp(g->builder, LLVMRealOGT, difference, one_neg, ""); - LLVMValueRef ok_bit = LLVMBuildAnd(g->builder, ok_bit_pos, ok_bit_neg, ""); - LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "FloatCheckOk"); - LLVMBasicBlockRef bad_block = LLVMAppendBasicBlock(g->cur_fn_val, "FloatCheckFail"); - LLVMBuildCondBr(g->builder, ok_bit, ok_block, bad_block); - LLVMPositionBuilderAtEnd(g->builder, bad_block); - gen_safety_crash(g, PanicMsgIdFloatToInt); - LLVMPositionBuilderAtEnd(g->builder, ok_block); - } - return result; - } - case CastOpBoolToInt: - assert(wanted_type->id == ZigTypeIdInt); - assert(actual_type->id == ZigTypeIdBool); - return LLVMBuildZExt(g->builder, expr_val, get_llvm_type(g, wanted_type), ""); - case CastOpErrSet: - if (ir_want_runtime_safety(g, &cast_instruction->base)) { - add_error_range_check(g, wanted_type, g->err_tag_type, expr_val); - } - return expr_val; - case CastOpBitCast: - return LLVMBuildBitCast(g->builder, expr_val, get_llvm_type(g, wanted_type), ""); - } - zig_unreachable(); -} - -static LLVMValueRef ir_render_ptr_of_array_to_slice(CodeGen *g, Stage1Air *executable, - Stage1AirInstPtrOfArrayToSlice *instruction) -{ - ZigType *actual_type = instruction->operand->value->type; - ZigType *slice_type = instruction->base.value->type; - ZigType *slice_ptr_type = slice_type->data.structure.fields[slice_ptr_index]->type_entry; - size_t ptr_index = slice_type->data.structure.fields[slice_ptr_index]->gen_index; - size_t len_index = slice_type->data.structure.fields[slice_len_index]->gen_index; - - LLVMValueRef result_loc = ir_llvm_value(g, instruction->result_loc); - - assert(actual_type->id == ZigTypeIdPointer); - ZigType *array_type = actual_type->data.pointer.child_type; - assert(array_type->id == ZigTypeIdArray); - - if (type_has_bits(g, actual_type)) { - LLVMValueRef ptr_field_ptr = LLVMBuildStructGEP2(g->builder, get_llvm_type(g, slice_type), - result_loc, ptr_index, ""); - LLVMValueRef indices[] = { - LLVMConstNull(g->builtin_types.entry_usize->llvm_type), - LLVMConstInt(g->builtin_types.entry_usize->llvm_type, 0, false), - }; - LLVMValueRef expr_val = ir_llvm_value(g, instruction->operand); - LLVMValueRef slice_start_ptr = LLVMBuildInBoundsGEP2(g->builder, - get_llvm_type(g, array_type), expr_val, indices, 2, ""); - gen_store_untyped(g, slice_start_ptr, ptr_field_ptr, 0, false); - } else if (ir_want_runtime_safety(g, &instruction->base) && ptr_index != SIZE_MAX) { - LLVMValueRef ptr_field_ptr = LLVMBuildStructGEP2(g->builder, get_llvm_type(g, slice_type), result_loc, ptr_index, ""); - gen_undef_init(g, slice_ptr_type, slice_ptr_type, ptr_field_ptr); - } - - LLVMValueRef len_field_ptr = LLVMBuildStructGEP2(g->builder, get_llvm_type(g, slice_type), result_loc, len_index, ""); - LLVMValueRef len_value = LLVMConstInt(g->builtin_types.entry_usize->llvm_type, - array_type->data.array.len, false); - gen_store_untyped(g, len_value, len_field_ptr, 0, false); - - return result_loc; -} - -static LLVMValueRef ir_render_ptr_cast(CodeGen *g, Stage1Air *executable, - Stage1AirInstPtrCast *instruction) -{ - ZigType *wanted_type = instruction->base.value->type; - if (!type_has_bits(g, wanted_type)) { - return nullptr; - } - LLVMValueRef ptr = ir_llvm_value(g, instruction->ptr); - LLVMValueRef result_ptr = LLVMBuildBitCast(g->builder, ptr, get_llvm_type(g, wanted_type), ""); - bool want_safety_check = instruction->safety_check_on && ir_want_runtime_safety(g, &instruction->base); - if (!want_safety_check || ptr_allows_addr_zero(wanted_type)) - return result_ptr; - - LLVMValueRef zero = LLVMConstNull(LLVMTypeOf(result_ptr)); - LLVMValueRef ok_bit = LLVMBuildICmp(g->builder, LLVMIntNE, result_ptr, zero, ""); - LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "PtrCastFail"); - LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "PtrCastOk"); - LLVMBuildCondBr(g->builder, ok_bit, ok_block, fail_block); - - LLVMPositionBuilderAtEnd(g->builder, fail_block); - gen_safety_crash(g, PanicMsgIdPtrCastNull); - - LLVMPositionBuilderAtEnd(g->builder, ok_block); - return result_ptr; -} - -static LLVMValueRef ir_render_bit_cast(CodeGen *g, Stage1Air *executable, - Stage1AirInstBitCast *instruction) -{ - ZigType *wanted_type = instruction->base.value->type; - ZigType *actual_type = instruction->operand->value->type; - LLVMValueRef value = ir_llvm_value(g, instruction->operand); - - bool wanted_is_ptr = handle_is_ptr(g, wanted_type); - bool actual_is_ptr = handle_is_ptr(g, actual_type); - if (wanted_is_ptr == actual_is_ptr) { - // We either bitcast the value directly or bitcast the pointer which does a pointer cast - LLVMTypeRef wanted_type_ref = wanted_is_ptr ? - LLVMPointerType(get_llvm_type(g, wanted_type), 0) : get_llvm_type(g, wanted_type); - return LLVMBuildBitCast(g->builder, value, wanted_type_ref, ""); - } else if (actual_is_ptr) { - // A scalar is wanted but we got a pointer - LLVMTypeRef wanted_elem_type_ref = get_llvm_type(g, wanted_type); - LLVMValueRef bitcasted_ptr = LLVMBuildBitCast(g->builder, value, - LLVMPointerType(wanted_elem_type_ref, 0), ""); - uint32_t alignment = get_abi_alignment(g, actual_type); - return gen_load_untyped(g, wanted_elem_type_ref, bitcasted_ptr, alignment, false, ""); - } else { - // A pointer is wanted but we got a scalar - assert(actual_type->id == ZigTypeIdPointer); - LLVMTypeRef wanted_ptr_type_ref = LLVMPointerType(get_llvm_type(g, wanted_type), 0); - return LLVMBuildBitCast(g->builder, value, wanted_ptr_type_ref, ""); - } -} - -static LLVMValueRef ir_render_widen_or_shorten(CodeGen *g, Stage1Air *executable, - Stage1AirInstWidenOrShorten *instruction) -{ - ZigType *actual_type = instruction->target->value->type; - // TODO instead of this logic, use the Noop instruction to change the type from - // enum_tag to the underlying int type - ZigType *int_type; - if (actual_type->id == ZigTypeIdEnum) { - int_type = actual_type->data.enumeration.tag_int_type; - } else { - int_type = actual_type; - } - LLVMValueRef target_val = ir_llvm_value(g, instruction->target); - return gen_widen_or_shorten(g, ir_want_runtime_safety(g, &instruction->base), int_type, - instruction->base.value->type, target_val); -} - -static LLVMValueRef ir_render_int_to_ptr(CodeGen *g, Stage1Air *executable, Stage1AirInstIntToPtr *instruction) { - ZigType *wanted_type = instruction->base.value->type; - LLVMValueRef target_val = ir_llvm_value(g, instruction->target); - const uint32_t align_bytes = get_ptr_align(g, wanted_type); - - if (ir_want_runtime_safety(g, &instruction->base)) { - ZigType *usize = g->builtin_types.entry_usize; - LLVMValueRef zero = LLVMConstNull(usize->llvm_type); - - if (!ptr_allows_addr_zero(wanted_type)) { - LLVMValueRef is_zero_bit = LLVMBuildICmp(g->builder, LLVMIntEQ, target_val, zero, ""); - LLVMBasicBlockRef bad_block = LLVMAppendBasicBlock(g->cur_fn_val, "PtrToIntBad"); - LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "PtrToIntOk"); - LLVMBuildCondBr(g->builder, is_zero_bit, bad_block, ok_block); - - LLVMPositionBuilderAtEnd(g->builder, bad_block); - gen_safety_crash(g, PanicMsgIdPtrCastNull); - - LLVMPositionBuilderAtEnd(g->builder, ok_block); - } - - if (align_bytes > 1) { - LLVMValueRef alignment_minus_1 = LLVMConstInt(usize->llvm_type, align_bytes - 1, false); - LLVMValueRef anded_val = LLVMBuildAnd(g->builder, target_val, alignment_minus_1, ""); - LLVMValueRef is_ok_bit = LLVMBuildICmp(g->builder, LLVMIntEQ, anded_val, zero, ""); - LLVMBasicBlockRef bad_block = LLVMAppendBasicBlock(g->cur_fn_val, "PtrToIntAlignBad"); - LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "PtrToIntAlignOk"); - LLVMBuildCondBr(g->builder, is_ok_bit, ok_block, bad_block); - - LLVMPositionBuilderAtEnd(g->builder, bad_block); - gen_safety_crash(g, PanicMsgIdIncorrectAlignment); - - LLVMPositionBuilderAtEnd(g->builder, ok_block); - } - } - return LLVMBuildIntToPtr(g->builder, target_val, get_llvm_type(g, wanted_type), ""); -} - -static LLVMValueRef ir_render_ptr_to_int(CodeGen *g, Stage1Air *executable, Stage1AirInstPtrToInt *instruction) { - ZigType *wanted_type = instruction->base.value->type; - LLVMValueRef target_val = ir_llvm_value(g, instruction->target); - return LLVMBuildPtrToInt(g->builder, target_val, get_llvm_type(g, wanted_type), ""); -} - -static LLVMValueRef ir_render_int_to_enum(CodeGen *g, Stage1Air *executable, Stage1AirInstIntToEnum *instruction) { - ZigType *wanted_type = instruction->base.value->type; - assert(wanted_type->id == ZigTypeIdEnum); - ZigType *tag_int_type = wanted_type->data.enumeration.tag_int_type; - - LLVMValueRef target_val = ir_llvm_value(g, instruction->target); - LLVMValueRef tag_int_value = gen_widen_or_shorten(g, ir_want_runtime_safety(g, &instruction->base), - instruction->target->value->type, tag_int_type, target_val); - - if (ir_want_runtime_safety(g, &instruction->base) && !wanted_type->data.enumeration.non_exhaustive) { - LLVMBasicBlockRef bad_value_block = LLVMAppendBasicBlock(g->cur_fn_val, "BadValue"); - LLVMBasicBlockRef ok_value_block = LLVMAppendBasicBlock(g->cur_fn_val, "OkValue"); - size_t field_count = wanted_type->data.enumeration.src_field_count; - LLVMValueRef switch_instr = LLVMBuildSwitch(g->builder, tag_int_value, bad_value_block, field_count); - - HashMap occupied_tag_values = {}; - occupied_tag_values.init(field_count); - - for (size_t field_i = 0; field_i < field_count; field_i += 1) { - TypeEnumField *type_enum_field = &wanted_type->data.enumeration.fields[field_i]; - - Buf *name = type_enum_field->name; - auto entry = occupied_tag_values.put_unique(type_enum_field->value, name); - if (entry != nullptr) { - continue; - } - - LLVMValueRef this_tag_int_value = bigint_to_llvm_const(get_llvm_type(g, tag_int_type), - &type_enum_field->value); - LLVMAddCase(switch_instr, this_tag_int_value, ok_value_block); - } - occupied_tag_values.deinit(); - LLVMPositionBuilderAtEnd(g->builder, bad_value_block); - gen_safety_crash(g, PanicMsgIdBadEnumValue); - - LLVMPositionBuilderAtEnd(g->builder, ok_value_block); - } - return tag_int_value; -} - -static LLVMValueRef ir_render_int_to_err(CodeGen *g, Stage1Air *executable, Stage1AirInstIntToErr *instruction) { - ZigType *wanted_type = instruction->base.value->type; - assert(wanted_type->id == ZigTypeIdErrorSet); - - ZigType *actual_type = instruction->target->value->type; - assert(actual_type->id == ZigTypeIdInt); - assert(!actual_type->data.integral.is_signed); - - LLVMValueRef target_val = ir_llvm_value(g, instruction->target); - - if (ir_want_runtime_safety(g, &instruction->base)) { - add_error_range_check(g, wanted_type, actual_type, target_val); - } - - return gen_widen_or_shorten(g, false, actual_type, g->err_tag_type, target_val); -} - -static LLVMValueRef ir_render_err_to_int(CodeGen *g, Stage1Air *executable, Stage1AirInstErrToInt *instruction) { - ZigType *wanted_type = instruction->base.value->type; - assert(wanted_type->id == ZigTypeIdInt); - assert(!wanted_type->data.integral.is_signed); - - ZigType *actual_type = instruction->target->value->type; - LLVMValueRef target_val = ir_llvm_value(g, instruction->target); - - if (actual_type->id == ZigTypeIdErrorSet) { - return gen_widen_or_shorten(g, ir_want_runtime_safety(g, &instruction->base), - g->err_tag_type, wanted_type, target_val); - } else if (actual_type->id == ZigTypeIdErrorUnion) { - // this should have been a compile time constant - assert(type_has_bits(g, actual_type->data.error_union.err_set_type)); - - if (!type_has_bits(g, actual_type->data.error_union.payload_type)) { - return gen_widen_or_shorten(g, ir_want_runtime_safety(g, &instruction->base), - g->err_tag_type, wanted_type, target_val); - } else { - zig_panic("TODO err to int when error union payload type not void"); - } - } else { - zig_unreachable(); - } -} - -static LLVMValueRef ir_render_unreachable(CodeGen *g, Stage1Air *executable, - Stage1AirInstUnreachable *unreachable_instruction) -{ - if (ir_want_runtime_safety(g, &unreachable_instruction->base)) { - gen_safety_crash(g, PanicMsgIdUnreachable); - } else { - LLVMBuildUnreachable(g->builder); - } - return nullptr; -} - -static LLVMValueRef ir_render_cond_br(CodeGen *g, Stage1Air *executable, - Stage1AirInstCondBr *cond_br_instruction) -{ - LLVMBuildCondBr(g->builder, - ir_llvm_value(g, cond_br_instruction->condition), - cond_br_instruction->then_block->llvm_block, - cond_br_instruction->else_block->llvm_block); - return nullptr; -} - -static LLVMValueRef ir_render_br(CodeGen *g, Stage1Air *executable, Stage1AirInstBr *br_instruction) { - LLVMBuildBr(g->builder, br_instruction->dest_block->llvm_block); - return nullptr; -} - -static LLVMValueRef ir_render_binary_not(CodeGen *g, Stage1Air *executable, - Stage1AirInstBinaryNot *inst) -{ - LLVMValueRef operand = ir_llvm_value(g, inst->operand); - return LLVMBuildNot(g->builder, operand, ""); -} - -static LLVMValueRef gen_soft_float_neg(CodeGen *g, ZigType *operand_type, LLVMValueRef operand) { - uint32_t vector_len = operand_type->id == ZigTypeIdVector ? operand_type->data.vector.len : 0; - uint16_t num_bits = operand_type->id == ZigTypeIdVector ? - operand_type->data.vector.elem_type->data.floating.bit_count : - operand_type->data.floating.bit_count; - - ZigType *iX_type = get_int_type(g, true, num_bits); - LLVMValueRef sign_mask = LLVMConstShl( - LLVMConstInt(iX_type->llvm_type, 1, false), - LLVMConstInt(iX_type->llvm_type, num_bits - 1, false)); - - LLVMValueRef sign_mask_splat = (vector_len == 0) ? sign_mask : - LLVMBuildVectorSplat(g->builder, vector_len, sign_mask, ""); - - LLVMValueRef bitcasted_operand = LLVMBuildBitCast(g->builder, operand, - (vector_len == 0) ? - iX_type->llvm_type : - get_vector_type(g, vector_len, iX_type)->llvm_type, - ""); - - LLVMValueRef result = LLVMBuildXor(g->builder, bitcasted_operand, sign_mask_splat, ""); - return LLVMBuildBitCast(g->builder, result, operand_type->llvm_type, ""); -} - -static LLVMValueRef gen_negation(CodeGen *g, Stage1AirInst *inst, Stage1AirInst *operand, bool wrapping) { - LLVMValueRef llvm_operand = ir_llvm_value(g, operand); - ZigType *operand_type = operand->value->type; - ZigType *scalar_type = (operand_type->id == ZigTypeIdVector) ? - operand_type->data.vector.elem_type : operand_type; - - if ((scalar_type == g->builtin_types.entry_f80 && !target_has_f80(g->zig_target)) || - (scalar_type == g->builtin_types.entry_f128 && !target_long_double_is_f128(g->zig_target)) || - (scalar_type == g->builtin_types.entry_f16 && !target_is_arm(g->zig_target))) { - return gen_soft_float_neg(g, operand_type, llvm_operand); - } - - if (scalar_type->id == ZigTypeIdFloat) { - ZigLLVMSetFastMath(g->builder, ir_want_fast_math(g, inst)); - return LLVMBuildFNeg(g->builder, llvm_operand, ""); - } else if (scalar_type->id == ZigTypeIdInt) { - if (wrapping) { - return LLVMBuildNeg(g->builder, llvm_operand, ""); - } else if (ir_want_runtime_safety(g, inst)) { - LLVMValueRef zero = LLVMConstNull(LLVMTypeOf(llvm_operand)); - return gen_overflow_op(g, operand_type, AddSubMulSub, zero, llvm_operand); - } else if (scalar_type->data.integral.is_signed) { - return LLVMBuildNSWNeg(g->builder, llvm_operand, ""); - } else { - zig_unreachable(); - } - } else { - zig_unreachable(); - } -} - -static LLVMValueRef ir_render_negation(CodeGen *g, Stage1Air *executable, - Stage1AirInstNegation *inst) -{ - return gen_negation(g, &inst->base, inst->operand, inst->wrapping); -} - -static LLVMValueRef ir_render_bool_not(CodeGen *g, Stage1Air *executable, Stage1AirInstBoolNot *instruction) { - LLVMValueRef value = ir_llvm_value(g, instruction->value); - LLVMValueRef zero = LLVMConstNull(LLVMTypeOf(value)); - return LLVMBuildICmp(g->builder, LLVMIntEQ, value, zero, ""); -} - -static void render_decl_var(CodeGen *g, ZigVar *var) { - if (!type_has_bits(g, var->var_type)) - return; - - var->value_ref = ir_llvm_value(g, var->ptr_instruction); - gen_var_debug_decl(g, var); -} - -static LLVMValueRef ir_render_decl_var(CodeGen *g, Stage1Air *executable, Stage1AirInstDeclVar *instruction) { - instruction->var->ptr_instruction = instruction->var_ptr; - instruction->var->did_the_decl_codegen = true; - render_decl_var(g, instruction->var); - return nullptr; -} - -static LLVMValueRef ir_render_load_ptr(CodeGen *g, Stage1Air *executable, - Stage1AirInstLoadPtr *instruction) -{ - ZigType *child_type = instruction->base.value->type; - if (!type_has_bits(g, child_type)) - return nullptr; - - LLVMValueRef ptr = ir_llvm_value(g, instruction->ptr); - ZigType *ptr_type = instruction->ptr->value->type; - assert(ptr_type->id == ZigTypeIdPointer); - - ir_assert(ptr_type->data.pointer.vector_index != VECTOR_INDEX_RUNTIME, &instruction->base); - if (ptr_type->data.pointer.vector_index != VECTOR_INDEX_NONE) { - LLVMValueRef index_val = LLVMConstInt(LLVMInt32Type(), - ptr_type->data.pointer.vector_index, false); - uint32_t vec_len = ptr_type->data.pointer.host_int_bytes; - LLVMTypeRef vec_llvm_ty = LLVMVectorType(get_llvm_type(g, child_type), vec_len); - LLVMValueRef loaded_vector = LLVMBuildLoad2(g->builder, vec_llvm_ty, ptr, ""); - return LLVMBuildExtractElement(g->builder, loaded_vector, index_val, ""); - } - - uint32_t host_int_bytes = ptr_type->data.pointer.host_int_bytes; - if (host_int_bytes == 0) - return get_handle_value(g, ptr, child_type, ptr_type); - - bool big_endian = g->is_big_endian; - - LLVMTypeRef int_ptr_ty = LLVMPointerType(LLVMIntType(host_int_bytes * 8), 0); - LLVMValueRef int_ptr = LLVMBuildBitCast(g->builder, ptr, int_ptr_ty, ""); - LLVMValueRef containing_int = gen_load_untyped(g, LLVMIntType(host_int_bytes * 8), int_ptr, - get_ptr_align(g, ptr_type), ptr_type->data.pointer.is_volatile, ""); - - uint32_t host_bit_count = LLVMGetIntTypeWidth(LLVMTypeOf(containing_int)); - ir_assert(host_bit_count == host_int_bytes * 8, &instruction->base); - uint32_t size_in_bits = type_size_bits(g, child_type); - - uint32_t bit_offset = ptr_type->data.pointer.bit_offset_in_host; - uint32_t shift_amt = big_endian ? host_bit_count - bit_offset - size_in_bits : bit_offset; - - LLVMValueRef shift_amt_val = LLVMConstInt(LLVMTypeOf(containing_int), shift_amt, false); - LLVMValueRef shifted_value = LLVMBuildLShr(g->builder, containing_int, shift_amt_val, ""); - - if (handle_is_ptr(g, child_type)) { - LLVMValueRef result_loc = ir_llvm_value(g, instruction->result_loc); - LLVMTypeRef same_size_int = LLVMIntType(size_in_bits); - LLVMValueRef truncated_int = LLVMBuildTrunc(g->builder, shifted_value, same_size_int, ""); - LLVMValueRef bitcasted_ptr = LLVMBuildBitCast(g->builder, result_loc, - LLVMPointerType(same_size_int, 0), ""); - LLVMBuildStore(g->builder, truncated_int, bitcasted_ptr); - return result_loc; - } - - if (child_type->id == ZigTypeIdFloat) { - LLVMTypeRef same_size_int = LLVMIntType(size_in_bits); - LLVMValueRef truncated_int = LLVMBuildTrunc(g->builder, shifted_value, same_size_int, ""); - return LLVMBuildBitCast(g->builder, truncated_int, get_llvm_type(g, child_type), ""); - } - - return LLVMBuildTrunc(g->builder, shifted_value, get_llvm_type(g, child_type), ""); -} - -static bool value_is_all_undef_array(CodeGen *g, ZigValue *const_val, size_t len) { - switch (const_val->data.x_array.special) { - case ConstArraySpecialUndef: - return true; - case ConstArraySpecialBuf: - return false; - case ConstArraySpecialNone: - for (size_t i = 0; i < len; i += 1) { - if (!value_is_all_undef(g, &const_val->data.x_array.data.s_none.elements[i])) - return false; - } - return true; - } - zig_unreachable(); -} - -static bool value_is_all_undef(CodeGen *g, ZigValue *const_val) { - Error err; - if (const_val->special == ConstValSpecialLazy && - (err = ir_resolve_lazy(g, nullptr, const_val))) - codegen_report_errors_and_exit(g); - - switch (const_val->special) { - case ConstValSpecialLazy: - zig_unreachable(); - case ConstValSpecialRuntime: - return false; - case ConstValSpecialUndef: - return true; - case ConstValSpecialStatic: - if (const_val->type->id == ZigTypeIdStruct) { - for (size_t i = 0; i < const_val->type->data.structure.src_field_count; i += 1) { - TypeStructField *field = const_val->type->data.structure.fields[i]; - if (field->is_comptime) { - // Comptime fields are part of the type, may be uninitialized, - // and should not be inspected. - continue; - } - if (!value_is_all_undef(g, const_val->data.x_struct.fields[i])) - return false; - } - return true; - } else if (const_val->type->id == ZigTypeIdArray) { - return value_is_all_undef_array(g, const_val, const_val->type->data.array.len); - } else if (const_val->type->id == ZigTypeIdVector) { - return value_is_all_undef_array(g, const_val, const_val->type->data.vector.len); - } else { - return false; - } - } - zig_unreachable(); -} - -static LLVMValueRef gen_valgrind_client_request(CodeGen *g, LLVMValueRef default_value, LLVMValueRef request, - LLVMValueRef a1, LLVMValueRef a2, LLVMValueRef a3, LLVMValueRef a4, LLVMValueRef a5) -{ - if (!target_has_valgrind_support(g->zig_target)) { - return default_value; - } - LLVMTypeRef usize_type_ref = g->builtin_types.entry_usize->llvm_type; - bool asm_has_side_effects = true; - bool asm_is_alignstack = false; - if (g->zig_target->arch == ZigLLVM_x86_64) { - if (g->zig_target->os == OsLinux || target_os_is_darwin(g->zig_target->os) || g->zig_target->os == OsSolaris || - (g->zig_target->os == OsWindows && g->zig_target->abi != ZigLLVM_MSVC)) - { - if (g->cur_fn->valgrind_client_request_array == nullptr) { - LLVMBasicBlockRef prev_block = LLVMGetInsertBlock(g->builder); - LLVMBasicBlockRef entry_block = LLVMGetEntryBasicBlock(g->cur_fn->llvm_value); - LLVMValueRef first_inst = LLVMGetFirstInstruction(entry_block); - LLVMPositionBuilderBefore(g->builder, first_inst); - LLVMTypeRef array_type_ref = LLVMArrayType(usize_type_ref, 6); - g->cur_fn->valgrind_client_request_array = LLVMBuildAlloca(g->builder, array_type_ref, ""); - LLVMPositionBuilderAtEnd(g->builder, prev_block); - } - LLVMValueRef array_ptr = g->cur_fn->valgrind_client_request_array; - LLVMValueRef array_elements[] = {request, a1, a2, a3, a4, a5}; - LLVMValueRef zero = LLVMConstInt(usize_type_ref, 0, false); - for (unsigned i = 0; i < 6; i += 1) { - LLVMValueRef indexes[] = { - zero, - LLVMConstInt(usize_type_ref, i, false), - }; - LLVMValueRef elem_ptr = LLVMBuildInBoundsGEP2(g->builder, - LLVMGetAllocatedType(array_ptr), array_ptr, indexes, 2, ""); - LLVMBuildStore(g->builder, array_elements[i], elem_ptr); - } - - Buf *asm_template = buf_create_from_str( - "rolq $$3, %rdi ; rolq $$13, %rdi\n" - "rolq $$61, %rdi ; rolq $$51, %rdi\n" - "xchgq %rbx,%rbx\n" - ); - Buf *asm_constraints = buf_create_from_str( - "={rdx},{rax},0,~{cc},~{memory}" - ); - unsigned input_and_output_count = 2; - LLVMValueRef array_ptr_as_usize = LLVMBuildPtrToInt(g->builder, array_ptr, usize_type_ref, ""); - LLVMValueRef param_values[] = { array_ptr_as_usize, default_value }; - LLVMTypeRef param_types[] = {usize_type_ref, usize_type_ref}; - LLVMTypeRef function_type = LLVMFunctionType(usize_type_ref, param_types, - input_and_output_count, false); - LLVMValueRef asm_fn = LLVMGetInlineAsm(function_type, buf_ptr(asm_template), buf_len(asm_template), - buf_ptr(asm_constraints), buf_len(asm_constraints), asm_has_side_effects, asm_is_alignstack, - LLVMInlineAsmDialectATT, false); - return LLVMBuildCall2(g->builder, function_type, asm_fn, param_values, input_and_output_count, ""); - } - } - zig_unreachable(); -} - -static void gen_valgrind_undef(CodeGen *g, LLVMValueRef dest_ptr, LLVMValueRef byte_count) { - static const uint32_t VG_USERREQ__MAKE_MEM_UNDEFINED = 1296236545; - ZigType *usize = g->builtin_types.entry_usize; - LLVMValueRef zero = LLVMConstInt(usize->llvm_type, 0, false); - LLVMValueRef req = LLVMConstInt(usize->llvm_type, VG_USERREQ__MAKE_MEM_UNDEFINED, false); - LLVMValueRef ptr_as_usize = LLVMBuildPtrToInt(g->builder, dest_ptr, usize->llvm_type, ""); - gen_valgrind_client_request(g, zero, req, ptr_as_usize, byte_count, zero, zero, zero); -} - -static void gen_undef_init(CodeGen *g, ZigType *ptr_type, ZigType *value_type, LLVMValueRef ptr) { - assert(type_has_bits(g, value_type)); - - uint64_t ptr_align_bytes = get_ptr_align(g, ptr_type); - assert(ptr_align_bytes > 0); - uint64_t size_bytes = LLVMStoreSizeOfType(g->target_data_ref, get_llvm_type(g, value_type)); - assert(size_bytes > 0); - - if (ptr_type->data.pointer.host_int_bytes == 0) { - // memset uninitialized memory to 0xaa - LLVMTypeRef ptr_u8 = LLVMPointerType(LLVMInt8Type(), 0); - LLVMValueRef fill_char = LLVMConstInt(LLVMInt8Type(), 0xaa, false); - LLVMValueRef dest_ptr = LLVMBuildBitCast(g->builder, ptr, ptr_u8, ""); - ZigType *usize = g->builtin_types.entry_usize; - LLVMValueRef byte_count = LLVMConstInt(usize->llvm_type, size_bytes, false); - ZigLLVMBuildMemSet(g->builder, dest_ptr, fill_char, byte_count, ptr_align_bytes, false); - // then tell valgrind that the memory is undefined even though we just memset it - if (g->valgrind_enabled) { - gen_valgrind_undef(g, dest_ptr, byte_count); - } - return; - } - - // This is a pointer into a packed struct, we can't use memset here. - // The jury is still out on what pattern should be written here so clear the - // old value and call it a day. Generating a 0xAA...AA mask for this n-bit - // value is left as an exercise for the (bored) reader. - LLVMValueRef zero = LLVMConstNull(get_llvm_type(g, value_type)); - gen_assign_raw(g, ptr, ptr_type, zero); -} - -static LLVMValueRef ir_render_store_ptr(CodeGen *g, Stage1Air *executable, Stage1AirInstStorePtr *instruction) { - Error err; - - ZigType *ptr_type = instruction->ptr->value->type; - assert(ptr_type->id == ZigTypeIdPointer); - bool ptr_type_has_bits; - if ((err = type_has_bits2(g, ptr_type, &ptr_type_has_bits))) - codegen_report_errors_and_exit(g); - if (!ptr_type_has_bits) - return nullptr; - if (instruction->ptr->ref_count == 0) { - // In this case, this StorePtr instruction should be elided. Something happened like this: - // var t = true; - // const x = if (t) Num.Two else unreachable; - // The if condition is a runtime value, so the StorePtr for `x = Num.Two` got generated - // (this instruction being rendered) but because of `else unreachable` the result ended - // up being a comptime const value. - return nullptr; - } - - bool have_init_expr = !value_is_all_undef(g, instruction->value->value); - if (have_init_expr) { - LLVMValueRef ptr = ir_llvm_value(g, instruction->ptr); - LLVMValueRef value = ir_llvm_value(g, instruction->value); - gen_assign_raw(g, ptr, ptr_type, value); - } else if (ir_want_runtime_safety(g, &instruction->base)) { - gen_undef_init(g, ptr_type, instruction->value->value->type, - ir_llvm_value(g, instruction->ptr)); - } - return nullptr; -} - -static LLVMValueRef ir_render_vector_store_elem(CodeGen *g, Stage1Air *executable, - Stage1AirInstVectorStoreElem *instruction) -{ - LLVMValueRef vector_ptr = ir_llvm_value(g, instruction->vector_ptr); - LLVMValueRef index = ir_llvm_value(g, instruction->index); - LLVMValueRef value = ir_llvm_value(g, instruction->value); - - LLVMValueRef loaded_vector = gen_load(g, vector_ptr, instruction->vector_ptr->value->type, ""); - LLVMValueRef modified_vector = LLVMBuildInsertElement(g->builder, loaded_vector, value, index, ""); - gen_store(g, modified_vector, vector_ptr, instruction->vector_ptr->value->type); - return nullptr; -} - -static LLVMValueRef ir_render_var_ptr(CodeGen *g, Stage1Air *executable, Stage1AirInstVarPtr *instruction) { - Error err; - - ZigType *ptr_type = instruction->base.value->type; - assert(ptr_type->id == ZigTypeIdPointer); - bool ptr_type_has_bits; - if ((err = type_has_bits2(g, ptr_type, &ptr_type_has_bits))) - codegen_report_errors_and_exit(g); - - if (!ptr_type_has_bits) { - return nullptr; - } - - // The extra bitcasts are needed in case the LLVM value is an unnamed - // struct, as it happens when rendering container types with extra alignment - // fields. - if (instruction->base.value->special != ConstValSpecialRuntime) { - return LLVMBuildBitCast(g->builder, ir_llvm_value(g, &instruction->base), - get_llvm_type(g, ptr_type), ""); - } - - ZigVar *var = instruction->var; - assert(var->value_ref); - return LLVMBuildBitCast(g->builder, var->value_ref, - get_llvm_type(g, ptr_type), ""); -} - -static LLVMValueRef ir_render_return_ptr(CodeGen *g, Stage1Air *executable, - Stage1AirInstReturnPtr *instruction) -{ - if (!type_has_bits(g, instruction->base.value->type)) - return nullptr; - ir_assert(g->cur_ret_ptr != nullptr, &instruction->base); - return g->cur_ret_ptr; -} - -static LLVMValueRef ir_render_elem_ptr(CodeGen *g, Stage1Air *executable, Stage1AirInstElemPtr *instruction) { - LLVMValueRef array_ptr_ptr = ir_llvm_value(g, instruction->array_ptr); - ZigType *array_ptr_type = instruction->array_ptr->value->type; - assert(array_ptr_type->id == ZigTypeIdPointer); - ZigType *array_type = array_ptr_type->data.pointer.child_type; - LLVMValueRef subscript_value = ir_llvm_value(g, instruction->elem_index); - assert(subscript_value); - - if (!type_has_bits(g, array_type)) - return nullptr; - - bool safety_check_on = ir_want_runtime_safety(g, &instruction->base) && instruction->safety_check_on; - - if (array_type->id == ZigTypeIdArray || - (array_type->id == ZigTypeIdPointer && array_type->data.pointer.ptr_len == PtrLenSingle)) - { - LLVMValueRef array_ptr = get_handle_value(g, array_ptr_ptr, array_type, array_ptr_type); - if (array_type->id == ZigTypeIdPointer) { - assert(array_type->data.pointer.child_type->id == ZigTypeIdArray); - array_type = array_type->data.pointer.child_type; - } - - assert(array_type->data.array.len != 0 || array_type->data.array.sentinel != nullptr); - - if (safety_check_on) { - uint64_t extra_len_from_sentinel = (array_type->data.array.sentinel != nullptr) ? 1 : 0; - uint64_t full_len = array_type->data.array.len + extra_len_from_sentinel; - LLVMValueRef end = LLVMConstInt(g->builtin_types.entry_usize->llvm_type, full_len, false); - add_bounds_check(g, subscript_value, LLVMIntEQ, nullptr, LLVMIntULT, end); - } - if (array_ptr_type->data.pointer.host_int_bytes != 0) { - return array_ptr_ptr; - } - ZigType *child_type = array_type->data.array.child_type; - if (child_type->id == ZigTypeIdStruct && - child_type->data.structure.layout == ContainerLayoutPacked) - { - ZigType *ptr_type = instruction->base.value->type; - size_t host_int_bytes = ptr_type->data.pointer.host_int_bytes; - if (host_int_bytes != 0) { - uint32_t size_in_bits = type_size_bits(g, ptr_type->data.pointer.child_type); - LLVMTypeRef ptr_u8_type_ref = LLVMPointerType(LLVMInt8Type(), 0); - LLVMValueRef u8_array_ptr = LLVMBuildBitCast(g->builder, array_ptr, ptr_u8_type_ref, ""); - assert(size_in_bits % 8 == 0); - LLVMValueRef elem_size_bytes = LLVMConstInt(g->builtin_types.entry_usize->llvm_type, - size_in_bits / 8, false); - LLVMValueRef byte_offset = LLVMBuildNUWMul(g->builder, subscript_value, elem_size_bytes, ""); - LLVMValueRef indices[] = { byte_offset }; - LLVMValueRef elem_byte_ptr = LLVMBuildInBoundsGEP2(g->builder, LLVMInt8Type(), - u8_array_ptr, indices, 1, ""); - return LLVMBuildBitCast(g->builder, elem_byte_ptr, LLVMPointerType(get_llvm_type(g, child_type), 0), ""); - } - } - LLVMValueRef indices[] = { - LLVMConstNull(g->builtin_types.entry_usize->llvm_type), - subscript_value - }; - return LLVMBuildInBoundsGEP2(g->builder, get_llvm_type(g, array_type), array_ptr, - indices, 2, ""); - } else if (array_type->id == ZigTypeIdPointer) { - LLVMValueRef array_ptr = get_handle_value(g, array_ptr_ptr, array_type, array_ptr_type); - assert(LLVMGetTypeKind(LLVMTypeOf(array_ptr)) == LLVMPointerTypeKind); - LLVMValueRef indices[] = { subscript_value }; - LLVMTypeRef elem_llvm_ty = get_llvm_type(g, array_type->data.pointer.child_type); - return LLVMBuildInBoundsGEP2(g->builder, elem_llvm_ty, array_ptr, indices, 1, ""); - } else if (array_type->id == ZigTypeIdStruct) { - LLVMValueRef array_ptr = get_handle_value(g, array_ptr_ptr, array_type, array_ptr_type); - assert(array_type->data.structure.special == StructSpecialSlice); - - ZigType *ptr_type = array_type->data.structure.fields[slice_ptr_index]->type_entry; - if (!type_has_bits(g, ptr_type)) { - if (safety_check_on) { - assert(LLVMGetTypeKind(LLVMTypeOf(array_ptr)) == LLVMIntegerTypeKind); - add_bounds_check(g, subscript_value, LLVMIntEQ, nullptr, LLVMIntULT, array_ptr); - } - return nullptr; - } - - assert(LLVMGetTypeKind(LLVMTypeOf(array_ptr)) == LLVMPointerTypeKind); - - if (safety_check_on) { - size_t len_index = array_type->data.structure.fields[slice_len_index]->gen_index; - assert(len_index != SIZE_MAX); - LLVMValueRef len_ptr = LLVMBuildStructGEP2(g->builder, get_llvm_type(g, array_type), - array_ptr, (unsigned)len_index, ""); - LLVMValueRef len = gen_load_untyped(g, ZigLLVMGetGEPResultElementType(len_ptr), len_ptr, - 0, false, ""); - LLVMIntPredicate upper_op = (ptr_type->data.pointer.sentinel != nullptr) ? LLVMIntULE : LLVMIntULT; - add_bounds_check(g, subscript_value, LLVMIntEQ, nullptr, upper_op, len); - } - - size_t ptr_index = array_type->data.structure.fields[slice_ptr_index]->gen_index; - assert(ptr_index != SIZE_MAX); - LLVMValueRef ptr_ptr = LLVMBuildStructGEP2(g->builder, get_llvm_type(g, array_type), - array_ptr, (unsigned)ptr_index, ""); - LLVMValueRef ptr = gen_load_untyped(g, - LLVMPointerTypeInContext(LLVMGetGlobalContext(), 0), ptr_ptr, 0, false, ""); - LLVMTypeRef elem_llvm_ty = get_llvm_type(g, ptr_type->data.pointer.child_type); - return LLVMBuildInBoundsGEP2(g->builder, elem_llvm_ty, ptr, &subscript_value, 1, ""); - } else if (array_type->id == ZigTypeIdVector) { - return array_ptr_ptr; - } else { - zig_unreachable(); - } -} - -static LLVMValueRef get_new_stack_addr(CodeGen *g, LLVMTypeRef new_stack_llvm_ty, - LLVMValueRef new_stack) -{ - LLVMValueRef ptr_field_ptr = LLVMBuildStructGEP2(g->builder, new_stack_llvm_ty, new_stack, (unsigned)slice_ptr_index, ""); - LLVMValueRef len_field_ptr = LLVMBuildStructGEP2(g->builder, new_stack_llvm_ty, new_stack, (unsigned)slice_len_index, ""); - - LLVMValueRef ptr_value = gen_load_untyped(g, ZigLLVMGetGEPResultElementType(ptr_field_ptr), - ptr_field_ptr, 0, false, ""); - LLVMValueRef len_value = gen_load_untyped(g, ZigLLVMGetGEPResultElementType(len_field_ptr), - len_field_ptr, 0, false, ""); - - LLVMValueRef ptr_addr = LLVMBuildPtrToInt(g->builder, ptr_value, LLVMTypeOf(len_value), ""); - LLVMValueRef end_addr = LLVMBuildNUWAdd(g->builder, ptr_addr, len_value, ""); - const unsigned alignment_factor = ZigLLVMDataLayoutGetStackAlignment(g->target_data_ref); - LLVMValueRef align_amt = LLVMConstInt(LLVMTypeOf(end_addr), alignment_factor, false); - LLVMValueRef align_adj = LLVMBuildURem(g->builder, end_addr, align_amt, ""); - return LLVMBuildNUWSub(g->builder, end_addr, align_adj, ""); -} - -static void gen_set_stack_pointer(CodeGen *g, LLVMValueRef aligned_end_addr) { - LLVMValueRef write_register_fn_val = get_write_register_fn_val(g); - - if (g->sp_md_node == nullptr) { - Buf *sp_reg_name = buf_create_from_str(arch_stack_pointer_register_name(g->zig_target->arch)); - LLVMValueRef str_node = LLVMMDString(buf_ptr(sp_reg_name), buf_len(sp_reg_name) + 1); - g->sp_md_node = LLVMMDNode(&str_node, 1); - } - - LLVMValueRef params[] = { - g->sp_md_node, - aligned_end_addr, - }; - - LLVMBuildCall2(g->builder, LLVMGlobalGetValueType(write_register_fn_val), write_register_fn_val, params, 2, ""); -} - -static void render_async_spills(CodeGen *g) { - ZigType *fn_type = g->cur_fn->type_entry; - ZigType *import = get_scope_import(&g->cur_fn->fndef_scope->base); - - CalcLLVMFieldIndex arg_calc = {0}; - frame_index_arg_calc(g, &arg_calc, fn_type->data.fn.fn_type_id.return_type); - for (size_t var_i = 0; var_i < g->cur_fn->variable_list.length; var_i += 1) { - ZigVar *var = g->cur_fn->variable_list.at(var_i); - - if (!type_has_bits(g, var->var_type)) { - continue; - } - if (ir_get_var_is_comptime(var)) - continue; - switch (type_requires_comptime(g, var->var_type)) { - case ReqCompTimeInvalid: - zig_unreachable(); - case ReqCompTimeYes: - continue; - case ReqCompTimeNo: - break; - } - if (var->src_arg_index == SIZE_MAX) { - continue; - } - - calc_llvm_field_index_add(g, &arg_calc, var->var_type); - var->value_ref = LLVMBuildStructGEP2(g->builder, - get_llvm_type(g, get_fn_frame_type(g, g->cur_fn)), - g->cur_frame_ptr, arg_calc.field_index - 1, var->name); - if (var->decl_node) { - var->di_loc_var = ZigLLVMCreateAutoVariable(g->dbuilder, get_di_scope(g, var->parent_scope), - var->name, import->data.structure.root_struct->di_file, - node_line_onebased(var->decl_node), - get_llvm_di_type(g, var->var_type), !g->strip_debug_symbols, 0); - gen_var_debug_decl(g, var); - } - } - - ZigType *frame_type = g->cur_fn->frame_type->data.frame.locals_struct; - - for (size_t alloca_i = 0; alloca_i < g->cur_fn->alloca_gen_list.length; alloca_i += 1) { - Stage1AirInstAlloca *instruction = g->cur_fn->alloca_gen_list.at(alloca_i); - if (instruction->field_index == SIZE_MAX) - continue; - - size_t gen_index = frame_type->data.structure.fields[instruction->field_index]->gen_index; - instruction->base.llvm_value = LLVMBuildStructGEP2(g->builder, - get_llvm_type(g, get_fn_frame_type(g, g->cur_fn)), - g->cur_frame_ptr, gen_index, - instruction->name_hint); - } -} - -static void render_async_var_decls(CodeGen *g, Scope *scope) { - for (;;) { - switch (scope->id) { - case ScopeIdCImport: - zig_unreachable(); - case ScopeIdFnDef: - return; - case ScopeIdVarDecl: { - ZigVar *var = reinterpret_cast(scope)->var; - if (var->did_the_decl_codegen) { - render_decl_var(g, var); - } - } - ZIG_FALLTHROUGH; - - case ScopeIdDecls: - case ScopeIdBlock: - case ScopeIdDefer: - case ScopeIdDeferExpr: - case ScopeIdLoop: - case ScopeIdSuspend: - case ScopeIdCompTime: - case ScopeIdNoSuspend: - case ScopeIdRuntime: - case ScopeIdTypeOf: - case ScopeIdExpr: - scope = scope->parent; - continue; - } - } -} - -static LLVMValueRef gen_frame_size(CodeGen *g, LLVMValueRef fn_val) { - assert(g->need_frame_size_prefix_data); - LLVMTypeRef usize_llvm_type = g->builtin_types.entry_usize->llvm_type; - LLVMTypeRef ptr_usize_llvm_type = LLVMPointerType(usize_llvm_type, 0); - LLVMValueRef casted_fn_val = LLVMBuildBitCast(g->builder, fn_val, ptr_usize_llvm_type, ""); - LLVMValueRef negative_one = LLVMConstInt(LLVMInt32Type(), -1, true); - LLVMValueRef prefix_ptr = LLVMBuildInBoundsGEP2(g->builder, usize_llvm_type, casted_fn_val, &negative_one, 1, ""); - LLVMValueRef load_inst = LLVMBuildLoad2(g->builder, usize_llvm_type, prefix_ptr, ""); - - // Some architectures (e.g SPARCv9) has different alignment requirements between a - // function/usize pointer and also require all loads to be aligned. - // On those architectures, not explicitly setting the alignment will lead into @frameSize - // generating usize-aligned load instruction that could crash if the function pointer - // happens to be not usize-aligned. - LLVMSetAlignment(load_inst, 1); - return load_inst; -} - -static void gen_init_stack_trace(CodeGen *g, LLVMValueRef trace_field_ptr, LLVMValueRef addrs_field_ptr) { - LLVMTypeRef usize_type_ref = g->builtin_types.entry_usize->llvm_type; - LLVMValueRef zero = LLVMConstNull(usize_type_ref); - LLVMTypeRef stack_trace_llvm_ty = get_llvm_type(g, get_stack_trace_type(g)); - - LLVMValueRef index_ptr = LLVMBuildStructGEP2(g->builder, stack_trace_llvm_ty, trace_field_ptr, 0, ""); - LLVMBuildStore(g->builder, zero, index_ptr); - - LLVMValueRef addrs_slice_ptr = LLVMBuildStructGEP2(g->builder, stack_trace_llvm_ty, trace_field_ptr, 1, ""); - LLVMValueRef addrs_ptr_ptr = LLVMBuildStructGEP2(g->builder, - ZigLLVMGetGEPResultElementType(addrs_slice_ptr), - addrs_slice_ptr, slice_ptr_index, ""); - LLVMValueRef indices[] = { LLVMConstNull(usize_type_ref), LLVMConstNull(usize_type_ref) }; - LLVMValueRef trace_field_addrs_as_ptr = LLVMBuildInBoundsGEP2(g->builder, - ZigLLVMGetGEPResultElementType(addrs_field_ptr), addrs_field_ptr, indices, 2, ""); - LLVMBuildStore(g->builder, trace_field_addrs_as_ptr, addrs_ptr_ptr); - - LLVMValueRef addrs_len_ptr = LLVMBuildStructGEP2(g->builder, - ZigLLVMGetGEPResultElementType(addrs_slice_ptr), - addrs_slice_ptr, slice_len_index, ""); - LLVMBuildStore(g->builder, LLVMConstInt(usize_type_ref, stack_trace_ptr_count, false), addrs_len_ptr); -} - -static LLVMValueRef ir_render_call(CodeGen *g, Stage1Air *executable, Stage1AirInstCall *instruction) { - Error err; - - LLVMTypeRef usize_type_ref = g->builtin_types.entry_usize->llvm_type; - - LLVMValueRef fn_val; - LLVMTypeRef fn_llvm_ty; - ZigType *fn_type; - bool callee_is_async; - if (instruction->fn_entry) { - fn_val = fn_llvm_value(g, instruction->fn_entry); - fn_type = instruction->fn_entry->type_entry; - callee_is_async = fn_is_async(instruction->fn_entry); - fn_llvm_ty = LLVMGlobalGetValueType(fn_val); - } else { - assert(instruction->fn_ref); - fn_val = ir_llvm_value(g, instruction->fn_ref); - fn_type = instruction->fn_ref->value->type; - callee_is_async = fn_type->data.fn.fn_type_id.cc == CallingConventionAsync; - fn_llvm_ty = fn_type->data.fn.raw_type_ref; - } - - FnTypeId *fn_type_id = &fn_type->data.fn.fn_type_id; - - ZigType *src_return_type = fn_type_id->return_type; - bool ret_has_bits = type_has_bits(g, src_return_type); - - CallingConvention cc = fn_type->data.fn.fn_type_id.cc; - - bool first_arg_ret = ret_has_bits && want_first_arg_sret(g, fn_type_id); - bool prefix_arg_err_ret_stack = codegen_fn_has_err_ret_tracing_arg(g, fn_type_id->return_type); - bool is_var_args = fn_type_id->is_var_args; - ZigList gen_param_values = {}; - ZigList gen_param_types = {}; - LLVMValueRef result_loc = instruction->result_loc ? ir_llvm_value(g, instruction->result_loc) : nullptr; - LLVMValueRef zero = LLVMConstNull(usize_type_ref); - bool need_frame_ptr_ptr_spill = false; - ZigType *anyframe_type = nullptr; - LLVMValueRef frame_result_loc_uncasted = nullptr; - LLVMValueRef frame_result_loc; - LLVMTypeRef frame_struct_llvm_ty; - LLVMValueRef awaiter_init_val; - LLVMValueRef ret_ptr; - if (callee_is_async) { - if (instruction->new_stack == nullptr) { - if (instruction->modifier == CallModifierAsync) { - frame_result_loc = result_loc; - if (result_loc != nullptr) { - ir_assert(instruction->result_loc->value->type->id == ZigTypeIdPointer, &instruction->base); - frame_struct_llvm_ty = get_llvm_type(g, instruction->result_loc->value->type->data.pointer.child_type); - } else { - frame_struct_llvm_ty = nullptr; - } - } else { - ir_assert(instruction->frame_result_loc != nullptr, &instruction->base); - frame_result_loc_uncasted = ir_llvm_value(g, instruction->frame_result_loc); - ir_assert(instruction->fn_entry != nullptr, &instruction->base); - frame_struct_llvm_ty = get_llvm_type(g, instruction->fn_entry->frame_type); - frame_result_loc = LLVMBuildBitCast(g->builder, frame_result_loc_uncasted, - LLVMPointerType(frame_struct_llvm_ty, 0), ""); - } - } else { - if (instruction->new_stack->value->type->id == ZigTypeIdPointer && - instruction->new_stack->value->type->data.pointer.child_type->id == ZigTypeIdFnFrame) - { - frame_result_loc = ir_llvm_value(g, instruction->new_stack); - frame_struct_llvm_ty = get_llvm_type(g, instruction->new_stack->value->type->data.pointer.child_type); - } else { - LLVMValueRef frame_slice_ptr = ir_llvm_value(g, instruction->new_stack); - LLVMTypeRef frame_slice_llvm_ty = get_llvm_type(g, instruction->new_stack->value->type); - if (ir_want_runtime_safety(g, &instruction->base)) { - LLVMValueRef given_len_ptr = LLVMBuildStructGEP2(g->builder, - frame_slice_llvm_ty, frame_slice_ptr, slice_len_index, ""); - LLVMValueRef given_frame_len = LLVMBuildLoad2(g->builder, usize_type_ref, given_len_ptr, ""); - LLVMValueRef actual_frame_len = gen_frame_size(g, fn_val); - - LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "FrameSizeCheckFail"); - LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "FrameSizeCheckOk"); - - LLVMValueRef ok_bit = LLVMBuildICmp(g->builder, LLVMIntUGE, given_frame_len, actual_frame_len, ""); - LLVMBuildCondBr(g->builder, ok_bit, ok_block, fail_block); - - LLVMPositionBuilderAtEnd(g->builder, fail_block); - gen_safety_crash(g, PanicMsgIdFrameTooSmall); - - LLVMPositionBuilderAtEnd(g->builder, ok_block); - } - need_frame_ptr_ptr_spill = true; - LLVMValueRef frame_ptr_ptr = LLVMBuildStructGEP2(g->builder, frame_slice_llvm_ty, - frame_slice_ptr, slice_ptr_index, ""); - LLVMValueRef frame_ptr = LLVMBuildLoad2(g->builder, - ZigLLVMGetGEPResultElementType(frame_ptr_ptr), frame_ptr_ptr, ""); - if (instruction->fn_entry == nullptr) { - anyframe_type = get_any_frame_type(g, src_return_type); - frame_result_loc = LLVMBuildBitCast(g->builder, frame_ptr, get_llvm_type(g, anyframe_type), ""); - frame_struct_llvm_ty = anyframe_type->data.any_frame.struct_llvm_ty; - } else { - ZigType *frame_type = get_fn_frame_type(g, instruction->fn_entry); - if ((err = type_resolve(g, frame_type, ResolveStatusLLVMFull))) - codegen_report_errors_and_exit(g); - ZigType *ptr_frame_type = get_pointer_to_type(g, frame_type, false); - frame_result_loc = LLVMBuildBitCast(g->builder, frame_ptr, - get_llvm_type(g, ptr_frame_type), ""); - frame_struct_llvm_ty = get_llvm_type(g, frame_type); - } - } - } - if (instruction->modifier == CallModifierAsync) { - if (instruction->new_stack == nullptr) { - awaiter_init_val = zero; - - if (ret_has_bits) { - // Use the result location which is inside the frame if this is an async call. - ret_ptr = LLVMBuildStructGEP2(g->builder, frame_struct_llvm_ty, - frame_result_loc, frame_ret_start + 2, ""); - } - } else { - awaiter_init_val = zero; - - if (ret_has_bits) { - if (result_loc != nullptr) { - // Use the result location provided to the @asyncCall builtin - ret_ptr = result_loc; - } else { - // no result location provided to @asyncCall - use the one inside the frame. - ret_ptr = LLVMBuildStructGEP2(g->builder, frame_struct_llvm_ty, - frame_result_loc, frame_ret_start + 2, ""); - } - } - } - - // even if prefix_arg_err_ret_stack is true, let the async function do its own - // initialization. - } else { - if (instruction->modifier == CallModifierNoSuspend && !fn_is_async(g->cur_fn)) { - // Async function called as a normal function, and calling function is not async. - // This is allowed because it was called with `nosuspend` which asserts that it will - // never suspend. - awaiter_init_val = zero; - } else { - // async function called as a normal function - awaiter_init_val = LLVMBuildPtrToInt(g->builder, g->cur_frame_ptr, usize_type_ref, ""); // caller's own frame pointer - } - if (ret_has_bits) { - if (result_loc == nullptr) { - // return type is a scalar, but we still need a pointer to it. Use the async fn frame. - ret_ptr = LLVMBuildStructGEP2(g->builder, frame_struct_llvm_ty, frame_result_loc, frame_ret_start + 2, ""); - } else { - // Use the call instruction's result location. - ret_ptr = result_loc; - } - - // Store a zero in the awaiter's result ptr to indicate we do not need a copy made. - LLVMValueRef awaiter_ret_ptr = LLVMBuildStructGEP2(g->builder, frame_struct_llvm_ty, frame_result_loc, frame_ret_start + 1, ""); - LLVMValueRef zero_ptr = LLVMConstNull(ZigLLVMGetGEPResultElementType(awaiter_ret_ptr)); - LLVMBuildStore(g->builder, zero_ptr, awaiter_ret_ptr); - } - - if (prefix_arg_err_ret_stack) { - LLVMValueRef err_ret_trace_ptr_ptr = LLVMBuildStructGEP2(g->builder, frame_struct_llvm_ty, frame_result_loc, - frame_index_trace_arg(g, src_return_type) + 1, ""); - bool is_llvm_alloca; - LLVMValueRef my_err_ret_trace_val = get_cur_err_ret_trace_val(g, instruction->base.scope, - &is_llvm_alloca); - LLVMBuildStore(g->builder, my_err_ret_trace_val, err_ret_trace_ptr_ptr); - } - } - - assert(frame_result_loc != nullptr); - - LLVMValueRef fn_ptr_ptr = LLVMBuildStructGEP2(g->builder, frame_struct_llvm_ty, frame_result_loc, frame_fn_ptr_index, ""); - LLVMValueRef bitcasted_fn_val = LLVMBuildBitCast(g->builder, fn_val, - LLVMPointerTypeInContext(LLVMGetGlobalContext(), 0), ""); - LLVMBuildStore(g->builder, bitcasted_fn_val, fn_ptr_ptr); - - LLVMValueRef resume_index_ptr = LLVMBuildStructGEP2(g->builder, frame_struct_llvm_ty, frame_result_loc, frame_resume_index, ""); - LLVMBuildStore(g->builder, zero, resume_index_ptr); - - LLVMValueRef awaiter_ptr = LLVMBuildStructGEP2(g->builder, frame_struct_llvm_ty, frame_result_loc, frame_awaiter_index, ""); - LLVMBuildStore(g->builder, awaiter_init_val, awaiter_ptr); - - if (ret_has_bits) { - LLVMValueRef ret_ptr_ptr = LLVMBuildStructGEP2(g->builder, frame_struct_llvm_ty, frame_result_loc, frame_ret_start, ""); - LLVMBuildStore(g->builder, ret_ptr, ret_ptr_ptr); - } - } else if (instruction->modifier == CallModifierAsync) { - // Async call of blocking function - if (instruction->new_stack != nullptr) { - zig_panic("TODO @asyncCall of non-async function"); - } - frame_result_loc = result_loc; - if (result_loc != nullptr) { - ir_assert(instruction->result_loc->value->type->id == ZigTypeIdPointer, &instruction->base); - frame_struct_llvm_ty = get_llvm_type(g, instruction->result_loc->value->type->data.pointer.child_type); - } else { - frame_struct_llvm_ty = nullptr; - } - awaiter_init_val = LLVMConstAllOnes(usize_type_ref); - - LLVMValueRef awaiter_ptr = LLVMBuildStructGEP2(g->builder, frame_struct_llvm_ty, frame_result_loc, frame_awaiter_index, ""); - LLVMBuildStore(g->builder, awaiter_init_val, awaiter_ptr); - - if (ret_has_bits) { - ret_ptr = LLVMBuildStructGEP2(g->builder, frame_struct_llvm_ty, frame_result_loc, frame_ret_start + 2, ""); - LLVMValueRef ret_ptr_ptr = LLVMBuildStructGEP2(g->builder, frame_struct_llvm_ty, frame_result_loc, frame_ret_start, ""); - LLVMBuildStore(g->builder, ret_ptr, ret_ptr_ptr); - - if (first_arg_ret) { - gen_param_values.append(ret_ptr); - } - if (prefix_arg_err_ret_stack) { - // Set up the callee stack trace pointer pointing into the frame. - // Then we have to wire up the StackTrace pointers. - // Await is responsible for merging error return traces. - uint32_t trace_field_index_start = frame_index_trace_arg(g, src_return_type); - LLVMValueRef callee_trace_ptr_ptr = LLVMBuildStructGEP2(g->builder, frame_struct_llvm_ty, frame_result_loc, - trace_field_index_start, ""); - LLVMValueRef trace_field_ptr = LLVMBuildStructGEP2(g->builder, frame_struct_llvm_ty, frame_result_loc, - trace_field_index_start + 2, ""); - LLVMValueRef addrs_field_ptr = LLVMBuildStructGEP2(g->builder, frame_struct_llvm_ty, frame_result_loc, - trace_field_index_start + 3, ""); - - LLVMBuildStore(g->builder, trace_field_ptr, callee_trace_ptr_ptr); - - gen_init_stack_trace(g, trace_field_ptr, addrs_field_ptr); - - bool is_llvm_alloca; - gen_param_values.append(get_cur_err_ret_trace_val(g, instruction->base.scope, &is_llvm_alloca)); - } - } - } else { - if (first_arg_ret) { - gen_param_values.append(result_loc); - } - if (prefix_arg_err_ret_stack) { - bool is_llvm_alloca; - gen_param_values.append(get_cur_err_ret_trace_val(g, instruction->base.scope, &is_llvm_alloca)); - } - } - FnWalk fn_walk = {}; - fn_walk.id = FnWalkIdCall; - fn_walk.data.call.inst = instruction; - fn_walk.data.call.is_var_args = is_var_args; - fn_walk.data.call.gen_param_values = &gen_param_values; - fn_walk.data.call.gen_param_types = &gen_param_types; - walk_function_params(g, fn_type, &fn_walk); - - ZigLLVM_CallAttr call_attr; - switch (instruction->modifier) { - case CallModifierBuiltin: - case CallModifierCompileTime: - zig_unreachable(); - case CallModifierNone: - case CallModifierNoSuspend: - case CallModifierAsync: - call_attr = ZigLLVM_CallAttrAuto; - break; - case CallModifierNeverTail: - call_attr = ZigLLVM_CallAttrNeverTail; - break; - case CallModifierNeverInline: - call_attr = ZigLLVM_CallAttrNeverInline; - break; - case CallModifierAlwaysTail: - call_attr = ZigLLVM_CallAttrAlwaysTail; - break; - case CallModifierAlwaysInline: - ir_assert(instruction->fn_entry != nullptr, &instruction->base); - call_attr = ZigLLVM_CallAttrAlwaysInline; - break; - } - - ZigLLVM_CallingConv llvm_cc = get_llvm_cc(g, cc); - LLVMValueRef result; - - if (callee_is_async) { - CalcLLVMFieldIndex arg_calc_start = {0}; - frame_index_arg_calc(g, &arg_calc_start, fn_type->data.fn.fn_type_id.return_type); - - LLVMValueRef casted_frame; - LLVMTypeRef casted_frame_llvm_ty; - if (instruction->new_stack != nullptr && instruction->fn_entry == nullptr) { - // We need the frame type to be a pointer to a struct that includes the args - - // Count ahead to determine how many llvm struct fields we need. - CalcLLVMFieldIndex arg_calc = arg_calc_start; - for (size_t i = 0; i < gen_param_types.length; i += 1) { - calc_llvm_field_index_add(g, &arg_calc, gen_param_types.at(i)); - } - size_t field_count = arg_calc.field_index; - - LLVMTypeRef *field_types = heap::c_allocator.allocate_nonzero(field_count); - LLVMGetStructElementTypes(frame_struct_llvm_ty, field_types); - assert(LLVMCountStructElementTypes(frame_struct_llvm_ty) == arg_calc_start.field_index); - - arg_calc = arg_calc_start; - for (size_t arg_i = 0; arg_i < gen_param_values.length; arg_i += 1) { - CalcLLVMFieldIndex prev = arg_calc; - // Use the declared argument type and not the value one to be - // consistent with the assignment operation below. - calc_llvm_field_index_add(g, &arg_calc, gen_param_types.at(arg_i)); - field_types[arg_calc.field_index - 1] = get_llvm_type(g, gen_param_types.at(arg_i)); - if (arg_calc.field_index - prev.field_index > 1) { - // Padding field - uint32_t pad_bytes = arg_calc.offset - prev.offset - gen_param_types.at(arg_i)->abi_size; - LLVMTypeRef pad_llvm_type = LLVMArrayType(LLVMInt8Type(), pad_bytes); - field_types[arg_calc.field_index - 2] = pad_llvm_type; - } - } - LLVMTypeRef frame_with_args_type = LLVMStructType(field_types, field_count, false); - heap::c_allocator.deallocate(field_types, field_count); - LLVMTypeRef ptr_frame_with_args_type = LLVMPointerType(frame_with_args_type, 0); - - casted_frame = LLVMBuildBitCast(g->builder, frame_result_loc, ptr_frame_with_args_type, ""); - casted_frame_llvm_ty = frame_with_args_type; - } else { - casted_frame = frame_result_loc; - casted_frame_llvm_ty = frame_struct_llvm_ty; - } - - CalcLLVMFieldIndex arg_calc = arg_calc_start; - for (size_t arg_i = 0; arg_i < gen_param_values.length; arg_i += 1) { - calc_llvm_field_index_add(g, &arg_calc, gen_param_types.at(arg_i)); - LLVMValueRef arg_ptr = LLVMBuildStructGEP2(g->builder, casted_frame_llvm_ty, casted_frame, arg_calc.field_index - 1, ""); - gen_assign_raw(g, arg_ptr, get_pointer_to_type(g, gen_param_types.at(arg_i), true), - gen_param_values.at(arg_i)); - } - gen_param_types.deinit(); - - if (instruction->modifier == CallModifierAsync) { - gen_resume(g, fn_llvm_ty, fn_val, frame_result_loc, ResumeIdCall); - if (instruction->new_stack != nullptr) { - return LLVMBuildBitCast(g->builder, frame_result_loc, - get_llvm_type(g, instruction->base.value->type), ""); - } - return nullptr; - } else if (instruction->modifier == CallModifierNoSuspend && !fn_is_async(g->cur_fn)) { - gen_resume(g, fn_llvm_ty, fn_val, frame_result_loc, ResumeIdCall); - - if (ir_want_runtime_safety(g, &instruction->base)) { - LLVMValueRef awaiter_ptr = LLVMBuildStructGEP2(g->builder, frame_struct_llvm_ty, - frame_result_loc, frame_awaiter_index, ""); - LLVMValueRef all_ones = LLVMConstAllOnes(usize_type_ref); - LLVMValueRef prev_val = gen_maybe_atomic_op(g, LLVMAtomicRMWBinOpXchg, awaiter_ptr, - all_ones, LLVMAtomicOrderingRelease); - LLVMValueRef ok_val = LLVMBuildICmp(g->builder, LLVMIntEQ, prev_val, all_ones, ""); - - LLVMBasicBlockRef bad_block = LLVMAppendBasicBlock(g->cur_fn_val, "NoSuspendPanic"); - LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "NoSuspendOk"); - LLVMBuildCondBr(g->builder, ok_val, ok_block, bad_block); - - // The async function suspended, but this nosuspend call asserted it wouldn't. - LLVMPositionBuilderAtEnd(g->builder, bad_block); - gen_safety_crash(g, PanicMsgIdBadNoSuspendCall); - - LLVMPositionBuilderAtEnd(g->builder, ok_block); - } - - ZigType *result_type = instruction->base.value->type; - ZigType *ptr_result_type = get_pointer_to_type(g, result_type, true); - return gen_await_early_return(g, &instruction->base, - frame_struct_llvm_ty, frame_result_loc, - result_type, ptr_result_type, result_loc, true); - } else { - ZigType *ptr_result_type = get_pointer_to_type(g, src_return_type, true); - - LLVMBasicBlockRef call_bb = gen_suspend_begin(g, "CallResume"); - - LLVMValueRef call_inst = gen_resume(g, fn_llvm_ty, fn_val, frame_result_loc, ResumeIdCall); - set_tail_call_if_appropriate(g, call_inst); - LLVMBuildRetVoid(g->builder); - - LLVMPositionBuilderAtEnd(g->builder, call_bb); - gen_assert_resume_id(g, &instruction->base, ResumeIdReturn, PanicMsgIdResumedAnAwaitingFn, nullptr); - render_async_var_decls(g, instruction->base.scope); - - if (!type_has_bits(g, src_return_type)) - return nullptr; - - if (result_loc != nullptr) { - if (instruction->result_loc->id == Stage1AirInstIdReturnPtr) { - instruction->base.spill = nullptr; - return g->cur_ret_ptr; - } else { - return get_handle_value(g, result_loc, src_return_type, ptr_result_type); - } - } - - if (need_frame_ptr_ptr_spill) { - LLVMValueRef frame_slice_ptr = ir_llvm_value(g, instruction->new_stack); - LLVMValueRef frame_ptr_ptr = LLVMBuildStructGEP2(g->builder, - get_llvm_type(g, instruction->new_stack->value->type), - frame_slice_ptr, slice_ptr_index, ""); - frame_result_loc_uncasted = LLVMBuildLoad2(g->builder, - ZigLLVMGetGEPResultElementType(frame_ptr_ptr), frame_ptr_ptr, ""); - } - if (frame_result_loc_uncasted != nullptr) { - if (instruction->fn_entry != nullptr) { - frame_struct_llvm_ty = get_llvm_type(g, instruction->fn_entry->frame_type); - frame_result_loc = LLVMBuildBitCast(g->builder, frame_result_loc_uncasted, - LLVMPointerType(frame_struct_llvm_ty, 0), ""); - } else { - frame_result_loc = LLVMBuildBitCast(g->builder, frame_result_loc_uncasted, - get_llvm_type(g, anyframe_type), ""); - frame_struct_llvm_ty = anyframe_type->data.any_frame.struct_llvm_ty; - } - } - - LLVMValueRef result_ptr = LLVMBuildStructGEP2(g->builder, frame_struct_llvm_ty, - frame_result_loc, frame_ret_start + 2, ""); - return LLVMBuildLoad2(g->builder, get_llvm_type(g, src_return_type), result_ptr, ""); - } - } else { - gen_param_types.deinit(); - } - - if (instruction->new_stack == nullptr || instruction->is_async_call_builtin) { - result = ZigLLVMBuildCall(g->builder, fn_llvm_ty, fn_val, - gen_param_values.items, (unsigned)gen_param_values.length, llvm_cc, call_attr, ""); - } else if (instruction->modifier == CallModifierAsync) { - zig_panic("TODO @asyncCall of non-async function"); - } else { - LLVMValueRef new_stack_addr = get_new_stack_addr(g, - get_llvm_type(g, instruction->new_stack->value->type), - ir_llvm_value(g, instruction->new_stack)); - LLVMValueRef old_stack_ref; - if (src_return_type->id != ZigTypeIdUnreachable) { - LLVMValueRef stacksave_fn_val = get_stacksave_fn_val(g); - old_stack_ref = LLVMBuildCall2(g->builder, LLVMGlobalGetValueType(stacksave_fn_val), stacksave_fn_val, nullptr, 0, ""); - } - gen_set_stack_pointer(g, new_stack_addr); - result = ZigLLVMBuildCall(g->builder, fn_llvm_ty, fn_val, - gen_param_values.items, (unsigned)gen_param_values.length, llvm_cc, call_attr, ""); - if (src_return_type->id != ZigTypeIdUnreachable) { - LLVMValueRef stackrestore_fn_val = get_stackrestore_fn_val(g); - LLVMBuildCall2(g->builder, LLVMGlobalGetValueType(stackrestore_fn_val), stackrestore_fn_val, &old_stack_ref, 1, ""); - } - } - - if (src_return_type->id == ZigTypeIdUnreachable) { - return LLVMBuildUnreachable(g->builder); - } else if (!ret_has_bits) { - return nullptr; - } else if (first_arg_ret) { - ZigLLVMSetCallSret(result, get_llvm_type(g, src_return_type)); - return result_loc; - } else if (fn_returns_c_abi_small_struct(fn_type_id)) { - LLVMTypeRef abi_type = get_llvm_c_abi_type(g, src_return_type); - LLVMTypeRef abi_type_ptr = LLVMPointerType(abi_type, 0); - LLVMValueRef bitcast = LLVMBuildBitCast(g->builder, result_loc, abi_type_ptr, ""); - LLVMBuildStore(g->builder, result, bitcast); - return result_loc; - } else if (handle_is_ptr(g, src_return_type)) { - LLVMValueRef store_instr = LLVMBuildStore(g->builder, result, result_loc); - LLVMSetAlignment(store_instr, get_ptr_align(g, instruction->result_loc->value->type)); - return result_loc; - } else if (!callee_is_async && instruction->modifier == CallModifierAsync) { - LLVMBuildStore(g->builder, result, ret_ptr); - return result_loc; - } else { - return result; - } -} - -static LLVMValueRef ir_render_struct_field_ptr(CodeGen *g, Stage1Air *executable, - Stage1AirInstStructFieldPtr *instruction) -{ - Error err; - - if (instruction->base.value->special != ConstValSpecialRuntime) - return nullptr; - - LLVMValueRef struct_ptr = ir_llvm_value(g, instruction->struct_ptr); - // not necessarily a pointer. could be ZigTypeIdStruct - ZigType *struct_ptr_type = instruction->struct_ptr->value->type; - TypeStructField *field = instruction->field; - - if (!type_has_bits(g, field->type_entry)) - return nullptr; - - if (struct_ptr_type->id == ZigTypeIdPointer && - struct_ptr_type->data.pointer.host_int_bytes != 0) - { - return struct_ptr; - } - - ZigType *struct_type; - if (struct_ptr_type->id == ZigTypeIdPointer) { - if (struct_ptr_type->data.pointer.inferred_struct_field != nullptr) { - struct_type = struct_ptr_type->data.pointer.inferred_struct_field->inferred_struct_type; - } else { - struct_type = struct_ptr_type->data.pointer.child_type; - } - } else { - struct_type = struct_ptr_type; - } - - if ((err = type_resolve(g, struct_type, ResolveStatusLLVMFull))) - codegen_report_errors_and_exit(g); - - ir_assert(field->gen_index != SIZE_MAX, &instruction->base); - LLVMValueRef field_ptr_val = LLVMBuildStructGEP2(g->builder, - get_llvm_type(g, struct_type), struct_ptr, (unsigned)field->gen_index, ""); - ZigType *res_type = instruction->base.value->type; - ir_assert(res_type->id == ZigTypeIdPointer, &instruction->base); - if (res_type->data.pointer.host_int_bytes != 0) { - // We generate packed structs with get_llvm_type_of_n_bytes, which is - // u8 for 1 byte or [n]u8 for multiple bytes. But the pointer to the type - // is supposed to be a pointer to the integer. So we bitcast it here. - LLVMTypeRef int_elem_type = LLVMIntType(8*res_type->data.pointer.host_int_bytes); - LLVMTypeRef integer_ptr_type = LLVMPointerType(int_elem_type, 0); - return LLVMBuildBitCast(g->builder, field_ptr_val, integer_ptr_type, ""); - } - return field_ptr_val; -} - -static LLVMValueRef ir_render_union_field_ptr(CodeGen *g, Stage1Air *executable, - Stage1AirInstUnionFieldPtr *instruction) -{ - if (instruction->base.value->special != ConstValSpecialRuntime) - return nullptr; - - ZigType *union_ptr_type = instruction->union_ptr->value->type; - assert(union_ptr_type->id == ZigTypeIdPointer); - ZigType *union_type = union_ptr_type->data.pointer.child_type; - assert(union_type->id == ZigTypeIdUnion); - - TypeUnionField *field = instruction->field; - - if (!type_has_bits(g, field->type_entry)) { - ZigType *tag_type = union_type->data.unionation.tag_type; - if (!instruction->initializing || tag_type == nullptr || !type_has_bits(g, tag_type)) - return nullptr; - - // The field has no bits but we still have to change the discriminant - // value here - LLVMValueRef union_ptr = ir_llvm_value(g, instruction->union_ptr); - - LLVMTypeRef tag_type_ref = get_llvm_type(g, tag_type); - LLVMValueRef tag_field_ptr = nullptr; - if (union_type->data.unionation.gen_field_count == 0) { - assert(union_type->data.unionation.gen_tag_index == SIZE_MAX); - // The whole union is collapsed into the discriminant - tag_field_ptr = LLVMBuildBitCast(g->builder, union_ptr, - LLVMPointerType(tag_type_ref, 0), ""); - } else { - assert(union_type->data.unionation.gen_tag_index != SIZE_MAX); - tag_field_ptr = LLVMBuildStructGEP2(g->builder, - get_llvm_type(g, union_type), - union_ptr, union_type->data.unionation.gen_tag_index, ""); - } - - LLVMValueRef tag_value = bigint_to_llvm_const(tag_type_ref, - &field->enum_field->value); - assert(tag_field_ptr != nullptr); - gen_store_untyped(g, tag_value, tag_field_ptr, 0, false); - - return nullptr; - } - - LLVMValueRef union_ptr = ir_llvm_value(g, instruction->union_ptr); - LLVMTypeRef field_type_ref = LLVMPointerType(get_llvm_type(g, field->type_entry), 0); - - if (union_type->data.unionation.gen_tag_index == SIZE_MAX) { - LLVMValueRef union_field_ptr = LLVMBuildStructGEP2(g->builder, - get_llvm_type(g, union_type), union_ptr, 0, ""); - LLVMValueRef bitcasted_union_field_ptr = LLVMBuildBitCast(g->builder, union_field_ptr, field_type_ref, ""); - return bitcasted_union_field_ptr; - } - - if (instruction->initializing) { - LLVMValueRef tag_field_ptr = LLVMBuildStructGEP2(g->builder, - get_llvm_type(g, union_type), - union_ptr, union_type->data.unionation.gen_tag_index, ""); - LLVMValueRef tag_value = bigint_to_llvm_const(get_llvm_type(g, union_type->data.unionation.tag_type), - &field->enum_field->value); - gen_store_untyped(g, tag_value, tag_field_ptr, 0, false); - } else if (instruction->safety_check_on && ir_want_runtime_safety(g, &instruction->base)) { - LLVMValueRef tag_field_ptr = LLVMBuildStructGEP2(g->builder, - get_llvm_type(g, union_type), - union_ptr, union_type->data.unionation.gen_tag_index, ""); - LLVMValueRef tag_value = gen_load_untyped(g, ZigLLVMGetGEPResultElementType(tag_field_ptr), - tag_field_ptr, 0, false, ""); - - - LLVMValueRef expected_tag_value = bigint_to_llvm_const(get_llvm_type(g, union_type->data.unionation.tag_type), - &field->enum_field->value); - LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "UnionCheckOk"); - LLVMBasicBlockRef bad_block = LLVMAppendBasicBlock(g->cur_fn_val, "UnionCheckFail"); - LLVMValueRef ok_val = LLVMBuildICmp(g->builder, LLVMIntEQ, tag_value, expected_tag_value, ""); - LLVMBuildCondBr(g->builder, ok_val, ok_block, bad_block); - - LLVMPositionBuilderAtEnd(g->builder, bad_block); - gen_safety_crash(g, PanicMsgIdBadUnionField); - - LLVMPositionBuilderAtEnd(g->builder, ok_block); - } - - LLVMValueRef union_field_ptr = LLVMBuildStructGEP2(g->builder, get_llvm_type(g, union_type), - union_ptr, union_type->data.unionation.gen_union_index, ""); - LLVMValueRef bitcasted_union_field_ptr = LLVMBuildBitCast(g->builder, union_field_ptr, field_type_ref, ""); - return bitcasted_union_field_ptr; -} - -static size_t find_asm_index(CodeGen *g, AstNode *node, AsmToken *tok, Buf *src_template) { - const char *ptr = buf_ptr(src_template) + tok->start + 2; - size_t len = tok->end - tok->start - 2; - size_t result = 0; - for (size_t i = 0; i < node->data.asm_expr.output_list.length; i += 1, result += 1) { - AsmOutput *asm_output = node->data.asm_expr.output_list.at(i); - if (buf_eql_mem(asm_output->asm_symbolic_name, ptr, len)) { - return result; - } - } - for (size_t i = 0; i < node->data.asm_expr.input_list.length; i += 1, result += 1) { - AsmInput *asm_input = node->data.asm_expr.input_list.at(i); - if (buf_eql_mem(asm_input->asm_symbolic_name, ptr, len)) { - return result; - } - } - return SIZE_MAX; -} - -static LLVMValueRef ir_render_asm_gen(CodeGen *g, Stage1Air *executable, Stage1AirInstAsm *instruction) { - AstNode *asm_node = instruction->base.source_node; - assert(asm_node->type == NodeTypeAsmExpr); - AstNodeAsmExpr *asm_expr = &asm_node->data.asm_expr; - - Buf *src_template = instruction->asm_template; - - Buf llvm_template = BUF_INIT; - buf_resize(&llvm_template, 0); - - for (size_t token_i = 0; token_i < instruction->token_list_len; token_i += 1) { - AsmToken *asm_token = &instruction->token_list[token_i]; - switch (asm_token->id) { - case AsmTokenIdTemplate: - for (size_t offset = asm_token->start; offset < asm_token->end; offset += 1) { - uint8_t c = *((uint8_t*)(buf_ptr(src_template) + offset)); - if (c == '$') { - buf_append_str(&llvm_template, "$$"); - } else { - buf_append_char(&llvm_template, c); - } - } - break; - case AsmTokenIdPercent: - buf_append_char(&llvm_template, '%'); - break; - case AsmTokenIdVar: - { - size_t index = find_asm_index(g, asm_node, asm_token, src_template); - assert(index < SIZE_MAX); - buf_appendf(&llvm_template, "$%" ZIG_PRI_usize "", index); - break; - } - case AsmTokenIdUniqueId: - buf_append_str(&llvm_template, "${:uid}"); - break; - } - } - - Buf constraint_buf = BUF_INIT; - buf_resize(&constraint_buf, 0); - - assert(instruction->return_count == 0 || instruction->return_count == 1); - - size_t total_constraint_count = asm_expr->output_list.length + - asm_expr->input_list.length + - asm_expr->clobber_list.length; - size_t input_and_output_count = asm_expr->output_list.length + - asm_expr->input_list.length - - instruction->return_count; - size_t total_index = 0; - size_t param_index = 0; - LLVMTypeRef *param_types = heap::c_allocator.allocate(input_and_output_count); - LLVMValueRef *param_values = heap::c_allocator.allocate(input_and_output_count); - LLVMTypeRef *param_needs_attr = heap::c_allocator.allocate(input_and_output_count); - for (size_t i = 0; i < asm_expr->output_list.length; i += 1, total_index += 1) { - AsmOutput *asm_output = asm_expr->output_list.at(i); - bool is_return = (asm_output->return_type != nullptr); - assert(*buf_ptr(asm_output->constraint) == '='); - // LLVM uses commas internally to separate different constraints, - // alternative constraints are achieved with pipes. - // We still allow the user to use commas in a way that is similar - // to GCC's inline assembly. - // http://llvm.org/docs/LangRef.html#constraint-codes - buf_replace(asm_output->constraint, ',', '|'); - - if (is_return) { - buf_appendf(&constraint_buf, "=%s", buf_ptr(asm_output->constraint) + 1); - } else { - buf_appendf(&constraint_buf, "=*%s", buf_ptr(asm_output->constraint) + 1); - ZigVar *variable = instruction->output_vars[i]; - param_needs_attr[param_index] = get_llvm_type(g, variable->var_type); - } - if (total_index + 1 < total_constraint_count) { - buf_append_char(&constraint_buf, ','); - } - - if (!is_return) { - ZigVar *variable = instruction->output_vars[i]; - assert(variable); - param_types[param_index] = LLVMTypeOf(variable->value_ref); - param_values[param_index] = variable->value_ref; - param_index += 1; - } - } - for (size_t i = 0; i < asm_expr->input_list.length; i += 1, total_index += 1, param_index += 1) { - AsmInput *asm_input = asm_expr->input_list.at(i); - buf_replace(asm_input->constraint, ',', '|'); - Stage1AirInst *ir_input = instruction->input_list[i]; - buf_append_buf(&constraint_buf, asm_input->constraint); - if (total_index + 1 < total_constraint_count) { - buf_append_char(&constraint_buf, ','); - } - - ZigType *const type = ir_input->value->type; - LLVMTypeRef type_ref = get_llvm_type(g, type); - LLVMValueRef value_ref = ir_llvm_value(g, ir_input); - LLVMTypeRef elem_type_ref = nullptr; - // Handle integers of non pot bitsize by widening them. - if (type->id == ZigTypeIdInt) { - const size_t bitsize = type->data.integral.bit_count; - if (bitsize < 8 || !is_power_of_2(bitsize)) { - const bool is_signed = type->data.integral.is_signed; - const size_t wider_bitsize = bitsize < 8 ? 8 : round_to_next_power_of_2(bitsize); - ZigType *const wider_type = get_int_type(g, is_signed, wider_bitsize); - type_ref = get_llvm_type(g, wider_type); - value_ref = gen_widen_or_shorten(g, false, type, wider_type, value_ref); - } - } else if (handle_is_ptr(g, type)) { - elem_type_ref = type_ref; - ZigType *gen_type = get_pointer_to_type(g, type, true); - type_ref = get_llvm_type(g, gen_type); - } - - param_types[param_index] = type_ref; - param_values[param_index] = value_ref; - // In the case of indirect inputs, LLVM requires the callsite to have an elementtype() attribute. - if (buf_ptr(asm_input->constraint)[0] == '*') { - param_needs_attr[param_index] = elem_type_ref ? elem_type_ref : - get_llvm_type(g, type->data.pointer.child_type); - } - } - for (size_t i = 0; i < asm_expr->clobber_list.length; i += 1, total_index += 1) { - Buf *clobber_buf = asm_expr->clobber_list.at(i); - buf_appendf(&constraint_buf, "~{%s}", buf_ptr(clobber_buf)); - if (total_index + 1 < total_constraint_count) { - buf_append_char(&constraint_buf, ','); - } - } - - // Add some architecture-specific clobbers. - const char *arch_clobbers = nullptr; - switch (g->zig_target->arch) { - case ZigLLVM_x86: - case ZigLLVM_x86_64: - arch_clobbers = "~{dirflag},~{fpsr},~{flags}"; - break; - case ZigLLVM_mips: - case ZigLLVM_mipsel: - case ZigLLVM_mips64: - case ZigLLVM_mips64el: - arch_clobbers = "~{$1}"; - break; - default: - break; - } - - if (arch_clobbers != nullptr) { - if (buf_len(&constraint_buf)) - buf_append_char(&constraint_buf, ','); - buf_append_str(&constraint_buf, arch_clobbers); - } - - LLVMTypeRef ret_type; - if (instruction->return_count == 0) { - ret_type = LLVMVoidType(); - } else { - ret_type = get_llvm_type(g, instruction->base.value->type); - } - LLVMTypeRef function_type = LLVMFunctionType(ret_type, param_types, (unsigned)input_and_output_count, false); - - bool is_volatile = instruction->has_side_effects || (asm_expr->output_list.length == 0); - LLVMValueRef asm_fn = LLVMGetInlineAsm(function_type, buf_ptr(&llvm_template), buf_len(&llvm_template), - buf_ptr(&constraint_buf), buf_len(&constraint_buf), is_volatile, false, LLVMInlineAsmDialectATT, false); - - LLVMValueRef built_call = LLVMBuildCall2(g->builder, function_type, - asm_fn, param_values, (unsigned)input_and_output_count, ""); - - for (size_t i = 0; i < input_and_output_count; i += 1) { - if (param_needs_attr[i] != nullptr) { - LLVMTypeRef elem_ty = param_needs_attr[i]; - ZigLLVMSetCallElemTypeAttr(built_call, i, elem_ty); - } - } - - - - heap::c_allocator.deallocate(param_types, input_and_output_count); - heap::c_allocator.deallocate(param_values, input_and_output_count); - heap::c_allocator.deallocate(param_needs_attr, input_and_output_count); - return built_call; -} - -static LLVMValueRef gen_non_null_bit(CodeGen *g, ZigType *maybe_type, LLVMValueRef maybe_handle) { - assert(maybe_type->id == ZigTypeIdOptional || - (maybe_type->id == ZigTypeIdPointer && maybe_type->data.pointer.allow_zero)); - - ZigType *child_type = maybe_type->data.maybe.child_type; - if (!type_has_bits(g, child_type)) - return maybe_handle; - - bool is_scalar = !handle_is_ptr(g, maybe_type); - if (is_scalar) - return LLVMBuildICmp(g->builder, LLVMIntNE, maybe_handle, LLVMConstNull(get_llvm_type(g, maybe_type)), ""); - - LLVMValueRef maybe_field_ptr = LLVMBuildStructGEP2(g->builder, - get_llvm_type(g, maybe_type), maybe_handle, maybe_null_index, ""); - return gen_load_untyped(g, ZigLLVMGetGEPResultElementType(maybe_field_ptr), maybe_field_ptr, 0, false, ""); -} - -static LLVMValueRef ir_render_test_non_null(CodeGen *g, Stage1Air *executable, - Stage1AirInstTestNonNull *instruction) -{ - return gen_non_null_bit(g, instruction->value->value->type, ir_llvm_value(g, instruction->value)); -} - -static LLVMValueRef ir_render_optional_unwrap_ptr(CodeGen *g, Stage1Air *executable, - Stage1AirInstOptionalUnwrapPtr *instruction) -{ - if (instruction->base.value->special != ConstValSpecialRuntime) - return nullptr; - - ZigType *ptr_type = instruction->base_ptr->value->type; - assert(ptr_type->id == ZigTypeIdPointer); - ZigType *maybe_type = ptr_type->data.pointer.child_type; - assert(maybe_type->id == ZigTypeIdOptional); - ZigType *child_type = maybe_type->data.maybe.child_type; - LLVMValueRef base_ptr = ir_llvm_value(g, instruction->base_ptr); - if (instruction->safety_check_on && ir_want_runtime_safety(g, &instruction->base)) { - LLVMValueRef maybe_handle = get_handle_value(g, base_ptr, maybe_type, ptr_type); - LLVMValueRef non_null_bit = gen_non_null_bit(g, maybe_type, maybe_handle); - LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "UnwrapOptionalFail"); - LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "UnwrapOptionalOk"); - LLVMBuildCondBr(g->builder, non_null_bit, ok_block, fail_block); - - LLVMPositionBuilderAtEnd(g->builder, fail_block); - gen_safety_crash(g, PanicMsgIdUnwrapOptionalFail); - - LLVMPositionBuilderAtEnd(g->builder, ok_block); - } - if (!type_has_bits(g, child_type)) { - if (instruction->initializing) { - LLVMValueRef non_null_bit = LLVMConstInt(LLVMInt1Type(), 1, false); - gen_store_untyped(g, non_null_bit, base_ptr, 0, false); - } - return nullptr; - } else { - bool is_scalar = !handle_is_ptr(g, maybe_type); - if (is_scalar) { - return base_ptr; - } else { - LLVMValueRef optional_struct_ref = get_handle_value(g, base_ptr, maybe_type, ptr_type); - if (instruction->initializing) { - LLVMValueRef non_null_bit_ptr = LLVMBuildStructGEP2(g->builder, - get_llvm_type(g, maybe_type), optional_struct_ref, maybe_null_index, ""); - LLVMValueRef non_null_bit = LLVMConstInt(LLVMInt1Type(), 1, false); - gen_store_untyped(g, non_null_bit, non_null_bit_ptr, 0, false); - } - return LLVMBuildStructGEP2(g->builder, - get_llvm_type(g, maybe_type), optional_struct_ref, maybe_child_index, ""); - } - } -} - -static LLVMValueRef get_int_builtin_fn(CodeGen *g, ZigType *expr_type, BuiltinFnId fn_id) { - bool is_vector = expr_type->id == ZigTypeIdVector; - ZigType *int_type = is_vector ? expr_type->data.vector.elem_type : expr_type; - assert(int_type->id == ZigTypeIdInt); - uint32_t vector_len = is_vector ? expr_type->data.vector.len : 0; - ZigLLVMFnKey key = {}; - const char *fn_name; - uint32_t n_args; - if (fn_id == BuiltinFnIdCtz) { - fn_name = "cttz"; - n_args = 2; - key.id = ZigLLVMFnIdCtz; - key.data.ctz.bit_count = (uint32_t)int_type->data.integral.bit_count; - key.data.ctz.vector_len = vector_len; - } else if (fn_id == BuiltinFnIdClz) { - fn_name = "ctlz"; - n_args = 2; - key.id = ZigLLVMFnIdClz; - key.data.clz.bit_count = (uint32_t)int_type->data.integral.bit_count; - key.data.clz.vector_len = vector_len; - } else if (fn_id == BuiltinFnIdPopCount) { - fn_name = "ctpop"; - n_args = 1; - key.id = ZigLLVMFnIdPopCount; - key.data.pop_count.bit_count = (uint32_t)int_type->data.integral.bit_count; - key.data.pop_count.vector_len = vector_len; - } else if (fn_id == BuiltinFnIdBswap) { - fn_name = "bswap"; - n_args = 1; - key.id = ZigLLVMFnIdBswap; - key.data.bswap.bit_count = (uint32_t)int_type->data.integral.bit_count; - key.data.bswap.vector_len = vector_len; - } else if (fn_id == BuiltinFnIdBitReverse) { - fn_name = "bitreverse"; - n_args = 1; - key.id = ZigLLVMFnIdBitReverse; - key.data.bit_reverse.bit_count = (uint32_t)int_type->data.integral.bit_count; - key.data.bit_reverse.vector_len = vector_len; - } else { - zig_unreachable(); - } - - auto existing_entry = g->llvm_fn_table.maybe_get(key); - if (existing_entry) - return existing_entry->value; - - char llvm_name[64]; - if (is_vector) - snprintf(llvm_name, sizeof(llvm_name), "llvm.%s.v%" PRIu32 "i%" PRIu32, fn_name, vector_len, int_type->data.integral.bit_count); - else - snprintf(llvm_name, sizeof(llvm_name), "llvm.%s.i%" PRIu32, fn_name, int_type->data.integral.bit_count); - LLVMTypeRef param_types[] = { - get_llvm_type(g, expr_type), - LLVMInt1Type(), - }; - LLVMTypeRef fn_type = LLVMFunctionType(get_llvm_type(g, expr_type), param_types, n_args, false); - LLVMValueRef fn_val = LLVMAddFunction(g->module, llvm_name, fn_type); - assert(LLVMGetIntrinsicID(fn_val)); - - g->llvm_fn_table.put(key, fn_val); - - return fn_val; -} - -static LLVMValueRef ir_render_clz(CodeGen *g, Stage1Air *executable, Stage1AirInstClz *instruction) { - ZigType *int_type = instruction->op->value->type; - LLVMValueRef fn_val = get_int_builtin_fn(g, int_type, BuiltinFnIdClz); - LLVMValueRef operand = ir_llvm_value(g, instruction->op); - LLVMValueRef params[] { - operand, - LLVMConstNull(LLVMInt1Type()), - }; - LLVMValueRef wrong_size_int = LLVMBuildCall2(g->builder, LLVMGlobalGetValueType(fn_val), fn_val, params, 2, ""); - return gen_widen_or_shorten(g, false, int_type, instruction->base.value->type, wrong_size_int); -} - -static LLVMValueRef ir_render_ctz(CodeGen *g, Stage1Air *executable, Stage1AirInstCtz *instruction) { - ZigType *int_type = instruction->op->value->type; - LLVMValueRef fn_val = get_int_builtin_fn(g, int_type, BuiltinFnIdCtz); - LLVMValueRef operand = ir_llvm_value(g, instruction->op); - LLVMValueRef params[] { - operand, - LLVMConstNull(LLVMInt1Type()), - }; - LLVMValueRef wrong_size_int = LLVMBuildCall2(g->builder, LLVMGlobalGetValueType(fn_val), fn_val, params, 2, ""); - return gen_widen_or_shorten(g, false, int_type, instruction->base.value->type, wrong_size_int); -} - -static LLVMValueRef ir_render_shuffle_vector(CodeGen *g, Stage1Air *executable, Stage1AirInstShuffleVector *instruction) { - uint64_t len_a = instruction->a->value->type->data.vector.len; - uint64_t len_mask = instruction->mask->value->type->data.vector.len; - - // LLVM uses integers larger than the length of the first array to - // index into the second array. This was deemed unnecessarily fragile - // when changing code, so Zig uses negative numbers to index the - // second vector. These start at -1 and go down, and are easiest to use - // with the ~ operator. Here we convert between the two formats. - Stage1AirInst *mask = instruction->mask; - LLVMValueRef *values = heap::c_allocator.allocate(len_mask); - for (uint64_t i = 0; i < len_mask; i++) { - if (mask->value->data.x_array.data.s_none.elements[i].special == ConstValSpecialUndef) { - values[i] = LLVMGetUndef(LLVMInt32Type()); - } else { - int32_t v = bigint_as_signed(&mask->value->data.x_array.data.s_none.elements[i].data.x_bigint); - uint32_t index_val = (v >= 0) ? (uint32_t)v : (uint32_t)~v + (uint32_t)len_a; - values[i] = LLVMConstInt(LLVMInt32Type(), index_val, false); - } - } - - LLVMValueRef llvm_mask_value = LLVMConstVector(values, len_mask); - heap::c_allocator.deallocate(values, len_mask); - - return LLVMBuildShuffleVector(g->builder, - ir_llvm_value(g, instruction->a), - ir_llvm_value(g, instruction->b), - llvm_mask_value, ""); -} - -static LLVMValueRef ir_render_select(CodeGen *g, Stage1Air *executable, Stage1AirInstSelect *instruction) { - LLVMValueRef pred = ir_llvm_value(g, instruction->pred); - LLVMValueRef a = ir_llvm_value(g, instruction->a); - LLVMValueRef b = ir_llvm_value(g, instruction->b); - return LLVMBuildSelect(g->builder, pred, a, b, ""); -} - -static LLVMValueRef ir_render_splat(CodeGen *g, Stage1Air *executable, Stage1AirInstSplat *instruction) { - ZigType *result_type = instruction->base.value->type; - ir_assert(result_type->id == ZigTypeIdVector, &instruction->base); - uint32_t len = result_type->data.vector.len; - LLVMTypeRef op_llvm_type = LLVMVectorType(get_llvm_type(g, instruction->scalar->value->type), 1); - LLVMTypeRef mask_llvm_type = LLVMVectorType(LLVMInt32Type(), len); - LLVMValueRef undef_vector = LLVMGetUndef(op_llvm_type); - LLVMValueRef op_vector = LLVMBuildInsertElement(g->builder, undef_vector, - ir_llvm_value(g, instruction->scalar), LLVMConstInt(LLVMInt32Type(), 0, false), ""); - return LLVMBuildShuffleVector(g->builder, op_vector, undef_vector, LLVMConstNull(mask_llvm_type), ""); -} - -static LLVMValueRef ir_render_pop_count(CodeGen *g, Stage1Air *executable, Stage1AirInstPopCount *instruction) { - ZigType *int_type = instruction->op->value->type; - LLVMValueRef fn_val = get_int_builtin_fn(g, int_type, BuiltinFnIdPopCount); - LLVMValueRef operand = ir_llvm_value(g, instruction->op); - LLVMValueRef wrong_size_int = LLVMBuildCall2(g->builder, LLVMGlobalGetValueType(fn_val), fn_val, &operand, 1, ""); - return gen_widen_or_shorten(g, false, int_type, instruction->base.value->type, wrong_size_int); -} - -static LLVMValueRef ir_render_switch_br(CodeGen *g, Stage1Air *executable, Stage1AirInstSwitchBr *instruction) { - ZigType *target_type = instruction->target_value->value->type; - LLVMBasicBlockRef else_block = instruction->else_block->llvm_block; - - LLVMValueRef target_value = ir_llvm_value(g, instruction->target_value); - if (target_type->id == ZigTypeIdPointer) { - const ZigType *usize = g->builtin_types.entry_usize; - target_value = LLVMBuildPtrToInt(g->builder, target_value, usize->llvm_type, ""); - } - - LLVMValueRef switch_instr = LLVMBuildSwitch(g->builder, target_value, else_block, - (unsigned)instruction->case_count); - - for (size_t i = 0; i < instruction->case_count; i += 1) { - Stage1AirInstSwitchBrCase *this_case = &instruction->cases[i]; - - LLVMValueRef case_value = ir_llvm_value(g, this_case->value); - if (target_type->id == ZigTypeIdPointer) { - const ZigType *usize = g->builtin_types.entry_usize; - case_value = LLVMBuildPtrToInt(g->builder, case_value, usize->llvm_type, ""); - } - - LLVMAddCase(switch_instr, case_value, this_case->block->llvm_block); - } - - return nullptr; -} - -static LLVMValueRef ir_render_phi(CodeGen *g, Stage1Air *executable, Stage1AirInstPhi *instruction) { - if (!type_has_bits(g, instruction->base.value->type)) - return nullptr; - - LLVMTypeRef phi_type; - if (handle_is_ptr(g, instruction->base.value->type)) { - phi_type = LLVMPointerType(get_llvm_type(g,instruction->base.value->type), 0); - } else { - phi_type = get_llvm_type(g, instruction->base.value->type); - } - - LLVMValueRef phi = LLVMBuildPhi(g->builder, phi_type, ""); - LLVMValueRef *incoming_values = heap::c_allocator.allocate(instruction->incoming_count); - LLVMBasicBlockRef *incoming_blocks = heap::c_allocator.allocate(instruction->incoming_count); - for (size_t i = 0; i < instruction->incoming_count; i += 1) { - incoming_values[i] = ir_llvm_value(g, instruction->incoming_values[i]); - incoming_blocks[i] = instruction->incoming_blocks[i]->llvm_exit_block; - } - LLVMAddIncoming(phi, incoming_values, incoming_blocks, (unsigned)instruction->incoming_count); - heap::c_allocator.deallocate(incoming_values, instruction->incoming_count); - heap::c_allocator.deallocate(incoming_blocks, instruction->incoming_count); - return phi; -} - -static LLVMValueRef ir_render_ref(CodeGen *g, Stage1Air *executable, Stage1AirInstRef *instruction) { - if (!type_has_bits(g, instruction->base.value->type)) { - return nullptr; - } - if (instruction->operand->id == Stage1AirInstIdCall) { - Stage1AirInstCall *call = reinterpret_cast(instruction->operand); - if (call->result_loc != nullptr) { - return ir_llvm_value(g, call->result_loc); - } - } - LLVMValueRef value = ir_llvm_value(g, instruction->operand); - if (handle_is_ptr(g, instruction->operand->value->type)) { - return value; - } else { - LLVMValueRef result_loc = ir_llvm_value(g, instruction->result_loc); - gen_store_untyped(g, value, result_loc, 0, false); - return result_loc; - } -} - -static LLVMValueRef ir_render_err_name(CodeGen *g, Stage1Air *executable, Stage1AirInstErrName *instruction) { - assert(g->generate_error_name_table); - assert(g->errors_by_index.length > 0); - - LLVMValueRef err_val = ir_llvm_value(g, instruction->value); - if (ir_want_runtime_safety(g, &instruction->base)) { - LLVMValueRef zero = LLVMConstNull(LLVMTypeOf(err_val)); - LLVMValueRef end_val = LLVMConstInt(LLVMTypeOf(err_val), g->errors_by_index.length, false); - add_bounds_check(g, err_val, LLVMIntNE, zero, LLVMIntULT, end_val); - } - - LLVMValueRef indices[] = { - LLVMConstNull(g->builtin_types.entry_usize->llvm_type), - err_val, - }; - return LLVMBuildInBoundsGEP2(g->builder, - LLVMGlobalGetValueType(g->err_name_table), - g->err_name_table, indices, 2, ""); -} - -static LLVMValueRef get_enum_tag_name_function(CodeGen *g, ZigType *enum_type) { - assert(enum_type->id == ZigTypeIdEnum); - if (enum_type->data.enumeration.name_function) - return enum_type->data.enumeration.name_function; - - ZigType *u8_ptr_type = get_pointer_to_type_extra2(g, g->builtin_types.entry_u8, false, false, - PtrLenUnknown, get_abi_alignment(g, g->builtin_types.entry_u8), 0, 0, false, - VECTOR_INDEX_NONE, nullptr, g->intern.for_zero_byte()); - ZigType *u8_slice_type = get_slice_type(g, u8_ptr_type); - ZigType *tag_int_type = enum_type->data.enumeration.tag_int_type; - - LLVMTypeRef tag_int_llvm_type = get_llvm_type(g, tag_int_type); - LLVMTypeRef fn_type_ref = LLVMFunctionType(LLVMPointerType(get_llvm_type(g, u8_slice_type), 0), - &tag_int_llvm_type, 1, false); - - const char *fn_name = get_mangled_name(g, - buf_ptr(buf_sprintf("__zig_tag_name_%s", buf_ptr(&enum_type->name)))); - LLVMValueRef fn_val = LLVMAddFunction(g->module, fn_name, fn_type_ref); - LLVMSetLinkage(fn_val, LLVMInternalLinkage); - ZigLLVMFunctionSetCallingConv(fn_val, get_llvm_cc(g, CallingConventionUnspecified)); - add_common_fn_attributes(g, fn_val); - if (!g->omit_frame_pointer) { - ZigLLVMAddFunctionAttr(fn_val, "frame-pointer", "all"); - } - - LLVMBasicBlockRef prev_block = LLVMGetInsertBlock(g->builder); - LLVMValueRef prev_debug_location = LLVMGetCurrentDebugLocation(g->builder); - ZigFn *prev_cur_fn = g->cur_fn; - LLVMValueRef prev_cur_fn_val = g->cur_fn_val; - - LLVMBasicBlockRef entry_block = LLVMAppendBasicBlock(fn_val, "Entry"); - LLVMPositionBuilderAtEnd(g->builder, entry_block); - ZigLLVMClearCurrentDebugLocation(g->builder); - g->cur_fn = nullptr; - g->cur_fn_val = fn_val; - - size_t field_count = enum_type->data.enumeration.src_field_count; - LLVMBasicBlockRef bad_value_block = LLVMAppendBasicBlock(g->cur_fn_val, "BadValue"); - LLVMValueRef tag_int_value = LLVMGetParam(fn_val, 0); - LLVMValueRef switch_instr = LLVMBuildSwitch(g->builder, tag_int_value, bad_value_block, field_count); - - - ZigType *usize = g->builtin_types.entry_usize; - LLVMValueRef array_ptr_indices[] = { - LLVMConstNull(usize->llvm_type), - LLVMConstNull(usize->llvm_type), - }; - - HashMap occupied_tag_values = {}; - occupied_tag_values.init(field_count); - - for (size_t field_i = 0; field_i < field_count; field_i += 1) { - TypeEnumField *type_enum_field = &enum_type->data.enumeration.fields[field_i]; - - Buf *name = type_enum_field->name; - auto entry = occupied_tag_values.put_unique(type_enum_field->value, name); - if (entry != nullptr) { - continue; - } - - LLVMValueRef str_init = LLVMConstString(buf_ptr(name), (unsigned)buf_len(name), false); - LLVMValueRef str_global = LLVMAddGlobal(g->module, LLVMTypeOf(str_init), ""); - LLVMSetInitializer(str_global, str_init); - LLVMSetLinkage(str_global, LLVMPrivateLinkage); - LLVMSetGlobalConstant(str_global, true); - LLVMSetUnnamedAddr(str_global, true); - LLVMSetAlignment(str_global, LLVMABIAlignmentOfType(g->target_data_ref, LLVMTypeOf(str_init))); - - LLVMValueRef fields[] = { - LLVMConstInBoundsGEP2(LLVMGlobalGetValueType(str_global), str_global, array_ptr_indices, 2), - LLVMConstInt(g->builtin_types.entry_usize->llvm_type, buf_len(name), false), - }; - LLVMValueRef slice_init_value = LLVMConstNamedStruct(get_llvm_type(g, u8_slice_type), fields, 2); - - LLVMValueRef slice_global = LLVMAddGlobal(g->module, LLVMTypeOf(slice_init_value), ""); - LLVMSetInitializer(slice_global, slice_init_value); - LLVMSetLinkage(slice_global, LLVMPrivateLinkage); - LLVMSetGlobalConstant(slice_global, true); - LLVMSetUnnamedAddr(slice_global, true); - LLVMSetAlignment(slice_global, LLVMABIAlignmentOfType(g->target_data_ref, LLVMTypeOf(slice_init_value))); - - LLVMBasicBlockRef return_block = LLVMAppendBasicBlock(g->cur_fn_val, "Name"); - LLVMValueRef this_tag_int_value = bigint_to_llvm_const(get_llvm_type(g, tag_int_type), - &enum_type->data.enumeration.fields[field_i].value); - LLVMAddCase(switch_instr, this_tag_int_value, return_block); - - LLVMPositionBuilderAtEnd(g->builder, return_block); - LLVMBuildRet(g->builder, slice_global); - } - occupied_tag_values.deinit(); - - LLVMPositionBuilderAtEnd(g->builder, bad_value_block); - if (g->build_mode == BuildModeDebug || g->build_mode == BuildModeSafeRelease) { - gen_safety_crash(g, PanicMsgIdBadEnumValue); - } else { - LLVMBuildUnreachable(g->builder); - } - - g->cur_fn = prev_cur_fn; - g->cur_fn_val = prev_cur_fn_val; - LLVMPositionBuilderAtEnd(g->builder, prev_block); - if (!g->strip_debug_symbols) { - LLVMSetCurrentDebugLocation(g->builder, prev_debug_location); - } - - enum_type->data.enumeration.name_function = fn_val; - return fn_val; -} - -static LLVMValueRef ir_render_enum_tag_name(CodeGen *g, Stage1Air *executable, - Stage1AirInstTagName *instruction) -{ - ZigType *enum_type = instruction->target->value->type; - assert(enum_type->id == ZigTypeIdEnum); - - LLVMValueRef enum_name_function = get_enum_tag_name_function(g, enum_type); - - LLVMValueRef enum_tag_value = ir_llvm_value(g, instruction->target); - return ZigLLVMBuildCall(g->builder, LLVMGlobalGetValueType(enum_name_function), enum_name_function, - &enum_tag_value, 1, - get_llvm_cc(g, CallingConventionUnspecified), ZigLLVM_CallAttrAuto, ""); -} - -static LLVMValueRef ir_render_field_parent_ptr(CodeGen *g, Stage1Air *executable, - Stage1AirInstFieldParentPtr *instruction) -{ - ZigType *container_ptr_type = instruction->base.value->type; - assert(container_ptr_type->id == ZigTypeIdPointer); - - ZigType *container_type = container_ptr_type->data.pointer.child_type; - - size_t byte_offset = LLVMOffsetOfElement(g->target_data_ref, - get_llvm_type(g, container_type), instruction->field->gen_index); - - LLVMValueRef field_ptr_val = ir_llvm_value(g, instruction->field_ptr); - - if (byte_offset == 0) { - return LLVMBuildBitCast(g->builder, field_ptr_val, get_llvm_type(g, container_ptr_type), ""); - } else { - ZigType *usize = g->builtin_types.entry_usize; - - LLVMValueRef field_ptr_int = LLVMBuildPtrToInt(g->builder, field_ptr_val, usize->llvm_type, ""); - - LLVMValueRef base_ptr_int = LLVMBuildNUWSub(g->builder, field_ptr_int, - LLVMConstInt(usize->llvm_type, byte_offset, false), ""); - - return LLVMBuildIntToPtr(g->builder, base_ptr_int, get_llvm_type(g, container_ptr_type), ""); - } -} - -static LLVMValueRef ir_render_align_cast(CodeGen *g, Stage1Air *executable, Stage1AirInstAlignCast *instruction) { - LLVMValueRef target_val = ir_llvm_value(g, instruction->target); - assert(target_val); - - bool want_runtime_safety = ir_want_runtime_safety(g, &instruction->base); - if (!want_runtime_safety) { - return target_val; - } - - ZigType *target_type = instruction->base.value->type; - uint32_t align_bytes; - LLVMValueRef ptr_val; - - if (target_type->id == ZigTypeIdPointer) { - align_bytes = get_ptr_align(g, target_type); - ptr_val = target_val; - } else if (target_type->id == ZigTypeIdFn) { - align_bytes = target_type->data.fn.fn_type_id.alignment; - ptr_val = target_val; - } else if (target_type->id == ZigTypeIdOptional && - target_type->data.maybe.child_type->id == ZigTypeIdPointer) - { - align_bytes = get_ptr_align(g, target_type->data.maybe.child_type); - ptr_val = target_val; - } else if (target_type->id == ZigTypeIdOptional && - target_type->data.maybe.child_type->id == ZigTypeIdFn) - { - align_bytes = target_type->data.maybe.child_type->data.fn.fn_type_id.alignment; - ptr_val = target_val; - } else if (target_type->id == ZigTypeIdStruct && - target_type->data.structure.special == StructSpecialSlice) - { - ZigType *slice_ptr_type = target_type->data.structure.fields[slice_ptr_index]->type_entry; - align_bytes = get_ptr_align(g, slice_ptr_type); - - size_t ptr_index = target_type->data.structure.fields[slice_ptr_index]->gen_index; - LLVMValueRef ptr_val_ptr = LLVMBuildStructGEP2(g->builder, - get_llvm_type(g, target_type), - target_val, (unsigned)ptr_index, ""); - ptr_val = gen_load_untyped(g, ZigLLVMGetGEPResultElementType(ptr_val_ptr), ptr_val_ptr, 0, false, ""); - } else { - zig_unreachable(); - } - - assert(align_bytes != 1); - - ZigType *usize = g->builtin_types.entry_usize; - LLVMValueRef ptr_as_int_val = LLVMBuildPtrToInt(g->builder, ptr_val, usize->llvm_type, ""); - LLVMValueRef alignment_minus_1 = LLVMConstInt(usize->llvm_type, align_bytes - 1, false); - LLVMValueRef anded_val = LLVMBuildAnd(g->builder, ptr_as_int_val, alignment_minus_1, ""); - LLVMValueRef ok_bit = LLVMBuildICmp(g->builder, LLVMIntEQ, anded_val, LLVMConstNull(usize->llvm_type), ""); - - LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "AlignCastOk"); - LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "AlignCastFail"); - - LLVMBuildCondBr(g->builder, ok_bit, ok_block, fail_block); - - LLVMPositionBuilderAtEnd(g->builder, fail_block); - gen_safety_crash(g, PanicMsgIdIncorrectAlignment); - - LLVMPositionBuilderAtEnd(g->builder, ok_block); - - return target_val; -} - -static LLVMValueRef ir_render_error_return_trace(CodeGen *g, Stage1Air *executable, - Stage1AirInstErrorReturnTrace *instruction) -{ - bool is_llvm_alloca; - LLVMValueRef cur_err_ret_trace_val = get_cur_err_ret_trace_val(g, instruction->base.scope, &is_llvm_alloca); - if (cur_err_ret_trace_val == nullptr) { - return LLVMConstNull(get_llvm_type(g, ptr_to_stack_trace_type(g))); - } - return cur_err_ret_trace_val; -} - -static LLVMAtomicOrdering to_LLVMAtomicOrdering(AtomicOrder atomic_order) { - switch (atomic_order) { - case AtomicOrderUnordered: return LLVMAtomicOrderingUnordered; - case AtomicOrderMonotonic: return LLVMAtomicOrderingMonotonic; - case AtomicOrderAcquire: return LLVMAtomicOrderingAcquire; - case AtomicOrderRelease: return LLVMAtomicOrderingRelease; - case AtomicOrderAcqRel: return LLVMAtomicOrderingAcquireRelease; - case AtomicOrderSeqCst: return LLVMAtomicOrderingSequentiallyConsistent; - } - zig_unreachable(); -} - -static LLVMAtomicRMWBinOp to_LLVMAtomicRMWBinOp(AtomicRmwOp op, bool is_signed, bool is_float) { - switch (op) { - case AtomicRmwOp_xchg: return LLVMAtomicRMWBinOpXchg; - case AtomicRmwOp_add: - return is_float ? LLVMAtomicRMWBinOpFAdd : LLVMAtomicRMWBinOpAdd; - case AtomicRmwOp_sub: - return is_float ? LLVMAtomicRMWBinOpFSub : LLVMAtomicRMWBinOpSub; - case AtomicRmwOp_and: return LLVMAtomicRMWBinOpAnd; - case AtomicRmwOp_nand: return LLVMAtomicRMWBinOpNand; - case AtomicRmwOp_or: return LLVMAtomicRMWBinOpOr; - case AtomicRmwOp_xor: return LLVMAtomicRMWBinOpXor; - case AtomicRmwOp_max: - return is_signed ? LLVMAtomicRMWBinOpMax : LLVMAtomicRMWBinOpUMax; - case AtomicRmwOp_min: - return is_signed ? LLVMAtomicRMWBinOpMin : LLVMAtomicRMWBinOpUMin; - } - zig_unreachable(); -} - -static LLVMTypeRef get_atomic_abi_type(CodeGen *g, Stage1AirInst *instruction, bool RMWXchg) { - // If the operand type of an atomic operation is not byte sized we need to - // widen it before using it and then truncate the result. - // RMW exchange of floating-point values is bitcasted to same-sized integer - // types to work around a LLVM deficiency when targeting ARM/AArch64. - - ir_assert(instruction->value->type->id == ZigTypeIdPointer, instruction); - ZigType *operand_type = instruction->value->type->data.pointer.child_type; - if (operand_type->id == ZigTypeIdInt || operand_type->id == ZigTypeIdEnum) { - if (operand_type->id == ZigTypeIdEnum) { - operand_type = operand_type->data.enumeration.tag_int_type; - } - auto bit_count = operand_type->data.integral.bit_count; - bool is_signed = operand_type->data.integral.is_signed; - - ir_assert(bit_count != 0, instruction); - if (!is_power_of_2(bit_count) || bit_count % 8) { - return get_llvm_type(g, get_int_type(g, is_signed, operand_type->abi_size * 8)); - } else { - return nullptr; - } - } else if (operand_type->id == ZigTypeIdFloat) { - return RMWXchg ? LLVMIntType(operand_type->abi_size * 8) : nullptr; - } else if (operand_type->id == ZigTypeIdBool) { - return g->builtin_types.entry_u8->llvm_type; - } else { - ir_assert(get_codegen_ptr_type_bail(g, operand_type) != nullptr, instruction); - return nullptr; - } -} - -static LLVMValueRef ir_render_cmpxchg(CodeGen *g, Stage1Air *executable, Stage1AirInstCmpxchg *instruction) { - LLVMValueRef ptr_val = ir_llvm_value(g, instruction->ptr); - LLVMValueRef cmp_val = ir_llvm_value(g, instruction->cmp_value); - LLVMValueRef new_val = ir_llvm_value(g, instruction->new_value); - - ZigType *operand_type = instruction->new_value->value->type; - LLVMTypeRef actual_abi_type = get_atomic_abi_type(g, instruction->ptr, false); - if (actual_abi_type != nullptr) { - // operand needs widening and truncating - ptr_val = LLVMBuildBitCast(g->builder, ptr_val, - LLVMPointerType(actual_abi_type, 0), ""); - if (operand_type->data.integral.is_signed) { - cmp_val = LLVMBuildSExt(g->builder, cmp_val, actual_abi_type, ""); - new_val = LLVMBuildSExt(g->builder, new_val, actual_abi_type, ""); - } else { - cmp_val = LLVMBuildZExt(g->builder, cmp_val, actual_abi_type, ""); - new_val = LLVMBuildZExt(g->builder, new_val, actual_abi_type, ""); - } - } - - LLVMAtomicOrdering success_order = to_LLVMAtomicOrdering(instruction->success_order); - LLVMAtomicOrdering failure_order = to_LLVMAtomicOrdering(instruction->failure_order); - - LLVMValueRef result_val = LLVMBuildAtomicCmpXchg(g->builder, ptr_val, cmp_val, new_val, - success_order, failure_order, g->is_single_threaded); - LLVMSetWeak(result_val, instruction->is_weak); - - ZigType *optional_type = instruction->base.value->type; - assert(optional_type->id == ZigTypeIdOptional); - ZigType *child_type = optional_type->data.maybe.child_type; - - if (!handle_is_ptr(g, optional_type)) { - LLVMValueRef payload_val = LLVMBuildExtractValue(g->builder, result_val, 0, ""); - if (actual_abi_type != nullptr) { - payload_val = LLVMBuildTrunc(g->builder, payload_val, get_llvm_type(g, operand_type), ""); - } - LLVMValueRef success_bit = LLVMBuildExtractValue(g->builder, result_val, 1, ""); - return LLVMBuildSelect(g->builder, success_bit, LLVMConstNull(get_llvm_type(g, child_type)), payload_val, ""); - } - - // When the cmpxchg is discarded, the result location will have no bits. - if (!type_has_bits(g, instruction->result_loc->value->type)) { - return nullptr; - } - - LLVMValueRef result_loc = ir_llvm_value(g, instruction->result_loc); - ir_assert(result_loc != nullptr, &instruction->base); - ir_assert(type_has_bits(g, child_type), &instruction->base); - - LLVMValueRef payload_val = LLVMBuildExtractValue(g->builder, result_val, 0, ""); - if (actual_abi_type != nullptr) { - payload_val = LLVMBuildTrunc(g->builder, payload_val, get_llvm_type(g, operand_type), ""); - } - LLVMTypeRef result_loc_struct_llvm_ty = get_llvm_type(g, - instruction->result_loc->value->type->data.pointer.child_type); - LLVMValueRef val_ptr = LLVMBuildStructGEP2(g->builder, - result_loc_struct_llvm_ty, result_loc, maybe_child_index, ""); - gen_assign_raw(g, val_ptr, get_pointer_to_type(g, child_type, false), payload_val); - - LLVMValueRef success_bit = LLVMBuildExtractValue(g->builder, result_val, 1, ""); - LLVMValueRef nonnull_bit = LLVMBuildNot(g->builder, success_bit, ""); - LLVMValueRef maybe_ptr = LLVMBuildStructGEP2(g->builder, result_loc_struct_llvm_ty, result_loc, - maybe_null_index, ""); - gen_store_untyped(g, nonnull_bit, maybe_ptr, 0, false); - return result_loc; -} - -static LLVMValueRef ir_render_reduced_call(CodeGen *g, LLVMValueRef llvm_fn, LLVMValueRef operand_vector, size_t vector_len, LLVMValueRef accum_init, ZigType *accum_ty) { - LLVMTypeRef llvm_usize_ty = g->builtin_types.entry_usize->llvm_type; - LLVMValueRef llvm_vector_len = LLVMConstInt(llvm_usize_ty, vector_len, false); - LLVMTypeRef llvm_result_ty = LLVMTypeOf(accum_init); - - // Allocate and initialize our mutable variables - LLVMValueRef i_ptr = build_alloca(g, g->builtin_types.entry_usize, "i", 0); - LLVMBuildStore(g->builder, LLVMConstInt(llvm_usize_ty, 0, false), i_ptr); - LLVMValueRef accum_ptr = build_alloca(g, accum_ty, "accum", 0); - LLVMBuildStore(g->builder, accum_init, accum_ptr); - - // Setup the loop - LLVMBasicBlockRef loop = LLVMAppendBasicBlock(g->cur_fn_val, "ReduceLoop"); - LLVMBasicBlockRef loop_exit = LLVMAppendBasicBlock(g->cur_fn_val, "AfterReduce"); - LLVMBuildBr(g->builder, loop); - { - LLVMPositionBuilderAtEnd(g->builder, loop); - - // while (i < vec.len) - LLVMValueRef i = LLVMBuildLoad2(g->builder, llvm_usize_ty, i_ptr, ""); - LLVMValueRef cond = LLVMBuildICmp(g->builder, LLVMIntULT, i, llvm_vector_len, ""); - LLVMBasicBlockRef loop_then = LLVMAppendBasicBlock(g->cur_fn_val, "ReduceLoopThen"); - - LLVMBuildCondBr(g->builder, cond, loop_then, loop_exit); - - { - LLVMPositionBuilderAtEnd(g->builder, loop_then); - - // accum = f(accum, vec[i]); - LLVMValueRef accum = LLVMBuildLoad2(g->builder, llvm_result_ty, accum_ptr, ""); - LLVMValueRef element = LLVMBuildExtractElement(g->builder, operand_vector, i, ""); - LLVMValueRef params[] { - accum, - element - }; - LLVMValueRef new_accum = LLVMBuildCall2(g->builder, LLVMGlobalGetValueType(llvm_fn), llvm_fn, params, 2, ""); - LLVMBuildStore(g->builder, new_accum, accum_ptr); - - // i += 1 - LLVMValueRef new_i = LLVMBuildAdd(g->builder, i, LLVMConstInt(llvm_usize_ty, 1, false), ""); - LLVMBuildStore(g->builder, new_i, i_ptr); - LLVMBuildBr(g->builder, loop); - } - } - - LLVMPositionBuilderAtEnd(g->builder, loop_exit); - return LLVMBuildLoad2(g->builder, llvm_result_ty, accum_ptr, ""); -} - -static LLVMValueRef ir_render_reduce(CodeGen *g, Stage1Air *executable, Stage1AirInstReduce *instruction) { - LLVMValueRef value = ir_llvm_value(g, instruction->value); - - ZigType *value_type = instruction->value->value->type; - assert(value_type->id == ZigTypeIdVector); - ZigType *scalar_type = value_type->data.vector.elem_type; - - bool float_intrinsics_allowed = true; - const char *compiler_rt_type_abbrev = nullptr; - const char *math_float_prefix = nullptr; - const char *math_float_suffix = nullptr; - if ((scalar_type == g->builtin_types.entry_f80 && !target_has_f80(g->zig_target)) || - (scalar_type == g->builtin_types.entry_f128 && !target_long_double_is_f128(g->zig_target)) || - (scalar_type == g->builtin_types.entry_f16 && !target_is_arm(g->zig_target))) { - float_intrinsics_allowed = false; - compiler_rt_type_abbrev = get_compiler_rt_type_abbrev(scalar_type); - math_float_prefix = libc_float_prefix(g, scalar_type); - math_float_suffix = libc_float_suffix(g, scalar_type); - } - - ZigLLVMSetFastMath(g->builder, ir_want_fast_math(g, &instruction->base)); - - char fn_name[64]; - ZigValue *init_value = nullptr; - switch (instruction->op) { - case ReduceOp_and: - assert(scalar_type->id == ZigTypeIdInt || scalar_type->id == ZigTypeIdBool); - return ZigLLVMBuildAndReduce(g->builder, value); - break; - case ReduceOp_or: - assert(scalar_type->id == ZigTypeIdInt || scalar_type->id == ZigTypeIdBool); - return ZigLLVMBuildOrReduce(g->builder, value); - break; - case ReduceOp_xor: - assert(scalar_type->id == ZigTypeIdInt || scalar_type->id == ZigTypeIdBool); - return ZigLLVMBuildXorReduce(g->builder, value); - break; - case ReduceOp_min: { - if (scalar_type->id == ZigTypeIdInt) { - const bool is_signed = scalar_type->data.integral.is_signed; - return ZigLLVMBuildIntMinReduce(g->builder, value, is_signed); - } else if (scalar_type->id == ZigTypeIdFloat) { - if (float_intrinsics_allowed) { - return ZigLLVMBuildFPMinReduce(g->builder, value); - } else { - snprintf(fn_name, sizeof(fn_name), "%sfmin%s", math_float_prefix, math_float_suffix); - init_value = create_const_float(g, scalar_type, NAN); - } - } else zig_unreachable(); - } break; - case ReduceOp_max: { - if (scalar_type->id == ZigTypeIdInt) { - const bool is_signed = scalar_type->data.integral.is_signed; - return ZigLLVMBuildIntMaxReduce(g->builder, value, is_signed); - } else if (scalar_type->id == ZigTypeIdFloat) { - if (float_intrinsics_allowed) { - return ZigLLVMBuildFPMaxReduce(g->builder, value); - } else { - snprintf(fn_name, sizeof(fn_name), "%sfmax%s", math_float_prefix, math_float_suffix); - init_value = create_const_float(g, scalar_type, NAN); - } - } else zig_unreachable(); - } break; - case ReduceOp_add: { - if (scalar_type->id == ZigTypeIdInt) { - return ZigLLVMBuildAddReduce(g->builder, value); - } else if (scalar_type->id == ZigTypeIdFloat) { - if (float_intrinsics_allowed) { - LLVMValueRef neutral_value = LLVMConstReal( - get_llvm_type(g, scalar_type), -0.0); - return ZigLLVMBuildFPAddReduce(g->builder, neutral_value, value); - } else { - snprintf(fn_name, sizeof(fn_name), "__add%sf3", compiler_rt_type_abbrev); - init_value = create_const_float(g, scalar_type, 0.0); - } - } else zig_unreachable(); - } break; - case ReduceOp_mul: { - if (scalar_type->id == ZigTypeIdInt) { - return ZigLLVMBuildMulReduce(g->builder, value); - } else if (scalar_type->id == ZigTypeIdFloat) { - if (float_intrinsics_allowed) { - LLVMValueRef neutral_value = LLVMConstReal( - get_llvm_type(g, scalar_type), 1.0); - return ZigLLVMBuildFPMulReduce(g->builder, neutral_value, value); - } else { - snprintf(fn_name, sizeof(fn_name), "__mul%sf3", compiler_rt_type_abbrev); - init_value = create_const_float(g, scalar_type, 1.0); - } - } else zig_unreachable(); - } break; - default: - zig_unreachable(); - } - - - LLVMValueRef llvm_init_value = gen_const_val(g, init_value, ""); - uint32_t vector_len = value_type->data.vector.len; - LLVMTypeRef llvm_scalar_type = get_llvm_type(g, scalar_type); - const LLVMValueRef llvm_fn = get_soft_float_fn(g, fn_name, 2, llvm_scalar_type, llvm_scalar_type); - return ir_render_reduced_call(g, llvm_fn, value, vector_len, llvm_init_value, scalar_type); -} - -static LLVMValueRef ir_render_fence(CodeGen *g, Stage1Air *executable, Stage1AirInstFence *instruction) { - LLVMAtomicOrdering atomic_order = to_LLVMAtomicOrdering(instruction->order); - LLVMBuildFence(g->builder, atomic_order, false, ""); - return nullptr; -} - -static LLVMValueRef ir_render_truncate(CodeGen *g, Stage1Air *executable, Stage1AirInstTruncate *instruction) { - LLVMValueRef target_val = ir_llvm_value(g, instruction->target); - ZigType *dest_type = instruction->base.value->type; - ZigType *src_type = instruction->target->value->type; - if (dest_type == src_type) { - // no-op - return target_val; - } if (src_type->data.integral.bit_count == dest_type->data.integral.bit_count) { - return LLVMBuildBitCast(g->builder, target_val, get_llvm_type(g, dest_type), ""); - } else { - LLVMValueRef target_val = ir_llvm_value(g, instruction->target); - return LLVMBuildTrunc(g->builder, target_val, get_llvm_type(g, dest_type), ""); - } -} - -static LLVMValueRef ir_render_memset(CodeGen *g, Stage1Air *executable, Stage1AirInstMemset *instruction) { - LLVMValueRef dest_ptr = ir_llvm_value(g, instruction->dest_ptr); - LLVMValueRef len_val = ir_llvm_value(g, instruction->count); - - LLVMTypeRef ptr_u8 = LLVMPointerType(LLVMInt8Type(), 0); - LLVMValueRef dest_ptr_casted = LLVMBuildBitCast(g->builder, dest_ptr, ptr_u8, ""); - - ZigType *ptr_type = instruction->dest_ptr->value->type; - assert(ptr_type->id == ZigTypeIdPointer); - - bool val_is_undef = value_is_all_undef(g, instruction->byte->value); - LLVMValueRef fill_char; - if (val_is_undef) { - if (ir_want_runtime_safety_scope(g, instruction->base.scope)) { - fill_char = LLVMConstInt(LLVMInt8Type(), 0xaa, false); - } else { - return nullptr; - } - } else { - fill_char = ir_llvm_value(g, instruction->byte); - } - ZigLLVMBuildMemSet(g->builder, dest_ptr_casted, fill_char, len_val, get_ptr_align(g, ptr_type), - ptr_type->data.pointer.is_volatile); - - if (val_is_undef && g->valgrind_enabled) { - gen_valgrind_undef(g, dest_ptr_casted, len_val); - } - return nullptr; -} - -static LLVMValueRef ir_render_memcpy(CodeGen *g, Stage1Air *executable, Stage1AirInstMemcpy *instruction) { - LLVMValueRef dest_ptr = ir_llvm_value(g, instruction->dest_ptr); - LLVMValueRef src_ptr = ir_llvm_value(g, instruction->src_ptr); - LLVMValueRef len_val = ir_llvm_value(g, instruction->count); - - LLVMTypeRef ptr_u8 = LLVMPointerType(LLVMInt8Type(), 0); - - LLVMValueRef dest_ptr_casted = LLVMBuildBitCast(g->builder, dest_ptr, ptr_u8, ""); - LLVMValueRef src_ptr_casted = LLVMBuildBitCast(g->builder, src_ptr, ptr_u8, ""); - - ZigType *dest_ptr_type = instruction->dest_ptr->value->type; - ZigType *src_ptr_type = instruction->src_ptr->value->type; - - assert(dest_ptr_type->id == ZigTypeIdPointer); - assert(src_ptr_type->id == ZigTypeIdPointer); - - bool is_volatile = (dest_ptr_type->data.pointer.is_volatile || src_ptr_type->data.pointer.is_volatile); - ZigLLVMBuildMemCpy(g->builder, dest_ptr_casted, get_ptr_align(g, dest_ptr_type), - src_ptr_casted, get_ptr_align(g, src_ptr_type), len_val, is_volatile); - return nullptr; -} - -static LLVMValueRef ir_render_wasm_memory_size(CodeGen *g, Stage1Air *executable, Stage1AirInstWasmMemorySize *instruction) { - // TODO adjust for wasm64 - LLVMValueRef param = ir_llvm_value(g, instruction->index); - LLVMValueRef val = LLVMBuildCall2(g->builder, LLVMGlobalGetValueType(gen_wasm_memory_size(g)), gen_wasm_memory_size(g), ¶m, 1, ""); - return val; -} - -static LLVMValueRef ir_render_wasm_memory_grow(CodeGen *g, Stage1Air *executable, Stage1AirInstWasmMemoryGrow *instruction) { - // TODO adjust for wasm64 - LLVMValueRef params[] = { - ir_llvm_value(g, instruction->index), - ir_llvm_value(g, instruction->delta), - }; - LLVMValueRef val = LLVMBuildCall2(g->builder, LLVMGlobalGetValueType(gen_wasm_memory_grow(g)), gen_wasm_memory_grow(g), params, 2, ""); - return val; -} - -static LLVMValueRef ir_render_prefetch(CodeGen *g, Stage1Air *executable, Stage1AirInstPrefetch *instruction) { - static_assert(PrefetchRwRead == 0, ""); - static_assert(PrefetchRwWrite == 1, ""); - assert(instruction->rw == PrefetchRwRead || instruction->rw == PrefetchRwWrite); - - assert(instruction->locality >= 0 && instruction->locality <= 3); - - static_assert(PrefetchCacheInstruction == 0, ""); - static_assert(PrefetchCacheData == 1, ""); - assert(instruction->cache == PrefetchCacheData || instruction->cache == PrefetchCacheInstruction); - - // LLVM fails during codegen of instruction cache prefetchs for these architectures. - // This is an LLVM bug as the prefetch intrinsic should be a noop if not supported by the target. - // To work around this, simply don't emit llvm.prefetch in this case. - // See https://bugs.llvm.org/show_bug.cgi?id=21037 - if (instruction->cache == PrefetchCacheInstruction) { - switch (g->zig_target->arch) { - case ZigLLVM_x86: - case ZigLLVM_x86_64: - case ZigLLVM_ppc: - case ZigLLVM_ppcle: - case ZigLLVM_ppc64: - case ZigLLVM_ppc64le: - return nullptr; - default: - break; - } - } - - // Another case of the same LLVM bug described above - if (instruction->rw == PrefetchRwWrite && instruction->cache == PrefetchCacheInstruction) { - switch (g->zig_target->arch) { - case ZigLLVM_arm: - return nullptr; - default: - break; - } - - } - - LLVMValueRef params[] = { - LLVMBuildBitCast(g->builder, ir_llvm_value(g, instruction->ptr), LLVMPointerType(LLVMInt8Type(), 0), ""), - LLVMConstInt(LLVMInt32Type(), instruction->rw, false), - LLVMConstInt(LLVMInt32Type(), instruction->locality, false), - LLVMConstInt(LLVMInt32Type(), instruction->cache, false), - }; - LLVMValueRef val = LLVMBuildCall2(g->builder, LLVMGlobalGetValueType(gen_prefetch(g)), gen_prefetch(g), params, 4, ""); - return val; -} - -static LLVMValueRef ir_render_slice(CodeGen *g, Stage1Air *executable, Stage1AirInstSlice *instruction) { - Error err; - - LLVMValueRef array_ptr_ptr = ir_llvm_value(g, instruction->ptr); - ZigType *array_ptr_type = instruction->ptr->value->type; - assert(array_ptr_type->id == ZigTypeIdPointer); - ZigType *array_type = array_ptr_type->data.pointer.child_type; - LLVMValueRef array_ptr = get_handle_value(g, array_ptr_ptr, array_type, array_ptr_type); - - bool want_runtime_safety = instruction->safety_check_on && ir_want_runtime_safety(g, &instruction->base); - - // The result is either a slice or a pointer to an array - ZigType *result_type = instruction->base.value->type; - - // This is not whether the result type has a sentinel, but whether there should be a sentinel check, - // e.g. if they used [a..b :s] syntax. - ZigValue *sentinel = instruction->sentinel; - - LLVMValueRef slice_start_ptr = nullptr; - LLVMValueRef len_value = nullptr; - - if (array_type->id == ZigTypeIdArray || - (array_type->id == ZigTypeIdPointer && array_type->data.pointer.ptr_len == PtrLenSingle)) - { - if (array_type->id == ZigTypeIdPointer) { - array_type = array_type->data.pointer.child_type; - } - LLVMValueRef start_val = ir_llvm_value(g, instruction->start); - LLVMValueRef end_val; - if (instruction->end) { - end_val = ir_llvm_value(g, instruction->end); - } else { - end_val = LLVMConstInt(g->builtin_types.entry_usize->llvm_type, array_type->data.array.len, false); - } - - if (want_runtime_safety) { - // Safety check: start <= end - if (instruction->start->value->special == ConstValSpecialRuntime || instruction->end) { - add_bounds_check(g, start_val, LLVMIntEQ, nullptr, LLVMIntULE, end_val); - } - - // Safety check: the last element of the slice (the sentinel if - // requested) must be inside the array - // XXX: Overflow is not checked here... - const size_t full_len = array_type->data.array.len + - (array_type->data.array.sentinel != nullptr); - LLVMValueRef array_end = LLVMConstInt(g->builtin_types.entry_usize->llvm_type, - full_len, false); - - LLVMValueRef check_end_val = end_val; - if (sentinel != nullptr) { - LLVMValueRef usize_one = LLVMConstInt(g->builtin_types.entry_usize->llvm_type, 1, false); - check_end_val = LLVMBuildNUWAdd(g->builder, end_val, usize_one, ""); - } - add_bounds_check(g, check_end_val, LLVMIntEQ, nullptr, LLVMIntULE, array_end); - } - - bool value_has_bits; - if ((err = type_has_bits2(g, array_type, &value_has_bits))) - codegen_report_errors_and_exit(g); - - if (value_has_bits) { - LLVMTypeRef array_llvm_ty = get_llvm_type(g, array_type); - if (want_runtime_safety && sentinel != nullptr) { - LLVMValueRef indices[] = { - LLVMConstNull(g->builtin_types.entry_usize->llvm_type), - end_val, - }; - LLVMValueRef sentinel_elem_ptr = LLVMBuildInBoundsGEP2(g->builder, - array_llvm_ty, array_ptr, indices, 2, ""); - add_sentinel_check(g, sentinel_elem_ptr, sentinel); - } - - LLVMValueRef indices[] = { - LLVMConstNull(g->builtin_types.entry_usize->llvm_type), - start_val, - }; - slice_start_ptr = LLVMBuildInBoundsGEP2(g->builder, array_llvm_ty, array_ptr, indices, 2, ""); - } - - len_value = LLVMBuildNUWSub(g->builder, end_val, start_val, ""); - } else if (array_type->id == ZigTypeIdPointer) { - assert(array_type->data.pointer.ptr_len != PtrLenSingle); - LLVMValueRef start_val = ir_llvm_value(g, instruction->start); - LLVMValueRef end_val = ir_llvm_value(g, instruction->end); - - if (want_runtime_safety) { - // Safety check: start <= end - add_bounds_check(g, start_val, LLVMIntEQ, nullptr, LLVMIntULE, end_val); - } - - bool value_has_bits; - if ((err = type_has_bits2(g, array_type, &value_has_bits))) - codegen_report_errors_and_exit(g); - - if (value_has_bits) { - LLVMTypeRef elem_llvm_ty = get_llvm_type(g, array_type->data.pointer.child_type); - if (want_runtime_safety && sentinel != nullptr) { - LLVMValueRef sentinel_elem_ptr = LLVMBuildInBoundsGEP2(g->builder, elem_llvm_ty, - array_ptr, &end_val, 1, ""); - add_sentinel_check(g, sentinel_elem_ptr, sentinel); - } - - slice_start_ptr = LLVMBuildInBoundsGEP2(g->builder, elem_llvm_ty, array_ptr, - &start_val, 1, ""); - } - - len_value = LLVMBuildNUWSub(g->builder, end_val, start_val, ""); - } else if (array_type->id == ZigTypeIdStruct) { - assert(array_type->data.structure.special == StructSpecialSlice); - assert(LLVMGetTypeKind(LLVMTypeOf(array_ptr)) == LLVMPointerTypeKind); - - const size_t gen_len_index = array_type->data.structure.fields[slice_len_index]->gen_index; - assert(gen_len_index != SIZE_MAX); - - LLVMValueRef prev_end = nullptr; - if (!instruction->end || want_runtime_safety) { - LLVMValueRef src_len_ptr = LLVMBuildStructGEP2(g->builder, - get_llvm_type(g, array_type), array_ptr, gen_len_index, ""); - prev_end = gen_load_untyped(g, ZigLLVMGetGEPResultElementType(src_len_ptr), src_len_ptr, 0, false, ""); - } - - LLVMValueRef start_val = ir_llvm_value(g, instruction->start); - LLVMValueRef end_val; - if (instruction->end) { - end_val = ir_llvm_value(g, instruction->end); - } else { - end_val = prev_end; - } - - ZigType *ptr_field_type = array_type->data.structure.fields[slice_ptr_index]->type_entry; - - if (want_runtime_safety) { - assert(prev_end); - // Safety check: start <= end - add_bounds_check(g, start_val, LLVMIntEQ, nullptr, LLVMIntULE, end_val); - - // Safety check: the sentinel counts as one more element - // XXX: Overflow is not checked here... - LLVMValueRef check_prev_end = prev_end; - if (ptr_field_type->data.pointer.sentinel != nullptr) { - LLVMValueRef usize_one = LLVMConstInt(g->builtin_types.entry_usize->llvm_type, 1, false); - check_prev_end = LLVMBuildNUWAdd(g->builder, prev_end, usize_one, ""); - } - LLVMValueRef check_end_val = end_val; - if (sentinel != nullptr) { - LLVMValueRef usize_one = LLVMConstInt(g->builtin_types.entry_usize->llvm_type, 1, false); - check_end_val = LLVMBuildNUWAdd(g->builder, end_val, usize_one, ""); - } - - add_bounds_check(g, check_end_val, LLVMIntEQ, nullptr, LLVMIntULE, check_prev_end); - } - - bool ptr_has_bits; - if ((err = type_has_bits2(g, ptr_field_type, &ptr_has_bits))) - codegen_report_errors_and_exit(g); - - if (ptr_has_bits) { - LLVMTypeRef elem_llvm_ty = get_llvm_type(g, ptr_field_type->data.pointer.child_type); - const size_t gen_ptr_index = array_type->data.structure.fields[slice_ptr_index]->gen_index; - assert(gen_ptr_index != SIZE_MAX); - - LLVMValueRef src_ptr_ptr = LLVMBuildStructGEP2(g->builder, - get_llvm_type(g, array_type), array_ptr, gen_ptr_index, ""); - LLVMValueRef src_ptr = gen_load_untyped(g, ZigLLVMGetGEPResultElementType(src_ptr_ptr), - src_ptr_ptr, 0, false, ""); - - if (sentinel != nullptr) { - LLVMValueRef sentinel_elem_ptr = LLVMBuildInBoundsGEP2(g->builder, elem_llvm_ty, - src_ptr, &end_val, 1, ""); - add_sentinel_check(g, sentinel_elem_ptr, sentinel); - } - - slice_start_ptr = LLVMBuildInBoundsGEP2(g->builder, elem_llvm_ty, src_ptr, &start_val, 1, ""); - } - - len_value = LLVMBuildNUWSub(g->builder, end_val, start_val, ""); - } else { - zig_unreachable(); - } - - bool result_has_bits; - if ((err = type_has_bits2(g, result_type, &result_has_bits))) - codegen_report_errors_and_exit(g); - - // Nothing to do, we're only interested in the bound checks emitted above - if (!result_has_bits) - return nullptr; - - // The starting pointer for the slice may be null in case of zero-sized - // arrays, the length value is always defined. - assert(len_value != nullptr); - - // The slice decays into a pointer to an array, the size is tracked in the - // type itself - if (result_type->id == ZigTypeIdPointer) { - ir_assert(instruction->result_loc == nullptr, &instruction->base); - LLVMTypeRef result_ptr_type = get_llvm_type(g, result_type); - - if (slice_start_ptr != nullptr) { - return LLVMBuildBitCast(g->builder, slice_start_ptr, result_ptr_type, ""); - } - - return LLVMGetUndef(result_ptr_type); - } - - ir_assert(instruction->result_loc != nullptr, &instruction->base); - // Create a new slice - LLVMValueRef tmp_struct_ptr = ir_llvm_value(g, instruction->result_loc); - - ZigType *slice_ptr_type = result_type->data.structure.fields[slice_ptr_index]->type_entry; - - // The slice may not have a pointer at all if it points to a zero-sized type - const size_t gen_ptr_index = result_type->data.structure.fields[slice_ptr_index]->gen_index; - if (gen_ptr_index != SIZE_MAX) { - LLVMValueRef ptr_field_ptr = LLVMBuildStructGEP2(g->builder, - get_llvm_type(g, result_type), tmp_struct_ptr, gen_ptr_index, ""); - if (slice_start_ptr != nullptr) { - gen_store_untyped(g, slice_start_ptr, ptr_field_ptr, 0, false); - } else if (want_runtime_safety) { - gen_undef_init(g, slice_ptr_type, slice_ptr_type, ptr_field_ptr); - } else { - gen_store_untyped(g, LLVMGetUndef(get_llvm_type(g, slice_ptr_type)), ptr_field_ptr, 0, false); - } - } - - const size_t gen_len_index = result_type->data.structure.fields[slice_len_index]->gen_index; - assert(gen_len_index != SIZE_MAX); - - LLVMValueRef len_field_ptr = LLVMBuildStructGEP2(g->builder, - get_llvm_type(g, result_type), tmp_struct_ptr, gen_len_index, ""); - gen_store_untyped(g, len_value, len_field_ptr, 0, false); - - return tmp_struct_ptr; -} - -static LLVMValueRef get_trap_fn_val(CodeGen *g) { - if (g->trap_fn_val) - return g->trap_fn_val; - - LLVMTypeRef fn_type = LLVMFunctionType(LLVMVoidType(), nullptr, 0, false); - g->trap_fn_val = LLVMAddFunction(g->module, "llvm.debugtrap", fn_type); - assert(LLVMGetIntrinsicID(g->trap_fn_val)); - - return g->trap_fn_val; -} - - -static LLVMValueRef ir_render_breakpoint(CodeGen *g, Stage1Air *executable, Stage1AirInstBreakpoint *instruction) { - LLVMBuildCall2(g->builder, LLVMGlobalGetValueType(get_trap_fn_val(g)), get_trap_fn_val(g), nullptr, 0, ""); - return nullptr; -} - -static LLVMValueRef ir_render_return_address(CodeGen *g, Stage1Air *executable, - Stage1AirInstReturnAddress *instruction) -{ - if ((target_is_wasm(g->zig_target) && g->zig_target->os != OsEmscripten) || target_is_bpf(g->zig_target)) { - // LLVM 13 reports "Non-Emscripten WebAssembly hasn't implemented __builtin_return_address" - // https://github.com/ziglang/zig/issues/11946 - return LLVMConstNull(get_llvm_type(g, instruction->base.value->type)); - } - - LLVMValueRef zero = LLVMConstNull(g->builtin_types.entry_i32->llvm_type); - LLVMValueRef ptr_val = LLVMBuildCall2(g->builder, LLVMGlobalGetValueType(get_return_address_fn_val(g)), get_return_address_fn_val(g), &zero, 1, ""); - return LLVMBuildPtrToInt(g->builder, ptr_val, g->builtin_types.entry_usize->llvm_type, ""); -} - -static LLVMValueRef get_frame_address_fn_val(CodeGen *g) { - if (g->frame_address_fn_val) - return g->frame_address_fn_val; - - ZigType *return_type = get_pointer_to_type(g, g->builtin_types.entry_u8, true); - - LLVMTypeRef fn_type = LLVMFunctionType(get_llvm_type(g, return_type), - &g->builtin_types.entry_i32->llvm_type, 1, false); - g->frame_address_fn_val = LLVMAddFunction(g->module, "llvm.frameaddress.p0", fn_type); - assert(LLVMGetIntrinsicID(g->frame_address_fn_val)); - - return g->frame_address_fn_val; -} - -static LLVMValueRef ir_render_frame_address(CodeGen *g, Stage1Air *executable, - Stage1AirInstFrameAddress *instruction) -{ - LLVMValueRef zero = LLVMConstNull(g->builtin_types.entry_i32->llvm_type); - LLVMValueRef ptr_val = LLVMBuildCall2(g->builder, LLVMGlobalGetValueType(get_frame_address_fn_val(g)), get_frame_address_fn_val(g), &zero, 1, ""); - return LLVMBuildPtrToInt(g->builder, ptr_val, g->builtin_types.entry_usize->llvm_type, ""); -} - -static LLVMValueRef ir_render_handle(CodeGen *g, Stage1Air *executable, Stage1AirInstFrameHandle *instruction) { - return g->cur_frame_ptr; -} - -static LLVMValueRef render_shl_with_overflow(CodeGen *g, Stage1AirInstOverflowOp *instruction) { - ZigType *int_type = instruction->result_ptr_type; - assert(int_type->id == ZigTypeIdInt); - - LLVMValueRef op1 = ir_llvm_value(g, instruction->op1); - LLVMValueRef op2 = ir_llvm_value(g, instruction->op2); - LLVMValueRef ptr_result = ir_llvm_value(g, instruction->result_ptr); - - LLVMValueRef op2_casted = gen_widen_or_shorten(g, false, instruction->op2->value->type, - instruction->op1->value->type, op2); - - LLVMValueRef result = LLVMBuildShl(g->builder, op1, op2_casted, ""); - LLVMValueRef orig_val; - if (int_type->data.integral.is_signed) { - orig_val = LLVMBuildAShr(g->builder, result, op2_casted, ""); - } else { - orig_val = LLVMBuildLShr(g->builder, result, op2_casted, ""); - } - LLVMValueRef overflow_bit = LLVMBuildICmp(g->builder, LLVMIntNE, op1, orig_val, ""); - - gen_store(g, result, ptr_result, instruction->result_ptr->value->type); - - return overflow_bit; -} - -static LLVMValueRef ir_render_overflow_op(CodeGen *g, Stage1Air *executable, Stage1AirInstOverflowOp *instruction) { - AddSubMul add_sub_mul; - switch (instruction->op) { - case IrOverflowOpAdd: - add_sub_mul = AddSubMulAdd; - break; - case IrOverflowOpSub: - add_sub_mul = AddSubMulSub; - break; - case IrOverflowOpMul: - add_sub_mul = AddSubMulMul; - break; - case IrOverflowOpShl: - return render_shl_with_overflow(g, instruction); - } - - ZigType *int_type = instruction->result_ptr_type; - assert(int_type->id == ZigTypeIdInt); - - LLVMValueRef fn_val = get_int_overflow_fn(g, int_type, add_sub_mul); - - LLVMValueRef op1 = ir_llvm_value(g, instruction->op1); - LLVMValueRef op2 = ir_llvm_value(g, instruction->op2); - LLVMValueRef ptr_result = ir_llvm_value(g, instruction->result_ptr); - - LLVMValueRef params[] = { - op1, - op2, - }; - - LLVMValueRef result_struct = LLVMBuildCall2(g->builder, LLVMGlobalGetValueType(fn_val), fn_val, params, 2, ""); - LLVMValueRef result = LLVMBuildExtractValue(g->builder, result_struct, 0, ""); - LLVMValueRef overflow_bit = LLVMBuildExtractValue(g->builder, result_struct, 1, ""); - gen_store(g, result, ptr_result, instruction->result_ptr->value->type); - - return overflow_bit; -} - -static LLVMValueRef ir_render_test_err(CodeGen *g, Stage1Air *executable, Stage1AirInstTestErr *instruction) { - ZigType *err_union_type = instruction->err_union->value->type; - ZigType *payload_type = err_union_type->data.error_union.payload_type; - LLVMValueRef err_union_handle = ir_llvm_value(g, instruction->err_union); - - LLVMValueRef err_val; - if (type_has_bits(g, payload_type)) { - LLVMValueRef err_val_ptr = LLVMBuildStructGEP2(g->builder, - get_llvm_type(g, err_union_type), err_union_handle, err_union_err_index, ""); - err_val = gen_load_untyped(g, ZigLLVMGetGEPResultElementType(err_val_ptr), err_val_ptr, 0, false, ""); - } else { - err_val = err_union_handle; - } - - LLVMValueRef zero = LLVMConstNull(get_llvm_type(g, g->err_tag_type)); - return LLVMBuildICmp(g->builder, LLVMIntNE, err_val, zero, ""); -} - -static LLVMValueRef ir_render_unwrap_err_code(CodeGen *g, Stage1Air *executable, - Stage1AirInstUnwrapErrCode *instruction) -{ - if (instruction->base.value->special != ConstValSpecialRuntime) - return nullptr; - - ZigType *ptr_type = instruction->err_union_ptr->value->type; - assert(ptr_type->id == ZigTypeIdPointer); - ZigType *err_union_type = ptr_type->data.pointer.child_type; - ZigType *payload_type = err_union_type->data.error_union.payload_type; - LLVMValueRef err_union_ptr = ir_llvm_value(g, instruction->err_union_ptr); - if (!type_has_bits(g, payload_type)) { - return err_union_ptr; - } else { - // TODO assign undef to the payload - LLVMValueRef err_union_handle = get_handle_value(g, err_union_ptr, err_union_type, ptr_type); - return LLVMBuildStructGEP2(g->builder, get_llvm_type(g, err_union_type), err_union_handle, - err_union_err_index, ""); - } -} - -static LLVMValueRef ir_render_unwrap_err_payload(CodeGen *g, Stage1Air *executable, - Stage1AirInstUnwrapErrPayload *instruction) -{ - Error err; - - if (instruction->base.value->special != ConstValSpecialRuntime) - return nullptr; - - bool want_safety = instruction->safety_check_on && ir_want_runtime_safety(g, &instruction->base) && - g->errors_by_index.length > 1; - - ZigType *ptr_type = instruction->value->value->type; - assert(ptr_type->id == ZigTypeIdPointer); - ZigType *err_union_type = ptr_type->data.pointer.child_type; - ZigType *payload_type = err_union_type->data.error_union.payload_type; - LLVMValueRef err_union_ptr = ir_llvm_value(g, instruction->value); - - LLVMValueRef zero = LLVMConstNull(get_llvm_type(g, g->err_tag_type)); - bool value_has_bits; - if ((err = type_has_bits2(g, instruction->base.value->type, &value_has_bits))) - codegen_report_errors_and_exit(g); - if (!want_safety && !value_has_bits) { - if (instruction->initializing) { - gen_store_untyped(g, zero, err_union_ptr, 0, false); - } - return nullptr; - } - - - LLVMValueRef err_union_handle = get_handle_value(g, err_union_ptr, err_union_type, ptr_type); - - if (!type_has_bits(g, err_union_type->data.error_union.err_set_type)) { - return err_union_handle; - } - - LLVMTypeRef err_union_llvm_ty = get_llvm_type(g, err_union_type); - - if (want_safety) { - LLVMValueRef err_val; - if (type_has_bits(g, payload_type)) { - LLVMValueRef err_val_ptr = LLVMBuildStructGEP2(g->builder, err_union_llvm_ty, - err_union_handle, err_union_err_index, ""); - err_val = gen_load_untyped(g, ZigLLVMGetGEPResultElementType(err_val_ptr), err_val_ptr, 0, false, ""); - } else { - err_val = err_union_handle; - } - LLVMValueRef cond_val = LLVMBuildICmp(g->builder, LLVMIntEQ, err_val, zero, ""); - LLVMBasicBlockRef err_block = LLVMAppendBasicBlock(g->cur_fn_val, "UnwrapErrError"); - LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "UnwrapErrOk"); - LLVMBuildCondBr(g->builder, cond_val, ok_block, err_block); - - LLVMPositionBuilderAtEnd(g->builder, err_block); - gen_safety_crash_for_err(g, err_val, instruction->base.scope); - - LLVMPositionBuilderAtEnd(g->builder, ok_block); - } - - if (type_has_bits(g, payload_type)) { - if (instruction->initializing) { - LLVMValueRef err_tag_ptr = LLVMBuildStructGEP2(g->builder, err_union_llvm_ty, - err_union_handle, err_union_err_index, ""); - LLVMValueRef ok_err_val = LLVMConstNull(get_llvm_type(g, g->err_tag_type)); - gen_store_untyped(g, ok_err_val, err_tag_ptr, 0, false); - } - return LLVMBuildStructGEP2(g->builder, err_union_llvm_ty, err_union_handle, - err_union_payload_index, ""); - } else { - if (instruction->initializing) { - gen_store_untyped(g, zero, err_union_ptr, 0, false); - } - return nullptr; - } -} - -static LLVMValueRef ir_render_optional_wrap(CodeGen *g, Stage1Air *executable, Stage1AirInstOptionalWrap *instruction) { - ZigType *wanted_type = instruction->base.value->type; - - assert(wanted_type->id == ZigTypeIdOptional); - - ZigType *child_type = wanted_type->data.maybe.child_type; - - if (!type_has_bits(g, child_type)) { - LLVMValueRef result = LLVMConstAllOnes(LLVMInt1Type()); - if (instruction->result_loc != nullptr) { - LLVMValueRef result_loc = ir_llvm_value(g, instruction->result_loc); - gen_store_untyped(g, result, result_loc, 0, false); - } - return result; - } - - LLVMValueRef payload_val = ir_llvm_value(g, instruction->operand); - if (!handle_is_ptr(g, wanted_type)) { - if (instruction->result_loc != nullptr) { - LLVMValueRef result_loc = ir_llvm_value(g, instruction->result_loc); - gen_store_untyped(g, payload_val, result_loc, 0, false); - } - return payload_val; - } - - LLVMValueRef result_loc = ir_llvm_value(g, instruction->result_loc); - LLVMTypeRef result_llvm_struct_ty = get_llvm_type(g, wanted_type); - - LLVMValueRef val_ptr = LLVMBuildStructGEP2(g->builder, result_llvm_struct_ty, result_loc, - maybe_child_index, ""); - // child_type and instruction->value->value->type may differ by constness - gen_assign_raw(g, val_ptr, get_pointer_to_type(g, child_type, false), payload_val); - LLVMValueRef maybe_ptr = LLVMBuildStructGEP2(g->builder, result_llvm_struct_ty, result_loc, - maybe_null_index, ""); - gen_store_untyped(g, LLVMConstAllOnes(LLVMInt1Type()), maybe_ptr, 0, false); - - return result_loc; -} - -static LLVMValueRef ir_render_err_wrap_code(CodeGen *g, Stage1Air *executable, Stage1AirInstErrWrapCode *instruction) { - ZigType *wanted_type = instruction->base.value->type; - - assert(wanted_type->id == ZigTypeIdErrorUnion); - - LLVMValueRef err_val = ir_llvm_value(g, instruction->operand); - - if (!handle_is_ptr(g, wanted_type)) - return err_val; - - LLVMValueRef result_loc = ir_llvm_value(g, instruction->result_loc); - - LLVMValueRef err_tag_ptr = LLVMBuildStructGEP2(g->builder, get_llvm_type(g, wanted_type), - result_loc, err_union_err_index, ""); - gen_store_untyped(g, err_val, err_tag_ptr, 0, false); - - // TODO store undef to the payload - - return result_loc; -} - -static LLVMValueRef ir_render_err_wrap_payload(CodeGen *g, Stage1Air *executable, Stage1AirInstErrWrapPayload *instruction) { - ZigType *wanted_type = instruction->base.value->type; - - assert(wanted_type->id == ZigTypeIdErrorUnion); - - ZigType *payload_type = wanted_type->data.error_union.payload_type; - ZigType *err_set_type = wanted_type->data.error_union.err_set_type; - - if (!type_has_bits(g, err_set_type)) { - return ir_llvm_value(g, instruction->operand); - } - - LLVMValueRef ok_err_val = LLVMConstNull(get_llvm_type(g, g->err_tag_type)); - - if (!type_has_bits(g, payload_type)) - return ok_err_val; - - - LLVMValueRef result_loc = ir_llvm_value(g, instruction->result_loc); - - LLVMValueRef payload_val = ir_llvm_value(g, instruction->operand); - LLVMTypeRef result_struct_llvm_ty = get_llvm_type(g, wanted_type); - - LLVMValueRef err_tag_ptr = LLVMBuildStructGEP2(g->builder, result_struct_llvm_ty, result_loc, - err_union_err_index, ""); - gen_store_untyped(g, ok_err_val, err_tag_ptr, 0, false); - - LLVMValueRef payload_ptr = LLVMBuildStructGEP2(g->builder, result_struct_llvm_ty, result_loc, - err_union_payload_index, ""); - gen_assign_raw(g, payload_ptr, get_pointer_to_type(g, payload_type, false), payload_val); - - return result_loc; -} - -static LLVMValueRef ir_render_union_tag(CodeGen *g, Stage1Air *executable, Stage1AirInstUnionTag *instruction) { - ZigType *union_type = instruction->value->value->type; - - ZigType *tag_type = union_type->data.unionation.tag_type; - if (!type_has_bits(g, tag_type)) - return nullptr; - - LLVMValueRef union_val = ir_llvm_value(g, instruction->value); - if (union_type->data.unionation.gen_field_count == 0) - return union_val; - - assert(union_type->data.unionation.gen_tag_index != SIZE_MAX); - LLVMValueRef tag_field_ptr = LLVMBuildStructGEP2(g->builder, - get_llvm_type(g, union_type), union_val, - union_type->data.unionation.gen_tag_index, ""); - ZigType *ptr_type = get_pointer_to_type(g, tag_type, false); - return get_handle_value(g, tag_field_ptr, tag_type, ptr_type); -} - -static LLVMValueRef ir_render_panic(CodeGen *g, Stage1Air *executable, Stage1AirInstPanic *instruction) { - bool is_llvm_alloca; - LLVMValueRef err_ret_trace_val = get_cur_err_ret_trace_val(g, instruction->base.scope, &is_llvm_alloca); - gen_panic(g, ir_llvm_value(g, instruction->msg), err_ret_trace_val, is_llvm_alloca); - return nullptr; -} - -static LLVMValueRef ir_render_atomic_rmw(CodeGen *g, Stage1Air *executable, - Stage1AirInstAtomicRmw *instruction) -{ - bool is_signed; - ZigType *operand_type = instruction->operand->value->type; - bool is_float = operand_type->id == ZigTypeIdFloat; - if (operand_type->id == ZigTypeIdInt) { - is_signed = operand_type->data.integral.is_signed; - } else { - is_signed = false; - } - LLVMAtomicRMWBinOp op = to_LLVMAtomicRMWBinOp(instruction->op, is_signed, is_float); - LLVMAtomicOrdering ordering = to_LLVMAtomicOrdering(instruction->ordering); - LLVMValueRef ptr = ir_llvm_value(g, instruction->ptr); - LLVMValueRef operand = ir_llvm_value(g, instruction->operand); - - LLVMTypeRef actual_abi_type = get_atomic_abi_type(g, instruction->ptr, - op == LLVMAtomicRMWBinOpXchg); - if (actual_abi_type != nullptr) { - // operand needs widening and truncating or bitcasting. - LLVMValueRef casted_ptr = LLVMBuildBitCast(g->builder, ptr, - LLVMPointerType(actual_abi_type, 0), ""); - LLVMValueRef casted_operand; - if (is_float) { - casted_operand = LLVMBuildBitCast(g->builder, operand, actual_abi_type, ""); - } else if (operand_type->data.integral.is_signed) { - casted_operand = LLVMBuildSExt(g->builder, operand, actual_abi_type, ""); - } else { - casted_operand = LLVMBuildZExt(g->builder, operand, actual_abi_type, ""); - } - LLVMValueRef uncasted_result = LLVMBuildAtomicRMW(g->builder, op, casted_ptr, casted_operand, ordering, - g->is_single_threaded); - if (is_float) { - return LLVMBuildBitCast(g->builder, uncasted_result, get_llvm_type(g, operand_type), ""); - } else { - return LLVMBuildTrunc(g->builder, uncasted_result, get_llvm_type(g, operand_type), ""); - } - } - - if (get_codegen_ptr_type_bail(g, operand_type) == nullptr) { - return LLVMBuildAtomicRMW(g->builder, op, ptr, operand, ordering, g->is_single_threaded); - } - - // it's a pointer but we need to treat it as an int - LLVMValueRef casted_ptr = LLVMBuildBitCast(g->builder, ptr, - LLVMPointerType(g->builtin_types.entry_usize->llvm_type, 0), ""); - LLVMValueRef casted_operand = LLVMBuildPtrToInt(g->builder, operand, g->builtin_types.entry_usize->llvm_type, ""); - LLVMValueRef uncasted_result = LLVMBuildAtomicRMW(g->builder, op, casted_ptr, casted_operand, ordering, - g->is_single_threaded); - return LLVMBuildIntToPtr(g->builder, uncasted_result, get_llvm_type(g, operand_type), ""); -} - -static LLVMValueRef ir_render_atomic_load(CodeGen *g, Stage1Air *executable, - Stage1AirInstAtomicLoad *instruction) -{ - LLVMAtomicOrdering ordering = to_LLVMAtomicOrdering(instruction->ordering); - LLVMValueRef ptr = ir_llvm_value(g, instruction->ptr); - - ZigType *operand_type = instruction->ptr->value->type->data.pointer.child_type; - LLVMTypeRef actual_abi_type = get_atomic_abi_type(g, instruction->ptr, false); - if (actual_abi_type != nullptr) { - // operand needs widening and truncating - ptr = LLVMBuildBitCast(g->builder, ptr, LLVMPointerType(actual_abi_type, 0), ""); - LLVMValueRef load_inst = gen_load_untyped(g, actual_abi_type, ptr, - get_ptr_align(g, instruction->ptr->value->type), - instruction->ptr->value->type->data.pointer.is_volatile, ""); - LLVMSetOrdering(load_inst, ordering); - return LLVMBuildTrunc(g->builder, load_inst, get_llvm_type(g, operand_type), ""); - } - LLVMValueRef load_inst = gen_load(g, ptr, instruction->ptr->value->type, ""); - LLVMSetOrdering(load_inst, ordering); - return load_inst; -} - -static LLVMValueRef ir_render_atomic_store(CodeGen *g, Stage1Air *executable, - Stage1AirInstAtomicStore *instruction) -{ - LLVMAtomicOrdering ordering = to_LLVMAtomicOrdering(instruction->ordering); - LLVMValueRef ptr = ir_llvm_value(g, instruction->ptr); - LLVMValueRef value = ir_llvm_value(g, instruction->value); - - LLVMTypeRef actual_abi_type = get_atomic_abi_type(g, instruction->ptr, false); - if (actual_abi_type != nullptr) { - // operand needs widening - ptr = LLVMBuildBitCast(g->builder, ptr, - LLVMPointerType(actual_abi_type, 0), ""); - if (instruction->value->value->type->data.integral.is_signed) { - value = LLVMBuildSExt(g->builder, value, actual_abi_type, ""); - } else { - value = LLVMBuildZExt(g->builder, value, actual_abi_type, ""); - } - } - LLVMValueRef store_inst = gen_store(g, value, ptr, instruction->ptr->value->type); - LLVMSetOrdering(store_inst, ordering); - return nullptr; -} - -static LLVMValueRef ir_render_float_op(CodeGen *g, Stage1Air *executable, Stage1AirInstFloatOp *instruction) { - LLVMValueRef operand = ir_llvm_value(g, instruction->operand); - ZigType *operand_type = instruction->operand->value->type; - return gen_float_un_op(g, operand, operand_type, instruction->fn_id); -} - -static LLVMValueRef ir_render_soft_mul_add(CodeGen *g, Stage1Air *executable, Stage1AirInstMulAdd *instruction, ZigType *float_type) { - ZigType *operand_type = instruction->op1->value->type; - uint32_t vector_len = operand_type->id == ZigTypeIdVector ? operand_type->data.vector.len : 0; - - const char *fn_name; - if (float_type == g->builtin_types.entry_f16) - fn_name = "__fmah"; - else if (float_type == g->builtin_types.entry_f32) - fn_name = "fmaf"; - else if (float_type == g->builtin_types.entry_f64) - fn_name = "fma"; - else if (float_type == g->builtin_types.entry_f80) - fn_name = "__fmax"; - else if (float_type == g->builtin_types.entry_f128) - fn_name = "fmaq"; - else - zig_unreachable(); - - LLVMTypeRef float_type_ref = float_type->llvm_type; - LLVMValueRef func_ref = get_soft_float_fn(g, fn_name, 3, float_type_ref, float_type_ref); - - LLVMValueRef op1 = ir_llvm_value(g, instruction->op1); - LLVMValueRef op2 = ir_llvm_value(g, instruction->op2); - LLVMValueRef op3 = ir_llvm_value(g, instruction->op3); - if (vector_len == 0) { - LLVMValueRef params[3] = { op1, op2, op3 }; - return LLVMBuildCall2(g->builder, LLVMGlobalGetValueType(func_ref), func_ref, params, 3, ""); - } - - LLVMValueRef result = LLVMGetUndef(get_llvm_type(g, instruction->op1->value->type)); - LLVMTypeRef usize_ref = g->builtin_types.entry_usize->llvm_type; - for (uint32_t i = 0; i < vector_len; i++) { - LLVMValueRef index_value = LLVMConstInt(usize_ref, i, false); - - LLVMValueRef params[3] = { - LLVMBuildExtractElement(g->builder, op1, index_value, ""), - LLVMBuildExtractElement(g->builder, op2, index_value, ""), - LLVMBuildExtractElement(g->builder, op3, index_value, ""), - }; - LLVMValueRef call_result = LLVMBuildCall2(g->builder, LLVMGlobalGetValueType(func_ref), func_ref, params, 3, ""); - result = LLVMBuildInsertElement(g->builder, result, call_result, index_value, ""); - } - return result; -} - -static LLVMValueRef ir_render_mul_add(CodeGen *g, Stage1Air *executable, Stage1AirInstMulAdd *instruction) { - ZigType *operand_type = instruction->op1->value->type; - operand_type = operand_type->id == ZigTypeIdVector ? operand_type->data.vector.elem_type : operand_type; - if ((operand_type == g->builtin_types.entry_f80 && !target_has_f80(g->zig_target)) || - (operand_type == g->builtin_types.entry_f128 && !target_long_double_is_f128(g->zig_target)) || - (operand_type == g->builtin_types.entry_f16 && !target_is_arm(g->zig_target))) { - return ir_render_soft_mul_add(g, executable, instruction, operand_type); - } - LLVMValueRef op1 = ir_llvm_value(g, instruction->op1); - LLVMValueRef op2 = ir_llvm_value(g, instruction->op2); - LLVMValueRef op3 = ir_llvm_value(g, instruction->op3); - assert(instruction->base.value->type->id == ZigTypeIdFloat || - instruction->base.value->type->id == ZigTypeIdVector); - LLVMValueRef fn_val = get_float_fn(g, instruction->base.value->type, ZigLLVMFnIdFMA, BuiltinFnIdMulAdd); - LLVMValueRef args[3] = { op1, op2, op3 }; - return LLVMBuildCall2(g->builder, LLVMGlobalGetValueType(fn_val), fn_val, args, 3, ""); -} - -static LLVMValueRef ir_render_bswap(CodeGen *g, Stage1Air *executable, Stage1AirInstBswap *instruction) { - LLVMValueRef op = ir_llvm_value(g, instruction->op); - ZigType *expr_type = instruction->base.value->type; - bool is_vector = expr_type->id == ZigTypeIdVector; - ZigType *int_type = is_vector ? expr_type->data.vector.elem_type : expr_type; - assert(int_type->id == ZigTypeIdInt); - if (int_type->data.integral.bit_count % 16 == 0) { - LLVMValueRef fn_val = get_int_builtin_fn(g, expr_type, BuiltinFnIdBswap); - return LLVMBuildCall2(g->builder, LLVMGlobalGetValueType(fn_val), fn_val, &op, 1, ""); - } - // Not an even number of bytes, so we zext 1 byte, then bswap, shift right 1 byte, truncate - ZigType *extended_type = get_int_type(g, int_type->data.integral.is_signed, - int_type->data.integral.bit_count + 8); - LLVMValueRef shift_amt = LLVMConstInt(get_llvm_type(g, extended_type), 8, false); - if (is_vector) { - extended_type = get_vector_type(g, expr_type->data.vector.len, extended_type); - LLVMValueRef *values = heap::c_allocator.allocate_nonzero(expr_type->data.vector.len); - for (uint32_t i = 0; i < expr_type->data.vector.len; i += 1) { - values[i] = shift_amt; - } - shift_amt = LLVMConstVector(values, expr_type->data.vector.len); - heap::c_allocator.deallocate(values, expr_type->data.vector.len); - } - // aabbcc - LLVMValueRef extended = LLVMBuildZExt(g->builder, op, get_llvm_type(g, extended_type), ""); - // 00aabbcc - LLVMValueRef fn_val = get_int_builtin_fn(g, extended_type, BuiltinFnIdBswap); - LLVMValueRef swapped = LLVMBuildCall2(g->builder, LLVMGlobalGetValueType(fn_val), fn_val, &extended, 1, ""); - // ccbbaa00 - LLVMValueRef shifted = ZigLLVMBuildLShrExact(g->builder, swapped, shift_amt, ""); - // 00ccbbaa - return LLVMBuildTrunc(g->builder, shifted, get_llvm_type(g, expr_type), ""); -} - -static LLVMValueRef ir_render_extern(CodeGen *g, Stage1Air *executable, - Stage1AirInstExtern *instruction) -{ - ZigType *expr_type = instruction->base.value->type; - assert(get_src_ptr_type(expr_type)); - - const char *symbol_name = buf_ptr(instruction->name); - const LLVMLinkage linkage = to_llvm_linkage(instruction->linkage, true); - - LLVMValueRef global_value = LLVMGetNamedGlobal(g->module, symbol_name); - if (global_value == nullptr) { - global_value = LLVMAddGlobal(g->module, get_llvm_type(g, expr_type), symbol_name); - LLVMSetLinkage(global_value, linkage); - LLVMSetGlobalConstant(global_value, true); - if (instruction->is_thread_local) - LLVMSetThreadLocalMode(global_value, LLVMGeneralDynamicTLSModel); - } else if (LLVMGetLinkage(global_value) != linkage) { - // XXX: Handle this case better! - zig_panic("duplicate extern symbol"); - } - - return LLVMBuildBitCast(g->builder, global_value, get_llvm_type(g, expr_type), ""); -} - -static LLVMValueRef ir_render_bit_reverse(CodeGen *g, Stage1Air *executable, Stage1AirInstBitReverse *instruction) { - LLVMValueRef op = ir_llvm_value(g, instruction->op); - ZigType *int_type = instruction->base.value->type; - assert(int_type->id == ZigTypeIdInt); - LLVMValueRef fn_val = get_int_builtin_fn(g, instruction->base.value->type, BuiltinFnIdBitReverse); - return LLVMBuildCall2(g->builder, LLVMGlobalGetValueType(fn_val), fn_val, &op, 1, ""); -} - -static LLVMValueRef ir_render_vector_to_array(CodeGen *g, Stage1Air *executable, - Stage1AirInstVectorToArray *instruction) -{ - ZigType *array_type = instruction->base.value->type; - assert(array_type->id == ZigTypeIdArray); - assert(handle_is_ptr(g, array_type)); - LLVMValueRef result_loc = ir_llvm_value(g, instruction->result_loc); - LLVMValueRef vector = ir_llvm_value(g, instruction->vector); - - ZigType *elem_type = array_type->data.array.child_type; - bool bitcast_ok = elem_type->size_in_bits == elem_type->abi_size * 8; - if (bitcast_ok) { - LLVMValueRef casted_ptr = LLVMBuildBitCast(g->builder, result_loc, - LLVMPointerType(get_llvm_type(g, instruction->vector->value->type), 0), ""); - uint32_t alignment = get_ptr_align(g, instruction->result_loc->value->type); - gen_store_untyped(g, vector, casted_ptr, alignment, false); - } else { - // If the ABI size of the element type is not evenly divisible by size_in_bits, a simple bitcast - // will not work, and we fall back to extractelement. - LLVMTypeRef usize_type_ref = g->builtin_types.entry_usize->llvm_type; - LLVMTypeRef u32_type_ref = LLVMInt32Type(); - LLVMValueRef zero = LLVMConstInt(usize_type_ref, 0, false); - LLVMTypeRef array_llvm_ty = get_llvm_type(g, array_type); - for (uintptr_t i = 0; i < instruction->vector->value->type->data.vector.len; i++) { - LLVMValueRef index_usize = LLVMConstInt(usize_type_ref, i, false); - LLVMValueRef index_u32 = LLVMConstInt(u32_type_ref, i, false); - LLVMValueRef indexes[] = { zero, index_usize }; - LLVMValueRef elem_ptr = LLVMBuildInBoundsGEP2(g->builder, array_llvm_ty, result_loc, indexes, 2, ""); - LLVMValueRef elem = LLVMBuildExtractElement(g->builder, vector, index_u32, ""); - LLVMBuildStore(g->builder, elem, elem_ptr); - } - } - return result_loc; -} - -static LLVMValueRef ir_render_array_to_vector(CodeGen *g, Stage1Air *executable, - Stage1AirInstArrayToVector *instruction) -{ - ZigType *vector_type = instruction->base.value->type; - assert(vector_type->id == ZigTypeIdVector); - assert(!handle_is_ptr(g, vector_type)); - LLVMValueRef array_ptr = ir_llvm_value(g, instruction->array); - LLVMTypeRef vector_type_ref = get_llvm_type(g, vector_type); - - ZigType *elem_type = vector_type->data.vector.elem_type; - bool bitcast_ok = elem_type->size_in_bits == elem_type->abi_size * 8; - ZigType *array_type = instruction->array->value->type; - ir_assert(array_type->id == ZigTypeIdArray, &instruction->base); - if (bitcast_ok) { - LLVMValueRef casted_ptr = LLVMBuildBitCast(g->builder, array_ptr, - LLVMPointerType(vector_type_ref, 0), ""); - uint32_t alignment = get_abi_alignment(g, array_type->data.array.child_type); - return gen_load_untyped(g, vector_type_ref, casted_ptr, alignment, false, ""); - } else { - // If the ABI size of the element type is not evenly divisible by size_in_bits, a simple bitcast - // will not work, and we fall back to insertelement. - LLVMTypeRef usize_type_ref = g->builtin_types.entry_usize->llvm_type; - LLVMTypeRef u32_type_ref = LLVMInt32Type(); - LLVMValueRef zero = LLVMConstInt(usize_type_ref, 0, false); - LLVMValueRef vector = LLVMGetUndef(vector_type_ref); - LLVMTypeRef array_llvm_ty = get_llvm_type(g, array_type); - LLVMTypeRef elem_llvm_ty = get_llvm_type(g, elem_type); - for (uintptr_t i = 0; i < instruction->base.value->type->data.vector.len; i++) { - LLVMValueRef index_usize = LLVMConstInt(usize_type_ref, i, false); - LLVMValueRef index_u32 = LLVMConstInt(u32_type_ref, i, false); - LLVMValueRef indexes[] = { zero, index_usize }; - LLVMValueRef elem_ptr = LLVMBuildInBoundsGEP2(g->builder, array_llvm_ty, array_ptr, - indexes, 2, ""); - LLVMValueRef elem = LLVMBuildLoad2(g->builder, elem_llvm_ty, elem_ptr, ""); - vector = LLVMBuildInsertElement(g->builder, vector, elem, index_u32, ""); - } - return vector; - } -} - -static LLVMValueRef ir_render_assert_zero(CodeGen *g, Stage1Air *executable, - Stage1AirInstAssertZero *instruction) -{ - LLVMValueRef target = ir_llvm_value(g, instruction->target); - ZigType *int_type = instruction->target->value->type; - if (ir_want_runtime_safety(g, &instruction->base)) { - return gen_assert_zero(g, target, int_type); - } - return nullptr; -} - -static LLVMValueRef ir_render_assert_non_null(CodeGen *g, Stage1Air *executable, - Stage1AirInstAssertNonNull *instruction) -{ - LLVMValueRef target = ir_llvm_value(g, instruction->target); - ZigType *target_type = instruction->target->value->type; - - if (target_type->id == ZigTypeIdPointer) { - assert(target_type->data.pointer.ptr_len == PtrLenC); - LLVMValueRef non_null_bit = LLVMBuildICmp(g->builder, LLVMIntNE, target, - LLVMConstNull(get_llvm_type(g, target_type)), ""); - - LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "AssertNonNullFail"); - LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "AssertNonNullOk"); - LLVMBuildCondBr(g->builder, non_null_bit, ok_block, fail_block); - - LLVMPositionBuilderAtEnd(g->builder, fail_block); - gen_assertion(g, PanicMsgIdUnwrapOptionalFail, &instruction->base); - - LLVMPositionBuilderAtEnd(g->builder, ok_block); - } else { - zig_unreachable(); - } - return nullptr; -} - -static LLVMValueRef ir_render_suspend_begin(CodeGen *g, Stage1Air *executable, - Stage1AirInstSuspendBegin *instruction) -{ - if (fn_is_async(g->cur_fn)) { - instruction->resume_bb = gen_suspend_begin(g, "SuspendResume"); - } - return nullptr; -} - -static LLVMValueRef ir_render_suspend_finish(CodeGen *g, Stage1Air *executable, - Stage1AirInstSuspendFinish *instruction) -{ - LLVMBuildRetVoid(g->builder); - - LLVMPositionBuilderAtEnd(g->builder, instruction->begin->resume_bb); - if (ir_want_runtime_safety(g, &instruction->base)) { - LLVMBuildStore(g->builder, g->cur_bad_not_suspended_index, g->cur_async_resume_index_ptr); - } - render_async_var_decls(g, instruction->base.scope); - return nullptr; -} - -static LLVMValueRef gen_await_early_return(CodeGen *g, Stage1AirInst *source_instr, - LLVMTypeRef target_frame_struct_llvm_ty, LLVMValueRef target_frame_ptr, - ZigType *result_type, ZigType *ptr_result_type, LLVMValueRef result_loc, bool non_async) -{ - LLVMTypeRef usize_type_ref = g->builtin_types.entry_usize->llvm_type; - LLVMValueRef their_result_ptr = nullptr; - if (type_has_bits(g, result_type) && (non_async || result_loc != nullptr)) { - LLVMValueRef their_result_ptr_ptr = LLVMBuildStructGEP2(g->builder, - target_frame_struct_llvm_ty, target_frame_ptr, frame_ret_start, ""); - their_result_ptr = LLVMBuildLoad2(g->builder, - ZigLLVMGetGEPResultElementType(their_result_ptr_ptr), their_result_ptr_ptr, ""); - if (result_loc != nullptr) { - LLVMTypeRef ptr_u8 = LLVMPointerType(LLVMInt8Type(), 0); - LLVMValueRef dest_ptr_casted = LLVMBuildBitCast(g->builder, result_loc, ptr_u8, ""); - LLVMValueRef src_ptr_casted = LLVMBuildBitCast(g->builder, their_result_ptr, ptr_u8, ""); - bool is_volatile = false; - uint32_t abi_align = get_abi_alignment(g, result_type); - LLVMValueRef byte_count_val = LLVMConstInt(usize_type_ref, type_size(g, result_type), false); - ZigLLVMBuildMemCpy(g->builder, - dest_ptr_casted, abi_align, - src_ptr_casted, abi_align, byte_count_val, is_volatile); - } - } - if (codegen_fn_has_err_ret_tracing_arg(g, result_type)) { - LLVMValueRef their_trace_ptr_ptr = LLVMBuildStructGEP2(g->builder, - target_frame_struct_llvm_ty, target_frame_ptr, - frame_index_trace_arg(g, result_type), ""); - LLVMValueRef src_trace_ptr = LLVMBuildLoad2(g->builder, - ZigLLVMGetGEPResultElementType(their_trace_ptr_ptr), their_trace_ptr_ptr, ""); - bool is_llvm_alloca; - LLVMValueRef dest_trace_ptr = get_cur_err_ret_trace_val(g, source_instr->scope, &is_llvm_alloca); - LLVMValueRef args[] = { dest_trace_ptr, src_trace_ptr }; - ZigLLVMBuildCall(g->builder, LLVMGlobalGetValueType(get_merge_err_ret_traces_fn_val(g)), - get_merge_err_ret_traces_fn_val(g), args, 2, - get_llvm_cc(g, CallingConventionUnspecified), ZigLLVM_CallAttrAuto, ""); - } - if (non_async && type_has_bits(g, result_type)) { - LLVMValueRef result_ptr = (result_loc == nullptr) ? their_result_ptr : result_loc; - return get_handle_value(g, result_ptr, result_type, ptr_result_type); - } else { - return nullptr; - } -} - -static LLVMValueRef ir_render_await(CodeGen *g, Stage1Air *executable, Stage1AirInstAwait *instruction) { - LLVMTypeRef usize_type_ref = g->builtin_types.entry_usize->llvm_type; - LLVMValueRef zero = LLVMConstNull(usize_type_ref); - LLVMValueRef target_frame_ptr = ir_llvm_value(g, instruction->frame); - ir_assert(instruction->frame->value->type->id == ZigTypeIdAnyFrame, &instruction->base); - LLVMTypeRef target_frame_llvm_ty = instruction->frame->value->type->data.any_frame.struct_llvm_ty; - ZigType *result_type = instruction->base.value->type; - ZigType *ptr_result_type = get_pointer_to_type(g, result_type, true); - - LLVMValueRef result_loc = (instruction->result_loc == nullptr) ? - nullptr : ir_llvm_value(g, instruction->result_loc); - - if (instruction->is_nosuspend || - (instruction->target_fn != nullptr && !fn_is_async(instruction->target_fn))) - { - return gen_await_early_return(g, &instruction->base, target_frame_llvm_ty, - target_frame_ptr, result_type, ptr_result_type, result_loc, true); - } - - // Prepare to be suspended - LLVMBasicBlockRef resume_bb = gen_suspend_begin(g, "AwaitResume"); - LLVMBasicBlockRef end_bb = LLVMAppendBasicBlock(g->cur_fn_val, "AwaitEnd"); - - // At this point resuming the function will continue from resume_bb. - // This code is as if it is running inside the suspend block. - - // supply the awaiter return pointer - if (type_has_bits(g, result_type)) { - LLVMValueRef awaiter_ret_ptr_ptr = LLVMBuildStructGEP2(g->builder, target_frame_llvm_ty, - target_frame_ptr, frame_ret_start + 1, ""); - if (result_loc == nullptr) { - // no copy needed - LLVMBuildStore(g->builder, LLVMConstNull(ZigLLVMGetGEPResultElementType(awaiter_ret_ptr_ptr)), - awaiter_ret_ptr_ptr); - } else { - LLVMBuildStore(g->builder, result_loc, awaiter_ret_ptr_ptr); - } - } - - // supply the error return trace pointer - if (codegen_fn_has_err_ret_tracing_arg(g, result_type)) { - bool is_llvm_alloca; - LLVMValueRef my_err_ret_trace_val = get_cur_err_ret_trace_val(g, instruction->base.scope, &is_llvm_alloca); - assert(my_err_ret_trace_val != nullptr); - LLVMValueRef err_ret_trace_ptr_ptr = LLVMBuildStructGEP2(g->builder, target_frame_llvm_ty, - target_frame_ptr, frame_index_trace_arg(g, result_type) + 1, ""); - LLVMBuildStore(g->builder, my_err_ret_trace_val, err_ret_trace_ptr_ptr); - } - - // caller's own frame pointer - LLVMValueRef awaiter_init_val = LLVMBuildPtrToInt(g->builder, g->cur_frame_ptr, usize_type_ref, ""); - LLVMValueRef awaiter_ptr = LLVMBuildStructGEP2(g->builder, target_frame_llvm_ty, - target_frame_ptr, frame_awaiter_index, ""); - LLVMValueRef prev_val = gen_maybe_atomic_op(g, LLVMAtomicRMWBinOpXchg, awaiter_ptr, awaiter_init_val, - LLVMAtomicOrderingRelease); - - LLVMBasicBlockRef bad_await_block = LLVMAppendBasicBlock(g->cur_fn_val, "BadAwait"); - LLVMBasicBlockRef complete_suspend_block = LLVMAppendBasicBlock(g->cur_fn_val, "CompleteSuspend"); - LLVMBasicBlockRef early_return_block = LLVMAppendBasicBlock(g->cur_fn_val, "EarlyReturn"); - - LLVMValueRef all_ones = LLVMConstAllOnes(usize_type_ref); - LLVMValueRef switch_instr = LLVMBuildSwitch(g->builder, prev_val, bad_await_block, 2); - - LLVMAddCase(switch_instr, zero, complete_suspend_block); - LLVMAddCase(switch_instr, all_ones, early_return_block); - - // We discovered that another awaiter was already here. - LLVMPositionBuilderAtEnd(g->builder, bad_await_block); - gen_assertion(g, PanicMsgIdBadAwait, &instruction->base); - - // Rely on the target to resume us from suspension. - LLVMPositionBuilderAtEnd(g->builder, complete_suspend_block); - LLVMBuildRetVoid(g->builder); - - // Early return: The async function has already completed. We must copy the result and - // the error return trace if applicable. - LLVMPositionBuilderAtEnd(g->builder, early_return_block); - gen_await_early_return(g, &instruction->base, target_frame_llvm_ty, target_frame_ptr, - result_type, ptr_result_type, result_loc, false); - LLVMBuildBr(g->builder, end_bb); - - LLVMPositionBuilderAtEnd(g->builder, resume_bb); - gen_assert_resume_id(g, &instruction->base, ResumeIdReturn, PanicMsgIdResumedAnAwaitingFn, nullptr); - LLVMBuildBr(g->builder, end_bb); - - LLVMPositionBuilderAtEnd(g->builder, end_bb); - // Rely on the spill for the llvm_value to be populated. - // See the implementation of ir_llvm_value. - return nullptr; -} - -static LLVMValueRef ir_render_resume(CodeGen *g, Stage1Air *executable, Stage1AirInstResume *instruction) { - LLVMValueRef frame = ir_llvm_value(g, instruction->frame); - ZigType *frame_type = instruction->frame->value->type; - assert(frame_type->id == ZigTypeIdAnyFrame); - - gen_resume(g, g->anyframe_fn_type, nullptr, frame, ResumeIdManual); - return nullptr; -} - -static LLVMValueRef ir_render_frame_size(CodeGen *g, Stage1Air *executable, - Stage1AirInstFrameSize *instruction) -{ - LLVMValueRef fn_val = ir_llvm_value(g, instruction->fn); - return gen_frame_size(g, fn_val); -} - -static LLVMValueRef ir_render_spill_begin(CodeGen *g, Stage1Air *executable, - Stage1AirInstSpillBegin *instruction) -{ - if (!fn_is_async(g->cur_fn)) - return nullptr; - - switch (instruction->spill_id) { - case SpillIdInvalid: - zig_unreachable(); - case SpillIdRetErrCode: { - LLVMValueRef operand = ir_llvm_value(g, instruction->operand); - LLVMValueRef ptr = ir_llvm_value(g, g->cur_fn->err_code_spill); - LLVMBuildStore(g->builder, operand, ptr); - return nullptr; - } - - } - zig_unreachable(); -} - -static LLVMValueRef ir_render_spill_end(CodeGen *g, Stage1Air *executable, Stage1AirInstSpillEnd *instruction) { - if (!fn_is_async(g->cur_fn)) - return ir_llvm_value(g, instruction->begin->operand); - - switch (instruction->begin->spill_id) { - case SpillIdInvalid: - zig_unreachable(); - case SpillIdRetErrCode: { - LLVMValueRef ptr = ir_llvm_value(g, g->cur_fn->err_code_spill); - LLVMTypeRef llvm_ty = g->builtin_types.entry_global_error_set->llvm_type; - return LLVMBuildLoad2(g->builder, llvm_ty, ptr, ""); - } - - } - zig_unreachable(); -} - -static LLVMValueRef ir_render_vector_extract_elem(CodeGen *g, Stage1Air *executable, - Stage1AirInstVectorExtractElem *instruction) -{ - LLVMValueRef vector = ir_llvm_value(g, instruction->vector); - LLVMValueRef index = ir_llvm_value(g, instruction->index); - return LLVMBuildExtractElement(g->builder, vector, index, ""); -} - -static void set_debug_location(CodeGen *g, Stage1AirInst *instruction) { - AstNode *source_node = instruction->source_node; - Scope *scope = instruction->scope; - - assert(source_node); - assert(scope); - - ZigLLVMSetCurrentDebugLocation(g->builder, node_line_onebased(source_node), - node_column_onebased(source_node), get_di_scope(g, scope)); -} - -static LLVMValueRef ir_render_instruction(CodeGen *g, Stage1Air *executable, Stage1AirInst *instruction) { - switch (instruction->id) { - case Stage1AirInstIdInvalid: - case Stage1AirInstIdConst: - case Stage1AirInstIdAlloca: - zig_unreachable(); - - case Stage1AirInstIdDeclVar: - return ir_render_decl_var(g, executable, (Stage1AirInstDeclVar *)instruction); - case Stage1AirInstIdReturn: - return ir_render_return(g, executable, (Stage1AirInstReturn *)instruction); - case Stage1AirInstIdBinOp: - return ir_render_bin_op(g, executable, (Stage1AirInstBinOp *)instruction); - case Stage1AirInstIdCast: - return ir_render_cast(g, executable, (Stage1AirInstCast *)instruction); - case Stage1AirInstIdUnreachable: - return ir_render_unreachable(g, executable, (Stage1AirInstUnreachable *)instruction); - case Stage1AirInstIdCondBr: - return ir_render_cond_br(g, executable, (Stage1AirInstCondBr *)instruction); - case Stage1AirInstIdBr: - return ir_render_br(g, executable, (Stage1AirInstBr *)instruction); - case Stage1AirInstIdBinaryNot: - return ir_render_binary_not(g, executable, (Stage1AirInstBinaryNot *)instruction); - case Stage1AirInstIdNegation: - return ir_render_negation(g, executable, (Stage1AirInstNegation *)instruction); - case Stage1AirInstIdLoadPtr: - return ir_render_load_ptr(g, executable, (Stage1AirInstLoadPtr *)instruction); - case Stage1AirInstIdStorePtr: - return ir_render_store_ptr(g, executable, (Stage1AirInstStorePtr *)instruction); - case Stage1AirInstIdVectorStoreElem: - return ir_render_vector_store_elem(g, executable, (Stage1AirInstVectorStoreElem *)instruction); - case Stage1AirInstIdVarPtr: - return ir_render_var_ptr(g, executable, (Stage1AirInstVarPtr *)instruction); - case Stage1AirInstIdReturnPtr: - return ir_render_return_ptr(g, executable, (Stage1AirInstReturnPtr *)instruction); - case Stage1AirInstIdElemPtr: - return ir_render_elem_ptr(g, executable, (Stage1AirInstElemPtr *)instruction); - case Stage1AirInstIdCall: - return ir_render_call(g, executable, (Stage1AirInstCall *)instruction); - case Stage1AirInstIdStructFieldPtr: - return ir_render_struct_field_ptr(g, executable, (Stage1AirInstStructFieldPtr *)instruction); - case Stage1AirInstIdUnionFieldPtr: - return ir_render_union_field_ptr(g, executable, (Stage1AirInstUnionFieldPtr *)instruction); - case Stage1AirInstIdAsm: - return ir_render_asm_gen(g, executable, (Stage1AirInstAsm *)instruction); - case Stage1AirInstIdTestNonNull: - return ir_render_test_non_null(g, executable, (Stage1AirInstTestNonNull *)instruction); - case Stage1AirInstIdOptionalUnwrapPtr: - return ir_render_optional_unwrap_ptr(g, executable, (Stage1AirInstOptionalUnwrapPtr *)instruction); - case Stage1AirInstIdClz: - return ir_render_clz(g, executable, (Stage1AirInstClz *)instruction); - case Stage1AirInstIdCtz: - return ir_render_ctz(g, executable, (Stage1AirInstCtz *)instruction); - case Stage1AirInstIdPopCount: - return ir_render_pop_count(g, executable, (Stage1AirInstPopCount *)instruction); - case Stage1AirInstIdSwitchBr: - return ir_render_switch_br(g, executable, (Stage1AirInstSwitchBr *)instruction); - case Stage1AirInstIdBswap: - return ir_render_bswap(g, executable, (Stage1AirInstBswap *)instruction); - case Stage1AirInstIdBitReverse: - return ir_render_bit_reverse(g, executable, (Stage1AirInstBitReverse *)instruction); - case Stage1AirInstIdPhi: - return ir_render_phi(g, executable, (Stage1AirInstPhi *)instruction); - case Stage1AirInstIdRef: - return ir_render_ref(g, executable, (Stage1AirInstRef *)instruction); - case Stage1AirInstIdErrName: - return ir_render_err_name(g, executable, (Stage1AirInstErrName *)instruction); - case Stage1AirInstIdCmpxchg: - return ir_render_cmpxchg(g, executable, (Stage1AirInstCmpxchg *)instruction); - case Stage1AirInstIdFence: - return ir_render_fence(g, executable, (Stage1AirInstFence *)instruction); - case Stage1AirInstIdReduce: - return ir_render_reduce(g, executable, (Stage1AirInstReduce *)instruction); - case Stage1AirInstIdTruncate: - return ir_render_truncate(g, executable, (Stage1AirInstTruncate *)instruction); - case Stage1AirInstIdBoolNot: - return ir_render_bool_not(g, executable, (Stage1AirInstBoolNot *)instruction); - case Stage1AirInstIdMemset: - return ir_render_memset(g, executable, (Stage1AirInstMemset *)instruction); - case Stage1AirInstIdMemcpy: - return ir_render_memcpy(g, executable, (Stage1AirInstMemcpy *)instruction); - case Stage1AirInstIdSlice: - return ir_render_slice(g, executable, (Stage1AirInstSlice *)instruction); - case Stage1AirInstIdBreakpoint: - return ir_render_breakpoint(g, executable, (Stage1AirInstBreakpoint *)instruction); - case Stage1AirInstIdReturnAddress: - return ir_render_return_address(g, executable, (Stage1AirInstReturnAddress *)instruction); - case Stage1AirInstIdFrameAddress: - return ir_render_frame_address(g, executable, (Stage1AirInstFrameAddress *)instruction); - case Stage1AirInstIdFrameHandle: - return ir_render_handle(g, executable, (Stage1AirInstFrameHandle *)instruction); - case Stage1AirInstIdOverflowOp: - return ir_render_overflow_op(g, executable, (Stage1AirInstOverflowOp *)instruction); - case Stage1AirInstIdTestErr: - return ir_render_test_err(g, executable, (Stage1AirInstTestErr *)instruction); - case Stage1AirInstIdUnwrapErrCode: - return ir_render_unwrap_err_code(g, executable, (Stage1AirInstUnwrapErrCode *)instruction); - case Stage1AirInstIdUnwrapErrPayload: - return ir_render_unwrap_err_payload(g, executable, (Stage1AirInstUnwrapErrPayload *)instruction); - case Stage1AirInstIdOptionalWrap: - return ir_render_optional_wrap(g, executable, (Stage1AirInstOptionalWrap *)instruction); - case Stage1AirInstIdErrWrapCode: - return ir_render_err_wrap_code(g, executable, (Stage1AirInstErrWrapCode *)instruction); - case Stage1AirInstIdErrWrapPayload: - return ir_render_err_wrap_payload(g, executable, (Stage1AirInstErrWrapPayload *)instruction); - case Stage1AirInstIdUnionTag: - return ir_render_union_tag(g, executable, (Stage1AirInstUnionTag *)instruction); - case Stage1AirInstIdPtrCast: - return ir_render_ptr_cast(g, executable, (Stage1AirInstPtrCast *)instruction); - case Stage1AirInstIdBitCast: - return ir_render_bit_cast(g, executable, (Stage1AirInstBitCast *)instruction); - case Stage1AirInstIdWidenOrShorten: - return ir_render_widen_or_shorten(g, executable, (Stage1AirInstWidenOrShorten *)instruction); - case Stage1AirInstIdPtrToInt: - return ir_render_ptr_to_int(g, executable, (Stage1AirInstPtrToInt *)instruction); - case Stage1AirInstIdIntToPtr: - return ir_render_int_to_ptr(g, executable, (Stage1AirInstIntToPtr *)instruction); - case Stage1AirInstIdIntToEnum: - return ir_render_int_to_enum(g, executable, (Stage1AirInstIntToEnum *)instruction); - case Stage1AirInstIdIntToErr: - return ir_render_int_to_err(g, executable, (Stage1AirInstIntToErr *)instruction); - case Stage1AirInstIdErrToInt: - return ir_render_err_to_int(g, executable, (Stage1AirInstErrToInt *)instruction); - case Stage1AirInstIdPanic: - return ir_render_panic(g, executable, (Stage1AirInstPanic *)instruction); - case Stage1AirInstIdTagName: - return ir_render_enum_tag_name(g, executable, (Stage1AirInstTagName *)instruction); - case Stage1AirInstIdFieldParentPtr: - return ir_render_field_parent_ptr(g, executable, (Stage1AirInstFieldParentPtr *)instruction); - case Stage1AirInstIdAlignCast: - return ir_render_align_cast(g, executable, (Stage1AirInstAlignCast *)instruction); - case Stage1AirInstIdErrorReturnTrace: - return ir_render_error_return_trace(g, executable, (Stage1AirInstErrorReturnTrace *)instruction); - case Stage1AirInstIdAtomicRmw: - return ir_render_atomic_rmw(g, executable, (Stage1AirInstAtomicRmw *)instruction); - case Stage1AirInstIdAtomicLoad: - return ir_render_atomic_load(g, executable, (Stage1AirInstAtomicLoad *)instruction); - case Stage1AirInstIdAtomicStore: - return ir_render_atomic_store(g, executable, (Stage1AirInstAtomicStore *)instruction); - case Stage1AirInstIdSaveErrRetAddr: - return ir_render_save_err_ret_addr(g, executable, (Stage1AirInstSaveErrRetAddr *)instruction); - case Stage1AirInstIdFloatOp: - return ir_render_float_op(g, executable, (Stage1AirInstFloatOp *)instruction); - case Stage1AirInstIdMulAdd: - return ir_render_mul_add(g, executable, (Stage1AirInstMulAdd *)instruction); - case Stage1AirInstIdArrayToVector: - return ir_render_array_to_vector(g, executable, (Stage1AirInstArrayToVector *)instruction); - case Stage1AirInstIdVectorToArray: - return ir_render_vector_to_array(g, executable, (Stage1AirInstVectorToArray *)instruction); - case Stage1AirInstIdAssertZero: - return ir_render_assert_zero(g, executable, (Stage1AirInstAssertZero *)instruction); - case Stage1AirInstIdAssertNonNull: - return ir_render_assert_non_null(g, executable, (Stage1AirInstAssertNonNull *)instruction); - case Stage1AirInstIdPtrOfArrayToSlice: - return ir_render_ptr_of_array_to_slice(g, executable, (Stage1AirInstPtrOfArrayToSlice *)instruction); - case Stage1AirInstIdSuspendBegin: - return ir_render_suspend_begin(g, executable, (Stage1AirInstSuspendBegin *)instruction); - case Stage1AirInstIdSuspendFinish: - return ir_render_suspend_finish(g, executable, (Stage1AirInstSuspendFinish *)instruction); - case Stage1AirInstIdResume: - return ir_render_resume(g, executable, (Stage1AirInstResume *)instruction); - case Stage1AirInstIdFrameSize: - return ir_render_frame_size(g, executable, (Stage1AirInstFrameSize *)instruction); - case Stage1AirInstIdAwait: - return ir_render_await(g, executable, (Stage1AirInstAwait *)instruction); - case Stage1AirInstIdSpillBegin: - return ir_render_spill_begin(g, executable, (Stage1AirInstSpillBegin *)instruction); - case Stage1AirInstIdSpillEnd: - return ir_render_spill_end(g, executable, (Stage1AirInstSpillEnd *)instruction); - case Stage1AirInstIdShuffleVector: - return ir_render_shuffle_vector(g, executable, (Stage1AirInstShuffleVector *) instruction); - case Stage1AirInstIdSelect: - return ir_render_select(g, executable, (Stage1AirInstSelect *) instruction); - case Stage1AirInstIdSplat: - return ir_render_splat(g, executable, (Stage1AirInstSplat *) instruction); - case Stage1AirInstIdVectorExtractElem: - return ir_render_vector_extract_elem(g, executable, (Stage1AirInstVectorExtractElem *) instruction); - case Stage1AirInstIdWasmMemorySize: - return ir_render_wasm_memory_size(g, executable, (Stage1AirInstWasmMemorySize *) instruction); - case Stage1AirInstIdWasmMemoryGrow: - return ir_render_wasm_memory_grow(g, executable, (Stage1AirInstWasmMemoryGrow *) instruction); - case Stage1AirInstIdExtern: - return ir_render_extern(g, executable, (Stage1AirInstExtern *) instruction); - case Stage1AirInstIdPrefetch: - return ir_render_prefetch(g, executable, (Stage1AirInstPrefetch *) instruction); - } - zig_unreachable(); -} - -static void ir_render(CodeGen *g, ZigFn *fn_entry) { - assert(fn_entry); - - Stage1Air *executable = &fn_entry->analyzed_executable; - assert(executable->basic_block_list.length > 0); - - for (size_t block_i = 0; block_i < executable->basic_block_list.length; block_i += 1) { - Stage1AirBasicBlock *current_block = executable->basic_block_list.at(block_i); - if (get_scope_typeof(current_block->scope) != nullptr) { - LLVMBuildBr(g->builder, current_block->llvm_block); - } - assert(current_block->llvm_block); - LLVMPositionBuilderAtEnd(g->builder, current_block->llvm_block); - for (size_t instr_i = 0; instr_i < current_block->instruction_list.length; instr_i += 1) { - Stage1AirInst *instruction = current_block->instruction_list.at(instr_i); - if (instruction->ref_count == 0 && !ir_inst_gen_has_side_effects(instruction)) - continue; - if (get_scope_typeof(instruction->scope) != nullptr) - continue; - - if (!g->strip_debug_symbols) { - set_debug_location(g, instruction); - } - instruction->llvm_value = ir_render_instruction(g, executable, instruction); - if (instruction->spill != nullptr && instruction->llvm_value != nullptr) { - LLVMValueRef spill_ptr = ir_llvm_value(g, instruction->spill); - gen_assign_raw(g, spill_ptr, instruction->spill->value->type, instruction->llvm_value); - instruction->llvm_value = nullptr; - } - } - current_block->llvm_exit_block = LLVMGetInsertBlock(g->builder); - } -} - -static LLVMValueRef gen_const_ptr_struct_recursive(CodeGen *g, ZigValue *struct_const_val, size_t field_index); -static LLVMValueRef gen_const_ptr_array_recursive(CodeGen *g, ZigValue *array_const_val, size_t index); -static LLVMValueRef gen_const_ptr_union_recursive(CodeGen *g, ZigValue *union_const_val); -static LLVMValueRef gen_const_ptr_err_union_code_recursive(CodeGen *g, ZigValue *err_union_const_val); -static LLVMValueRef gen_const_ptr_err_union_payload_recursive(CodeGen *g, ZigValue *err_union_const_val); -static LLVMValueRef gen_const_ptr_optional_payload_recursive(CodeGen *g, ZigValue *optional_const_val); - -static LLVMValueRef gen_parent_ptr(CodeGen *g, ZigValue *val, ConstParent *parent) { - switch (parent->id) { - case ConstParentIdNone: - render_const_val(g, val, ""); - render_const_val_global(g, val, ""); - return val->llvm_global; - case ConstParentIdStruct: { - ZigValue *struct_val = parent->data.p_struct.struct_val; - size_t src_field_index = parent->data.p_struct.field_index; - size_t gen_field_index = struct_val->type->data.structure.fields[src_field_index]->gen_index; - return gen_const_ptr_struct_recursive(g, struct_val, gen_field_index); - } - case ConstParentIdErrUnionCode: - return gen_const_ptr_err_union_code_recursive(g, parent->data.p_err_union_code.err_union_val); - case ConstParentIdErrUnionPayload: - return gen_const_ptr_err_union_payload_recursive(g, parent->data.p_err_union_payload.err_union_val); - case ConstParentIdOptionalPayload: - return gen_const_ptr_optional_payload_recursive(g, parent->data.p_optional_payload.optional_val); - case ConstParentIdArray: - return gen_const_ptr_array_recursive(g, parent->data.p_array.array_val, - parent->data.p_array.elem_index); - case ConstParentIdUnion: - return gen_const_ptr_union_recursive(g, parent->data.p_union.union_val); - case ConstParentIdScalar: - render_const_val(g, parent->data.p_scalar.scalar_val, ""); - render_const_val_global(g, parent->data.p_scalar.scalar_val, ""); - return parent->data.p_scalar.scalar_val->llvm_global; - } - zig_unreachable(); -} - -static LLVMValueRef gen_const_ptr_array_recursive(CodeGen *g, ZigValue *array_const_val, size_t index) { - expand_undef_array(g, array_const_val); - ConstParent *parent = &array_const_val->parent; - LLVMValueRef base_ptr = gen_parent_ptr(g, array_const_val, parent); - - ZigType *usize = g->builtin_types.entry_usize; - LLVMTypeRef array_llvm_ty = get_llvm_type(g, array_const_val->type); - LLVMValueRef casted_base_ptr = LLVMConstBitCast(base_ptr, LLVMPointerType(array_llvm_ty, 0)); - LLVMValueRef indices[] = { - LLVMConstNull(usize->llvm_type), - LLVMConstInt(usize->llvm_type, index, false), - }; - return LLVMConstInBoundsGEP2(array_llvm_ty, casted_base_ptr, indices, 2); -} - -static LLVMValueRef gen_const_ptr_struct_recursive(CodeGen *g, ZigValue *struct_const_val, size_t field_index) { - ConstParent *parent = &struct_const_val->parent; - LLVMValueRef base_ptr = gen_parent_ptr(g, struct_const_val, parent); - - LLVMValueRef indices[] = { - LLVMConstNull(LLVMInt32Type()), - LLVMConstInt(LLVMInt32Type(), field_index, false), - }; - - // The structure pointed by base_ptr may include trailing padding for - // alignment purposes and have the following LLVM type: <{ %T, [N x i8] }>. - // Add an extra bitcast as we're only interested in the %T part. - assert(handle_is_ptr(g, struct_const_val->type)); - - LLVMTypeRef struct_llvm_ty = get_llvm_type(g, struct_const_val->type); - LLVMValueRef casted_base_ptr = LLVMConstBitCast(base_ptr, LLVMPointerType(struct_llvm_ty, 0)); - return LLVMConstInBoundsGEP2(struct_llvm_ty, casted_base_ptr, indices, 2); -} - -static LLVMValueRef gen_const_ptr_err_union_code_recursive(CodeGen *g, ZigValue *err_union_const_val) { - ConstParent *parent = &err_union_const_val->parent; - LLVMValueRef base_ptr = gen_parent_ptr(g, err_union_const_val, parent); - - ZigType *u32 = g->builtin_types.entry_u32; - LLVMValueRef indices[] = { - LLVMConstNull(get_llvm_type(g, u32)), - LLVMConstInt(get_llvm_type(g, u32), err_union_err_index, false), - }; - return LLVMConstInBoundsGEP2(get_llvm_type(g, err_union_const_val->type), base_ptr, indices, 2); -} - -static LLVMValueRef gen_const_ptr_err_union_payload_recursive(CodeGen *g, ZigValue *err_union_const_val) { - ConstParent *parent = &err_union_const_val->parent; - LLVMValueRef base_ptr = gen_parent_ptr(g, err_union_const_val, parent); - - ZigType *u32 = g->builtin_types.entry_u32; - LLVMValueRef indices[] = { - LLVMConstNull(get_llvm_type(g, u32)), - LLVMConstInt(get_llvm_type(g, u32), err_union_payload_index, false), - }; - return LLVMConstInBoundsGEP2(get_llvm_type(g, err_union_const_val->type), base_ptr, indices, 2); -} - -static LLVMValueRef gen_const_ptr_optional_payload_recursive(CodeGen *g, ZigValue *optional_const_val) { - ConstParent *parent = &optional_const_val->parent; - LLVMValueRef base_ptr = gen_parent_ptr(g, optional_const_val, parent); - - ZigType *u32 = g->builtin_types.entry_u32; - LLVMValueRef indices[] = { - LLVMConstNull(get_llvm_type(g, u32)), - LLVMConstInt(get_llvm_type(g, u32), maybe_child_index, false), - }; - return LLVMConstInBoundsGEP2(get_llvm_type(g, optional_const_val->type), base_ptr, indices, 2); -} - -static LLVMValueRef gen_const_ptr_union_recursive(CodeGen *g, ZigValue *union_const_val) { - ConstParent *parent = &union_const_val->parent; - LLVMValueRef base_ptr = gen_parent_ptr(g, union_const_val, parent); - - // Slot in the structure where the payload is stored, if equal to SIZE_MAX - // the union has no tag and a single field and is collapsed into the field - // itself - size_t union_payload_index = union_const_val->type->data.unionation.gen_union_index; - - ZigType *u32 = g->builtin_types.entry_u32; - LLVMValueRef indices[] = { - LLVMConstNull(get_llvm_type(g, u32)), - LLVMConstInt(get_llvm_type(g, u32), union_payload_index, false), - }; - return LLVMConstInBoundsGEP2(get_llvm_type(g, union_const_val->type), base_ptr, indices, (union_payload_index != SIZE_MAX) ? 2 : 1); -} - -static LLVMValueRef pack_const_int(CodeGen *g, LLVMTypeRef big_int_type_ref, ZigValue *const_val) { - switch (const_val->special) { - case ConstValSpecialLazy: - case ConstValSpecialRuntime: - zig_unreachable(); - case ConstValSpecialUndef: - return LLVMConstInt(big_int_type_ref, 0, false); - case ConstValSpecialStatic: - break; - } - - ZigType *type_entry = const_val->type; - assert(type_has_bits(g, type_entry)); - switch (type_entry->id) { - case ZigTypeIdInvalid: - case ZigTypeIdMetaType: - case ZigTypeIdUnreachable: - case ZigTypeIdComptimeFloat: - case ZigTypeIdComptimeInt: - case ZigTypeIdEnumLiteral: - case ZigTypeIdUndefined: - case ZigTypeIdNull: - case ZigTypeIdErrorUnion: - case ZigTypeIdErrorSet: - case ZigTypeIdBoundFn: - case ZigTypeIdVoid: - case ZigTypeIdOpaque: - zig_unreachable(); - case ZigTypeIdBool: - return LLVMConstInt(big_int_type_ref, const_val->data.x_bool ? 1 : 0, false); - case ZigTypeIdEnum: - { - assert(type_entry->data.enumeration.decl_node->data.container_decl.init_arg_expr != nullptr); - LLVMValueRef int_val = gen_const_val(g, const_val, ""); - return LLVMConstZExt(int_val, big_int_type_ref); - } - case ZigTypeIdInt: - { - LLVMValueRef int_val = gen_const_val(g, const_val, ""); - return LLVMConstZExt(int_val, big_int_type_ref); - } - case ZigTypeIdFloat: - { - LLVMValueRef float_val = gen_const_val(g, const_val, ""); - LLVMValueRef int_val = LLVMConstFPToUI(float_val, - LLVMIntType((unsigned)type_entry->data.floating.bit_count)); - return LLVMConstZExt(int_val, big_int_type_ref); - } - case ZigTypeIdPointer: - case ZigTypeIdFn: - case ZigTypeIdOptional: - { - LLVMValueRef ptr_val = gen_const_val(g, const_val, ""); - LLVMValueRef ptr_size_int_val = LLVMConstPtrToInt(ptr_val, g->builtin_types.entry_usize->llvm_type); - return LLVMConstZExt(ptr_size_int_val, big_int_type_ref); - } - case ZigTypeIdArray: { - LLVMValueRef val = LLVMConstInt(big_int_type_ref, 0, false); - if (const_val->data.x_array.special == ConstArraySpecialUndef) { - return val; - } - expand_undef_array(g, const_val); - bool is_big_endian = g->is_big_endian; // TODO get endianness from struct type - uint32_t packed_bits_size = type_size_bits(g, type_entry->data.array.child_type); - size_t used_bits = 0; - for (size_t i = 0; i < type_entry->data.array.len; i += 1) { - ZigValue *elem_val = &const_val->data.x_array.data.s_none.elements[i]; - LLVMValueRef child_val = pack_const_int(g, big_int_type_ref, elem_val); - - if (is_big_endian) { - LLVMValueRef shift_amt = LLVMConstInt(big_int_type_ref, packed_bits_size, false); - val = LLVMConstShl(val, shift_amt); - val = LLVMConstOr(val, child_val); - } else { - LLVMValueRef shift_amt = LLVMConstInt(big_int_type_ref, used_bits, false); - LLVMValueRef child_val_shifted = LLVMConstShl(child_val, shift_amt); - val = LLVMConstOr(val, child_val_shifted); - used_bits += packed_bits_size; - } - } - - if (type_entry->data.array.sentinel != nullptr) { - ZigValue *elem_val = type_entry->data.array.sentinel; - LLVMValueRef child_val = pack_const_int(g, big_int_type_ref, elem_val); - - if (is_big_endian) { - LLVMValueRef shift_amt = LLVMConstInt(big_int_type_ref, packed_bits_size, false); - val = LLVMConstShl(val, shift_amt); - val = LLVMConstOr(val, child_val); - } else { - LLVMValueRef shift_amt = LLVMConstInt(big_int_type_ref, used_bits, false); - LLVMValueRef child_val_shifted = LLVMConstShl(child_val, shift_amt); - val = LLVMConstOr(val, child_val_shifted); - used_bits += packed_bits_size; - } - } - return val; - } - case ZigTypeIdVector: - zig_panic("TODO bit pack a vector"); - case ZigTypeIdUnion: - zig_panic("TODO bit pack a union"); - case ZigTypeIdStruct: - { - assert(type_entry->data.structure.layout == ContainerLayoutPacked); - bool is_big_endian = g->is_big_endian; // TODO get endianness from struct type - - LLVMValueRef val = LLVMConstInt(big_int_type_ref, 0, false); - size_t used_bits = 0; - for (size_t i = 0; i < type_entry->data.structure.src_field_count; i += 1) { - TypeStructField *field = type_entry->data.structure.fields[i]; - if (field->gen_index == SIZE_MAX || field->is_comptime) { - continue; - } - LLVMValueRef child_val = pack_const_int(g, big_int_type_ref, const_val->data.x_struct.fields[i]); - uint32_t packed_bits_size = type_size_bits(g, field->type_entry); - if (is_big_endian) { - LLVMValueRef shift_amt = LLVMConstInt(big_int_type_ref, packed_bits_size, false); - val = LLVMConstShl(val, shift_amt); - val = LLVMConstOr(val, child_val); - } else { - LLVMValueRef shift_amt = LLVMConstInt(big_int_type_ref, used_bits, false); - LLVMValueRef child_val_shifted = LLVMConstShl(child_val, shift_amt); - val = LLVMConstOr(val, child_val_shifted); - used_bits += packed_bits_size; - } - } - return val; - } - case ZigTypeIdFnFrame: - zig_panic("TODO bit pack an async function frame"); - case ZigTypeIdAnyFrame: - zig_panic("TODO bit pack an anyframe"); - } - zig_unreachable(); -} - -// We have this because union constants can't be represented by the official union type, -// and this property bubbles up in whatever aggregate type contains a union constant -static bool is_llvm_value_unnamed_type(CodeGen *g, ZigType *type_entry, LLVMValueRef val) { - return LLVMTypeOf(val) != get_llvm_type(g, type_entry); -} - -static LLVMValueRef gen_const_val_ptr(CodeGen *g, ZigValue *const_val, const char *name) { - switch (const_val->data.x_ptr.special) { - case ConstPtrSpecialInvalid: - case ConstPtrSpecialDiscard: - zig_unreachable(); - case ConstPtrSpecialRef: - { - ZigValue *pointee = const_val->data.x_ptr.data.ref.pointee; - render_const_val(g, pointee, ""); - render_const_val_global(g, pointee, ""); - const_val->llvm_value = LLVMConstBitCast(pointee->llvm_global, - get_llvm_type(g, const_val->type)); - return const_val->llvm_value; - } - case ConstPtrSpecialBaseArray: - case ConstPtrSpecialSubArray: - { - ZigValue *array_const_val = const_val->data.x_ptr.data.base_array.array_val; - assert(array_const_val->type->id == ZigTypeIdArray); - if (!type_has_bits(g, array_const_val->type)) { - // make this a null pointer - ZigType *usize = g->builtin_types.entry_usize; - const_val->llvm_value = LLVMConstIntToPtr(LLVMConstNull(usize->llvm_type), - get_llvm_type(g, const_val->type)); - return const_val->llvm_value; - } - size_t elem_index = const_val->data.x_ptr.data.base_array.elem_index; - LLVMValueRef uncasted_ptr_val = gen_const_ptr_array_recursive(g, array_const_val, elem_index); - LLVMValueRef ptr_val = LLVMConstBitCast(uncasted_ptr_val, get_llvm_type(g, const_val->type)); - const_val->llvm_value = ptr_val; - return ptr_val; - } - case ConstPtrSpecialBaseStruct: - { - ZigValue *struct_const_val = const_val->data.x_ptr.data.base_struct.struct_val; - assert(struct_const_val->type->id == ZigTypeIdStruct); - if (!type_has_bits(g, struct_const_val->type)) { - // make this a null pointer - ZigType *usize = g->builtin_types.entry_usize; - const_val->llvm_value = LLVMConstIntToPtr(LLVMConstNull(usize->llvm_type), - get_llvm_type(g, const_val->type)); - return const_val->llvm_value; - } - size_t src_field_index = const_val->data.x_ptr.data.base_struct.field_index; - size_t gen_field_index = struct_const_val->type->data.structure.fields[src_field_index]->gen_index; - LLVMValueRef uncasted_ptr_val = gen_const_ptr_struct_recursive(g, struct_const_val, - gen_field_index); - LLVMValueRef ptr_val = LLVMConstBitCast(uncasted_ptr_val, get_llvm_type(g, const_val->type)); - const_val->llvm_value = ptr_val; - return ptr_val; - } - case ConstPtrSpecialBaseErrorUnionCode: - { - ZigValue *err_union_const_val = const_val->data.x_ptr.data.base_err_union_code.err_union_val; - assert(err_union_const_val->type->id == ZigTypeIdErrorUnion); - if (!type_has_bits(g, err_union_const_val->type)) { - // make this a null pointer - ZigType *usize = g->builtin_types.entry_usize; - const_val->llvm_value = LLVMConstIntToPtr(LLVMConstNull(usize->llvm_type), - get_llvm_type(g, const_val->type)); - return const_val->llvm_value; - } - LLVMValueRef uncasted_ptr_val = gen_const_ptr_err_union_code_recursive(g, err_union_const_val); - LLVMValueRef ptr_val = LLVMConstBitCast(uncasted_ptr_val, get_llvm_type(g, const_val->type)); - const_val->llvm_value = ptr_val; - return ptr_val; - } - case ConstPtrSpecialBaseErrorUnionPayload: - { - ZigValue *err_union_const_val = const_val->data.x_ptr.data.base_err_union_payload.err_union_val; - assert(err_union_const_val->type->id == ZigTypeIdErrorUnion); - if (!type_has_bits(g, err_union_const_val->type)) { - // make this a null pointer - ZigType *usize = g->builtin_types.entry_usize; - const_val->llvm_value = LLVMConstIntToPtr(LLVMConstNull(usize->llvm_type), - get_llvm_type(g, const_val->type)); - return const_val->llvm_value; - } - LLVMValueRef uncasted_ptr_val = gen_const_ptr_err_union_payload_recursive(g, err_union_const_val); - LLVMValueRef ptr_val = LLVMConstBitCast(uncasted_ptr_val, get_llvm_type(g, const_val->type)); - const_val->llvm_value = ptr_val; - return ptr_val; - } - case ConstPtrSpecialBaseOptionalPayload: - { - ZigValue *optional_const_val = const_val->data.x_ptr.data.base_optional_payload.optional_val; - assert(optional_const_val->type->id == ZigTypeIdOptional); - if (!type_has_bits(g, optional_const_val->type)) { - // make this a null pointer - ZigType *usize = g->builtin_types.entry_usize; - const_val->llvm_value = LLVMConstIntToPtr(LLVMConstNull(usize->llvm_type), - get_llvm_type(g, const_val->type)); - return const_val->llvm_value; - } - LLVMValueRef uncasted_ptr_val = gen_const_ptr_optional_payload_recursive(g, optional_const_val); - LLVMValueRef ptr_val = LLVMConstBitCast(uncasted_ptr_val, get_llvm_type(g, const_val->type)); - const_val->llvm_value = ptr_val; - return ptr_val; - } - case ConstPtrSpecialHardCodedAddr: - { - uint64_t addr_value = const_val->data.x_ptr.data.hard_coded_addr.addr; - ZigType *usize = g->builtin_types.entry_usize; - const_val->llvm_value = LLVMConstIntToPtr( - LLVMConstInt(usize->llvm_type, addr_value, false), get_llvm_type(g, const_val->type)); - return const_val->llvm_value; - } - case ConstPtrSpecialFunction: - return LLVMConstBitCast(fn_llvm_value(g, const_val->data.x_ptr.data.fn.fn_entry), - get_llvm_type(g, const_val->type)); - case ConstPtrSpecialNull: - return LLVMConstNull(get_llvm_type(g, const_val->type)); - } - zig_unreachable(); -} - -static LLVMValueRef gen_const_val_err_set(CodeGen *g, ZigValue *const_val, const char *name) { - uint64_t value = (const_val->data.x_err_set == nullptr) ? 0 : const_val->data.x_err_set->value; - return LLVMConstInt(get_llvm_type(g, g->builtin_types.entry_global_error_set), value, false); -} - -static LLVMValueRef gen_const_val(CodeGen *g, ZigValue *const_val, const char *name) { - Error err; - - ZigType *type_entry = const_val->type; - assert(type_has_bits(g, type_entry)); - - if (const_val->special == ConstValSpecialLazy && - (err = ir_resolve_lazy(g, nullptr, const_val))) - codegen_report_errors_and_exit(g); - - switch (const_val->special) { - case ConstValSpecialLazy: - case ConstValSpecialRuntime: - zig_unreachable(); - case ConstValSpecialUndef: - return LLVMGetUndef(get_llvm_type(g, type_entry)); - case ConstValSpecialStatic: - break; - } - - if ((err = type_resolve(g, type_entry, ResolveStatusLLVMFull))) - zig_unreachable(); - - switch (type_entry->id) { - case ZigTypeIdInt: - return bigint_to_llvm_const(get_llvm_type(g, type_entry), &const_val->data.x_bigint); - case ZigTypeIdErrorSet: - return gen_const_val_err_set(g, const_val, name); - case ZigTypeIdFloat: - switch (type_entry->data.floating.bit_count) { - case 16: - { - LLVMValueRef as_int = LLVMConstInt(LLVMInt16Type(), const_val->data.x_f16.v, false); - return LLVMConstBitCast(as_int, get_llvm_type(g, type_entry)); - } - case 32: - return LLVMConstReal(get_llvm_type(g, type_entry), const_val->data.x_f32); - case 64: - return LLVMConstReal(get_llvm_type(g, type_entry), const_val->data.x_f64); - case 80: { - LLVMTypeRef llvm_i80 = LLVMIntType(80); - LLVMValueRef x = LLVMConstInt(llvm_i80, const_val->data.x_f80.signExp, false); - x = LLVMConstShl(x, LLVMConstInt(llvm_i80, 64, false)); - x = LLVMConstOr(x, LLVMConstInt(llvm_i80, const_val->data.x_f80.signif, false)); - if (target_has_f80(g->zig_target)) { - return LLVMConstBitCast(x, LLVMX86FP80Type()); - } else { - return x; - } - } - case 128: - { - uint64_t buf[2]; - - // LLVM seems to require that the lower half of the f128 be - // placed first in the buffer. -#if ZIG_BYTE_ORDER == ZIG_LITTLE_ENDIAN - buf[0] = const_val->data.x_f128.v[0]; - buf[1] = const_val->data.x_f128.v[1]; -#elif ZIG_BYTE_ORDER == ZIG_BIG_ENDIAN - buf[0] = const_val->data.x_f128.v[1]; - buf[1] = const_val->data.x_f128.v[0]; -#else -#error Unsupported endian -#endif - - LLVMValueRef as_int = LLVMConstIntOfArbitraryPrecision(LLVMInt128Type(), 2, buf); - return LLVMConstBitCast(as_int, get_llvm_type(g, type_entry)); - } - default: - zig_unreachable(); - } - case ZigTypeIdBool: - if (const_val->data.x_bool) { - return LLVMConstAllOnes(LLVMInt1Type()); - } else { - return LLVMConstNull(LLVMInt1Type()); - } - case ZigTypeIdOptional: - { - ZigType *child_type = type_entry->data.maybe.child_type; - - if (get_src_ptr_type(type_entry) != nullptr) { - bool has_bits; - if ((err = type_has_bits2(g, child_type, &has_bits))) - codegen_report_errors_and_exit(g); - - if (has_bits) - return gen_const_val_ptr(g, const_val, name); - - // No bits, treat this value as a boolean - const unsigned bool_val = optional_value_is_null(const_val) ? 0 : 1; - return LLVMConstInt(LLVMInt1Type(), bool_val, false); - } else if (child_type->id == ZigTypeIdErrorSet) { - return gen_const_val_err_set(g, const_val, name); - } else if (!type_has_bits(g, child_type)) { - return LLVMConstInt(LLVMInt1Type(), const_val->data.x_optional ? 1 : 0, false); - } else { - LLVMValueRef child_val; - LLVMValueRef maybe_val; - bool make_unnamed_struct; - if (const_val->data.x_optional) { - child_val = gen_const_val(g, const_val->data.x_optional, ""); - maybe_val = LLVMConstAllOnes(LLVMInt1Type()); - - make_unnamed_struct = is_llvm_value_unnamed_type(g, const_val->type, child_val); - } else { - child_val = LLVMGetUndef(get_llvm_type(g, child_type)); - maybe_val = LLVMConstNull(LLVMInt1Type()); - - make_unnamed_struct = false; - } - - LLVMValueRef fields[] = { - child_val, - maybe_val, - nullptr, - }; - if (make_unnamed_struct) { - LLVMValueRef result = LLVMConstStruct(fields, 2, false); - uint64_t last_field_offset = LLVMOffsetOfElement(g->target_data_ref, LLVMTypeOf(result), 1); - uint64_t end_offset = last_field_offset + - LLVMStoreSizeOfType(g->target_data_ref, LLVMTypeOf(fields[1])); - uint64_t expected_sz = LLVMABISizeOfType(g->target_data_ref, get_llvm_type(g, type_entry)); - unsigned pad_sz = expected_sz - end_offset; - if (pad_sz != 0) { - fields[2] = LLVMGetUndef(LLVMArrayType(LLVMInt8Type(), pad_sz)); - result = LLVMConstStruct(fields, 3, false); - } - uint64_t actual_sz = LLVMStoreSizeOfType(g->target_data_ref, LLVMTypeOf(result)); - assert(actual_sz == expected_sz); - return result; - } else { - return LLVMConstNamedStruct(get_llvm_type(g, type_entry), fields, 2); - } - } - } - case ZigTypeIdStruct: - { - LLVMValueRef *fields = heap::c_allocator.allocate(type_entry->data.structure.gen_field_count); - size_t src_field_count = type_entry->data.structure.src_field_count; - bool make_unnamed_struct = false; - assert(type_entry->data.structure.resolve_status == ResolveStatusLLVMFull); - if (type_entry->data.structure.layout == ContainerLayoutPacked) { - size_t src_field_index = 0; - while (src_field_index < src_field_count) { - TypeStructField *type_struct_field = type_entry->data.structure.fields[src_field_index]; - if (type_struct_field->gen_index == SIZE_MAX || type_struct_field->is_comptime) { - src_field_index += 1; - continue; - } - - size_t src_field_index_end = src_field_index + 1; - for (; src_field_index_end < src_field_count; src_field_index_end += 1) { - TypeStructField *it_field = type_entry->data.structure.fields[src_field_index_end]; - if (it_field->gen_index != type_struct_field->gen_index) - break; - } - - if (src_field_index + 1 == src_field_index_end && !type_entry->data.structure.misaligned_field) { - ZigValue *field_val = const_val->data.x_struct.fields[src_field_index]; - LLVMValueRef val = gen_const_val(g, field_val, ""); - fields[type_struct_field->gen_index] = val; - make_unnamed_struct = make_unnamed_struct || is_llvm_value_unnamed_type(g, field_val->type, val); - } else { - bool is_big_endian = g->is_big_endian; // TODO get endianness from struct type - LLVMTypeRef field_ty = LLVMStructGetTypeAtIndex(get_llvm_type(g, type_entry), - (unsigned)type_struct_field->gen_index); - const size_t size_in_bytes = LLVMStoreSizeOfType(g->target_data_ref, field_ty); - const size_t size_in_bits = size_in_bytes * 8; - LLVMTypeRef big_int_type_ref = LLVMIntType(size_in_bits); - LLVMValueRef val = LLVMConstInt(big_int_type_ref, 0, false); - size_t used_bits = 0; - for (size_t i = src_field_index; i < src_field_index_end; i += 1) { - TypeStructField *it_field = type_entry->data.structure.fields[i]; - if (it_field->gen_index == SIZE_MAX) { - continue; - } - LLVMValueRef child_val = pack_const_int(g, big_int_type_ref, - const_val->data.x_struct.fields[i]); - uint32_t packed_bits_size = type_size_bits(g, it_field->type_entry); - if (is_big_endian) { - LLVMValueRef shift_amt = LLVMConstInt(big_int_type_ref, - size_in_bits - used_bits - packed_bits_size, false); - LLVMValueRef child_val_shifted = LLVMConstShl(child_val, shift_amt); - val = LLVMConstOr(val, child_val_shifted); - } else { - LLVMValueRef shift_amt = LLVMConstInt(big_int_type_ref, used_bits, false); - LLVMValueRef child_val_shifted = LLVMConstShl(child_val, shift_amt); - val = LLVMConstOr(val, child_val_shifted); - } - used_bits += packed_bits_size; - } - assert(size_in_bits >= used_bits); - if (LLVMGetTypeKind(field_ty) != LLVMArrayTypeKind) { - assert(LLVMGetTypeKind(field_ty) == LLVMIntegerTypeKind); - fields[type_struct_field->gen_index] = val; - } else { - const LLVMValueRef AMT = LLVMConstInt(LLVMTypeOf(val), 8, false); - - LLVMValueRef *values = heap::c_allocator.allocate(size_in_bytes); - for (size_t i = 0; i < size_in_bytes; i++) { - const size_t idx = is_big_endian ? size_in_bytes - 1 - i : i; - values[idx] = LLVMConstTruncOrBitCast(val, LLVMInt8Type()); - val = LLVMConstLShr(val, AMT); - } - - fields[type_struct_field->gen_index] = LLVMConstArray(LLVMInt8Type(), values, size_in_bytes); - } - } - - src_field_index = src_field_index_end; - } - } else { - for (uint32_t i = 0; i < src_field_count; i += 1) { - TypeStructField *type_struct_field = type_entry->data.structure.fields[i]; - if (type_struct_field->gen_index == SIZE_MAX || type_struct_field->is_comptime) { - continue; - } - ZigValue *field_val = const_val->data.x_struct.fields[i]; - if (field_val == nullptr) { - add_node_error(g, type_struct_field->decl_node, - buf_sprintf("compiler bug: generating const value for struct field '%s'", - buf_ptr(type_struct_field->name))); - codegen_report_errors_and_exit(g); - } - ZigType *field_type = field_val->type; - assert(field_type != nullptr); - if ((err = ensure_const_val_repr(nullptr, g, nullptr, field_val, field_type))) { - zig_unreachable(); - } - - LLVMValueRef val = gen_const_val(g, field_val, ""); - make_unnamed_struct = make_unnamed_struct || is_llvm_value_unnamed_type(g, field_type, val); - - // Find the next runtime field - size_t next_rt_gen_index = type_entry->data.structure.gen_field_count; - size_t next_offset = type_entry->abi_size; - for (size_t j = i + 1; j < src_field_count; j++) { - const size_t index = type_entry->data.structure.fields[j]->gen_index; - const size_t offset = type_entry->data.structure.fields[j]->offset; - - if (index != SIZE_MAX) { - next_rt_gen_index = index; - next_offset = offset; - break; - } - } - - // How much padding is needed to reach the next field - const size_t pad_bytes = next_offset - - (type_struct_field->offset + LLVMABISizeOfType(g->target_data_ref, LLVMTypeOf(val))); - // Catch underflow - assert((ssize_t)pad_bytes >= 0); - - if (type_struct_field->gen_index + 1 != next_rt_gen_index) { - // If there's a hole between this field and the next - // we have an alignment gap to fill - fields[type_struct_field->gen_index] = val; - fields[type_struct_field->gen_index + 1] = LLVMGetUndef(LLVMArrayType(LLVMInt8Type(), pad_bytes)); - } else if (pad_bytes != 0) { - LLVMValueRef padded_val[] = { - val, - LLVMGetUndef(LLVMArrayType(LLVMInt8Type(), pad_bytes)), - }; - fields[type_struct_field->gen_index] = LLVMConstStruct(padded_val, 2, true); - make_unnamed_struct = true; - } else { - fields[type_struct_field->gen_index] = val; - } - } - } - if (make_unnamed_struct) { - LLVMValueRef unnamed_struct = LLVMConstStruct(fields, type_entry->data.structure.gen_field_count, - type_entry->data.structure.layout == ContainerLayoutPacked); - heap::c_allocator.deallocate(fields, type_entry->data.structure.gen_field_count); - return unnamed_struct; - } else { - LLVMValueRef named_struct = LLVMConstNamedStruct(get_llvm_type(g, type_entry), fields, type_entry->data.structure.gen_field_count); - heap::c_allocator.deallocate(fields, type_entry->data.structure.gen_field_count); - return named_struct; - } - } - case ZigTypeIdArray: - { - uint64_t len = type_entry->data.array.len; - switch (const_val->data.x_array.special) { - case ConstArraySpecialUndef: - return LLVMGetUndef(get_llvm_type(g, type_entry)); - case ConstArraySpecialNone: { - uint64_t extra_len_from_sentinel = (type_entry->data.array.sentinel != nullptr) ? 1 : 0; - uint64_t full_len = len + extra_len_from_sentinel; - LLVMValueRef *values = heap::c_allocator.allocate(full_len); - LLVMTypeRef element_type_ref = get_llvm_type(g, type_entry->data.array.child_type); - bool make_unnamed_struct = false; - for (uint64_t i = 0; i < len; i += 1) { - ZigValue *elem_value = &const_val->data.x_array.data.s_none.elements[i]; - LLVMValueRef val = gen_const_val(g, elem_value, ""); - values[i] = val; - make_unnamed_struct = make_unnamed_struct || is_llvm_value_unnamed_type(g, elem_value->type, val); - } - if (type_entry->data.array.sentinel != nullptr) { - values[len] = gen_const_val(g, type_entry->data.array.sentinel, ""); - } - if (make_unnamed_struct) { - LLVMValueRef unnamed_struct = LLVMConstStruct(values, full_len, true); - heap::c_allocator.deallocate(values, full_len); - return unnamed_struct; - } else { - LLVMValueRef array = LLVMConstArray(element_type_ref, values, (unsigned)full_len); - heap::c_allocator.deallocate(values, full_len); - return array; - } - } - case ConstArraySpecialBuf: { - Buf *buf = const_val->data.x_array.data.s_buf; - return LLVMConstString(buf_ptr(buf), (unsigned)buf_len(buf), - type_entry->data.array.sentinel == nullptr); - } - } - zig_unreachable(); - } - case ZigTypeIdVector: { - uint32_t len = type_entry->data.vector.len; - switch (const_val->data.x_array.special) { - case ConstArraySpecialUndef: - return LLVMGetUndef(get_llvm_type(g, type_entry)); - case ConstArraySpecialNone: { - LLVMValueRef *values = heap::c_allocator.allocate(len); - for (uint64_t i = 0; i < len; i += 1) { - ZigValue *elem_value = &const_val->data.x_array.data.s_none.elements[i]; - values[i] = gen_const_val(g, elem_value, ""); - } - LLVMValueRef vector = LLVMConstVector(values, len); - heap::c_allocator.deallocate(values, len); - return vector; - } - case ConstArraySpecialBuf: { - Buf *buf = const_val->data.x_array.data.s_buf; - assert(buf_len(buf) == len); - LLVMValueRef *values = heap::c_allocator.allocate(len); - for (uint64_t i = 0; i < len; i += 1) { - values[i] = LLVMConstInt(g->builtin_types.entry_u8->llvm_type, buf_ptr(buf)[i], false); - } - LLVMValueRef vector = LLVMConstVector(values, len); - heap::c_allocator.deallocate(values, len); - return vector; - } - } - zig_unreachable(); - } - case ZigTypeIdUnion: - { - // Force type_entry->data.unionation.union_llvm_type to get resolved - (void)get_llvm_type(g, type_entry); - - if (type_entry->data.unionation.gen_field_count == 0) { - if (type_entry->data.unionation.tag_type == nullptr) { - return nullptr; - } else { - return bigint_to_llvm_const(get_llvm_type(g, type_entry->data.unionation.tag_type), - &const_val->data.x_union.tag); - } - } - - LLVMTypeRef union_type_ref = type_entry->data.unionation.union_llvm_type; - assert(union_type_ref != nullptr); - - LLVMValueRef union_value_ref; - bool make_unnamed_struct; - ZigValue *payload_value = const_val->data.x_union.payload; - if (payload_value == nullptr || !type_has_bits(g, payload_value->type)) { - if (type_entry->data.unionation.gen_tag_index == SIZE_MAX) - return LLVMGetUndef(get_llvm_type(g, type_entry)); - - union_value_ref = LLVMGetUndef(union_type_ref); - make_unnamed_struct = false; - } else { - uint64_t field_type_bytes = LLVMABISizeOfType(g->target_data_ref, - get_llvm_type(g, payload_value->type)); - uint64_t pad_bytes = type_entry->data.unionation.union_abi_size - field_type_bytes; - LLVMValueRef correctly_typed_value = gen_const_val(g, payload_value, ""); - make_unnamed_struct = is_llvm_value_unnamed_type(g, payload_value->type, correctly_typed_value) || - payload_value->type != type_entry->data.unionation.most_aligned_union_member->type_entry; - - { - if (pad_bytes == 0) { - union_value_ref = correctly_typed_value; - } else { - LLVMValueRef fields[2]; - fields[0] = correctly_typed_value; - fields[1] = LLVMGetUndef(LLVMArrayType(LLVMInt8Type(), (unsigned)pad_bytes)); - if (make_unnamed_struct || type_entry->data.unionation.gen_tag_index != SIZE_MAX) { - union_value_ref = LLVMConstStruct(fields, 2, false); - } else { - union_value_ref = LLVMConstNamedStruct(union_type_ref, fields, 2); - } - } - } - - if (type_entry->data.unionation.gen_tag_index == SIZE_MAX) { - return union_value_ref; - } - } - - LLVMValueRef tag_value = bigint_to_llvm_const( - get_llvm_type(g, type_entry->data.unionation.tag_type), - &const_val->data.x_union.tag); - - LLVMValueRef fields[3]; - fields[type_entry->data.unionation.gen_union_index] = union_value_ref; - fields[type_entry->data.unionation.gen_tag_index] = tag_value; - - if (make_unnamed_struct) { - LLVMValueRef result = LLVMConstStruct(fields, 2, false); - uint64_t last_field_offset = LLVMOffsetOfElement(g->target_data_ref, LLVMTypeOf(result), 1); - uint64_t end_offset = last_field_offset + - LLVMStoreSizeOfType(g->target_data_ref, LLVMTypeOf(fields[1])); - uint64_t expected_sz = LLVMABISizeOfType(g->target_data_ref, get_llvm_type(g, type_entry)); - unsigned pad_sz = expected_sz - end_offset; - if (pad_sz != 0) { - fields[2] = LLVMGetUndef(LLVMArrayType(LLVMInt8Type(), pad_sz)); - result = LLVMConstStruct(fields, 3, false); - } - uint64_t actual_sz = LLVMStoreSizeOfType(g->target_data_ref, LLVMTypeOf(result)); - assert(actual_sz == expected_sz); - return result; - } else { - return LLVMConstNamedStruct(get_llvm_type(g, type_entry), fields, 2); - } - - } - - case ZigTypeIdEnum: - return bigint_to_llvm_const(get_llvm_type(g, type_entry), &const_val->data.x_enum_tag); - case ZigTypeIdFn: - if (const_val->data.x_ptr.special == ConstPtrSpecialFunction && - const_val->data.x_ptr.mut != ConstPtrMutComptimeConst) { - zig_unreachable(); - } - // Treat it the same as we do for pointers - return gen_const_val_ptr(g, const_val, name); - case ZigTypeIdPointer: - return gen_const_val_ptr(g, const_val, name); - case ZigTypeIdErrorUnion: - { - ZigType *payload_type = type_entry->data.error_union.payload_type; - ZigType *err_set_type = type_entry->data.error_union.err_set_type; - if (!type_has_bits(g, payload_type)) { - assert(type_has_bits(g, err_set_type)); - ErrorTableEntry *err_set = const_val->data.x_err_union.error_set->data.x_err_set; - uint64_t value = (err_set == nullptr) ? 0 : err_set->value; - return LLVMConstInt(get_llvm_type(g, g->err_tag_type), value, false); - } else if (!type_has_bits(g, err_set_type)) { - assert(type_has_bits(g, payload_type)); - return gen_const_val(g, const_val->data.x_err_union.payload, ""); - } else { - LLVMValueRef err_tag_value; - LLVMValueRef err_payload_value; - bool make_unnamed_struct; - ErrorTableEntry *err_set = const_val->data.x_err_union.error_set->data.x_err_set; - if (err_set != nullptr) { - err_tag_value = LLVMConstInt(get_llvm_type(g, g->err_tag_type), err_set->value, false); - err_payload_value = LLVMConstNull(get_llvm_type(g, payload_type)); - make_unnamed_struct = false; - } else { - err_tag_value = LLVMConstNull(get_llvm_type(g, g->err_tag_type)); - ZigValue *payload_val = const_val->data.x_err_union.payload; - err_payload_value = gen_const_val(g, payload_val, ""); - make_unnamed_struct = is_llvm_value_unnamed_type(g, payload_val->type, err_payload_value); - } - LLVMValueRef fields[3]; - fields[err_union_err_index] = err_tag_value; - fields[err_union_payload_index] = err_payload_value; - size_t field_count = 2; - if (type_entry->data.error_union.pad_llvm_type != nullptr) { - fields[2] = LLVMGetUndef(type_entry->data.error_union.pad_llvm_type); - field_count = 3; - } - if (make_unnamed_struct) { - return LLVMConstStruct(fields, field_count, false); - } else { - return LLVMConstNamedStruct(get_llvm_type(g, type_entry), fields, field_count); - } - } - } - case ZigTypeIdVoid: - return nullptr; - case ZigTypeIdInvalid: - case ZigTypeIdMetaType: - case ZigTypeIdUnreachable: - case ZigTypeIdComptimeFloat: - case ZigTypeIdComptimeInt: - case ZigTypeIdEnumLiteral: - case ZigTypeIdUndefined: - case ZigTypeIdNull: - case ZigTypeIdBoundFn: - case ZigTypeIdOpaque: - zig_unreachable(); - case ZigTypeIdFnFrame: - zig_panic("TODO: gen_const_val ZigTypeIdFnFrame"); - case ZigTypeIdAnyFrame: - zig_panic("TODO: gen_const_val ZigTypeIdAnyFrame"); - } - zig_unreachable(); -} - -static void render_const_val(CodeGen *g, ZigValue *const_val, const char *name) { - if (!const_val->llvm_value) - const_val->llvm_value = gen_const_val(g, const_val, name); - - if (const_val->llvm_global) - LLVMSetInitializer(const_val->llvm_global, const_val->llvm_value); -} - -static void render_const_val_global(CodeGen *g, ZigValue *const_val, const char *name) { - if (!const_val->llvm_global) { - LLVMTypeRef type_ref = const_val->llvm_value ? - LLVMTypeOf(const_val->llvm_value) : get_llvm_type(g, const_val->type); - LLVMValueRef global_value = LLVMAddGlobal(g->module, type_ref, name); - LLVMSetLinkage(global_value, (name == nullptr) ? LLVMPrivateLinkage : LLVMInternalLinkage); - LLVMSetGlobalConstant(global_value, true); - LLVMSetUnnamedAddr(global_value, true); - LLVMSetAlignment(global_value, (const_val->llvm_align == 0) ? - get_abi_alignment(g, const_val->type) : const_val->llvm_align); - - const_val->llvm_global = global_value; - } - - if (const_val->llvm_value) - LLVMSetInitializer(const_val->llvm_global, const_val->llvm_value); -} - -static void generate_error_name_table(CodeGen *g) { - if (g->err_name_table != nullptr || !g->generate_error_name_table) { - return; - } - - assert(g->errors_by_index.length > 0); - - ZigType *u8_ptr_type = get_pointer_to_type_extra(g, g->builtin_types.entry_u8, true, false, - PtrLenUnknown, get_abi_alignment(g, g->builtin_types.entry_u8), 0, 0, false); - ZigType *str_type = get_slice_type(g, u8_ptr_type); - - LLVMValueRef *values = heap::c_allocator.allocate(g->errors_by_index.length); - values[0] = LLVMGetUndef(get_llvm_type(g, str_type)); - for (size_t i = 1; i < g->errors_by_index.length; i += 1) { - ErrorTableEntry *err_entry = g->errors_by_index.at(i); - Buf *name = &err_entry->name; - - g->largest_err_name_len = max(g->largest_err_name_len, buf_len(name)); - - LLVMValueRef str_init = LLVMConstString(buf_ptr(name), (unsigned)buf_len(name), false); - LLVMValueRef str_global = LLVMAddGlobal(g->module, LLVMTypeOf(str_init), ""); - LLVMSetInitializer(str_global, str_init); - LLVMSetLinkage(str_global, LLVMPrivateLinkage); - LLVMSetGlobalConstant(str_global, true); - LLVMSetUnnamedAddr(str_global, true); - LLVMSetAlignment(str_global, LLVMABIAlignmentOfType(g->target_data_ref, LLVMTypeOf(str_init))); - - LLVMValueRef fields[] = { - LLVMConstBitCast(str_global, get_llvm_type(g, u8_ptr_type)), - LLVMConstInt(g->builtin_types.entry_usize->llvm_type, buf_len(name), false), - }; - values[i] = LLVMConstNamedStruct(get_llvm_type(g, str_type), fields, 2); - } - - LLVMValueRef err_name_table_init = LLVMConstArray(get_llvm_type(g, str_type), values, (unsigned)g->errors_by_index.length); - heap::c_allocator.deallocate(values, g->errors_by_index.length); - - g->err_name_table = LLVMAddGlobal(g->module, LLVMTypeOf(err_name_table_init), - get_mangled_name(g, buf_ptr(buf_create_from_str("__zig_err_name_table")))); - LLVMSetInitializer(g->err_name_table, err_name_table_init); - LLVMSetLinkage(g->err_name_table, LLVMPrivateLinkage); - LLVMSetGlobalConstant(g->err_name_table, true); - LLVMSetUnnamedAddr(g->err_name_table, true); - LLVMSetAlignment(g->err_name_table, LLVMABIAlignmentOfType(g->target_data_ref, LLVMTypeOf(err_name_table_init))); -} - -static void build_all_basic_blocks(CodeGen *g, ZigFn *fn) { - Stage1Air *executable = &fn->analyzed_executable; - assert(executable->basic_block_list.length > 0); - LLVMValueRef fn_val = fn_llvm_value(g, fn); - LLVMBasicBlockRef first_bb = nullptr; - if (fn_is_async(fn)) { - first_bb = LLVMAppendBasicBlock(fn_val, "AsyncSwitch"); - g->cur_preamble_llvm_block = first_bb; - } - for (size_t block_i = 0; block_i < executable->basic_block_list.length; block_i += 1) { - Stage1AirBasicBlock *bb = executable->basic_block_list.at(block_i); - bb->llvm_block = LLVMAppendBasicBlock(fn_val, bb->name_hint); - } - if (first_bb == nullptr) { - first_bb = executable->basic_block_list.at(0)->llvm_block; - } - LLVMPositionBuilderAtEnd(g->builder, first_bb); -} - -static void gen_global_var(CodeGen *g, ZigVar *var, LLVMValueRef init_val, - ZigType *type_entry) -{ - if (g->strip_debug_symbols) { - return; - } - - assert(var->gen_is_const); - assert(type_entry); - - ZigType *import = get_scope_import(var->parent_scope); - assert(import); - - bool is_local_to_unit = true; - ZigLLVMCreateGlobalVariable(g->dbuilder, get_di_scope(g, var->parent_scope), var->name, - var->name, import->data.structure.root_struct->di_file, - node_line_onebased(var->decl_node), - get_llvm_di_type(g, type_entry), is_local_to_unit); - - // TODO ^^ make an actual global variable -} - -static void set_global_tls(CodeGen *g, ZigVar *var, LLVMValueRef global_value) { - bool is_extern = var->decl_node->data.variable_declaration.is_extern; - bool is_export = var->decl_node->data.variable_declaration.is_export; - bool is_internal_linkage = !is_extern && !is_export; - if (var->is_thread_local && (!g->is_single_threaded || !is_internal_linkage)) { - LLVMSetThreadLocalMode(global_value, LLVMGeneralDynamicTLSModel); - } -} - -static void do_code_gen(CodeGen *g) { - Error err; - assert(!g->errors.length); - - generate_error_name_table(g); - - // Generate module level variables - for (size_t i = 0; i < g->global_vars.length; i += 1) { - TldVar *tld_var = g->global_vars.at(i); - ZigVar *var = tld_var->var; - - if (var->var_type->id == ZigTypeIdComptimeFloat) { - // Generate debug info for it but that's it. - ZigValue *const_val = var->const_value; - assert(const_val->special != ConstValSpecialRuntime); - if ((err = ir_resolve_lazy(g, var->decl_node, const_val))) - zig_unreachable(); - if (const_val->type != var->var_type) { - zig_panic("TODO debug info for var with ptr casted value"); - } - ZigType *var_type = g->builtin_types.entry_f128; - ZigValue coerced_value = {}; - coerced_value.special = ConstValSpecialStatic; - coerced_value.type = var_type; - coerced_value.data.x_f128 = bigfloat_to_f128(&const_val->data.x_bigfloat); - LLVMValueRef init_val = gen_const_val(g, &coerced_value, ""); - gen_global_var(g, var, init_val, var_type); - continue; - } - - if (var->var_type->id == ZigTypeIdComptimeInt) { - // Generate debug info for it but that's it. - ZigValue *const_val = var->const_value; - assert(const_val->special != ConstValSpecialRuntime); - if ((err = ir_resolve_lazy(g, var->decl_node, const_val))) - zig_unreachable(); - if (const_val->type != var->var_type) { - zig_panic("TODO debug info for var with ptr casted value"); - } - size_t bits_needed = bigint_bits_needed(&const_val->data.x_bigint); - if (bits_needed < 8) { - bits_needed = 8; - } - ZigType *var_type = get_int_type(g, const_val->data.x_bigint.is_negative, bits_needed); - LLVMValueRef init_val = bigint_to_llvm_const(get_llvm_type(g, var_type), &const_val->data.x_bigint); - gen_global_var(g, var, init_val, var_type); - continue; - } - - if (!type_has_bits(g, var->var_type)) - continue; - - assert(var->decl_node); - - GlobalLinkageId linkage; - const char *unmangled_name = var->name; - const char *symbol_name; - if (var->export_list.length == 0) { - if (var->decl_node->data.variable_declaration.is_extern) { - symbol_name = unmangled_name; - linkage = GlobalLinkageIdStrong; - } else { - symbol_name = get_mangled_name(g, unmangled_name); - linkage = GlobalLinkageIdInternal; - } - } else { - GlobalExport *global_export = &var->export_list.items[0]; - symbol_name = buf_ptr(&global_export->name); - linkage = global_export->linkage; - } - - LLVMValueRef global_value; - bool externally_initialized = var->decl_node->data.variable_declaration.expr == nullptr; - if (externally_initialized) { - LLVMValueRef existing_llvm_var = LLVMGetNamedGlobal(g->module, symbol_name); - if (existing_llvm_var) { - global_value = LLVMConstBitCast(existing_llvm_var, - LLVMPointerType(get_llvm_type(g, var->var_type), 0)); - } else { - global_value = LLVMAddGlobal(g->module, get_llvm_type(g, var->var_type), symbol_name); - // TODO debug info for the extern variable - - LLVMSetLinkage(global_value, to_llvm_linkage(linkage, true)); - maybe_import_dll(g, global_value, GlobalLinkageIdStrong); - LLVMSetAlignment(global_value, var->align_bytes); - LLVMSetGlobalConstant(global_value, var->gen_is_const); - set_global_tls(g, var, global_value); - } - } else { - bool exported = (linkage != GlobalLinkageIdInternal); - render_const_val(g, var->const_value, symbol_name); - render_const_val_global(g, var->const_value, symbol_name); - global_value = var->const_value->llvm_global; - - if (exported) { - LLVMSetLinkage(global_value, to_llvm_linkage(linkage, false)); - maybe_export_dll(g, global_value, GlobalLinkageIdStrong); - } - if (var->section_name) { - LLVMSetSection(global_value, buf_ptr(var->section_name)); - } - LLVMSetAlignment(global_value, var->align_bytes); - - // TODO debug info for function pointers - // Here we use const_value->type because that's the type of the llvm global, - // which we const ptr cast upon use to whatever it needs to be. - if (var->gen_is_const && var->const_value->type->id != ZigTypeIdFn) { - gen_global_var(g, var, var->const_value->llvm_value, var->const_value->type); - } - - LLVMSetGlobalConstant(global_value, var->gen_is_const); - set_global_tls(g, var, global_value); - } - - var->value_ref = global_value; - - for (size_t export_i = 1; export_i < var->export_list.length; export_i += 1) { - GlobalExport *global_export = &var->export_list.items[export_i]; - LLVMAddAlias2(g->module, LLVMTypeOf(var->value_ref), 0, var->value_ref, buf_ptr(&global_export->name)); - } - } - - // Generate function definitions. - stage2_progress_update_node(g->sub_progress_node, 0, g->fn_defs.length); - for (size_t fn_i = 0; fn_i < g->fn_defs.length; fn_i += 1) { - ZigFn *fn_table_entry = g->fn_defs.at(fn_i); - Stage2ProgressNode *fn_prog_node = stage2_progress_start(g->sub_progress_node, - buf_ptr(&fn_table_entry->symbol_name), buf_len(&fn_table_entry->symbol_name), 0); - - FnTypeId *fn_type_id = &fn_table_entry->type_entry->data.fn.fn_type_id; - CallingConvention cc = fn_type_id->cc; - bool is_c_abi = !calling_convention_allows_zig_types(cc); - bool want_sret = want_first_arg_sret(g, fn_type_id); - - LLVMValueRef fn = fn_llvm_value(g, fn_table_entry); - g->cur_fn = fn_table_entry; - g->cur_fn_val = fn; - - build_all_basic_blocks(g, fn_table_entry); - clear_debug_source_node(g); - - bool is_async = fn_is_async(fn_table_entry); - - if (is_async) { - g->cur_frame_ptr = LLVMGetParam(fn, 0); - } else { - if (want_sret) { - g->cur_ret_ptr = LLVMGetParam(fn, 0); - } else if (type_has_bits(g, fn_type_id->return_type)) { - g->cur_ret_ptr = build_alloca(g, fn_type_id->return_type, "result", 0); - // TODO add debug info variable for this - } else { - g->cur_ret_ptr = nullptr; - } - } - - uint32_t err_ret_trace_arg_index = get_err_ret_trace_arg_index(g, fn_table_entry); - bool have_err_ret_trace_arg = err_ret_trace_arg_index != UINT32_MAX; - if (have_err_ret_trace_arg) { - g->cur_err_ret_trace_val_arg = LLVMGetParam(fn, err_ret_trace_arg_index); - } else { - g->cur_err_ret_trace_val_arg = nullptr; - } - - // error return tracing setup - bool have_err_ret_trace_stack = g->have_err_ret_tracing && fn_table_entry->calls_or_awaits_errorable_fn && - !is_async && !have_err_ret_trace_arg; - LLVMValueRef err_ret_array_val = nullptr; - if (have_err_ret_trace_stack) { - ZigType *array_type = get_array_type(g, g->builtin_types.entry_usize, stack_trace_ptr_count, nullptr); - err_ret_array_val = build_alloca(g, array_type, "error_return_trace_addresses", get_abi_alignment(g, array_type)); - - (void)get_llvm_type(g, get_stack_trace_type(g)); - g->cur_err_ret_trace_val_stack = build_alloca(g, get_stack_trace_type(g), "error_return_trace", - get_abi_alignment(g, g->stack_trace_type)); - } else { - g->cur_err_ret_trace_val_stack = nullptr; - } - - if (fn_returns_c_abi_small_struct(fn_type_id)) { - LLVMTypeRef abi_type = get_llvm_c_abi_type(g, fn_type_id->return_type); - fn_table_entry->abi_return_value = LLVMBuildAlloca(g->builder, abi_type, ""); - } - - if (!is_async) { - // allocate async frames for nosuspend calls & awaits to async functions - ZigType *largest_call_frame_type = nullptr; - Stage1AirInst *all_calls_alloca = ir_create_alloca(g, &fn_table_entry->fndef_scope->base, - fn_table_entry->body_node, fn_table_entry, g->builtin_types.entry_void, "@async_call_frame"); - for (size_t i = 0; i < fn_table_entry->call_list.length; i += 1) { - Stage1AirInstCall *call = fn_table_entry->call_list.at(i); - if (call->fn_entry == nullptr) - continue; - if (!fn_is_async(call->fn_entry)) - continue; - if (call->modifier != CallModifierNoSuspend) - continue; - if (call->frame_result_loc != nullptr) - continue; - ZigType *callee_frame_type = get_fn_frame_type(g, call->fn_entry); - if (largest_call_frame_type == nullptr || - callee_frame_type->abi_size > largest_call_frame_type->abi_size) - { - largest_call_frame_type = callee_frame_type; - } - call->frame_result_loc = all_calls_alloca; - } - if (largest_call_frame_type != nullptr) { - all_calls_alloca->value->type = get_pointer_to_type(g, largest_call_frame_type, false); - } - // allocate temporary stack data - for (size_t alloca_i = 0; alloca_i < fn_table_entry->alloca_gen_list.length; alloca_i += 1) { - Stage1AirInstAlloca *instruction = fn_table_entry->alloca_gen_list.at(alloca_i); - ZigType *ptr_type = instruction->base.value->type; - assert(ptr_type->id == ZigTypeIdPointer); - ZigType *child_type = ptr_type->data.pointer.child_type; - if (type_resolve(g, child_type, ResolveStatusSizeKnown)) - zig_unreachable(); - if (!type_has_bits(g, child_type)) - continue; - if (instruction->base.ref_count == 0) - continue; - if (instruction->base.value->special != ConstValSpecialRuntime) { - if (const_ptr_pointee(nullptr, g, instruction->base.value, nullptr)->special != - ConstValSpecialRuntime) - { - continue; - } - } - if (type_resolve(g, child_type, ResolveStatusLLVMFull)) - zig_unreachable(); - instruction->base.llvm_value = build_alloca(g, child_type, instruction->name_hint, - get_ptr_align(g, ptr_type)); - } - } - - ZigType *import = get_scope_import(&fn_table_entry->fndef_scope->base); - unsigned gen_i_init = want_sret ? 1 : 0; - - // create debug variable declarations for variables and allocate all local variables - FnWalk fn_walk_var = {}; - fn_walk_var.id = FnWalkIdVars; - fn_walk_var.data.vars.import = import; - fn_walk_var.data.vars.fn = fn_table_entry; - fn_walk_var.data.vars.llvm_fn = fn; - fn_walk_var.data.vars.gen_i = gen_i_init; - for (size_t var_i = 0; var_i < fn_table_entry->variable_list.length; var_i += 1) { - ZigVar *var = fn_table_entry->variable_list.at(var_i); - - if (!type_has_bits(g, var->var_type)) { - continue; - } - if (ir_get_var_is_comptime(var)) - continue; - switch (type_requires_comptime(g, var->var_type)) { - case ReqCompTimeInvalid: - zig_unreachable(); - case ReqCompTimeYes: - continue; - case ReqCompTimeNo: - break; - } - - if (var->src_arg_index == SIZE_MAX) { - var->di_loc_var = ZigLLVMCreateAutoVariable(g->dbuilder, get_di_scope(g, var->parent_scope), - var->name, import->data.structure.root_struct->di_file, - node_line_onebased(var->decl_node), - get_llvm_di_type(g, var->var_type), !g->strip_debug_symbols, 0); - - } else if (is_c_abi) { - fn_walk_var.data.vars.var = var; - iter_function_params_c_abi(g, fn_table_entry->type_entry, &fn_walk_var, var->src_arg_index); - } else if (!is_async) { - ZigType *gen_type; - FnGenParamInfo *gen_info = &fn_table_entry->type_entry->data.fn.gen_param_info[var->src_arg_index]; - assert(gen_info->gen_index != SIZE_MAX); - - if (handle_is_ptr(g, var->var_type)) { - if (gen_info->is_byval) { - gen_type = var->var_type; - } else { - gen_type = gen_info->type; - } - var->value_ref = LLVMGetParam(fn, gen_info->gen_index); - } else { - gen_type = var->var_type; - var->value_ref = build_alloca(g, var->var_type, var->name, var->align_bytes); - } - if (var->decl_node) { - var->di_loc_var = ZigLLVMCreateParameterVariable(g->dbuilder, get_di_scope(g, var->parent_scope), - var->name, import->data.structure.root_struct->di_file, - node_line_onebased(var->decl_node), - get_llvm_di_type(g, gen_type), !g->strip_debug_symbols, 0, (unsigned)(gen_info->gen_index+1)); - } - - } - } - - LLVMTypeRef usize_type_ref = g->builtin_types.entry_usize->llvm_type; - - // finishing error return trace setup. we have to do this after all the allocas. - if (have_err_ret_trace_stack) { - ZigType *usize = g->builtin_types.entry_usize; - size_t index_field_index = g->stack_trace_type->data.structure.fields[0]->gen_index; - LLVMValueRef index_field_ptr = LLVMBuildStructGEP2(g->builder, - get_llvm_type(g, g->stack_trace_type), - g->cur_err_ret_trace_val_stack, (unsigned)index_field_index, ""); - gen_store_untyped(g, LLVMConstNull(usize->llvm_type), index_field_ptr, 0, false); - - size_t addresses_field_index = g->stack_trace_type->data.structure.fields[1]->gen_index; - LLVMValueRef addresses_field_ptr = LLVMBuildStructGEP2(g->builder, - get_llvm_type(g, g->stack_trace_type), - g->cur_err_ret_trace_val_stack, (unsigned)addresses_field_index, ""); - - ZigType *slice_type = g->stack_trace_type->data.structure.fields[1]->type_entry; - size_t ptr_field_index = slice_type->data.structure.fields[slice_ptr_index]->gen_index; - LLVMValueRef ptr_field_ptr = LLVMBuildStructGEP2(g->builder, - ZigLLVMGetGEPResultElementType(addresses_field_ptr), - addresses_field_ptr, (unsigned)ptr_field_index, ""); - LLVMValueRef zero = LLVMConstNull(usize->llvm_type); - LLVMValueRef indices[] = {zero, zero}; - LLVMValueRef err_ret_array_val_elem0_ptr = LLVMBuildInBoundsGEP2(g->builder, - LLVMGetAllocatedType(err_ret_array_val), err_ret_array_val, indices, 2, ""); - ZigType *ptr_ptr_usize_type = get_pointer_to_type(g, get_pointer_to_type(g, usize, false), false); - gen_store(g, err_ret_array_val_elem0_ptr, ptr_field_ptr, ptr_ptr_usize_type); - - size_t len_field_index = slice_type->data.structure.fields[slice_len_index]->gen_index; - LLVMValueRef len_field_ptr = LLVMBuildStructGEP2(g->builder, - ZigLLVMGetGEPResultElementType(addresses_field_ptr), - addresses_field_ptr, (unsigned)len_field_index, ""); - gen_store(g, LLVMConstInt(usize->llvm_type, stack_trace_ptr_count, false), len_field_ptr, get_pointer_to_type(g, usize, false)); - } - - if (is_async) { - (void)get_llvm_type(g, fn_table_entry->frame_type); - g->cur_resume_block_count = 0; - - LLVMValueRef size_val = LLVMConstInt(usize_type_ref, fn_table_entry->frame_type->abi_size, false); - if (g->need_frame_size_prefix_data) { - ZigLLVMFunctionSetPrefixData(fn_table_entry->llvm_value, size_val); - } - - if (!g->strip_debug_symbols) { - AstNode *source_node = fn_table_entry->proto_node; - ZigLLVMSetCurrentDebugLocation(g->builder, - node_line_onebased(source_node), node_column_onebased(source_node), - get_di_scope(g, fn_table_entry->child_scope)); - } - Stage1Air *executable = &fn_table_entry->analyzed_executable; - LLVMBasicBlockRef bad_resume_block = LLVMAppendBasicBlock(g->cur_fn_val, "BadResume"); - LLVMPositionBuilderAtEnd(g->builder, bad_resume_block); - gen_assertion_scope(g, PanicMsgIdBadResume, fn_table_entry->child_scope); - - LLVMPositionBuilderAtEnd(g->builder, g->cur_preamble_llvm_block); - render_async_spills(g); - g->cur_async_awaiter_ptr = LLVMBuildStructGEP2(g->builder, - get_llvm_type(g, get_fn_frame_type(g, g->cur_fn)), - g->cur_frame_ptr, frame_awaiter_index, ""); - LLVMValueRef resume_index_ptr = LLVMBuildStructGEP2(g->builder, - get_llvm_type(g, get_fn_frame_type(g, g->cur_fn)), - g->cur_frame_ptr, frame_resume_index, ""); - g->cur_async_resume_index_ptr = resume_index_ptr; - - if (type_has_bits(g, fn_type_id->return_type)) { - LLVMValueRef cur_ret_ptr_ptr = LLVMBuildStructGEP2(g->builder, - get_llvm_type(g, get_fn_frame_type(g, g->cur_fn)), - g->cur_frame_ptr, frame_ret_start, ""); - g->cur_ret_ptr = LLVMBuildLoad2(g->builder, - ZigLLVMGetGEPResultElementType(cur_ret_ptr_ptr), cur_ret_ptr_ptr, ""); - } - uint32_t trace_field_index_stack = UINT32_MAX; - if (codegen_fn_has_err_ret_tracing_stack(g, fn_table_entry, true)) { - trace_field_index_stack = frame_index_trace_stack(g, fn_table_entry); - g->cur_err_ret_trace_val_stack = LLVMBuildStructGEP2(g->builder, - get_llvm_type(g, get_fn_frame_type(g, g->cur_fn)), - g->cur_frame_ptr, - trace_field_index_stack, ""); - } - - LLVMValueRef resume_index = LLVMBuildLoad2(g->builder, usize_type_ref, resume_index_ptr, ""); - LLVMValueRef switch_instr = LLVMBuildSwitch(g->builder, resume_index, bad_resume_block, 4); - g->cur_async_switch_instr = switch_instr; - - LLVMValueRef zero = LLVMConstNull(usize_type_ref); - Stage1AirBasicBlock *entry_block = executable->basic_block_list.at(0); - LLVMAddCase(switch_instr, zero, entry_block->llvm_block); - g->cur_resume_block_count += 1; - - { - LLVMBasicBlockRef bad_not_suspended_bb = LLVMAppendBasicBlock(g->cur_fn_val, "NotSuspended"); - size_t new_block_index = g->cur_resume_block_count; - g->cur_resume_block_count += 1; - g->cur_bad_not_suspended_index = LLVMConstInt(usize_type_ref, new_block_index, false); - LLVMAddCase(g->cur_async_switch_instr, g->cur_bad_not_suspended_index, bad_not_suspended_bb); - - LLVMPositionBuilderAtEnd(g->builder, bad_not_suspended_bb); - gen_assertion_scope(g, PanicMsgIdResumeNotSuspendedFn, fn_table_entry->child_scope); - } - - LLVMPositionBuilderAtEnd(g->builder, entry_block->llvm_block); - LLVMBuildStore(g->builder, g->cur_bad_not_suspended_index, g->cur_async_resume_index_ptr); - if (trace_field_index_stack != UINT32_MAX) { - if (codegen_fn_has_err_ret_tracing_arg(g, fn_type_id->return_type)) { - LLVMValueRef trace_ptr_ptr = LLVMBuildStructGEP2(g->builder, - get_llvm_type(g, get_fn_frame_type(g, g->cur_fn)), - g->cur_frame_ptr, - frame_index_trace_arg(g, fn_type_id->return_type), ""); - LLVMValueRef zero_ptr = LLVMConstNull(ZigLLVMGetGEPResultElementType(trace_ptr_ptr)); - LLVMBuildStore(g->builder, zero_ptr, trace_ptr_ptr); - } - - LLVMValueRef trace_field_ptr = LLVMBuildStructGEP2(g->builder, - get_llvm_type(g, get_fn_frame_type(g, g->cur_fn)), - g->cur_frame_ptr, - trace_field_index_stack, ""); - LLVMValueRef addrs_field_ptr = LLVMBuildStructGEP2(g->builder, - get_llvm_type(g, get_fn_frame_type(g, g->cur_fn)), - g->cur_frame_ptr, - trace_field_index_stack + 1, ""); - - gen_init_stack_trace(g, trace_field_ptr, addrs_field_ptr); - } - render_async_var_decls(g, entry_block->instruction_list.at(0)->scope); - } else { - // create debug variable declarations for parameters - // rely on the first variables in the variable_list being parameters. - FnWalk fn_walk_init = {}; - fn_walk_init.id = FnWalkIdInits; - fn_walk_init.data.inits.fn = fn_table_entry; - fn_walk_init.data.inits.llvm_fn = fn; - fn_walk_init.data.inits.gen_i = gen_i_init; - walk_function_params(g, fn_table_entry->type_entry, &fn_walk_init); - } - - ir_render(g, fn_table_entry); - - stage2_progress_end(fn_prog_node); - } - - assert(!g->errors.length); - - if (buf_len(&g->global_asm) != 0) { - LLVMSetModuleInlineAsm2(g->module, buf_ptr(&g->global_asm), buf_len(&g->global_asm)); - } - - while (g->type_resolve_stack.length != 0) { - ZigType *ty = g->type_resolve_stack.last(); - if (type_resolve(g, ty, ResolveStatusLLVMFull)) - zig_unreachable(); - } - - ZigLLVMDIBuilderFinalize(g->dbuilder); - - if (g->verbose_llvm_ir) { - fflush(stderr); - LLVMDumpModule(g->module); - } - - char *error = nullptr; - if (LLVMVerifyModule(g->module, LLVMReturnStatusAction, &error)) { - zig_panic("broken LLVM module found: %s\nThis is a bug in the Zig compiler.", error); - } -} - -static void zig_llvm_emit_output(CodeGen *g) { - g->pass1_arena->destruct(&heap::c_allocator); - g->pass1_arena = nullptr; - - bool is_small = g->build_mode == BuildModeSmallRelease; - - char *err_msg = nullptr; - const char *asm_filename = nullptr; - const char *bin_filename = nullptr; - const char *llvm_ir_filename = nullptr; - const char *bitcode_filename = nullptr; - - if (buf_len(&g->o_file_output_path) != 0) bin_filename = buf_ptr(&g->o_file_output_path); - if (buf_len(&g->asm_file_output_path) != 0) asm_filename = buf_ptr(&g->asm_file_output_path); - if (buf_len(&g->llvm_ir_file_output_path) != 0) llvm_ir_filename = buf_ptr(&g->llvm_ir_file_output_path); - if (buf_len(&g->bitcode_file_output_path) != 0) bitcode_filename = buf_ptr(&g->bitcode_file_output_path); - - // Unfortunately, LLVM shits the bed when we ask for both binary and assembly. - // So we call the entire pipeline multiple times if this is requested. - if (asm_filename != nullptr && bin_filename != nullptr) { - if (ZigLLVMTargetMachineEmitToFile(g->target_machine, g->module, &err_msg, - g->build_mode == BuildModeDebug, is_small, g->enable_time_report, g->tsan_enabled, - g->have_lto, nullptr, bin_filename, llvm_ir_filename, nullptr)) - { - fprintf(stderr, "LLVM failed to emit bin=%s, ir=%s: %s\n", - bin_filename, llvm_ir_filename, err_msg); - exit(1); - } - bin_filename = nullptr; - llvm_ir_filename = nullptr; - } - - if (ZigLLVMTargetMachineEmitToFile(g->target_machine, g->module, &err_msg, - g->build_mode == BuildModeDebug, is_small, g->enable_time_report, g->tsan_enabled, - g->have_lto, asm_filename, bin_filename, llvm_ir_filename, bitcode_filename)) - { - fprintf(stderr, "LLVM failed to emit asm=%s, bin=%s, ir=%s, bc=%s: %s\n", - asm_filename, bin_filename, llvm_ir_filename, bitcode_filename, - err_msg); - exit(1); - } - - LLVMDisposeModule(g->module); - g->module = nullptr; - LLVMDisposeTargetData(g->target_data_ref); - g->target_data_ref = nullptr; - LLVMDisposeTargetMachine(g->target_machine); - g->target_machine = nullptr; -} - -struct CIntTypeInfo { - CIntType id; - const char *name; - bool is_signed; -}; - -static const CIntTypeInfo c_int_type_infos[] = { - {CIntTypeShort, "c_short", true}, - {CIntTypeUShort, "c_ushort", false}, - {CIntTypeInt, "c_int", true}, - {CIntTypeUInt, "c_uint", false}, - {CIntTypeLong, "c_long", true}, - {CIntTypeULong, "c_ulong", false}, - {CIntTypeLongLong, "c_longlong", true}, - {CIntTypeULongLong, "c_ulonglong", false}, -}; - -static const bool is_signed_list[] = { false, true, }; - -struct GlobalLinkageValue { - GlobalLinkageId id; - const char *name; -}; - -static void add_fp_entry(CodeGen *g, const char *name, uint32_t bit_count, LLVMTypeRef type_ref, - ZigType **field) -{ - ZigType *entry = new_type_table_entry(ZigTypeIdFloat); - entry->llvm_type = type_ref; - entry->size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, entry->llvm_type); - entry->abi_size = LLVMABISizeOfType(g->target_data_ref, entry->llvm_type); - entry->abi_align = LLVMABIAlignmentOfType(g->target_data_ref, entry->llvm_type); - buf_init_from_str(&entry->name, name); - entry->data.floating.bit_count = bit_count; - - entry->llvm_di_type = ZigLLVMCreateDebugBasicType(g->dbuilder, buf_ptr(&entry->name), - entry->size_in_bits, ZigLLVMEncoding_DW_ATE_float()); - *field = entry; - g->primitive_type_table.put(&entry->name, entry); -} - -static void define_builtin_types(CodeGen *g) { - { - // if this type is anywhere in the AST, we should never hit codegen. - ZigType *entry = new_type_table_entry(ZigTypeIdInvalid); - buf_init_from_str(&entry->name, "(invalid)"); - g->builtin_types.entry_invalid = entry; - } - { - ZigType *entry = new_type_table_entry(ZigTypeIdComptimeFloat); - buf_init_from_str(&entry->name, "comptime_float"); - g->builtin_types.entry_num_lit_float = entry; - g->primitive_type_table.put(&entry->name, entry); - } - { - ZigType *entry = new_type_table_entry(ZigTypeIdComptimeInt); - buf_init_from_str(&entry->name, "comptime_int"); - g->builtin_types.entry_num_lit_int = entry; - g->primitive_type_table.put(&entry->name, entry); - } - { - ZigType *entry = new_type_table_entry(ZigTypeIdEnumLiteral); - buf_init_from_str(&entry->name, "@Type(.EnumLiteral)"); - g->builtin_types.entry_enum_literal = entry; - } - { - ZigType *entry = new_type_table_entry(ZigTypeIdUndefined); - buf_init_from_str(&entry->name, "@Type(.Undefined)"); - g->builtin_types.entry_undef = entry; - } - { - ZigType *entry = new_type_table_entry(ZigTypeIdNull); - buf_init_from_str(&entry->name, "@Type(.Null)"); - g->builtin_types.entry_null = entry; - } - { - ZigType *entry = new_type_table_entry(ZigTypeIdOpaque); - buf_init_from_str(&entry->name, "(anytype)"); - g->builtin_types.entry_anytype = entry; - } - - for (size_t i = 0; i < array_length(c_int_type_infos); i += 1) { - const CIntTypeInfo *info = &c_int_type_infos[i]; - uint32_t size_in_bits = target_c_type_size_in_bits(g->zig_target, info->id); - bool is_signed = info->is_signed; - - ZigType *entry = new_type_table_entry(ZigTypeIdInt); - entry->llvm_type = LLVMIntType(size_in_bits); - entry->size_in_bits = size_in_bits; - entry->abi_size = LLVMABISizeOfType(g->target_data_ref, entry->llvm_type); - entry->abi_align = LLVMABIAlignmentOfType(g->target_data_ref, entry->llvm_type); - - buf_init_from_str(&entry->name, info->name); - - entry->llvm_di_type = ZigLLVMCreateDebugBasicType(g->dbuilder, buf_ptr(&entry->name), - size_in_bits, - is_signed ? ZigLLVMEncoding_DW_ATE_signed() : ZigLLVMEncoding_DW_ATE_unsigned()); - entry->data.integral.is_signed = is_signed; - entry->data.integral.bit_count = size_in_bits; - g->primitive_type_table.put(&entry->name, entry); - - get_c_int_type_ptr(g, info->id)[0] = entry; - } - - { - ZigType *entry = new_type_table_entry(ZigTypeIdBool); - entry->llvm_type = LLVMInt1Type(); - entry->size_in_bits = 1; - entry->abi_size = LLVMABISizeOfType(g->target_data_ref, entry->llvm_type); - entry->abi_align = LLVMABIAlignmentOfType(g->target_data_ref, entry->llvm_type); - buf_init_from_str(&entry->name, "bool"); - entry->llvm_di_type = ZigLLVMCreateDebugBasicType(g->dbuilder, buf_ptr(&entry->name), - 1, ZigLLVMEncoding_DW_ATE_boolean()); - g->builtin_types.entry_bool = entry; - g->primitive_type_table.put(&entry->name, entry); - } - - for (size_t sign_i = 0; sign_i < array_length(is_signed_list); sign_i += 1) { - bool is_signed = is_signed_list[sign_i]; - - ZigType *entry = new_type_table_entry(ZigTypeIdInt); - entry->llvm_type = LLVMIntType(g->pointer_size_bytes * 8); - entry->size_in_bits = g->pointer_size_bytes * 8; - entry->abi_size = LLVMABISizeOfType(g->target_data_ref, entry->llvm_type); - entry->abi_align = LLVMABIAlignmentOfType(g->target_data_ref, entry->llvm_type); - - const char u_or_i = is_signed ? 'i' : 'u'; - buf_resize(&entry->name, 0); - buf_appendf(&entry->name, "%csize", u_or_i); - - entry->data.integral.is_signed = is_signed; - entry->data.integral.bit_count = g->pointer_size_bytes * 8; - - entry->llvm_di_type = ZigLLVMCreateDebugBasicType(g->dbuilder, buf_ptr(&entry->name), - 8*LLVMStoreSizeOfType(g->target_data_ref, entry->llvm_type), - is_signed ? ZigLLVMEncoding_DW_ATE_signed() : ZigLLVMEncoding_DW_ATE_unsigned()); - g->primitive_type_table.put(&entry->name, entry); - - if (is_signed) { - g->builtin_types.entry_isize = entry; - } else { - g->builtin_types.entry_usize = entry; - } - } - - if (target_is_arm(g->zig_target)) { - add_fp_entry(g, "f16", 16, LLVMHalfType(), &g->builtin_types.entry_f16); - } else { - ZigType *u16_ty = get_int_type(g, false, 16); - add_fp_entry(g, "f16", 16, get_llvm_type(g, u16_ty), &g->builtin_types.entry_f16); - } - add_fp_entry(g, "f32", 32, LLVMFloatType(), &g->builtin_types.entry_f32); - add_fp_entry(g, "f64", 64, LLVMDoubleType(), &g->builtin_types.entry_f64); - add_fp_entry(g, "f128", 128, LLVMFP128Type(), &g->builtin_types.entry_f128); - - { - ZigType *entry = new_type_table_entry(ZigTypeIdFloat); - entry->size_in_bits = 80; - - buf_init_from_str(&entry->name, "f80"); - entry->data.floating.bit_count = 80; - - if (target_has_f80(g->zig_target)) { - entry->llvm_type = LLVMX86FP80Type(); - - // Note the following u64 alignments: - // x86-linux: 4 - // x86-windows: 8 - // LLVM makes x86_fp80 have the following alignment and sizes regardless - // of operating system: - // x86_64: size=16, align=16 - // x86: size=12, align=4 - // However in Zig we override x86-windows to have size=16, align=16 - // in order for the property to hold that u80 and f80 have the same ABI size. - unsigned u64_alignment = LLVMABIAlignmentOfType(g->target_data_ref, LLVMInt64Type()); - - if (u64_alignment >= 8) { - entry->abi_size = 16; - entry->abi_align = 16; - } else if (u64_alignment >= 4) { - entry->abi_size = 12; - entry->abi_align = 4; - } else { - entry->abi_size = 10; - entry->abi_align = u64_alignment; - } - } else { - // We use an int here instead of x86_fp80 because on targets such as arm, - // LLVM will give "ERROR: Cannot select" for any instructions involving - // the x86_fp80 type. - ZigType *u80_ty = get_int_type(g, false, 80); - assert(!target_has_f80(g->zig_target)); - assert(u80_ty->size_in_bits == entry->size_in_bits); - entry->llvm_type = get_llvm_type(g, u80_ty); - entry->abi_size = u80_ty->abi_size; - entry->abi_align = u80_ty->abi_align; - } - - entry->llvm_di_type = ZigLLVMCreateDebugBasicType(g->dbuilder, buf_ptr(&entry->name), - entry->size_in_bits, ZigLLVMEncoding_DW_ATE_unsigned()); - - g->builtin_types.entry_f80 = entry; - g->primitive_type_table.put(&entry->name, entry); - } - - switch (g->zig_target->arch) { - case ZigLLVM_x86: - case ZigLLVM_x86_64: - if (g->zig_target->abi != ZigLLVM_MSVC) { - add_fp_entry(g, "c_longdouble", 80, LLVMX86FP80Type(), &g->builtin_types.entry_c_longdouble); - g->builtin_types.entry_c_longdouble->abi_size = g->builtin_types.entry_f80->abi_size; - g->builtin_types.entry_c_longdouble->abi_align = g->builtin_types.entry_f80->abi_align; - } else { - add_fp_entry(g, "c_longdouble", 64, LLVMDoubleType(), &g->builtin_types.entry_c_longdouble); - } - break; - case ZigLLVM_arm: - case ZigLLVM_armeb: - case ZigLLVM_thumb: - case ZigLLVM_thumbeb: - add_fp_entry(g, "c_longdouble", 64, LLVMDoubleType(), &g->builtin_types.entry_c_longdouble); - break; - case ZigLLVM_aarch64: - case ZigLLVM_aarch64_be: - if (g->zig_target->os == OsWindows || target_os_is_darwin(g->zig_target->os)) - add_fp_entry(g, "c_longdouble", 64, LLVMDoubleType(), &g->builtin_types.entry_c_longdouble); - else - add_fp_entry(g, "c_longdouble", 128, LLVMFP128Type(), &g->builtin_types.entry_c_longdouble); - break; - case ZigLLVM_riscv32: - case ZigLLVM_riscv64: - add_fp_entry(g, "c_longdouble", 128, LLVMFP128Type(), &g->builtin_types.entry_c_longdouble); - break; - case ZigLLVM_wasm32: - case ZigLLVM_wasm64: - add_fp_entry(g, "c_longdouble", 128, LLVMFP128Type(), &g->builtin_types.entry_c_longdouble); - break; - case ZigLLVM_mips: - case ZigLLVM_mipsel: - // Assume o32 ABI - add_fp_entry(g, "c_longdouble", 64, LLVMDoubleType(), &g->builtin_types.entry_c_longdouble); - break; - case ZigLLVM_mips64: - case ZigLLVM_mips64el: - add_fp_entry(g, "c_longdouble", 128, LLVMFP128Type(), &g->builtin_types.entry_c_longdouble); - break; - case ZigLLVM_ppc: - case ZigLLVM_ppcle: - case ZigLLVM_ppc64: - case ZigLLVM_ppc64le: - add_fp_entry(g, "c_longdouble", 128, LLVMFP128Type(), &g->builtin_types.entry_c_longdouble); - break; - case ZigLLVM_sparcv9: - add_fp_entry(g, "c_longdouble", 128, LLVMFP128Type(), &g->builtin_types.entry_c_longdouble); - break; - case ZigLLVM_systemz: - add_fp_entry(g, "c_longdouble", 128, LLVMDoubleType(), &g->builtin_types.entry_c_longdouble); - break; - case ZigLLVM_avr: - // It's either a float or a double, depending on a toolchain switch - add_fp_entry(g, "c_longdouble", 64, LLVMDoubleType(), &g->builtin_types.entry_c_longdouble); - break; - case ZigLLVM_msp430: - add_fp_entry(g, "c_longdouble", 64, LLVMDoubleType(), &g->builtin_types.entry_c_longdouble); - break; - case ZigLLVM_bpfel: - case ZigLLVM_bpfeb: - add_fp_entry(g, "c_longdouble", 64, LLVMDoubleType(), &g->builtin_types.entry_c_longdouble); - break; - case ZigLLVM_nvptx: - case ZigLLVM_nvptx64: - add_fp_entry(g, "c_longdouble", 64, LLVMDoubleType(), &g->builtin_types.entry_c_longdouble); - break; - default: - zig_panic("TODO implement mapping for c_longdouble"); - } - - { - ZigType *entry = new_type_table_entry(ZigTypeIdVoid); - entry->llvm_type = LLVMVoidType(); - buf_init_from_str(&entry->name, "void"); - entry->llvm_di_type = ZigLLVMCreateDebugBasicType(g->dbuilder, buf_ptr(&entry->name), - 0, - ZigLLVMEncoding_DW_ATE_signed()); - g->builtin_types.entry_void = entry; - g->primitive_type_table.put(&entry->name, entry); - } - { - ZigType *entry = new_type_table_entry(ZigTypeIdUnreachable); - entry->llvm_type = LLVMVoidType(); - buf_init_from_str(&entry->name, "noreturn"); - entry->llvm_di_type = g->builtin_types.entry_void->llvm_di_type; - g->builtin_types.entry_unreachable = entry; - g->primitive_type_table.put(&entry->name, entry); - } - { - ZigType *entry = new_type_table_entry(ZigTypeIdMetaType); - buf_init_from_str(&entry->name, "type"); - g->builtin_types.entry_type = entry; - g->primitive_type_table.put(&entry->name, entry); - } - - g->builtin_types.entry_u8 = get_int_type(g, false, 8); - g->builtin_types.entry_u16 = get_int_type(g, false, 16); - g->builtin_types.entry_u29 = get_int_type(g, false, 29); - g->builtin_types.entry_u32 = get_int_type(g, false, 32); - g->builtin_types.entry_u64 = get_int_type(g, false, 64); - g->builtin_types.entry_i8 = get_int_type(g, true, 8); - g->builtin_types.entry_i32 = get_int_type(g, true, 32); - g->builtin_types.entry_i64 = get_int_type(g, true, 64); - - { - g->builtin_types.entry_anyopaque = get_opaque_type(g, nullptr, nullptr, "anyopaque", - buf_create_from_str("anyopaque")); - g->primitive_type_table.put(&g->builtin_types.entry_anyopaque->name, g->builtin_types.entry_anyopaque); - } - - { - ZigType *ptr_const_anyopaque = get_pointer_to_type(g, - g->builtin_types.entry_anyopaque, true); - g->builtin_types.entry_opt_ptr_const_anyopaque = get_optional_type(g, ptr_const_anyopaque); - } - - { - ZigType *entry = new_type_table_entry(ZigTypeIdErrorSet); - buf_init_from_str(&entry->name, "anyerror"); - entry->data.error_set.err_count = UINT32_MAX; - - // TODO https://github.com/ziglang/zig/issues/786 - g->err_tag_type = g->builtin_types.entry_u16; - - entry->size_in_bits = g->err_tag_type->size_in_bits; - entry->abi_align = g->err_tag_type->abi_align; - entry->abi_size = g->err_tag_type->abi_size; - - g->builtin_types.entry_global_error_set = entry; - - g->errors_by_index.append(nullptr); - - g->primitive_type_table.put(&entry->name, entry); - } -} - -static void define_intern_values(CodeGen *g) { - { - auto& value = g->intern.x_undefined; - value.type = g->builtin_types.entry_undef; - value.special = ConstValSpecialStatic; - } - { - auto& value = g->intern.x_void; - value.type = g->builtin_types.entry_void; - value.special = ConstValSpecialStatic; - } - { - auto& value = g->intern.x_null; - value.type = g->builtin_types.entry_null; - value.special = ConstValSpecialStatic; - } - { - auto& value = g->intern.x_unreachable; - value.type = g->builtin_types.entry_unreachable; - value.special = ConstValSpecialStatic; - } - { - auto& value = g->intern.zero_byte; - value.type = g->builtin_types.entry_u8; - value.special = ConstValSpecialStatic; - bigint_init_unsigned(&value.data.x_bigint, 0); - } -} - -static BuiltinFnEntry *create_builtin_fn(CodeGen *g, BuiltinFnId id, const char *name, size_t count) { - BuiltinFnEntry *builtin_fn = heap::c_allocator.create(); - buf_init_from_str(&builtin_fn->name, name); - builtin_fn->id = id; - builtin_fn->param_count = count; - g->builtin_fn_table.put(&builtin_fn->name, builtin_fn); - return builtin_fn; -} - -static void define_builtin_fns(CodeGen *g) { - create_builtin_fn(g, BuiltinFnIdBreakpoint, "breakpoint", 0); - create_builtin_fn(g, BuiltinFnIdReturnAddress, "returnAddress", 0); - create_builtin_fn(g, BuiltinFnIdMemcpy, "memcpy", 3); - create_builtin_fn(g, BuiltinFnIdMemset, "memset", 3); - create_builtin_fn(g, BuiltinFnIdSizeof, "sizeOf", 1); - create_builtin_fn(g, BuiltinFnIdAlignOf, "alignOf", 1); - create_builtin_fn(g, BuiltinFnIdField, "field", 2); - create_builtin_fn(g, BuiltinFnIdTypeInfo, "typeInfo", 1); - create_builtin_fn(g, BuiltinFnIdType, "Type", 1); - create_builtin_fn(g, BuiltinFnIdHasField, "hasField", 2); - create_builtin_fn(g, BuiltinFnIdTypeof, "TypeOf", SIZE_MAX); - create_builtin_fn(g, BuiltinFnIdAddWithOverflow, "addWithOverflow", 4); - create_builtin_fn(g, BuiltinFnIdSubWithOverflow, "subWithOverflow", 4); - create_builtin_fn(g, BuiltinFnIdMulWithOverflow, "mulWithOverflow", 4); - create_builtin_fn(g, BuiltinFnIdShlWithOverflow, "shlWithOverflow", 4); - create_builtin_fn(g, BuiltinFnIdCInclude, "cInclude", 1); - create_builtin_fn(g, BuiltinFnIdCDefine, "cDefine", 2); - create_builtin_fn(g, BuiltinFnIdCUndef, "cUndef", 1); - create_builtin_fn(g, BuiltinFnIdCtz, "ctz", 1); - create_builtin_fn(g, BuiltinFnIdClz, "clz", 1); - create_builtin_fn(g, BuiltinFnIdPopCount, "popCount", 1); - create_builtin_fn(g, BuiltinFnIdBswap, "byteSwap", 1); - create_builtin_fn(g, BuiltinFnIdBitReverse, "bitReverse", 1); - create_builtin_fn(g, BuiltinFnIdImport, "import", 1); - create_builtin_fn(g, BuiltinFnIdCImport, "cImport", 1); - create_builtin_fn(g, BuiltinFnIdErrName, "errorName", 1); - create_builtin_fn(g, BuiltinFnIdTypeName, "typeName", 1); - create_builtin_fn(g, BuiltinFnIdEmbedFile, "embedFile", 1); - create_builtin_fn(g, BuiltinFnIdCmpxchgWeak, "cmpxchgWeak", 6); - create_builtin_fn(g, BuiltinFnIdCmpxchgStrong, "cmpxchgStrong", 6); - create_builtin_fn(g, BuiltinFnIdFence, "fence", 1); - create_builtin_fn(g, BuiltinFnIdTruncate, "truncate", 2); - create_builtin_fn(g, BuiltinFnIdIntCast, "intCast", 2); - create_builtin_fn(g, BuiltinFnIdFloatCast, "floatCast", 2); - create_builtin_fn(g, BuiltinFnIdIntToFloat, "intToFloat", 2); - create_builtin_fn(g, BuiltinFnIdFloatToInt, "floatToInt", 2); - create_builtin_fn(g, BuiltinFnIdBoolToInt, "boolToInt", 1); - create_builtin_fn(g, BuiltinFnIdErrToInt, "errorToInt", 1); - create_builtin_fn(g, BuiltinFnIdIntToErr, "intToError", 1); - create_builtin_fn(g, BuiltinFnIdEnumToInt, "enumToInt", 1); - create_builtin_fn(g, BuiltinFnIdIntToEnum, "intToEnum", 2); - create_builtin_fn(g, BuiltinFnIdCompileErr, "compileError", 1); - create_builtin_fn(g, BuiltinFnIdCompileLog, "compileLog", SIZE_MAX); - create_builtin_fn(g, BuiltinFnIdVectorType, "Vector", 2); - create_builtin_fn(g, BuiltinFnIdShuffle, "shuffle", 4); - create_builtin_fn(g, BuiltinFnIdSelect, "select", 4); - create_builtin_fn(g, BuiltinFnIdSplat, "splat", 2); - create_builtin_fn(g, BuiltinFnIdSetCold, "setCold", 1); - create_builtin_fn(g, BuiltinFnIdSetRuntimeSafety, "setRuntimeSafety", 1); - create_builtin_fn(g, BuiltinFnIdSetFloatMode, "setFloatMode", 1); - create_builtin_fn(g, BuiltinFnIdPanic, "panic", 1); - create_builtin_fn(g, BuiltinFnIdPtrCast, "ptrCast", 2); - create_builtin_fn(g, BuiltinFnIdBitCast, "bitCast", 2); - create_builtin_fn(g, BuiltinFnIdIntToPtr, "intToPtr", 2); - create_builtin_fn(g, BuiltinFnIdPtrToInt, "ptrToInt", 1); - create_builtin_fn(g, BuiltinFnIdTagName, "tagName", 1); - create_builtin_fn(g, BuiltinFnIdFieldParentPtr, "fieldParentPtr", 3); - create_builtin_fn(g, BuiltinFnIdOffsetOf, "offsetOf", 2); - create_builtin_fn(g, BuiltinFnIdBitOffsetOf, "bitOffsetOf", 2); - create_builtin_fn(g, BuiltinFnIdDivExact, "divExact", 2); - create_builtin_fn(g, BuiltinFnIdDivTrunc, "divTrunc", 2); - create_builtin_fn(g, BuiltinFnIdDivFloor, "divFloor", 2); - create_builtin_fn(g, BuiltinFnIdRem, "rem", 2); - create_builtin_fn(g, BuiltinFnIdMod, "mod", 2); - create_builtin_fn(g, BuiltinFnIdSqrt, "sqrt", 1); - create_builtin_fn(g, BuiltinFnIdSin, "sin", 1); - create_builtin_fn(g, BuiltinFnIdCos, "cos", 1); - create_builtin_fn(g, BuiltinFnIdTan, "tan", 1); - create_builtin_fn(g, BuiltinFnIdExp, "exp", 1); - create_builtin_fn(g, BuiltinFnIdExp2, "exp2", 1); - create_builtin_fn(g, BuiltinFnIdLog, "log", 1); - create_builtin_fn(g, BuiltinFnIdLog2, "log2", 1); - create_builtin_fn(g, BuiltinFnIdLog10, "log10", 1); - create_builtin_fn(g, BuiltinFnIdFabs, "fabs", 1); - create_builtin_fn(g, BuiltinFnIdFloor, "floor", 1); - create_builtin_fn(g, BuiltinFnIdCeil, "ceil", 1); - create_builtin_fn(g, BuiltinFnIdTrunc, "trunc", 1); - create_builtin_fn(g, BuiltinFnIdNearbyInt, "nearbyInt", 1); - create_builtin_fn(g, BuiltinFnIdRound, "round", 1); - create_builtin_fn(g, BuiltinFnIdMulAdd, "mulAdd", 4); - create_builtin_fn(g, BuiltinFnIdAsyncCall, "asyncCall", SIZE_MAX); - create_builtin_fn(g, BuiltinFnIdShlExact, "shlExact", 2); - create_builtin_fn(g, BuiltinFnIdShrExact, "shrExact", 2); - create_builtin_fn(g, BuiltinFnIdSetEvalBranchQuota, "setEvalBranchQuota", 1); - create_builtin_fn(g, BuiltinFnIdAlignCast, "alignCast", 2); - create_builtin_fn(g, BuiltinFnIdSetAlignStack, "setAlignStack", 1); - create_builtin_fn(g, BuiltinFnIdExport, "export", 2); - create_builtin_fn(g, BuiltinFnIdExtern, "extern", 2); - create_builtin_fn(g, BuiltinFnIdErrorReturnTrace, "errorReturnTrace", 0); - create_builtin_fn(g, BuiltinFnIdAtomicRmw, "atomicRmw", 5); - create_builtin_fn(g, BuiltinFnIdAtomicLoad, "atomicLoad", 3); - create_builtin_fn(g, BuiltinFnIdAtomicStore, "atomicStore", 4); - create_builtin_fn(g, BuiltinFnIdErrSetCast, "errSetCast", 2); - create_builtin_fn(g, BuiltinFnIdThis, "This", 0); - create_builtin_fn(g, BuiltinFnIdHasDecl, "hasDecl", 2); - create_builtin_fn(g, BuiltinFnIdUnionInit, "unionInit", 3); - create_builtin_fn(g, BuiltinFnIdFrameHandle, "frame", 0); - create_builtin_fn(g, BuiltinFnIdFrameType, "Frame", 1); - create_builtin_fn(g, BuiltinFnIdFrameAddress, "frameAddress", 0); - create_builtin_fn(g, BuiltinFnIdFrameSize, "frameSize", 1); - create_builtin_fn(g, BuiltinFnIdAs, "as", 2); - create_builtin_fn(g, BuiltinFnIdCall, "call", 3); - create_builtin_fn(g, BuiltinFnIdBitSizeof, "bitSizeOf", 1); - create_builtin_fn(g, BuiltinFnIdWasmMemorySize, "wasmMemorySize", 1); - create_builtin_fn(g, BuiltinFnIdWasmMemoryGrow, "wasmMemoryGrow", 2); - create_builtin_fn(g, BuiltinFnIdSrc, "src", 0); - create_builtin_fn(g, BuiltinFnIdReduce, "reduce", 2); - create_builtin_fn(g, BuiltinFnIdMaximum, "max", 2); - create_builtin_fn(g, BuiltinFnIdMinimum, "min", 2); - create_builtin_fn(g, BuiltinFnIdPrefetch, "prefetch", 2); - create_builtin_fn(g, BuiltinFnIdAddrSpaceCast, "addrSpaceCast", 2); -} - -static const char *bool_to_str(bool b) { - return b ? "true" : "false"; -} - -static const char *build_mode_to_str(BuildMode build_mode) { - switch (build_mode) { - case BuildModeDebug: return "Debug"; - case BuildModeSafeRelease: return "ReleaseSafe"; - case BuildModeFastRelease: return "ReleaseFast"; - case BuildModeSmallRelease: return "ReleaseSmall"; - } - zig_unreachable(); -} - -static const char *subsystem_to_str(TargetSubsystem subsystem) { - switch (subsystem) { - case TargetSubsystemConsole: return "Console"; - case TargetSubsystemWindows: return "Windows"; - case TargetSubsystemPosix: return "Posix"; - case TargetSubsystemNative: return "Native"; - case TargetSubsystemEfiApplication: return "EfiApplication"; - case TargetSubsystemEfiBootServiceDriver: return "EfiBootServiceDriver"; - case TargetSubsystemEfiRom: return "EfiRom"; - case TargetSubsystemEfiRuntimeDriver: return "EfiRuntimeDriver"; - case TargetSubsystemAuto: zig_unreachable(); - } - zig_unreachable(); -} - -// Returns TargetSubsystemAuto to mean "no subsystem" -TargetSubsystem detect_subsystem(CodeGen *g) { - if (g->subsystem != TargetSubsystemAuto) - return g->subsystem; - if (g->zig_target->os == OsWindows) { - if (g->stage1.have_dllmain_crt_startup) - return TargetSubsystemAuto; - if (g->stage1.have_c_main || g->is_test_build || g->stage1.have_winmain_crt_startup || g->stage1.have_wwinmain_crt_startup) - return TargetSubsystemConsole; - if (g->stage1.have_winmain || g->stage1.have_wwinmain) - return TargetSubsystemWindows; - } else if (g->zig_target->os == OsUefi) { - return TargetSubsystemEfiApplication; - } - return TargetSubsystemAuto; -} - -static bool detect_err_ret_tracing(CodeGen *g) { - return !g->strip_debug_symbols && - g->build_mode != BuildModeFastRelease && - g->build_mode != BuildModeSmallRelease; -} - -static LLVMCodeModel to_llvm_code_model(CodeGen *g) { - switch (g->code_model) { - case CodeModelDefault: - return LLVMCodeModelDefault; - case CodeModelTiny: - return LLVMCodeModelTiny; - case CodeModelSmall: - return LLVMCodeModelSmall; - case CodeModelKernel: - return LLVMCodeModelKernel; - case CodeModelMedium: - return LLVMCodeModelMedium; - case CodeModelLarge: - return LLVMCodeModelLarge; - } - - zig_unreachable(); -} - -Buf *codegen_generate_builtin_source(CodeGen *g) { - // Note that this only runs when zig0 is building the self-hosted zig compiler code, - // so it makes a few assumption that are always true for that case. Once we have - // built the stage2 zig components then zig is in charge of generating the builtin.zig - // file. - - g->have_err_ret_tracing = detect_err_ret_tracing(g); - - Buf *contents = buf_alloc(); - buf_appendf(contents, - "const std = @import(\"std\");\n" - ); - - const char *cur_os = nullptr; - { - uint32_t field_count = (uint32_t)target_os_count(); - for (uint32_t i = 0; i < field_count; i += 1) { - Os os_type = target_os_enum(i); - const char *name = target_os_name(os_type); - - if (os_type == g->zig_target->os) { - cur_os = name; - } - } - } - assert(cur_os != nullptr); - - const char *cur_arch = nullptr; - { - uint32_t field_count = (uint32_t)target_arch_count(); - for (uint32_t arch_i = 0; arch_i < field_count; arch_i += 1) { - ZigLLVM_ArchType arch = target_arch_enum(arch_i); - const char *arch_name = target_arch_name(arch); - if (arch == g->zig_target->arch) { - cur_arch = arch_name; - } - } - - // Workaround to LLVM/Zig naming mismatch. - // LLVM calls it sparcv9, while Zig calls it sparc64. - if (!strcmp(cur_arch, "sparcv9")) { - cur_arch = "sparc64"; - } - } - assert(cur_arch != nullptr); - - const char *cur_abi = nullptr; - { - uint32_t field_count = (uint32_t)target_abi_count(); - for (uint32_t i = 0; i < field_count; i += 1) { - ZigLLVM_EnvironmentType abi = target_abi_enum(i); - const char *name = target_abi_name(abi); - - if (abi == g->zig_target->abi) { - cur_abi = name; - } - } - } - assert(cur_abi != nullptr); - - const char *cur_obj_fmt = nullptr; - { - uint32_t field_count = (uint32_t)target_oformat_count(); - for (uint32_t i = 0; i < field_count; i += 1) { - ZigLLVM_ObjectFormatType oformat = target_oformat_enum(i); - const char *name = target_oformat_name(oformat); - - ZigLLVM_ObjectFormatType target_oformat = target_object_format(g->zig_target); - if (oformat == target_oformat) { - cur_obj_fmt = name; - } - } - - } - assert(cur_obj_fmt != nullptr); - - // If any of these asserts trip then you need to either fix the internal compiler enum - // or the corresponding one in std.Target or std.builtin. - static_assert(ContainerLayoutAuto == 0, ""); - static_assert(ContainerLayoutExtern == 1, ""); - static_assert(ContainerLayoutPacked == 2, ""); - - static_assert(CallingConventionUnspecified == 0, ""); - static_assert(CallingConventionC == 1, ""); - static_assert(CallingConventionNaked == 2, ""); - static_assert(CallingConventionAsync == 3, ""); - static_assert(CallingConventionInline == 4, ""); - static_assert(CallingConventionInterrupt == 5, ""); - static_assert(CallingConventionSignal == 6, ""); - static_assert(CallingConventionStdcall == 7, ""); - static_assert(CallingConventionFastcall == 8, ""); - static_assert(CallingConventionVectorcall == 9, ""); - static_assert(CallingConventionThiscall == 10, ""); - static_assert(CallingConventionAPCS == 11, ""); - static_assert(CallingConventionAAPCS == 12, ""); - static_assert(CallingConventionAAPCSVFP == 13, ""); - static_assert(CallingConventionSysV == 14, ""); - static_assert(CallingConventionWin64 == 15, ""); - - static_assert(BuiltinPtrSizeOne == 0, ""); - static_assert(BuiltinPtrSizeMany == 1, ""); - static_assert(BuiltinPtrSizeSlice == 2, ""); - static_assert(BuiltinPtrSizeC == 3, ""); - - static_assert(TargetSubsystemConsole == 0, ""); - static_assert(TargetSubsystemWindows == 1, ""); - static_assert(TargetSubsystemPosix == 2, ""); - static_assert(TargetSubsystemNative == 3, ""); - static_assert(TargetSubsystemEfiApplication == 4, ""); - static_assert(TargetSubsystemEfiBootServiceDriver == 5, ""); - static_assert(TargetSubsystemEfiRom == 6, ""); - static_assert(TargetSubsystemEfiRuntimeDriver == 7, ""); - - buf_appendf(contents, "pub const output_mode = std.builtin.OutputMode.Obj;\n"); - buf_appendf(contents, "pub const link_mode = std.builtin.LinkMode.%s;\n", ZIG_QUOTE(ZIG_LINK_MODE)); - buf_appendf(contents, "pub const is_test = false;\n"); - buf_appendf(contents, "pub const single_threaded = %s;\n", bool_to_str(g->is_single_threaded)); - buf_appendf(contents, "pub const abi = std.Target.Abi.%s;\n", cur_abi); - buf_appendf(contents, "pub const cpu = std.Target.Cpu.baseline(.%s);\n", cur_arch); - buf_appendf(contents, "pub const os = std.Target.Os.Tag.defaultVersionRange(.%s, .%s);\n", cur_os, cur_arch); - buf_appendf(contents, - "pub const target = std.Target{\n" - " .cpu = cpu,\n" - " .os = os,\n" - " .abi = abi,\n" - " .ofmt = object_format,\n" - "};\n" - ); - - buf_appendf(contents, "pub const object_format = std.Target.ObjectFormat.%s;\n", cur_obj_fmt); - buf_appendf(contents, "pub const mode = std.builtin.Mode.%s;\n", build_mode_to_str(g->build_mode)); - buf_appendf(contents, "pub const link_libc = %s;\n", bool_to_str(g->link_libc)); - buf_appendf(contents, "pub const link_libcpp = %s;\n", bool_to_str(g->link_libcpp)); - buf_appendf(contents, "pub const have_error_return_tracing = %s;\n", bool_to_str(g->have_err_ret_tracing)); - buf_appendf(contents, "pub const valgrind_support = false;\n"); - buf_appendf(contents, "pub const sanitize_thread = false;\n"); - buf_appendf(contents, "pub const position_independent_code = %s;\n", bool_to_str(g->have_pic)); - buf_appendf(contents, "pub const position_independent_executable = %s;\n", bool_to_str(g->have_pie)); - buf_appendf(contents, "pub const strip_debug_info = %s;\n", bool_to_str(g->strip_debug_symbols)); - buf_appendf(contents, "pub const code_model = std.builtin.CodeModel.default;\n"); - buf_appendf(contents, "pub const zig_backend = std.builtin.CompilerBackend.stage1;\n"); - - { - TargetSubsystem detected_subsystem = detect_subsystem(g); - if (detected_subsystem != TargetSubsystemAuto) { - buf_appendf(contents, "pub const explicit_subsystem = std.builtin.SubSystem.%s;\n", subsystem_to_str(detected_subsystem)); - } - } - - return contents; -} - -static ZigPackage *create_test_runner_pkg(CodeGen *g) { - return codegen_create_package(g, buf_ptr(g->zig_lib_dir), "test_runner.zig", ""); -} - -static Error define_builtin_compile_vars(CodeGen *g) { - Error err; - - if (g->std_package == nullptr) - return ErrorNone; - - assert(g->main_pkg); - - const char *builtin_zig_basename = "builtin.zig"; - - Buf *contents; - if (g->builtin_zig_path == nullptr) { - // Then this is zig0 building stage2. We can make many assumptions about the compilation. - Buf *out_dir = buf_alloc(); - os_path_split(&g->o_file_output_path, out_dir, nullptr); - g->builtin_zig_path = buf_alloc(); - os_path_join(out_dir, buf_create_from_str(builtin_zig_basename), g->builtin_zig_path); - - Buf *resolve_paths[] = { g->builtin_zig_path, }; - *g->builtin_zig_path = os_path_resolve(resolve_paths, 1); - - contents = codegen_generate_builtin_source(g); - if ((err = os_write_file(g->builtin_zig_path, contents))) { - fprintf(stderr, "Unable to write file '%s': %s\n", buf_ptr(g->builtin_zig_path), err_str(err)); - exit(1); - } - - g->compile_var_package = new_package(buf_ptr(out_dir), builtin_zig_basename, "builtin"); - } else { - Buf *resolve_paths[] = { g->builtin_zig_path, }; - *g->builtin_zig_path = os_path_resolve(resolve_paths, 1); - - contents = buf_alloc(); - if ((err = os_fetch_file_path(g->builtin_zig_path, contents))) { - fprintf(stderr, "unable to open '%s': %s\n", buf_ptr(g->builtin_zig_path), err_str(err)); - exit(1); - } - Buf builtin_dirname = BUF_INIT; - os_path_dirname(g->builtin_zig_path, &builtin_dirname); - g->compile_var_package = new_package(buf_ptr(&builtin_dirname), builtin_zig_basename, "builtin"); - } - - if (g->is_test_build) { - if (g->test_runner_package == nullptr) { - g->test_runner_package = create_test_runner_pkg(g); - } - g->root_pkg = g->test_runner_package; - } else { - g->root_pkg = g->main_pkg; - } - - ZigPackage *compiler_rt_pkg = codegen_create_package(g, buf_ptr(g->zig_lib_dir), - "compiler_rt.zig", "compiler_rt"); - - g->compile_var_package->package_table.put(buf_create_from_str("std"), g->std_package); - g->main_pkg->package_table.put(buf_create_from_str("builtin"), g->compile_var_package); - g->main_pkg->package_table.put(buf_create_from_str("root"), g->root_pkg); - g->std_package->package_table.put(buf_create_from_str("builtin"), g->compile_var_package); - g->std_package->package_table.put(buf_create_from_str("std"), g->std_package); - g->std_package->package_table.put(buf_create_from_str("root"), g->root_pkg); - g->std_package->package_table.put(buf_create_from_str("compiler_rt"), compiler_rt_pkg); - g->compile_var_import = add_source_file(g, g->compile_var_package, g->builtin_zig_path, contents, - SourceKindPkgMain); - - return ErrorNone; -} - -static void init(CodeGen *g) { - if (g->module) - return; - - codegen_add_time_event(g, "Initialize"); - { - const char *progress_name = "Initialize"; - codegen_switch_sub_prog_node(g, stage2_progress_start(g->main_progress_node, - progress_name, strlen(progress_name), 0)); - } - - g->have_err_ret_tracing = detect_err_ret_tracing(g); - - assert(g->root_out_name); - g->module = LLVMModuleCreateWithName(buf_ptr(g->root_out_name)); - - LLVMSetTarget(g->module, buf_ptr(&g->llvm_triple_str)); - - if (target_object_format(g->zig_target) == ZigLLVM_COFF) { - ZigLLVMAddModuleCodeViewFlag(g->module); - } else { - ZigLLVMAddModuleDebugInfoFlag(g->module); - } - - LLVMTargetRef target_ref; - char *err_msg = nullptr; - if (LLVMGetTargetFromTriple(buf_ptr(&g->llvm_triple_str), &target_ref, &err_msg)) { - fprintf(stderr, - "Zig is expecting LLVM to understand this target: '%s'\n" - "However LLVM responded with: \"%s\"\n" - "Zig is unable to continue. This is a bug in Zig:\n" - "https://github.com/ziglang/zig/issues/438\n" - , buf_ptr(&g->llvm_triple_str), err_msg); - exit(1); - } - - bool is_optimized = g->build_mode != BuildModeDebug; - LLVMCodeGenOptLevel opt_level = is_optimized ? LLVMCodeGenLevelAggressive : LLVMCodeGenLevelNone; - - LLVMRelocMode reloc_mode; - if (g->have_pic) { - reloc_mode = LLVMRelocPIC; - } else if (g->link_mode_dynamic) { - reloc_mode = LLVMRelocDynamicNoPic; - } else { - reloc_mode = LLVMRelocStatic; - } - - if (g->have_pic) { - ZigLLVMSetModulePICLevel(g->module); - } - - if (g->have_pie) { - ZigLLVMSetModulePIELevel(g->module); - } - - if (g->code_model != CodeModelDefault) { - ZigLLVMSetModuleCodeModel(g->module, to_llvm_code_model(g)); - } - - const char *target_specific_cpu_args = ""; - const char *target_specific_features = ""; - - if (g->zig_target->is_native_cpu) { - target_specific_cpu_args = ZigLLVMGetHostCPUName(); - target_specific_features = ZigLLVMGetNativeFeatures(); - } - - // Override CPU and features if defined by user. - if (g->zig_target->llvm_cpu_name != nullptr) { - target_specific_cpu_args = g->zig_target->llvm_cpu_name; - } - if (g->zig_target->llvm_cpu_features != nullptr) { - target_specific_features = g->zig_target->llvm_cpu_features; - } - if (g->verbose_llvm_cpu_features) { - fprintf(stderr, "name=%s triple=%s\n", buf_ptr(g->root_out_name), buf_ptr(&g->llvm_triple_str)); - fprintf(stderr, "name=%s target_specific_cpu_args=%s\n", buf_ptr(g->root_out_name), target_specific_cpu_args); - fprintf(stderr, "name=%s target_specific_features=%s\n", buf_ptr(g->root_out_name), target_specific_features); - } - - // TODO handle float ABI better- it should depend on the ABI portion of std.Target - ZigLLVMABIType float_abi = ZigLLVMABITypeDefault; - - const char *abi_name = g->zig_target->llvm_target_abi; - if (abi_name == nullptr && target_is_riscv(g->zig_target)) { - // RISC-V Linux defaults to ilp32d/lp64d - if (g->zig_target->os == OsLinux) { - abi_name = (g->zig_target->arch == ZigLLVM_riscv32) ? "ilp32d" : "lp64d"; - } else { - abi_name = (g->zig_target->arch == ZigLLVM_riscv32) ? "ilp32" : "lp64"; - } - } - - g->target_machine = ZigLLVMCreateTargetMachine(target_ref, buf_ptr(&g->llvm_triple_str), - target_specific_cpu_args, target_specific_features, opt_level, reloc_mode, - to_llvm_code_model(g), g->function_sections, float_abi, abi_name); - - g->target_data_ref = LLVMCreateTargetDataLayout(g->target_machine); - - char *layout_str = LLVMCopyStringRepOfTargetData(g->target_data_ref); - LLVMSetDataLayout(g->module, layout_str); - - assert(g->pointer_size_bytes == LLVMPointerSize(g->target_data_ref)); - g->is_big_endian = (LLVMByteOrder(g->target_data_ref) == LLVMBigEndian); - - g->builder = LLVMCreateBuilder(); - g->dbuilder = ZigLLVMCreateDIBuilder(g->module, true); - - // Don't use the version string here, llvm misparses it when it includes the git revision. - Stage2SemVer semver = stage2_version(); - Buf *producer = buf_sprintf("zig %d.%d.%d", semver.major, semver.minor, semver.patch); - const char *flags = ""; - unsigned runtime_version = 0; - - // For macOS stack traces, we want to avoid having to parse the compilation unit debug - // info. As long as each debug info file has a path independent of the compilation unit - // directory (DW_AT_comp_dir), then we never have to look at the compilation unit debug - // info. If we provide an absolute path to LLVM here for the compilation unit debug info, - // LLVM will emit DWARF info that depends on DW_AT_comp_dir. To avoid this, we pass "." - // for the compilation unit directory. This forces each debug file to have a directory - // rather than be relative to DW_AT_comp_dir. According to DWARF 5, debug files will - // no longer reference DW_AT_comp_dir, for the purpose of being able to support the - // common practice of stripping all but the line number sections from an executable. - const char *compile_unit_dir = target_os_is_darwin(g->zig_target->os) ? "." : - buf_ptr(&g->main_pkg->root_src_dir); - - ZigLLVMDIFile *compile_unit_file = ZigLLVMCreateFile(g->dbuilder, buf_ptr(g->root_out_name), - compile_unit_dir); - g->compile_unit = ZigLLVMCreateCompileUnit(g->dbuilder, ZigLLVMLang_DW_LANG_C99(), - compile_unit_file, buf_ptr(producer), is_optimized, flags, runtime_version, - "", 0, !g->strip_debug_symbols); - - // This is for debug stuff that doesn't have a real file. - g->dummy_di_file = nullptr; - - define_builtin_types(g); - define_intern_values(g); - - Stage1AirInst *sentinel_instructions = heap::c_allocator.allocate(2); - g->invalid_inst_gen = &sentinel_instructions[0]; - g->invalid_inst_gen->value = g->pass1_arena->create(); - g->invalid_inst_gen->value->type = g->builtin_types.entry_invalid; - - g->unreach_instruction = &sentinel_instructions[1]; - g->unreach_instruction->value = g->pass1_arena->create(); - g->unreach_instruction->value->type = g->builtin_types.entry_unreachable; - - g->invalid_inst_src = heap::c_allocator.create(); - - define_builtin_fns(g); - Error err; - if ((err = define_builtin_compile_vars(g))) { - fprintf(stderr, "Unable to create builtin.zig: %s\n", err_str(err)); - exit(1); - } -} - -static void update_test_functions_builtin_decl(CodeGen *g) { - Error err; - - assert(g->is_test_build); - - if (g->test_fns.length == 0) { - fprintf(stderr, "No tests to run.\n"); - exit(0); - } - - ZigType *fn_type = get_test_fn_type(g); - - ZigValue *test_fn_type_val = get_builtin_value(g, "TestFn"); - assert(test_fn_type_val->type->id == ZigTypeIdMetaType); - ZigType *struct_type = test_fn_type_val->data.x_type; - if ((err = type_resolve(g, struct_type, ResolveStatusSizeKnown))) - zig_unreachable(); - - ZigValue *test_fn_array = g->pass1_arena->create(); - test_fn_array->type = get_array_type(g, struct_type, g->test_fns.length, nullptr); - test_fn_array->special = ConstValSpecialStatic; - test_fn_array->data.x_array.data.s_none.elements = g->pass1_arena->allocate(g->test_fns.length); - - for (size_t i = 0; i < g->test_fns.length; i += 1) { - ZigFn *test_fn_entry = g->test_fns.at(i); - - ZigValue *this_val = &test_fn_array->data.x_array.data.s_none.elements[i]; - this_val->special = ConstValSpecialStatic; - this_val->type = struct_type; - this_val->parent.id = ConstParentIdArray; - this_val->parent.data.p_array.array_val = test_fn_array; - this_val->parent.data.p_array.elem_index = i; - this_val->data.x_struct.fields = alloc_const_vals_ptrs(g, 3); - - ZigValue *name_field = this_val->data.x_struct.fields[0]; - ZigValue *name_array_val = create_const_str_lit(g, &test_fn_entry->symbol_name)->data.x_ptr.data.ref.pointee; - init_const_slice(g, name_field, name_array_val, 0, buf_len(&test_fn_entry->symbol_name), true, nullptr); - - ZigValue *fn_field = this_val->data.x_struct.fields[1]; - fn_field->type = fn_type; - fn_field->special = ConstValSpecialStatic; - fn_field->data.x_ptr.special = ConstPtrSpecialFunction; - fn_field->data.x_ptr.mut = ConstPtrMutComptimeConst; - fn_field->data.x_ptr.data.fn.fn_entry = test_fn_entry; - - ZigValue *frame_size_field = this_val->data.x_struct.fields[2]; - frame_size_field->type = get_optional_type(g, g->builtin_types.entry_usize); - frame_size_field->special = ConstValSpecialStatic; - frame_size_field->data.x_optional = nullptr; - - if (fn_is_async(test_fn_entry)) { - frame_size_field->data.x_optional = g->pass1_arena->create(); - frame_size_field->data.x_optional->special = ConstValSpecialStatic; - frame_size_field->data.x_optional->type = g->builtin_types.entry_usize; - bigint_init_unsigned(&frame_size_field->data.x_optional->data.x_bigint, - test_fn_entry->frame_type->abi_size); - } - } - report_errors_and_maybe_exit(g); - - ZigValue *test_fn_slice = create_const_slice(g, test_fn_array, 0, g->test_fns.length, true, nullptr); - - update_compile_var(g, buf_create_from_str("test_functions"), test_fn_slice); - assert(g->test_runner_package != nullptr); -} - -static Buf *get_resolved_root_src_path(CodeGen *g) { - // TODO memoize - if (buf_len(&g->main_pkg->root_src_path) == 0) - return nullptr; - - Buf rel_full_path = BUF_INIT; - os_path_join(&g->main_pkg->root_src_dir, &g->main_pkg->root_src_path, &rel_full_path); - - Buf *resolved_path = buf_alloc(); - Buf *resolve_paths[] = {&rel_full_path}; - *resolved_path = os_path_resolve(resolve_paths, 1); - - return resolved_path; -} - -static void gen_root_source(CodeGen *g) { - Buf *resolved_path = get_resolved_root_src_path(g); - if (resolved_path == nullptr) - return; - - Buf *source_code = buf_alloc(); - Error err; - // No need for using the caching system for this file fetch because it is handled - // separately. - if ((err = os_fetch_file_path(resolved_path, source_code))) { - fprintf(stderr, "unable to open '%s': %s\n", buf_ptr(resolved_path), err_str(err)); - exit(1); - } - - ZigType *root_import_alias = add_source_file(g, g->main_pkg, resolved_path, source_code, SourceKindRoot); - assert(root_import_alias == g->root_import); - - assert(g->root_out_name); - - // Zig has lazy top level definitions. Here we semantically analyze the panic function. - Buf *import_target_path; - Buf full_path = BUF_INIT; - ZigType *std_import; - if ((err = analyze_import(g, g->root_import, buf_create_from_str("std"), &std_import, - &import_target_path, &full_path))) - { - if (err == ErrorFileNotFound) { - fprintf(stderr, "unable to find '%s'", buf_ptr(import_target_path)); - } else { - fprintf(stderr, "unable to open '%s': %s\n", buf_ptr(&full_path), err_str(err)); - } - exit(1); - } - - Tld *builtin_tld = find_decl(g, &get_container_scope(std_import)->base, - buf_create_from_str("builtin")); - assert(builtin_tld != nullptr); - resolve_top_level_decl(g, builtin_tld, nullptr, false); - report_errors_and_maybe_exit(g); - assert(builtin_tld->id == TldIdVar); - TldVar *builtin_tld_var = (TldVar*)builtin_tld; - ZigValue *builtin_val = builtin_tld_var->var->const_value; - assert(builtin_val->type->id == ZigTypeIdMetaType); - g->std_builtin_import = builtin_val->data.x_type; - - Tld *panic_tld = find_decl(g, &get_container_scope(g->std_builtin_import)->base, - buf_create_from_str("panic")); - assert(panic_tld != nullptr); - resolve_top_level_decl(g, panic_tld, nullptr, false); - report_errors_and_maybe_exit(g); - assert(panic_tld->id == TldIdVar); - TldVar *panic_tld_var = (TldVar*)panic_tld; - ZigValue *panic_fn_val = panic_tld_var->var->const_value; - assert(panic_fn_val->type->id == ZigTypeIdFn); - assert(panic_fn_val->data.x_ptr.special == ConstPtrSpecialFunction); - g->panic_fn = panic_fn_val->data.x_ptr.data.fn.fn_entry; - assert(g->panic_fn != nullptr); - - if (g->include_compiler_rt) { - Buf *import_target_path; - Buf full_path = BUF_INIT; - ZigType *compiler_rt_import; - if ((err = analyze_import(g, std_import, buf_create_from_str("compiler_rt"), - &compiler_rt_import, &import_target_path, &full_path))) - { - if (err == ErrorFileNotFound) { - fprintf(stderr, "unable to find '%s'\n", buf_ptr(import_target_path)); - } else { - fprintf(stderr, "unable to open '%s': %s\n", buf_ptr(&full_path), err_str(err)); - } - exit(1); - } - } - - if (!g->error_during_imports) { - semantic_analyze(g); - } - report_errors_and_maybe_exit(g); - - if (g->is_test_build) { - update_test_functions_builtin_decl(g); - if (!g->error_during_imports) { - semantic_analyze(g); - } - } - - report_errors_and_maybe_exit(g); - -} - -void codegen_print_timing_report(CodeGen *g, FILE *f) { - double start_time = g->timing_events.at(0).time; - double end_time = g->timing_events.last().time; - double total = end_time - start_time; - fprintf(f, "%20s%12s%12s%12s%12s\n", "Name", "Start", "End", "Duration", "Percent"); - for (size_t i = 0; i < g->timing_events.length - 1; i += 1) { - TimeEvent *te = &g->timing_events.at(i); - TimeEvent *next_te = &g->timing_events.at(i + 1); - fprintf(f, "%20s%12.4f%12.4f%12.4f%12.4f\n", te->name, - te->time - start_time, - next_te->time - start_time, - next_te->time - te->time, - (next_te->time - te->time) / total); - } - fprintf(f, "%20s%12.4f%12.4f%12.4f%12.4f\n", "Total", 0.0, total, total, 1.0); -} - -void codegen_add_time_event(CodeGen *g, const char *name) { - OsTimeStamp timestamp = os_timestamp_monotonic(); - double seconds = (double)timestamp.sec; - seconds += ((double)timestamp.nsec) / 1000000000.0; - g->timing_events.append({seconds, name}); -} - -void codegen_build_object(CodeGen *g) { - g->have_err_ret_tracing = detect_err_ret_tracing(g); - - init(g); - - codegen_add_time_event(g, "Semantic Analysis"); - const char *progress_name = "Semantic Analysis"; - codegen_switch_sub_prog_node(g, stage2_progress_start(g->main_progress_node, - progress_name, strlen(progress_name), 0)); - - gen_root_source(g); - - - codegen_add_time_event(g, "Code Generation"); - { - const char *progress_name = "Code Generation"; - codegen_switch_sub_prog_node(g, stage2_progress_start(g->main_progress_node, - progress_name, strlen(progress_name), 0)); - } - - do_code_gen(g); - codegen_add_time_event(g, "LLVM Emit Object"); - { - const char *progress_name = "LLVM Emit Object"; - codegen_switch_sub_prog_node(g, stage2_progress_start(g->main_progress_node, - progress_name, strlen(progress_name), 0)); - } - zig_llvm_emit_output(g); - - codegen_add_time_event(g, "Done"); - codegen_switch_sub_prog_node(g, nullptr); - - // append all export symbols to stage2 so we can provide them to the linker - if (target_is_wasm(g->zig_target)){ - Error err; - auto export_it = g->exported_symbol_names.entry_iterator(); - decltype(g->exported_symbol_names)::Entry *curr_entry = nullptr; - while ((curr_entry = export_it.next()) != nullptr) { - if ((err = stage2_append_symbol(&g->stage1, buf_ptr(curr_entry->key), buf_len(curr_entry->key)))) { - fprintf(stderr, "Unable to export symbol '%s': %s\n", buf_ptr(curr_entry->key), err_str(err)); - } - } - } -} - -ZigPackage *codegen_create_package(CodeGen *g, const char *root_src_dir, const char *root_src_path, - const char *pkg_path) -{ - init(g); - ZigPackage *pkg = new_package(root_src_dir, root_src_path, pkg_path); - if (g->std_package != nullptr) { - assert(g->compile_var_package != nullptr); - pkg->package_table.put(buf_create_from_str("std"), g->std_package); - - pkg->package_table.put(buf_create_from_str("root"), g->root_pkg); - - pkg->package_table.put(buf_create_from_str("builtin"), g->compile_var_package); - } - return pkg; -} - -void codegen_destroy(CodeGen *g) { - if (g->pass1_arena != nullptr) { - g->pass1_arena->destruct(&heap::c_allocator); - g->pass1_arena = nullptr; - } - heap::c_allocator.destroy(g); -} - -CodeGen *codegen_create(Buf *main_pkg_path, Buf *root_src_path, const ZigTarget *target, - BuildMode build_mode, Buf *override_lib_dir, - bool is_test_build) -{ - CodeGen *g = heap::c_allocator.create(); - g->pass1_arena = heap::ArenaAllocator::construct(&heap::c_allocator, &heap::c_allocator, "pass1"); - - g->subsystem = TargetSubsystemAuto; - g->zig_target = target; - - assert(override_lib_dir != nullptr); - g->zig_lib_dir = override_lib_dir; - - g->zig_std_dir = buf_alloc(); - os_path_join(g->zig_lib_dir, buf_create_from_str("std"), g->zig_std_dir); - - g->build_mode = build_mode; - g->import_table.init(32); - g->builtin_fn_table.init(32); - g->primitive_type_table.init(32); - g->type_table.init(32); - g->fn_type_table.init(32); - g->error_table.init(16); - g->generic_table.init(16); - g->llvm_fn_table.init(16); - g->memoized_fn_eval_table.init(16); - g->exported_symbol_names.init(8); - g->external_symbol_names.init(8); - g->string_literals_table.init(16); - g->type_info_cache.init(32); - g->one_possible_values.init(32); - g->is_test_build = is_test_build; - g->is_single_threaded = false; - g->code_model = CodeModelDefault; - buf_resize(&g->global_asm, 0); - - for (size_t i = 0; i < array_length(symbols_that_llvm_depends_on); i += 1) { - g->external_symbol_names.put(buf_create_from_str(symbols_that_llvm_depends_on[i]), nullptr); - } - - if (root_src_path) { - Buf *root_pkg_path; - Buf *rel_root_src_path; - if (main_pkg_path == nullptr) { - Buf *src_basename = buf_alloc(); - Buf *src_dir = buf_alloc(); - os_path_split(root_src_path, src_dir, src_basename); - - if (buf_len(src_basename) == 0) { - fprintf(stderr, "Invalid root source path: %s\n", buf_ptr(root_src_path)); - exit(1); - } - root_pkg_path = src_dir; - rel_root_src_path = src_basename; - } else { - Buf resolved_root_src_path = os_path_resolve(&root_src_path, 1); - Buf resolved_main_pkg_path = os_path_resolve(&main_pkg_path, 1); - - if (!buf_starts_with_buf(&resolved_root_src_path, &resolved_main_pkg_path)) { - fprintf(stderr, "Root source path '%s' outside main package path '%s'\n", - buf_ptr(root_src_path), buf_ptr(main_pkg_path)); - exit(1); - } - root_pkg_path = main_pkg_path; - rel_root_src_path = buf_create_from_mem( - buf_ptr(&resolved_root_src_path) + buf_len(&resolved_main_pkg_path) + 1, - buf_len(&resolved_root_src_path) - buf_len(&resolved_main_pkg_path) - 1); - } - - g->main_pkg = new_package(buf_ptr(root_pkg_path), buf_ptr(rel_root_src_path), ""); - g->std_package = new_package(buf_ptr(g->zig_std_dir), "std.zig", "std"); - g->main_pkg->package_table.put(buf_create_from_str("std"), g->std_package); - } else { - g->main_pkg = new_package(".", "", ""); - } - - target_triple_llvm(&g->llvm_triple_str, g->zig_target); - g->pointer_size_bytes = target_arch_pointer_bit_width(g->zig_target->arch) / 8; - - if (!target_has_debug_info(g->zig_target)) { - g->strip_debug_symbols = true; - } - - return g; -} - -bool codegen_fn_has_err_ret_tracing_arg(CodeGen *g, ZigType *return_type) { - return g->have_err_ret_tracing && - (return_type->id == ZigTypeIdErrorUnion || - return_type->id == ZigTypeIdErrorSet); -} - -bool codegen_fn_has_err_ret_tracing_stack(CodeGen *g, ZigFn *fn, bool is_async) { - if (is_async) { - return g->have_err_ret_tracing && (fn->calls_or_awaits_errorable_fn || - codegen_fn_has_err_ret_tracing_arg(g, fn->type_entry->data.fn.fn_type_id.return_type)); - } else { - return g->have_err_ret_tracing && fn->calls_or_awaits_errorable_fn && - !codegen_fn_has_err_ret_tracing_arg(g, fn->type_entry->data.fn.fn_type_id.return_type); - } -} - -void codegen_switch_sub_prog_node(CodeGen *g, Stage2ProgressNode *node) { - if (g->sub_progress_node != nullptr) { - stage2_progress_end(g->sub_progress_node); - } - g->sub_progress_node = node; -} - -ZigValue *CodeGen::Intern::for_undefined() { - return &this->x_undefined; -} - -ZigValue *CodeGen::Intern::for_void() { - return &this->x_void; -} - -ZigValue *CodeGen::Intern::for_null() { - return &this->x_null; -} - -ZigValue *CodeGen::Intern::for_unreachable() { - return &this->x_unreachable; -} - -ZigValue *CodeGen::Intern::for_zero_byte() { - return &this->zero_byte; -} diff --git a/src/stage1/codegen.hpp b/src/stage1/codegen.hpp deleted file mode 100644 index 33b2f7475794..000000000000 --- a/src/stage1/codegen.hpp +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (c) 2015 Andrew Kelley - * - * This file is part of zig, which is MIT licensed. - * See http://opensource.org/licenses/MIT - */ - -#ifndef ZIG_CODEGEN_HPP -#define ZIG_CODEGEN_HPP - -#include "parser.hpp" -#include "errmsg.hpp" -#include "target.hpp" -#include "stage2.h" - -#include - -CodeGen *codegen_create(Buf *main_pkg_path, Buf *root_src_path, const ZigTarget *target, - BuildMode build_mode, Buf *zig_lib_dir, bool is_test_build); - -void codegen_build_object(CodeGen *g); -void codegen_destroy(CodeGen *); - -void codegen_add_time_event(CodeGen *g, const char *name); -void codegen_print_timing_report(CodeGen *g, FILE *f); - -ZigPackage *codegen_create_package(CodeGen *g, const char *root_src_dir, const char *root_src_path, - const char *pkg_path); - -TargetSubsystem detect_subsystem(CodeGen *g); - -bool codegen_fn_has_err_ret_tracing_arg(CodeGen *g, ZigType *return_type); -bool codegen_fn_has_err_ret_tracing_stack(CodeGen *g, ZigFn *fn, bool is_async); - -ATTRIBUTE_NORETURN -void codegen_report_errors_and_exit(CodeGen *g); - -void codegen_switch_sub_prog_node(CodeGen *g, Stage2ProgressNode *node); - -#endif diff --git a/src/stage1/empty.cpp b/src/stage1/empty.cpp deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/src/stage1/errmsg.cpp b/src/stage1/errmsg.cpp deleted file mode 100644 index 943b118ddbf2..000000000000 --- a/src/stage1/errmsg.cpp +++ /dev/null @@ -1,135 +0,0 @@ -/* - * Copyright (c) 2016 Andrew Kelley - * - * This file is part of zig, which is MIT licensed. - * See http://opensource.org/licenses/MIT - */ - -#include "errmsg.hpp" -#include "os.hpp" - -#include - -enum ErrType { - ErrTypeError, - ErrTypeNote, -}; - -static void print_err_msg_type(ErrorMsg *err, ErrColor color, ErrType err_type) { - bool supports_color = os_stderr_supports_color(); - bool use_colors = color == ErrColorOn || (color == ErrColorAuto && supports_color); - - // Show the error location, if available - if (err->path != nullptr) { - const char *path = buf_ptr(err->path); - Slice pathslice{path, strlen(path)}; - - // Cache cwd - static Buf *cwdbuf{nullptr}; - static Slice cwd; - - if (cwdbuf == nullptr) { - cwdbuf = buf_alloc(); - Error err = os_get_cwd(cwdbuf); - if (err != ErrorNone) - zig_panic("get cwd failed"); - buf_append_char(cwdbuf, ZIG_OS_SEP_CHAR); - cwd.ptr = buf_ptr(cwdbuf); - cwd.len = strlen(cwd.ptr); - } - - const size_t line = err->line_start + 1; - const size_t col = err->column_start + 1; - if (use_colors) os_stderr_set_color(TermColorBold); - - // Strip cwd from path - if (memStartsWith(pathslice, cwd)) - fprintf(stderr, ".%c%s:%" ZIG_PRI_usize ":%" ZIG_PRI_usize ": ", ZIG_OS_SEP_CHAR, path+cwd.len, line, col); - else - fprintf(stderr, "%s:%" ZIG_PRI_usize ":%" ZIG_PRI_usize ": ", path, line, col); - } - - // Write out the error type - switch (err_type) { - case ErrTypeError: - if (use_colors) os_stderr_set_color(TermColorRed); - fprintf(stderr, "error: "); - break; - case ErrTypeNote: - if (use_colors) os_stderr_set_color(TermColorCyan); - fprintf(stderr, "note: "); - break; - default: - zig_unreachable(); - } - - // Write out the error message - if (use_colors) os_stderr_set_color(TermColorBold); - fputs(buf_ptr(err->msg), stderr); - if (use_colors) os_stderr_set_color(TermColorReset); - fputc('\n', stderr); - - if (buf_len(&err->line_buf) != 0){ - // Show the referenced line - fprintf(stderr, "%s\n", buf_ptr(&err->line_buf)); - for (size_t i = 0; i < err->column_start; i += 1) { - fprintf(stderr, " "); - } - // Draw the caret - if (use_colors) os_stderr_set_color(TermColorGreen); - fprintf(stderr, "^"); - if (use_colors) os_stderr_set_color(TermColorReset); - fprintf(stderr, "\n"); - } - - for (size_t i = 0; i < err->notes.length; i += 1) { - ErrorMsg *note = err->notes.at(i); - print_err_msg_type(note, color, ErrTypeNote); - } -} - -void print_err_msg(ErrorMsg *err, ErrColor color) { - print_err_msg_type(err, color, ErrTypeError); -} - -void err_msg_add_note(ErrorMsg *parent, ErrorMsg *note) { - parent->notes.append(note); -} - -ErrorMsg *err_msg_create_with_offset(Buf *path, uint32_t byte_offset, const char *source, - Buf *msg) -{ - ErrorMsg *err_msg = heap::c_allocator.create(); - err_msg->path = path; - err_msg->msg = msg; - err_msg->line_start = 0; - err_msg->column_start = 0; - - if (source == nullptr) { - // Must initialize the buffer anyway - buf_init_from_str(&err_msg->line_buf, ""); - return err_msg; - } - - size_t line_start = 0; - size_t i = 0; - for (;i < byte_offset; i += 1) { - switch (source[i]) { - case '\n': - err_msg->line_start += 1; - err_msg->column_start = 0; - line_start = i + 1; - continue; - default: - err_msg->column_start += 1; - continue; - } - } - while (source[i] != '\n' && source[i] != 0) { - i += 1; - } - - buf_init_from_mem(&err_msg->line_buf, source + line_start, i - line_start); - - return err_msg; -} diff --git a/src/stage1/errmsg.hpp b/src/stage1/errmsg.hpp deleted file mode 100644 index b8b6b3e7f29a..000000000000 --- a/src/stage1/errmsg.hpp +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (c) 2015 Andrew Kelley - * - * This file is part of zig, which is MIT licensed. - * See http://opensource.org/licenses/MIT - */ - -#ifndef ZIG_ERRMSG_HPP -#define ZIG_ERRMSG_HPP - -#include "buffer.hpp" -#include "list.hpp" -#include "stage1.h" - -struct ErrorMsg { - size_t line_start; - size_t column_start; - Buf *msg; - Buf *path; - Buf line_buf; - - ZigList notes; -}; - -void print_err_msg(ErrorMsg *msg, ErrColor color); - -void err_msg_add_note(ErrorMsg *parent, ErrorMsg *note); -ErrorMsg *err_msg_create_with_offset(Buf *path, uint32_t byte_offset, const char *source, Buf *msg); - -#endif diff --git a/src/stage1/error.cpp b/src/stage1/error.cpp deleted file mode 100644 index e77632e8f25d..000000000000 --- a/src/stage1/error.cpp +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Copyright (c) 2016 Andrew Kelley - * - * This file is part of zig, which is MIT licensed. - * See http://opensource.org/licenses/MIT - */ - -#include "error.hpp" - -const char *err_str(Error err) { - switch (err) { - case ErrorNone: return "(no error)"; - case ErrorNoMem: return "out of memory"; - case ErrorInvalidFormat: return "invalid format"; - case ErrorSemanticAnalyzeFail: return "semantic analyze failed"; - case ErrorAccess: return "access denied"; - case ErrorInterrupted: return "interrupted"; - case ErrorSystemResources: return "lack of system resources"; - case ErrorFileNotFound: return "file not found"; - case ErrorFileSystem: return "file system error"; - case ErrorFileTooBig: return "file too big"; - case ErrorDivByZero: return "division by zero"; - case ErrorOverflow: return "overflow"; - case ErrorPathAlreadyExists: return "path already exists"; - case ErrorUnexpected: return "unexpected error"; - case ErrorExactDivRemainder: return "exact division had a remainder"; - case ErrorNegativeDenominator: return "negative denominator"; - case ErrorShiftedOutOneBits: return "exact shift shifted out one bits"; - case ErrorCCompileErrors: return "C compile errors"; - case ErrorEndOfFile: return "end of file"; - case ErrorIsDir: return "is directory"; - case ErrorNotDir: return "not a directory"; - case ErrorUnsupportedOperatingSystem: return "unsupported operating system"; - case ErrorSharingViolation: return "sharing violation"; - case ErrorPipeBusy: return "pipe busy"; - case ErrorPrimitiveTypeNotFound: return "primitive type not found"; - case ErrorCacheUnavailable: return "cache unavailable"; - case ErrorPathTooLong: return "path too long"; - case ErrorCCompilerCannotFindFile: return "C compiler cannot find file"; - case ErrorReadingDepFile: return "failed to read .d file"; - case ErrorInvalidDepFile: return "invalid .d file"; - case ErrorMissingArchitecture: return "missing architecture"; - case ErrorMissingOperatingSystem: return "missing operating system"; - case ErrorUnknownArchitecture: return "unrecognized architecture"; - case ErrorUnknownOperatingSystem: return "unrecognized operating system"; - case ErrorUnknownABI: return "unrecognized C ABI"; - case ErrorInvalidFilename: return "invalid filename"; - case ErrorDiskQuota: return "disk space quota exceeded"; - case ErrorDiskSpace: return "out of disk space"; - case ErrorUnexpectedWriteFailure: return "unexpected write failure"; - case ErrorUnexpectedSeekFailure: return "unexpected seek failure"; - case ErrorUnexpectedFileTruncationFailure: return "unexpected file truncation failure"; - case ErrorUnimplemented: return "unimplemented"; - case ErrorOperationAborted: return "operation aborted"; - case ErrorBrokenPipe: return "broken pipe"; - case ErrorNoSpaceLeft: return "no space left"; - case ErrorNoCCompilerInstalled: return "no C compiler installed"; - case ErrorNotLazy: return "not lazy"; - case ErrorIsAsync: return "is async"; - case ErrorImportOutsidePkgPath: return "import of file outside package path"; - case ErrorUnknownCpu: return "unknown CPU"; - case ErrorUnknownCpuFeature: return "unknown CPU feature"; - case ErrorInvalidCpuFeatures: return "invalid CPU features"; - case ErrorInvalidLlvmCpuFeaturesFormat: return "invalid LLVM CPU features format"; - case ErrorUnknownApplicationBinaryInterface: return "unknown application binary interface"; - case ErrorASTUnitFailure: return "compiler bug: clang encountered a compile error, but the libclang API does not expose the error. See https://github.com/ziglang/zig/issues/4455 for more details"; - case ErrorBadPathName: return "bad path name"; - case ErrorSymLinkLoop: return "sym link loop"; - case ErrorProcessFdQuotaExceeded: return "process fd quota exceeded"; - case ErrorSystemFdQuotaExceeded: return "system fd quota exceeded"; - case ErrorNoDevice: return "no device"; - case ErrorDeviceBusy: return "device busy"; - case ErrorUnableToSpawnCCompiler: return "unable to spawn system C compiler"; - case ErrorCCompilerExitCode: return "system C compiler exited with failure code"; - case ErrorCCompilerCrashed: return "system C compiler crashed"; - case ErrorCCompilerCannotFindHeaders: return "system C compiler cannot find libc headers"; - case ErrorLibCRuntimeNotFound: return "libc runtime not found"; - case ErrorLibCStdLibHeaderNotFound: return "libc std lib headers not found"; - case ErrorLibCKernel32LibNotFound: return "kernel32 library not found"; - case ErrorUnsupportedArchitecture: return "unsupported architecture"; - case ErrorWindowsSdkNotFound: return "Windows SDK not found"; - case ErrorUnknownDynamicLinkerPath: return "unknown dynamic linker path"; - case ErrorTargetHasNoDynamicLinker: return "target has no dynamic linker"; - case ErrorInvalidAbiVersion: return "invalid C ABI version"; - case ErrorInvalidOperatingSystemVersion: return "invalid operating system version"; - case ErrorUnknownClangOption: return "unknown Clang option"; - case ErrorNestedResponseFile: return "nested response file"; - case ErrorZigIsTheCCompiler: return "Zig was not provided with libc installation information, and so it does not know where the libc paths are on the system. Zig attempted to use the system C compiler to find out where the libc paths are, but discovered that Zig is being used as the system C compiler."; - case ErrorFileBusy: return "file is busy"; - case ErrorLocked: return "file is locked by another process"; - case ErrorInvalidCharacter: return "invalid character"; - case ErrorUnicodePointTooLarge: return "unicode codepoint too large"; - } - return "(invalid error)"; -} diff --git a/src/stage1/error.hpp b/src/stage1/error.hpp deleted file mode 100644 index 90772df10814..000000000000 --- a/src/stage1/error.hpp +++ /dev/null @@ -1,17 +0,0 @@ -/* - * Copyright (c) 2015 Andrew Kelley - * - * This file is part of zig, which is MIT licensed. - * See http://opensource.org/licenses/MIT - */ - -#ifndef ERROR_HPP -#define ERROR_HPP - -#include "stage2.h" - -const char *err_str(Error err); - -#define assertNoError(err) assert((err) == ErrorNone); - -#endif diff --git a/src/stage1/hash_map.hpp b/src/stage1/hash_map.hpp deleted file mode 100644 index 0dad87289ebf..000000000000 --- a/src/stage1/hash_map.hpp +++ /dev/null @@ -1,446 +0,0 @@ -/* - * Copyright (c) 2015 Andrew Kelley - * - * This file is part of zig, which is MIT licensed. - * See http://opensource.org/licenses/MIT - */ - -#ifndef ZIG_HASH_MAP_HPP -#define ZIG_HASH_MAP_HPP - -#include "util.hpp" - -#include - -template -struct MakePointer { - typedef K const *Type; - static Type convert(K const &val) { - return &val; - } -}; - -template -struct MakePointer { - typedef K *Type; - static Type convert(K * const &val) { - return val; - } -}; - -template -struct MakePointer { - typedef K const *Type; - static Type convert(K const * const &val) { - return val; - } -}; - -template::Type key), - bool (*EqualFn)(typename MakePointer::Type a, typename MakePointer::Type b)> -class HashMap { -public: - void init(int capacity) { - init_capacity(capacity); - } - void deinit(void) { - _entries.deinit(); - heap::c_allocator.deallocate(_index_bytes, - _indexes_len * capacity_index_size(_indexes_len)); - } - - struct Entry { - uint32_t hash; - uint32_t distance_from_start_index; - K key; - V value; - }; - - void clear() { - _entries.clear(); - memset(_index_bytes, 0, _indexes_len * capacity_index_size(_indexes_len)); - _max_distance_from_start_index = 0; - _modification_count += 1; - } - - size_t size() const { - return _entries.length; - } - - void put(const K &key, const V &value) { - _modification_count += 1; - - // This allows us to take a pointer to an entry in `internal_put` which - // will not become a dead pointer when the array list is appended. - _entries.ensure_capacity(_entries.length + 1); - - if (_index_bytes == nullptr) { - if (_entries.length < 16) { - _entries.append({HashFunction(MakePointer::convert(key)), 0, key, value}); - return; - } else { - _indexes_len = 32; - _index_bytes = heap::c_allocator.allocate(_indexes_len); - _max_distance_from_start_index = 0; - for (size_t i = 0; i < _entries.length; i += 1) { - Entry *entry = &_entries.items[i]; - put_index(entry, i, _index_bytes); - } - return internal_put(key, value, _index_bytes); - } - } - - // if we would get too full (60%), double the indexes size - if ((_entries.length + 1) * 5 >= _indexes_len * 3) { - heap::c_allocator.deallocate(_index_bytes, - _indexes_len * capacity_index_size(_indexes_len)); - _indexes_len *= 2; - size_t sz = capacity_index_size(_indexes_len); - // This zero initializes the bytes, setting them all empty. - _index_bytes = heap::c_allocator.allocate(_indexes_len * sz); - _max_distance_from_start_index = 0; - for (size_t i = 0; i < _entries.length; i += 1) { - Entry *entry = &_entries.items[i]; - switch (sz) { - case 1: - put_index(entry, i, (uint8_t*)_index_bytes); - continue; - case 2: - put_index(entry, i, (uint16_t*)_index_bytes); - continue; - case 4: - put_index(entry, i, (uint32_t*)_index_bytes); - continue; - default: - put_index(entry, i, (size_t*)_index_bytes); - continue; - } - } - } - - switch (capacity_index_size(_indexes_len)) { - case 1: return internal_put(key, value, (uint8_t*)_index_bytes); - case 2: return internal_put(key, value, (uint16_t*)_index_bytes); - case 4: return internal_put(key, value, (uint32_t*)_index_bytes); - default: return internal_put(key, value, (size_t*)_index_bytes); - } - } - - Entry *put_unique(const K &key, const V &value) { - // TODO make this more efficient - Entry *entry = internal_get(key); - if (entry) - return entry; - put(key, value); - return nullptr; - } - - const V &get(const K &key) const { - Entry *entry = internal_get(key); - if (!entry) - zig_panic("key not found"); - return entry->value; - } - - Entry *maybe_get(const K &key) const { - return internal_get(key); - } - - bool remove(const K &key) { - bool deleted_something = maybe_remove(key); - if (!deleted_something) - zig_panic("key not found"); - return deleted_something; - } - - bool maybe_remove(const K &key) { - _modification_count += 1; - if (_index_bytes == nullptr) { - uint32_t hash = HashFunction(MakePointer::convert(key)); - for (size_t i = 0; i < _entries.length; i += 1) { - if (_entries.items[i].hash == hash && EqualFn(MakePointer::convert(_entries.items[i].key), MakePointer::convert(key))) { - _entries.swap_remove(i); - return true; - } - } - return false; - } - switch (capacity_index_size(_indexes_len)) { - case 1: return internal_remove(key, (uint8_t*)_index_bytes); - case 2: return internal_remove(key, (uint16_t*)_index_bytes); - case 4: return internal_remove(key, (uint32_t*)_index_bytes); - default: return internal_remove(key, (size_t*)_index_bytes); - } - } - - class Iterator { - public: - Entry *next() { - if (_inital_modification_count != _table->_modification_count) - zig_panic("concurrent modification"); - if (_index >= _table->_entries.length) - return nullptr; - Entry *entry = &_table->_entries.items[_index]; - _index += 1; - return entry; - } - private: - const HashMap * _table; - // iterator through the entry array - size_t _index = 0; - // used to detect concurrent modification - uint32_t _inital_modification_count; - Iterator(const HashMap * table) : - _table(table), _inital_modification_count(table->_modification_count) { - } - friend HashMap; - }; - - // you must not modify the underlying HashMap while this iterator is still in use - Iterator entry_iterator() const { - return Iterator(this); - } - -private: - // Maintains insertion order. - ZigList _entries; - // If _indexes_len is less than 2**8, this is an array of uint8_t. - // If _indexes_len is less than 2**16, it is an array of uint16_t. - // If _indexes_len is less than 2**32, it is an array of uint32_t. - // Otherwise it is size_t. - // It's off by 1. 0 means empty slot, 1 means index 0, etc. - uint8_t *_index_bytes; - // This is the number of indexes. When indexes are bytes, it equals number of bytes. - // When indexes are uint16_t, _indexes_len is half the number of bytes. - size_t _indexes_len; - - size_t _max_distance_from_start_index; - // This is used to detect bugs where a hashtable is edited while an iterator is running. - uint32_t _modification_count; - - void init_capacity(size_t capacity) { - _entries = {}; - _entries.ensure_capacity(capacity); - _indexes_len = 0; - if (capacity >= 16) { - // So that at capacity it will only be 60% full. - _indexes_len = capacity * 5 / 3; - size_t sz = capacity_index_size(_indexes_len); - // This zero initializes _index_bytes which sets them all to empty. - _index_bytes = heap::c_allocator.allocate(_indexes_len * sz); - } else { - _index_bytes = nullptr; - } - - _max_distance_from_start_index = 0; - _modification_count = 0; - } - - static size_t capacity_index_size(size_t len) { - if (len < UINT8_MAX) - return 1; - if (len < UINT16_MAX) - return 2; - if (len < UINT32_MAX) - return 4; - return sizeof(size_t); - } - - template - void internal_put(const K &key, const V &value, I *indexes) { - uint32_t hash = HashFunction(MakePointer::convert(key)); - uint32_t distance_from_start_index = 0; - size_t start_index = hash_to_index(hash); - for (size_t roll_over = 0; roll_over < _indexes_len; - roll_over += 1, distance_from_start_index += 1) - { - size_t index_index = (start_index + roll_over) % _indexes_len; - I index_data = indexes[index_index]; - if (index_data == 0) { - _entries.append_assuming_capacity({ hash, distance_from_start_index, key, value }); - indexes[index_index] = _entries.length; - if (distance_from_start_index > _max_distance_from_start_index) - _max_distance_from_start_index = distance_from_start_index; - return; - } - // This pointer survives the following append because we call - // _entries.ensure_capacity before internal_put. - Entry *entry = &_entries.items[index_data - 1]; - if (entry->hash == hash && EqualFn(MakePointer::convert(entry->key), MakePointer::convert(key))) { - *entry = {hash, distance_from_start_index, key, value}; - if (distance_from_start_index > _max_distance_from_start_index) - _max_distance_from_start_index = distance_from_start_index; - return; - } - if (entry->distance_from_start_index < distance_from_start_index) { - // In this case, we did not find the item. We will put a new entry. - // However, we will use this index for the new entry, and move - // the previous index down the line, to keep the _max_distance_from_start_index - // as small as possible. - _entries.append_assuming_capacity({ hash, distance_from_start_index, key, value }); - indexes[index_index] = _entries.length; - if (distance_from_start_index > _max_distance_from_start_index) - _max_distance_from_start_index = distance_from_start_index; - - distance_from_start_index = entry->distance_from_start_index; - - // Find somewhere to put the index we replaced by shifting - // following indexes backwards. - roll_over += 1; - distance_from_start_index += 1; - for (; roll_over < _indexes_len; roll_over += 1, distance_from_start_index += 1) { - size_t index_index = (start_index + roll_over) % _indexes_len; - I next_index_data = indexes[index_index]; - if (next_index_data == 0) { - if (distance_from_start_index > _max_distance_from_start_index) - _max_distance_from_start_index = distance_from_start_index; - entry->distance_from_start_index = distance_from_start_index; - indexes[index_index] = index_data; - return; - } - Entry *next_entry = &_entries.items[next_index_data - 1]; - if (next_entry->distance_from_start_index < distance_from_start_index) { - if (distance_from_start_index > _max_distance_from_start_index) - _max_distance_from_start_index = distance_from_start_index; - entry->distance_from_start_index = distance_from_start_index; - indexes[index_index] = index_data; - distance_from_start_index = next_entry->distance_from_start_index; - entry = next_entry; - index_data = next_index_data; - } - } - zig_unreachable(); - } - } - zig_unreachable(); - } - - template - void put_index(Entry *entry, size_t entry_index, I *indexes) { - size_t start_index = hash_to_index(entry->hash); - size_t index_data = entry_index + 1; - for (size_t roll_over = 0, distance_from_start_index = 0; - roll_over < _indexes_len; roll_over += 1, distance_from_start_index += 1) - { - size_t index_index = (start_index + roll_over) % _indexes_len; - size_t next_index_data = indexes[index_index]; - if (next_index_data == 0) { - if (distance_from_start_index > _max_distance_from_start_index) - _max_distance_from_start_index = distance_from_start_index; - entry->distance_from_start_index = distance_from_start_index; - indexes[index_index] = index_data; - return; - } - Entry *next_entry = &_entries.items[next_index_data - 1]; - if (next_entry->distance_from_start_index < distance_from_start_index) { - if (distance_from_start_index > _max_distance_from_start_index) - _max_distance_from_start_index = distance_from_start_index; - entry->distance_from_start_index = distance_from_start_index; - indexes[index_index] = index_data; - distance_from_start_index = next_entry->distance_from_start_index; - entry = next_entry; - index_data = next_index_data; - } - } - zig_unreachable(); - } - - Entry *internal_get(const K &key) const { - if (_index_bytes == nullptr) { - uint32_t hash = HashFunction(MakePointer::convert(key)); - for (size_t i = 0; i < _entries.length; i += 1) { - if (_entries.items[i].hash == hash && EqualFn(MakePointer::convert(_entries.items[i].key), MakePointer::convert(key))) { - return &_entries.items[i]; - } - } - return nullptr; - } - switch (capacity_index_size(_indexes_len)) { - case 1: return internal_get2(key, (uint8_t*)_index_bytes); - case 2: return internal_get2(key, (uint16_t*)_index_bytes); - case 4: return internal_get2(key, (uint32_t*)_index_bytes); - default: return internal_get2(key, (size_t*)_index_bytes); - } - } - - template - Entry *internal_get2(const K &key, I *indexes) const { - uint32_t hash = HashFunction(MakePointer::convert(key)); - size_t start_index = hash_to_index(hash); - for (size_t roll_over = 0; roll_over <= _max_distance_from_start_index; roll_over += 1) { - size_t index_index = (start_index + roll_over) % _indexes_len; - size_t index_data = indexes[index_index]; - if (index_data == 0) - return nullptr; - - Entry *entry = &_entries.items[index_data - 1]; - if (entry->hash == hash && EqualFn(MakePointer::convert(entry->key), MakePointer::convert(key))) - return entry; - } - return nullptr; - } - - size_t hash_to_index(uint32_t hash) const { - return ((size_t)hash) % _indexes_len; - } - - template - bool internal_remove(const K &key, I *indexes) { - uint32_t hash = HashFunction(MakePointer::convert(key)); - size_t start_index = hash_to_index(hash); - for (size_t roll_over = 0; roll_over <= _max_distance_from_start_index; roll_over += 1) { - size_t index_index = (start_index + roll_over) % _indexes_len; - size_t index_data = indexes[index_index]; - if (index_data == 0) - return false; - - size_t index = index_data - 1; - Entry *entry = &_entries.items[index]; - if (entry->hash != hash || !EqualFn(MakePointer::convert(entry->key), MakePointer::convert(key))) - continue; - - size_t prev_index = index_index; - _entries.swap_remove(index); - if (_entries.length > 0 && _entries.length != index) { - // Because of the swap remove, now we need to update the index that was - // pointing to the last entry and is now pointing to this removed item slot. - update_entry_index(_entries.length, index, indexes); - } - - // Now we have to shift over the following indexes. - roll_over += 1; - for (; roll_over < _indexes_len; roll_over += 1) { - size_t next_index = (start_index + roll_over) % _indexes_len; - if (indexes[next_index] == 0) { - indexes[prev_index] = 0; - return true; - } - Entry *next_entry = &_entries.items[indexes[next_index] - 1]; - if (next_entry->distance_from_start_index == 0) { - indexes[prev_index] = 0; - return true; - } - indexes[prev_index] = indexes[next_index]; - prev_index = next_index; - next_entry->distance_from_start_index -= 1; - } - zig_unreachable(); - } - return false; - } - - template - void update_entry_index(size_t old_entry_index, size_t new_entry_index, I *indexes) { - size_t start_index = hash_to_index(_entries.items[new_entry_index].hash); - for (size_t roll_over = 0; roll_over <= _max_distance_from_start_index; roll_over += 1) { - size_t index_index = (start_index + roll_over) % _indexes_len; - if (indexes[index_index] == old_entry_index + 1) { - indexes[index_index] = new_entry_index + 1; - return; - } - } - zig_unreachable(); - } -}; -#endif diff --git a/src/stage1/heap.cpp b/src/stage1/heap.cpp deleted file mode 100644 index caf15cde365e..000000000000 --- a/src/stage1/heap.cpp +++ /dev/null @@ -1,314 +0,0 @@ -/* - * Copyright (c) 2020 Andrew Kelley - * - * This file is part of zig, which is MIT licensed. - * See http://opensource.org/licenses/MIT - */ - -#include -#include - -#include "heap.hpp" - -namespace heap { - -extern mem::Allocator &bootstrap_allocator; - -// -// BootstrapAllocator implementation is identical to CAllocator minus -// profile profile functionality. Splitting off to a base interface doesn't -// seem worthwhile. -// - -void BootstrapAllocator::init(const char *name) {} -void BootstrapAllocator::deinit() {} - -void *BootstrapAllocator::internal_allocate(const mem::TypeInfo &info, size_t count) { - return mem::os::calloc(count, info.size); -} - -void *BootstrapAllocator::internal_allocate_nonzero(const mem::TypeInfo &info, size_t count) { - return mem::os::malloc(count * info.size); -} - -void *BootstrapAllocator::internal_reallocate(const mem::TypeInfo &info, void *old_ptr, size_t old_count, size_t new_count) { - auto new_ptr = this->internal_reallocate_nonzero(info, old_ptr, old_count, new_count); - if (new_count > old_count) - memset(reinterpret_cast(new_ptr) + (old_count * info.size), 0, (new_count - old_count) * info.size); - return new_ptr; -} - -void *BootstrapAllocator::internal_reallocate_nonzero(const mem::TypeInfo &info, void *old_ptr, size_t old_count, size_t new_count) { - return mem::os::realloc(old_ptr, new_count * info.size); -} - -void BootstrapAllocator::internal_deallocate(const mem::TypeInfo &info, void *ptr, size_t count) { - mem::os::free(ptr); -} - -void CAllocator::init(const char *name) { } - -void CAllocator::deinit() { } - -CAllocator *CAllocator::construct(mem::Allocator *allocator, const char *name) { - auto p = new(allocator->create()) CAllocator(); - p->init(name); - return p; -} - -void CAllocator::destruct(mem::Allocator *allocator) { - this->deinit(); - allocator->destroy(this); -} - -void *CAllocator::internal_allocate(const mem::TypeInfo &info, size_t count) { - return mem::os::calloc(count, info.size); -} - -void *CAllocator::internal_allocate_nonzero(const mem::TypeInfo &info, size_t count) { - return mem::os::malloc(count * info.size); -} - -void *CAllocator::internal_reallocate(const mem::TypeInfo &info, void *old_ptr, size_t old_count, size_t new_count) { - auto new_ptr = this->internal_reallocate_nonzero(info, old_ptr, old_count, new_count); - if (new_count > old_count) - memset(reinterpret_cast(new_ptr) + (old_count * info.size), 0, (new_count - old_count) * info.size); - return new_ptr; -} - -void *CAllocator::internal_reallocate_nonzero(const mem::TypeInfo &info, void *old_ptr, size_t old_count, size_t new_count) { - return mem::os::realloc(old_ptr, new_count * info.size); -} - -void CAllocator::internal_deallocate(const mem::TypeInfo &info, void *ptr, size_t count) { - mem::os::free(ptr); -} - -struct ArenaAllocator::Impl { - Allocator *backing; - - // regular allocations bump through a segment of static size - struct Segment { - static constexpr size_t size = 65536; - static constexpr size_t object_threshold = 4096; - - uint8_t data[size]; - }; - - // active segment - Segment *segment; - size_t segment_offset; - - // keep track of segments - struct SegmentTrack { - static constexpr size_t size = (4096 - sizeof(SegmentTrack *)) / sizeof(Segment *); - - // null if first - SegmentTrack *prev; - Segment *segments[size]; - }; - static_assert(sizeof(SegmentTrack) <= 4096, "unwanted struct padding"); - - // active segment track - SegmentTrack *segment_track; - size_t segment_track_remain; - - // individual allocations punted to backing allocator - struct Object { - uint8_t *ptr; - size_t len; - }; - - // keep track of objects - struct ObjectTrack { - static constexpr size_t size = (4096 - sizeof(ObjectTrack *)) / sizeof(Object); - - // null if first - ObjectTrack *prev; - Object objects[size]; - }; - static_assert(sizeof(ObjectTrack) <= 4096, "unwanted struct padding"); - - // active object track - ObjectTrack *object_track; - size_t object_track_remain; - - ATTRIBUTE_RETURNS_NOALIAS inline void *allocate(const mem::TypeInfo& info, size_t count); - inline void *reallocate(const mem::TypeInfo& info, void *old_ptr, size_t old_count, size_t new_count); - - inline void new_segment(); - inline void track_segment(); - inline void track_object(Object object); -}; - -void *ArenaAllocator::Impl::allocate(const mem::TypeInfo& info, size_t count) { -#ifndef NDEBUG - // make behavior when size == 0 portable - if (info.size == 0 || count == 0) - return nullptr; -#endif - const size_t nbytes = info.size * count; - this->segment_offset = (this->segment_offset + (info.alignment - 1)) & ~(info.alignment - 1); - if (nbytes >= Segment::object_threshold) { - auto ptr = this->backing->allocate(nbytes); - this->track_object({ptr, nbytes}); - return ptr; - } - if (this->segment_offset + nbytes > Segment::size) - this->new_segment(); - auto ptr = &this->segment->data[this->segment_offset]; - this->segment_offset += nbytes; - return ptr; -} - -void *ArenaAllocator::Impl::reallocate(const mem::TypeInfo& info, void *old_ptr, size_t old_count, size_t new_count) { -#ifndef NDEBUG - // make behavior when size == 0 portable - if (info.size == 0 && old_ptr == nullptr) - return nullptr; -#endif - const size_t new_nbytes = info.size * new_count; - if (new_nbytes <= info.size * old_count) - return old_ptr; - const size_t old_nbytes = info.size * old_count; - this->segment_offset = (this->segment_offset + (info.alignment - 1)) & ~(info.alignment - 1); - if (new_nbytes >= Segment::object_threshold) { - auto new_ptr = this->backing->allocate(new_nbytes); - this->track_object({new_ptr, new_nbytes}); - memcpy(new_ptr, old_ptr, old_nbytes); - return new_ptr; - } - if (this->segment_offset + new_nbytes > Segment::size) - this->new_segment(); - auto new_ptr = &this->segment->data[this->segment_offset]; - this->segment_offset += new_nbytes; - memcpy(new_ptr, old_ptr, old_nbytes); - return new_ptr; -} - -void ArenaAllocator::Impl::new_segment() { - this->segment = this->backing->create(); - this->segment_offset = 0; - this->track_segment(); -} - -void ArenaAllocator::Impl::track_segment() { - assert(this->segment != nullptr); - if (this->segment_track_remain < 1) { - auto prev = this->segment_track; - this->segment_track = this->backing->create(); - this->segment_track->prev = prev; - this->segment_track_remain = SegmentTrack::size; - } - this->segment_track_remain -= 1; - this->segment_track->segments[this->segment_track_remain] = this->segment; -} - -void ArenaAllocator::Impl::track_object(Object object) { - if (this->object_track_remain < 1) { - auto prev = this->object_track; - this->object_track = this->backing->create(); - this->object_track->prev = prev; - this->object_track_remain = ObjectTrack::size; - } - this->object_track_remain -= 1; - this->object_track->objects[this->object_track_remain] = object; -} - -void ArenaAllocator::init(Allocator *backing, const char *name) { - this->impl = bootstrap_allocator.create(); - { - auto &r = *this->impl; - r.backing = backing; - r.segment_offset = Impl::Segment::size; - } -} - -void ArenaAllocator::deinit() { - auto &backing = *this->impl->backing; - - // segments - if (this->impl->segment_track) { - // active track is not full and bounded by track_remain - auto prev = this->impl->segment_track->prev; - { - auto t = this->impl->segment_track; - for (size_t i = this->impl->segment_track_remain; i < Impl::SegmentTrack::size; ++i) - backing.destroy(t->segments[i]); - backing.destroy(t); - } - - // previous tracks are full - for (auto t = prev; t != nullptr;) { - for (size_t i = 0; i < Impl::SegmentTrack::size; ++i) - backing.destroy(t->segments[i]); - prev = t->prev; - backing.destroy(t); - t = prev; - } - } - - // objects - if (this->impl->object_track) { - // active track is not full and bounded by track_remain - auto prev = this->impl->object_track->prev; - { - auto t = this->impl->object_track; - for (size_t i = this->impl->object_track_remain; i < Impl::ObjectTrack::size; ++i) { - auto &obj = t->objects[i]; - backing.deallocate(obj.ptr, obj.len); - } - backing.destroy(t); - } - - // previous tracks are full - for (auto t = prev; t != nullptr;) { - for (size_t i = 0; i < Impl::ObjectTrack::size; ++i) { - auto &obj = t->objects[i]; - backing.deallocate(obj.ptr, obj.len); - } - prev = t->prev; - backing.destroy(t); - t = prev; - } - } -} - -ArenaAllocator *ArenaAllocator::construct(mem::Allocator *allocator, mem::Allocator *backing, const char *name) { - auto p = new(allocator->create()) ArenaAllocator; - p->init(backing, name); - return p; -} - -void ArenaAllocator::destruct(mem::Allocator *allocator) { - this->deinit(); - allocator->destroy(this); -} - -void *ArenaAllocator::internal_allocate(const mem::TypeInfo &info, size_t count) { - return this->impl->allocate(info, count); -} - -void *ArenaAllocator::internal_allocate_nonzero(const mem::TypeInfo &info, size_t count) { - return this->impl->allocate(info, count); -} - -void *ArenaAllocator::internal_reallocate(const mem::TypeInfo &info, void *old_ptr, size_t old_count, size_t new_count) { - return this->internal_reallocate_nonzero(info, old_ptr, old_count, new_count); -} - -void *ArenaAllocator::internal_reallocate_nonzero(const mem::TypeInfo &info, void *old_ptr, size_t old_count, size_t new_count) { - return this->impl->reallocate(info, old_ptr, old_count, new_count); -} - -void ArenaAllocator::internal_deallocate(const mem::TypeInfo &info, void *ptr, size_t count) { - // noop -} - -BootstrapAllocator bootstrap_allocator_state; -mem::Allocator &bootstrap_allocator = bootstrap_allocator_state; - -CAllocator c_allocator_state; -mem::Allocator &c_allocator = c_allocator_state; - -} // namespace heap diff --git a/src/stage1/heap.hpp b/src/stage1/heap.hpp deleted file mode 100644 index a9467bc8318d..000000000000 --- a/src/stage1/heap.hpp +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright (c) 2020 Andrew Kelley - * - * This file is part of zig, which is MIT licensed. - * See http://opensource.org/licenses/MIT - */ - -#ifndef ZIG_HEAP_HPP -#define ZIG_HEAP_HPP - -#include "util_base.hpp" -#include "mem.hpp" - -namespace heap { - -struct BootstrapAllocator final : mem::Allocator { - void init(const char *name); - void deinit(); - void destruct(Allocator *allocator) {} - -private: - ATTRIBUTE_RETURNS_NOALIAS void *internal_allocate(const mem::TypeInfo &info, size_t count) final; - ATTRIBUTE_RETURNS_NOALIAS void *internal_allocate_nonzero(const mem::TypeInfo &info, size_t count) final; - void *internal_reallocate(const mem::TypeInfo &info, void *old_ptr, size_t old_count, size_t new_count) final; - void *internal_reallocate_nonzero(const mem::TypeInfo &info, void *old_ptr, size_t old_count, size_t new_count) final; - void internal_deallocate(const mem::TypeInfo &info, void *ptr, size_t count) final; -}; - -struct CAllocator final : mem::Allocator { - void init(const char *name); - void deinit(); - - static CAllocator *construct(mem::Allocator *allocator, const char *name); - void destruct(mem::Allocator *allocator) final; - - -private: - ATTRIBUTE_RETURNS_NOALIAS void *internal_allocate(const mem::TypeInfo &info, size_t count) final; - ATTRIBUTE_RETURNS_NOALIAS void *internal_allocate_nonzero(const mem::TypeInfo &info, size_t count) final; - void *internal_reallocate(const mem::TypeInfo &info, void *old_ptr, size_t old_count, size_t new_count) final; - void *internal_reallocate_nonzero(const mem::TypeInfo &info, void *old_ptr, size_t old_count, size_t new_count) final; - void internal_deallocate(const mem::TypeInfo &info, void *ptr, size_t count) final; - -}; - -// -// arena allocator -// -// - allocations are backed by the underlying allocator's memory -// - allocations are N:1 relationship to underlying allocations -// - dellocations are noops -// - deinit() releases all underlying memory -// -struct ArenaAllocator final : mem::Allocator { - void init(Allocator *backing, const char *name); - void deinit(); - - static ArenaAllocator *construct(mem::Allocator *allocator, mem::Allocator *backing, const char *name); - void destruct(mem::Allocator *allocator) final; - - -private: - ATTRIBUTE_RETURNS_NOALIAS void *internal_allocate(const mem::TypeInfo &info, size_t count) final; - ATTRIBUTE_RETURNS_NOALIAS void *internal_allocate_nonzero(const mem::TypeInfo &info, size_t count) final; - void *internal_reallocate(const mem::TypeInfo &info, void *old_ptr, size_t old_count, size_t new_count) final; - void *internal_reallocate_nonzero(const mem::TypeInfo &info, void *old_ptr, size_t old_count, size_t new_count) final; - void internal_deallocate(const mem::TypeInfo &info, void *ptr, size_t count) final; - - struct Impl; - Impl *impl; -}; - -extern BootstrapAllocator bootstrap_allocator_state; -extern mem::Allocator &bootstrap_allocator; - -extern CAllocator c_allocator_state; -extern mem::Allocator &c_allocator; - -} // namespace heap - -#endif diff --git a/src/stage1/ir.cpp b/src/stage1/ir.cpp deleted file mode 100644 index e15ca2c0298f..000000000000 --- a/src/stage1/ir.cpp +++ /dev/null @@ -1,26627 +0,0 @@ -/* - * Copyright (c) 2016 Andrew Kelley - * - * This file is part of zig, which is MIT licensed. - * See http://opensource.org/licenses/MIT - */ - -#include "astgen.hpp" -#include "analyze.hpp" -#include "error.hpp" -#include "ir.hpp" -#include "ir_print.hpp" -#include "os.hpp" -#include "range_set.hpp" -#include "softfloat.hpp" -#include "softfloat_ext.hpp" -#include "util.hpp" -#include "mem_list.hpp" -#include "all_types.hpp" -#include "zigendian.h" - -#include -#include - -struct IrBuilderGen { - CodeGen *codegen; - Stage1Air *exec; - Stage1AirBasicBlock *current_basic_block; - - // track for immediate post-analysis destruction - mem::List constants; -}; - -struct IrAnalyze { - CodeGen *codegen; - Stage1Zir *zir; - Stage1ZirBasicBlock *zir_current_basic_block; - IrBuilderGen new_irb; - size_t old_bb_index; - size_t instruction_index; - ZigType *explicit_return_type; - AstNode *explicit_return_type_source_node; - ZigList src_implicit_return_type_list; - ZigList resume_stack; - Stage1ZirBasicBlock *const_predecessor_bb; - size_t ref_count; - size_t break_debug_id; // for debugging purposes - Stage1AirInst *return_ptr; - Stage1Air *parent_exec; - size_t *backward_branch_count; - size_t *backward_branch_quota; - ZigFn *fn; - Stage1ZirInst *suspend_source_instr; - - // For the purpose of using in a debugger - void dump(); -}; - -enum ConstCastResultId { - ConstCastResultIdOk, - ConstCastResultIdInvalid, - ConstCastResultIdErrSet, - ConstCastResultIdErrSetGlobal, - ConstCastResultIdPointerChild, - ConstCastResultIdSliceChild, - ConstCastResultIdOptionalChild, - ConstCastResultIdOptionalShape, - ConstCastResultIdErrorUnionPayload, - ConstCastResultIdErrorUnionErrorSet, - ConstCastResultIdFnAlign, - ConstCastResultIdFnCC, - ConstCastResultIdFnVarArgs, - ConstCastResultIdFnIsGeneric, - ConstCastResultIdFnReturnType, - ConstCastResultIdFnArgCount, - ConstCastResultIdFnGenericArgCount, - ConstCastResultIdFnArg, - ConstCastResultIdFnArgNoAlias, - ConstCastResultIdType, - ConstCastResultIdUnresolvedInferredErrSet, - ConstCastResultIdAsyncAllocatorType, - ConstCastResultIdBadAllowsZero, - ConstCastResultIdArrayChild, - ConstCastResultIdSentinelArrays, - ConstCastResultIdPtrLens, - ConstCastResultIdCV, - ConstCastResultIdPtrSentinel, - ConstCastResultIdIntShorten, - ConstCastResultIdVectorLength, - ConstCastResultIdVectorChild, -}; - -struct ConstCastOnly; -struct ConstCastArg { - size_t arg_index; - ZigType *actual_param_type; - ZigType *expected_param_type; - ConstCastOnly *child; -}; - -struct ConstCastArgNoAlias { - size_t arg_index; -}; - -struct ConstCastOptionalMismatch; -struct ConstCastPointerMismatch; -struct ConstCastSliceMismatch; -struct ConstCastErrUnionErrSetMismatch; -struct ConstCastErrUnionPayloadMismatch; -struct ConstCastErrSetMismatch; -struct ConstCastTypeMismatch; -struct ConstCastArrayMismatch; -struct ConstCastBadAllowsZero; -struct ConstCastBadNullTermArrays; -struct ConstCastBadCV; -struct ConstCastPtrSentinel; -struct ConstCastIntShorten; - -struct ConstCastOnly { - ConstCastResultId id; - union { - ConstCastErrSetMismatch *error_set_mismatch; - ConstCastPointerMismatch *pointer_mismatch; - ConstCastSliceMismatch *slice_mismatch; - ConstCastOptionalMismatch *optional; - ConstCastErrUnionPayloadMismatch *error_union_payload; - ConstCastErrUnionErrSetMismatch *error_union_error_set; - ConstCastTypeMismatch *type_mismatch; - ConstCastArrayMismatch *array_mismatch; - ConstCastOnly *return_type; - ConstCastOnly *null_wrap_ptr_child; - ConstCastArg fn_arg; - ConstCastArgNoAlias arg_no_alias; - ConstCastBadAllowsZero *bad_allows_zero; - ConstCastBadNullTermArrays *sentinel_arrays; - ConstCastBadCV *bad_cv; - ConstCastPtrSentinel *bad_ptr_sentinel; - ConstCastIntShorten *int_shorten; - } data; -}; - -struct ConstCastTypeMismatch { - ZigType *wanted_type; - ZigType *actual_type; -}; - -struct ConstCastOptionalMismatch { - ConstCastOnly child; - ZigType *wanted_child; - ZigType *actual_child; -}; - -struct ConstCastPointerMismatch { - ConstCastOnly child; - ZigType *wanted_child; - ZigType *actual_child; -}; - -struct ConstCastSliceMismatch { - ConstCastOnly child; - ZigType *wanted_child; - ZigType *actual_child; -}; - -struct ConstCastArrayMismatch { - ConstCastOnly child; - ZigType *wanted_child; - ZigType *actual_child; -}; - -struct ConstCastErrUnionErrSetMismatch { - ConstCastOnly child; - ZigType *wanted_err_set; - ZigType *actual_err_set; -}; - -struct ConstCastErrUnionPayloadMismatch { - ConstCastOnly child; - ZigType *wanted_payload; - ZigType *actual_payload; -}; - -struct ConstCastErrSetMismatch { - ZigList missing_errors; -}; - -struct ConstCastBadAllowsZero { - ZigType *wanted_type; - ZigType *actual_type; -}; - -struct ConstCastBadNullTermArrays { - ConstCastOnly child; - ZigType *wanted_type; - ZigType *actual_type; -}; - -struct ConstCastBadCV { - ZigType *wanted_type; - ZigType *actual_type; -}; - -struct ConstCastPtrSentinel { - ZigType *wanted_type; - ZigType *actual_type; -}; - -struct ConstCastIntShorten { - ZigType *wanted_type; - ZigType *actual_type; -}; - -// for debugging purposes -struct DbgIrBreakPoint { - const char *src_file; - uint32_t line; -}; - -static Stage1AirInst *ir_implicit_cast(IrAnalyze *ira, Stage1AirInst *value, ZigType *expected_type); -static Stage1AirInst *ir_implicit_cast2(IrAnalyze *ira, Scope *scope, AstNode *source_node, - Stage1AirInst *value, ZigType *expected_type); -static Stage1AirInst *ir_get_deref(IrAnalyze *ira, Scope *scope, AstNode *source_node, Stage1AirInst *ptr, - ResultLoc *result_loc); -static Stage1AirInst *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field_name, - Scope *scope, AstNode *source_node, Stage1AirInst *container_ptr, AstNode *container_ptr_src, - ZigType *container_type, bool initializing); -static Stage1AirInst *ir_get_var_ptr(IrAnalyze *ira, Scope *scope, AstNode *source_node, ZigVar *var); -static ZigType *ir_resolve_atomic_operand_type(IrAnalyze *ira, Stage1AirInst *op); -static ZigType *adjust_ptr_align(CodeGen *g, ZigType *ptr_type, uint32_t new_align); -static ZigType *adjust_ptr_const(CodeGen *g, ZigType *ptr_type, bool is_const); -static ZigType *adjust_slice_align(CodeGen *g, ZigType *slice_type, uint32_t new_align); -static Error buf_read_value_bytes(IrAnalyze *ira, CodeGen *codegen, AstNode *source_node, uint8_t *buf, ZigValue *val); -static void buf_write_value_bytes(CodeGen *codegen, uint8_t *buf, ZigValue *val); -static Error ir_read_const_ptr(IrAnalyze *ira, CodeGen *codegen, AstNode *source_node, - ZigValue *out_val, ZigValue *ptr_val); -static Stage1AirInst *ir_analyze_ptr_cast(IrAnalyze *ira, Scope *scope, AstNode *source_node, - Stage1AirInst *ptr, AstNode *ptr_src, ZigType *dest_type, AstNode *dest_type_src, - bool safety_check_on, bool keep_bigger_alignment); -static ZigValue *ir_resolve_const(IrAnalyze *ira, Stage1AirInst *value, UndefAllowed undef_allowed); -static Error resolve_ptr_align(IrAnalyze *ira, ZigType *ty, uint32_t *result_align); -static Stage1AirInst *ir_analyze_int_to_ptr(IrAnalyze *ira, Scope *scope, AstNode *source_node, Stage1AirInst *target, - ZigType *ptr_type); -static Stage1AirInst *ir_analyze_bit_cast(IrAnalyze *ira, Scope *scope, AstNode *source_node, Stage1AirInst *value, - ZigType *dest_type); -static Stage1AirInst *ir_resolve_result_raw(IrAnalyze *ira, Stage1ZirInst *suspend_source_instr, - ResultLoc *result_loc, ZigType *value_type, Stage1AirInst *value, bool force_runtime, bool allow_discard); -static Stage1AirInst *ir_resolve_result(IrAnalyze *ira, Stage1ZirInst *suspend_source_instr, - ResultLoc *result_loc, ZigType *value_type, Stage1AirInst *value, bool force_runtime, bool allow_discard); -static Stage1AirInst *ir_analyze_unwrap_optional_payload(IrAnalyze *ira, Scope *scope, AstNode *source_node, - Stage1AirInst *base_ptr, bool safety_check_on, bool initializing); -static Stage1AirInst *ir_analyze_unwrap_error_payload(IrAnalyze *ira, Scope *scope, AstNode *source_node, - Stage1AirInst *base_ptr, bool safety_check_on, bool initializing); -static Stage1AirInst *ir_analyze_unwrap_err_code(IrAnalyze *ira, Scope *scope, AstNode *source_node, - Stage1AirInst *base_ptr, bool initializing); -static Stage1AirInst *ir_analyze_store_ptr(IrAnalyze *ira, Scope *scope, AstNode *source_node, - Stage1AirInst *ptr, Stage1AirInst *uncasted_value, bool allow_write_through_const); -static void ir_reset_result(ResultLoc *result_loc); -static Stage1AirInst *ir_analyze_struct_field_ptr(IrAnalyze *ira, Scope *scope, AstNode *source_node, - TypeStructField *field, Stage1AirInst *struct_ptr, ZigType *struct_type, bool initializing); -static Stage1AirInst *ir_analyze_inferred_field_ptr(IrAnalyze *ira, Buf *field_name, - Scope *scope, AstNode *source_node, Stage1AirInst *container_ptr, ZigType *container_type); -static Stage1AirInst *ir_analyze_test_non_null(IrAnalyze *ira, Scope *scope, AstNode *source_node, Stage1AirInst *value); -static Stage1AirInst *ir_error_dependency_loop(IrAnalyze *ira, AstNode *source_node); -static Stage1AirInst *ir_const_undef(IrAnalyze *ira, Scope *scope, AstNode *source_node, ZigType *ty); -static Stage1AirInst *ir_analyze_union_init(IrAnalyze *ira, Scope *scope, AstNode *source_node, - AstNode *field_source_node, ZigType *union_type, Buf *field_name, Stage1AirInst *field_result_loc, - Stage1AirInst *result_loc); -static Stage1AirInst *ir_analyze_struct_value_field_value(IrAnalyze *ira, Scope *scope, AstNode *source_node, - Stage1AirInst *struct_operand, TypeStructField *field); -static bool value_cmp_numeric_val_any(ZigValue *left, Cmp predicate, ZigValue *right); -static bool value_cmp_numeric_val_all(ZigValue *left, Cmp predicate, ZigValue *right); -static void memoize_field_init_val(CodeGen *codegen, ZigType *container_type, TypeStructField *field); -static void value_to_bigfloat(BigFloat *out, ZigValue *val); - -static Error ir_resolve_lazy_recurse(AstNode *source_node, ZigValue *val); -static Error ir_resolve_lazy_recurse_array(AstNode *source_node, ZigValue *val, size_t len); - - -static void ir_assert_impl(bool ok, Stage1AirInst *source_instruction, char const *file, unsigned int line) { - if (ok) return; - src_assert_impl(ok, source_instruction->source_node, file, line); -} - -#define ir_assert(OK, SOURCE_INSTRUCTION) ir_assert_impl((OK), (SOURCE_INSTRUCTION), __FILE__, __LINE__) - -void destroy_instruction_gen(Stage1AirInst *inst) { - switch (inst->id) { - case Stage1AirInstIdInvalid: - zig_unreachable(); - case Stage1AirInstIdReturn: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1AirInstIdConst: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1AirInstIdBinOp: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1AirInstIdCast: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1AirInstIdCall: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1AirInstIdCondBr: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1AirInstIdBr: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1AirInstIdPhi: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1AirInstIdUnreachable: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1AirInstIdElemPtr: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1AirInstIdVarPtr: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1AirInstIdReturnPtr: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1AirInstIdLoadPtr: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1AirInstIdStorePtr: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1AirInstIdVectorStoreElem: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1AirInstIdStructFieldPtr: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1AirInstIdUnionFieldPtr: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1AirInstIdAsm: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1AirInstIdTestNonNull: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1AirInstIdOptionalUnwrapPtr: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1AirInstIdPopCount: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1AirInstIdClz: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1AirInstIdCtz: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1AirInstIdBswap: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1AirInstIdBitReverse: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1AirInstIdSwitchBr: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1AirInstIdUnionTag: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1AirInstIdRef: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1AirInstIdErrName: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1AirInstIdCmpxchg: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1AirInstIdFence: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1AirInstIdReduce: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1AirInstIdTruncate: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1AirInstIdShuffleVector: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1AirInstIdSelect: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1AirInstIdSplat: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1AirInstIdBoolNot: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1AirInstIdMemset: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1AirInstIdMemcpy: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1AirInstIdSlice: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1AirInstIdBreakpoint: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1AirInstIdReturnAddress: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1AirInstIdFrameAddress: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1AirInstIdFrameHandle: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1AirInstIdFrameSize: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1AirInstIdOverflowOp: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1AirInstIdTestErr: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1AirInstIdUnwrapErrCode: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1AirInstIdUnwrapErrPayload: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1AirInstIdOptionalWrap: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1AirInstIdErrWrapCode: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1AirInstIdErrWrapPayload: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1AirInstIdPtrCast: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1AirInstIdBitCast: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1AirInstIdWidenOrShorten: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1AirInstIdPtrToInt: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1AirInstIdIntToPtr: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1AirInstIdIntToEnum: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1AirInstIdIntToErr: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1AirInstIdErrToInt: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1AirInstIdTagName: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1AirInstIdPanic: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1AirInstIdFieldParentPtr: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1AirInstIdAlignCast: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1AirInstIdErrorReturnTrace: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1AirInstIdAtomicRmw: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1AirInstIdSaveErrRetAddr: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1AirInstIdFloatOp: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1AirInstIdMulAdd: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1AirInstIdAtomicLoad: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1AirInstIdAtomicStore: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1AirInstIdDeclVar: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1AirInstIdArrayToVector: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1AirInstIdVectorToArray: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1AirInstIdPtrOfArrayToSlice: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1AirInstIdAssertZero: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1AirInstIdAssertNonNull: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1AirInstIdAlloca: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1AirInstIdSuspendBegin: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1AirInstIdSuspendFinish: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1AirInstIdResume: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1AirInstIdAwait: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1AirInstIdSpillBegin: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1AirInstIdSpillEnd: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1AirInstIdVectorExtractElem: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1AirInstIdBinaryNot: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1AirInstIdNegation: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1AirInstIdWasmMemorySize: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1AirInstIdWasmMemoryGrow: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1AirInstIdExtern: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case Stage1AirInstIdPrefetch: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - } - zig_unreachable(); -} - -static void ira_ref(IrAnalyze *ira) { - ira->ref_count += 1; -} -static void ira_deref(IrAnalyze *ira) { - if (ira->ref_count > 1) { - ira->ref_count -= 1; - - // immediate destruction of dangling Stage1AirInstConst is not possible - // free tracking memory because it will never be used - ira->new_irb.constants.deinit(&heap::c_allocator); - return; - } - assert(ira->ref_count != 0); - - for (size_t bb_i = 0; bb_i < ira->zir->basic_block_list.length; bb_i += 1) { - Stage1ZirBasicBlock *pass1_bb = ira->zir->basic_block_list.items[bb_i]; - for (size_t inst_i = 0; inst_i < pass1_bb->instruction_list.length; inst_i += 1) { - Stage1ZirInst *pass1_inst = pass1_bb->instruction_list.items[inst_i]; - destroy_instruction_src(pass1_inst); - } - heap::c_allocator.destroy(pass1_bb); - } - ira->zir->basic_block_list.deinit(); - ira->zir->tld_list.deinit(); - heap::c_allocator.destroy(ira->zir); - ira->src_implicit_return_type_list.deinit(); - ira->resume_stack.deinit(); - - // destroy dangling Stage1AirInstConst - for (size_t i = 0; i < ira->new_irb.constants.length; i += 1) { - auto constant = ira->new_irb.constants.items[i]; - if (constant->base.ref_count == 0 && !ir_inst_gen_has_side_effects(&constant->base)) - destroy_instruction_gen(&constant->base); - } - ira->new_irb.constants.deinit(&heap::c_allocator); - - heap::c_allocator.destroy(ira); -} - -static ZigValue *const_ptr_pointee_unchecked_no_isf(CodeGen *g, ZigValue *const_val) { - assert(get_src_ptr_type(const_val->type) != nullptr); - assert(const_val->special == ConstValSpecialStatic); - - switch (type_has_one_possible_value(g, const_val->type->data.pointer.child_type)) { - case OnePossibleValueInvalid: - return nullptr; - case OnePossibleValueYes: - return get_the_one_possible_value(g, const_val->type->data.pointer.child_type); - case OnePossibleValueNo: - break; - } - - ZigValue *result; - switch (const_val->data.x_ptr.special) { - case ConstPtrSpecialInvalid: - zig_unreachable(); - case ConstPtrSpecialRef: - result = const_val->data.x_ptr.data.ref.pointee; - break; - case ConstPtrSpecialBaseArray: { - ZigValue *array_val = const_val->data.x_ptr.data.base_array.array_val; - size_t elem_index = const_val->data.x_ptr.data.base_array.elem_index; - if (elem_index == array_val->type->data.array.len) { - result = array_val->type->data.array.sentinel; - } else { - expand_undef_array(g, array_val); - result = &array_val->data.x_array.data.s_none.elements[elem_index]; - } - break; - } - case ConstPtrSpecialSubArray: { - ZigValue *array_val = const_val->data.x_ptr.data.base_array.array_val; - size_t elem_index = const_val->data.x_ptr.data.base_array.elem_index; - - expand_undef_array(g, array_val); - result = g->pass1_arena->create(); - result->special = array_val->special; - result->type = get_array_type(g, array_val->type->data.array.child_type, - array_val->type->data.array.len - elem_index, array_val->type->data.array.sentinel); - result->data.x_array.special = ConstArraySpecialNone; - result->data.x_array.data.s_none.elements = &array_val->data.x_array.data.s_none.elements[elem_index]; - result->parent.id = ConstParentIdArray; - result->parent.data.p_array.array_val = array_val; - result->parent.data.p_array.elem_index = elem_index; - break; - } - case ConstPtrSpecialBaseStruct: { - ZigValue *struct_val = const_val->data.x_ptr.data.base_struct.struct_val; - expand_undef_struct(g, struct_val); - size_t field_index = const_val->data.x_ptr.data.base_struct.field_index; - assert(struct_val->type->id == ZigTypeIdStruct); - assert(!struct_val->type->data.structure.fields[field_index]->is_comptime); - result = struct_val->data.x_struct.fields[field_index]; - break; - } - case ConstPtrSpecialBaseErrorUnionCode: - result = const_val->data.x_ptr.data.base_err_union_code.err_union_val->data.x_err_union.error_set; - break; - case ConstPtrSpecialBaseErrorUnionPayload: - result = const_val->data.x_ptr.data.base_err_union_payload.err_union_val->data.x_err_union.payload; - break; - case ConstPtrSpecialBaseOptionalPayload: - result = const_val->data.x_ptr.data.base_optional_payload.optional_val->data.x_optional; - break; - case ConstPtrSpecialNull: - result = const_val; - break; - case ConstPtrSpecialHardCodedAddr: - zig_unreachable(); - case ConstPtrSpecialDiscard: - zig_unreachable(); - case ConstPtrSpecialFunction: - zig_unreachable(); - } - assert(result != nullptr); - return result; -} - -static ZigValue *const_ptr_pointee_unchecked(CodeGen *g, ZigValue *const_val) { - assert(get_src_ptr_type(const_val->type) != nullptr); - assert(const_val->special == ConstValSpecialStatic); - - InferredStructField *isf = const_val->type->data.pointer.inferred_struct_field; - if (isf != nullptr) { - TypeStructField *field = find_struct_type_field(isf->inferred_struct_type, isf->field_name); - assert(field != nullptr); - if (field->is_comptime) { - assert(field->init_val != nullptr); - return field->init_val; - } - ZigValue *struct_val = const_ptr_pointee_unchecked_no_isf(g, const_val); - assert(struct_val->type->id == ZigTypeIdStruct); - return struct_val->data.x_struct.fields[field->src_index]; - } - - return const_ptr_pointee_unchecked_no_isf(g, const_val); -} - -static bool is_tuple(ZigType *type) { - return type->id == ZigTypeIdStruct && type->data.structure.special == StructSpecialInferredTuple; -} - -static bool is_slice(ZigType *type) { - return type->id == ZigTypeIdStruct && type->data.structure.special == StructSpecialSlice; -} - -// This function returns true when you can change the type of a ZigValue and the -// value remains meaningful. -static bool types_have_same_zig_comptime_repr(CodeGen *codegen, ZigType *expected, ZigType *actual) { - if (expected == actual) - return true; - - if (get_src_ptr_type(expected) != nullptr && get_src_ptr_type(actual) != nullptr) - return true; - - if (is_opt_err_set(expected) && is_opt_err_set(actual)) - return true; - - // XXX: Vectors and arrays are interchangeable at comptime - if (expected->id != actual->id) - return false; - - switch (expected->id) { - case ZigTypeIdInvalid: - case ZigTypeIdUnreachable: - zig_unreachable(); - case ZigTypeIdMetaType: - case ZigTypeIdVoid: - case ZigTypeIdBool: - case ZigTypeIdComptimeFloat: - case ZigTypeIdComptimeInt: - case ZigTypeIdEnumLiteral: - case ZigTypeIdUndefined: - case ZigTypeIdNull: - case ZigTypeIdBoundFn: - case ZigTypeIdErrorSet: - case ZigTypeIdOpaque: - case ZigTypeIdAnyFrame: - case ZigTypeIdFn: - return true; - case ZigTypeIdPointer: - return expected->data.pointer.inferred_struct_field == actual->data.pointer.inferred_struct_field; - case ZigTypeIdFloat: - return expected->data.floating.bit_count == actual->data.floating.bit_count; - case ZigTypeIdInt: - return expected->data.integral.is_signed == actual->data.integral.is_signed; - case ZigTypeIdStruct: - return is_slice(expected) && is_slice(actual); - case ZigTypeIdOptional: - case ZigTypeIdErrorUnion: - case ZigTypeIdEnum: - case ZigTypeIdUnion: - case ZigTypeIdFnFrame: - return false; - case ZigTypeIdVector: - return expected->data.vector.len == actual->data.vector.len && - types_have_same_zig_comptime_repr(codegen, expected->data.vector.elem_type, actual->data.vector.elem_type); - case ZigTypeIdArray: - return expected->data.array.len == actual->data.array.len && - expected->data.array.child_type == actual->data.array.child_type && - (expected->data.array.sentinel == nullptr || (actual->data.array.sentinel != nullptr && - const_values_equal(codegen, expected->data.array.sentinel, actual->data.array.sentinel))); - } - zig_unreachable(); -} - -static void ir_inst_gen_append(Stage1AirBasicBlock *basic_block, Stage1AirInst *instruction) { - assert(basic_block); - assert(instruction); - basic_block->instruction_list.append(instruction); -} - -static size_t exec_next_debug_id_gen(Stage1Air *exec) { - size_t result = exec->next_debug_id; - exec->next_debug_id += 1; - return result; -} - -static bool value_is_comptime(ZigValue *const_val) { - return const_val->special != ConstValSpecialRuntime; -} - -static bool instr_is_comptime(Stage1AirInst *instruction) { - return value_is_comptime(instruction->value); -} - -static void ir_ref_inst_gen(Stage1AirInst *instruction) { - assert(instruction->id != Stage1AirInstIdInvalid); - instruction->ref_count += 1; -} - -static void create_result_ptr(CodeGen *codegen, ZigType *expected_type, - ZigValue **out_result, ZigValue **out_result_ptr) -{ - ZigValue *result = codegen->pass1_arena->create(); - ZigValue *result_ptr = codegen->pass1_arena->create(); - result->special = ConstValSpecialUndef; - result->type = expected_type; - result_ptr->special = ConstValSpecialStatic; - result_ptr->type = get_pointer_to_type(codegen, result->type, false); - result_ptr->data.x_ptr.mut = ConstPtrMutComptimeVar; - result_ptr->data.x_ptr.special = ConstPtrSpecialRef; - result_ptr->data.x_ptr.data.ref.pointee = result; - - *out_result = result; - *out_result_ptr = result_ptr; -} - -ZigType *ir_analyze_type_expr(IrAnalyze *ira, Scope *scope, AstNode *node) { - Error err; - - ZigValue *result; - ZigValue *result_ptr; - create_result_ptr(ira->codegen, ira->codegen->builtin_types.entry_type, &result, &result_ptr); - - if ((err = ir_eval_const_value(ira->codegen, scope, node, result_ptr, - ira->backward_branch_count, ira->backward_branch_quota, - nullptr, nullptr, node, nullptr, ira->new_irb.exec, nullptr, UndefBad))) - { - return ira->codegen->builtin_types.entry_invalid; - } - if (type_is_invalid(result->type)) - return ira->codegen->builtin_types.entry_invalid; - - assert(result->special != ConstValSpecialRuntime); - ZigType *res_type = result->data.x_type; - - return res_type; -} - -static Stage1AirBasicBlock *ir_create_basic_block_gen(IrAnalyze *ira, Scope *scope, const char *name_hint) { - Stage1AirBasicBlock *result = heap::c_allocator.create(); - result->scope = scope; - result->name_hint = name_hint; - result->debug_id = exec_next_debug_id_gen(ira->new_irb.exec); - return result; -} - -static Stage1AirBasicBlock *ir_build_bb_from(IrAnalyze *ira, Stage1ZirBasicBlock *other_bb) { - Stage1AirBasicBlock *new_bb = ir_create_basic_block_gen(ira, other_bb->scope, other_bb->name_hint); - other_bb->child = new_bb; - return new_bb; -} - -static constexpr Stage1AirInstId ir_inst_id(Stage1AirInstDeclVar *) { - return Stage1AirInstIdDeclVar; -} - -static constexpr Stage1AirInstId ir_inst_id(Stage1AirInstBr *) { - return Stage1AirInstIdBr; -} - -static constexpr Stage1AirInstId ir_inst_id(Stage1AirInstCondBr *) { - return Stage1AirInstIdCondBr; -} - -static constexpr Stage1AirInstId ir_inst_id(Stage1AirInstSwitchBr *) { - return Stage1AirInstIdSwitchBr; -} - -static constexpr Stage1AirInstId ir_inst_id(Stage1AirInstPhi *) { - return Stage1AirInstIdPhi; -} - -static constexpr Stage1AirInstId ir_inst_id(Stage1AirInstBinaryNot *) { - return Stage1AirInstIdBinaryNot; -} - -static constexpr Stage1AirInstId ir_inst_id(Stage1AirInstNegation *) { - return Stage1AirInstIdNegation; -} - -static constexpr Stage1AirInstId ir_inst_id(Stage1AirInstBinOp *) { - return Stage1AirInstIdBinOp; -} - -static constexpr Stage1AirInstId ir_inst_id(Stage1AirInstLoadPtr *) { - return Stage1AirInstIdLoadPtr; -} - -static constexpr Stage1AirInstId ir_inst_id(Stage1AirInstStorePtr *) { - return Stage1AirInstIdStorePtr; -} - -static constexpr Stage1AirInstId ir_inst_id(Stage1AirInstVectorStoreElem *) { - return Stage1AirInstIdVectorStoreElem; -} - -static constexpr Stage1AirInstId ir_inst_id(Stage1AirInstStructFieldPtr *) { - return Stage1AirInstIdStructFieldPtr; -} - -static constexpr Stage1AirInstId ir_inst_id(Stage1AirInstUnionFieldPtr *) { - return Stage1AirInstIdUnionFieldPtr; -} - -static constexpr Stage1AirInstId ir_inst_id(Stage1AirInstElemPtr *) { - return Stage1AirInstIdElemPtr; -} - -static constexpr Stage1AirInstId ir_inst_id(Stage1AirInstVarPtr *) { - return Stage1AirInstIdVarPtr; -} - -static constexpr Stage1AirInstId ir_inst_id(Stage1AirInstReturnPtr *) { - return Stage1AirInstIdReturnPtr; -} - -static constexpr Stage1AirInstId ir_inst_id(Stage1AirInstCall *) { - return Stage1AirInstIdCall; -} - -static constexpr Stage1AirInstId ir_inst_id(Stage1AirInstReturn *) { - return Stage1AirInstIdReturn; -} - -static constexpr Stage1AirInstId ir_inst_id(Stage1AirInstCast *) { - return Stage1AirInstIdCast; -} - -static constexpr Stage1AirInstId ir_inst_id(Stage1AirInstUnreachable *) { - return Stage1AirInstIdUnreachable; -} - -static constexpr Stage1AirInstId ir_inst_id(Stage1AirInstAsm *) { - return Stage1AirInstIdAsm; -} - -static constexpr Stage1AirInstId ir_inst_id(Stage1AirInstTestNonNull *) { - return Stage1AirInstIdTestNonNull; -} - -static constexpr Stage1AirInstId ir_inst_id(Stage1AirInstOptionalUnwrapPtr *) { - return Stage1AirInstIdOptionalUnwrapPtr; -} - -static constexpr Stage1AirInstId ir_inst_id(Stage1AirInstOptionalWrap *) { - return Stage1AirInstIdOptionalWrap; -} - -static constexpr Stage1AirInstId ir_inst_id(Stage1AirInstUnionTag *) { - return Stage1AirInstIdUnionTag; -} - -static constexpr Stage1AirInstId ir_inst_id(Stage1AirInstClz *) { - return Stage1AirInstIdClz; -} - -static constexpr Stage1AirInstId ir_inst_id(Stage1AirInstCtz *) { - return Stage1AirInstIdCtz; -} - -static constexpr Stage1AirInstId ir_inst_id(Stage1AirInstPopCount *) { - return Stage1AirInstIdPopCount; -} - -static constexpr Stage1AirInstId ir_inst_id(Stage1AirInstBswap *) { - return Stage1AirInstIdBswap; -} - -static constexpr Stage1AirInstId ir_inst_id(Stage1AirInstBitReverse *) { - return Stage1AirInstIdBitReverse; -} - -static constexpr Stage1AirInstId ir_inst_id(Stage1AirInstRef *) { - return Stage1AirInstIdRef; -} - -static constexpr Stage1AirInstId ir_inst_id(Stage1AirInstErrName *) { - return Stage1AirInstIdErrName; -} - -static constexpr Stage1AirInstId ir_inst_id(Stage1AirInstCmpxchg *) { - return Stage1AirInstIdCmpxchg; -} - -static constexpr Stage1AirInstId ir_inst_id(Stage1AirInstFence *) { - return Stage1AirInstIdFence; -} - -static constexpr Stage1AirInstId ir_inst_id(Stage1AirInstReduce *) { - return Stage1AirInstIdReduce; -} - -static constexpr Stage1AirInstId ir_inst_id(Stage1AirInstTruncate *) { - return Stage1AirInstIdTruncate; -} - -static constexpr Stage1AirInstId ir_inst_id(Stage1AirInstShuffleVector *) { - return Stage1AirInstIdShuffleVector; -} - -static constexpr Stage1AirInstId ir_inst_id(Stage1AirInstSelect *) { - return Stage1AirInstIdSelect; -} - -static constexpr Stage1AirInstId ir_inst_id(Stage1AirInstSplat *) { - return Stage1AirInstIdSplat; -} - -static constexpr Stage1AirInstId ir_inst_id(Stage1AirInstBoolNot *) { - return Stage1AirInstIdBoolNot; -} - -static constexpr Stage1AirInstId ir_inst_id(Stage1AirInstMemset *) { - return Stage1AirInstIdMemset; -} - -static constexpr Stage1AirInstId ir_inst_id(Stage1AirInstMemcpy *) { - return Stage1AirInstIdMemcpy; -} - -static constexpr Stage1AirInstId ir_inst_id(Stage1AirInstSlice *) { - return Stage1AirInstIdSlice; -} - -static constexpr Stage1AirInstId ir_inst_id(Stage1AirInstBreakpoint *) { - return Stage1AirInstIdBreakpoint; -} - -static constexpr Stage1AirInstId ir_inst_id(Stage1AirInstReturnAddress *) { - return Stage1AirInstIdReturnAddress; -} - -static constexpr Stage1AirInstId ir_inst_id(Stage1AirInstFrameAddress *) { - return Stage1AirInstIdFrameAddress; -} - -static constexpr Stage1AirInstId ir_inst_id(Stage1AirInstFrameHandle *) { - return Stage1AirInstIdFrameHandle; -} - -static constexpr Stage1AirInstId ir_inst_id(Stage1AirInstFrameSize *) { - return Stage1AirInstIdFrameSize; -} - -static constexpr Stage1AirInstId ir_inst_id(Stage1AirInstOverflowOp *) { - return Stage1AirInstIdOverflowOp; -} - -static constexpr Stage1AirInstId ir_inst_id(Stage1AirInstTestErr *) { - return Stage1AirInstIdTestErr; -} - -static constexpr Stage1AirInstId ir_inst_id(Stage1AirInstMulAdd *) { - return Stage1AirInstIdMulAdd; -} - -static constexpr Stage1AirInstId ir_inst_id(Stage1AirInstFloatOp *) { - return Stage1AirInstIdFloatOp; -} - -static constexpr Stage1AirInstId ir_inst_id(Stage1AirInstUnwrapErrCode *) { - return Stage1AirInstIdUnwrapErrCode; -} - -static constexpr Stage1AirInstId ir_inst_id(Stage1AirInstUnwrapErrPayload *) { - return Stage1AirInstIdUnwrapErrPayload; -} - -static constexpr Stage1AirInstId ir_inst_id(Stage1AirInstErrWrapCode *) { - return Stage1AirInstIdErrWrapCode; -} - -static constexpr Stage1AirInstId ir_inst_id(Stage1AirInstErrWrapPayload *) { - return Stage1AirInstIdErrWrapPayload; -} - -static constexpr Stage1AirInstId ir_inst_id(Stage1AirInstPtrCast *) { - return Stage1AirInstIdPtrCast; -} - -static constexpr Stage1AirInstId ir_inst_id(Stage1AirInstBitCast *) { - return Stage1AirInstIdBitCast; -} - -static constexpr Stage1AirInstId ir_inst_id(Stage1AirInstWidenOrShorten *) { - return Stage1AirInstIdWidenOrShorten; -} - -static constexpr Stage1AirInstId ir_inst_id(Stage1AirInstIntToPtr *) { - return Stage1AirInstIdIntToPtr; -} - -static constexpr Stage1AirInstId ir_inst_id(Stage1AirInstPtrToInt *) { - return Stage1AirInstIdPtrToInt; -} - -static constexpr Stage1AirInstId ir_inst_id(Stage1AirInstIntToEnum *) { - return Stage1AirInstIdIntToEnum; -} - -static constexpr Stage1AirInstId ir_inst_id(Stage1AirInstIntToErr *) { - return Stage1AirInstIdIntToErr; -} - -static constexpr Stage1AirInstId ir_inst_id(Stage1AirInstErrToInt *) { - return Stage1AirInstIdErrToInt; -} - -static constexpr Stage1AirInstId ir_inst_id(Stage1AirInstPanic *) { - return Stage1AirInstIdPanic; -} - -static constexpr Stage1AirInstId ir_inst_id(Stage1AirInstTagName *) { - return Stage1AirInstIdTagName; -} - -static constexpr Stage1AirInstId ir_inst_id(Stage1AirInstFieldParentPtr *) { - return Stage1AirInstIdFieldParentPtr; -} - -static constexpr Stage1AirInstId ir_inst_id(Stage1AirInstAlignCast *) { - return Stage1AirInstIdAlignCast; -} - -static constexpr Stage1AirInstId ir_inst_id(Stage1AirInstErrorReturnTrace *) { - return Stage1AirInstIdErrorReturnTrace; -} - -static constexpr Stage1AirInstId ir_inst_id(Stage1AirInstAtomicRmw *) { - return Stage1AirInstIdAtomicRmw; -} - -static constexpr Stage1AirInstId ir_inst_id(Stage1AirInstAtomicLoad *) { - return Stage1AirInstIdAtomicLoad; -} - -static constexpr Stage1AirInstId ir_inst_id(Stage1AirInstAtomicStore *) { - return Stage1AirInstIdAtomicStore; -} - -static constexpr Stage1AirInstId ir_inst_id(Stage1AirInstSaveErrRetAddr *) { - return Stage1AirInstIdSaveErrRetAddr; -} - -static constexpr Stage1AirInstId ir_inst_id(Stage1AirInstVectorToArray *) { - return Stage1AirInstIdVectorToArray; -} - -static constexpr Stage1AirInstId ir_inst_id(Stage1AirInstArrayToVector *) { - return Stage1AirInstIdArrayToVector; -} - -static constexpr Stage1AirInstId ir_inst_id(Stage1AirInstAssertZero *) { - return Stage1AirInstIdAssertZero; -} - -static constexpr Stage1AirInstId ir_inst_id(Stage1AirInstAssertNonNull *) { - return Stage1AirInstIdAssertNonNull; -} - -static constexpr Stage1AirInstId ir_inst_id(Stage1AirInstPtrOfArrayToSlice *) { - return Stage1AirInstIdPtrOfArrayToSlice; -} - -static constexpr Stage1AirInstId ir_inst_id(Stage1AirInstSuspendBegin *) { - return Stage1AirInstIdSuspendBegin; -} - -static constexpr Stage1AirInstId ir_inst_id(Stage1AirInstSuspendFinish *) { - return Stage1AirInstIdSuspendFinish; -} - -static constexpr Stage1AirInstId ir_inst_id(Stage1AirInstAwait *) { - return Stage1AirInstIdAwait; -} - -static constexpr Stage1AirInstId ir_inst_id(Stage1AirInstResume *) { - return Stage1AirInstIdResume; -} - -static constexpr Stage1AirInstId ir_inst_id(Stage1AirInstSpillBegin *) { - return Stage1AirInstIdSpillBegin; -} - -static constexpr Stage1AirInstId ir_inst_id(Stage1AirInstSpillEnd *) { - return Stage1AirInstIdSpillEnd; -} - -static constexpr Stage1AirInstId ir_inst_id(Stage1AirInstVectorExtractElem *) { - return Stage1AirInstIdVectorExtractElem; -} - -static constexpr Stage1AirInstId ir_inst_id(Stage1AirInstAlloca *) { - return Stage1AirInstIdAlloca; -} - -static constexpr Stage1AirInstId ir_inst_id(Stage1AirInstConst *) { - return Stage1AirInstIdConst; -} - -static constexpr Stage1AirInstId ir_inst_id(Stage1AirInstWasmMemorySize *) { - return Stage1AirInstIdWasmMemorySize; -} - -static constexpr Stage1AirInstId ir_inst_id(Stage1AirInstWasmMemoryGrow *) { - return Stage1AirInstIdWasmMemoryGrow; -} - -static constexpr Stage1AirInstId ir_inst_id(Stage1AirInstExtern *) { - return Stage1AirInstIdExtern; -} - -static constexpr Stage1AirInstId ir_inst_id(Stage1AirInstPrefetch *) { - return Stage1AirInstIdPrefetch; -} - -template -static T *ir_create_inst_gen(IrBuilderGen *irb, Scope *scope, AstNode *source_node) { - T *special_instruction = heap::c_allocator.create(); - special_instruction->base.id = ir_inst_id(special_instruction); - special_instruction->base.scope = scope; - special_instruction->base.source_node = source_node; - special_instruction->base.debug_id = exec_next_debug_id_gen(irb->exec); - special_instruction->base.value = irb->codegen->pass1_arena->create(); - return special_instruction; -} - -template -static T *ir_create_inst_noval(IrBuilderGen *irb, Scope *scope, AstNode *source_node) { - T *special_instruction = heap::c_allocator.create(); - special_instruction->base.id = ir_inst_id(special_instruction); - special_instruction->base.scope = scope; - special_instruction->base.source_node = source_node; - special_instruction->base.debug_id = exec_next_debug_id_gen(irb->exec); - return special_instruction; -} - -template -static T *ir_build_inst_gen(IrBuilderGen *irb, Scope *scope, AstNode *source_node) { - T *special_instruction = ir_create_inst_gen(irb, scope, source_node); - ir_inst_gen_append(irb->current_basic_block, &special_instruction->base); - return special_instruction; -} - -template -static T *ir_build_inst_noreturn(IrBuilderGen *irb, Scope *scope, AstNode *source_node) { - T *special_instruction = ir_create_inst_noval(irb, scope, source_node); - special_instruction->base.value = irb->codegen->intern.for_unreachable(); - ir_inst_gen_append(irb->current_basic_block, &special_instruction->base); - return special_instruction; -} - -template -static T *ir_build_inst_void(IrBuilderGen *irb, Scope *scope, AstNode *source_node) { - T *special_instruction = ir_create_inst_noval(irb, scope, source_node); - special_instruction->base.value = irb->codegen->intern.for_void(); - ir_inst_gen_append(irb->current_basic_block, &special_instruction->base); - return special_instruction; -} - -Stage1AirInst *ir_create_alloca(CodeGen *g, Scope *scope, AstNode *source_node, ZigFn *fn, - ZigType *var_type, const char *name_hint) -{ - Stage1AirInstAlloca *alloca_gen = heap::c_allocator.create(); - alloca_gen->base.id = Stage1AirInstIdAlloca; - alloca_gen->base.source_node = source_node; - alloca_gen->base.scope = scope; - alloca_gen->base.value = g->pass1_arena->create(); - alloca_gen->base.value->type = get_pointer_to_type(g, var_type, false); - alloca_gen->base.ref_count = 1; - alloca_gen->name_hint = name_hint; - fn->alloca_gen_list.append(alloca_gen); - return &alloca_gen->base; -} - -static Stage1AirInst *ir_build_cast(IrAnalyze *ira, Scope *scope, AstNode *source_node, - ZigType *dest_type, Stage1AirInst *value, CastOp cast_op) -{ - Stage1AirInstCast *inst = ir_build_inst_gen(&ira->new_irb, scope, source_node); - inst->base.value->type = dest_type; - inst->value = value; - inst->cast_op = cast_op; - - ir_ref_inst_gen(value); - - return &inst->base; -} - -static Stage1AirInst *ir_build_cond_br_gen(IrAnalyze *ira, Scope *scope, AstNode *source_node, Stage1AirInst *condition, - Stage1AirBasicBlock *then_block, Stage1AirBasicBlock *else_block) -{ - Stage1AirInstCondBr *inst = ir_build_inst_noreturn(&ira->new_irb, scope, source_node); - inst->condition = condition; - inst->then_block = then_block; - inst->else_block = else_block; - - ir_ref_inst_gen(condition); - - return &inst->base; -} - -static Stage1AirInst *ir_build_return_gen(IrAnalyze *ira, Scope *scope, AstNode *source_node, Stage1AirInst *operand) { - Stage1AirInstReturn *inst = ir_build_inst_noreturn(&ira->new_irb, scope, source_node); - inst->operand = operand; - - if (operand != nullptr) ir_ref_inst_gen(operand); - - return &inst->base; -} - -static Stage1AirInst *ir_build_bin_op_gen(IrAnalyze *ira, Scope *scope, AstNode *source_node, ZigType *res_type, - IrBinOp op_id, Stage1AirInst *op1, Stage1AirInst *op2, bool safety_check_on) -{ - Stage1AirInstBinOp *inst = ir_build_inst_gen(&ira->new_irb, - scope, source_node); - inst->base.value->type = res_type; - inst->op_id = op_id; - inst->op1 = op1; - inst->op2 = op2; - inst->safety_check_on = safety_check_on; - - ir_ref_inst_gen(op1); - ir_ref_inst_gen(op2); - - return &inst->base; -} - - -static Stage1AirInst *ir_build_var_ptr_gen(IrAnalyze *ira, Scope *scope, AstNode *source_node, ZigVar *var) { - Stage1AirInstVarPtr *instruction = ir_build_inst_gen(&ira->new_irb, scope, source_node); - instruction->var = var; - - var->ref_count += 1; - - return &instruction->base; -} - -static Stage1AirInst *ir_build_return_ptr(IrAnalyze *ira, Scope *scope, AstNode *source_node, ZigType *ty) { - Stage1AirInstReturnPtr *instruction = ir_build_inst_gen(&ira->new_irb, scope, source_node); - instruction->base.value->type = ty; - return &instruction->base; -} - -static Stage1AirInst *ir_build_elem_ptr_gen(IrAnalyze *ira, Scope *scope, AstNode *source_node, - Stage1AirInst *array_ptr, Stage1AirInst *elem_index, bool safety_check_on, ZigType *return_type) -{ - Stage1AirInstElemPtr *instruction = ir_build_inst_gen(&ira->new_irb, scope, source_node); - instruction->base.value->type = return_type; - instruction->array_ptr = array_ptr; - instruction->elem_index = elem_index; - instruction->safety_check_on = safety_check_on; - - ir_ref_inst_gen(array_ptr); - ir_ref_inst_gen(elem_index); - - return &instruction->base; -} - -static Stage1AirInst *ir_build_struct_field_ptr(IrAnalyze *ira, Scope *scope, AstNode *source_node, - Stage1AirInst *struct_ptr, TypeStructField *field, ZigType *ptr_type) -{ - Stage1AirInstStructFieldPtr *inst = ir_build_inst_gen(&ira->new_irb, scope, source_node); - inst->base.value->type = ptr_type; - inst->struct_ptr = struct_ptr; - inst->field = field; - - ir_ref_inst_gen(struct_ptr); - - return &inst->base; -} - -static Stage1AirInst *ir_build_union_field_ptr(IrAnalyze *ira, Scope *scope, AstNode *source_node, - Stage1AirInst *union_ptr, TypeUnionField *field, bool safety_check_on, bool initializing, ZigType *ptr_type) -{ - Stage1AirInstUnionFieldPtr *inst = ir_build_inst_gen(&ira->new_irb, - scope, source_node); - inst->base.value->type = ptr_type; - inst->initializing = initializing; - inst->safety_check_on = safety_check_on; - inst->union_ptr = union_ptr; - inst->field = field; - - ir_ref_inst_gen(union_ptr); - - return &inst->base; -} - -static Stage1AirInstCall *ir_build_call_gen(IrAnalyze *ira, Scope *scope, AstNode *source_node, - ZigFn *fn_entry, Stage1AirInst *fn_ref, size_t arg_count, Stage1AirInst **args, - CallModifier modifier, Stage1AirInst *new_stack, bool is_async_call_builtin, - Stage1AirInst *result_loc, ZigType *return_type) -{ - Stage1AirInstCall *call_instruction = ir_build_inst_gen(&ira->new_irb, - scope, source_node); - call_instruction->base.value->type = return_type; - call_instruction->fn_entry = fn_entry; - call_instruction->fn_ref = fn_ref; - call_instruction->args = args; - call_instruction->arg_count = arg_count; - call_instruction->modifier = modifier; - call_instruction->is_async_call_builtin = is_async_call_builtin; - call_instruction->new_stack = new_stack; - call_instruction->result_loc = result_loc; - - if (fn_ref != nullptr) ir_ref_inst_gen(fn_ref); - for (size_t i = 0; i < arg_count; i += 1) - ir_ref_inst_gen(args[i]); - if (new_stack != nullptr) ir_ref_inst_gen(new_stack); - if (result_loc != nullptr) ir_ref_inst_gen(result_loc); - - return call_instruction; -} - -static Stage1AirInst *ir_build_phi_gen(IrAnalyze *ira, Scope *scope, AstNode *source_node, bool merge_comptime, - size_t incoming_count, Stage1AirBasicBlock **incoming_blocks, Stage1AirInst **incoming_values, ZigType *result_type) -{ - assert(incoming_count != 0); - assert(incoming_count != SIZE_MAX); - - if (merge_comptime && instr_is_comptime(incoming_values[incoming_count - 1])) { - // We need to check whether all the merged values are comptime-known and equal. - // If so, we elide the runtime phi and replace it with any of the identical comptime-known values. - ZigValue *comptime_value = ir_resolve_const(ira, incoming_values[incoming_count - 1], UndefOk); - if (comptime_value == nullptr) - return ira->codegen->invalid_inst_gen; - - for (size_t i = incoming_count - 1; i > 0;) { - i -= 1; - if (!instr_is_comptime(incoming_values[i])) { - comptime_value = nullptr; - break; - } - ZigValue *value = ir_resolve_const(ira, incoming_values[i], UndefOk); - if (value == nullptr) - return ira->codegen->invalid_inst_gen; - if (!const_values_equal(ira->codegen, comptime_value, value)) { - comptime_value = nullptr; - break; - } - } - if (comptime_value != nullptr) - return incoming_values[0]; - } - - Stage1AirInstPhi *phi_instruction = ir_build_inst_gen(&ira->new_irb, - scope, source_node); - phi_instruction->base.value->type = result_type; - phi_instruction->incoming_count = incoming_count; - phi_instruction->incoming_blocks = incoming_blocks; - phi_instruction->incoming_values = incoming_values; - - for (size_t i = 0; i < incoming_count; i += 1) { - ir_ref_inst_gen(incoming_values[i]); - } - - return &phi_instruction->base; -} - -static Stage1AirInst *ir_build_br_gen(IrAnalyze *ira, Scope *scope, AstNode *source_node, Stage1AirBasicBlock *dest_block) { - Stage1AirInstBr *inst = ir_build_inst_noreturn(&ira->new_irb, scope, source_node); - inst->dest_block = dest_block; - - return &inst->base; -} - -static Stage1AirInst *ir_build_negation(IrAnalyze *ira, Scope *scope, AstNode *source_node, Stage1AirInst *operand, ZigType *expr_type, bool wrapping) { - Stage1AirInstNegation *instruction = ir_build_inst_gen(&ira->new_irb, - scope, source_node); - instruction->base.value->type = expr_type; - instruction->operand = operand; - instruction->wrapping = wrapping; - - ir_ref_inst_gen(operand); - - return &instruction->base; -} - -static Stage1AirInst *ir_build_binary_not(IrAnalyze *ira, Scope *scope, AstNode *source_node, Stage1AirInst *operand, - ZigType *expr_type) -{ - Stage1AirInstBinaryNot *instruction = ir_build_inst_gen(&ira->new_irb, - scope, source_node); - instruction->base.value->type = expr_type; - instruction->operand = operand; - - ir_ref_inst_gen(operand); - - return &instruction->base; -} - -static Stage1AirInst *ir_build_unreachable_gen(IrAnalyze *ira, Scope *scope, AstNode *source_node) { - Stage1AirInstUnreachable *inst = ir_build_inst_noreturn(&ira->new_irb, scope, source_node); - return &inst->base; -} - -static Stage1AirInst *ir_build_store_ptr_gen(IrAnalyze *ira, Scope *scope, AstNode *source_node, Stage1AirInst *ptr, Stage1AirInst *value) { - Stage1AirInstStorePtr *instruction = ir_build_inst_void(&ira->new_irb, - scope, source_node); - instruction->ptr = ptr; - instruction->value = value; - - ir_ref_inst_gen(ptr); - ir_ref_inst_gen(value); - - return &instruction->base; -} - -static Stage1AirInst *ir_build_vector_store_elem(IrAnalyze *ira, Scope *scope, AstNode *source_node, - Stage1AirInst *vector_ptr, Stage1AirInst *index, Stage1AirInst *value) -{ - Stage1AirInstVectorStoreElem *inst = ir_build_inst_void( - &ira->new_irb, scope, source_node); - inst->vector_ptr = vector_ptr; - inst->index = index; - inst->value = value; - - ir_ref_inst_gen(vector_ptr); - ir_ref_inst_gen(index); - ir_ref_inst_gen(value); - - return &inst->base; -} - -static Stage1AirInst *ir_build_var_decl_gen(IrAnalyze *ira, Scope *scope, AstNode *source_node, - ZigVar *var, Stage1AirInst *var_ptr) -{ - Stage1AirInstDeclVar *inst = ir_build_inst_gen(&ira->new_irb, - scope, source_node); - inst->base.value->special = ConstValSpecialStatic; - inst->base.value->type = ira->codegen->builtin_types.entry_void; - inst->var = var; - inst->var_ptr = var_ptr; - - ir_ref_inst_gen(var_ptr); - - return &inst->base; -} - -static Stage1AirInst *ir_build_extern_gen(IrAnalyze *ira, Scope *scope, AstNode *source_node, Buf *name, - GlobalLinkageId linkage, bool is_thread_local, ZigType *expr_type) -{ - Stage1AirInstExtern *instruction = ir_build_inst_gen(&ira->new_irb, - scope, source_node); - instruction->base.value->type = expr_type; - instruction->name = name; - instruction->linkage = linkage; - instruction->is_thread_local = is_thread_local; - - return &instruction->base; -} - -static Stage1AirInst *ir_build_load_ptr_gen(IrAnalyze *ira, Scope *scope, AstNode *source_node, - Stage1AirInst *ptr, ZigType *ty, Stage1AirInst *result_loc) -{ - Stage1AirInstLoadPtr *instruction = ir_build_inst_gen( - &ira->new_irb, scope, source_node); - instruction->base.value->type = ty; - instruction->ptr = ptr; - instruction->result_loc = result_loc; - - ir_ref_inst_gen(ptr); - if (result_loc != nullptr) ir_ref_inst_gen(result_loc); - - return &instruction->base; -} - -static Stage1AirInst *ir_build_asm_gen(IrAnalyze *ira, Scope *scope, AstNode *source_node, - Buf *asm_template, AsmToken *token_list, size_t token_list_len, - Stage1AirInst **input_list, Stage1AirInst **output_types, ZigVar **output_vars, size_t return_count, - bool has_side_effects, ZigType *return_type) -{ - Stage1AirInstAsm *instruction = ir_build_inst_gen(&ira->new_irb, scope, source_node); - instruction->base.value->type = return_type; - instruction->asm_template = asm_template; - instruction->token_list = token_list; - instruction->token_list_len = token_list_len; - instruction->input_list = input_list; - instruction->output_types = output_types; - instruction->output_vars = output_vars; - instruction->return_count = return_count; - instruction->has_side_effects = has_side_effects; - - assert(source_node->type == NodeTypeAsmExpr); - for (size_t i = 0; i < source_node->data.asm_expr.output_list.length; i += 1) { - Stage1AirInst *output_type = output_types[i]; - if (output_type) ir_ref_inst_gen(output_type); - } - - for (size_t i = 0; i < source_node->data.asm_expr.input_list.length; i += 1) { - Stage1AirInst *input_value = input_list[i]; - ir_ref_inst_gen(input_value); - } - - return &instruction->base; -} - -static Stage1AirInst *ir_build_test_non_null_gen(IrAnalyze *ira, Scope *scope, AstNode *source_node, Stage1AirInst *value) { - Stage1AirInstTestNonNull *inst = ir_build_inst_gen(&ira->new_irb, - scope, source_node); - inst->base.value->type = ira->codegen->builtin_types.entry_bool; - inst->value = value; - - ir_ref_inst_gen(value); - - return &inst->base; -} - -static Stage1AirInst *ir_build_optional_unwrap_ptr_gen(IrAnalyze *ira, Scope *scope, AstNode *source_node, - Stage1AirInst *base_ptr, bool safety_check_on, bool initializing, ZigType *result_type) -{ - Stage1AirInstOptionalUnwrapPtr *inst = ir_build_inst_gen(&ira->new_irb, - scope, source_node); - inst->base.value->type = result_type; - inst->base_ptr = base_ptr; - inst->safety_check_on = safety_check_on; - inst->initializing = initializing; - - ir_ref_inst_gen(base_ptr); - - return &inst->base; -} - -static Stage1AirInst *ir_build_optional_wrap(IrAnalyze *ira, Scope *scope, AstNode *source_node, ZigType *result_ty, - Stage1AirInst *operand, Stage1AirInst *result_loc) -{ - Stage1AirInstOptionalWrap *instruction = ir_build_inst_gen( - &ira->new_irb, scope, source_node); - instruction->base.value->type = result_ty; - instruction->operand = operand; - instruction->result_loc = result_loc; - - ir_ref_inst_gen(operand); - if (result_loc != nullptr) ir_ref_inst_gen(result_loc); - - return &instruction->base; -} - -static Stage1AirInst *ir_build_err_wrap_payload(IrAnalyze *ira, Scope *scope, AstNode *source_node, - ZigType *result_type, Stage1AirInst *operand, Stage1AirInst *result_loc) -{ - Stage1AirInstErrWrapPayload *instruction = ir_build_inst_gen( - &ira->new_irb, scope, source_node); - instruction->base.value->type = result_type; - instruction->operand = operand; - instruction->result_loc = result_loc; - - ir_ref_inst_gen(operand); - if (result_loc != nullptr) ir_ref_inst_gen(result_loc); - - return &instruction->base; -} - -static Stage1AirInst *ir_build_err_wrap_code(IrAnalyze *ira, Scope *scope, AstNode *source_node, - ZigType *result_type, Stage1AirInst *operand, Stage1AirInst *result_loc) -{ - Stage1AirInstErrWrapCode *instruction = ir_build_inst_gen( - &ira->new_irb, scope, source_node); - instruction->base.value->type = result_type; - instruction->operand = operand; - instruction->result_loc = result_loc; - - ir_ref_inst_gen(operand); - if (result_loc != nullptr) ir_ref_inst_gen(result_loc); - - return &instruction->base; -} - -static Stage1AirInst *ir_build_clz_gen(IrAnalyze *ira, Scope *scope, AstNode *source_node, ZigType *result_type, Stage1AirInst *op) { - Stage1AirInstClz *instruction = ir_build_inst_gen(&ira->new_irb, - scope, source_node); - instruction->base.value->type = result_type; - instruction->op = op; - - ir_ref_inst_gen(op); - - return &instruction->base; -} - -static Stage1AirInst *ir_build_ctz_gen(IrAnalyze *ira, Scope *scope, AstNode *source_node, ZigType *result_type, Stage1AirInst *op) { - Stage1AirInstCtz *instruction = ir_build_inst_gen(&ira->new_irb, - scope, source_node); - instruction->base.value->type = result_type; - instruction->op = op; - - ir_ref_inst_gen(op); - - return &instruction->base; -} - -static Stage1AirInst *ir_build_pop_count_gen(IrAnalyze *ira, Scope *scope, AstNode *source_node, ZigType *result_type, - Stage1AirInst *op) -{ - Stage1AirInstPopCount *instruction = ir_build_inst_gen(&ira->new_irb, - scope, source_node); - instruction->base.value->type = result_type; - instruction->op = op; - - ir_ref_inst_gen(op); - - return &instruction->base; -} - -static Stage1AirInst *ir_build_bswap_gen(IrAnalyze *ira, Scope *scope, AstNode *source_node, ZigType *op_type, - Stage1AirInst *op) -{ - Stage1AirInstBswap *instruction = ir_build_inst_gen(&ira->new_irb, - scope, source_node); - instruction->base.value->type = op_type; - instruction->op = op; - - ir_ref_inst_gen(op); - - return &instruction->base; -} - -static Stage1AirInst *ir_build_bit_reverse_gen(IrAnalyze *ira, Scope *scope, AstNode *source_node, ZigType *int_type, - Stage1AirInst *op) -{ - Stage1AirInstBitReverse *instruction = ir_build_inst_gen(&ira->new_irb, - scope, source_node); - instruction->base.value->type = int_type; - instruction->op = op; - - ir_ref_inst_gen(op); - - return &instruction->base; -} - -static Stage1AirInstSwitchBr *ir_build_switch_br_gen(IrAnalyze *ira, Scope *scope, AstNode *source_node, - Stage1AirInst *target_value, Stage1AirBasicBlock *else_block, size_t case_count, Stage1AirInstSwitchBrCase *cases) -{ - Stage1AirInstSwitchBr *instruction = ir_build_inst_noreturn(&ira->new_irb, - scope, source_node); - instruction->target_value = target_value; - instruction->else_block = else_block; - instruction->case_count = case_count; - instruction->cases = cases; - - ir_ref_inst_gen(target_value); - - for (size_t i = 0; i < case_count; i += 1) { - ir_ref_inst_gen(cases[i].value); - } - - return instruction; -} - -static Stage1AirInst *ir_build_union_tag(IrAnalyze *ira, Scope *scope, AstNode *source_node, Stage1AirInst *value, - ZigType *tag_type) -{ - Stage1AirInstUnionTag *instruction = ir_build_inst_gen(&ira->new_irb, - scope, source_node); - instruction->value = value; - instruction->base.value->type = tag_type; - - ir_ref_inst_gen(value); - - return &instruction->base; -} - -static Stage1AirInst *ir_build_ref_gen(IrAnalyze *ira, Scope *scope, AstNode *source_node, ZigType *result_type, - Stage1AirInst *operand, Stage1AirInst *result_loc) -{ - Stage1AirInstRef *instruction = ir_build_inst_gen(&ira->new_irb, - scope, source_node); - instruction->base.value->type = result_type; - instruction->operand = operand; - instruction->result_loc = result_loc; - - ir_ref_inst_gen(operand); - if (result_loc != nullptr) ir_ref_inst_gen(result_loc); - - return &instruction->base; -} - -static Stage1AirInst *ir_build_err_name_gen(IrAnalyze *ira, Scope *scope, AstNode *source_node, Stage1AirInst *value, - ZigType *str_type) -{ - Stage1AirInstErrName *instruction = ir_build_inst_gen(&ira->new_irb, - scope, source_node); - instruction->base.value->type = str_type; - instruction->value = value; - - ir_ref_inst_gen(value); - - return &instruction->base; -} - -static Stage1AirInst *ir_build_cmpxchg_gen(IrAnalyze *ira, Scope *scope, AstNode *source_node, ZigType *result_type, - Stage1AirInst *ptr, Stage1AirInst *cmp_value, Stage1AirInst *new_value, - AtomicOrder success_order, AtomicOrder failure_order, bool is_weak, Stage1AirInst *result_loc) -{ - Stage1AirInstCmpxchg *instruction = ir_build_inst_gen(&ira->new_irb, - scope, source_node); - instruction->base.value->type = result_type; - instruction->ptr = ptr; - instruction->cmp_value = cmp_value; - instruction->new_value = new_value; - instruction->success_order = success_order; - instruction->failure_order = failure_order; - instruction->is_weak = is_weak; - instruction->result_loc = result_loc; - - ir_ref_inst_gen(ptr); - ir_ref_inst_gen(cmp_value); - ir_ref_inst_gen(new_value); - if (result_loc != nullptr) ir_ref_inst_gen(result_loc); - - return &instruction->base; -} - -static Stage1AirInst *ir_build_fence_gen(IrAnalyze *ira, Scope *scope, AstNode *source_node, AtomicOrder order) { - Stage1AirInstFence *instruction = ir_build_inst_void(&ira->new_irb, - scope, source_node); - instruction->order = order; - - return &instruction->base; -} - -static Stage1AirInst *ir_build_reduce_gen(IrAnalyze *ira, Scope *scope, AstNode *source_node, ReduceOp op, Stage1AirInst *value, ZigType *result_type) { - Stage1AirInstReduce *instruction = ir_build_inst_gen(&ira->new_irb, - scope, source_node); - instruction->base.value->type = result_type; - instruction->op = op; - instruction->value = value; - - ir_ref_inst_gen(value); - - return &instruction->base; -} - -static void ir_set_cursor_at_end_gen(IrBuilderGen *irb, Stage1AirBasicBlock *basic_block) { - assert(basic_block); - irb->current_basic_block = basic_block; -} - -static void ir_append_basic_block_gen(IrBuilderGen *irb, Stage1AirBasicBlock *bb) { - assert(!bb->already_appended); - bb->already_appended = true; - irb->exec->basic_block_list.append(bb); -} - -static void ir_set_cursor_at_end_and_append_block_gen(IrBuilderGen *irb, Stage1AirBasicBlock *basic_block) { - ir_append_basic_block_gen(irb, basic_block); - ir_set_cursor_at_end_gen(irb, basic_block); -} - -static Stage1AirInst *ir_build_suspend_begin_gen(IrAnalyze *ira, Scope *scope, AstNode *source_node) { - Stage1AirInstSuspendBegin *inst = ir_build_inst_void(&ira->new_irb, - scope, source_node); - return &inst->base; -} - -static Stage1AirInst *ir_build_save_err_ret_addr_gen(IrAnalyze *ira, Scope *scope, AstNode *source_node) { - Stage1AirInstSaveErrRetAddr *inst = ir_build_inst_void(&ira->new_irb, - scope, source_node); - return &inst->base; -} - -static Stage1AirInst *ir_build_truncate_gen(IrAnalyze *ira, Scope *scope, AstNode *source_node, ZigType *dest_type, - Stage1AirInst *target) -{ - Stage1AirInstTruncate *instruction = ir_build_inst_gen(&ira->new_irb, - scope, source_node); - instruction->base.value->type = dest_type; - instruction->target = target; - - ir_ref_inst_gen(target); - - return &instruction->base; -} - -static Stage1AirInst *ir_build_shuffle_vector_gen(IrAnalyze *ira, Scope *scope, AstNode *source_node, - ZigType *result_type, Stage1AirInst *a, Stage1AirInst *b, Stage1AirInst *mask) -{ - Stage1AirInstShuffleVector *inst = ir_build_inst_gen(&ira->new_irb, scope, source_node); - inst->base.value->type = result_type; - inst->a = a; - inst->b = b; - inst->mask = mask; - - ir_ref_inst_gen(a); - ir_ref_inst_gen(b); - ir_ref_inst_gen(mask); - - return &inst->base; -} - -static Stage1AirInst *ir_build_select_gen(IrAnalyze *ira, Scope *scope, AstNode *source_node, - ZigType *result_type, Stage1AirInst *pred, Stage1AirInst *a, Stage1AirInst *b) -{ - Stage1AirInstSelect *inst = ir_build_inst_gen(&ira->new_irb, scope, source_node); - inst->base.value->type = result_type; - inst->pred = pred; - inst->a = a; - inst->b = b; - - ir_ref_inst_gen(pred); - ir_ref_inst_gen(a); - ir_ref_inst_gen(b); - - return &inst->base; -} - -static Stage1AirInst *ir_build_splat_gen(IrAnalyze *ira, Scope *scope, AstNode *source_node, ZigType *result_type, - Stage1AirInst *scalar) -{ - Stage1AirInstSplat *instruction = ir_build_inst_gen( - &ira->new_irb, scope, source_node); - instruction->base.value->type = result_type; - instruction->scalar = scalar; - - ir_ref_inst_gen(scalar); - - return &instruction->base; -} - -static Stage1AirInst *ir_build_bool_not_gen(IrAnalyze *ira, Scope *scope, AstNode *source_node, Stage1AirInst *value) { - Stage1AirInstBoolNot *instruction = ir_build_inst_gen(&ira->new_irb, - scope, source_node); - instruction->base.value->type = ira->codegen->builtin_types.entry_bool; - instruction->value = value; - - ir_ref_inst_gen(value); - - return &instruction->base; -} - -static Stage1AirInst *ir_build_memset_gen(IrAnalyze *ira, Scope *scope, AstNode *source_node, - Stage1AirInst *dest_ptr, Stage1AirInst *byte, Stage1AirInst *count) -{ - Stage1AirInstMemset *instruction = ir_build_inst_void(&ira->new_irb, - scope, source_node); - instruction->dest_ptr = dest_ptr; - instruction->byte = byte; - instruction->count = count; - - ir_ref_inst_gen(dest_ptr); - ir_ref_inst_gen(byte); - ir_ref_inst_gen(count); - - return &instruction->base; -} - -static Stage1AirInst *ir_build_memcpy_gen(IrAnalyze *ira, Scope *scope, AstNode *source_node, - Stage1AirInst *dest_ptr, Stage1AirInst *src_ptr, Stage1AirInst *count) -{ - Stage1AirInstMemcpy *instruction = ir_build_inst_void(&ira->new_irb, - scope, source_node); - instruction->dest_ptr = dest_ptr; - instruction->src_ptr = src_ptr; - instruction->count = count; - - ir_ref_inst_gen(dest_ptr); - ir_ref_inst_gen(src_ptr); - ir_ref_inst_gen(count); - - return &instruction->base; -} - -static Stage1AirInst *ir_build_slice_gen(IrAnalyze *ira, Scope *scope, AstNode *source_node, ZigType *slice_type, - Stage1AirInst *ptr, Stage1AirInst *start, Stage1AirInst *end, bool safety_check_on, Stage1AirInst *result_loc, - ZigValue *sentinel) -{ - Stage1AirInstSlice *instruction = ir_build_inst_gen( - &ira->new_irb, scope, source_node); - instruction->base.value->type = slice_type; - instruction->ptr = ptr; - instruction->start = start; - instruction->end = end; - instruction->safety_check_on = safety_check_on; - instruction->result_loc = result_loc; - instruction->sentinel = sentinel; - - ir_ref_inst_gen(ptr); - ir_ref_inst_gen(start); - if (end != nullptr) ir_ref_inst_gen(end); - if (result_loc != nullptr) ir_ref_inst_gen(result_loc); - - return &instruction->base; -} - -static Stage1AirInst *ir_build_breakpoint_gen(IrAnalyze *ira, Scope *scope, AstNode *source_node) { - Stage1AirInstBreakpoint *instruction = ir_build_inst_void(&ira->new_irb, - scope, source_node); - return &instruction->base; -} - -static Stage1AirInst *ir_build_return_address_gen(IrAnalyze *ira, Scope *scope, AstNode *source_node) { - Stage1AirInstReturnAddress *inst = ir_build_inst_gen(&ira->new_irb, scope, source_node); - inst->base.value->type = ira->codegen->builtin_types.entry_usize; - return &inst->base; -} - -static Stage1AirInst *ir_build_frame_address_gen(IrAnalyze *ira, Scope *scope, AstNode *source_node) { - Stage1AirInstFrameAddress *inst = ir_build_inst_gen(&ira->new_irb, scope, source_node); - inst->base.value->type = ira->codegen->builtin_types.entry_usize; - return &inst->base; -} - -static Stage1AirInst *ir_build_handle_gen(IrAnalyze *ira, Scope *scope, AstNode *source_node, ZigType *ty) { - Stage1AirInstFrameHandle *inst = ir_build_inst_gen(&ira->new_irb, scope, source_node); - inst->base.value->type = ty; - return &inst->base; -} - -static Stage1AirInst *ir_build_frame_size_gen(IrAnalyze *ira, Scope *scope, AstNode *source_node, Stage1AirInst *fn) -{ - Stage1AirInstFrameSize *inst = ir_build_inst_gen(&ira->new_irb, scope, source_node); - inst->base.value->type = ira->codegen->builtin_types.entry_usize; - inst->fn = fn; - - ir_ref_inst_gen(fn); - - return &inst->base; -} - -static Stage1AirInst *ir_build_overflow_op_gen(IrAnalyze *ira, Scope *scope, AstNode *source_node, - IrOverflowOp op, Stage1AirInst *op1, Stage1AirInst *op2, Stage1AirInst *result_ptr, - ZigType *result_ptr_type) -{ - Stage1AirInstOverflowOp *instruction = ir_build_inst_gen(&ira->new_irb, - scope, source_node); - instruction->base.value->type = ira->codegen->builtin_types.entry_bool; - instruction->op = op; - instruction->op1 = op1; - instruction->op2 = op2; - instruction->result_ptr = result_ptr; - instruction->result_ptr_type = result_ptr_type; - - ir_ref_inst_gen(op1); - ir_ref_inst_gen(op2); - ir_ref_inst_gen(result_ptr); - - return &instruction->base; -} - -static Stage1AirInst *ir_build_float_op_gen(IrAnalyze *ira, Scope *scope, AstNode *source_node, Stage1AirInst *operand, - BuiltinFnId fn_id, ZigType *operand_type) -{ - Stage1AirInstFloatOp *instruction = ir_build_inst_gen(&ira->new_irb, - scope, source_node); - instruction->base.value->type = operand_type; - instruction->operand = operand; - instruction->fn_id = fn_id; - - ir_ref_inst_gen(operand); - - return &instruction->base; -} - -static Stage1AirInst *ir_build_mul_add_gen(IrAnalyze *ira, Scope *scope, AstNode *source_node, Stage1AirInst *op1, Stage1AirInst *op2, - Stage1AirInst *op3, ZigType *expr_type) -{ - Stage1AirInstMulAdd *instruction = ir_build_inst_gen(&ira->new_irb, - scope, source_node); - instruction->base.value->type = expr_type; - instruction->op1 = op1; - instruction->op2 = op2; - instruction->op3 = op3; - - ir_ref_inst_gen(op1); - ir_ref_inst_gen(op2); - ir_ref_inst_gen(op3); - - return &instruction->base; -} - -static Stage1AirInst *ir_build_test_err_gen(IrAnalyze *ira, Scope *scope, AstNode *source_node, Stage1AirInst *err_union) { - Stage1AirInstTestErr *instruction = ir_build_inst_gen( - &ira->new_irb, scope, source_node); - instruction->base.value->type = ira->codegen->builtin_types.entry_bool; - instruction->err_union = err_union; - - ir_ref_inst_gen(err_union); - - return &instruction->base; -} - -static Stage1AirInst *ir_build_unwrap_err_code_gen(IrAnalyze *ira, Scope *scope, AstNode *source_node, - Stage1AirInst *err_union_ptr, ZigType *result_type) -{ - Stage1AirInstUnwrapErrCode *inst = ir_build_inst_gen(&ira->new_irb, scope, source_node); - inst->base.value->type = result_type; - inst->err_union_ptr = err_union_ptr; - - ir_ref_inst_gen(err_union_ptr); - - return &inst->base; -} - -static Stage1AirInst *ir_build_unwrap_err_payload_gen(IrAnalyze *ira, Scope *scope, AstNode *source_node, - Stage1AirInst *value, bool safety_check_on, bool initializing, ZigType *result_type) -{ - Stage1AirInstUnwrapErrPayload *inst = ir_build_inst_gen(&ira->new_irb, scope, source_node); - inst->base.value->type = result_type; - inst->value = value; - inst->safety_check_on = safety_check_on; - inst->initializing = initializing; - - ir_ref_inst_gen(value); - - return &inst->base; -} - -static Stage1AirInst *ir_build_ptr_cast_gen(IrAnalyze *ira, Scope *scope, AstNode *source_node, - ZigType *ptr_type, Stage1AirInst *ptr, bool safety_check_on) -{ - Stage1AirInstPtrCast *instruction = ir_build_inst_gen( - &ira->new_irb, scope, source_node); - instruction->base.value->type = ptr_type; - instruction->ptr = ptr; - instruction->safety_check_on = safety_check_on; - - ir_ref_inst_gen(ptr); - - return &instruction->base; -} - -static Stage1AirInst *ir_build_bit_cast_gen(IrAnalyze *ira, Scope *scope, AstNode *source_node, - Stage1AirInst *operand, ZigType *ty) -{ - Stage1AirInstBitCast *instruction = ir_build_inst_gen( - &ira->new_irb, scope, source_node); - instruction->base.value->type = ty; - instruction->operand = operand; - - ir_ref_inst_gen(operand); - - return &instruction->base; -} - -static Stage1AirInst *ir_build_widen_or_shorten(IrAnalyze *ira, Scope *scope, AstNode *source_node, Stage1AirInst *target, - ZigType *result_type) -{ - Stage1AirInstWidenOrShorten *inst = ir_build_inst_gen(&ira->new_irb, scope, source_node); - inst->base.value->type = result_type; - inst->target = target; - - ir_ref_inst_gen(target); - - return &inst->base; -} - -static Stage1AirInst *ir_build_int_to_ptr_gen(IrAnalyze *ira, Scope *scope, AstNode *source_node, - Stage1AirInst *target, ZigType *ptr_type) -{ - Stage1AirInstIntToPtr *instruction = ir_build_inst_gen(&ira->new_irb, scope, source_node); - instruction->base.value->type = ptr_type; - instruction->target = target; - - ir_ref_inst_gen(target); - - return &instruction->base; -} - -static Stage1AirInst *ir_build_ptr_to_int_gen(IrAnalyze *ira, Scope *scope, AstNode *source_node, Stage1AirInst *target) { - Stage1AirInstPtrToInt *inst = ir_build_inst_gen(&ira->new_irb, scope, source_node); - inst->base.value->type = ira->codegen->builtin_types.entry_usize; - inst->target = target; - - ir_ref_inst_gen(target); - - return &inst->base; -} - -static Stage1AirInst *ir_build_int_to_enum_gen(IrAnalyze *ira, Scope *scope, AstNode *source_node, - ZigType *dest_type, Stage1AirInst *target) -{ - Stage1AirInstIntToEnum *instruction = ir_build_inst_gen(&ira->new_irb, scope, source_node); - instruction->base.value->type = dest_type; - instruction->target = target; - - ir_ref_inst_gen(target); - - return &instruction->base; -} - -static Stage1AirInst *ir_build_int_to_err_gen(IrAnalyze *ira, Scope *scope, AstNode *source_node, Stage1AirInst *target, - ZigType *wanted_type) -{ - Stage1AirInstIntToErr *instruction = ir_build_inst_gen(&ira->new_irb, scope, source_node); - instruction->base.value->type = wanted_type; - instruction->target = target; - - ir_ref_inst_gen(target); - - return &instruction->base; -} - -static Stage1AirInst *ir_build_err_to_int_gen(IrAnalyze *ira, Scope *scope, AstNode *source_node, Stage1AirInst *target, - ZigType *wanted_type) -{ - Stage1AirInstErrToInt *instruction = ir_build_inst_gen(&ira->new_irb, scope, source_node); - instruction->base.value->type = wanted_type; - instruction->target = target; - - ir_ref_inst_gen(target); - - return &instruction->base; -} - -static Stage1AirInst *ir_build_panic_gen(IrAnalyze *ira, Scope *scope, AstNode *source_node, Stage1AirInst *msg) { - Stage1AirInstPanic *instruction = ir_build_inst_noreturn(&ira->new_irb, - scope, source_node); - instruction->msg = msg; - - ir_ref_inst_gen(msg); - - return &instruction->base; -} - -static Stage1AirInst *ir_build_tag_name_gen(IrAnalyze *ira, Scope *scope, AstNode *source_node, Stage1AirInst *target, - ZigType *result_type) -{ - Stage1AirInstTagName *instruction = ir_build_inst_gen(&ira->new_irb, - scope, source_node); - instruction->base.value->type = result_type; - instruction->target = target; - - ir_ref_inst_gen(target); - - return &instruction->base; -} - -static Stage1AirInst *ir_build_field_parent_ptr_gen(IrAnalyze *ira, Scope *scope, AstNode *source_node, - Stage1AirInst *field_ptr, TypeStructField *field, ZigType *result_type) -{ - Stage1AirInstFieldParentPtr *inst = ir_build_inst_gen(&ira->new_irb, - scope, source_node); - inst->base.value->type = result_type; - inst->field_ptr = field_ptr; - inst->field = field; - - ir_ref_inst_gen(field_ptr); - - return &inst->base; -} - -static Stage1AirInst *ir_build_align_cast_gen(IrAnalyze *ira, Scope *scope, AstNode *source_node, Stage1AirInst *target, - ZigType *result_type) -{ - Stage1AirInstAlignCast *instruction = ir_build_inst_gen(&ira->new_irb, scope, source_node); - instruction->base.value->type = result_type; - instruction->target = target; - - ir_ref_inst_gen(target); - - return &instruction->base; -} - -static Stage1AirInst *ir_build_error_return_trace_gen(IrAnalyze *ira, Scope *scope, AstNode *source_node, - IrInstErrorReturnTraceOptional optional, ZigType *result_type) -{ - Stage1AirInstErrorReturnTrace *inst = ir_build_inst_gen(&ira->new_irb, scope, source_node); - inst->base.value->type = result_type; - inst->optional = optional; - - return &inst->base; -} - -static Stage1AirInst *ir_build_atomic_rmw_gen(IrAnalyze *ira, Scope *scope, AstNode *source_node, - Stage1AirInst *ptr, Stage1AirInst *operand, AtomicRmwOp op, AtomicOrder ordering, ZigType *operand_type) -{ - Stage1AirInstAtomicRmw *instruction = ir_build_inst_gen(&ira->new_irb, scope, source_node); - instruction->base.value->type = operand_type; - instruction->ptr = ptr; - instruction->op = op; - instruction->operand = operand; - instruction->ordering = ordering; - - ir_ref_inst_gen(ptr); - ir_ref_inst_gen(operand); - - return &instruction->base; -} - -static Stage1AirInst *ir_build_atomic_load_gen(IrAnalyze *ira, Scope *scope, AstNode *source_node, - Stage1AirInst *ptr, AtomicOrder ordering, ZigType *operand_type) -{ - Stage1AirInstAtomicLoad *instruction = ir_build_inst_gen(&ira->new_irb, - scope, source_node); - instruction->base.value->type = operand_type; - instruction->ptr = ptr; - instruction->ordering = ordering; - - ir_ref_inst_gen(ptr); - - return &instruction->base; -} - -static Stage1AirInst *ir_build_atomic_store_gen(IrAnalyze *ira, Scope *scope, AstNode *source_node, - Stage1AirInst *ptr, Stage1AirInst *value, AtomicOrder ordering) -{ - Stage1AirInstAtomicStore *instruction = ir_build_inst_void(&ira->new_irb, - scope, source_node); - instruction->ptr = ptr; - instruction->value = value; - instruction->ordering = ordering; - - ir_ref_inst_gen(ptr); - ir_ref_inst_gen(value); - - return &instruction->base; -} - - -static Stage1AirInst *ir_build_vector_to_array(IrAnalyze *ira, Scope *scope, AstNode *source_node, - ZigType *result_type, Stage1AirInst *vector, Stage1AirInst *result_loc) -{ - Stage1AirInstVectorToArray *instruction = ir_build_inst_gen(&ira->new_irb, - scope, source_node); - instruction->base.value->type = result_type; - instruction->vector = vector; - instruction->result_loc = result_loc; - - ir_ref_inst_gen(vector); - ir_ref_inst_gen(result_loc); - - return &instruction->base; -} - -static Stage1AirInst *ir_build_ptr_of_array_to_slice(IrAnalyze *ira, Scope *scope, AstNode *source_node, - ZigType *result_type, Stage1AirInst *operand, Stage1AirInst *result_loc) -{ - Stage1AirInstPtrOfArrayToSlice *instruction = ir_build_inst_gen(&ira->new_irb, - scope, source_node); - instruction->base.value->type = result_type; - instruction->operand = operand; - instruction->result_loc = result_loc; - - ir_ref_inst_gen(operand); - ir_ref_inst_gen(result_loc); - - return &instruction->base; -} - -static Stage1AirInst *ir_build_array_to_vector(IrAnalyze *ira, Scope *scope, AstNode *source_node, - Stage1AirInst *array, ZigType *result_type) -{ - Stage1AirInstArrayToVector *instruction = ir_build_inst_gen(&ira->new_irb, - scope, source_node); - instruction->base.value->type = result_type; - instruction->array = array; - - ir_ref_inst_gen(array); - - return &instruction->base; -} - -static Stage1AirInst *ir_build_assert_zero(IrAnalyze *ira, Scope *scope, AstNode *source_node, - Stage1AirInst *target) -{ - Stage1AirInstAssertZero *instruction = ir_build_inst_gen(&ira->new_irb, - scope, source_node); - instruction->base.value->type = ira->codegen->builtin_types.entry_void; - instruction->target = target; - - ir_ref_inst_gen(target); - - return &instruction->base; -} - -static Stage1AirInst *ir_build_assert_non_null(IrAnalyze *ira, Scope *scope, AstNode *source_node, - Stage1AirInst *target) -{ - Stage1AirInstAssertNonNull *instruction = ir_build_inst_gen(&ira->new_irb, - scope, source_node); - instruction->base.value->type = ira->codegen->builtin_types.entry_void; - instruction->target = target; - - ir_ref_inst_gen(target); - - return &instruction->base; -} - -static Stage1AirInstAlloca *ir_build_alloca_gen(IrAnalyze *ira, Scope *scope, AstNode *source_node, - uint32_t align, const char *name_hint) -{ - Stage1AirInstAlloca *instruction = ir_create_inst_gen(&ira->new_irb, - scope, source_node); - instruction->align = align; - instruction->name_hint = name_hint; - - return instruction; -} - -static Stage1AirInst *ir_build_suspend_finish_gen(IrAnalyze *ira, Scope *scope, AstNode *source_node, Stage1AirInstSuspendBegin *begin) { - Stage1AirInstSuspendFinish *inst = ir_build_inst_void(&ira->new_irb, - scope, source_node); - inst->begin = begin; - - ir_ref_inst_gen(&begin->base); - - return &inst->base; -} - -static Stage1AirInstAwait *ir_build_await_gen(IrAnalyze *ira, Scope *scope, AstNode *source_node, - Stage1AirInst *frame, ZigType *result_type, Stage1AirInst *result_loc, bool is_nosuspend) -{ - Stage1AirInstAwait *instruction = ir_build_inst_gen(&ira->new_irb, - scope, source_node); - instruction->base.value->type = result_type; - instruction->frame = frame; - instruction->result_loc = result_loc; - instruction->is_nosuspend = is_nosuspend; - - ir_ref_inst_gen(frame); - if (result_loc != nullptr) ir_ref_inst_gen(result_loc); - - return instruction; -} - -static Stage1AirInst *ir_build_resume_gen(IrAnalyze *ira, Scope *scope, AstNode *source_node, Stage1AirInst *frame) { - Stage1AirInstResume *instruction = ir_build_inst_void(&ira->new_irb, - scope, source_node); - instruction->frame = frame; - - ir_ref_inst_gen(frame); - - return &instruction->base; -} - -static Stage1AirInst *ir_build_spill_begin_gen(IrAnalyze *ira, Scope *scope, AstNode *source_node, Stage1AirInst *operand, - SpillId spill_id) -{ - Stage1AirInstSpillBegin *instruction = ir_build_inst_void(&ira->new_irb, - scope, source_node); - instruction->operand = operand; - instruction->spill_id = spill_id; - - ir_ref_inst_gen(operand); - - return &instruction->base; -} - -static Stage1AirInst *ir_build_spill_end_gen(IrAnalyze *ira, Scope *scope, AstNode *source_node, Stage1AirInstSpillBegin *begin, - ZigType *result_type) -{ - Stage1AirInstSpillEnd *instruction = ir_build_inst_gen(&ira->new_irb, - scope, source_node); - instruction->base.value->type = result_type; - instruction->begin = begin; - - ir_ref_inst_gen(&begin->base); - - return &instruction->base; -} - -static Stage1AirInst *ir_build_vector_extract_elem(IrAnalyze *ira, Scope *scope, AstNode *source_node, - Stage1AirInst *vector, Stage1AirInst *index) -{ - Stage1AirInstVectorExtractElem *instruction = ir_build_inst_gen( - &ira->new_irb, scope, source_node); - instruction->base.value->type = vector->value->type->data.vector.elem_type; - instruction->vector = vector; - instruction->index = index; - - ir_ref_inst_gen(vector); - ir_ref_inst_gen(index); - - return &instruction->base; -} - -static Stage1AirInst *ir_build_wasm_memory_size_gen(IrAnalyze *ira, Scope *scope, AstNode *source_node, Stage1AirInst *index) { - Stage1AirInstWasmMemorySize *instruction = ir_build_inst_gen(&ira->new_irb, - scope, source_node); - instruction->base.value->type = ira->codegen->builtin_types.entry_u32; - instruction->index = index; - - ir_ref_inst_gen(index); - - return &instruction->base; -} - -static Stage1AirInst *ir_build_wasm_memory_grow_gen(IrAnalyze *ira, Scope *scope, AstNode *source_node, Stage1AirInst *index, Stage1AirInst *delta) { - Stage1AirInstWasmMemoryGrow *instruction = ir_build_inst_gen(&ira->new_irb, - scope, source_node); - instruction->base.value->type = ira->codegen->builtin_types.entry_i32; - instruction->index = index; - instruction->delta = delta; - - ir_ref_inst_gen(index); - ir_ref_inst_gen(delta); - - return &instruction->base; -} - -static Error parse_asm_template(IrAnalyze *ira, AstNode *source_node, Buf *asm_template, - ZigList *tok_list) -{ - // TODO Connect the errors in this function back up to the actual source location - // rather than just the token. https://github.com/ziglang/zig/issues/2080 - enum State { - StateStart, - StatePercent, - StateTemplate, - StateVar, - }; - - assert(tok_list->length == 0); - - AsmToken *cur_tok = nullptr; - - enum State state = StateStart; - - for (size_t i = 0; i < buf_len(asm_template); i += 1) { - uint8_t c = *((uint8_t*)buf_ptr(asm_template) + i); - switch (state) { - case StateStart: - if (c == '%') { - tok_list->add_one(); - cur_tok = &tok_list->last(); - cur_tok->id = AsmTokenIdPercent; - cur_tok->start = i; - state = StatePercent; - } else { - tok_list->add_one(); - cur_tok = &tok_list->last(); - cur_tok->id = AsmTokenIdTemplate; - cur_tok->start = i; - state = StateTemplate; - } - break; - case StatePercent: - if (c == '%') { - cur_tok->end = i; - state = StateStart; - } else if (c == '[') { - cur_tok->id = AsmTokenIdVar; - state = StateVar; - } else if (c == '=') { - cur_tok->id = AsmTokenIdUniqueId; - cur_tok->end = i; - state = StateStart; - } else { - add_node_error(ira->codegen, source_node, - buf_create_from_str("expected a '%' or '['")); - return ErrorSemanticAnalyzeFail; - } - break; - case StateTemplate: - if (c == '%') { - cur_tok->end = i; - i -= 1; - cur_tok = nullptr; - state = StateStart; - } - break; - case StateVar: - if (c == ']') { - cur_tok->end = i; - state = StateStart; - } else if ((c >= 'a' && c <= 'z') || - (c >= '0' && c <= '9') || - (c == '_')) - { - // do nothing - } else { - add_node_error(ira->codegen, source_node, - buf_sprintf("invalid substitution character: '%c'", c)); - return ErrorSemanticAnalyzeFail; - } - break; - } - } - - switch (state) { - case StateStart: - break; - case StatePercent: - case StateVar: - add_node_error(ira->codegen, source_node, buf_sprintf("unexpected end of assembly template")); - return ErrorSemanticAnalyzeFail; - case StateTemplate: - cur_tok->end = buf_len(asm_template); - break; - } - return ErrorNone; -} - -// errors should be populated with set1's values -static ZigType *get_error_set_union(CodeGen *g, ErrorTableEntry **errors, ZigType *set1, ZigType *set2, - Buf *type_name) -{ - assert(set1->id == ZigTypeIdErrorSet); - assert(set2->id == ZigTypeIdErrorSet); - - ZigType *err_set_type = new_type_table_entry(ZigTypeIdErrorSet); - err_set_type->size_in_bits = g->builtin_types.entry_global_error_set->size_in_bits; - err_set_type->abi_align = g->builtin_types.entry_global_error_set->abi_align; - err_set_type->abi_size = g->builtin_types.entry_global_error_set->abi_size; - if (type_name == nullptr) { - buf_resize(&err_set_type->name, 0); - buf_appendf(&err_set_type->name, "error{"); - } else { - buf_init_from_buf(&err_set_type->name, type_name); - } - - for (uint32_t i = 0, count = set1->data.error_set.err_count; i < count; i += 1) { - assert(errors[set1->data.error_set.errors[i]->value] == set1->data.error_set.errors[i]); - } - - uint32_t count = set1->data.error_set.err_count; - for (uint32_t i = 0; i < set2->data.error_set.err_count; i += 1) { - ErrorTableEntry *error_entry = set2->data.error_set.errors[i]; - if (errors[error_entry->value] == nullptr) { - count += 1; - } - } - - err_set_type->data.error_set.err_count = count; - err_set_type->data.error_set.errors = heap::c_allocator.allocate(count); - - bool need_comma = false; - for (uint32_t i = 0; i < set1->data.error_set.err_count; i += 1) { - ErrorTableEntry *error_entry = set1->data.error_set.errors[i]; - if (type_name == nullptr) { - const char *comma = need_comma ? "," : ""; - need_comma = true; - buf_appendf(&err_set_type->name, "%s%s", comma, buf_ptr(&error_entry->name)); - } - err_set_type->data.error_set.errors[i] = error_entry; - } - - uint32_t index = set1->data.error_set.err_count; - for (uint32_t i = 0; i < set2->data.error_set.err_count; i += 1) { - ErrorTableEntry *error_entry = set2->data.error_set.errors[i]; - if (errors[error_entry->value] == nullptr) { - errors[error_entry->value] = error_entry; - if (type_name == nullptr) { - const char *comma = need_comma ? "," : ""; - need_comma = true; - buf_appendf(&err_set_type->name, "%s%s", comma, buf_ptr(&error_entry->name)); - } - err_set_type->data.error_set.errors[index] = error_entry; - index += 1; - } - } - assert(index == count); - - if (type_name == nullptr) { - buf_appendf(&err_set_type->name, "}"); - } - - return err_set_type; - -} - -static ZigType *make_err_set_with_one_item(CodeGen *g, Scope *parent_scope, AstNode *node, - ErrorTableEntry *err_entry) -{ - ZigType *err_set_type = new_type_table_entry(ZigTypeIdErrorSet); - buf_resize(&err_set_type->name, 0); - buf_appendf(&err_set_type->name, "error{%s}", buf_ptr(&err_entry->name)); - err_set_type->size_in_bits = g->builtin_types.entry_global_error_set->size_in_bits; - err_set_type->abi_align = g->builtin_types.entry_global_error_set->abi_align; - err_set_type->abi_size = g->builtin_types.entry_global_error_set->abi_size; - err_set_type->data.error_set.err_count = 1; - err_set_type->data.error_set.errors = heap::c_allocator.create(); - - err_set_type->data.error_set.errors[0] = err_entry; - - return err_set_type; -} - -static void invalidate_exec_gen(Stage1Air *exec, ErrorMsg *msg) { - if (exec->first_err_trace_msg != nullptr) - return; - - exec->first_err_trace_msg = msg; - - for (size_t i = 0; i < exec->tld_list.length; i += 1) { - exec->tld_list.items[i]->resolution = TldResolutionInvalid; - } - - if (exec->source_exec != nullptr) - invalidate_exec(exec->source_exec, msg); -} - - -static ErrorMsg *exec_add_error_node_gen(CodeGen *codegen, Stage1Air *exec, AstNode *source_node, Buf *msg) { - ErrorMsg *err_msg = add_node_error(codegen, source_node, msg); - invalidate_exec_gen(exec, err_msg); - if (exec->parent_exec) { - ir_add_call_stack_errors_gen(codegen, exec, err_msg, 10); - } - return err_msg; -} - -static ErrorMsg *ir_add_error_node(IrAnalyze *ira, AstNode *source_node, Buf *msg) { - return exec_add_error_node_gen(ira->codegen, ira->new_irb.exec, source_node, msg); -} - -static ErrorMsg *opt_ir_add_error_node(IrAnalyze *ira, CodeGen *codegen, AstNode *source_node, Buf *msg) { - if (ira != nullptr) - return exec_add_error_node_gen(codegen, ira->new_irb.exec, source_node, msg); - else - return add_node_error(codegen, source_node, msg); -} - -static ErrorMsg *ir_add_error(IrAnalyze *ira, Stage1AirInst *source_instruction, Buf *msg) { - return ir_add_error_node(ira, source_instruction->source_node, msg); -} - -// This function takes a comptime ptr and makes the child const value conform to the type -// described by the pointer. -static Error eval_comptime_ptr_reinterpret(IrAnalyze *ira, CodeGen *codegen, AstNode *source_node, - ZigValue *ptr_val) -{ - Error err; - assert(ptr_val->type->id == ZigTypeIdPointer); - assert(ptr_val->special == ConstValSpecialStatic); - ZigValue tmp = {}; - tmp.special = ConstValSpecialStatic; - tmp.type = ptr_val->type->data.pointer.child_type; - if ((err = ir_read_const_ptr(ira, codegen, source_node, &tmp, ptr_val))) - return err; - ZigValue *child_val = const_ptr_pointee_unchecked(codegen, ptr_val); - copy_const_val(codegen, child_val, &tmp); - return ErrorNone; -} - -ZigValue *const_ptr_pointee(IrAnalyze *ira, CodeGen *codegen, ZigValue *const_val, - AstNode *source_node) -{ - Error err; - ZigValue *val = const_ptr_pointee_unchecked(codegen, const_val); - if (val == nullptr) return nullptr; - assert(const_val->type->id == ZigTypeIdPointer); - ZigType *expected_type = const_val->type->data.pointer.child_type; - if (expected_type == codegen->builtin_types.entry_anytype) { - return val; - } - switch (type_has_one_possible_value(codegen, expected_type)) { - case OnePossibleValueInvalid: - return nullptr; - case OnePossibleValueNo: - break; - case OnePossibleValueYes: - return get_the_one_possible_value(codegen, expected_type); - } - if (!types_have_same_zig_comptime_repr(codegen, expected_type, val->type)) { - if ((err = eval_comptime_ptr_reinterpret(ira, codegen, source_node, const_val))) - return nullptr; - return const_ptr_pointee_unchecked(codegen, const_val); - } - return val; -} - -static Error ir_exec_scan_for_side_effects(CodeGen *codegen, Stage1Air *exec) { - Stage1AirBasicBlock *bb = exec->basic_block_list.at(0); - for (size_t i = 0; i < bb->instruction_list.length; i += 1) { - Stage1AirInst *instruction = bb->instruction_list.at(i); - if (instruction->id == Stage1AirInstIdReturn) { - return ErrorNone; - } else if (ir_inst_gen_has_side_effects(instruction)) { - if (instr_is_comptime(instruction)) { - switch (instruction->id) { - case Stage1AirInstIdUnwrapErrPayload: - case Stage1AirInstIdOptionalUnwrapPtr: - case Stage1AirInstIdUnionFieldPtr: - continue; - default: - break; - } - } - if (get_scope_typeof(instruction->scope) != nullptr) { - // doesn't count, it's inside a @TypeOf() - continue; - } - exec_add_error_node_gen(codegen, exec, instruction->source_node, - buf_sprintf("unable to evaluate constant expression")); - return ErrorSemanticAnalyzeFail; - } - } - zig_unreachable(); -} - -static bool ir_emit_global_runtime_side_effect(IrAnalyze *ira, Stage1ZirInst* source_instruction) { - if (ir_should_inline(ira->zir, source_instruction->scope)) { - ir_add_error_node(ira, source_instruction->source_node, buf_sprintf("unable to evaluate constant expression")); - return false; - } - return true; -} - -static bool const_val_fits_in_num_lit(ZigValue *const_val, ZigType *num_lit_type) { - return ((num_lit_type->id == ZigTypeIdComptimeFloat && - (const_val->type->id == ZigTypeIdFloat || const_val->type->id == ZigTypeIdComptimeFloat)) || - (num_lit_type->id == ZigTypeIdComptimeInt && - (const_val->type->id == ZigTypeIdInt || const_val->type->id == ZigTypeIdComptimeInt))); -} - -static bool float_has_fraction(ZigValue *const_val) { - if (const_val->type->id == ZigTypeIdComptimeFloat) { - return bigfloat_has_fraction(&const_val->data.x_bigfloat); - } else if (const_val->type->id == ZigTypeIdFloat) { - switch (const_val->type->data.floating.bit_count) { - case 16: - { - float16_t floored = f16_roundToInt(const_val->data.x_f16, softfloat_round_minMag, false); - return !f16_eq(floored, const_val->data.x_f16); - } - case 32: - return floorf(const_val->data.x_f32) != const_val->data.x_f32; - case 64: - return floor(const_val->data.x_f64) != const_val->data.x_f64; - case 80: - { - extFloat80_t floored; - extF80M_roundToInt(&const_val->data.x_f80, softfloat_round_minMag, false, &floored); - return !extF80M_eq(&floored, &const_val->data.x_f80); - } - case 128: - { - float128_t floored; - f128M_roundToInt(&const_val->data.x_f128, softfloat_round_minMag, false, &floored); - return !f128M_eq(&floored, &const_val->data.x_f128); - } - default: - zig_unreachable(); - } - } else { - zig_unreachable(); - } -} - -static void float_append_buf(Buf *buf, ZigValue *const_val) { - if (const_val->type->id == ZigTypeIdComptimeFloat) { - bigfloat_append_buf(buf, &const_val->data.x_bigfloat); - } else if (const_val->type->id == ZigTypeIdFloat) { - switch (const_val->type->data.floating.bit_count) { - case 16: - buf_appendf(buf, "%f", zig_f16_to_double(const_val->data.x_f16)); - break; - case 32: - buf_appendf(buf, "%f", const_val->data.x_f32); - break; - case 64: - buf_appendf(buf, "%f", const_val->data.x_f64); - break; - case 80: - { - float64_t f64_value = extF80M_to_f64(&const_val->data.x_f80); - double double_value; - memcpy(&double_value, &f64_value, sizeof(double)); - - buf_appendf(buf, "%f", const_val->data.x_f64); - break; - } - case 128: - { - // TODO actual implementation - const size_t extra_len = 100; - size_t old_len = buf_len(buf); - buf_resize(buf, old_len + extra_len); - - float64_t f64_value = f128M_to_f64(&const_val->data.x_f128); - double double_value; - memcpy(&double_value, &f64_value, sizeof(double)); - - int len = snprintf(buf_ptr(buf) + old_len, extra_len, "%f", double_value); - assert(len > 0); - buf_resize(buf, old_len + len); - break; - } - default: - zig_unreachable(); - } - } else { - zig_unreachable(); - } -} - -static void float_init_bigint(BigInt *bigint, ZigValue *const_val) { - if (const_val->type->id == ZigTypeIdComptimeFloat) { - bigint_init_bigfloat(bigint, &const_val->data.x_bigfloat); - } else if (const_val->type->id == ZigTypeIdFloat) { - switch (const_val->type->data.floating.bit_count) { - case 16: - { - double x = zig_f16_to_double(const_val->data.x_f16); - if (x >= 0) { - bigint_init_unsigned(bigint, (uint64_t)x); - } else { - bigint_init_unsigned(bigint, (uint64_t)-x); - bigint->is_negative = true; - } - break; - } - case 32: - if (const_val->data.x_f32 >= 0) { - bigint_init_unsigned(bigint, (uint64_t)(const_val->data.x_f32)); - } else { - bigint_init_unsigned(bigint, (uint64_t)(-const_val->data.x_f32)); - bigint->is_negative = true; - } - break; - case 64: - if (const_val->data.x_f64 >= 0) { - bigint_init_unsigned(bigint, (uint64_t)(const_val->data.x_f64)); - } else { - bigint_init_unsigned(bigint, (uint64_t)(-const_val->data.x_f64)); - bigint->is_negative = true; - } - break; - case 80: - { - float128_t f128_value; - extF80M_to_f128M(&const_val->data.x_f80, &f128_value); - BigFloat tmp_float; - bigfloat_init_128(&tmp_float, f128_value); - bigint_init_bigfloat(bigint, &tmp_float); - } - break; - case 128: - { - BigFloat tmp_float; - bigfloat_init_128(&tmp_float, const_val->data.x_f128); - bigint_init_bigfloat(bigint, &tmp_float); - } - break; - default: - zig_unreachable(); - } - } else { - zig_unreachable(); - } -} - -static void float_init_bigfloat(ZigValue *dest_val, BigFloat *bigfloat) { - if (dest_val->type->id == ZigTypeIdComptimeFloat) { - bigfloat_init_bigfloat(&dest_val->data.x_bigfloat, bigfloat); - } else if (dest_val->type->id == ZigTypeIdFloat) { - switch (dest_val->type->data.floating.bit_count) { - case 16: - dest_val->data.x_f16 = bigfloat_to_f16(bigfloat); - break; - case 32: - dest_val->data.x_f32 = bigfloat_to_f32(bigfloat); - break; - case 64: - dest_val->data.x_f64 = bigfloat_to_f64(bigfloat); - break; - case 80: { - float128_t f128_value = bigfloat_to_f128(bigfloat); - f128M_to_extF80M(&f128_value, &dest_val->data.x_f80); - break; - } - case 128: - dest_val->data.x_f128 = bigfloat_to_f128(bigfloat); - break; - default: - zig_unreachable(); - } - } else { - zig_unreachable(); - } -} - -static void float_init_f16(ZigValue *dest_val, float16_t x) { - if (dest_val->type->id == ZigTypeIdComptimeFloat) { - bigfloat_init_16(&dest_val->data.x_bigfloat, x); - } else if (dest_val->type->id == ZigTypeIdFloat) { - switch (dest_val->type->data.floating.bit_count) { - case 16: - dest_val->data.x_f16 = x; - break; - case 32: - dest_val->data.x_f32 = zig_f16_to_double(x); - break; - case 64: - dest_val->data.x_f64 = zig_f16_to_double(x); - break; - case 80: - f16_to_extF80M(x, &dest_val->data.x_f80); - break; - case 128: - f16_to_f128M(x, &dest_val->data.x_f128); - break; - default: - zig_unreachable(); - } - } else { - zig_unreachable(); - } -} - -static void float_init_f32(ZigValue *dest_val, float x) { - if (dest_val->type->id == ZigTypeIdComptimeFloat) { - bigfloat_init_32(&dest_val->data.x_bigfloat, x); - } else if (dest_val->type->id == ZigTypeIdFloat) { - switch (dest_val->type->data.floating.bit_count) { - case 16: - dest_val->data.x_f16 = zig_double_to_f16(x); - break; - case 32: - dest_val->data.x_f32 = x; - break; - case 64: - dest_val->data.x_f64 = x; - break; - case 80: { - float32_t x_f32; - memcpy(&x_f32, &x, sizeof(float)); - f32_to_extF80M(x_f32, &dest_val->data.x_f80); - break; - } - case 128: - { - float32_t x_f32; - memcpy(&x_f32, &x, sizeof(float)); - f32_to_f128M(x_f32, &dest_val->data.x_f128); - break; - } - default: - zig_unreachable(); - } - } else { - zig_unreachable(); - } -} - -static void float_init_f64(ZigValue *dest_val, double x) { - if (dest_val->type->id == ZigTypeIdComptimeFloat) { - bigfloat_init_64(&dest_val->data.x_bigfloat, x); - } else if (dest_val->type->id == ZigTypeIdFloat) { - switch (dest_val->type->data.floating.bit_count) { - case 16: - dest_val->data.x_f16 = zig_double_to_f16(x); - break; - case 32: - dest_val->data.x_f32 = x; - break; - case 64: - dest_val->data.x_f64 = x; - break; - case 80: { - float64_t x_f64; - memcpy(&x_f64, &x, sizeof(double)); - f64_to_extF80M(x_f64, &dest_val->data.x_f80); - break; - } - case 128: - { - float64_t x_f64; - memcpy(&x_f64, &x, sizeof(double)); - f64_to_f128M(x_f64, &dest_val->data.x_f128); - break; - } - default: - zig_unreachable(); - } - } else { - zig_unreachable(); - } -} - -static void float_init_f128(ZigValue *dest_val, float128_t x) { - if (dest_val->type->id == ZigTypeIdComptimeFloat) { - bigfloat_init_128(&dest_val->data.x_bigfloat, x); - } else if (dest_val->type->id == ZigTypeIdFloat) { - switch (dest_val->type->data.floating.bit_count) { - case 16: - dest_val->data.x_f16 = f128M_to_f16(&x); - break; - case 32: - { - float32_t f32_val = f128M_to_f32(&x); - memcpy(&dest_val->data.x_f32, &f32_val, sizeof(float)); - break; - } - case 64: - { - float64_t f64_val = f128M_to_f64(&x); - memcpy(&dest_val->data.x_f64, &f64_val, sizeof(double)); - break; - } - case 80: - f128M_to_extF80M(&x, &dest_val->data.x_f80); - break; - case 128: - { - memcpy(&dest_val->data.x_f128, &x, sizeof(float128_t)); - break; - } - default: - zig_unreachable(); - } - } else { - zig_unreachable(); - } -} - -static void float_init_float(ZigValue *dest_val, ZigValue *src_val) { - if (src_val->type->id == ZigTypeIdComptimeFloat) { - float_init_bigfloat(dest_val, &src_val->data.x_bigfloat); - } else if (src_val->type->id == ZigTypeIdFloat) { - switch (src_val->type->data.floating.bit_count) { - case 16: - float_init_f16(dest_val, src_val->data.x_f16); - break; - case 32: - float_init_f32(dest_val, src_val->data.x_f32); - break; - case 64: - float_init_f64(dest_val, src_val->data.x_f64); - break; - case 80: { - float128_t f128_value; - extF80M_to_f128M(&src_val->data.x_f80, &f128_value); - float_init_f128(dest_val, f128_value); - break; - } - case 128: - float_init_f128(dest_val, src_val->data.x_f128); - break; - default: - zig_unreachable(); - } - } else { - zig_unreachable(); - } -} - -static bool float_is_nan(ZigValue *op) { - if (op->type->id == ZigTypeIdComptimeFloat) { - return bigfloat_is_nan(&op->data.x_bigfloat); - } else if (op->type->id == ZigTypeIdFloat) { - switch (op->type->data.floating.bit_count) { - case 16: - return zig_f16_isNaN(op->data.x_f16); - case 32: - return op->data.x_f32 != op->data.x_f32; - case 64: - return op->data.x_f64 != op->data.x_f64; - case 80: - return zig_extF80_isNaN(&op->data.x_f80); - case 128: - return zig_f128_isNaN(&op->data.x_f128); - default: - zig_unreachable(); - } - } else { - zig_unreachable(); - } -} - -static Cmp float_cmp(ZigValue *op1, ZigValue *op2) { - if (op1->type == op2->type) { - if (op1->type->id == ZigTypeIdComptimeFloat) { - return bigfloat_cmp(&op1->data.x_bigfloat, &op2->data.x_bigfloat); - } else if (op1->type->id == ZigTypeIdFloat) { - switch (op1->type->data.floating.bit_count) { - case 16: - if (f16_lt(op1->data.x_f16, op2->data.x_f16)) { - return CmpLT; - } else if (f16_lt(op2->data.x_f16, op1->data.x_f16)) { - return CmpGT; - } else { - return CmpEQ; - } - case 32: - if (op1->data.x_f32 > op2->data.x_f32) { - return CmpGT; - } else if (op1->data.x_f32 < op2->data.x_f32) { - return CmpLT; - } else { - return CmpEQ; - } - case 64: - if (op1->data.x_f64 > op2->data.x_f64) { - return CmpGT; - } else if (op1->data.x_f64 < op2->data.x_f64) { - return CmpLT; - } else { - return CmpEQ; - } - case 80: - if (extF80M_lt(&op1->data.x_f80, &op2->data.x_f80)) { - return CmpLT; - } else if (extF80M_eq(&op1->data.x_f80, &op2->data.x_f80)) { - return CmpEQ; - } else { - return CmpGT; - } - case 128: - if (f128M_lt(&op1->data.x_f128, &op2->data.x_f128)) { - return CmpLT; - } else if (f128M_eq(&op1->data.x_f128, &op2->data.x_f128)) { - return CmpEQ; - } else { - return CmpGT; - } - default: - zig_unreachable(); - } - } else { - zig_unreachable(); - } - } - BigFloat op1_big; - BigFloat op2_big; - value_to_bigfloat(&op1_big, op1); - value_to_bigfloat(&op2_big, op2); - return bigfloat_cmp(&op1_big, &op2_big); -} - -// This function cannot handle NaN -static Cmp float_cmp_zero(ZigValue *op) { - if (op->type->id == ZigTypeIdComptimeFloat) { - return bigfloat_cmp_zero(&op->data.x_bigfloat); - } else if (op->type->id == ZigTypeIdFloat) { - switch (op->type->data.floating.bit_count) { - case 16: - { - const float16_t zero = zig_double_to_f16(0); - if (f16_lt(op->data.x_f16, zero)) { - return CmpLT; - } else if (f16_lt(zero, op->data.x_f16)) { - return CmpGT; - } else { - return CmpEQ; - } - } - case 32: - if (op->data.x_f32 < 0.0) { - return CmpLT; - } else if (op->data.x_f32 > 0.0) { - return CmpGT; - } else { - return CmpEQ; - } - case 64: - if (op->data.x_f64 < 0.0) { - return CmpLT; - } else if (op->data.x_f64 > 0.0) { - return CmpGT; - } else { - return CmpEQ; - } - case 80: { - extFloat80_t zero_float; - ui32_to_extF80M(0, &zero_float); - if (extF80M_lt(&op->data.x_f80, &zero_float)) { - return CmpLT; - } else if (extF80M_eq(&op->data.x_f80, &zero_float)) { - return CmpEQ; - } else { - return CmpGT; - } - } - case 128: { - float128_t zero_float; - ui32_to_f128M(0, &zero_float); - if (f128M_lt(&op->data.x_f128, &zero_float)) { - return CmpLT; - } else if (f128M_eq(&op->data.x_f128, &zero_float)) { - return CmpEQ; - } else { - return CmpGT; - } - } - default: - zig_unreachable(); - } - } else { - zig_unreachable(); - } -} - -static void float_add(ZigValue *out_val, ZigValue *op1, ZigValue *op2) { - assert(op1->type == op2->type); - out_val->type = op1->type; - if (op1->type->id == ZigTypeIdComptimeFloat) { - bigfloat_add(&out_val->data.x_bigfloat, &op1->data.x_bigfloat, &op2->data.x_bigfloat); - } else if (op1->type->id == ZigTypeIdFloat) { - switch (op1->type->data.floating.bit_count) { - case 16: - out_val->data.x_f16 = f16_add(op1->data.x_f16, op2->data.x_f16); - return; - case 32: - out_val->data.x_f32 = op1->data.x_f32 + op2->data.x_f32; - return; - case 64: - out_val->data.x_f64 = op1->data.x_f64 + op2->data.x_f64; - return; - case 80: - extF80M_add(&op1->data.x_f80, &op2->data.x_f80, &out_val->data.x_f80); - return; - case 128: - f128M_add(&op1->data.x_f128, &op2->data.x_f128, &out_val->data.x_f128); - return; - default: - zig_unreachable(); - } - } else { - zig_unreachable(); - } -} - -static void float_sub(ZigValue *out_val, ZigValue *op1, ZigValue *op2) { - assert(op1->type == op2->type); - out_val->type = op1->type; - if (op1->type->id == ZigTypeIdComptimeFloat) { - bigfloat_sub(&out_val->data.x_bigfloat, &op1->data.x_bigfloat, &op2->data.x_bigfloat); - } else if (op1->type->id == ZigTypeIdFloat) { - switch (op1->type->data.floating.bit_count) { - case 16: - out_val->data.x_f16 = f16_sub(op1->data.x_f16, op2->data.x_f16); - return; - case 32: - out_val->data.x_f32 = op1->data.x_f32 - op2->data.x_f32; - return; - case 64: - out_val->data.x_f64 = op1->data.x_f64 - op2->data.x_f64; - return; - case 80: - extF80M_sub(&op1->data.x_f80, &op2->data.x_f80, &out_val->data.x_f80); - return; - case 128: - f128M_sub(&op1->data.x_f128, &op2->data.x_f128, &out_val->data.x_f128); - return; - default: - zig_unreachable(); - } - } else { - zig_unreachable(); - } -} - -static void float_mul(ZigValue *out_val, ZigValue *op1, ZigValue *op2) { - assert(op1->type == op2->type); - out_val->type = op1->type; - if (op1->type->id == ZigTypeIdComptimeFloat) { - bigfloat_mul(&out_val->data.x_bigfloat, &op1->data.x_bigfloat, &op2->data.x_bigfloat); - } else if (op1->type->id == ZigTypeIdFloat) { - switch (op1->type->data.floating.bit_count) { - case 16: - out_val->data.x_f16 = f16_mul(op1->data.x_f16, op2->data.x_f16); - return; - case 32: - out_val->data.x_f32 = op1->data.x_f32 * op2->data.x_f32; - return; - case 64: - out_val->data.x_f64 = op1->data.x_f64 * op2->data.x_f64; - return; - case 80: - extF80M_mul(&op1->data.x_f80, &op2->data.x_f80, &out_val->data.x_f80); - return; - case 128: - f128M_mul(&op1->data.x_f128, &op2->data.x_f128, &out_val->data.x_f128); - return; - default: - zig_unreachable(); - } - } else { - zig_unreachable(); - } -} - -static void float_div(ZigValue *out_val, ZigValue *op1, ZigValue *op2) { - assert(op1->type == op2->type); - out_val->type = op1->type; - if (op1->type->id == ZigTypeIdComptimeFloat) { - bigfloat_div(&out_val->data.x_bigfloat, &op1->data.x_bigfloat, &op2->data.x_bigfloat); - } else if (op1->type->id == ZigTypeIdFloat) { - switch (op1->type->data.floating.bit_count) { - case 16: - out_val->data.x_f16 = f16_div(op1->data.x_f16, op2->data.x_f16); - return; - case 32: - out_val->data.x_f32 = op1->data.x_f32 / op2->data.x_f32; - return; - case 64: - out_val->data.x_f64 = op1->data.x_f64 / op2->data.x_f64; - return; - case 80: - extF80M_div(&op1->data.x_f80, &op2->data.x_f80, &out_val->data.x_f80); - return; - case 128: - f128M_div(&op1->data.x_f128, &op2->data.x_f128, &out_val->data.x_f128); - return; - default: - zig_unreachable(); - } - } else { - zig_unreachable(); - } -} - -static void float_div_trunc(ZigValue *out_val, ZigValue *op1, ZigValue *op2) { - assert(op1->type == op2->type); - out_val->type = op1->type; - if (op1->type->id == ZigTypeIdComptimeFloat) { - bigfloat_div_trunc(&out_val->data.x_bigfloat, &op1->data.x_bigfloat, &op2->data.x_bigfloat); - } else if (op1->type->id == ZigTypeIdFloat) { - switch (op1->type->data.floating.bit_count) { - case 16: - out_val->data.x_f16 = f16_div(op1->data.x_f16, op2->data.x_f16); - out_val->data.x_f16 = f16_roundToInt(out_val->data.x_f16, softfloat_round_minMag, false); - return; - case 32: - out_val->data.x_f32 = truncf(op1->data.x_f32 / op2->data.x_f32); - return; - case 64: - out_val->data.x_f64 = trunc(op1->data.x_f64 / op2->data.x_f64); - return; - case 80: - extF80M_div(&op1->data.x_f80, &op2->data.x_f80, &out_val->data.x_f80); - extF80M_roundToInt(&out_val->data.x_f80, softfloat_round_minMag, false, &out_val->data.x_f80); - return; - case 128: - f128M_div(&op1->data.x_f128, &op2->data.x_f128, &out_val->data.x_f128); - f128M_roundToInt(&out_val->data.x_f128, softfloat_round_minMag, false, &out_val->data.x_f128); - return; - default: - zig_unreachable(); - } - } else { - zig_unreachable(); - } -} - -static void float_div_floor(ZigValue *out_val, ZigValue *op1, ZigValue *op2) { - assert(op1->type == op2->type); - out_val->type = op1->type; - if (op1->type->id == ZigTypeIdComptimeFloat) { - bigfloat_div_floor(&out_val->data.x_bigfloat, &op1->data.x_bigfloat, &op2->data.x_bigfloat); - } else if (op1->type->id == ZigTypeIdFloat) { - switch (op1->type->data.floating.bit_count) { - case 16: - out_val->data.x_f16 = f16_div(op1->data.x_f16, op2->data.x_f16); - out_val->data.x_f16 = f16_roundToInt(out_val->data.x_f16, softfloat_round_min, false); - return; - case 32: - out_val->data.x_f32 = floorf(op1->data.x_f32 / op2->data.x_f32); - return; - case 64: - out_val->data.x_f64 = floor(op1->data.x_f64 / op2->data.x_f64); - return; - case 80: - extF80M_div(&op1->data.x_f80, &op2->data.x_f80, &out_val->data.x_f80); - extF80M_roundToInt(&out_val->data.x_f80, softfloat_round_min, false, &out_val->data.x_f80); - return; - case 128: - f128M_div(&op1->data.x_f128, &op2->data.x_f128, &out_val->data.x_f128); - f128M_roundToInt(&out_val->data.x_f128, softfloat_round_min, false, &out_val->data.x_f128); - return; - default: - zig_unreachable(); - } - } else { - zig_unreachable(); - } -} - -// c = a - b * trunc(a / b) -static float16_t zig_f16_rem(float16_t a, float16_t b) { - float16_t c; - c = f16_div(a, b); - c = f16_roundToInt(c, softfloat_round_minMag, false); - c = f16_mul(b, c); - c = f16_sub(a, c); - return c; -} - -// c = a - b * trunc(a / b) -static void zig_f128M_rem(const float128_t* a, const float128_t* b, float128_t* c) { - f128M_div(a, b, c); - f128M_roundToInt(c, softfloat_round_minMag, false, c); - f128M_mul(b, c, c); - f128M_sub(a, c, c); -} - -// c = a - b * trunc(a / b) -static void zig_extF80M_rem(const extFloat80_t* a, const extFloat80_t* b, extFloat80_t* c) { - extF80M_div(a, b, c); - extF80M_roundToInt(c, softfloat_round_minMag, false, c); - extF80M_mul(b, c, c); - extF80M_sub(a, c, c); -} - -static void float_rem(ZigValue *out_val, ZigValue *op1, ZigValue *op2) { - assert(op1->type == op2->type); - out_val->type = op1->type; - if (op1->type->id == ZigTypeIdComptimeFloat) { - bigfloat_rem(&out_val->data.x_bigfloat, &op1->data.x_bigfloat, &op2->data.x_bigfloat); - } else if (op1->type->id == ZigTypeIdFloat) { - switch (op1->type->data.floating.bit_count) { - case 16: - out_val->data.x_f16 = zig_f16_rem(op1->data.x_f16, op2->data.x_f16); - return; - case 32: - out_val->data.x_f32 = fmodf(op1->data.x_f32, op2->data.x_f32); - return; - case 64: - out_val->data.x_f64 = fmod(op1->data.x_f64, op2->data.x_f64); - return; - case 80: - zig_extF80M_rem(&op1->data.x_f80, &op2->data.x_f80, &out_val->data.x_f80); - return; - case 128: - zig_f128M_rem(&op1->data.x_f128, &op2->data.x_f128, &out_val->data.x_f128); - return; - default: - zig_unreachable(); - } - } else { - zig_unreachable(); - } -} - -// c = a - b * trunc(a / b) -static float16_t zig_f16_mod(float16_t a, float16_t b) { - float16_t c; - c = f16_div(a, b); - c = f16_roundToInt(c, softfloat_round_min, true); - c = f16_mul(b, c); - c = f16_sub(a, c); - return c; -} - -// c = a - b * trunc(a / b) -static void zig_f128M_mod(const float128_t* a, const float128_t* b, float128_t* c) { - f128M_div(a, b, c); - f128M_roundToInt(c, softfloat_round_min, true, c); - f128M_mul(b, c, c); - f128M_sub(a, c, c); -} - -// c = a - b * trunc(a / b) -static void zig_extF80M_mod(const extFloat80_t* a, const extFloat80_t* b, extFloat80_t* c) { - extF80M_div(a, b, c); - extF80M_roundToInt(c, softfloat_round_min, true, c); - extF80M_mul(b, c, c); - extF80M_sub(a, c, c); -} - -static void float_mod(ZigValue *out_val, ZigValue *op1, ZigValue *op2) { - assert(op1->type == op2->type); - out_val->type = op1->type; - if (op1->type->id == ZigTypeIdComptimeFloat) { - bigfloat_mod(&out_val->data.x_bigfloat, &op1->data.x_bigfloat, &op2->data.x_bigfloat); - } else if (op1->type->id == ZigTypeIdFloat) { - switch (op1->type->data.floating.bit_count) { - case 16: - out_val->data.x_f16 = zig_f16_mod(op1->data.x_f16, op2->data.x_f16); - return; - case 32: - out_val->data.x_f32 = fmodf(fmodf(op1->data.x_f32, op2->data.x_f32) + op2->data.x_f32, op2->data.x_f32); - return; - case 64: - out_val->data.x_f64 = fmod(fmod(op1->data.x_f64, op2->data.x_f64) + op2->data.x_f64, op2->data.x_f64); - return; - case 80: - zig_extF80M_mod(&op1->data.x_f80, &op2->data.x_f80, &out_val->data.x_f80); - return; - case 128: - zig_f128M_mod(&op1->data.x_f128, &op2->data.x_f128, &out_val->data.x_f128); - return; - default: - zig_unreachable(); - } - } else { - zig_unreachable(); - } -} - -static void float_max(ZigValue *out_val, ZigValue *op1, ZigValue *op2) { - assert(op1->type == op2->type); - out_val->type = op1->type; - if (op1->type->id == ZigTypeIdComptimeFloat) { - bigfloat_max(&out_val->data.x_bigfloat, &op1->data.x_bigfloat, &op2->data.x_bigfloat); - } else if (op1->type->id == ZigTypeIdFloat) { - switch (op1->type->data.floating.bit_count) { - case 16: - if (zig_f16_isNaN(op1->data.x_f16)) { - out_val->data.x_f16 = op2->data.x_f16; - } else if (zig_f16_isNaN(op2->data.x_f16)) { - out_val->data.x_f16 = op1->data.x_f16; - } else { - out_val->data.x_f16 = f16_lt(op1->data.x_f16, op2->data.x_f16) ? op2->data.x_f16 : op1->data.x_f16; - } - return; - case 32: - if (op1->data.x_f32 != op1->data.x_f32) { - out_val->data.x_f32 = op2->data.x_f32; - } else if (op2->data.x_f32 != op2->data.x_f32) { - out_val->data.x_f32 = op1->data.x_f32; - } else { - out_val->data.x_f32 = op1->data.x_f32 > op2->data.x_f32 ? op1->data.x_f32 : op2->data.x_f32; - } - return; - case 64: - if (op1->data.x_f64 != op1->data.x_f64) { - out_val->data.x_f64 = op2->data.x_f64; - } else if (op2->data.x_f64 != op2->data.x_f64) { - out_val->data.x_f64 = op1->data.x_f64; - } else { - out_val->data.x_f64 = op1->data.x_f64 > op2->data.x_f64 ? op1->data.x_f64 : op2->data.x_f64; - } - return; - case 80: - if (zig_extF80_isNaN(&op1->data.x_f80)) { - out_val->data.x_f80 = op2->data.x_f80; - } else if (zig_extF80_isNaN(&op2->data.x_f80)) { - out_val->data.x_f80 = op1->data.x_f80; - } else { - out_val->data.x_f80 = extF80M_lt(&op1->data.x_f80, &op2->data.x_f80) ? op2->data.x_f80 : op1->data.x_f80; - } - return; - case 128: - if (zig_f128_isNaN(&op1->data.x_f128)) { - out_val->data.x_f128 = op2->data.x_f128; - } else if (zig_f128_isNaN(&op2->data.x_f128)) { - out_val->data.x_f128 = op1->data.x_f128; - } else { - out_val->data.x_f128 = f128M_lt(&op1->data.x_f128, &op2->data.x_f128) ? op2->data.x_f128 : op1->data.x_f128; - } - return; - default: - zig_unreachable(); - } - } else { - zig_unreachable(); - } -} - -static void float_min(ZigValue *out_val, ZigValue *op1, ZigValue *op2) { - assert(op1->type == op2->type); - out_val->type = op1->type; - if (op1->type->id == ZigTypeIdComptimeFloat) { - bigfloat_min(&out_val->data.x_bigfloat, &op1->data.x_bigfloat, &op2->data.x_bigfloat); - } else if (op1->type->id == ZigTypeIdFloat) { - switch (op1->type->data.floating.bit_count) { - case 16: - if (zig_f16_isNaN(op1->data.x_f16)) { - out_val->data.x_f16 = op2->data.x_f16; - } else if (zig_f16_isNaN(op2->data.x_f16)) { - out_val->data.x_f16 = op1->data.x_f16; - } else { - out_val->data.x_f16 = f16_lt(op1->data.x_f16, op2->data.x_f16) ? op1->data.x_f16 : op2->data.x_f16; - } - return; - case 32: - if (op1->data.x_f32 != op1->data.x_f32) { - out_val->data.x_f32 = op2->data.x_f32; - } else if (op2->data.x_f32 != op2->data.x_f32) { - out_val->data.x_f32 = op1->data.x_f32; - } else { - out_val->data.x_f32 = op1->data.x_f32 < op2->data.x_f32 ? op1->data.x_f32 : op2->data.x_f32; - } - return; - case 64: - if (op1->data.x_f64 != op1->data.x_f64) { - out_val->data.x_f64 = op2->data.x_f64; - } else if (op2->data.x_f64 != op2->data.x_f64) { - out_val->data.x_f64 = op1->data.x_f64; - } else { - out_val->data.x_f64 = op1->data.x_f32 < op2->data.x_f64 ? op1->data.x_f64 : op2->data.x_f64; - } - return; - case 80: - if (zig_extF80_isNaN(&op1->data.x_f80)) { - out_val->data.x_f80 = op2->data.x_f80; - } else if (zig_extF80_isNaN(&op2->data.x_f80)) { - out_val->data.x_f80 = op1->data.x_f80; - } else { - out_val->data.x_f80 = extF80M_lt(&op1->data.x_f80, &op2->data.x_f80) ? op1->data.x_f80 : op2->data.x_f80; - } - return; - case 128: - if (zig_f128_isNaN(&op1->data.x_f128)) { - out_val->data.x_f128 = op2->data.x_f128; - } else if (zig_f128_isNaN(&op2->data.x_f128)) { - out_val->data.x_f128 = op1->data.x_f128; - } else { - out_val->data.x_f128 = f128M_lt(&op1->data.x_f128, &op2->data.x_f128) ? op1->data.x_f128 : op2->data.x_f128; - } - return; - default: - zig_unreachable(); - } - } else { - zig_unreachable(); - } -} - -static void float_negate(ZigValue *out_val, ZigValue *op) { - out_val->type = op->type; - if (op->type->id == ZigTypeIdComptimeFloat) { - bigfloat_negate(&out_val->data.x_bigfloat, &op->data.x_bigfloat); - } else if (op->type->id == ZigTypeIdFloat) { - switch (op->type->data.floating.bit_count) { - case 16: - out_val->data.x_f16 = f16_neg(op->data.x_f16); - return; - case 32: - out_val->data.x_f32 = -op->data.x_f32; - return; - case 64: - out_val->data.x_f64 = -op->data.x_f64; - return; - case 80: - extF80M_neg(&op->data.x_f80, &out_val->data.x_f80); - return; - case 128: - f128M_neg(&op->data.x_f128, &out_val->data.x_f128); - return; - default: - zig_unreachable(); - } - } else { - zig_unreachable(); - } -} - -void float_write_ieee597(ZigValue *op, uint8_t *buf, bool target_is_big_endian) { - if (op->type->id != ZigTypeIdFloat) - zig_unreachable(); - - const unsigned n = op->type->data.floating.bit_count / 8; - assert(n <= 16); - - switch (op->type->data.floating.bit_count) { - case 16: - memcpy(buf, &op->data.x_f16, 2); - break; - case 32: - memcpy(buf, &op->data.x_f32, 4); - break; - case 64: - memcpy(buf, &op->data.x_f64, 8); - break; - case 80: - memcpy(buf, &op->data.x_f80, 16); - break; - case 128: - memcpy(buf, &op->data.x_f128, 16); - break; - default: - zig_unreachable(); - } - - // Byteswap if system endianness != target endianness - if (native_is_big_endian != target_is_big_endian) { - for (size_t i = 0; i < n / 2; i++) { - uint8_t u = buf[i]; - buf[i] = buf[n - 1 - i]; - buf[n - 1 - i] = u; - } - } -} - -void float_read_ieee597(ZigValue *val, uint8_t *buf, bool target_is_big_endian) { - if (val->type->id != ZigTypeIdFloat) - zig_unreachable(); - - const unsigned n = val->type->data.floating.bit_count / 8; - assert(n <= 16); - - uint8_t tmp[16]; - uint8_t *ptr = buf; - - // Byteswap if system endianness != target endianness - if (native_is_big_endian != target_is_big_endian) { - memcpy(tmp, buf, n); - for (size_t i = 0; i < n / 2; i++) { - uint8_t u = tmp[i]; - tmp[i] = tmp[n - 1 - i]; - tmp[n - 1 - i] = u; - } - - ptr = tmp; - } - - switch (val->type->data.floating.bit_count) { - case 16: - memcpy(&val->data.x_f16, ptr, 2); - return; - case 32: - memcpy(&val->data.x_f32, ptr, 4); - return; - case 64: - memcpy(&val->data.x_f64, ptr, 8); - return; - case 80: - memcpy(&val->data.x_f80, ptr, 16); - return; - case 128: - memcpy(&val->data.x_f128, ptr, 16); - return; - default: - zig_unreachable(); - } -} - -static void value_to_bigfloat(BigFloat *out, ZigValue *val) { - switch (val->type->id) { - case ZigTypeIdInt: - case ZigTypeIdComptimeInt: - bigfloat_init_bigint(out, &val->data.x_bigint); - return; - case ZigTypeIdComptimeFloat: - *out = val->data.x_bigfloat; - return; - case ZigTypeIdFloat: switch (val->type->data.floating.bit_count) { - case 16: - bigfloat_init_16(out, val->data.x_f16); - return; - case 32: - bigfloat_init_32(out, val->data.x_f32); - return; - case 64: - bigfloat_init_64(out, val->data.x_f64); - return; - case 80: { - float128_t f128_value; - extF80M_to_f128M(&val->data.x_f80, &f128_value); - bigfloat_init_128(out, f128_value); - return; - } - case 128: - bigfloat_init_128(out, val->data.x_f128); - return; - default: - zig_unreachable(); - } - default: - zig_unreachable(); - } -} - -static bool ir_num_lit_fits_in_other_type(IrAnalyze *ira, Stage1AirInst *instruction, ZigType *other_type, - bool explicit_cast) -{ - if (type_is_invalid(other_type)) { - return false; - } - - ZigValue *const_val = ir_resolve_const(ira, instruction, LazyOkNoUndef); - if (const_val == nullptr) - return false; - - if (const_val->special == ConstValSpecialLazy) { - switch (const_val->data.x_lazy->id) { - case LazyValueIdAlignOf: { - // This is guaranteed to fit into a u29 - if (other_type->id == ZigTypeIdComptimeInt) - return true; - size_t align_bits = get_align_amt_type(ira->codegen)->data.integral.bit_count; - if (other_type->id == ZigTypeIdInt && !other_type->data.integral.is_signed && - other_type->data.integral.bit_count >= align_bits) - { - return true; - } - break; - } - case LazyValueIdSizeOf: { - // This is guaranteed to fit into a usize - if (other_type->id == ZigTypeIdComptimeInt) - return true; - size_t usize_bits = ira->codegen->builtin_types.entry_usize->data.integral.bit_count; - if (other_type->id == ZigTypeIdInt && !other_type->data.integral.is_signed && - other_type->data.integral.bit_count >= usize_bits) - { - return true; - } - break; - } - default: - break; - } - } - - const_val = ir_resolve_const(ira, instruction, UndefBad); - if (const_val == nullptr) - return false; - - bool const_val_is_int = (const_val->type->id == ZigTypeIdInt || const_val->type->id == ZigTypeIdComptimeInt); - bool const_val_is_float = (const_val->type->id == ZigTypeIdFloat || const_val->type->id == ZigTypeIdComptimeFloat); - assert(const_val_is_int || const_val_is_float); - - if (const_val_is_int && other_type->id == ZigTypeIdComptimeFloat) { - return true; - } - if (other_type->id == ZigTypeIdFloat) { - if (const_val->type->id == ZigTypeIdComptimeInt || const_val->type->id == ZigTypeIdComptimeFloat) { - return true; - } - if (const_val->type->id == ZigTypeIdInt) { - BigFloat tmp_bf; - bigfloat_init_bigint(&tmp_bf, &const_val->data.x_bigint); - BigFloat orig_bf; - switch (other_type->data.floating.bit_count) { - case 16: { - float16_t tmp = bigfloat_to_f16(&tmp_bf); - bigfloat_init_16(&orig_bf, tmp); - break; - } - case 32: { - float tmp = bigfloat_to_f32(&tmp_bf); - bigfloat_init_32(&orig_bf, tmp); - break; - } - case 64: { - double tmp = bigfloat_to_f64(&tmp_bf); - bigfloat_init_64(&orig_bf, tmp); - break; - } - case 80: { - float128_t tmp = bigfloat_to_f128(&tmp_bf); - extFloat80_t tmp80; - f128M_to_extF80M(&tmp, &tmp80); - extF80M_to_f128M(&tmp80, &tmp); - bigfloat_init_128(&orig_bf, tmp); - break; - } - case 128: { - float128_t tmp = bigfloat_to_f128(&tmp_bf); - bigfloat_init_128(&orig_bf, tmp); - break; - } - default: - zig_unreachable(); - } - BigInt orig_bi; - bigint_init_bigfloat(&orig_bi, &orig_bf); - if (bigint_cmp(&orig_bi, &const_val->data.x_bigint) == CmpEQ) { - return true; - } - Buf *val_buf = buf_alloc(); - bigint_append_buf(val_buf, &const_val->data.x_bigint, 10); - ir_add_error_node(ira, instruction->source_node, - buf_sprintf("type %s cannot represent integer value %s", - buf_ptr(&other_type->name), - buf_ptr(val_buf))); - return false; - } - if (other_type->data.floating.bit_count >= const_val->type->data.floating.bit_count) { - return true; - } - switch (other_type->data.floating.bit_count) { - case 16: - switch (const_val->type->data.floating.bit_count) { - case 32: { - float16_t tmp = zig_double_to_f16(const_val->data.x_f32); - float orig = zig_f16_to_double(tmp); - if (const_val->data.x_f32 == orig) { - return true; - } - break; - } - case 64: { - float16_t tmp = zig_double_to_f16(const_val->data.x_f64); - double orig = zig_f16_to_double(tmp); - if (const_val->data.x_f64 == orig) { - return true; - } - break; - } - case 80: { - float16_t tmp = extF80M_to_f16(&const_val->data.x_f80); - extFloat80_t orig; - f16_to_extF80M(tmp, &orig); - if (extF80M_eq(&orig, &const_val->data.x_f80)) { - return true; - } - break; - } - case 128: { - float16_t tmp = f128M_to_f16(&const_val->data.x_f128); - float128_t orig; - f16_to_f128M(tmp, &orig); - if (f128M_eq(&orig, &const_val->data.x_f128)) { - return true; - } - break; - } - default: - zig_unreachable(); - } - break; - case 32: - switch (const_val->type->data.floating.bit_count) { - case 64: { - float tmp = const_val->data.x_f64; - double orig = tmp; - if (const_val->data.x_f64 == orig) { - return true; - } - break; - } - case 80: { - float32_t tmp = extF80M_to_f32(&const_val->data.x_f80); - extFloat80_t orig; - f32_to_extF80M(tmp, &orig); - if (extF80M_eq(&orig, &const_val->data.x_f80)) { - return true; - } - break; - } - case 128: { - float32_t tmp = f128M_to_f32(&const_val->data.x_f128); - float128_t orig; - f32_to_f128M(tmp, &orig); - if (f128M_eq(&orig, &const_val->data.x_f128)) { - return true; - } - break; - } - default: - zig_unreachable(); - } - break; - case 64: - switch (const_val->type->data.floating.bit_count) { - case 80: { - float64_t tmp = extF80M_to_f64(&const_val->data.x_f80); - extFloat80_t orig; - f64_to_extF80M(tmp, &orig); - if (extF80M_eq(&orig, &const_val->data.x_f80)) { - return true; - } - break; - } - case 128: { - float64_t tmp = f128M_to_f64(&const_val->data.x_f128); - float128_t orig; - f64_to_f128M(tmp, &orig); - if (f128M_eq(&orig, &const_val->data.x_f128)) { - return true; - } - break; - } - default: - zig_unreachable(); - } - break; - case 80: { - assert(const_val->type->data.floating.bit_count == 128); - extFloat80_t tmp; - f128M_to_extF80M(&const_val->data.x_f128, &tmp); - float128_t orig; - extF80M_to_f128M(&tmp, &orig); - if (f128M_eq(&orig, &const_val->data.x_f128)) { - return true; - } - break; - } - case 128: - return true; - default: - zig_unreachable(); - } - Buf *val_buf = buf_alloc(); - float_append_buf(val_buf, const_val); - ir_add_error_node(ira, instruction->source_node, - buf_sprintf("cast of value %s to type '%s' loses information", - buf_ptr(val_buf), - buf_ptr(&other_type->name))); - return false; - } else if (other_type->id == ZigTypeIdInt && const_val_is_int) { - if (!other_type->data.integral.is_signed && const_val->data.x_bigint.is_negative) { - Buf *val_buf = buf_alloc(); - bigint_append_buf(val_buf, &const_val->data.x_bigint, 10); - ir_add_error_node(ira, instruction->source_node, - buf_sprintf("cannot cast negative value %s to unsigned integer type '%s'", - buf_ptr(val_buf), - buf_ptr(&other_type->name))); - return false; - } - if (bigint_fits_in_bits(&const_val->data.x_bigint, other_type->data.integral.bit_count, - other_type->data.integral.is_signed)) - { - return true; - } - } else if (const_val_fits_in_num_lit(const_val, other_type)) { - return true; - } else if (other_type->id == ZigTypeIdOptional) { - ZigType *child_type = other_type->data.maybe.child_type; - if (const_val_fits_in_num_lit(const_val, child_type)) { - return true; - } else if (child_type->id == ZigTypeIdInt && const_val_is_int) { - if (!child_type->data.integral.is_signed && const_val->data.x_bigint.is_negative) { - Buf *val_buf = buf_alloc(); - bigint_append_buf(val_buf, &const_val->data.x_bigint, 10); - ir_add_error_node(ira, instruction->source_node, - buf_sprintf("cannot cast negative value %s to unsigned integer type '%s'", - buf_ptr(val_buf), - buf_ptr(&child_type->name))); - return false; - } - if (bigint_fits_in_bits(&const_val->data.x_bigint, - child_type->data.integral.bit_count, - child_type->data.integral.is_signed)) - { - return true; - } - } else if (child_type->id == ZigTypeIdFloat && const_val_is_float) { - return true; - } - } - if (explicit_cast && (other_type->id == ZigTypeIdInt || other_type->id == ZigTypeIdComptimeInt) && - const_val_is_float) - { - if (float_has_fraction(const_val)) { - Buf *val_buf = buf_alloc(); - float_append_buf(val_buf, const_val); - - ir_add_error_node(ira, instruction->source_node, - buf_sprintf("fractional component prevents float value %s from being casted to type '%s'", - buf_ptr(val_buf), - buf_ptr(&other_type->name))); - return false; - } else { - if (other_type->id == ZigTypeIdComptimeInt) { - return true; - } else { - BigInt bigint; - float_init_bigint(&bigint, const_val); - if (bigint_fits_in_bits(&bigint, other_type->data.integral.bit_count, - other_type->data.integral.is_signed)) - { - return true; - } - } - } - } - - const char *num_lit_str; - Buf *val_buf = buf_alloc(); - if (const_val_is_float) { - num_lit_str = "float"; - float_append_buf(val_buf, const_val); - } else { - num_lit_str = "integer"; - bigint_append_buf(val_buf, &const_val->data.x_bigint, 10); - } - - ir_add_error_node(ira, instruction->source_node, - buf_sprintf("%s value %s cannot be coerced to type '%s'", - num_lit_str, - buf_ptr(val_buf), - buf_ptr(&other_type->name))); - return false; -} - -static bool is_tagged_union(ZigType *type) { - if (type->id != ZigTypeIdUnion) - return false; - return (type->data.unionation.decl_node->data.container_decl.auto_enum || - type->data.unionation.decl_node->data.container_decl.init_arg_expr != nullptr); -} - -static void populate_error_set_table(ErrorTableEntry **errors, ZigType *set) { - assert(set->id == ZigTypeIdErrorSet); - for (uint32_t i = 0; i < set->data.error_set.err_count; i += 1) { - ErrorTableEntry *error_entry = set->data.error_set.errors[i]; - assert(errors[error_entry->value] == nullptr); - errors[error_entry->value] = error_entry; - } -} - -static ErrorTableEntry *better_documented_error(ErrorTableEntry *preferred, ErrorTableEntry *other) { - if (preferred->decl_node->type == NodeTypeErrorSetField) - return preferred; - if (other->decl_node->type == NodeTypeErrorSetField) - return other; - return preferred; -} - -static ZigType *get_error_set_intersection(IrAnalyze *ira, ZigType *set1, ZigType *set2, - AstNode *source_node) -{ - assert(set1->id == ZigTypeIdErrorSet); - assert(set2->id == ZigTypeIdErrorSet); - - if (!resolve_inferred_error_set(ira->codegen, set1, source_node)) { - return ira->codegen->builtin_types.entry_invalid; - } - if (!resolve_inferred_error_set(ira->codegen, set2, source_node)) { - return ira->codegen->builtin_types.entry_invalid; - } - if (type_is_global_error_set(set1)) { - return set2; - } - if (type_is_global_error_set(set2)) { - return set1; - } - size_t errors_count = ira->codegen->errors_by_index.length; - ErrorTableEntry **errors = heap::c_allocator.allocate(errors_count); - populate_error_set_table(errors, set1); - ZigList intersection_list = {}; - - ZigType *err_set_type = new_type_table_entry(ZigTypeIdErrorSet); - buf_resize(&err_set_type->name, 0); - buf_appendf(&err_set_type->name, "error{"); - - bool need_comma = false; - for (uint32_t i = 0; i < set2->data.error_set.err_count; i += 1) { - ErrorTableEntry *error_entry = set2->data.error_set.errors[i]; - ErrorTableEntry *existing_entry = errors[error_entry->value]; - if (existing_entry != nullptr) { - // prefer the one with docs - const char *comma = need_comma ? "," : ""; - need_comma = true; - ErrorTableEntry *existing_entry_with_docs = better_documented_error(existing_entry, error_entry); - intersection_list.append(existing_entry_with_docs); - buf_appendf(&err_set_type->name, "%s%s", comma, buf_ptr(&existing_entry_with_docs->name)); - } - } - heap::c_allocator.deallocate(errors, errors_count); - - err_set_type->data.error_set.err_count = intersection_list.length; - err_set_type->data.error_set.errors = intersection_list.items; - err_set_type->size_in_bits = ira->codegen->builtin_types.entry_global_error_set->size_in_bits; - err_set_type->abi_align = ira->codegen->builtin_types.entry_global_error_set->abi_align; - err_set_type->abi_size = ira->codegen->builtin_types.entry_global_error_set->abi_size; - - buf_appendf(&err_set_type->name, "}"); - - return err_set_type; -} - -static ConstCastOnly types_match_const_cast_only(IrAnalyze *ira, ZigType *wanted_type, - ZigType *actual_type, AstNode *source_node, bool wanted_is_mutable) -{ - CodeGen *g = ira->codegen; - ConstCastOnly result = {}; - result.id = ConstCastResultIdOk; - - Error err; - - if (wanted_type == actual_type) - return result; - - // If pointers have the same representation in memory, they can be "const-casted". - // `const` attribute can be gained - // `volatile` attribute can be gained - // `allowzero` attribute can be gained (whether from explicit attribute, C pointer, or optional pointer) - // but only if !wanted_is_mutable - // alignment can be decreased - // bit offset attributes must match exactly - // PtrLenSingle/PtrLenUnknown must match exactly, but PtrLenC matches either one - // sentinel-terminated pointers can coerce into PtrLenUnknown - ZigType *wanted_ptr_type = get_src_ptr_type(wanted_type); - ZigType *actual_ptr_type = get_src_ptr_type(actual_type); - bool wanted_allows_zero = ptr_allows_addr_zero(wanted_type); - bool actual_allows_zero = ptr_allows_addr_zero(actual_type); - bool wanted_is_c_ptr = wanted_type->id == ZigTypeIdPointer && wanted_type->data.pointer.ptr_len == PtrLenC; - bool actual_is_c_ptr = actual_type->id == ZigTypeIdPointer && actual_type->data.pointer.ptr_len == PtrLenC; - bool wanted_opt_or_ptr = wanted_ptr_type != nullptr && wanted_ptr_type->id == ZigTypeIdPointer; - bool actual_opt_or_ptr = actual_ptr_type != nullptr && actual_ptr_type->id == ZigTypeIdPointer; - if (wanted_opt_or_ptr && actual_opt_or_ptr) { - bool ok_null_term_ptrs = - wanted_ptr_type->data.pointer.sentinel == nullptr || - (actual_ptr_type->data.pointer.sentinel != nullptr && - const_values_equal(ira->codegen, wanted_ptr_type->data.pointer.sentinel, - actual_ptr_type->data.pointer.sentinel)) || - actual_ptr_type->data.pointer.ptr_len == PtrLenC; - if (!ok_null_term_ptrs) { - result.id = ConstCastResultIdPtrSentinel; - result.data.bad_ptr_sentinel = heap::c_allocator.allocate_nonzero(1); - result.data.bad_ptr_sentinel->wanted_type = wanted_ptr_type; - result.data.bad_ptr_sentinel->actual_type = actual_ptr_type; - return result; - } - bool ptr_lens_equal = actual_ptr_type->data.pointer.ptr_len == wanted_ptr_type->data.pointer.ptr_len; - if (!(ptr_lens_equal || wanted_is_c_ptr || actual_is_c_ptr)) { - result.id = ConstCastResultIdPtrLens; - return result; - } - - bool ok_cv_qualifiers = - (!actual_ptr_type->data.pointer.is_const || wanted_ptr_type->data.pointer.is_const) && - (!actual_ptr_type->data.pointer.is_volatile || wanted_ptr_type->data.pointer.is_volatile); - if (!ok_cv_qualifiers) { - result.id = ConstCastResultIdCV; - result.data.bad_cv = heap::c_allocator.allocate_nonzero(1); - result.data.bad_cv->wanted_type = wanted_ptr_type; - result.data.bad_cv->actual_type = actual_ptr_type; - return result; - } - - ConstCastOnly child = types_match_const_cast_only(ira, wanted_ptr_type->data.pointer.child_type, - actual_ptr_type->data.pointer.child_type, source_node, !wanted_ptr_type->data.pointer.is_const); - if (child.id == ConstCastResultIdInvalid) - return child; - if (child.id != ConstCastResultIdOk) { - result.id = ConstCastResultIdPointerChild; - result.data.pointer_mismatch = heap::c_allocator.allocate_nonzero(1); - result.data.pointer_mismatch->child = child; - result.data.pointer_mismatch->wanted_child = wanted_ptr_type->data.pointer.child_type; - result.data.pointer_mismatch->actual_child = actual_ptr_type->data.pointer.child_type; - return result; - } - bool ok_allows_zero = (wanted_allows_zero && - (actual_allows_zero || !wanted_is_mutable)) || - (!wanted_allows_zero && !actual_allows_zero); - if (!ok_allows_zero) { - result.id = ConstCastResultIdBadAllowsZero; - result.data.bad_allows_zero = heap::c_allocator.allocate_nonzero(1); - result.data.bad_allows_zero->wanted_type = wanted_type; - result.data.bad_allows_zero->actual_type = actual_type; - return result; - } - if ((err = type_resolve(g, actual_ptr_type->data.pointer.child_type, ResolveStatusAlignmentKnown))) { - result.id = ConstCastResultIdInvalid; - return result; - } - if ((err = type_resolve(g, wanted_ptr_type->data.pointer.child_type, ResolveStatusAlignmentKnown))) { - result.id = ConstCastResultIdInvalid; - return result; - } - if ((err = type_resolve(g, wanted_type, ResolveStatusZeroBitsKnown))) { - result.id = ConstCastResultIdInvalid; - return result; - } - if ((err = type_resolve(g, actual_type, ResolveStatusZeroBitsKnown))) { - result.id = ConstCastResultIdInvalid; - return result; - } - if (type_has_bits(g, wanted_type) == type_has_bits(g, actual_type) && - actual_ptr_type->data.pointer.bit_offset_in_host == wanted_ptr_type->data.pointer.bit_offset_in_host && - actual_ptr_type->data.pointer.host_int_bytes == wanted_ptr_type->data.pointer.host_int_bytes && - get_ptr_align(ira->codegen, actual_ptr_type) >= get_ptr_align(ira->codegen, wanted_ptr_type)) - { - return result; - } - } - - // arrays - if (wanted_type->id == ZigTypeIdArray && actual_type->id == ZigTypeIdArray && - wanted_type->data.array.len == actual_type->data.array.len) - { - ConstCastOnly child = types_match_const_cast_only(ira, wanted_type->data.array.child_type, - actual_type->data.array.child_type, source_node, wanted_is_mutable); - if (child.id == ConstCastResultIdInvalid) - return child; - if (child.id != ConstCastResultIdOk) { - result.id = ConstCastResultIdArrayChild; - result.data.array_mismatch = heap::c_allocator.allocate_nonzero(1); - result.data.array_mismatch->child = child; - result.data.array_mismatch->wanted_child = wanted_type->data.array.child_type; - result.data.array_mismatch->actual_child = actual_type->data.array.child_type; - return result; - } - bool ok_null_terminated = (wanted_type->data.array.sentinel == nullptr) || - (actual_type->data.array.sentinel != nullptr && - const_values_equal(ira->codegen, wanted_type->data.array.sentinel, actual_type->data.array.sentinel)); - if (!ok_null_terminated) { - result.id = ConstCastResultIdSentinelArrays; - result.data.sentinel_arrays = heap::c_allocator.allocate_nonzero(1); - result.data.sentinel_arrays->child = child; - result.data.sentinel_arrays->wanted_type = wanted_type; - result.data.sentinel_arrays->actual_type = actual_type; - return result; - } - return result; - } - - // slice const - if (is_slice(wanted_type) && is_slice(actual_type)) { - ZigType *actual_ptr_type = actual_type->data.structure.fields[slice_ptr_index]->type_entry; - ZigType *wanted_ptr_type = wanted_type->data.structure.fields[slice_ptr_index]->type_entry; - if ((err = type_resolve(g, actual_ptr_type->data.pointer.child_type, ResolveStatusAlignmentKnown))) { - result.id = ConstCastResultIdInvalid; - return result; - } - if ((err = type_resolve(g, wanted_ptr_type->data.pointer.child_type, ResolveStatusAlignmentKnown))) { - result.id = ConstCastResultIdInvalid; - return result; - } - bool ok_sentinels = - wanted_ptr_type->data.pointer.sentinel == nullptr || - (actual_ptr_type->data.pointer.sentinel != nullptr && - const_values_equal(ira->codegen, wanted_ptr_type->data.pointer.sentinel, - actual_ptr_type->data.pointer.sentinel)); - if (!ok_sentinels) { - result.id = ConstCastResultIdPtrSentinel; - result.data.bad_ptr_sentinel = heap::c_allocator.allocate_nonzero(1); - result.data.bad_ptr_sentinel->wanted_type = wanted_ptr_type; - result.data.bad_ptr_sentinel->actual_type = actual_ptr_type; - return result; - } - if ((!actual_ptr_type->data.pointer.is_const || wanted_ptr_type->data.pointer.is_const) && - (!actual_ptr_type->data.pointer.is_volatile || wanted_ptr_type->data.pointer.is_volatile) && - actual_ptr_type->data.pointer.bit_offset_in_host == wanted_ptr_type->data.pointer.bit_offset_in_host && - actual_ptr_type->data.pointer.host_int_bytes == wanted_ptr_type->data.pointer.host_int_bytes && - get_ptr_align(g, actual_ptr_type) >= get_ptr_align(g, wanted_ptr_type)) - { - ConstCastOnly child = types_match_const_cast_only(ira, wanted_ptr_type->data.pointer.child_type, - actual_ptr_type->data.pointer.child_type, source_node, !wanted_ptr_type->data.pointer.is_const); - if (child.id == ConstCastResultIdInvalid) - return child; - if (child.id != ConstCastResultIdOk) { - result.id = ConstCastResultIdSliceChild; - result.data.slice_mismatch = heap::c_allocator.allocate_nonzero(1); - result.data.slice_mismatch->child = child; - result.data.slice_mismatch->actual_child = actual_ptr_type->data.pointer.child_type; - result.data.slice_mismatch->wanted_child = wanted_ptr_type->data.pointer.child_type; - } - return result; - } - } - - // optional types - if (wanted_type->id == ZigTypeIdOptional && actual_type->id == ZigTypeIdOptional) { - // Consider the case where the wanted type is ??[*]T and the actual one - // is ?[*]T, we cannot turn the former into the latter even though the - // child types are compatible (?[*]T and [*]T are both represented as a - // pointer). The extra level of indirection in ??[*]T means it's - // represented as a regular, fat, optional type and, as a consequence, - // has a different shape than the one of ?[*]T. - if ((wanted_ptr_type != nullptr) != (actual_ptr_type != nullptr)) { - // The use of type_mismatch is intentional - result.id = ConstCastResultIdOptionalShape; - result.data.type_mismatch = heap::c_allocator.allocate_nonzero(1); - result.data.type_mismatch->wanted_type = wanted_type; - result.data.type_mismatch->actual_type = actual_type; - return result; - } - ConstCastOnly child = types_match_const_cast_only(ira, wanted_type->data.maybe.child_type, - actual_type->data.maybe.child_type, source_node, wanted_is_mutable); - if (child.id == ConstCastResultIdInvalid) - return child; - if (child.id != ConstCastResultIdOk) { - result.id = ConstCastResultIdOptionalChild; - result.data.optional = heap::c_allocator.allocate_nonzero(1); - result.data.optional->child = child; - result.data.optional->wanted_child = wanted_type->data.maybe.child_type; - result.data.optional->actual_child = actual_type->data.maybe.child_type; - } - return result; - } - - // error union - if (wanted_type->id == ZigTypeIdErrorUnion && actual_type->id == ZigTypeIdErrorUnion) { - ConstCastOnly payload_child = types_match_const_cast_only(ira, wanted_type->data.error_union.payload_type, - actual_type->data.error_union.payload_type, source_node, wanted_is_mutable); - if (payload_child.id == ConstCastResultIdInvalid) - return payload_child; - if (payload_child.id != ConstCastResultIdOk) { - result.id = ConstCastResultIdErrorUnionPayload; - result.data.error_union_payload = heap::c_allocator.allocate_nonzero(1); - result.data.error_union_payload->child = payload_child; - result.data.error_union_payload->wanted_payload = wanted_type->data.error_union.payload_type; - result.data.error_union_payload->actual_payload = actual_type->data.error_union.payload_type; - return result; - } - ConstCastOnly error_set_child = types_match_const_cast_only(ira, wanted_type->data.error_union.err_set_type, - actual_type->data.error_union.err_set_type, source_node, wanted_is_mutable); - if (error_set_child.id == ConstCastResultIdInvalid) - return error_set_child; - if (error_set_child.id != ConstCastResultIdOk) { - result.id = ConstCastResultIdErrorUnionErrorSet; - result.data.error_union_error_set = heap::c_allocator.allocate_nonzero(1); - result.data.error_union_error_set->child = error_set_child; - result.data.error_union_error_set->wanted_err_set = wanted_type->data.error_union.err_set_type; - result.data.error_union_error_set->actual_err_set = actual_type->data.error_union.err_set_type; - return result; - } - return result; - } - - // error set - if (wanted_type->id == ZigTypeIdErrorSet && actual_type->id == ZigTypeIdErrorSet) { - ZigType *contained_set = actual_type; - ZigType *container_set = wanted_type; - - // if the container set is inferred, then this will always work. - if (container_set->data.error_set.infer_fn != nullptr && container_set->data.error_set.incomplete) { - return result; - } - // if the container set is the global one, it will always work. - if (type_is_global_error_set(container_set)) { - return result; - } - - if (!resolve_inferred_error_set(ira->codegen, contained_set, source_node)) { - result.id = ConstCastResultIdUnresolvedInferredErrSet; - return result; - } - - if (type_is_global_error_set(contained_set)) { - result.id = ConstCastResultIdErrSetGlobal; - return result; - } - - size_t errors_count = g->errors_by_index.length; - ErrorTableEntry **errors = heap::c_allocator.allocate(errors_count); - for (uint32_t i = 0; i < container_set->data.error_set.err_count; i += 1) { - ErrorTableEntry *error_entry = container_set->data.error_set.errors[i]; - assert(errors[error_entry->value] == nullptr); - errors[error_entry->value] = error_entry; - } - for (uint32_t i = 0; i < contained_set->data.error_set.err_count; i += 1) { - ErrorTableEntry *contained_error_entry = contained_set->data.error_set.errors[i]; - ErrorTableEntry *error_entry = errors[contained_error_entry->value]; - if (error_entry == nullptr) { - if (result.id == ConstCastResultIdOk) { - result.id = ConstCastResultIdErrSet; - result.data.error_set_mismatch = heap::c_allocator.create(); - } - result.data.error_set_mismatch->missing_errors.append(contained_error_entry); - } - } - heap::c_allocator.deallocate(errors, errors_count); - return result; - } - - // fn - if (wanted_type->id == ZigTypeIdFn && - actual_type->id == ZigTypeIdFn) - { - if (wanted_type->data.fn.fn_type_id.alignment > actual_type->data.fn.fn_type_id.alignment) { - result.id = ConstCastResultIdFnAlign; - return result; - } - if (wanted_type->data.fn.fn_type_id.is_var_args != actual_type->data.fn.fn_type_id.is_var_args) { - result.id = ConstCastResultIdFnVarArgs; - return result; - } - if (wanted_type->data.fn.is_generic != actual_type->data.fn.is_generic) { - result.id = ConstCastResultIdFnIsGeneric; - return result; - } - if (!wanted_type->data.fn.is_generic && - actual_type->data.fn.fn_type_id.return_type->id != ZigTypeIdUnreachable) - { - ConstCastOnly child = types_match_const_cast_only(ira, wanted_type->data.fn.fn_type_id.return_type, - actual_type->data.fn.fn_type_id.return_type, source_node, false); - if (child.id == ConstCastResultIdInvalid) - return child; - if (child.id != ConstCastResultIdOk) { - result.id = ConstCastResultIdFnReturnType; - result.data.return_type = heap::c_allocator.allocate_nonzero(1); - *result.data.return_type = child; - return result; - } - } - if (wanted_type->data.fn.fn_type_id.param_count != actual_type->data.fn.fn_type_id.param_count) { - result.id = ConstCastResultIdFnArgCount; - return result; - } - if (wanted_type->data.fn.fn_type_id.next_param_index != actual_type->data.fn.fn_type_id.next_param_index) { - result.id = ConstCastResultIdFnGenericArgCount; - return result; - } - assert(wanted_type->data.fn.is_generic || - wanted_type->data.fn.fn_type_id.next_param_index == wanted_type->data.fn.fn_type_id.param_count); - for (size_t i = 0; i < wanted_type->data.fn.fn_type_id.param_count; i += 1) { - // note it's reversed for parameters - FnTypeParamInfo *actual_param_info = &actual_type->data.fn.fn_type_id.param_info[i]; - FnTypeParamInfo *expected_param_info = &wanted_type->data.fn.fn_type_id.param_info[i]; - - ConstCastOnly arg_child = types_match_const_cast_only(ira, actual_param_info->type, - expected_param_info->type, source_node, false); - if (arg_child.id == ConstCastResultIdInvalid) - return arg_child; - if (arg_child.id != ConstCastResultIdOk) { - result.id = ConstCastResultIdFnArg; - result.data.fn_arg.arg_index = i; - result.data.fn_arg.actual_param_type = actual_param_info->type; - result.data.fn_arg.expected_param_type = expected_param_info->type; - result.data.fn_arg.child = heap::c_allocator.allocate_nonzero(1); - *result.data.fn_arg.child = arg_child; - return result; - } - - if (expected_param_info->is_noalias != actual_param_info->is_noalias) { - result.id = ConstCastResultIdFnArgNoAlias; - result.data.arg_no_alias.arg_index = i; - return result; - } - } - if (wanted_type->data.fn.fn_type_id.cc != actual_type->data.fn.fn_type_id.cc) { - // ConstCastResultIdFnCC is guaranteed to be the last one reported, meaning everything else is ok. - result.id = ConstCastResultIdFnCC; - return result; - } - return result; - } - - if (wanted_type->id == ZigTypeIdInt && actual_type->id == ZigTypeIdInt) { - if (wanted_type->data.integral.is_signed != actual_type->data.integral.is_signed || - wanted_type->data.integral.bit_count != actual_type->data.integral.bit_count) - { - result.id = ConstCastResultIdIntShorten; - result.data.int_shorten = heap::c_allocator.allocate_nonzero(1); - result.data.int_shorten->wanted_type = wanted_type; - result.data.int_shorten->actual_type = actual_type; - return result; - } - return result; - } - - if (wanted_type->id == ZigTypeIdFloat && actual_type->id == ZigTypeIdFloat) { - if (wanted_type->data.floating.bit_count == actual_type->data.floating.bit_count) { - return result; - } - } - - if (wanted_type->id == ZigTypeIdVector && actual_type->id == ZigTypeIdVector) { - if (actual_type->data.vector.len != wanted_type->data.vector.len) { - result.id = ConstCastResultIdVectorLength; - return result; - } - - ConstCastOnly child = types_match_const_cast_only(ira, wanted_type->data.vector.elem_type, - actual_type->data.vector.elem_type, source_node, false); - if (child.id == ConstCastResultIdInvalid) - return child; - if (child.id != ConstCastResultIdOk) { - result.id = ConstCastResultIdVectorChild; - return result; - } - - return result; - } - - result.id = ConstCastResultIdType; - result.data.type_mismatch = heap::c_allocator.allocate_nonzero(1); - result.data.type_mismatch->wanted_type = wanted_type; - result.data.type_mismatch->actual_type = actual_type; - return result; -} - -static void update_errors_helper(CodeGen *g, ErrorTableEntry ***errors, size_t *errors_count) { - size_t old_errors_count = *errors_count; - *errors_count = g->errors_by_index.length; - *errors = heap::c_allocator.reallocate(*errors, old_errors_count, *errors_count); -} - -static ZigType *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_node, ZigType *expected_type, - Stage1AirInst **instructions, size_t instruction_count) -{ - Error err; - assert(instruction_count >= 1); - Stage1AirInst *prev_inst; - size_t i = 0; - for (;;) { - prev_inst = instructions[i]; - if (type_is_invalid(prev_inst->value->type)) { - return ira->codegen->builtin_types.entry_invalid; - } - if (prev_inst->value->type->id == ZigTypeIdUnreachable) { - i += 1; - if (i == instruction_count) { - return prev_inst->value->type; - } - continue; - } - break; - } - ErrorTableEntry **errors = nullptr; - size_t errors_count = 0; - ZigType *err_set_type = nullptr; - if (prev_inst->value->type->id == ZigTypeIdErrorSet) { - if (!resolve_inferred_error_set(ira->codegen, prev_inst->value->type, prev_inst->source_node)) { - return ira->codegen->builtin_types.entry_invalid; - } - if (type_is_global_error_set(prev_inst->value->type)) { - err_set_type = ira->codegen->builtin_types.entry_global_error_set; - } else { - err_set_type = prev_inst->value->type; - update_errors_helper(ira->codegen, &errors, &errors_count); - - for (uint32_t i = 0; i < err_set_type->data.error_set.err_count; i += 1) { - ErrorTableEntry *error_entry = err_set_type->data.error_set.errors[i]; - assert(errors[error_entry->value] == nullptr); - errors[error_entry->value] = error_entry; - } - } - } - - bool any_are_null = (prev_inst->value->type->id == ZigTypeIdNull); - bool convert_to_const_slice = false; - bool make_the_slice_const = false; - bool make_the_pointer_const = false; - for (; i < instruction_count; i += 1) { - Stage1AirInst *cur_inst = instructions[i]; - ZigType *cur_type = cur_inst->value->type; - ZigType *prev_type = prev_inst->value->type; - - if (type_is_invalid(cur_type)) { - return cur_type; - } - - if (prev_type == cur_type) { - continue; - } - - if (prev_type->id == ZigTypeIdUnreachable) { - prev_inst = cur_inst; - continue; - } - - if (cur_type->id == ZigTypeIdUnreachable) { - continue; - } - - if (prev_type->id == ZigTypeIdErrorSet) { - ir_assert(err_set_type != nullptr, prev_inst); - if (cur_type->id == ZigTypeIdErrorSet) { - if (type_is_global_error_set(err_set_type)) { - continue; - } - bool allow_infer = cur_type->data.error_set.infer_fn != nullptr && - cur_type->data.error_set.infer_fn == ira->fn; - if (!allow_infer && !resolve_inferred_error_set(ira->codegen, cur_type, cur_inst->source_node)) { - return ira->codegen->builtin_types.entry_invalid; - } - if (!allow_infer && type_is_global_error_set(cur_type)) { - err_set_type = ira->codegen->builtin_types.entry_global_error_set; - prev_inst = cur_inst; - continue; - } - - // number of declared errors might have increased now - update_errors_helper(ira->codegen, &errors, &errors_count); - - // if err_set_type is a superset of cur_type, keep err_set_type. - // if cur_type is a superset of err_set_type, switch err_set_type to cur_type - bool prev_is_superset = true; - for (uint32_t i = 0; i < cur_type->data.error_set.err_count; i += 1) { - ErrorTableEntry *contained_error_entry = cur_type->data.error_set.errors[i]; - ErrorTableEntry *error_entry = errors[contained_error_entry->value]; - if (error_entry == nullptr) { - prev_is_superset = false; - break; - } - } - if (prev_is_superset) { - continue; - } - - // unset everything in errors - for (uint32_t i = 0; i < err_set_type->data.error_set.err_count; i += 1) { - ErrorTableEntry *error_entry = err_set_type->data.error_set.errors[i]; - errors[error_entry->value] = nullptr; - } - for (uint32_t i = 0, count = ira->codegen->errors_by_index.length; i < count; i += 1) { - assert(errors[i] == nullptr); - } - for (uint32_t i = 0; i < cur_type->data.error_set.err_count; i += 1) { - ErrorTableEntry *error_entry = cur_type->data.error_set.errors[i]; - assert(errors[error_entry->value] == nullptr); - errors[error_entry->value] = error_entry; - } - bool cur_is_superset = true; - for (uint32_t i = 0; i < err_set_type->data.error_set.err_count; i += 1) { - ErrorTableEntry *contained_error_entry = err_set_type->data.error_set.errors[i]; - ErrorTableEntry *error_entry = errors[contained_error_entry->value]; - if (error_entry == nullptr) { - cur_is_superset = false; - break; - } - } - if (cur_is_superset) { - err_set_type = cur_type; - prev_inst = cur_inst; - assert(errors != nullptr); - continue; - } - - // neither of them are supersets. so we invent a new error set type that is a union of both of them - err_set_type = get_error_set_union(ira->codegen, errors, cur_type, err_set_type, nullptr); - assert(errors != nullptr); - continue; - } else if (cur_type->id == ZigTypeIdErrorUnion) { - if (type_is_global_error_set(err_set_type)) { - prev_inst = cur_inst; - continue; - } - ZigType *cur_err_set_type = cur_type->data.error_union.err_set_type; - bool allow_infer = cur_err_set_type->data.error_set.infer_fn != nullptr && - cur_err_set_type->data.error_set.infer_fn == ira->fn; - if (!allow_infer && !resolve_inferred_error_set(ira->codegen, cur_err_set_type, cur_inst->source_node)) { - return ira->codegen->builtin_types.entry_invalid; - } - if (!allow_infer && type_is_global_error_set(cur_err_set_type)) { - err_set_type = ira->codegen->builtin_types.entry_global_error_set; - prev_inst = cur_inst; - continue; - } - - update_errors_helper(ira->codegen, &errors, &errors_count); - - // test if err_set_type is a subset of cur_type's error set - // unset everything in errors - for (uint32_t i = 0; i < err_set_type->data.error_set.err_count; i += 1) { - ErrorTableEntry *error_entry = err_set_type->data.error_set.errors[i]; - errors[error_entry->value] = nullptr; - } - for (uint32_t i = 0, count = ira->codegen->errors_by_index.length; i < count; i += 1) { - assert(errors[i] == nullptr); - } - for (uint32_t i = 0; i < cur_err_set_type->data.error_set.err_count; i += 1) { - ErrorTableEntry *error_entry = cur_err_set_type->data.error_set.errors[i]; - assert(errors[error_entry->value] == nullptr); - errors[error_entry->value] = error_entry; - } - bool cur_is_superset = true; - for (uint32_t i = 0; i < err_set_type->data.error_set.err_count; i += 1) { - ErrorTableEntry *contained_error_entry = err_set_type->data.error_set.errors[i]; - ErrorTableEntry *error_entry = errors[contained_error_entry->value]; - if (error_entry == nullptr) { - cur_is_superset = false; - break; - } - } - if (cur_is_superset) { - err_set_type = cur_err_set_type; - prev_inst = cur_inst; - assert(errors != nullptr); - continue; - } - - // not a subset. invent new error set type, union of both of them - err_set_type = get_error_set_union(ira->codegen, errors, cur_err_set_type, err_set_type, nullptr); - prev_inst = cur_inst; - assert(errors != nullptr); - continue; - } else { - prev_inst = cur_inst; - continue; - } - } - - if (cur_type->id == ZigTypeIdErrorSet) { - bool allow_infer = cur_type->data.error_set.infer_fn != nullptr && - cur_type->data.error_set.infer_fn == ira->fn; - if (!allow_infer && !resolve_inferred_error_set(ira->codegen, cur_type, cur_inst->source_node)) { - return ira->codegen->builtin_types.entry_invalid; - } - if (!allow_infer && type_is_global_error_set(cur_type)) { - err_set_type = ira->codegen->builtin_types.entry_global_error_set; - continue; - } - if (err_set_type != nullptr && type_is_global_error_set(err_set_type)) { - continue; - } - - update_errors_helper(ira->codegen, &errors, &errors_count); - - if (err_set_type == nullptr) { - bool allow_infer = false; - if (prev_type->id == ZigTypeIdErrorUnion) { - err_set_type = prev_type->data.error_union.err_set_type; - allow_infer = err_set_type->data.error_set.infer_fn != nullptr && - err_set_type->data.error_set.infer_fn == ira->fn; - } else { - err_set_type = cur_type; - } - - if (!allow_infer && !resolve_inferred_error_set(ira->codegen, err_set_type, cur_inst->source_node)) { - return ira->codegen->builtin_types.entry_invalid; - } - - if (!allow_infer && type_is_global_error_set(err_set_type)) { - err_set_type = ira->codegen->builtin_types.entry_global_error_set; - continue; - } - - update_errors_helper(ira->codegen, &errors, &errors_count); - - for (uint32_t i = 0; i < err_set_type->data.error_set.err_count; i += 1) { - ErrorTableEntry *error_entry = err_set_type->data.error_set.errors[i]; - assert(errors[error_entry->value] == nullptr); - errors[error_entry->value] = error_entry; - } - if (err_set_type == cur_type) { - continue; - } - } - // check if the cur type error set is a subset - bool prev_is_superset = true; - for (uint32_t i = 0; i < cur_type->data.error_set.err_count; i += 1) { - ErrorTableEntry *contained_error_entry = cur_type->data.error_set.errors[i]; - ErrorTableEntry *error_entry = errors[contained_error_entry->value]; - if (error_entry == nullptr) { - prev_is_superset = false; - break; - } - } - if (prev_is_superset) { - continue; - } - // not a subset. invent new error set type, union of both of them - err_set_type = get_error_set_union(ira->codegen, errors, err_set_type, cur_type, nullptr); - assert(errors != nullptr); - continue; - } - - if (prev_type->id == ZigTypeIdErrorUnion && cur_type->id == ZigTypeIdErrorUnion) { - ZigType *prev_payload_type = prev_type->data.error_union.payload_type; - ZigType *cur_payload_type = cur_type->data.error_union.payload_type; - - bool const_cast_prev = types_match_const_cast_only(ira, prev_payload_type, cur_payload_type, - source_node, false).id == ConstCastResultIdOk; - bool const_cast_cur = types_match_const_cast_only(ira, cur_payload_type, prev_payload_type, - source_node, false).id == ConstCastResultIdOk; - - if (const_cast_prev || const_cast_cur) { - if (const_cast_cur) { - prev_inst = cur_inst; - } - - ZigType *prev_err_set_type = (err_set_type == nullptr) ? prev_type->data.error_union.err_set_type : err_set_type; - ZigType *cur_err_set_type = cur_type->data.error_union.err_set_type; - if (prev_err_set_type == cur_err_set_type) - continue; - - bool allow_infer_prev = prev_err_set_type->data.error_set.infer_fn != nullptr && - prev_err_set_type->data.error_set.infer_fn == ira->fn; - bool allow_infer_cur = cur_err_set_type->data.error_set.infer_fn != nullptr && - cur_err_set_type->data.error_set.infer_fn == ira->fn; - - if (!allow_infer_prev && !resolve_inferred_error_set(ira->codegen, prev_err_set_type, cur_inst->source_node)) { - return ira->codegen->builtin_types.entry_invalid; - } - - if (!allow_infer_cur && !resolve_inferred_error_set(ira->codegen, cur_err_set_type, cur_inst->source_node)) { - return ira->codegen->builtin_types.entry_invalid; - } - - if ((!allow_infer_prev && type_is_global_error_set(prev_err_set_type)) || - (!allow_infer_cur && type_is_global_error_set(cur_err_set_type))) - { - err_set_type = ira->codegen->builtin_types.entry_global_error_set; - continue; - } - - update_errors_helper(ira->codegen, &errors, &errors_count); - - if (err_set_type == nullptr) { - err_set_type = prev_err_set_type; - for (uint32_t i = 0; i < prev_err_set_type->data.error_set.err_count; i += 1) { - ErrorTableEntry *error_entry = prev_err_set_type->data.error_set.errors[i]; - assert(errors[error_entry->value] == nullptr); - errors[error_entry->value] = error_entry; - } - } - bool prev_is_superset = true; - for (uint32_t i = 0; i < cur_err_set_type->data.error_set.err_count; i += 1) { - ErrorTableEntry *contained_error_entry = cur_err_set_type->data.error_set.errors[i]; - ErrorTableEntry *error_entry = errors[contained_error_entry->value]; - if (error_entry == nullptr) { - prev_is_superset = false; - break; - } - } - if (prev_is_superset) { - continue; - } - // unset all the errors - for (uint32_t i = 0; i < err_set_type->data.error_set.err_count; i += 1) { - ErrorTableEntry *error_entry = err_set_type->data.error_set.errors[i]; - errors[error_entry->value] = nullptr; - } - for (uint32_t i = 0, count = ira->codegen->errors_by_index.length; i < count; i += 1) { - assert(errors[i] == nullptr); - } - for (uint32_t i = 0; i < cur_err_set_type->data.error_set.err_count; i += 1) { - ErrorTableEntry *error_entry = cur_err_set_type->data.error_set.errors[i]; - assert(errors[error_entry->value] == nullptr); - errors[error_entry->value] = error_entry; - } - bool cur_is_superset = true; - for (uint32_t i = 0; i < prev_err_set_type->data.error_set.err_count; i += 1) { - ErrorTableEntry *contained_error_entry = prev_err_set_type->data.error_set.errors[i]; - ErrorTableEntry *error_entry = errors[contained_error_entry->value]; - if (error_entry == nullptr) { - cur_is_superset = false; - break; - } - } - if (cur_is_superset) { - err_set_type = cur_err_set_type; - continue; - } - - err_set_type = get_error_set_union(ira->codegen, errors, cur_err_set_type, prev_err_set_type, nullptr); - continue; - } - } - - if (prev_type->id == ZigTypeIdNull) { - prev_inst = cur_inst; - any_are_null = true; - continue; - } - - if (cur_type->id == ZigTypeIdNull) { - any_are_null = true; - continue; - } - - if (prev_type->id == ZigTypeIdEnum && cur_type->id == ZigTypeIdEnumLiteral) { - TypeEnumField *field = find_enum_type_field(prev_type, cur_inst->value->data.x_enum_literal); - if (field != nullptr) { - continue; - } - } - if (is_tagged_union(prev_type) && cur_type->id == ZigTypeIdEnumLiteral) { - TypeUnionField *field = find_union_type_field(prev_type, cur_inst->value->data.x_enum_literal); - if (field != nullptr) { - continue; - } - } - - if (cur_type->id == ZigTypeIdEnum && prev_type->id == ZigTypeIdEnumLiteral) { - TypeEnumField *field = find_enum_type_field(cur_type, prev_inst->value->data.x_enum_literal); - if (field != nullptr) { - prev_inst = cur_inst; - continue; - } - } - - if (is_tagged_union(cur_type) && prev_type->id == ZigTypeIdEnumLiteral) { - TypeUnionField *field = find_union_type_field(cur_type, prev_inst->value->data.x_enum_literal); - if (field != nullptr) { - prev_inst = cur_inst; - continue; - } - } - - if (prev_type->id == ZigTypeIdPointer && prev_type->data.pointer.ptr_len == PtrLenC && - (cur_type->id == ZigTypeIdComptimeInt || cur_type->id == ZigTypeIdInt)) - { - continue; - } - - if (cur_type->id == ZigTypeIdPointer && cur_type->data.pointer.ptr_len == PtrLenC && - (prev_type->id == ZigTypeIdComptimeInt || prev_type->id == ZigTypeIdInt)) - { - prev_inst = cur_inst; - continue; - } - - if (prev_type->id == ZigTypeIdPointer && cur_type->id == ZigTypeIdPointer) { - if (prev_type->data.pointer.ptr_len == PtrLenC && - types_match_const_cast_only(ira, prev_type->data.pointer.child_type, - cur_type->data.pointer.child_type, source_node, - !prev_type->data.pointer.is_const).id == ConstCastResultIdOk) - { - continue; - } - if (cur_type->data.pointer.ptr_len == PtrLenC && - types_match_const_cast_only(ira, cur_type->data.pointer.child_type, - prev_type->data.pointer.child_type, source_node, - !cur_type->data.pointer.is_const).id == ConstCastResultIdOk) - { - prev_inst = cur_inst; - continue; - } - } - - if (types_match_const_cast_only(ira, prev_type, cur_type, source_node, false).id == ConstCastResultIdOk) { - continue; - } - - if (types_match_const_cast_only(ira, cur_type, prev_type, source_node, false).id == ConstCastResultIdOk) { - prev_inst = cur_inst; - continue; - } - - if (prev_type->id == ZigTypeIdInt && - cur_type->id == ZigTypeIdInt) - { - if ((prev_type->data.integral.is_signed == cur_type->data.integral.is_signed) || - (cur_type->data.integral.is_signed && !prev_type->data.integral.is_signed)) { - if (cur_type->data.integral.bit_count > prev_type->data.integral.bit_count) { - prev_inst = cur_inst; - } - } - continue; - } - - if (prev_type->id == ZigTypeIdFloat && cur_type->id == ZigTypeIdFloat) { - if (cur_type->data.floating.bit_count > prev_type->data.floating.bit_count) { - prev_inst = cur_inst; - } - continue; - } - - if (prev_type->id == ZigTypeIdErrorUnion && - types_match_const_cast_only(ira, prev_type->data.error_union.payload_type, cur_type, - source_node, false).id == ConstCastResultIdOk) - { - continue; - } - - if (cur_type->id == ZigTypeIdErrorUnion && - types_match_const_cast_only(ira, cur_type->data.error_union.payload_type, prev_type, - source_node, false).id == ConstCastResultIdOk) - { - if (err_set_type != nullptr) { - ZigType *cur_err_set_type = cur_type->data.error_union.err_set_type; - bool allow_infer = cur_err_set_type->data.error_set.infer_fn != nullptr && - cur_err_set_type->data.error_set.infer_fn == ira->fn; - if (!allow_infer && !resolve_inferred_error_set(ira->codegen, cur_err_set_type, cur_inst->source_node)) { - return ira->codegen->builtin_types.entry_invalid; - } - if ((!allow_infer && type_is_global_error_set(cur_err_set_type)) || - type_is_global_error_set(err_set_type)) - { - err_set_type = ira->codegen->builtin_types.entry_global_error_set; - prev_inst = cur_inst; - continue; - } - - update_errors_helper(ira->codegen, &errors, &errors_count); - - err_set_type = get_error_set_union(ira->codegen, errors, err_set_type, cur_err_set_type, nullptr); - } - prev_inst = cur_inst; - continue; - } - - if (prev_type->id == ZigTypeIdOptional && - types_match_const_cast_only(ira, prev_type->data.maybe.child_type, cur_type, - source_node, false).id == ConstCastResultIdOk) - { - continue; - } - - if (cur_type->id == ZigTypeIdOptional && - types_match_const_cast_only(ira, cur_type->data.maybe.child_type, prev_type, - source_node, false).id == ConstCastResultIdOk) - { - prev_inst = cur_inst; - continue; - } - - if (prev_type->id == ZigTypeIdOptional && - types_match_const_cast_only(ira, cur_type, prev_type->data.maybe.child_type, - source_node, false).id == ConstCastResultIdOk) - { - prev_inst = cur_inst; - any_are_null = true; - continue; - } - - if (cur_type->id == ZigTypeIdOptional && - types_match_const_cast_only(ira, prev_type, cur_type->data.maybe.child_type, - source_node, false).id == ConstCastResultIdOk) - { - any_are_null = true; - continue; - } - - if (cur_type->id == ZigTypeIdUndefined) { - continue; - } - - if (prev_type->id == ZigTypeIdUndefined) { - prev_inst = cur_inst; - continue; - } - - if (prev_type->id == ZigTypeIdComptimeInt || - prev_type->id == ZigTypeIdComptimeFloat) - { - if (ir_num_lit_fits_in_other_type(ira, prev_inst, cur_type, false)) { - prev_inst = cur_inst; - continue; - } else { - return ira->codegen->builtin_types.entry_invalid; - } - } - - if (cur_type->id == ZigTypeIdComptimeInt || - cur_type->id == ZigTypeIdComptimeFloat) - { - if (ir_num_lit_fits_in_other_type(ira, cur_inst, prev_type, false)) { - continue; - } else { - return ira->codegen->builtin_types.entry_invalid; - } - } - - // *[N]T to [*]T - if (prev_type->id == ZigTypeIdPointer && - prev_type->data.pointer.ptr_len == PtrLenSingle && - prev_type->data.pointer.child_type->id == ZigTypeIdArray && - ((cur_type->id == ZigTypeIdPointer && cur_type->data.pointer.ptr_len == PtrLenUnknown))) - { - convert_to_const_slice = false; - prev_inst = cur_inst; - - if (prev_type->data.pointer.is_const && !cur_type->data.pointer.is_const) { - // const array pointer and non-const unknown pointer - make_the_pointer_const = true; - } - continue; - } - - // *[N]T to [*]T - if (cur_type->id == ZigTypeIdPointer && - cur_type->data.pointer.ptr_len == PtrLenSingle && - cur_type->data.pointer.child_type->id == ZigTypeIdArray && - ((prev_type->id == ZigTypeIdPointer && prev_type->data.pointer.ptr_len == PtrLenUnknown))) - { - if (cur_type->data.pointer.is_const && !prev_type->data.pointer.is_const) { - // const array pointer and non-const unknown pointer - make_the_pointer_const = true; - } - continue; - } - - // *[N]T to []T - // *[N]T to E![]T - if (cur_type->id == ZigTypeIdPointer && - cur_type->data.pointer.ptr_len == PtrLenSingle && - cur_type->data.pointer.child_type->id == ZigTypeIdArray && - ((prev_type->id == ZigTypeIdErrorUnion && is_slice(prev_type->data.error_union.payload_type)) || - is_slice(prev_type))) - { - ZigType *array_type = cur_type->data.pointer.child_type; - ZigType *slice_type = (prev_type->id == ZigTypeIdErrorUnion) ? - prev_type->data.error_union.payload_type : prev_type; - ZigType *slice_ptr_type = slice_type->data.structure.fields[slice_ptr_index]->type_entry; - if (types_match_const_cast_only(ira, slice_ptr_type->data.pointer.child_type, - array_type->data.array.child_type, source_node, false).id == ConstCastResultIdOk) - { - bool const_ok = (slice_ptr_type->data.pointer.is_const || array_type->data.array.len == 0 || - !cur_type->data.pointer.is_const); - if (!const_ok) make_the_slice_const = true; - convert_to_const_slice = false; - continue; - } - } - - // *[N]T to []T - // *[N]T to E![]T - if (prev_type->id == ZigTypeIdPointer && - prev_type->data.pointer.child_type->id == ZigTypeIdArray && - prev_type->data.pointer.ptr_len == PtrLenSingle && - ((cur_type->id == ZigTypeIdErrorUnion && is_slice(cur_type->data.error_union.payload_type)) || - (cur_type->id == ZigTypeIdOptional && is_slice(cur_type->data.maybe.child_type)) || - is_slice(cur_type))) - { - ZigType *array_type = prev_type->data.pointer.child_type; - ZigType *slice_type; - switch (cur_type->id) { - case ZigTypeIdErrorUnion: - slice_type = cur_type->data.error_union.payload_type; - break; - case ZigTypeIdOptional: - slice_type = cur_type->data.maybe.child_type; - break; - default: - slice_type = cur_type; - break; - } - ZigType *slice_ptr_type = slice_type->data.structure.fields[slice_ptr_index]->type_entry; - if (types_match_const_cast_only(ira, slice_ptr_type->data.pointer.child_type, - array_type->data.array.child_type, source_node, false).id == ConstCastResultIdOk) - { - bool const_ok = (slice_ptr_type->data.pointer.is_const || array_type->data.array.len == 0 || - !prev_type->data.pointer.is_const); - if (!const_ok) make_the_slice_const = true; - prev_inst = cur_inst; - convert_to_const_slice = false; - continue; - } - } - - // *[N]T and *[M]T - if (cur_type->id == ZigTypeIdPointer && cur_type->data.pointer.ptr_len == PtrLenSingle && - cur_type->data.pointer.child_type->id == ZigTypeIdArray && - prev_type->id == ZigTypeIdPointer && prev_type->data.pointer.ptr_len == PtrLenSingle && - prev_type->data.pointer.child_type->id == ZigTypeIdArray && - ( - prev_type->data.pointer.child_type->data.array.sentinel == nullptr || - (cur_type->data.pointer.child_type->data.array.sentinel != nullptr && - const_values_equal(ira->codegen, prev_type->data.pointer.child_type->data.array.sentinel, - cur_type->data.pointer.child_type->data.array.sentinel)) - ) && - types_match_const_cast_only(ira, - cur_type->data.pointer.child_type->data.array.child_type, - prev_type->data.pointer.child_type->data.array.child_type, - source_node, !cur_type->data.pointer.is_const).id == ConstCastResultIdOk) - { - bool const_ok = (cur_type->data.pointer.is_const || !prev_type->data.pointer.is_const || - prev_type->data.pointer.child_type->data.array.len == 0); - if (!const_ok) make_the_slice_const = true; - prev_inst = cur_inst; - convert_to_const_slice = true; - continue; - } - if (prev_type->id == ZigTypeIdPointer && prev_type->data.pointer.ptr_len == PtrLenSingle && - prev_type->data.pointer.child_type->id == ZigTypeIdArray && - cur_type->id == ZigTypeIdPointer && cur_type->data.pointer.ptr_len == PtrLenSingle && - cur_type->data.pointer.child_type->id == ZigTypeIdArray && - ( - cur_type->data.pointer.child_type->data.array.sentinel == nullptr || - (prev_type->data.pointer.child_type->data.array.sentinel != nullptr && - const_values_equal(ira->codegen, cur_type->data.pointer.child_type->data.array.sentinel, - prev_type->data.pointer.child_type->data.array.sentinel)) - ) && - types_match_const_cast_only(ira, - prev_type->data.pointer.child_type->data.array.child_type, - cur_type->data.pointer.child_type->data.array.child_type, - source_node, !prev_type->data.pointer.is_const).id == ConstCastResultIdOk) - { - bool const_ok = (prev_type->data.pointer.is_const || !cur_type->data.pointer.is_const || - cur_type->data.pointer.child_type->data.array.len == 0); - if (!const_ok) make_the_slice_const = true; - convert_to_const_slice = true; - continue; - } - - if (prev_type->id == ZigTypeIdEnum && is_tagged_union(cur_type)) { - if ((err = type_resolve(ira->codegen, cur_type, ResolveStatusZeroBitsKnown))) - return ira->codegen->builtin_types.entry_invalid; - if (cur_type->data.unionation.tag_type == prev_type) { - continue; - } - } - - if (cur_type->id == ZigTypeIdEnum && is_tagged_union(prev_type)) { - if ((err = type_resolve(ira->codegen, prev_type, ResolveStatusZeroBitsKnown))) - return ira->codegen->builtin_types.entry_invalid; - if (prev_type->data.unionation.tag_type == cur_type) { - prev_inst = cur_inst; - continue; - } - } - - ErrorMsg *msg = ir_add_error_node(ira, source_node, - buf_sprintf("incompatible types: '%s' and '%s'", - buf_ptr(&prev_type->name), buf_ptr(&cur_type->name))); - add_error_note(ira->codegen, msg, prev_inst->source_node, - buf_sprintf("type '%s' here", buf_ptr(&prev_type->name))); - add_error_note(ira->codegen, msg, cur_inst->source_node, - buf_sprintf("type '%s' here", buf_ptr(&cur_type->name))); - - return ira->codegen->builtin_types.entry_invalid; - } - - heap::c_allocator.deallocate(errors, errors_count); - - if (convert_to_const_slice) { - if (prev_inst->value->type->id == ZigTypeIdPointer) { - ZigType *array_type = prev_inst->value->type->data.pointer.child_type; - src_assert(array_type->id == ZigTypeIdArray, source_node); - ZigType *ptr_type = get_pointer_to_type_extra2( - ira->codegen, array_type->data.array.child_type, - prev_inst->value->type->data.pointer.is_const || make_the_slice_const, false, - PtrLenUnknown, - 0, 0, 0, false, - VECTOR_INDEX_NONE, nullptr, array_type->data.array.sentinel); - ZigType *slice_type = get_slice_type(ira->codegen, ptr_type); - if (err_set_type != nullptr) { - return get_error_union_type(ira->codegen, err_set_type, slice_type); - } else { - return slice_type; - } - } else { - zig_unreachable(); - } - } else if (err_set_type != nullptr) { - if (prev_inst->value->type->id == ZigTypeIdErrorSet) { - return err_set_type; - } else if (prev_inst->value->type->id == ZigTypeIdErrorUnion) { - ZigType *payload_type = prev_inst->value->type->data.error_union.payload_type; - if ((err = type_resolve(ira->codegen, payload_type, ResolveStatusSizeKnown))) - return ira->codegen->builtin_types.entry_invalid; - return get_error_union_type(ira->codegen, err_set_type, payload_type); - } else if (expected_type != nullptr && expected_type->id == ZigTypeIdErrorUnion) { - ZigType *payload_type = expected_type->data.error_union.payload_type; - if ((err = type_resolve(ira->codegen, payload_type, ResolveStatusSizeKnown))) - return ira->codegen->builtin_types.entry_invalid; - return get_error_union_type(ira->codegen, err_set_type, payload_type); - } else { - if (prev_inst->value->type->id == ZigTypeIdComptimeInt || - prev_inst->value->type->id == ZigTypeIdComptimeFloat) - { - ir_add_error_node(ira, source_node, - buf_sprintf("unable to make error union out of number literal")); - return ira->codegen->builtin_types.entry_invalid; - } else if (prev_inst->value->type->id == ZigTypeIdNull) { - ir_add_error_node(ira, source_node, - buf_sprintf("unable to make error union out of null literal")); - return ira->codegen->builtin_types.entry_invalid; - } else { - if ((err = type_resolve(ira->codegen, prev_inst->value->type, ResolveStatusSizeKnown))) - return ira->codegen->builtin_types.entry_invalid; - return get_error_union_type(ira->codegen, err_set_type, prev_inst->value->type); - } - } - } else if (any_are_null && prev_inst->value->type->id != ZigTypeIdNull) { - if (prev_inst->value->type->id == ZigTypeIdOptional) { - return prev_inst->value->type; - } else { - if ((err = type_resolve(ira->codegen, prev_inst->value->type, ResolveStatusSizeKnown))) - return ira->codegen->builtin_types.entry_invalid; - return get_optional_type(ira->codegen, prev_inst->value->type); - } - } else if (make_the_slice_const) { - ZigType *slice_type; - if (prev_inst->value->type->id == ZigTypeIdErrorUnion) { - slice_type = prev_inst->value->type->data.error_union.payload_type; - } else if (is_slice(prev_inst->value->type)) { - slice_type = prev_inst->value->type; - } else { - zig_unreachable(); - } - ZigType *slice_ptr_type = slice_type->data.structure.fields[slice_ptr_index]->type_entry; - ZigType *adjusted_ptr_type = adjust_ptr_const(ira->codegen, slice_ptr_type, make_the_slice_const); - ZigType *adjusted_slice_type = get_slice_type(ira->codegen, adjusted_ptr_type); - if (prev_inst->value->type->id == ZigTypeIdErrorUnion) { - return get_error_union_type(ira->codegen, prev_inst->value->type->data.error_union.err_set_type, - adjusted_slice_type); - } else if (is_slice(prev_inst->value->type)) { - return adjusted_slice_type; - } else { - zig_unreachable(); - } - } else if (make_the_pointer_const) { - return adjust_ptr_const(ira->codegen, prev_inst->value->type, make_the_pointer_const); - } else { - return prev_inst->value->type; - } -} - -static bool eval_const_expr_implicit_cast(IrAnalyze *ira, Scope *scope, AstNode *source_node, - CastOp cast_op, - ZigValue *other_val, ZigType *other_type, - ZigValue *const_val, ZigType *new_type) -{ - const_val->special = other_val->special; - - assert(other_val != const_val); - switch (cast_op) { - case CastOpNoCast: - zig_unreachable(); - case CastOpErrSet: - case CastOpBitCast: - zig_panic("TODO: eval_const_expr_implicit_cast CastOpErrSet, CastOpBitCast"); - case CastOpNoop: { - copy_const_val(ira->codegen, const_val, other_val); - const_val->type = new_type; - break; - } - case CastOpNumLitToConcrete: - if (other_val->type->id == ZigTypeIdComptimeFloat) { - assert(new_type->id == ZigTypeIdFloat); - switch (new_type->data.floating.bit_count) { - case 16: - const_val->data.x_f16 = bigfloat_to_f16(&other_val->data.x_bigfloat); - break; - case 32: - const_val->data.x_f32 = bigfloat_to_f32(&other_val->data.x_bigfloat); - break; - case 64: - const_val->data.x_f64 = bigfloat_to_f64(&other_val->data.x_bigfloat); - break; - case 80: { - float128_t tmp = bigfloat_to_f128(&other_val->data.x_bigfloat); - f128M_to_extF80M(&tmp, &const_val->data.x_f80); - break; - } - case 128: - const_val->data.x_f128 = bigfloat_to_f128(&other_val->data.x_bigfloat); - break; - default: - zig_unreachable(); - } - } else if (other_val->type->id == ZigTypeIdComptimeInt) { - bigint_init_bigint(&const_val->data.x_bigint, &other_val->data.x_bigint); - } else { - zig_unreachable(); - } - const_val->type = new_type; - break; - case CastOpIntToFloat: - if (new_type->id == ZigTypeIdFloat) { - BigFloat bigfloat; - bigfloat_init_bigint(&bigfloat, &other_val->data.x_bigint); - switch (new_type->data.floating.bit_count) { - case 16: - const_val->data.x_f16 = bigfloat_to_f16(&bigfloat); - break; - case 32: - const_val->data.x_f32 = bigfloat_to_f32(&bigfloat); - break; - case 64: - const_val->data.x_f64 = bigfloat_to_f64(&bigfloat); - break; - case 80: { - float128_t tmp = bigfloat_to_f128(&other_val->data.x_bigfloat); - f128M_to_extF80M(&tmp, &const_val->data.x_f80); - break; - } - case 128: - const_val->data.x_f128 = bigfloat_to_f128(&bigfloat); - break; - default: - zig_unreachable(); - } - } else if (new_type->id == ZigTypeIdComptimeFloat) { - bigfloat_init_bigint(&const_val->data.x_bigfloat, &other_val->data.x_bigint); - } else { - zig_unreachable(); - } - const_val->special = ConstValSpecialStatic; - break; - case CastOpFloatToInt: - float_init_bigint(&const_val->data.x_bigint, other_val); - if (new_type->id == ZigTypeIdInt) { - if (!bigint_fits_in_bits(&const_val->data.x_bigint, new_type->data.integral.bit_count, - new_type->data.integral.is_signed)) - { - Buf *int_buf = buf_alloc(); - bigint_append_buf(int_buf, &const_val->data.x_bigint, 10); - - ir_add_error_node(ira, source_node, - buf_sprintf("integer value '%s' cannot be stored in type '%s'", - buf_ptr(int_buf), buf_ptr(&new_type->name))); - return false; - } - } - - const_val->special = ConstValSpecialStatic; - break; - case CastOpBoolToInt: - bigint_init_unsigned(&const_val->data.x_bigint, other_val->data.x_bool ? 1 : 0); - const_val->special = ConstValSpecialStatic; - break; - } - return true; -} - -static Stage1AirInst *ir_const(IrAnalyze *ira, Scope *scope, AstNode *source_node, ZigType *ty) { - Stage1AirInstConst *const_instruction = ir_create_inst_gen(&ira->new_irb, - scope, source_node); - Stage1AirInst *new_instruction = &const_instruction->base; - new_instruction->value->type = ty; - new_instruction->value->special = ConstValSpecialStatic; - ira->new_irb.constants.append(&heap::c_allocator, const_instruction); - return new_instruction; -} - -static Stage1AirInst *ir_const_noval(IrAnalyze *ira, Scope *scope, AstNode *source_node) { - Stage1AirInstConst *const_instruction = ir_create_inst_noval(&ira->new_irb, - scope, source_node); - ira->new_irb.constants.append(&heap::c_allocator, const_instruction); - return &const_instruction->base; -} - -// This function initializes the new Stage1AirInst with the provided ZigValue, -// rather than creating a new one. -static Stage1AirInst *ir_const_move(IrAnalyze *ira, Scope *scope, AstNode *source_node, ZigValue *val) { - Stage1AirInst *result = ir_const_noval(ira, scope, source_node); - result->value = val; - return result; -} - -static Stage1AirInst *ir_resolve_cast(IrAnalyze *ira, Scope *scope, AstNode *source_node, Stage1AirInst *value, - ZigType *wanted_type, CastOp cast_op) -{ - if (instr_is_comptime(value) || !type_has_bits(ira->codegen, wanted_type)) { - Stage1AirInst *result = ir_const(ira, scope, source_node, wanted_type); - ZigValue *val = ir_resolve_const(ira, value, UndefBad); - if (val == nullptr) - return ira->codegen->invalid_inst_gen; - - if (!eval_const_expr_implicit_cast(ira, scope, source_node, cast_op, val, val->type, - result->value, wanted_type)) - { - return ira->codegen->invalid_inst_gen; - } - return result; - } else { - return ir_build_cast(ira, scope, source_node, - wanted_type, value, cast_op); - } -} - -static Stage1AirInst *ir_resolve_ptr_of_array_to_unknown_len_ptr(IrAnalyze *ira, - Scope *scope, AstNode *source_node, Stage1AirInst *value, ZigType *wanted_type) -{ - src_assert(value->value->type->id == ZigTypeIdPointer, source_node); - - Error err; - - if ((err = type_resolve(ira->codegen, value->value->type->data.pointer.child_type, - ResolveStatusAlignmentKnown))) - { - return ira->codegen->invalid_inst_gen; - } - - wanted_type = adjust_ptr_align(ira->codegen, wanted_type, get_ptr_align(ira->codegen, value->value->type)); - - if (instr_is_comptime(value)) { - ZigValue *val = ir_resolve_const(ira, value, UndefOk); - if (val == nullptr) - return ira->codegen->invalid_inst_gen; - if (val->special == ConstValSpecialUndef) - return ir_const_undef(ira, scope, source_node, wanted_type); - - ZigValue *pointee = const_ptr_pointee(ira, ira->codegen, val, source_node); - if (pointee == nullptr) - return ira->codegen->invalid_inst_gen; - if (pointee->special != ConstValSpecialRuntime) { - Stage1AirInst *result = ir_const(ira, scope, source_node, wanted_type); - result->value->data.x_ptr.special = ConstPtrSpecialBaseArray; - result->value->data.x_ptr.mut = val->data.x_ptr.mut; - result->value->data.x_ptr.data.base_array.array_val = pointee; - result->value->data.x_ptr.data.base_array.elem_index = 0; - return result; - } - } - - return ir_build_cast(ira, scope, source_node, - wanted_type, value, CastOpBitCast); -} - -static Stage1AirInst *ir_resolve_ptr_of_array_to_slice(IrAnalyze *ira, Scope *scope, AstNode *source_node, - Stage1AirInst *array_ptr, ZigType *wanted_type, ResultLoc *result_loc) -{ - Error err; - - assert(array_ptr->value->type->id == ZigTypeIdPointer); - assert(array_ptr->value->type->data.pointer.child_type->id == ZigTypeIdArray); - - ZigType *array_type = array_ptr->value->type->data.pointer.child_type; - size_t array_len = array_type->data.array.len; - - // A zero-sized array can be casted regardless of the destination alignment, or - // whether the pointer is undefined, and the result is always comptime known. - // TODO However, this is exposing a result location bug that I failed to solve on the first try. - // If you want to try to fix the bug, uncomment this block and get the tests passing. - //if (array_len == 0 && array_type->data.array.sentinel == nullptr) { - // ZigValue *undef_array = ira->codegen->pass1_arena->create(); - // undef_array->special = ConstValSpecialUndef; - // undef_array->type = array_type; - - // Stage1AirInst *result = ir_const(ira, scope, source_node, wanted_type); - // init_const_slice(ira->codegen, result->value, undef_array, 0, 0, false, nullptr); - // result->value->data.x_struct.fields[slice_ptr_index]->data.x_ptr.mut = ConstPtrMutComptimeConst; - // result->value->type = wanted_type; - // return result; - //} - - if ((err = type_resolve(ira->codegen, array_ptr->value->type, ResolveStatusAlignmentKnown))) { - return ira->codegen->invalid_inst_gen; - } - - if (array_len != 0) { - wanted_type = adjust_slice_align(ira->codegen, wanted_type, - get_ptr_align(ira->codegen, array_ptr->value->type)); - } - - if (instr_is_comptime(array_ptr)) { - UndefAllowed undef_allowed = (array_len == 0) ? UndefOk : UndefBad; - ZigValue *array_ptr_val = ir_resolve_const(ira, array_ptr, undef_allowed); - if (array_ptr_val == nullptr) - return ira->codegen->invalid_inst_gen; - src_assert(is_slice(wanted_type), source_node); - if (array_ptr_val->special == ConstValSpecialUndef) { - ZigValue *undef_array = ira->codegen->pass1_arena->create(); - undef_array->special = ConstValSpecialUndef; - undef_array->type = array_type; - - Stage1AirInst *result = ir_const(ira, scope, source_node, wanted_type); - init_const_slice(ira->codegen, result->value, undef_array, 0, 0, false, nullptr); - result->value->data.x_struct.fields[slice_ptr_index]->data.x_ptr.mut = ConstPtrMutComptimeConst; - result->value->type = wanted_type; - return result; - } - bool wanted_const = wanted_type->data.structure.fields[slice_ptr_index]->type_entry->data.pointer.is_const; - // Optimization to avoid creating unnecessary ZigValue in const_ptr_pointee - if (array_ptr_val->data.x_ptr.special == ConstPtrSpecialSubArray) { - ZigValue *array_val = array_ptr_val->data.x_ptr.data.base_array.array_val; - if (array_val->special != ConstValSpecialRuntime) { - Stage1AirInst *result = ir_const(ira, scope, source_node, wanted_type); - init_const_slice(ira->codegen, result->value, array_val, - array_ptr_val->data.x_ptr.data.base_array.elem_index, - array_type->data.array.len, wanted_const, nullptr); - result->value->data.x_struct.fields[slice_ptr_index]->data.x_ptr.mut = array_ptr_val->data.x_ptr.mut; - result->value->type = wanted_type; - return result; - } - } else if (array_ptr_val->data.x_ptr.special != ConstPtrSpecialHardCodedAddr) { - ZigValue *pointee = const_ptr_pointee(ira, ira->codegen, array_ptr_val, source_node); - if (pointee == nullptr) - return ira->codegen->invalid_inst_gen; - if (pointee->special != ConstValSpecialRuntime) { - assert(array_ptr_val->type->id == ZigTypeIdPointer); - - Stage1AirInst *result = ir_const(ira, scope, source_node, wanted_type); - init_const_slice(ira->codegen, result->value, pointee, 0, array_type->data.array.len, wanted_const, nullptr); - result->value->data.x_struct.fields[slice_ptr_index]->data.x_ptr.mut = array_ptr_val->data.x_ptr.mut; - result->value->type = wanted_type; - return result; - } - } - } - - if (result_loc == nullptr) result_loc = no_result_loc(); - Stage1AirInst *result_loc_inst = ir_resolve_result(ira, ira->suspend_source_instr, - result_loc, wanted_type, nullptr, true, true); - if (type_is_invalid(result_loc_inst->value->type) || - result_loc_inst->value->type->id == ZigTypeIdUnreachable) - { - return result_loc_inst; - } - return ir_build_ptr_of_array_to_slice(ira, scope, source_node, wanted_type, array_ptr, result_loc_inst); -} - -static Stage1AirBasicBlock *ir_get_new_bb(IrAnalyze *ira, Stage1ZirBasicBlock *old_bb, Stage1ZirInst *ref_old_instruction) { - assert(old_bb); - - if (old_bb->child) { - if (ref_old_instruction == nullptr || old_bb->child->ref_instruction != ref_old_instruction) { - return old_bb->child; - } - } - - Stage1AirBasicBlock *new_bb = ir_build_bb_from(ira, old_bb); - new_bb->ref_instruction = ref_old_instruction; - - return new_bb; -} - -static Stage1AirBasicBlock *ir_get_new_bb_runtime(IrAnalyze *ira, Stage1ZirBasicBlock *old_bb, Stage1ZirInst *ref_old_instruction) { - assert(ref_old_instruction != nullptr); - Stage1AirBasicBlock *new_bb = ir_get_new_bb(ira, old_bb, ref_old_instruction); - if (new_bb->must_be_comptime_source_node != nullptr) { - ErrorMsg *msg = ir_add_error_node(ira, ref_old_instruction->source_node, - buf_sprintf("control flow attempts to use compile-time variable at runtime")); - add_error_note(ira->codegen, msg, new_bb->must_be_comptime_source_node, - buf_sprintf("compile-time variable assigned here")); - return nullptr; - } - return new_bb; -} - -static void ir_start_bb(IrAnalyze *ira, Stage1ZirBasicBlock *old_bb, Stage1ZirBasicBlock *const_predecessor_bb) { - src_assert(!old_bb->suspended, - (old_bb->instruction_list.length != 0) ? - old_bb->instruction_list.at(0)->source_node : nullptr); - ira->instruction_index = 0; - ira->zir_current_basic_block = old_bb; - ira->const_predecessor_bb = const_predecessor_bb; - ira->old_bb_index = old_bb->index; -} - -static Stage1AirInst *ira_suspend(IrAnalyze *ira, Stage1ZirInst *old_instruction, Stage1ZirBasicBlock *next_bb, - IrSuspendPosition *suspend_pos) -{ - if (ira->codegen->verbose_ir) { - fprintf(stderr, "suspend %s_%" PRIu32 " %s_%" PRIu32 " #%" PRIu32 " (%zu,%zu)\n", - ira->zir_current_basic_block->name_hint, - ira->zir_current_basic_block->debug_id, - ira->zir->basic_block_list.at(ira->old_bb_index)->name_hint, - ira->zir->basic_block_list.at(ira->old_bb_index)->debug_id, - ira->zir_current_basic_block->instruction_list.at(ira->instruction_index)->debug_id, - ira->old_bb_index, ira->instruction_index); - } - suspend_pos->basic_block_index = ira->old_bb_index; - suspend_pos->instruction_index = ira->instruction_index; - - ira->zir_current_basic_block->suspended = true; - - // null next_bb means that the caller plans to call ira_resume before returning - if (next_bb != nullptr) { - ira->old_bb_index = next_bb->index; - ira->zir_current_basic_block = ira->zir->basic_block_list.at(ira->old_bb_index); - assert(ira->zir_current_basic_block == next_bb); - ira->instruction_index = 0; - ira->const_predecessor_bb = nullptr; - next_bb->child = ir_get_new_bb_runtime(ira, next_bb, old_instruction); - ira->new_irb.current_basic_block = next_bb->child; - } - return ira->codegen->unreach_instruction; -} - -static Stage1AirInst *ira_resume(IrAnalyze *ira) { - IrSuspendPosition pos = ira->resume_stack.pop(); - if (ira->codegen->verbose_ir) { - fprintf(stderr, "resume (%zu,%zu) ", pos.basic_block_index, pos.instruction_index); - } - ira->old_bb_index = pos.basic_block_index; - ira->zir_current_basic_block = ira->zir->basic_block_list.at(ira->old_bb_index); - assert(ira->zir_current_basic_block->in_resume_stack); - ira->zir_current_basic_block->in_resume_stack = false; - ira->zir_current_basic_block->suspended = false; - ira->instruction_index = pos.instruction_index; - assert(pos.instruction_index < ira->zir_current_basic_block->instruction_list.length); - if (ira->codegen->verbose_ir) { - fprintf(stderr, "%s_%" PRIu32 " #%" PRIu32 "\n", ira->zir_current_basic_block->name_hint, - ira->zir_current_basic_block->debug_id, - ira->zir_current_basic_block->instruction_list.at(pos.instruction_index)->debug_id); - } - ira->const_predecessor_bb = nullptr; - ira->new_irb.current_basic_block = ira->zir_current_basic_block->child; - assert(ira->new_irb.current_basic_block != nullptr); - return ira->codegen->unreach_instruction; -} - -static void ir_start_next_bb(IrAnalyze *ira) { - ira->old_bb_index += 1; - - bool need_repeat = true; - for (;;) { - while (ira->old_bb_index < ira->zir->basic_block_list.length) { - Stage1ZirBasicBlock *old_bb = ira->zir->basic_block_list.at(ira->old_bb_index); - if (old_bb->child == nullptr && old_bb->suspend_instruction_ref == nullptr) { - ira->old_bb_index += 1; - continue; - } - // if it's already started, or - // if it's a suspended block, - // then skip it - if (old_bb->suspended || - (old_bb->child != nullptr && old_bb->child->instruction_list.length != 0) || - (old_bb->child != nullptr && old_bb->child->already_appended)) - { - ira->old_bb_index += 1; - continue; - } - - // if there is a resume_stack, pop one from there rather than moving on. - // the last item of the resume stack will be a basic block that will - // move on to the next one below - if (ira->resume_stack.length != 0) { - ira_resume(ira); - return; - } - - if (old_bb->child == nullptr) { - old_bb->child = ir_get_new_bb_runtime(ira, old_bb, old_bb->suspend_instruction_ref); - } - ira->new_irb.current_basic_block = old_bb->child; - ir_start_bb(ira, old_bb, nullptr); - return; - } - if (!need_repeat) { - if (ira->resume_stack.length != 0) { - ira_resume(ira); - } - return; - } - need_repeat = false; - ira->old_bb_index = 0; - continue; - } -} - -static void ir_finish_bb(IrAnalyze *ira) { - if (!ira->new_irb.current_basic_block->already_appended) { - ir_append_basic_block_gen(&ira->new_irb, ira->new_irb.current_basic_block); - if (ira->codegen->verbose_ir) { - fprintf(stderr, "append new bb %s_%" PRIu32 "\n", ira->new_irb.current_basic_block->name_hint, - ira->new_irb.current_basic_block->debug_id); - } - } - ir_start_next_bb(ira); -} - -static Stage1AirInst *ir_unreach_error(IrAnalyze *ira) { - ira->old_bb_index = SIZE_MAX; - if (ira->new_irb.exec->first_err_trace_msg == nullptr) { - ira->new_irb.exec->first_err_trace_msg = ira->codegen->trace_err; - } - return ira->codegen->unreach_instruction; -} - -static bool ir_emit_backward_branch(IrAnalyze *ira, AstNode* source_node) { - size_t *bbc = ira->backward_branch_count; - size_t *quota = ira->backward_branch_quota; - - // If we're already over quota, we've already given an error message for this. - if (*bbc > *quota) { - assert(ira->codegen->errors.length > 0); - return false; - } - - *bbc += 1; - if (*bbc > *quota) { - ErrorMsg *msg = ir_add_error_node(ira, source_node, - buf_sprintf("evaluation exceeded %" ZIG_PRI_usize " backwards branches", *quota)); - add_error_note(ira->codegen, msg, source_node, - buf_sprintf("use @setEvalBranchQuota to raise branch limit from %" ZIG_PRI_usize, *quota)); - return false; - } - return true; -} - -static Stage1AirInst *ir_inline_bb(IrAnalyze *ira, AstNode* source_node, Stage1ZirBasicBlock *old_bb) { - if (old_bb->debug_id <= ira->zir_current_basic_block->debug_id) { - if (!ir_emit_backward_branch(ira, source_node)) - return ir_unreach_error(ira); - } - - old_bb->child = ira->zir_current_basic_block->child; - ir_start_bb(ira, old_bb, ira->zir_current_basic_block); - return ira->codegen->unreach_instruction; -} - -static Stage1AirInst *ir_finish_anal(IrAnalyze *ira, Stage1AirInst *instruction) { - if (instruction->value->type->id == ZigTypeIdUnreachable) - ir_finish_bb(ira); - return instruction; -} - -static Stage1AirInst *ir_const_fn(IrAnalyze *ira, Scope *scope, AstNode *source_node, ZigFn *fn_entry) { - Stage1AirInst *result = ir_const(ira, scope, source_node, fn_entry->type_entry); - result->value->special = ConstValSpecialStatic; - result->value->data.x_ptr.data.fn.fn_entry = fn_entry; - result->value->data.x_ptr.mut = ConstPtrMutComptimeConst; - result->value->data.x_ptr.special = ConstPtrSpecialFunction; - return result; -} - -static Stage1AirInst *ir_const_bound_fn(IrAnalyze *ira, Scope *scope, AstNode *source_node, - ZigFn *fn_entry, Stage1AirInst *first_arg, AstNode *first_arg_src) -{ - // This is unfortunately required to avoid improperly freeing first_arg_src - ira_ref(ira); - - Stage1AirInst *result = ir_const(ira, scope, source_node, get_bound_fn_type(ira->codegen, fn_entry)); - result->value->data.x_bound_fn.fn = fn_entry; - result->value->data.x_bound_fn.first_arg = first_arg; - result->value->data.x_bound_fn.first_arg_src = first_arg_src; - return result; -} - -static Stage1AirInst *ir_const_type(IrAnalyze *ira, Scope *scope, AstNode *source_node, ZigType *ty) { - Stage1AirInst *result = ir_const(ira, scope, source_node, ira->codegen->builtin_types.entry_type); - result->value->data.x_type = ty; - return result; -} - -static Stage1AirInst *ir_const_bool(IrAnalyze *ira, Scope *scope, AstNode *source_node, bool value) { - Stage1AirInst *result = ir_const(ira, scope, source_node, ira->codegen->builtin_types.entry_bool); - result->value->data.x_bool = value; - return result; -} - -static Stage1AirInst *ir_const_undef(IrAnalyze *ira, Scope *scope, AstNode *source_node, ZigType *ty) { - Stage1AirInst *result = ir_const(ira, scope, source_node, ty); - result->value->special = ConstValSpecialUndef; - return result; -} - -static Stage1AirInst *ir_const_unreachable(IrAnalyze *ira, Scope *scope, AstNode *source_node) { - Stage1AirInst *result = ir_const_noval(ira, scope, source_node); - result->value = ira->codegen->intern.for_unreachable(); - return result; -} - -static Stage1AirInst *ir_const_void(IrAnalyze *ira, Scope *scope, AstNode *source_node) { - Stage1AirInst *result = ir_const_noval(ira, scope, source_node); - result->value = ira->codegen->intern.for_void(); - return result; -} - -static Stage1AirInst *ir_const_unsigned(IrAnalyze *ira, Scope *scope, AstNode *source_node, uint64_t value) { - Stage1AirInst *result = ir_const(ira, scope, source_node, ira->codegen->builtin_types.entry_num_lit_int); - bigint_init_unsigned(&result->value->data.x_bigint, value); - return result; -} - -static Stage1AirInst *ir_get_const_ptr(IrAnalyze *ira, Scope *scope, AstNode *source_node, - ZigValue *pointee, ZigType *pointee_type, - ConstPtrMut ptr_mut, bool ptr_is_const, bool ptr_is_volatile, uint32_t ptr_align) -{ - ZigType *ptr_type = get_pointer_to_type_extra(ira->codegen, pointee_type, - ptr_is_const, ptr_is_volatile, PtrLenSingle, ptr_align, 0, 0, false); - Stage1AirInst *const_instr = ir_const(ira, scope, source_node, ptr_type); - ZigValue *const_val = const_instr->value; - const_val->data.x_ptr.special = ConstPtrSpecialRef; - const_val->data.x_ptr.mut = ptr_mut; - const_val->data.x_ptr.data.ref.pointee = pointee; - return const_instr; -} - -static Error ir_resolve_const_val(CodeGen *codegen, Stage1Air *exec, AstNode *source_node, - ZigValue *val, UndefAllowed undef_allowed) -{ - Error err; - for (;;) { - switch (val->special) { - case ConstValSpecialStatic: - return ErrorNone; - case ConstValSpecialRuntime: - if (!type_has_bits(codegen, val->type)) - return ErrorNone; - - exec_add_error_node_gen(codegen, exec, source_node, - buf_sprintf("unable to evaluate constant expression")); - return ErrorSemanticAnalyzeFail; - case ConstValSpecialUndef: - if (undef_allowed == UndefOk || undef_allowed == LazyOk) - return ErrorNone; - - exec_add_error_node_gen(codegen, exec, source_node, - buf_sprintf("use of undefined value here causes undefined behavior")); - return ErrorSemanticAnalyzeFail; - case ConstValSpecialLazy: - if (undef_allowed == LazyOk || undef_allowed == LazyOkNoUndef) - return ErrorNone; - - if ((err = ir_resolve_lazy(codegen, source_node, val))) - return err; - - continue; - } - } -} - -static ZigValue *ir_resolve_const(IrAnalyze *ira, Stage1AirInst *value, UndefAllowed undef_allowed) { - Error err; - if ((err = ir_resolve_const_val(ira->codegen, ira->new_irb.exec, value->source_node, - value->value, undef_allowed))) - { - return nullptr; - } - return value->value; -} - -Error ir_eval_const_value(CodeGen *codegen, Scope *scope, AstNode *node, - ZigValue *return_ptr, size_t *backward_branch_count, size_t *backward_branch_quota, - ZigFn *fn_entry, Buf *c_import_buf, AstNode *source_node, Buf *exec_name, - Stage1Air *parent_exec, AstNode *expected_type_source_node, UndefAllowed undef_allowed) -{ - Error err; - - src_assert(return_ptr->type->id == ZigTypeIdPointer, source_node); - - if (type_is_invalid(return_ptr->type)) - return ErrorSemanticAnalyzeFail; - - Stage1Zir *stage1_zir = heap::c_allocator.create(); - stage1_zir->name = exec_name; - stage1_zir->is_inline = true; - stage1_zir->begin_scope = scope; - - bool in_c_import_scope = c_import_buf != nullptr; - - if (!stage1_astgen(codegen, node, scope, stage1_zir, fn_entry, in_c_import_scope)) - return ErrorSemanticAnalyzeFail; - - if (stage1_zir->first_err_trace_msg != nullptr) { - codegen->trace_err = stage1_zir->first_err_trace_msg; - return ErrorSemanticAnalyzeFail; - } - - if (codegen->verbose_ir) { - fprintf(stderr, "\n{ // (IR)\n"); - ir_print_src(codegen, stderr, stage1_zir, 2); - fprintf(stderr, "}\n"); - } - Stage1Air *analyzed_executable = heap::c_allocator.create(); - analyzed_executable->source_node = source_node; - analyzed_executable->parent_exec = parent_exec; - analyzed_executable->source_exec = stage1_zir; - analyzed_executable->name = exec_name; - analyzed_executable->is_inline = true; - analyzed_executable->c_import_buf = c_import_buf; - analyzed_executable->begin_scope = scope; - ZigType *result_type = ir_analyze(codegen, stage1_zir, analyzed_executable, - backward_branch_count, backward_branch_quota, - return_ptr->type->data.pointer.child_type, expected_type_source_node, return_ptr, - fn_entry); - if (type_is_invalid(result_type)) { - return ErrorSemanticAnalyzeFail; - } - - if (codegen->verbose_ir) { - fprintf(stderr, "{ // (analyzed)\n"); - ir_print_gen(codegen, stderr, analyzed_executable, 2); - fprintf(stderr, "}\n"); - } - - if ((err = ir_exec_scan_for_side_effects(codegen, analyzed_executable))) - return err; - - ZigValue *result = const_ptr_pointee(nullptr, codegen, return_ptr, source_node); - if (result == nullptr) - return ErrorSemanticAnalyzeFail; - if ((err = ir_resolve_const_val(codegen, analyzed_executable, node, result, undef_allowed))) - return err; - - return ErrorNone; -} - -static ErrorTableEntry *ir_resolve_error(IrAnalyze *ira, Stage1AirInst *err_value) { - if (type_is_invalid(err_value->value->type)) - return nullptr; - - if (err_value->value->type->id != ZigTypeIdErrorSet) { - ir_add_error_node(ira, err_value->source_node, - buf_sprintf("expected error, found '%s'", buf_ptr(&err_value->value->type->name))); - return nullptr; - } - - ZigValue *const_val = ir_resolve_const(ira, err_value, UndefBad); - if (!const_val) - return nullptr; - - assert(const_val->data.x_err_set != nullptr); - return const_val->data.x_err_set; -} - -static ZigType *ir_resolve_const_type(CodeGen *codegen, Stage1Air *exec, AstNode *source_node, - ZigValue *val) -{ - Error err; - if ((err = ir_resolve_const_val(codegen, exec, source_node, val, UndefBad))) - return codegen->builtin_types.entry_invalid; - - assert(val->data.x_type != nullptr); - return val->data.x_type; -} - -static ZigValue *ir_resolve_type_lazy(IrAnalyze *ira, Stage1AirInst *type_value) { - if (type_is_invalid(type_value->value->type)) - return nullptr; - - if (type_value->value->type->id != ZigTypeIdMetaType) { - ir_add_error_node(ira, type_value->source_node, - buf_sprintf("expected type 'type', found '%s'", buf_ptr(&type_value->value->type->name))); - return nullptr; - } - - Error err; - if ((err = ir_resolve_const_val(ira->codegen, ira->new_irb.exec, type_value->source_node, - type_value->value, LazyOkNoUndef))) - { - return nullptr; - } - - return type_value->value; -} - -static ZigType *ir_resolve_type(IrAnalyze *ira, Stage1AirInst *type_value) { - ZigValue *val = ir_resolve_type_lazy(ira, type_value); - if (val == nullptr) - return ira->codegen->builtin_types.entry_invalid; - - return ir_resolve_const_type(ira->codegen, ira->new_irb.exec, type_value->source_node, val); -} - -static Error ir_validate_vector_elem_type(IrAnalyze *ira, AstNode *source_node, ZigType *elem_type) { - Error err; - bool is_valid; - if ((err = is_valid_vector_elem_type(ira->codegen, elem_type, &is_valid))) - return err; - if (!is_valid) { - ir_add_error_node(ira, source_node, - buf_sprintf("vector element type must be integer, float, bool, or pointer; '%s' is invalid", - buf_ptr(&elem_type->name))); - return ErrorSemanticAnalyzeFail; - } - return ErrorNone; -} - -static ZigType *ir_resolve_vector_elem_type(IrAnalyze *ira, Stage1AirInst *elem_type_value) { - Error err; - ZigType *elem_type = ir_resolve_type(ira, elem_type_value); - if (type_is_invalid(elem_type)) - return ira->codegen->builtin_types.entry_invalid; - if ((err = ir_validate_vector_elem_type(ira, elem_type_value->source_node, elem_type))) - return ira->codegen->builtin_types.entry_invalid; - return elem_type; -} - -static ZigType *ir_resolve_int_type(IrAnalyze *ira, Stage1AirInst *type_value) { - ZigType *ty = ir_resolve_type(ira, type_value); - if (type_is_invalid(ty)) - return ira->codegen->builtin_types.entry_invalid; - - if (ty->id != ZigTypeIdInt) { - ErrorMsg *msg = ir_add_error_node(ira, type_value->source_node, - buf_sprintf("expected integer type, found '%s'", buf_ptr(&ty->name))); - if (ty->id == ZigTypeIdVector && - ty->data.vector.elem_type->id == ZigTypeIdInt) - { - add_error_note(ira->codegen, msg, type_value->source_node, - buf_sprintf("represent vectors with their element types, i.e. '%s'", - buf_ptr(&ty->data.vector.elem_type->name))); - } - return ira->codegen->builtin_types.entry_invalid; - } - - return ty; -} - -static ZigType *ir_resolve_error_set_type(IrAnalyze *ira, AstNode *op_source, Stage1AirInst *type_value) { - if (type_is_invalid(type_value->value->type)) - return ira->codegen->builtin_types.entry_invalid; - - if (type_value->value->type->id != ZigTypeIdMetaType) { - ErrorMsg *msg = ir_add_error_node(ira, type_value->source_node, - buf_sprintf("expected error set type, found '%s'", buf_ptr(&type_value->value->type->name))); - add_error_note(ira->codegen, msg, op_source, - buf_sprintf("`||` merges error sets; `or` performs boolean OR")); - return ira->codegen->builtin_types.entry_invalid; - } - - ZigValue *const_val = ir_resolve_const(ira, type_value, UndefBad); - if (!const_val) - return ira->codegen->builtin_types.entry_invalid; - - assert(const_val->data.x_type != nullptr); - ZigType *result_type = const_val->data.x_type; - if (result_type->id != ZigTypeIdErrorSet) { - ErrorMsg *msg = ir_add_error_node(ira, type_value->source_node, - buf_sprintf("expected error set type, found type '%s'", buf_ptr(&result_type->name))); - add_error_note(ira->codegen, msg, op_source, - buf_sprintf("`||` merges error sets; `or` performs boolean OR")); - return ira->codegen->builtin_types.entry_invalid; - } - return result_type; -} - -static ZigFn *ir_resolve_fn(IrAnalyze *ira, Stage1AirInst *fn_value) { - if (type_is_invalid(fn_value->value->type)) - return nullptr; - - if (fn_value->value->type->id != ZigTypeIdFn) { - ir_add_error_node(ira, fn_value->source_node, - buf_sprintf("expected function type, found '%s'", buf_ptr(&fn_value->value->type->name))); - return nullptr; - } - - ZigValue *const_val = ir_resolve_const(ira, fn_value, UndefBad); - if (!const_val) - return nullptr; - - // May be a ConstPtrSpecialHardCodedAddr - if (const_val->data.x_ptr.special != ConstPtrSpecialFunction) - return nullptr; - - return const_val->data.x_ptr.data.fn.fn_entry; -} - -static Stage1AirInst *ir_analyze_optional_wrap(IrAnalyze *ira, Scope *scope, AstNode *source_node, - Stage1AirInst *value, ZigType *wanted_type, ResultLoc *result_loc) -{ - assert(wanted_type->id == ZigTypeIdOptional); - - if (instr_is_comptime(value)) { - ZigType *payload_type = wanted_type->data.maybe.child_type; - Stage1AirInst *casted_payload = ir_implicit_cast(ira, value, payload_type); - if (type_is_invalid(casted_payload->value->type)) - return ira->codegen->invalid_inst_gen; - - ZigValue *val = ir_resolve_const(ira, casted_payload, UndefOk); - if (!val) - return ira->codegen->invalid_inst_gen; - - Stage1AirInstConst *const_instruction = ir_create_inst_gen(&ira->new_irb, - scope, source_node); - const_instruction->base.value->special = ConstValSpecialStatic; - if (types_have_same_zig_comptime_repr(ira->codegen, wanted_type, payload_type)) { - copy_const_val(ira->codegen, const_instruction->base.value, val); - } else { - const_instruction->base.value->data.x_optional = val; - } - const_instruction->base.value->type = wanted_type; - return &const_instruction->base; - } - - if (result_loc == nullptr && handle_is_ptr(ira->codegen, wanted_type)) { - result_loc = no_result_loc(); - } - Stage1AirInst *result_loc_inst = nullptr; - if (result_loc != nullptr) { - result_loc_inst = ir_resolve_result(ira, ira->suspend_source_instr, result_loc, wanted_type, nullptr, true, true); - if (type_is_invalid(result_loc_inst->value->type) || - result_loc_inst->value->type->id == ZigTypeIdUnreachable) - { - return result_loc_inst; - } - } - Stage1AirInst *result = ir_build_optional_wrap(ira, scope, source_node, wanted_type, value, result_loc_inst); - result->value->data.rh_maybe = RuntimeHintOptionalNonNull; - return result; -} - -static Stage1AirInst *ir_analyze_err_wrap_payload(IrAnalyze *ira, Scope *scope, AstNode *source_node, - Stage1AirInst *value, ZigType *wanted_type, ResultLoc *result_loc) -{ - assert(wanted_type->id == ZigTypeIdErrorUnion); - - ZigType *payload_type = wanted_type->data.error_union.payload_type; - ZigType *err_set_type = wanted_type->data.error_union.err_set_type; - if (instr_is_comptime(value)) { - Stage1AirInst *casted_payload = ir_implicit_cast(ira, value, payload_type); - if (type_is_invalid(casted_payload->value->type)) - return ira->codegen->invalid_inst_gen; - - ZigValue *val = ir_resolve_const(ira, casted_payload, UndefOk); - if (val == nullptr) - return ira->codegen->invalid_inst_gen; - - ZigValue *err_set_val = ira->codegen->pass1_arena->create(); - err_set_val->type = err_set_type; - err_set_val->special = ConstValSpecialStatic; - err_set_val->data.x_err_set = nullptr; - - Stage1AirInstConst *const_instruction = ir_create_inst_gen(&ira->new_irb, - scope, source_node); - const_instruction->base.value->type = wanted_type; - const_instruction->base.value->special = ConstValSpecialStatic; - const_instruction->base.value->data.x_err_union.error_set = err_set_val; - const_instruction->base.value->data.x_err_union.payload = val; - return &const_instruction->base; - } - - Stage1AirInst *result_loc_inst; - if (handle_is_ptr(ira->codegen, wanted_type)) { - if (result_loc == nullptr) result_loc = no_result_loc(); - result_loc_inst = ir_resolve_result(ira, ira->suspend_source_instr, result_loc, wanted_type, nullptr, true, true); - if (type_is_invalid(result_loc_inst->value->type) || - result_loc_inst->value->type->id == ZigTypeIdUnreachable) { - return result_loc_inst; - } - } else { - result_loc_inst = nullptr; - } - - Stage1AirInst *result = ir_build_err_wrap_payload(ira, scope, source_node, wanted_type, value, result_loc_inst); - result->value->data.rh_error_union = RuntimeHintErrorUnionNonError; - return result; -} - -static Stage1AirInst *ir_analyze_err_set_cast(IrAnalyze *ira, Scope *scope, AstNode *source_node, Stage1AirInst *value, - ZigType *wanted_type) -{ - assert(value->value->type->id == ZigTypeIdErrorSet); - assert(wanted_type->id == ZigTypeIdErrorSet); - - if (instr_is_comptime(value)) { - ZigValue *val = ir_resolve_const(ira, value, UndefBad); - if (!val) - return ira->codegen->invalid_inst_gen; - - if (!resolve_inferred_error_set(ira->codegen, wanted_type, source_node)) { - return ira->codegen->invalid_inst_gen; - } - if (!type_is_global_error_set(wanted_type)) { - bool subset = false; - for (uint32_t i = 0, count = wanted_type->data.error_set.err_count; i < count; i += 1) { - if (wanted_type->data.error_set.errors[i]->value == val->data.x_err_set->value) { - subset = true; - break; - } - } - if (!subset) { - ir_add_error_node(ira, source_node, - buf_sprintf("error.%s not a member of error set '%s'", - buf_ptr(&val->data.x_err_set->name), buf_ptr(&wanted_type->name))); - return ira->codegen->invalid_inst_gen; - } - } - - Stage1AirInstConst *const_instruction = ir_create_inst_gen(&ira->new_irb, - scope, source_node); - const_instruction->base.value->type = wanted_type; - const_instruction->base.value->special = ConstValSpecialStatic; - const_instruction->base.value->data.x_err_set = val->data.x_err_set; - return &const_instruction->base; - } - - return ir_build_cast(ira, scope, source_node, wanted_type, value, CastOpErrSet); -} - -static Stage1AirInst *ir_analyze_frame_ptr_to_anyframe(IrAnalyze *ira, Scope *scope, AstNode *source_node, - Stage1AirInst *frame_ptr, ZigType *wanted_type) -{ - if (instr_is_comptime(frame_ptr)) { - ZigValue *ptr_val = ir_resolve_const(ira, frame_ptr, UndefBad); - if (ptr_val == nullptr) - return ira->codegen->invalid_inst_gen; - - src_assert(ptr_val->type->id == ZigTypeIdPointer, source_node ); - if (ptr_val->data.x_ptr.mut != ConstPtrMutRuntimeVar) { - zig_panic("TODO comptime frame pointer"); - } - } - - return ir_build_cast(ira, scope, source_node, wanted_type, frame_ptr, CastOpBitCast); -} - -static Stage1AirInst *ir_analyze_anyframe_to_anyframe(IrAnalyze *ira, Scope *scope, AstNode *source_node, - Stage1AirInst *value, ZigType *wanted_type) -{ - if (instr_is_comptime(value)) { - zig_panic("TODO comptime anyframe->T to anyframe"); - } - - return ir_build_cast(ira, scope, source_node, wanted_type, value, CastOpBitCast); -} - - -static Stage1AirInst *ir_analyze_err_wrap_code(IrAnalyze *ira, Scope *scope, AstNode *source_node, Stage1AirInst *value, - ZigType *wanted_type, ResultLoc *result_loc) -{ - assert(wanted_type->id == ZigTypeIdErrorUnion); - - Stage1AirInst *casted_value = ir_implicit_cast(ira, value, wanted_type->data.error_union.err_set_type); - - if (instr_is_comptime(casted_value)) { - ZigValue *val = ir_resolve_const(ira, casted_value, UndefBad); - if (!val) - return ira->codegen->invalid_inst_gen; - - ZigValue *err_set_val = ira->codegen->pass1_arena->create(); - err_set_val->special = ConstValSpecialStatic; - err_set_val->type = wanted_type->data.error_union.err_set_type; - err_set_val->data.x_err_set = val->data.x_err_set; - - Stage1AirInstConst *const_instruction = ir_create_inst_gen(&ira->new_irb, - scope, source_node); - const_instruction->base.value->type = wanted_type; - const_instruction->base.value->special = ConstValSpecialStatic; - const_instruction->base.value->data.x_err_union.error_set = err_set_val; - const_instruction->base.value->data.x_err_union.payload = nullptr; - return &const_instruction->base; - } - - Stage1AirInst *result_loc_inst; - if (handle_is_ptr(ira->codegen, wanted_type)) { - if (result_loc == nullptr) result_loc = no_result_loc(); - result_loc_inst = ir_resolve_result(ira, ira->suspend_source_instr, result_loc, wanted_type, nullptr, true, true); - if (type_is_invalid(result_loc_inst->value->type) || - result_loc_inst->value->type->id == ZigTypeIdUnreachable) - { - return result_loc_inst; - } - } else { - result_loc_inst = nullptr; - } - - - Stage1AirInst *result = ir_build_err_wrap_code(ira, scope, source_node, wanted_type, value, result_loc_inst); - result->value->data.rh_error_union = RuntimeHintErrorUnionError; - return result; -} - -static Stage1AirInst *ir_analyze_null_to_maybe(IrAnalyze *ira, Scope *scope, AstNode *source_node, Stage1AirInst *value, ZigType *wanted_type) { - assert(wanted_type->id == ZigTypeIdOptional); - assert(instr_is_comptime(value)); - - ZigValue *val = ir_resolve_const(ira, value, UndefBad); - assert(val != nullptr); - - Stage1AirInst *result = ir_const(ira, scope, source_node, wanted_type); - result->value->special = ConstValSpecialStatic; - - if (get_src_ptr_type(wanted_type) != nullptr) { - result->value->data.x_ptr.special = ConstPtrSpecialNull; - } else if (is_opt_err_set(wanted_type)) { - result->value->data.x_err_set = nullptr; - } else { - result->value->data.x_optional = nullptr; - } - return result; -} - -static Stage1AirInst *ir_analyze_null_to_c_pointer(IrAnalyze *ira, Scope *scope, AstNode *source_node, - Stage1AirInst *value, ZigType *wanted_type) -{ - assert(wanted_type->id == ZigTypeIdPointer); - assert(wanted_type->data.pointer.ptr_len == PtrLenC); - assert(instr_is_comptime(value)); - - ZigValue *val = ir_resolve_const(ira, value, UndefBad); - assert(val != nullptr); - - Stage1AirInst *result = ir_const(ira, scope, source_node, wanted_type); - result->value->data.x_ptr.special = ConstPtrSpecialNull; - result->value->data.x_ptr.mut = ConstPtrMutComptimeConst; - return result; -} - -static Stage1AirInst *ir_get_ref2(IrAnalyze *ira, Scope *scope, AstNode *source_node, Stage1AirInst *value, - ZigType *elem_type, bool is_const, bool is_volatile) -{ - Error err; - - if (type_is_invalid(elem_type)) - return ira->codegen->invalid_inst_gen; - - if (instr_is_comptime(value)) { - ZigValue *val = ir_resolve_const(ira, value, LazyOk); - if (!val) - return ira->codegen->invalid_inst_gen; - return ir_get_const_ptr(ira, scope, source_node, val, elem_type, - ConstPtrMutComptimeConst, is_const, is_volatile, 0); - } - - ZigType *ptr_type = get_pointer_to_type_extra(ira->codegen, elem_type, - is_const, is_volatile, PtrLenSingle, 0, 0, 0, false); - - if ((err = type_resolve(ira->codegen, ptr_type, ResolveStatusZeroBitsKnown))) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *result_loc; - if (type_has_bits(ira->codegen, ptr_type) && !handle_is_ptr(ira->codegen, elem_type)) { - result_loc = ir_resolve_result(ira, ira->suspend_source_instr, no_result_loc(), elem_type, nullptr, true, true); - } else { - result_loc = nullptr; - } - - Stage1AirInst *new_instruction = ir_build_ref_gen(ira, scope, source_node, ptr_type, value, result_loc); - new_instruction->value->data.rh_ptr = RuntimeHintPtrStack; - return new_instruction; -} - -static Stage1AirInst *ir_get_ref(IrAnalyze *ira, Scope *scope, AstNode *source_node, Stage1AirInst *value, - bool is_const, bool is_volatile) -{ - return ir_get_ref2(ira, scope, source_node, value, value->value->type, is_const, is_volatile); -} - -static ZigType *ir_resolve_union_tag_type(IrAnalyze *ira, AstNode *source_node, ZigType *union_type) { - assert(union_type->id == ZigTypeIdUnion); - - Error err; - if ((err = type_resolve(ira->codegen, union_type, ResolveStatusSizeKnown))) - return ira->codegen->builtin_types.entry_invalid; - - AstNode *decl_node = union_type->data.unionation.decl_node; - if (decl_node->data.container_decl.auto_enum || decl_node->data.container_decl.init_arg_expr != nullptr) { - assert(union_type->data.unionation.tag_type != nullptr); - return union_type->data.unionation.tag_type; - } else { - ErrorMsg *msg = ir_add_error_node(ira, source_node, buf_sprintf("union '%s' has no tag", - buf_ptr(&union_type->name))); - add_error_note(ira->codegen, msg, decl_node, buf_sprintf("consider 'union(enum)' here")); - return ira->codegen->builtin_types.entry_invalid; - } -} - -static bool can_fold_enum_type(ZigType *ty) { - assert(ty->id == ZigTypeIdEnum); - // We can fold the enum type (and avoid any check, be it at runtime or at - // compile time) iff it has only a single element and its tag type is - // zero-sized. - ZigType *tag_int_type = ty->data.enumeration.tag_int_type; - return ty->data.enumeration.layout == ContainerLayoutAuto && - ty->data.enumeration.src_field_count == 1 && - !ty->data.enumeration.non_exhaustive && - (tag_int_type->id == ZigTypeIdInt && tag_int_type->data.integral.bit_count == 0); -} - -static Stage1AirInst *ir_analyze_enum_to_int(IrAnalyze *ira, Scope *scope, AstNode *source_node, Stage1AirInst *target) { - Error err; - - Stage1AirInst *enum_target; - ZigType *enum_type; - if (target->value->type->id == ZigTypeIdUnion) { - enum_type = ir_resolve_union_tag_type(ira, target->source_node, target->value->type); - if (type_is_invalid(enum_type)) - return ira->codegen->invalid_inst_gen; - enum_target = ir_implicit_cast(ira, target, enum_type); - if (type_is_invalid(enum_target->value->type)) - return ira->codegen->invalid_inst_gen; - } else if (target->value->type->id == ZigTypeIdEnum) { - enum_target = target; - enum_type = target->value->type; - } else { - ir_add_error_node(ira, target->source_node, - buf_sprintf("expected enum, found type '%s'", buf_ptr(&target->value->type->name))); - return ira->codegen->invalid_inst_gen; - } - - if ((err = type_resolve(ira->codegen, enum_type, ResolveStatusSizeKnown))) - return ira->codegen->invalid_inst_gen; - - ZigType *tag_type = enum_type->data.enumeration.tag_int_type; - assert(tag_type->id == ZigTypeIdInt || tag_type->id == ZigTypeIdComptimeInt); - - // If there is only one possible tag, then we know at comptime what it is. - if (can_fold_enum_type(enum_type)) { - Stage1AirInst *result = ir_const(ira, scope, source_node, tag_type); - init_const_bigint(result->value, tag_type, - &enum_type->data.enumeration.fields[0].value); - return result; - } - - if (instr_is_comptime(enum_target)) { - ZigValue *val = ir_resolve_const(ira, enum_target, UndefBad); - if (!val) - return ira->codegen->invalid_inst_gen; - Stage1AirInst *result = ir_const(ira, scope, source_node, tag_type); - init_const_bigint(result->value, tag_type, &val->data.x_enum_tag); - return result; - } - - return ir_build_widen_or_shorten(ira, scope, source_node, enum_target, tag_type); -} - -static Stage1AirInst *ir_analyze_union_to_tag(IrAnalyze *ira, Scope *scope, AstNode *source_node, - Stage1AirInst *target, ZigType *wanted_type) -{ - assert(target->value->type->id == ZigTypeIdUnion); - assert(wanted_type->id == ZigTypeIdEnum); - assert(wanted_type == target->value->type->data.unionation.tag_type); - - if (instr_is_comptime(target)) { - ZigValue *val = ir_resolve_const(ira, target, UndefBad); - if (!val) - return ira->codegen->invalid_inst_gen; - Stage1AirInst *result = ir_const(ira, scope, source_node, wanted_type); - result->value->special = ConstValSpecialStatic; - result->value->type = wanted_type; - bigint_init_bigint(&result->value->data.x_enum_tag, &val->data.x_union.tag); - return result; - } - - // If there is only 1 possible tag, then we know at comptime what it is. - if (can_fold_enum_type(wanted_type)) { - Stage1AirInst *result = ir_const(ira, scope, source_node, wanted_type); - result->value->special = ConstValSpecialStatic; - result->value->type = wanted_type; - TypeEnumField *enum_field = target->value->type->data.unionation.fields[0].enum_field; - bigint_init_bigint(&result->value->data.x_enum_tag, &enum_field->value); - return result; - } - - return ir_build_union_tag(ira, scope, source_node, target, wanted_type); -} - -static Stage1AirInst *ir_analyze_undefined_to_anything(IrAnalyze *ira, Scope *scope, AstNode *source_node, - Stage1AirInst *target, ZigType *wanted_type) -{ - Stage1AirInst *result = ir_const(ira, scope, source_node, wanted_type); - result->value->special = ConstValSpecialUndef; - return result; -} - -static Stage1AirInst *ir_analyze_enum_to_union(IrAnalyze *ira, Scope *scope, AstNode *source_node, - Stage1AirInst *uncasted_target, ZigType *wanted_type) -{ - Error err; - assert(wanted_type->id == ZigTypeIdUnion); - - if ((err = type_resolve(ira->codegen, wanted_type, ResolveStatusZeroBitsKnown))) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *target = ir_implicit_cast(ira, uncasted_target, wanted_type->data.unionation.tag_type); - if (type_is_invalid(target->value->type)) - return ira->codegen->invalid_inst_gen; - - if (instr_is_comptime(target)) { - ZigValue *val = ir_resolve_const(ira, target, UndefBad); - if (!val) - return ira->codegen->invalid_inst_gen; - TypeUnionField *union_field = find_union_field_by_tag(wanted_type, &val->data.x_enum_tag); - if (union_field == nullptr) { - Buf *int_buf = buf_alloc(); - bigint_append_buf(int_buf, &target->value->data.x_enum_tag, 10); - - ir_add_error(ira, target, - buf_sprintf("no tag by value %s", buf_ptr(int_buf))); - return ira->codegen->invalid_inst_gen; - } - ZigType *field_type = resolve_union_field_type(ira->codegen, union_field); - if (field_type == nullptr) - return ira->codegen->invalid_inst_gen; - if ((err = type_resolve(ira->codegen, field_type, ResolveStatusZeroBitsKnown))) - return ira->codegen->invalid_inst_gen; - - switch (type_has_one_possible_value(ira->codegen, field_type)) { - case OnePossibleValueInvalid: - return ira->codegen->invalid_inst_gen; - case OnePossibleValueNo: { - AstNode *field_node = wanted_type->data.unionation.decl_node->data.container_decl.fields.at( - union_field->enum_field->decl_index); - ErrorMsg *msg = ir_add_error_node(ira, source_node, - buf_sprintf("cast to union '%s' must initialize '%s' field '%s'", - buf_ptr(&wanted_type->name), - buf_ptr(&field_type->name), - buf_ptr(union_field->name))); - add_error_note(ira->codegen, msg, field_node, - buf_sprintf("field '%s' declared here", buf_ptr(union_field->name))); - return ira->codegen->invalid_inst_gen; - } - case OnePossibleValueYes: - break; - } - - Stage1AirInst *result = ir_const(ira, scope, source_node, wanted_type); - result->value->special = ConstValSpecialStatic; - result->value->type = wanted_type; - bigint_init_bigint(&result->value->data.x_union.tag, &val->data.x_enum_tag); - result->value->data.x_union.payload = ira->codegen->pass1_arena->create(); - result->value->data.x_union.payload->special = ConstValSpecialStatic; - result->value->data.x_union.payload->type = field_type; - return result; - } - - if (target->value->type->data.enumeration.non_exhaustive) { - ir_add_error_node(ira, source_node, - buf_sprintf("runtime cast to union '%s' from non-exhaustive enum", - buf_ptr(&wanted_type->name))); - return ira->codegen->invalid_inst_gen; - } - - // if the union has all fields 0 bits, we can do it - // and in fact it's a noop cast because the union value is just the enum value - if (wanted_type->data.unionation.gen_field_count == 0) { - return ir_build_cast(ira, target->scope, target->source_node, wanted_type, target, CastOpNoop); - } - - ErrorMsg *msg = ir_add_error_node(ira, source_node, - buf_sprintf("runtime cast to union '%s' which has non-void fields", - buf_ptr(&wanted_type->name))); - for (uint32_t i = 0; i < wanted_type->data.unionation.src_field_count; i += 1) { - TypeUnionField *union_field = &wanted_type->data.unionation.fields[i]; - ZigType *field_type = resolve_union_field_type(ira->codegen, union_field); - if (field_type == nullptr) - return ira->codegen->invalid_inst_gen; - bool has_bits; - if ((err = type_has_bits2(ira->codegen, field_type, &has_bits))) - return ira->codegen->invalid_inst_gen; - if (has_bits) { - AstNode *field_node = wanted_type->data.unionation.decl_node->data.container_decl.fields.at(i); - add_error_note(ira->codegen, msg, field_node, - buf_sprintf("field '%s' has type '%s'", - buf_ptr(union_field->name), - buf_ptr(&field_type->name))); - } - } - return ira->codegen->invalid_inst_gen; -} - -static bool value_numeric_fits_in_type(ZigValue *value, ZigType *type_entry); - -static Stage1AirInst *ir_analyze_widen_or_shorten(IrAnalyze *ira, Scope *scope, AstNode *source_node, - Stage1AirInst *target, ZigType *wanted_type) -{ - ZigType *wanted_scalar_type = (target->value->type->id == ZigTypeIdVector) ? - wanted_type->data.vector.elem_type : wanted_type; - - assert(wanted_scalar_type->id == ZigTypeIdInt || wanted_scalar_type->id == ZigTypeIdFloat); - - if (instr_is_comptime(target)) { - ZigValue *val = ir_resolve_const(ira, target, UndefBad); - if (!val) - return ira->codegen->invalid_inst_gen; - - if (wanted_scalar_type->id == ZigTypeIdInt) { - if (!wanted_scalar_type->data.integral.is_signed && value_cmp_numeric_val_any(val, CmpLT, nullptr)) { - ir_add_error_node(ira, source_node, - buf_sprintf("attempt to cast negative value to unsigned integer")); - return ira->codegen->invalid_inst_gen; - } - if (!value_numeric_fits_in_type(val, wanted_scalar_type)) { - ir_add_error_node(ira, source_node, - buf_sprintf("cast from '%s' to '%s' truncates bits", - buf_ptr(&target->value->type->name), buf_ptr(&wanted_scalar_type->name))); - return ira->codegen->invalid_inst_gen; - } - } - - Stage1AirInst *result = ir_const(ira, scope, source_node, wanted_type); - result->value->type = wanted_type; - - if (wanted_type->id == ZigTypeIdVector) { - result->value->data.x_array.data.s_none.elements = ira->codegen->pass1_arena->allocate(wanted_type->data.vector.len); - - for (size_t i = 0; i < wanted_type->data.vector.len; i++) { - ZigValue *scalar_dest_value = &result->value->data.x_array.data.s_none.elements[i]; - ZigValue *scalar_src_value = &val->data.x_array.data.s_none.elements[i]; - - scalar_dest_value->type = wanted_scalar_type; - scalar_dest_value->special = ConstValSpecialStatic; - - if (wanted_scalar_type->id == ZigTypeIdInt) { - bigint_init_bigint(&scalar_dest_value->data.x_bigint, &scalar_src_value->data.x_bigint); - } else { - float_init_float(scalar_dest_value, scalar_src_value); - } - } - } else { - if (wanted_type->id == ZigTypeIdInt) { - bigint_init_bigint(&result->value->data.x_bigint, &val->data.x_bigint); - } else { - float_init_float(result->value, val); - } - } - - return result; - } - - // If the destination integer type has no bits, then we can emit a comptime - // zero. However, we still want to emit a runtime safety check to make sure - // the target is zero. - if (!type_has_bits(ira->codegen, wanted_type)) { - assert(wanted_type->id == ZigTypeIdInt); - assert(type_has_bits(ira->codegen, target->value->type)); - ir_build_assert_zero(ira, scope, source_node, target); - Stage1AirInst *result = ir_const_unsigned(ira, scope, source_node, 0); - result->value->type = wanted_type; - return result; - } - - return ir_build_widen_or_shorten(ira, scope, source_node, target, wanted_type); -} - -static Stage1AirInst *ir_analyze_int_to_enum(IrAnalyze *ira, Scope *scope, AstNode *source_node, - Stage1AirInst *target, ZigType *wanted_type) -{ - Error err; - assert(wanted_type->id == ZigTypeIdEnum); - - ZigType *actual_type = target->value->type; - - if ((err = type_resolve(ira->codegen, wanted_type, ResolveStatusSizeKnown))) - return ira->codegen->invalid_inst_gen; - - if (actual_type != wanted_type->data.enumeration.tag_int_type) { - ir_add_error_node(ira, source_node, - buf_sprintf("integer to enum cast from '%s' instead of its tag type, '%s'", - buf_ptr(&actual_type->name), - buf_ptr(&wanted_type->data.enumeration.tag_int_type->name))); - return ira->codegen->invalid_inst_gen; - } - - assert(actual_type->id == ZigTypeIdInt || actual_type->id == ZigTypeIdComptimeInt); - - if (instr_is_comptime(target)) { - ZigValue *val = ir_resolve_const(ira, target, UndefBad); - if (!val) - return ira->codegen->invalid_inst_gen; - - TypeEnumField *field = find_enum_field_by_tag(wanted_type, &val->data.x_bigint); - if (field == nullptr && !wanted_type->data.enumeration.non_exhaustive) { - Buf *val_buf = buf_alloc(); - bigint_append_buf(val_buf, &val->data.x_bigint, 10); - ErrorMsg *msg = ir_add_error_node(ira, source_node, - buf_sprintf("enum '%s' has no tag matching integer value %s", - buf_ptr(&wanted_type->name), buf_ptr(val_buf))); - add_error_note(ira->codegen, msg, wanted_type->data.enumeration.decl_node, - buf_sprintf("'%s' declared here", buf_ptr(&wanted_type->name))); - return ira->codegen->invalid_inst_gen; - } - - Stage1AirInst *result = ir_const(ira, scope, source_node, wanted_type); - bigint_init_bigint(&result->value->data.x_enum_tag, &val->data.x_bigint); - return result; - } - - return ir_build_int_to_enum_gen(ira, scope, source_node, wanted_type, target); -} - -static Stage1AirInst *ir_analyze_number_to_literal(IrAnalyze *ira, Scope *scope, AstNode *source_node, - Stage1AirInst *target, ZigType *wanted_type) -{ - ZigValue *val = ir_resolve_const(ira, target, UndefBad); - if (!val) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *result = ir_const(ira, scope, source_node, wanted_type); - if (wanted_type->id == ZigTypeIdComptimeFloat) { - float_init_float(result->value, val); - } else if (wanted_type->id == ZigTypeIdComptimeInt) { - bigint_init_bigint(&result->value->data.x_bigint, &val->data.x_bigint); - } else { - zig_unreachable(); - } - return result; -} - -static Stage1AirInst *ir_analyze_int_to_err(IrAnalyze *ira, Scope *scope, AstNode *source_node, Stage1AirInst *target, - ZigType *wanted_type) -{ - assert(target->value->type->id == ZigTypeIdInt); - assert(!target->value->type->data.integral.is_signed); - assert(wanted_type->id == ZigTypeIdErrorSet); - - if (instr_is_comptime(target)) { - ZigValue *val = ir_resolve_const(ira, target, UndefBad); - if (!val) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *result = ir_const(ira, scope, source_node, wanted_type); - - if (!resolve_inferred_error_set(ira->codegen, wanted_type, source_node)) { - return ira->codegen->invalid_inst_gen; - } - - if (type_is_global_error_set(wanted_type)) { - BigInt err_count; - bigint_init_unsigned(&err_count, ira->codegen->errors_by_index.length); - - if (bigint_cmp_zero(&val->data.x_bigint) == CmpEQ || bigint_cmp(&val->data.x_bigint, &err_count) != CmpLT) { - Buf *val_buf = buf_alloc(); - bigint_append_buf(val_buf, &val->data.x_bigint, 10); - ir_add_error_node(ira, source_node, - buf_sprintf("integer value %s represents no error", buf_ptr(val_buf))); - return ira->codegen->invalid_inst_gen; - } - - size_t index = bigint_as_usize(&val->data.x_bigint); - result->value->data.x_err_set = ira->codegen->errors_by_index.at(index); - return result; - } else { - ErrorTableEntry *err = nullptr; - BigInt err_int; - - for (uint32_t i = 0, count = wanted_type->data.error_set.err_count; i < count; i += 1) { - ErrorTableEntry *this_err = wanted_type->data.error_set.errors[i]; - bigint_init_unsigned(&err_int, this_err->value); - if (bigint_cmp(&val->data.x_bigint, &err_int) == CmpEQ) { - err = this_err; - break; - } - } - - if (err == nullptr) { - Buf *val_buf = buf_alloc(); - bigint_append_buf(val_buf, &val->data.x_bigint, 10); - ir_add_error_node(ira, source_node, - buf_sprintf("integer value %s represents no error in '%s'", buf_ptr(val_buf), buf_ptr(&wanted_type->name))); - return ira->codegen->invalid_inst_gen; - } - - result->value->data.x_err_set = err; - return result; - } - } - - return ir_build_int_to_err_gen(ira, scope, source_node, target, wanted_type); -} - -static Stage1AirInst *ir_analyze_err_to_int(IrAnalyze *ira, Scope *scope, AstNode *source_node, Stage1AirInst *target, - ZigType *wanted_type) -{ - assert(wanted_type->id == ZigTypeIdInt); - - ZigType *err_type = target->value->type; - - if (instr_is_comptime(target)) { - ZigValue *val = ir_resolve_const(ira, target, UndefBad); - if (!val) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *result = ir_const(ira, scope, source_node, wanted_type); - - ErrorTableEntry *err; - if (err_type->id == ZigTypeIdErrorUnion) { - err = val->data.x_err_union.error_set->data.x_err_set; - } else if (err_type->id == ZigTypeIdErrorSet) { - err = val->data.x_err_set; - } else { - zig_unreachable(); - } - result->value->type = wanted_type; - uint64_t err_value = err ? err->value : 0; - bigint_init_unsigned(&result->value->data.x_bigint, err_value); - - if (!bigint_fits_in_bits(&result->value->data.x_bigint, - wanted_type->data.integral.bit_count, wanted_type->data.integral.is_signed)) - { - ir_add_error_node(ira, source_node, - buf_sprintf("error code '%s' does not fit in '%s'", - buf_ptr(&err->name), buf_ptr(&wanted_type->name))); - return ira->codegen->invalid_inst_gen; - } - - return result; - } - - ZigType *err_set_type; - if (err_type->id == ZigTypeIdErrorUnion) { - err_set_type = err_type->data.error_union.err_set_type; - } else if (err_type->id == ZigTypeIdErrorSet) { - err_set_type = err_type; - } else { - zig_unreachable(); - } - if (!type_is_global_error_set(err_set_type)) { - if (!resolve_inferred_error_set(ira->codegen, err_set_type, source_node)) { - return ira->codegen->invalid_inst_gen; - } - if (err_set_type->data.error_set.err_count == 0) { - Stage1AirInst *result = ir_const(ira, scope, source_node, wanted_type); - bigint_init_unsigned(&result->value->data.x_bigint, 0); - return result; - } else if (err_set_type->data.error_set.err_count == 1) { - Stage1AirInst *result = ir_const(ira, scope, source_node, wanted_type); - ErrorTableEntry *err = err_set_type->data.error_set.errors[0]; - bigint_init_unsigned(&result->value->data.x_bigint, err->value); - return result; - } - } - - BigInt bn; - bigint_init_unsigned(&bn, ira->codegen->errors_by_index.length); - if (!bigint_fits_in_bits(&bn, wanted_type->data.integral.bit_count, wanted_type->data.integral.is_signed)) { - ir_add_error_node(ira, source_node, - buf_sprintf("too many error values to fit in '%s'", buf_ptr(&wanted_type->name))); - return ira->codegen->invalid_inst_gen; - } - - return ir_build_err_to_int_gen(ira, scope, source_node, target, wanted_type); -} - -static Stage1AirInst *ir_analyze_ptr_to_array(IrAnalyze *ira, Scope *scope, AstNode *source_node, Stage1AirInst *target, - ZigType *wanted_type) -{ - assert(wanted_type->id == ZigTypeIdPointer); - Error err; - if ((err = type_resolve(ira->codegen, target->value->type->data.pointer.child_type, ResolveStatusAlignmentKnown))) - return ira->codegen->invalid_inst_gen; - assert((wanted_type->data.pointer.is_const && target->value->type->data.pointer.is_const) || !target->value->type->data.pointer.is_const); - wanted_type = adjust_ptr_align(ira->codegen, wanted_type, get_ptr_align(ira->codegen, target->value->type)); - ZigType *array_type = wanted_type->data.pointer.child_type; - assert(array_type->id == ZigTypeIdArray); - assert(array_type->data.array.len == 1); - - if (instr_is_comptime(target)) { - ZigValue *val = ir_resolve_const(ira, target, UndefBad); - if (!val) - return ira->codegen->invalid_inst_gen; - - assert(val->type->id == ZigTypeIdPointer); - ZigValue *pointee = const_ptr_pointee(ira, ira->codegen, val, source_node); - if (pointee == nullptr) - return ira->codegen->invalid_inst_gen; - if (pointee->special != ConstValSpecialRuntime) { - ZigValue *array_val = ira->codegen->pass1_arena->create(); - array_val->special = ConstValSpecialStatic; - array_val->type = array_type; - array_val->data.x_array.special = ConstArraySpecialNone; - array_val->data.x_array.data.s_none.elements = pointee; - array_val->parent.id = ConstParentIdScalar; - array_val->parent.data.p_scalar.scalar_val = pointee; - - Stage1AirInstConst *const_instruction = ir_create_inst_gen(&ira->new_irb, - scope, source_node); - const_instruction->base.value->type = wanted_type; - const_instruction->base.value->special = ConstValSpecialStatic; - const_instruction->base.value->data.x_ptr.special = ConstPtrSpecialRef; - const_instruction->base.value->data.x_ptr.data.ref.pointee = array_val; - const_instruction->base.value->data.x_ptr.mut = val->data.x_ptr.mut; - return &const_instruction->base; - } - } - - // pointer to array and pointer to single item are represented the same way at runtime - return ir_build_cast(ira, target->scope, target->source_node, wanted_type, target, CastOpBitCast); -} - -static void report_recursive_error(IrAnalyze *ira, AstNode *source_node, ConstCastOnly *cast_result, - ErrorMsg *parent_msg) -{ - switch (cast_result->id) { - case ConstCastResultIdOk: - zig_unreachable(); - case ConstCastResultIdInvalid: - zig_unreachable(); - case ConstCastResultIdOptionalChild: { - ErrorMsg *msg = add_error_note(ira->codegen, parent_msg, source_node, - buf_sprintf("optional type child '%s' cannot cast into optional type child '%s'", - buf_ptr(&cast_result->data.optional->actual_child->name), - buf_ptr(&cast_result->data.optional->wanted_child->name))); - report_recursive_error(ira, source_node, &cast_result->data.optional->child, msg); - break; - } - case ConstCastResultIdOptionalShape: { - add_error_note(ira->codegen, parent_msg, source_node, - buf_sprintf("optional type child '%s' cannot cast into optional type '%s'", - buf_ptr(&cast_result->data.type_mismatch->actual_type->name), - buf_ptr(&cast_result->data.type_mismatch->wanted_type->name))); - break; - } - case ConstCastResultIdErrorUnionErrorSet: { - ErrorMsg *msg = add_error_note(ira->codegen, parent_msg, source_node, - buf_sprintf("error set '%s' cannot cast into error set '%s'", - buf_ptr(&cast_result->data.error_union_error_set->actual_err_set->name), - buf_ptr(&cast_result->data.error_union_error_set->wanted_err_set->name))); - report_recursive_error(ira, source_node, &cast_result->data.error_union_error_set->child, msg); - break; - } - case ConstCastResultIdErrSet: { - ZigList *missing_errors = &cast_result->data.error_set_mismatch->missing_errors; - for (size_t i = 0; i < missing_errors->length; i += 1) { - ErrorTableEntry *error_entry = missing_errors->at(i); - add_error_note(ira->codegen, parent_msg, ast_field_to_symbol_node(error_entry->decl_node), - buf_sprintf("'error.%s' not a member of destination error set", buf_ptr(&error_entry->name))); - } - break; - } - case ConstCastResultIdErrSetGlobal: { - add_error_note(ira->codegen, parent_msg, source_node, - buf_sprintf("cannot cast global error set into smaller set")); - break; - } - case ConstCastResultIdPointerChild: { - ErrorMsg *msg = add_error_note(ira->codegen, parent_msg, source_node, - buf_sprintf("pointer type child '%s' cannot cast into pointer type child '%s'", - buf_ptr(&cast_result->data.pointer_mismatch->actual_child->name), - buf_ptr(&cast_result->data.pointer_mismatch->wanted_child->name))); - report_recursive_error(ira, source_node, &cast_result->data.pointer_mismatch->child, msg); - break; - } - case ConstCastResultIdSliceChild: { - ErrorMsg *msg = add_error_note(ira->codegen, parent_msg, source_node, - buf_sprintf("slice type child '%s' cannot cast into slice type child '%s'", - buf_ptr(&cast_result->data.slice_mismatch->actual_child->name), - buf_ptr(&cast_result->data.slice_mismatch->wanted_child->name))); - report_recursive_error(ira, source_node, &cast_result->data.slice_mismatch->child, msg); - break; - } - case ConstCastResultIdErrorUnionPayload: { - ErrorMsg *msg = add_error_note(ira->codegen, parent_msg, source_node, - buf_sprintf("error union payload '%s' cannot cast into error union payload '%s'", - buf_ptr(&cast_result->data.error_union_payload->actual_payload->name), - buf_ptr(&cast_result->data.error_union_payload->wanted_payload->name))); - report_recursive_error(ira, source_node, &cast_result->data.error_union_payload->child, msg); - break; - } - case ConstCastResultIdType: { - AstNode *wanted_decl_node = type_decl_node(cast_result->data.type_mismatch->wanted_type); - AstNode *actual_decl_node = type_decl_node(cast_result->data.type_mismatch->actual_type); - if (wanted_decl_node != nullptr) { - add_error_note(ira->codegen, parent_msg, wanted_decl_node, - buf_sprintf("%s declared here", - buf_ptr(&cast_result->data.type_mismatch->wanted_type->name))); - } - if (actual_decl_node != nullptr) { - add_error_note(ira->codegen, parent_msg, actual_decl_node, - buf_sprintf("%s declared here", - buf_ptr(&cast_result->data.type_mismatch->actual_type->name))); - } - break; - } - case ConstCastResultIdFnArg: { - ErrorMsg *msg = add_error_note(ira->codegen, parent_msg, source_node, - buf_sprintf("parameter %" ZIG_PRI_usize ": '%s' cannot cast into '%s'", - cast_result->data.fn_arg.arg_index, - buf_ptr(&cast_result->data.fn_arg.actual_param_type->name), - buf_ptr(&cast_result->data.fn_arg.expected_param_type->name))); - report_recursive_error(ira, source_node, cast_result->data.fn_arg.child, msg); - break; - } - case ConstCastResultIdBadAllowsZero: { - ZigType *wanted_type = cast_result->data.bad_allows_zero->wanted_type; - ZigType *actual_type = cast_result->data.bad_allows_zero->actual_type; - bool wanted_allows_zero = ptr_allows_addr_zero(wanted_type); - bool actual_allows_zero = ptr_allows_addr_zero(actual_type); - if (actual_allows_zero && !wanted_allows_zero) { - add_error_note(ira->codegen, parent_msg, source_node, - buf_sprintf("'%s' could have null values which are illegal in type '%s'", - buf_ptr(&actual_type->name), - buf_ptr(&wanted_type->name))); - } else { - add_error_note(ira->codegen, parent_msg, source_node, - buf_sprintf("mutable '%s' allows illegal null values stored to type '%s'", - buf_ptr(&wanted_type->name), - buf_ptr(&actual_type->name))); - } - break; - } - case ConstCastResultIdPtrLens: { - add_error_note(ira->codegen, parent_msg, source_node, - buf_sprintf("pointer length mismatch")); - break; - } - case ConstCastResultIdPtrSentinel: { - ZigType *actual_type = cast_result->data.bad_ptr_sentinel->actual_type; - ZigType *wanted_type = cast_result->data.bad_ptr_sentinel->wanted_type; - { - Buf *txt_msg = buf_sprintf("destination pointer requires a terminating '"); - render_const_value(ira->codegen, txt_msg, wanted_type->data.pointer.sentinel); - buf_appendf(txt_msg, "' sentinel"); - if (actual_type->data.pointer.sentinel != nullptr) { - buf_appendf(txt_msg, ", but source pointer has a terminating '"); - render_const_value(ira->codegen, txt_msg, actual_type->data.pointer.sentinel); - buf_appendf(txt_msg, "' sentinel"); - } - add_error_note(ira->codegen, parent_msg, source_node, txt_msg); - } - break; - } - case ConstCastResultIdSentinelArrays: { - ZigType *actual_type = cast_result->data.sentinel_arrays->actual_type; - ZigType *wanted_type = cast_result->data.sentinel_arrays->wanted_type; - Buf *txt_msg = buf_sprintf("destination array requires a terminating '"); - render_const_value(ira->codegen, txt_msg, wanted_type->data.array.sentinel); - buf_appendf(txt_msg, "' sentinel"); - if (actual_type->data.array.sentinel != nullptr) { - buf_appendf(txt_msg, ", but source array has a terminating '"); - render_const_value(ira->codegen, txt_msg, actual_type->data.array.sentinel); - buf_appendf(txt_msg, "' sentinel"); - } - add_error_note(ira->codegen, parent_msg, source_node, txt_msg); - break; - } - case ConstCastResultIdCV: { - ZigType *wanted_type = cast_result->data.bad_cv->wanted_type; - ZigType *actual_type = cast_result->data.bad_cv->actual_type; - bool ok_const = !actual_type->data.pointer.is_const || wanted_type->data.pointer.is_const; - bool ok_volatile = !actual_type->data.pointer.is_volatile || wanted_type->data.pointer.is_volatile; - if (!ok_const) { - add_error_note(ira->codegen, parent_msg, source_node, buf_sprintf("cast discards const qualifier")); - } else if (!ok_volatile) { - add_error_note(ira->codegen, parent_msg, source_node, buf_sprintf("cast discards volatile qualifier")); - } else { - zig_unreachable(); - } - break; - } - case ConstCastResultIdFnIsGeneric: - add_error_note(ira->codegen, parent_msg, source_node, - buf_sprintf("only one of the functions is generic")); - break; - case ConstCastResultIdFnCC: - add_error_note(ira->codegen, parent_msg, source_node, - buf_sprintf("calling convention mismatch")); - break; - case ConstCastResultIdIntShorten: { - ZigType *wanted_type = cast_result->data.int_shorten->wanted_type; - ZigType *actual_type = cast_result->data.int_shorten->actual_type; - const char *wanted_signed = wanted_type->data.integral.is_signed ? "signed" : "unsigned"; - const char *actual_signed = actual_type->data.integral.is_signed ? "signed" : "unsigned"; - add_error_note(ira->codegen, parent_msg, source_node, - buf_sprintf("%s %" PRIu32 "-bit int cannot represent all possible %s %" PRIu32 "-bit values", - wanted_signed, wanted_type->data.integral.bit_count, - actual_signed, actual_type->data.integral.bit_count)); - break; - } - case ConstCastResultIdVectorLength: // TODO - case ConstCastResultIdVectorChild: // TODO - case ConstCastResultIdFnAlign: // TODO - case ConstCastResultIdFnVarArgs: // TODO - case ConstCastResultIdFnReturnType: // TODO - case ConstCastResultIdFnArgCount: // TODO - case ConstCastResultIdFnGenericArgCount: // TODO - case ConstCastResultIdFnArgNoAlias: // TODO - case ConstCastResultIdUnresolvedInferredErrSet: // TODO - case ConstCastResultIdAsyncAllocatorType: // TODO - case ConstCastResultIdArrayChild: // TODO - break; - } -} - -static Stage1AirInst *ir_analyze_array_to_vector(IrAnalyze *ira, Scope *scope, AstNode *source_node, - Stage1AirInst *array, ZigType *vector_type) -{ - if (instr_is_comptime(array)) { - // arrays and vectors have the same ZigValue representation - Stage1AirInst *result = ir_const(ira, scope, source_node, vector_type); - copy_const_val(ira->codegen, result->value, array->value); - result->value->type = vector_type; - return result; - } - return ir_build_array_to_vector(ira, scope, source_node, array, vector_type); -} - -static Stage1AirInst *ir_analyze_vector_to_array(IrAnalyze *ira, Scope *scope, AstNode *source_node, - Stage1AirInst *vector, ZigType *array_type, ResultLoc *result_loc) -{ - if (instr_is_comptime(vector)) { - // arrays and vectors have the same ZigValue representation - Stage1AirInst *result = ir_const(ira, scope, source_node, array_type); - copy_const_val(ira->codegen, result->value, vector->value); - result->value->type = array_type; - return result; - } - if (result_loc == nullptr) { - result_loc = no_result_loc(); - } - Stage1AirInst *result_loc_inst = ir_resolve_result(ira, ira->suspend_source_instr, result_loc, array_type, nullptr, true, true); - if (type_is_invalid(result_loc_inst->value->type) || result_loc_inst->value->type->id == ZigTypeIdUnreachable) { - return result_loc_inst; - } - return ir_build_vector_to_array(ira, scope, source_node, array_type, vector, result_loc_inst); -} - -static Stage1AirInst *ir_analyze_int_to_c_ptr(IrAnalyze *ira, Scope *scope, AstNode *source_node, - Stage1AirInst *integer, ZigType *dest_type) -{ - Stage1AirInst *unsigned_integer; - if (instr_is_comptime(integer)) { - unsigned_integer = integer; - } else { - assert(integer->value->type->id == ZigTypeIdInt); - - if (integer->value->type->data.integral.bit_count > - ira->codegen->builtin_types.entry_usize->data.integral.bit_count) - { - ir_add_error_node(ira, source_node, - buf_sprintf("integer type '%s' too big for implicit @intToPtr to type '%s'", - buf_ptr(&integer->value->type->name), - buf_ptr(&dest_type->name))); - return ira->codegen->invalid_inst_gen; - } - - if (integer->value->type->data.integral.is_signed) { - ZigType *unsigned_int_type = get_int_type(ira->codegen, false, - integer->value->type->data.integral.bit_count); - unsigned_integer = ir_analyze_bit_cast(ira, scope, source_node, integer, unsigned_int_type); - if (type_is_invalid(unsigned_integer->value->type)) - return ira->codegen->invalid_inst_gen; - } else { - unsigned_integer = integer; - } - } - - return ir_analyze_int_to_ptr(ira, scope, source_node, unsigned_integer, dest_type); -} - -static bool is_pointery_and_elem_is_not_pointery(ZigType *ty) { - if (ty->id == ZigTypeIdPointer) return ty->data.pointer.child_type->id != ZigTypeIdPointer; - if (ty->id == ZigTypeIdFn) return true; - if (ty->id == ZigTypeIdOptional) { - ZigType *ptr_ty = ty->data.maybe.child_type; - if (ptr_ty->id == ZigTypeIdPointer) return ptr_ty->data.pointer.child_type->id != ZigTypeIdPointer; - if (ptr_ty->id == ZigTypeIdFn) return true; - } - return false; -} - -static Stage1AirInst *ir_analyze_enum_literal(IrAnalyze *ira, Scope *scope, AstNode *source_node, Stage1AirInst *value, - ZigType *enum_type) -{ - assert(enum_type->id == ZigTypeIdEnum); - - Error err; - if ((err = type_resolve(ira->codegen, enum_type, ResolveStatusZeroBitsKnown))) - return ira->codegen->invalid_inst_gen; - - TypeEnumField *field = find_enum_type_field(enum_type, value->value->data.x_enum_literal); - if (field == nullptr) { - ErrorMsg *msg = ir_add_error_node(ira, source_node, buf_sprintf("enum '%s' has no field named '%s'", - buf_ptr(&enum_type->name), buf_ptr(value->value->data.x_enum_literal))); - add_error_note(ira->codegen, msg, enum_type->data.enumeration.decl_node, - buf_sprintf("'%s' declared here", buf_ptr(&enum_type->name))); - return ira->codegen->invalid_inst_gen; - } - Stage1AirInst *result = ir_const(ira, scope, source_node, enum_type); - bigint_init_bigint(&result->value->data.x_enum_tag, &field->value); - - return result; -} - -static Stage1AirInst *ir_analyze_struct_literal_to_array(IrAnalyze *ira, Scope *scope, AstNode *source_node, - Stage1AirInst *struct_ptr, ZigType *actual_type, ZigType *wanted_type) -{ - Error err; - - if ((err = type_resolve(ira->codegen, wanted_type, ResolveStatusSizeKnown))) - return ira->codegen->invalid_inst_gen; - - size_t array_len = wanted_type->data.array.len; - size_t instr_field_count = actual_type->data.structure.src_field_count; - assert(array_len == instr_field_count); - - bool need_comptime = ir_should_inline(ira->zir, scope) - || type_requires_comptime(ira->codegen, wanted_type) == ReqCompTimeYes; - bool is_comptime = true; - - ZigType *elem_type = wanted_type->data.array.child_type; - - // Determine if the struct_operand will be comptime. - ZigValue *elem_values = heap::c_allocator.allocate(array_len); - Stage1AirInst **casted_fields = heap::c_allocator.allocate(array_len); - Stage1AirInst *const_result = ir_const(ira, scope, source_node, wanted_type); - - for (size_t i = 0; i < array_len; i += 1) { - TypeStructField *src_field = actual_type->data.structure.fields[i]; - - Stage1AirInst *field_ptr = ir_analyze_struct_field_ptr(ira, scope, source_node, src_field, struct_ptr, - actual_type, false); - if (type_is_invalid(field_ptr->value->type)) - return ira->codegen->invalid_inst_gen; - Stage1AirInst *field_value = ir_get_deref(ira, scope, source_node, field_ptr, nullptr); - if (type_is_invalid(field_value->value->type)) - return ira->codegen->invalid_inst_gen; - Stage1AirInst *casted_value = ir_implicit_cast(ira, field_value, elem_type); - if (type_is_invalid(casted_value->value->type)) - return ira->codegen->invalid_inst_gen; - - casted_fields[i] = casted_value; - if (need_comptime || instr_is_comptime(casted_value)) { - ZigValue *field_val = ir_resolve_const(ira, casted_value, UndefOk); - if (field_val == nullptr) - return ira->codegen->invalid_inst_gen; - - field_val->parent.id = ConstParentIdArray; - field_val->parent.data.p_array.array_val = const_result->value; - field_val->parent.data.p_array.elem_index = i; - elem_values[i] = *field_val; - if (field_val->type->id == ZigTypeIdUndefined) { - elem_values[i].special = ConstValSpecialUndef; - } - } else { - is_comptime = false; - } - } - - if (is_comptime) { - Stage1AirInst *const_result = ir_const(ira, scope, source_node, wanted_type); - const_result->value->data.x_array.special = ConstArraySpecialNone; - const_result->value->data.x_array.data.s_none.elements = elem_values; - return const_result; - } - - Stage1AirInst *result_loc_inst = ir_resolve_result(ira, ira->suspend_source_instr, no_result_loc(), - wanted_type, nullptr, true, true); - if (type_is_invalid(result_loc_inst->value->type) || result_loc_inst->value->type->id == ZigTypeIdUnreachable) { - return ira->codegen->invalid_inst_gen; - } - - ZigType *elem_type_ptr = get_pointer_to_type(ira->codegen, elem_type, false); - for (size_t i = 0; i < array_len; i += 1) { - Stage1AirInst *index_val = ir_const(ira, scope, source_node, ira->codegen->builtin_types.entry_usize); - bigint_init_unsigned(&index_val->value->data.x_bigint, i); - - Stage1AirInst *elem_ptr = ir_build_elem_ptr_gen(ira, scope, source_node, - result_loc_inst, index_val, false, elem_type_ptr); - Stage1AirInst *store_ptr_inst = ir_analyze_store_ptr(ira, scope, source_node, elem_ptr, casted_fields[i], true); - if (type_is_invalid(store_ptr_inst->value->type)) - return ira->codegen->invalid_inst_gen; - } - - heap::c_allocator.deallocate(elem_values, array_len); - heap::c_allocator.deallocate(casted_fields, array_len); - - return result_loc_inst; -} - -static Stage1AirInst *ir_analyze_struct_literal_to_struct(IrAnalyze *ira, Scope *scope, AstNode *source_node, - Stage1AirInst *struct_ptr, ZigType *actual_type, ZigType *wanted_type) -{ - Error err; - - if (wanted_type->data.structure.resolve_status == ResolveStatusBeingInferred) { - ir_add_error_node(ira, source_node, buf_sprintf("type coercion of anon struct literal to inferred struct")); - return ira->codegen->invalid_inst_gen; - } - - if ((err = type_resolve(ira->codegen, wanted_type, ResolveStatusSizeKnown))) - return ira->codegen->invalid_inst_gen; - - size_t actual_field_count = wanted_type->data.structure.src_field_count; - size_t instr_field_count = actual_type->data.structure.src_field_count; - - bool need_comptime = ir_should_inline(ira->zir, scope) - || type_requires_comptime(ira->codegen, wanted_type) == ReqCompTimeYes; - bool is_comptime = true; - - // Determine if the struct_operand will be comptime. - // Also emit compile errors for missing fields and duplicate fields. - AstNode **field_assign_nodes = heap::c_allocator.allocate(actual_field_count); - ZigValue **field_values = heap::c_allocator.allocate(actual_field_count); - Stage1AirInst **casted_fields = heap::c_allocator.allocate(actual_field_count); - Stage1AirInst *const_result = ir_const(ira, scope, source_node, wanted_type); - - for (size_t i = 0; i < instr_field_count; i += 1) { - TypeStructField *src_field = actual_type->data.structure.fields[i]; - TypeStructField *dst_field = find_struct_type_field(wanted_type, src_field->name); - if (dst_field == nullptr) { - ErrorMsg *msg = ir_add_error_node(ira, source_node, buf_sprintf("no field named '%s' in struct '%s'", - buf_ptr(src_field->name), buf_ptr(&wanted_type->name))); - if (wanted_type->data.structure.decl_node) { - add_error_note(ira->codegen, msg, wanted_type->data.structure.decl_node, - buf_sprintf("struct '%s' declared here", buf_ptr(&wanted_type->name))); - } - add_error_note(ira->codegen, msg, src_field->decl_node, - buf_sprintf("field '%s' declared here", buf_ptr(src_field->name))); - return ira->codegen->invalid_inst_gen; - } - if (dst_field->is_comptime) { - ErrorMsg *msg = ir_add_error_node(ira, source_node, buf_sprintf("field '%s' in struct '%s' is comptime, it cannot be assigned", - buf_ptr(src_field->name), buf_ptr(&wanted_type->name))); - if (wanted_type->data.structure.decl_node) { - add_error_note(ira->codegen, msg, wanted_type->data.structure.decl_node, - buf_sprintf("struct '%s' declared here", buf_ptr(&wanted_type->name))); - } - add_error_note(ira->codegen, msg, src_field->decl_node, - buf_sprintf("field '%s' declared here", buf_ptr(src_field->name))); - return ira->codegen->invalid_inst_gen; - } - - src_assert(src_field->decl_node != nullptr, source_node); - AstNode *existing_assign_node = field_assign_nodes[dst_field->src_index]; - if (existing_assign_node != nullptr) { - ErrorMsg *msg = ir_add_error_node(ira, source_node, buf_sprintf("duplicate field")); - add_error_note(ira->codegen, msg, existing_assign_node, buf_sprintf("other field here")); - return ira->codegen->invalid_inst_gen; - } - field_assign_nodes[dst_field->src_index] = src_field->decl_node; - - Stage1AirInst *field_ptr = ir_analyze_struct_field_ptr(ira, scope, source_node, src_field, struct_ptr, - actual_type, false); - if (type_is_invalid(field_ptr->value->type)) - return ira->codegen->invalid_inst_gen; - Stage1AirInst *field_value = ir_get_deref(ira, scope, source_node, field_ptr, nullptr); - if (type_is_invalid(field_value->value->type)) - return ira->codegen->invalid_inst_gen; - Stage1AirInst *casted_value = ir_implicit_cast(ira, field_value, dst_field->type_entry); - if (type_is_invalid(casted_value->value->type)) - return ira->codegen->invalid_inst_gen; - - casted_fields[dst_field->src_index] = casted_value; - if (need_comptime || instr_is_comptime(casted_value)) { - ZigValue *field_val = ir_resolve_const(ira, casted_value, UndefOk); - if (field_val == nullptr) - return ira->codegen->invalid_inst_gen; - field_val->parent.id = ConstParentIdStruct; - field_val->parent.data.p_struct.struct_val = const_result->value; - field_val->parent.data.p_struct.field_index = dst_field->src_index; - field_values[dst_field->src_index] = field_val; - if (field_val->type->id == ZigTypeIdUndefined && dst_field->type_entry->id != ZigTypeIdUndefined) { - field_values[dst_field->src_index]->special = ConstValSpecialUndef; - } - } else { - is_comptime = false; - } - } - - bool any_missing = false; - for (size_t i = 0; i < actual_field_count; i += 1) { - if (field_assign_nodes[i] != nullptr) continue; - - // look for a default field value - TypeStructField *field = wanted_type->data.structure.fields[i]; - assert(!field->is_comptime); // field_assign_nodes[i] should be null for comptime fields - memoize_field_init_val(ira->codegen, wanted_type, field); - if (field->init_val == nullptr) { - ir_add_error_node(ira, source_node, - buf_sprintf("missing field: '%s'", buf_ptr(field->name))); - any_missing = true; - continue; - } - if (type_is_invalid(field->init_val->type)) - return ira->codegen->invalid_inst_gen; - ZigValue *init_val_copy = ira->codegen->pass1_arena->create(); - copy_const_val(ira->codegen, init_val_copy, field->init_val); - init_val_copy->parent.id = ConstParentIdStruct; - init_val_copy->parent.data.p_struct.struct_val = const_result->value; - init_val_copy->parent.data.p_struct.field_index = i; - field_values[i] = init_val_copy; - casted_fields[i] = ir_const_move(ira, scope, source_node, init_val_copy); - } - if (any_missing) - return ira->codegen->invalid_inst_gen; - - if (is_comptime) { - heap::c_allocator.deallocate(field_assign_nodes, actual_field_count); - Stage1AirInst *const_result = ir_const(ira, scope, source_node, wanted_type); - const_result->value->data.x_struct.fields = field_values; - return const_result; - } - - Stage1AirInst *result_loc_inst = ir_resolve_result(ira, ira->suspend_source_instr, no_result_loc(), - wanted_type, nullptr, true, true); - if (type_is_invalid(result_loc_inst->value->type) || result_loc_inst->value->type->id == ZigTypeIdUnreachable) { - return ira->codegen->invalid_inst_gen; - } - - for (size_t i = 0; i < actual_field_count; i += 1) { - TypeStructField *field = wanted_type->data.structure.fields[i]; - if (field->is_comptime) - continue; - - Stage1AirInst *field_ptr = ir_analyze_struct_field_ptr(ira, scope, source_node, field, result_loc_inst, wanted_type, true); - if (type_is_invalid(field_ptr->value->type)) - return ira->codegen->invalid_inst_gen; - Stage1AirInst *store_ptr_inst = ir_analyze_store_ptr(ira, scope, source_node, field_ptr, casted_fields[i], true); - if (type_is_invalid(store_ptr_inst->value->type)) - return ira->codegen->invalid_inst_gen; - } - - heap::c_allocator.deallocate(field_assign_nodes, actual_field_count); - heap::c_allocator.deallocate(field_values, actual_field_count); - heap::c_allocator.deallocate(casted_fields, actual_field_count); - - return result_loc_inst; -} - -static Stage1AirInst *ir_analyze_struct_literal_to_union(IrAnalyze *ira, Scope *scope, AstNode *source_node, - Stage1AirInst *struct_ptr, ZigType *struct_type, ZigType *union_type) -{ - Error err; - - assert(struct_type->id == ZigTypeIdStruct); - assert(union_type->id == ZigTypeIdUnion); - assert(struct_type->data.structure.src_field_count == 1); - - TypeStructField *only_field = struct_type->data.structure.fields[0]; - - if ((err = type_resolve(ira->codegen, union_type, ResolveStatusZeroBitsKnown))) - return ira->codegen->invalid_inst_gen; - - TypeUnionField *union_field = find_union_type_field(union_type, only_field->name); - if (union_field == nullptr) { - ir_add_error_node(ira, only_field->decl_node, - buf_sprintf("no field named '%s' in union '%s'", - buf_ptr(only_field->name), buf_ptr(&union_type->name))); - return ira->codegen->invalid_inst_gen; - } - - ZigType *payload_type = resolve_union_field_type(ira->codegen, union_field); - if (payload_type == nullptr) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *field_ptr = ir_analyze_struct_field_ptr(ira, scope, source_node, only_field, struct_ptr, - struct_type, false); - if (type_is_invalid(field_ptr->value->type)) - return ira->codegen->invalid_inst_gen; - Stage1AirInst *field_value = ir_get_deref(ira, scope, source_node, field_ptr, nullptr); - if (type_is_invalid(field_value->value->type)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *casted_value = ir_implicit_cast(ira, field_value, payload_type); - if (type_is_invalid(casted_value->value->type)) - return ira->codegen->invalid_inst_gen; - - if (instr_is_comptime(casted_value)) { - ZigValue *val = ir_resolve_const(ira, casted_value, UndefBad); - if (val == nullptr) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *result = ir_const(ira, scope, source_node, union_type); - bigint_init_bigint(&result->value->data.x_union.tag, &union_field->enum_field->value); - result->value->data.x_union.payload = val; - - val->parent.id = ConstParentIdUnion; - val->parent.data.p_union.union_val = result->value; - - return result; - } - - Stage1AirInst *result_loc_inst = ir_resolve_result(ira, ira->suspend_source_instr, no_result_loc(), - union_type, nullptr, true, true); - if (type_is_invalid(result_loc_inst->value->type) || result_loc_inst->value->type->id == ZigTypeIdUnreachable) { - return ira->codegen->invalid_inst_gen; - } - - Stage1AirInst *payload_ptr = ir_analyze_container_field_ptr(ira, only_field->name, - scope, source_node, result_loc_inst, source_node, union_type, true); - if (type_is_invalid(payload_ptr->value->type)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *store_ptr_inst = ir_analyze_store_ptr(ira, scope, source_node, payload_ptr, casted_value, false); - if (type_is_invalid(store_ptr_inst->value->type)) - return ira->codegen->invalid_inst_gen; - - return result_loc_inst; -} - -// Add a compile error and return ErrorSemanticAnalyzeFail if the pointer alignment does not work, -// otherwise return ErrorNone. Does not emit any instructions. -// Assumes that the pointer types have element types with the same ABI alignment. Avoids resolving the -// pointer types' alignments if both of the pointer types are ABI aligned. -static Error ir_cast_ptr_align(IrAnalyze *ira, Scope *scope, AstNode *source_node, ZigType *dest_ptr_type, - ZigType *src_ptr_type, AstNode *src_source_node) -{ - Error err; - - src_assert(dest_ptr_type->id == ZigTypeIdPointer, source_node); - src_assert(src_ptr_type->id == ZigTypeIdPointer, source_node); - - if (dest_ptr_type->data.pointer.explicit_alignment == 0 && - src_ptr_type->data.pointer.explicit_alignment == 0) - { - return ErrorNone; - } - - if ((err = type_resolve(ira->codegen, dest_ptr_type->data.pointer.child_type, ResolveStatusAlignmentKnown))) - return ErrorSemanticAnalyzeFail; - - if ((err = type_resolve(ira->codegen, src_ptr_type->data.pointer.child_type, ResolveStatusAlignmentKnown))) - return ErrorSemanticAnalyzeFail; - - uint32_t wanted_align = get_ptr_align(ira->codegen, dest_ptr_type); - uint32_t actual_align = get_ptr_align(ira->codegen, src_ptr_type); - if (wanted_align > actual_align) { - ErrorMsg *msg = ir_add_error_node(ira, source_node, buf_sprintf("cast increases pointer alignment")); - add_error_note(ira->codegen, msg, src_source_node, - buf_sprintf("'%s' has alignment %" PRIu32, buf_ptr(&src_ptr_type->name), actual_align)); - add_error_note(ira->codegen, msg, source_node, - buf_sprintf("'%s' has alignment %" PRIu32, buf_ptr(&dest_ptr_type->name), wanted_align)); - return ErrorSemanticAnalyzeFail; - } - - return ErrorNone; -} - -static Stage1AirInst *ir_analyze_struct_value_field_value(IrAnalyze *ira, Scope *scope, AstNode *source_node, - Stage1AirInst *struct_operand, TypeStructField *field) -{ - Stage1AirInst *struct_ptr = ir_get_ref(ira, scope, source_node, struct_operand, true, false); - if (type_is_invalid(struct_ptr->value->type)) - return ira->codegen->invalid_inst_gen; - Stage1AirInst *field_ptr = ir_analyze_struct_field_ptr(ira, scope, source_node, field, struct_ptr, - struct_operand->value->type, false); - if (type_is_invalid(field_ptr->value->type)) - return ira->codegen->invalid_inst_gen; - return ir_get_deref(ira, scope, source_node, field_ptr, nullptr); -} - -static Stage1AirInst *ir_analyze_optional_value_payload_value(IrAnalyze *ira, Scope *scope, AstNode *source_node, - Stage1AirInst *optional_operand, bool safety_check_on) -{ - Stage1AirInst *opt_ptr = ir_get_ref(ira, scope, source_node, optional_operand, true, false); - Stage1AirInst *payload_ptr = ir_analyze_unwrap_optional_payload(ira, scope, source_node, opt_ptr, - safety_check_on, false); - return ir_get_deref(ira, scope, source_node, payload_ptr, nullptr); -} - -static Stage1AirInst *ir_analyze_cast(IrAnalyze *ira, Scope *scope, AstNode *source_node, - ZigType *wanted_type, Stage1AirInst *value) -{ - Error err; - ZigType *actual_type = value->value->type; - - if (type_is_invalid(wanted_type) || type_is_invalid(actual_type)) { - return ira->codegen->invalid_inst_gen; - } - - // This means the wanted type is anything. - if (wanted_type == ira->codegen->builtin_types.entry_anytype) { - return value; - } - - // perfect match or non-const to const - ConstCastOnly const_cast_result = types_match_const_cast_only(ira, wanted_type, actual_type, - source_node, false); - if (const_cast_result.id == ConstCastResultIdInvalid) - return ira->codegen->invalid_inst_gen; - if (const_cast_result.id == ConstCastResultIdOk) { - return ir_resolve_cast(ira, scope, source_node, value, wanted_type, CastOpNoop); - } - - if (const_cast_result.id == ConstCastResultIdFnCC) { - src_assert(value->value->type->id == ZigTypeIdFn, source_node); - // ConstCastResultIdFnCC is guaranteed to be the last one reported, meaning everything else is ok. - if (wanted_type->data.fn.fn_type_id.cc == CallingConventionAsync && - actual_type->data.fn.fn_type_id.cc == CallingConventionUnspecified) - { - src_assert(value->value->data.x_ptr.special == ConstPtrSpecialFunction, source_node); - ZigFn *fn = value->value->data.x_ptr.data.fn.fn_entry; - if (fn->inferred_async_node == nullptr) { - fn->inferred_async_node = source_node; - } - return ir_resolve_cast(ira, scope, source_node, value, wanted_type, CastOpNoop); - } - } - - // cast from T to ?T - // note that the *T to ?*T case is handled via the "ConstCastOnly" mechanism - if (wanted_type->id == ZigTypeIdOptional) { - ZigType *wanted_child_type = wanted_type->data.maybe.child_type; - if (types_match_const_cast_only(ira, wanted_child_type, actual_type, source_node, - false).id == ConstCastResultIdOk) - { - return ir_analyze_optional_wrap(ira, scope, source_node, value, wanted_type, nullptr); - } else if (actual_type->id == ZigTypeIdComptimeInt || - actual_type->id == ZigTypeIdComptimeFloat) - { - if (ir_num_lit_fits_in_other_type(ira, value, wanted_child_type, true)) { - return ir_analyze_optional_wrap(ira, scope, source_node, value, wanted_type, nullptr); - } else { - return ira->codegen->invalid_inst_gen; - } - } else if ( - wanted_child_type->id == ZigTypeIdPointer && - wanted_child_type->data.pointer.ptr_len == PtrLenUnknown && - actual_type->id == ZigTypeIdPointer && - actual_type->data.pointer.ptr_len == PtrLenSingle && - actual_type->data.pointer.child_type->id == ZigTypeIdArray) - { - if ((err = type_resolve(ira->codegen, actual_type->data.pointer.child_type, ResolveStatusAlignmentKnown))) - return ira->codegen->invalid_inst_gen; - if ((err = type_resolve(ira->codegen, wanted_child_type->data.pointer.child_type, ResolveStatusAlignmentKnown))) - return ira->codegen->invalid_inst_gen; - if (get_ptr_align(ira->codegen, actual_type) >= get_ptr_align(ira->codegen, wanted_child_type) && - types_match_const_cast_only(ira, wanted_child_type->data.pointer.child_type, - actual_type->data.pointer.child_type->data.array.child_type, source_node, - !wanted_child_type->data.pointer.is_const).id == ConstCastResultIdOk) - { - Stage1AirInst *cast1 = ir_resolve_ptr_of_array_to_unknown_len_ptr(ira, scope, source_node, value, - wanted_child_type); - if (type_is_invalid(cast1->value->type)) - return ira->codegen->invalid_inst_gen; - return ir_analyze_optional_wrap(ira, scope, source_node, cast1, wanted_type, nullptr); - } - } - } - - // T to E!T - if (wanted_type->id == ZigTypeIdErrorUnion) { - if (types_match_const_cast_only(ira, wanted_type->data.error_union.payload_type, actual_type, - source_node, false).id == ConstCastResultIdOk) - { - return ir_analyze_err_wrap_payload(ira, scope, source_node, value, wanted_type, nullptr); - } else if (actual_type->id == ZigTypeIdComptimeInt || - actual_type->id == ZigTypeIdComptimeFloat) - { - if (ir_num_lit_fits_in_other_type(ira, value, wanted_type->data.error_union.payload_type, true)) { - return ir_analyze_err_wrap_payload(ira, scope, source_node, value, wanted_type, nullptr); - } else { - return ira->codegen->invalid_inst_gen; - } - } - } - - // cast from T to E!?T - if (wanted_type->id == ZigTypeIdErrorUnion && - wanted_type->data.error_union.payload_type->id == ZigTypeIdOptional && - actual_type->id != ZigTypeIdOptional) - { - ZigType *wanted_child_type = wanted_type->data.error_union.payload_type->data.maybe.child_type; - if (types_match_const_cast_only(ira, wanted_child_type, actual_type, source_node, false).id == ConstCastResultIdOk || - actual_type->id == ZigTypeIdNull || - actual_type->id == ZigTypeIdComptimeInt || - actual_type->id == ZigTypeIdComptimeFloat) - { - Stage1AirInst *cast1 = ir_analyze_cast(ira, scope, source_node, wanted_type->data.error_union.payload_type, value); - if (type_is_invalid(cast1->value->type)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *cast2 = ir_analyze_cast(ira, scope, source_node, wanted_type, cast1); - if (type_is_invalid(cast2->value->type)) - return ira->codegen->invalid_inst_gen; - - return cast2; - } - } - - - // cast from comptime-known number to another number type - if (instr_is_comptime(value) && - (actual_type->id == ZigTypeIdInt || actual_type->id == ZigTypeIdComptimeInt || - actual_type->id == ZigTypeIdFloat || actual_type->id == ZigTypeIdComptimeFloat) && - (wanted_type->id == ZigTypeIdInt || wanted_type->id == ZigTypeIdComptimeInt || - wanted_type->id == ZigTypeIdFloat || wanted_type->id == ZigTypeIdComptimeFloat)) - { - if (value->value->special == ConstValSpecialUndef) { - Stage1AirInst *result = ir_const(ira, scope, source_node, wanted_type); - result->value->special = ConstValSpecialUndef; - return result; - } - if (ir_num_lit_fits_in_other_type(ira, value, wanted_type, true)) { - if (wanted_type->id == ZigTypeIdComptimeInt || wanted_type->id == ZigTypeIdInt) { - Stage1AirInst *result = ir_const(ira, scope, source_node, wanted_type); - if (actual_type->id == ZigTypeIdComptimeInt || actual_type->id == ZigTypeIdInt) { - copy_const_val(ira->codegen, result->value, value->value); - result->value->type = wanted_type; - } else { - float_init_bigint(&result->value->data.x_bigint, value->value); - } - return result; - } else if (wanted_type->id == ZigTypeIdComptimeFloat || wanted_type->id == ZigTypeIdFloat) { - Stage1AirInst *result = ir_const(ira, scope, source_node, wanted_type); - if (actual_type->id == ZigTypeIdComptimeInt || actual_type->id == ZigTypeIdInt) { - BigFloat bf; - bigfloat_init_bigint(&bf, &value->value->data.x_bigint); - float_init_bigfloat(result->value, &bf); - } else { - float_init_float(result->value, value->value); - } - return result; - } - zig_unreachable(); - } else { - return ira->codegen->invalid_inst_gen; - } - } - - // widening conversion - if (wanted_type->id == ZigTypeIdInt && - actual_type->id == ZigTypeIdInt && - wanted_type->data.integral.is_signed == actual_type->data.integral.is_signed && - wanted_type->data.integral.bit_count >= actual_type->data.integral.bit_count) - { - return ir_analyze_widen_or_shorten(ira, scope, source_node, value, wanted_type); - } - - // small enough unsigned ints can get casted to large enough signed ints - if (wanted_type->id == ZigTypeIdInt && wanted_type->data.integral.is_signed && - actual_type->id == ZigTypeIdInt && !actual_type->data.integral.is_signed && - wanted_type->data.integral.bit_count > actual_type->data.integral.bit_count) - { - return ir_analyze_widen_or_shorten(ira, scope, source_node, value, wanted_type); - } - - // float widening conversion - if (wanted_type->id == ZigTypeIdFloat && - actual_type->id == ZigTypeIdFloat && - wanted_type->data.floating.bit_count >= actual_type->data.floating.bit_count) - { - return ir_analyze_widen_or_shorten(ira, scope, source_node, value, wanted_type); - } - - // *[N]T to ?[]T - if (wanted_type->id == ZigTypeIdOptional && - is_slice(wanted_type->data.maybe.child_type) && - actual_type->id == ZigTypeIdPointer && - actual_type->data.pointer.ptr_len == PtrLenSingle && - actual_type->data.pointer.child_type->id == ZigTypeIdArray) - { - Stage1AirInst *cast1 = ir_analyze_cast(ira, scope, source_node, wanted_type->data.maybe.child_type, value); - if (type_is_invalid(cast1->value->type)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *cast2 = ir_analyze_cast(ira, scope, source_node, wanted_type, cast1); - if (type_is_invalid(cast2->value->type)) - return ira->codegen->invalid_inst_gen; - - return cast2; - } - - // *[N]T to [*]T and [*c]T - if (wanted_type->id == ZigTypeIdPointer && - (wanted_type->data.pointer.ptr_len == PtrLenUnknown || wanted_type->data.pointer.ptr_len == PtrLenC) && - actual_type->id == ZigTypeIdPointer && - actual_type->data.pointer.ptr_len == PtrLenSingle && - actual_type->data.pointer.child_type->id == ZigTypeIdArray && - (!actual_type->data.pointer.is_const || wanted_type->data.pointer.is_const) && - (!actual_type->data.pointer.is_volatile || wanted_type->data.pointer.is_volatile)) - { - ZigType *actual_array_type = actual_type->data.pointer.child_type; - if (wanted_type->data.pointer.sentinel == nullptr || - (actual_array_type->data.array.sentinel != nullptr && - const_values_equal(ira->codegen, wanted_type->data.pointer.sentinel, - actual_array_type->data.array.sentinel))) - { - if ((err = type_resolve(ira->codegen, actual_type->data.pointer.child_type, ResolveStatusAlignmentKnown))) - return ira->codegen->invalid_inst_gen; - if ((err = type_resolve(ira->codegen, wanted_type->data.pointer.child_type, ResolveStatusAlignmentKnown))) - return ira->codegen->invalid_inst_gen; - if (get_ptr_align(ira->codegen, actual_type) >= get_ptr_align(ira->codegen, wanted_type) && - types_match_const_cast_only(ira, wanted_type->data.pointer.child_type, - actual_type->data.pointer.child_type->data.array.child_type, source_node, - !wanted_type->data.pointer.is_const).id == ConstCastResultIdOk) - { - return ir_resolve_ptr_of_array_to_unknown_len_ptr(ira, scope, source_node, value, wanted_type); - } - } - } - - // *[N]T to []T - // *[N]T to E![]T - if ((is_slice(wanted_type) || - (wanted_type->id == ZigTypeIdErrorUnion && - is_slice(wanted_type->data.error_union.payload_type))) && - actual_type->id == ZigTypeIdPointer && - actual_type->data.pointer.ptr_len == PtrLenSingle && - actual_type->data.pointer.child_type->id == ZigTypeIdArray) - { - ZigType *slice_type = (wanted_type->id == ZigTypeIdErrorUnion) ? - wanted_type->data.error_union.payload_type : wanted_type; - ZigType *slice_ptr_type = slice_type->data.structure.fields[slice_ptr_index]->type_entry; - assert(slice_ptr_type->id == ZigTypeIdPointer); - ZigType *array_type = actual_type->data.pointer.child_type; - bool const_ok = (slice_ptr_type->data.pointer.is_const || array_type->data.array.len == 0 - || !actual_type->data.pointer.is_const); - - if (types_match_const_cast_only(ira, slice_ptr_type->data.pointer.child_type, - array_type->data.array.child_type, source_node, - !slice_ptr_type->data.pointer.is_const).id == ConstCastResultIdOk && - (slice_ptr_type->data.pointer.sentinel == nullptr || - (array_type->data.array.sentinel != nullptr && - const_values_equal(ira->codegen, array_type->data.array.sentinel, - slice_ptr_type->data.pointer.sentinel)))) - { - if (!const_ok) { - ErrorMsg *msg = ir_add_error_node(ira, source_node, - buf_sprintf("cannot cast pointer to array literal to slice type '%s'", - buf_ptr(&wanted_type->name))); - add_error_note(ira->codegen, msg, source_node, - buf_sprintf("cast discards const qualifier")); - return ira->codegen->invalid_inst_gen; - } - // If the pointers both have ABI align, it works. - // Or if the array length is 0, alignment doesn't matter. - bool ok_align = array_type->data.array.len == 0 || - (slice_ptr_type->data.pointer.explicit_alignment == 0 && - actual_type->data.pointer.explicit_alignment == 0); - if (!ok_align) { - // If either one has non ABI align, we have to resolve them both - if ((err = type_resolve(ira->codegen, actual_type->data.pointer.child_type, - ResolveStatusAlignmentKnown))) - { - return ira->codegen->invalid_inst_gen; - } - if ((err = type_resolve(ira->codegen, slice_ptr_type->data.pointer.child_type, - ResolveStatusAlignmentKnown))) - { - return ira->codegen->invalid_inst_gen; - } - ok_align = get_ptr_align(ira->codegen, actual_type) >= get_ptr_align(ira->codegen, slice_ptr_type); - } - if (ok_align) { - if (wanted_type->id == ZigTypeIdErrorUnion) { - Stage1AirInst *cast1 = ir_analyze_cast(ira, scope, source_node, slice_type, value); - if (type_is_invalid(cast1->value->type)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *cast2 = ir_analyze_cast(ira, scope, source_node, wanted_type, cast1); - if (type_is_invalid(cast2->value->type)) - return ira->codegen->invalid_inst_gen; - - return cast2; - } else { - return ir_resolve_ptr_of_array_to_slice(ira, scope, source_node, value, slice_type, nullptr); - } - } - } - } - - // @Vector(N,T1) to @Vector(N,T2) - if (actual_type->id == ZigTypeIdVector && wanted_type->id == ZigTypeIdVector && - actual_type->data.vector.len == wanted_type->data.vector.len) - { - ZigType *scalar_actual_type = actual_type->data.vector.elem_type; - ZigType *scalar_wanted_type = wanted_type->data.vector.elem_type; - - // widening conversion - if (scalar_wanted_type->id == ZigTypeIdInt && - scalar_actual_type->id == ZigTypeIdInt && - scalar_wanted_type->data.integral.is_signed == scalar_actual_type->data.integral.is_signed && - scalar_wanted_type->data.integral.bit_count >= scalar_actual_type->data.integral.bit_count) - { - return ir_analyze_widen_or_shorten(ira, scope, source_node, value, wanted_type); - } - - // small enough unsigned ints can get casted to large enough signed ints - if (scalar_wanted_type->id == ZigTypeIdInt && scalar_wanted_type->data.integral.is_signed && - scalar_actual_type->id == ZigTypeIdInt && !scalar_actual_type->data.integral.is_signed && - scalar_wanted_type->data.integral.bit_count > scalar_actual_type->data.integral.bit_count) - { - return ir_analyze_widen_or_shorten(ira, scope, source_node, value, wanted_type); - } - - // float widening conversion - if (scalar_wanted_type->id == ZigTypeIdFloat && - scalar_actual_type->id == ZigTypeIdFloat && - scalar_wanted_type->data.floating.bit_count >= scalar_actual_type->data.floating.bit_count) - { - return ir_analyze_widen_or_shorten(ira, scope, source_node, value, wanted_type); - } - } - - // *@Frame(func) to anyframe->T or anyframe - // *@Frame(func) to ?anyframe->T or ?anyframe - // *@Frame(func) to E!anyframe->T or E!anyframe - if (actual_type->id == ZigTypeIdPointer && actual_type->data.pointer.ptr_len == PtrLenSingle && - !actual_type->data.pointer.is_const && - actual_type->data.pointer.child_type->id == ZigTypeIdFnFrame) - { - ZigType *anyframe_type; - if (wanted_type->id == ZigTypeIdAnyFrame) { - anyframe_type = wanted_type; - } else if (wanted_type->id == ZigTypeIdOptional && - wanted_type->data.maybe.child_type->id == ZigTypeIdAnyFrame) - { - anyframe_type = wanted_type->data.maybe.child_type; - } else if (wanted_type->id == ZigTypeIdErrorUnion && - wanted_type->data.error_union.payload_type->id == ZigTypeIdAnyFrame) - { - anyframe_type = wanted_type->data.error_union.payload_type; - } else { - anyframe_type = nullptr; - } - if (anyframe_type != nullptr) { - bool ok = true; - if (anyframe_type->data.any_frame.result_type != nullptr) { - ZigFn *fn = actual_type->data.pointer.child_type->data.frame.fn; - ZigType *fn_return_type = fn->type_entry->data.fn.fn_type_id.return_type; - if (anyframe_type->data.any_frame.result_type != fn_return_type) { - ok = false; - } - } - if (ok) { - Stage1AirInst *cast1 = ir_analyze_frame_ptr_to_anyframe(ira, scope, source_node, value, anyframe_type); - if (anyframe_type == wanted_type) - return cast1; - return ir_analyze_cast(ira, scope, source_node, wanted_type, cast1); - } - } - } - - // anyframe->T to anyframe - if (actual_type->id == ZigTypeIdAnyFrame && actual_type->data.any_frame.result_type != nullptr && - wanted_type->id == ZigTypeIdAnyFrame && wanted_type->data.any_frame.result_type == nullptr) - { - return ir_analyze_anyframe_to_anyframe(ira, scope, source_node, value, wanted_type); - } - - // cast from null literal to maybe type - if (wanted_type->id == ZigTypeIdOptional && - actual_type->id == ZigTypeIdNull) - { - return ir_analyze_null_to_maybe(ira, scope, source_node, value, wanted_type); - } - - // cast from null literal to C pointer - if (wanted_type->id == ZigTypeIdPointer && wanted_type->data.pointer.ptr_len == PtrLenC && - actual_type->id == ZigTypeIdNull) - { - return ir_analyze_null_to_c_pointer(ira, scope, source_node, value, wanted_type); - } - - // cast from E to E!T - if (wanted_type->id == ZigTypeIdErrorUnion && - actual_type->id == ZigTypeIdErrorSet) - { - return ir_analyze_err_wrap_code(ira, scope, source_node, value, wanted_type, nullptr); - } - - // cast from typed number to integer or float literal. - // works when the number is known at compile time - if (instr_is_comptime(value) && - ((actual_type->id == ZigTypeIdInt && wanted_type->id == ZigTypeIdComptimeInt) || - (actual_type->id == ZigTypeIdFloat && wanted_type->id == ZigTypeIdComptimeFloat))) - { - return ir_analyze_number_to_literal(ira, scope, source_node, value, wanted_type); - } - - // cast from enum literal to enum with matching field name - if (actual_type->id == ZigTypeIdEnumLiteral && wanted_type->id == ZigTypeIdEnum) - { - return ir_analyze_enum_literal(ira, scope, source_node, value, wanted_type); - } - - // cast from enum literal to optional enum - if (actual_type->id == ZigTypeIdEnumLiteral && - (wanted_type->id == ZigTypeIdOptional && wanted_type->data.maybe.child_type->id == ZigTypeIdEnum)) - { - Stage1AirInst *result = ir_analyze_enum_literal(ira, scope, source_node, value, wanted_type->data.maybe.child_type); - if (type_is_invalid(result->value->type)) - return result; - - return ir_analyze_optional_wrap(ira, scope, source_node, value, wanted_type, nullptr); - } - - // cast from enum literal to error union when payload is an enum - if (actual_type->id == ZigTypeIdEnumLiteral && - (wanted_type->id == ZigTypeIdErrorUnion && wanted_type->data.error_union.payload_type->id == ZigTypeIdEnum)) - { - Stage1AirInst *result = ir_analyze_enum_literal(ira, scope, source_node, value, wanted_type->data.error_union.payload_type); - if (type_is_invalid(result->value->type)) - return result; - - return ir_analyze_err_wrap_payload(ira, scope, source_node, value, wanted_type, nullptr); - } - - // cast from union to the enum type of the union - if (actual_type->id == ZigTypeIdUnion && wanted_type->id == ZigTypeIdEnum) { - if ((err = type_resolve(ira->codegen, actual_type, ResolveStatusZeroBitsKnown))) - return ira->codegen->invalid_inst_gen; - - if (actual_type->data.unionation.tag_type == wanted_type) { - return ir_analyze_union_to_tag(ira, scope, source_node, value, wanted_type); - } - } - - // enum to union which has the enum as the tag type, or - // enum literal to union which has a matching enum as the tag type - if (is_tagged_union(wanted_type) && (actual_type->id == ZigTypeIdEnum || - actual_type->id == ZigTypeIdEnumLiteral)) - { - return ir_analyze_enum_to_union(ira, scope, source_node, value, wanted_type); - } - - // cast from *T to *[1]T - if (wanted_type->id == ZigTypeIdPointer && wanted_type->data.pointer.ptr_len == PtrLenSingle && - actual_type->id == ZigTypeIdPointer && actual_type->data.pointer.ptr_len == PtrLenSingle) - { - ZigType *array_type = wanted_type->data.pointer.child_type; - if (array_type->id == ZigTypeIdArray && array_type->data.array.len == 1 && - types_match_const_cast_only(ira, array_type->data.array.child_type, - actual_type->data.pointer.child_type, source_node, - !wanted_type->data.pointer.is_const).id == ConstCastResultIdOk && - // `types_match_const_cast_only` only gets info for child_types - (!actual_type->data.pointer.is_const || wanted_type->data.pointer.is_const) && - (!actual_type->data.pointer.is_volatile || wanted_type->data.pointer.is_volatile)) - { - if ((err = ir_cast_ptr_align(ira, scope, source_node, wanted_type, actual_type, value->source_node))) - return ira->codegen->invalid_inst_gen; - - return ir_analyze_ptr_to_array(ira, scope, source_node, value, wanted_type); - } - } - - // [:x]T to [*:x]T - // [:x]T to [*c]T - if (wanted_type->id == ZigTypeIdPointer && is_slice(actual_type) && - ((wanted_type->data.pointer.ptr_len == PtrLenUnknown && wanted_type->data.pointer.sentinel != nullptr) || - wanted_type->data.pointer.ptr_len == PtrLenC)) - { - ZigType *slice_ptr_type = resolve_struct_field_type(ira->codegen, - actual_type->data.structure.fields[slice_ptr_index]); - if (types_match_const_cast_only(ira, wanted_type->data.pointer.child_type, - slice_ptr_type->data.pointer.child_type, source_node, - !wanted_type->data.pointer.is_const).id == ConstCastResultIdOk && - (slice_ptr_type->data.pointer.sentinel != nullptr && - (wanted_type->data.pointer.ptr_len == PtrLenC || - const_values_equal(ira->codegen, wanted_type->data.pointer.sentinel, - slice_ptr_type->data.pointer.sentinel)))) - { - TypeStructField *ptr_field = actual_type->data.structure.fields[slice_ptr_index]; - Stage1AirInst *slice_ptr = ir_analyze_struct_value_field_value(ira, scope, source_node, value, ptr_field); - return ir_implicit_cast2(ira, scope, source_node, slice_ptr, wanted_type); - } - } - - // cast from *T and [*]T to *anyopaque and ?*anyopaque - // but don't do it if the actual type is a double pointer - if (is_pointery_and_elem_is_not_pointery(actual_type)) { - ZigType *dest_ptr_type = nullptr; - if (wanted_type->id == ZigTypeIdPointer && - actual_type->id != ZigTypeIdOptional && - wanted_type->data.pointer.child_type == ira->codegen->builtin_types.entry_anyopaque) - { - dest_ptr_type = wanted_type; - } else if (wanted_type->id == ZigTypeIdOptional && - wanted_type->data.maybe.child_type->id == ZigTypeIdPointer && - wanted_type->data.maybe.child_type->data.pointer.child_type == ira->codegen->builtin_types.entry_anyopaque) - { - dest_ptr_type = wanted_type->data.maybe.child_type; - } - if (dest_ptr_type != nullptr) { - return ir_analyze_ptr_cast(ira, scope, source_node, value, source_node, - wanted_type, source_node, true, false); - } - } - - // cast from T to *T where T is zero bits - if (wanted_type->id == ZigTypeIdPointer && wanted_type->data.pointer.ptr_len == PtrLenSingle && - types_match_const_cast_only(ira, wanted_type->data.pointer.child_type, - actual_type, source_node, !wanted_type->data.pointer.is_const).id == ConstCastResultIdOk) - { - bool has_bits; - if ((err = type_has_bits2(ira->codegen, actual_type, &has_bits))) - return ira->codegen->invalid_inst_gen; - if (!has_bits) { - return ir_get_ref(ira, scope, source_node, value, false, false); - } - } - - // cast from @Vector(N, T) to [N]T - if (wanted_type->id == ZigTypeIdArray && actual_type->id == ZigTypeIdVector && - wanted_type->data.array.len == actual_type->data.vector.len && - types_match_const_cast_only(ira, wanted_type->data.array.child_type, - actual_type->data.vector.elem_type, source_node, false).id == ConstCastResultIdOk) - { - return ir_analyze_vector_to_array(ira, scope, source_node, value, wanted_type, nullptr); - } - - // cast from [N]T to @Vector(N, T) - if (actual_type->id == ZigTypeIdArray && wanted_type->id == ZigTypeIdVector && - actual_type->data.array.len == wanted_type->data.vector.len && - types_match_const_cast_only(ira, actual_type->data.array.child_type, - wanted_type->data.vector.elem_type, source_node, false).id == ConstCastResultIdOk) - { - return ir_analyze_array_to_vector(ira, scope, source_node, value, wanted_type); - } - - // casting between C pointers and normal pointers - if (wanted_type->id == ZigTypeIdPointer && actual_type->id == ZigTypeIdPointer && - (wanted_type->data.pointer.ptr_len == PtrLenC || actual_type->data.pointer.ptr_len == PtrLenC) && - types_match_const_cast_only(ira, wanted_type->data.pointer.child_type, - actual_type->data.pointer.child_type, source_node, - !wanted_type->data.pointer.is_const).id == ConstCastResultIdOk) - { - return ir_analyze_ptr_cast(ira, scope, source_node, value, source_node, - wanted_type, source_node, true, false); - } - - // cast from integer to C pointer - if (wanted_type->id == ZigTypeIdPointer && wanted_type->data.pointer.ptr_len == PtrLenC && - (actual_type->id == ZigTypeIdInt || actual_type->id == ZigTypeIdComptimeInt)) - { - return ir_analyze_int_to_c_ptr(ira, scope, source_node, value, wanted_type); - } - - // cast from inferred struct type to array, union, or struct - if (is_anon_container(actual_type)) { - const bool is_array_init = - actual_type->data.structure.special == StructSpecialInferredTuple; - const uint32_t field_count = actual_type->data.structure.src_field_count; - - if (wanted_type->id == ZigTypeIdArray && (is_array_init || field_count == 0) && - wanted_type->data.array.len == field_count) - { - Stage1AirInst *struct_ptr = ir_get_ref(ira, scope, source_node, value, true, false); - if (type_is_invalid(struct_ptr->value->type)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *ptr = ir_analyze_struct_literal_to_array(ira, scope, source_node, struct_ptr, actual_type, wanted_type); - if (ptr->value->type->id != ZigTypeIdPointer) - return ptr; - return ir_get_deref(ira, scope, source_node, ptr, nullptr); - } else if (wanted_type->id == ZigTypeIdStruct && !is_slice(wanted_type) && - (!is_array_init || field_count == 0)) - { - Stage1AirInst *struct_ptr = ir_get_ref(ira, scope, source_node, value, true, false); - if (type_is_invalid(struct_ptr->value->type)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *ptr = ir_analyze_struct_literal_to_struct(ira, scope, source_node, struct_ptr, actual_type, wanted_type); - if (ptr->value->type->id != ZigTypeIdPointer) - return ptr; - return ir_get_deref(ira, scope, source_node, ptr, nullptr); - } else if (wanted_type->id == ZigTypeIdUnion && !is_array_init && field_count == 1) { - Stage1AirInst *struct_ptr = ir_get_ref(ira, scope, source_node, value, true, false); - if (type_is_invalid(struct_ptr->value->type)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *ptr = ir_analyze_struct_literal_to_union(ira, scope, source_node, struct_ptr, actual_type, wanted_type); - if (ptr->value->type->id != ZigTypeIdPointer) - return ptr; - return ir_get_deref(ira, scope, source_node, ptr, nullptr); - } - } - - // cast from pointer to inferred struct type to pointer to array, union, or struct - if (actual_type->id == ZigTypeIdPointer && is_anon_container(actual_type->data.pointer.child_type)) { - ZigType *anon_type = actual_type->data.pointer.child_type; - const bool is_array_init = - anon_type->data.structure.special == StructSpecialInferredTuple; - const uint32_t field_count = anon_type->data.structure.src_field_count; - - if (wanted_type->id == ZigTypeIdPointer && - (!actual_type->data.pointer.is_volatile || wanted_type->data.pointer.is_volatile)) - { - ZigType *wanted_child = wanted_type->data.pointer.child_type; - bool const_ok = (!actual_type->data.pointer.is_const || wanted_type->data.pointer.is_const); - if (wanted_child->id == ZigTypeIdArray && (is_array_init || field_count == 0) && - wanted_child->data.array.len == field_count) - { - if (!const_ok && field_count != 0) { - ErrorMsg *msg = ir_add_error_node(ira, source_node, - buf_sprintf("cannot cast pointer to array literal to '%s'", - buf_ptr(&wanted_type->name))); - add_error_note(ira->codegen, msg, source_node, - buf_sprintf("cast discards const qualifier")); - return ira->codegen->invalid_inst_gen; - } - Stage1AirInst *res = ir_analyze_struct_literal_to_array(ira, scope, source_node, value, anon_type, wanted_child); - if (res->value->type->id == ZigTypeIdPointer) - return res; - return ir_get_ref(ira, scope, source_node, res, actual_type->data.pointer.is_const, actual_type->data.pointer.is_volatile); - } else if (wanted_child->id == ZigTypeIdStruct && !is_slice(wanted_type) && - (!is_array_init || field_count == 0) && const_ok) - { - Stage1AirInst *res = ir_analyze_struct_literal_to_struct(ira, scope, source_node, value, anon_type, wanted_child); - if (res->value->type->id == ZigTypeIdPointer) - return res; - return ir_get_ref(ira, scope, source_node, res, actual_type->data.pointer.is_const, actual_type->data.pointer.is_volatile); - } else if (wanted_child->id == ZigTypeIdUnion && !is_array_init && field_count == 1 && const_ok) { - Stage1AirInst *res = ir_analyze_struct_literal_to_union(ira, scope, source_node, value, anon_type, wanted_child); - if (res->value->type->id == ZigTypeIdPointer) - return res; - return ir_get_ref(ira, scope, source_node, res, actual_type->data.pointer.is_const, actual_type->data.pointer.is_volatile); - } - } else if (is_slice(wanted_type) && (is_array_init || field_count == 0)) { - ZigType *slice_type = wanted_type->data.structure.fields[slice_ptr_index]->type_entry; - if ((!actual_type->data.pointer.is_const || slice_type->data.pointer.is_const || field_count == 0) && - (!actual_type->data.pointer.is_volatile || slice_type->data.pointer.is_volatile)) - { - ZigType *slice_child_type = slice_type->data.pointer.child_type; - ZigType *slice_array_type = get_array_type(ira->codegen, slice_child_type, field_count, nullptr); - Stage1AirInst *res = ir_analyze_struct_literal_to_array(ira, scope, source_node, value, anon_type, slice_array_type); - if (type_is_invalid(res->value->type)) - return ira->codegen->invalid_inst_gen; - if (res->value->type->id != ZigTypeIdPointer) - res = ir_get_ref(ira, scope, source_node, res, actual_type->data.pointer.is_const, actual_type->data.pointer.is_volatile); - - return ir_resolve_ptr_of_array_to_slice(ira, scope, source_node, res, wanted_type, nullptr); - } else if (!slice_type->data.pointer.is_const && actual_type->data.pointer.is_const && field_count != 0) { - ErrorMsg *msg = ir_add_error_node(ira, source_node, - buf_sprintf("cannot cast pointer to array literal to slice type '%s'", - buf_ptr(&wanted_type->name))); - add_error_note(ira->codegen, msg, source_node, - buf_sprintf("cast discards const qualifier")); - return ira->codegen->invalid_inst_gen; - } - } - } - - // cast from undefined to anything - if (actual_type->id == ZigTypeIdUndefined) { - return ir_analyze_undefined_to_anything(ira, scope, source_node, value, wanted_type); - } - - // T to ?U, where T implicitly casts to U - if (wanted_type->id == ZigTypeIdOptional && actual_type->id != ZigTypeIdOptional) { - Stage1AirInst *cast1 = ir_implicit_cast2(ira, scope, source_node, value, wanted_type->data.maybe.child_type); - if (type_is_invalid(cast1->value->type)) - return ira->codegen->invalid_inst_gen; - return ir_implicit_cast2(ira, scope, source_node, cast1, wanted_type); - } - - // T to E!U, where T implicitly casts to U - if (wanted_type->id == ZigTypeIdErrorUnion && actual_type->id != ZigTypeIdErrorUnion && - actual_type->id != ZigTypeIdErrorSet) - { - Stage1AirInst *cast1 = ir_implicit_cast2(ira, scope, source_node, value, wanted_type->data.error_union.payload_type); - if (type_is_invalid(cast1->value->type)) - return ira->codegen->invalid_inst_gen; - return ir_implicit_cast2(ira, scope, source_node, cast1, wanted_type); - } - - // E!T to T - if (actual_type->id == ZigTypeIdErrorUnion) { - if (types_match_const_cast_only(ira, actual_type->data.error_union.payload_type, wanted_type, - source_node, false).id == ConstCastResultIdOk) - { - ErrorMsg *parent_msg = ir_add_error_node(ira, source_node, - buf_sprintf("cannot convert error union to payload type. consider using `try`, `catch`, or `if`. expected type '%s', found '%s'", - buf_ptr(&wanted_type->name), - buf_ptr(&actual_type->name))); - report_recursive_error(ira, source_node, &const_cast_result, parent_msg); - return ira->codegen->invalid_inst_gen; - } - } - - //?T to T - if (actual_type->id == ZigTypeIdOptional) { - if (types_match_const_cast_only(ira, actual_type->data.maybe.child_type, wanted_type, - source_node, false).id == ConstCastResultIdOk) - { - ErrorMsg *parent_msg = ir_add_error_node(ira, source_node, - buf_sprintf("cannot convert optional to payload type. consider using `.?`, `orelse`, or `if`. expected type '%s', found '%s'", - buf_ptr(&wanted_type->name), - buf_ptr(&actual_type->name))); - report_recursive_error(ira, source_node, &const_cast_result, parent_msg); - return ira->codegen->invalid_inst_gen; - } - } - - ErrorMsg *parent_msg = ir_add_error_node(ira, source_node, - buf_sprintf("expected type '%s', found '%s'", - buf_ptr(&wanted_type->name), - buf_ptr(&actual_type->name))); - report_recursive_error(ira, source_node, &const_cast_result, parent_msg); - return ira->codegen->invalid_inst_gen; -} - -static Stage1AirInst *ir_implicit_cast2(IrAnalyze *ira, Scope *scope, AstNode *source_node, - Stage1AirInst *value, ZigType *expected_type) -{ - assert(value); - assert(!expected_type || !type_is_invalid(expected_type)); - assert(value->value->type); - assert(!type_is_invalid(value->value->type)); - if (expected_type == nullptr) - return value; // anything will do - if (expected_type == value->value->type) - return value; // match - if (value->value->type->id == ZigTypeIdUnreachable) - return value; - - return ir_analyze_cast(ira, scope, source_node, expected_type, value); -} - -static Stage1AirInst *ir_implicit_cast(IrAnalyze *ira, Stage1AirInst *value, ZigType *expected_type) { - return ir_implicit_cast2(ira, value->scope, value->source_node, value, expected_type); -} - -static ZigType *get_ptr_elem_type(CodeGen *g, Stage1AirInst *ptr) { - ir_assert(ptr->value->type->id == ZigTypeIdPointer, ptr); - ZigType *elem_type = ptr->value->type->data.pointer.child_type; - if (elem_type != g->builtin_types.entry_anytype) - return elem_type; - - if (ir_resolve_lazy(g, ptr->source_node, ptr->value)) - return g->builtin_types.entry_invalid; - - assert(value_is_comptime(ptr->value)); - ZigValue *pointee = const_ptr_pointee_unchecked(g, ptr->value); - return pointee->type; -} - -static Stage1AirInst *ir_get_deref(IrAnalyze *ira, Scope *scope, AstNode *source_node, Stage1AirInst *ptr, - ResultLoc *result_loc) -{ - Error err; - ZigType *ptr_type = ptr->value->type; - if (type_is_invalid(ptr_type)) - return ira->codegen->invalid_inst_gen; - - if (ptr_type->id != ZigTypeIdPointer) { - ir_add_error_node(ira, source_node, - buf_sprintf("attempt to dereference non-pointer type '%s'", - buf_ptr(&ptr_type->name))); - return ira->codegen->invalid_inst_gen; - } - - ZigType *child_type = ptr_type->data.pointer.child_type; - if (type_is_invalid(child_type)) - return ira->codegen->invalid_inst_gen; - // if the child type has one possible value, the deref is comptime - switch (type_has_one_possible_value(ira->codegen, child_type)) { - case OnePossibleValueInvalid: - return ira->codegen->invalid_inst_gen; - case OnePossibleValueYes: - return ir_const_move(ira, scope, source_node, - get_the_one_possible_value(ira->codegen, child_type)); - case OnePossibleValueNo: - break; - } - if (instr_is_comptime(ptr)) { - if (ptr->value->special == ConstValSpecialUndef) { - // If we are in a TypeOf call, we return an undefined value instead of erroring - // since we know the type. - if (get_scope_typeof(scope)) { - return ir_const_undef(ira, scope, source_node, child_type); - } - - ir_add_error(ira, ptr, buf_sprintf("attempt to dereference undefined value")); - return ira->codegen->invalid_inst_gen; - } - if (ptr->value->data.x_ptr.mut != ConstPtrMutRuntimeVar) { - ZigValue *pointee = const_ptr_pointee_unchecked(ira->codegen, ptr->value); - if (child_type == ira->codegen->builtin_types.entry_anytype) { - child_type = pointee->type; - } - if (pointee->special != ConstValSpecialRuntime) { - Stage1AirInst *result = ir_const(ira, scope, source_node, child_type); - - if ((err = ir_read_const_ptr(ira, ira->codegen, source_node, result->value, - ptr->value))) - { - return ira->codegen->invalid_inst_gen; - } - result->value->type = child_type; - return result; - } - } - } - - // if the instruction is a const ref instruction we can skip it - if (ptr->id == Stage1AirInstIdRef) { - Stage1AirInstRef *ref_inst = reinterpret_cast(ptr); - return ref_inst->operand; - } - - // If the instruction is a element pointer instruction to a vector, we emit - // vector element extract instruction rather than load pointer. If the - // pointer type has non-VECTOR_INDEX_RUNTIME value, it would have been - // possible to implement this in the codegen for Stage1AirInstLoadPtr. - // However if it has VECTOR_INDEX_RUNTIME then we must emit a compile error - // if the vector index cannot be determined right here, right now, because - // the type information does not contain enough information to actually - // perform a dereference. - if (ptr_type->data.pointer.vector_index == VECTOR_INDEX_RUNTIME) { - if (ptr->id == Stage1AirInstIdElemPtr) { - Stage1AirInstElemPtr *elem_ptr = (Stage1AirInstElemPtr *)ptr; - Stage1AirInst *vector_loaded = ir_get_deref(ira, elem_ptr->array_ptr->scope, - elem_ptr->array_ptr->source_node, elem_ptr->array_ptr, nullptr); - Stage1AirInst *elem_index = elem_ptr->elem_index; - return ir_build_vector_extract_elem(ira, scope, source_node, vector_loaded, elem_index); - } - ir_add_error(ira, ptr, - buf_sprintf("unable to determine vector element index of type '%s'", buf_ptr(&ptr_type->name))); - return ira->codegen->invalid_inst_gen; - } - - Stage1AirInst *result_loc_inst; - if (ptr_type->data.pointer.host_int_bytes != 0 && handle_is_ptr(ira->codegen, child_type)) { - if (result_loc == nullptr) result_loc = no_result_loc(); - result_loc_inst = ir_resolve_result(ira, ira->suspend_source_instr, result_loc, child_type, nullptr, true, true); - if (type_is_invalid(result_loc_inst->value->type) || result_loc_inst->value->type->id == ZigTypeIdUnreachable) { - return result_loc_inst; - } - } else { - result_loc_inst = nullptr; - } - - return ir_build_load_ptr_gen(ira, scope, source_node, ptr, child_type, result_loc_inst); -} - -static bool ir_resolve_const_align(CodeGen *codegen, Stage1Air *exec, AstNode *source_node, - ZigValue *const_val, uint32_t *out) -{ - Error err; - if ((err = ir_resolve_const_val(codegen, exec, source_node, const_val, UndefBad))) - return false; - - uint32_t align_bytes = bigint_as_u32(&const_val->data.x_bigint); - if (align_bytes == 0) { - exec_add_error_node_gen(codegen, exec, source_node, buf_sprintf("alignment must be >= 1")); - return false; - } - - if (!is_power_of_2(align_bytes)) { - exec_add_error_node_gen(codegen, exec, source_node, - buf_sprintf("alignment value %" PRIu32 " is not a power of 2", align_bytes)); - return false; - } - - *out = align_bytes; - return true; -} - -static bool ir_resolve_align(IrAnalyze *ira, Stage1AirInst *value, ZigType *elem_type, uint32_t *out) { - if (type_is_invalid(value->value->type)) - return false; - - // Look for this pattern: `*align(@alignOf(T)) T`. - // This can be resolved to be `*out = 0` without resolving any alignment. - if (elem_type != nullptr && value->value->special == ConstValSpecialLazy && - value->value->data.x_lazy->id == LazyValueIdAlignOf) - { - LazyValueAlignOf *lazy_align_of = reinterpret_cast(value->value->data.x_lazy); - - ZigType *lazy_elem_type = ir_resolve_type(lazy_align_of->ira, lazy_align_of->target_type); - if (type_is_invalid(lazy_elem_type)) - return false; - - if (elem_type == lazy_elem_type) { - *out = 0; - return true; - } - } - - Stage1AirInst *casted_value = ir_implicit_cast(ira, value, get_align_amt_type(ira->codegen)); - if (type_is_invalid(casted_value->value->type)) - return false; - - return ir_resolve_const_align(ira->codegen, ira->new_irb.exec, value->source_node, - casted_value->value, out); -} - -static bool ir_resolve_unsigned(IrAnalyze *ira, Stage1AirInst *value, ZigType *int_type, uint64_t *out) { - if (type_is_invalid(value->value->type)) - return false; - - Stage1AirInst *casted_value = ir_implicit_cast(ira, value, int_type); - if (type_is_invalid(casted_value->value->type)) - return false; - - ZigValue *const_val = ir_resolve_const(ira, casted_value, UndefBad); - if (!const_val) - return false; - - *out = bigint_as_u64(&const_val->data.x_bigint); - return true; -} - -static bool ir_resolve_usize(IrAnalyze *ira, Stage1AirInst *value, uint64_t *out) { - return ir_resolve_unsigned(ira, value, ira->codegen->builtin_types.entry_usize, out); -} - -static bool ir_resolve_bool(IrAnalyze *ira, Stage1AirInst *value, bool *out) { - if (type_is_invalid(value->value->type)) - return false; - - Stage1AirInst *casted_value = ir_implicit_cast(ira, value, ira->codegen->builtin_types.entry_bool); - if (type_is_invalid(casted_value->value->type)) - return false; - - ZigValue *const_val = ir_resolve_const(ira, casted_value, UndefBad); - if (!const_val) - return false; - - *out = const_val->data.x_bool; - return true; -} - -static bool ir_resolve_comptime(IrAnalyze *ira, Stage1AirInst *value, bool *out) { - if (!value) { - *out = false; - return true; - } - return ir_resolve_bool(ira, value, out); -} - -static bool ir_resolve_reduce_op(IrAnalyze *ira, Stage1AirInst *value, ReduceOp *out) { - if (type_is_invalid(value->value->type)) - return false; - - ZigType *reduce_op_type = get_builtin_type(ira->codegen, "ReduceOp"); - - Stage1AirInst *casted_value = ir_implicit_cast(ira, value, reduce_op_type); - if (type_is_invalid(casted_value->value->type)) - return false; - - ZigValue *const_val = ir_resolve_const(ira, casted_value, UndefBad); - if (!const_val) - return false; - - *out = (ReduceOp)bigint_as_u32(&const_val->data.x_enum_tag); - return true; -} - -static bool ir_resolve_atomic_order(IrAnalyze *ira, Stage1AirInst *value, AtomicOrder *out) { - if (type_is_invalid(value->value->type)) - return false; - - ZigType *atomic_order_type = get_builtin_type(ira->codegen, "AtomicOrder"); - - Stage1AirInst *casted_value = ir_implicit_cast(ira, value, atomic_order_type); - if (type_is_invalid(casted_value->value->type)) - return false; - - ZigValue *const_val = ir_resolve_const(ira, casted_value, UndefBad); - if (!const_val) - return false; - - *out = (AtomicOrder)bigint_as_u32(&const_val->data.x_enum_tag); - return true; -} - -static bool ir_resolve_atomic_rmw_op(IrAnalyze *ira, Stage1AirInst *value, AtomicRmwOp *out) { - if (type_is_invalid(value->value->type)) - return false; - - ZigType *atomic_rmw_op_type = get_builtin_type(ira->codegen, "AtomicRmwOp"); - - Stage1AirInst *casted_value = ir_implicit_cast(ira, value, atomic_rmw_op_type); - if (type_is_invalid(casted_value->value->type)) - return false; - - ZigValue *const_val = ir_resolve_const(ira, casted_value, UndefBad); - if (!const_val) - return false; - - *out = (AtomicRmwOp)bigint_as_u32(&const_val->data.x_enum_tag); - return true; -} - -static bool ir_resolve_global_linkage(IrAnalyze *ira, Stage1AirInst *value, GlobalLinkageId *out) { - if (type_is_invalid(value->value->type)) - return false; - - ZigType *global_linkage_type = get_builtin_type(ira->codegen, "GlobalLinkage"); - - Stage1AirInst *casted_value = ir_implicit_cast(ira, value, global_linkage_type); - if (type_is_invalid(casted_value->value->type)) - return false; - - ZigValue *const_val = ir_resolve_const(ira, casted_value, UndefBad); - if (!const_val) - return false; - - *out = (GlobalLinkageId)bigint_as_u32(&const_val->data.x_enum_tag); - return true; -} - -static bool ir_resolve_float_mode(IrAnalyze *ira, Stage1AirInst *value, FloatMode *out) { - if (type_is_invalid(value->value->type)) - return false; - - ZigType *float_mode_type = get_builtin_type(ira->codegen, "FloatMode"); - - Stage1AirInst *casted_value = ir_implicit_cast(ira, value, float_mode_type); - if (type_is_invalid(casted_value->value->type)) - return false; - - ZigValue *const_val = ir_resolve_const(ira, casted_value, UndefBad); - if (!const_val) - return false; - - *out = (FloatMode)bigint_as_u32(&const_val->data.x_enum_tag); - return true; -} - -static Buf *ir_resolve_str(IrAnalyze *ira, Stage1AirInst *value) { - if (type_is_invalid(value->value->type)) - return nullptr; - - ZigType *ptr_type = get_pointer_to_type_extra(ira->codegen, ira->codegen->builtin_types.entry_u8, - true, false, PtrLenUnknown, 0, 0, 0, false); - ZigType *str_type = get_slice_type(ira->codegen, ptr_type); - Stage1AirInst *casted_value = ir_implicit_cast(ira, value, str_type); - if (type_is_invalid(casted_value->value->type)) - return nullptr; - - ZigValue *const_val = ir_resolve_const(ira, casted_value, UndefBad); - if (!const_val) - return nullptr; - - ZigValue *ptr_field = const_val->data.x_struct.fields[slice_ptr_index]; - ZigValue *len_field = const_val->data.x_struct.fields[slice_len_index]; - - assert(ptr_field->data.x_ptr.special == ConstPtrSpecialBaseArray); - ZigValue *array_val = ptr_field->data.x_ptr.data.base_array.array_val; - expand_undef_array(ira->codegen, array_val); - size_t len = bigint_as_usize(&len_field->data.x_bigint); - if (array_val->data.x_array.special == ConstArraySpecialBuf && len == buf_len(array_val->data.x_array.data.s_buf)) { - return array_val->data.x_array.data.s_buf; - } - Buf *result = buf_alloc(); - buf_resize(result, len); - for (size_t i = 0; i < len; i += 1) { - size_t new_index = ptr_field->data.x_ptr.data.base_array.elem_index + i; - ZigValue *char_val = &array_val->data.x_array.data.s_none.elements[new_index]; - if (char_val->special == ConstValSpecialUndef) { - ir_add_error(ira, casted_value, buf_sprintf("use of undefined value")); - return nullptr; - } - uint64_t big_c = bigint_as_u64(&char_val->data.x_bigint); - assert(big_c <= UINT8_MAX); - uint8_t c = (uint8_t)big_c; - buf_ptr(result)[i] = c; - } - return result; -} - -static Stage1AirInst *ir_analyze_instruction_add_implicit_return_type(IrAnalyze *ira, - Stage1ZirInstAddImplicitReturnType *instruction) -{ - Stage1AirInst *value = instruction->value->child; - if (type_is_invalid(value->value->type)) - return ir_unreach_error(ira); - - if (instruction->result_loc_ret == nullptr || !instruction->result_loc_ret->implicit_return_type_done) { - ira->src_implicit_return_type_list.append(value); - } - - return ir_const_void(ira, instruction->base.scope, instruction->base.source_node); -} - -static Stage1AirInst *ir_analyze_instruction_return(IrAnalyze *ira, Stage1ZirInstReturn *instruction) { - if (instruction->operand == nullptr) { - // result location mechanism took care of it. - Stage1AirInst *result = ir_build_return_gen(ira, instruction->base.scope, instruction->base.source_node, nullptr); - return ir_finish_anal(ira, result); - } - - Stage1AirInst *operand = instruction->operand->child; - if (type_is_invalid(operand->value->type)) - return ir_unreach_error(ira); - - Stage1AirInst *casted_operand = ir_implicit_cast(ira, operand, ira->explicit_return_type); - if (type_is_invalid(casted_operand->value->type)) { - AstNode *source_node = ira->explicit_return_type_source_node; - if (source_node != nullptr) { - ErrorMsg *msg = ira->codegen->errors.last(); - add_error_note(ira->codegen, msg, source_node, - buf_sprintf("return type declared here")); - } - return ir_unreach_error(ira); - } - - if (!instr_is_comptime(operand) && ira->explicit_return_type != nullptr && - handle_is_ptr(ira->codegen, ira->explicit_return_type)) - { - // result location mechanism took care of it. - Stage1AirInst *result = ir_build_return_gen(ira, instruction->base.scope, instruction->base.source_node, nullptr); - return ir_finish_anal(ira, result); - } - - if (casted_operand->value->special == ConstValSpecialRuntime && - casted_operand->value->type->id == ZigTypeIdPointer && - casted_operand->value->data.rh_ptr == RuntimeHintPtrStack) - { - ir_add_error_node(ira, instruction->operand->source_node, - buf_sprintf("function returns address of local variable")); - return ir_unreach_error(ira); - } - - Stage1AirInst *result = ir_build_return_gen(ira, instruction->base.scope, instruction->base.source_node, casted_operand); - return ir_finish_anal(ira, result); -} - -static Stage1AirInst *ir_analyze_instruction_const(IrAnalyze *ira, Stage1ZirInstConst *instruction) { - return ir_const_move(ira, instruction->base.scope, instruction->base.source_node, instruction->value); -} - -static Stage1AirInst *ir_analyze_bin_op_bool(IrAnalyze *ira, Stage1ZirInstBinOp *bin_op_instruction) { - Stage1AirInst *op1 = bin_op_instruction->op1->child; - if (type_is_invalid(op1->value->type)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *op2 = bin_op_instruction->op2->child; - if (type_is_invalid(op2->value->type)) - return ira->codegen->invalid_inst_gen; - - ZigType *bool_type = ira->codegen->builtin_types.entry_bool; - - Stage1AirInst *casted_op1 = ir_implicit_cast(ira, op1, bool_type); - if (type_is_invalid(casted_op1->value->type)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *casted_op2 = ir_implicit_cast(ira, op2, bool_type); - if (type_is_invalid(casted_op2->value->type)) - return ira->codegen->invalid_inst_gen; - - if (instr_is_comptime(casted_op1) && instr_is_comptime(casted_op2)) { - ZigValue *op1_val = ir_resolve_const(ira, casted_op1, UndefBad); - if (op1_val == nullptr) - return ira->codegen->invalid_inst_gen; - - ZigValue *op2_val = ir_resolve_const(ira, casted_op2, UndefBad); - if (op2_val == nullptr) - return ira->codegen->invalid_inst_gen; - - assert(casted_op1->value->type->id == ZigTypeIdBool); - assert(casted_op2->value->type->id == ZigTypeIdBool); - bool result_bool; - if (bin_op_instruction->op_id == IrBinOpBoolOr) { - result_bool = op1_val->data.x_bool || op2_val->data.x_bool; - } else if (bin_op_instruction->op_id == IrBinOpBoolAnd) { - result_bool = op1_val->data.x_bool && op2_val->data.x_bool; - } else { - zig_unreachable(); - } - return ir_const_bool(ira, bin_op_instruction->base.scope, - bin_op_instruction->base.source_node, result_bool); - } - - return ir_build_bin_op_gen(ira, bin_op_instruction->base.scope, - bin_op_instruction->base.source_node, bool_type, bin_op_instruction->op_id, - casted_op1, casted_op2, bin_op_instruction->safety_check_on); -} - -static bool resolve_cmp_op_id(IrBinOp op_id, Cmp cmp) { - switch (op_id) { - case IrBinOpCmpEq: - return cmp == CmpEQ; - case IrBinOpCmpNotEq: - return cmp != CmpEQ; - case IrBinOpCmpLessThan: - return cmp == CmpLT; - case IrBinOpCmpGreaterThan: - return cmp == CmpGT; - case IrBinOpCmpLessOrEq: - return cmp != CmpGT; - case IrBinOpCmpGreaterOrEq: - return cmp != CmpLT; - default: - zig_unreachable(); - } -} - -static void set_optional_value_to_null(ZigValue *val) { - assert(val->special == ConstValSpecialStatic); - if (val->type->id == ZigTypeIdNull) return; // nothing to do - assert(val->type->id == ZigTypeIdOptional); - if (get_src_ptr_type(val->type) != nullptr) { - val->data.x_ptr.special = ConstPtrSpecialNull; - } else if (is_opt_err_set(val->type)) { - val->data.x_err_set = nullptr; - } else { - val->data.x_optional = nullptr; - } -} - -static void set_optional_payload(ZigValue *opt_val, ZigValue *payload) { - assert(opt_val->special == ConstValSpecialStatic); - assert(opt_val->type->id == ZigTypeIdOptional); - if (payload == nullptr) { - set_optional_value_to_null(opt_val); - } else if (get_src_ptr_type(opt_val->type)) { - assert(get_src_ptr_type(payload->type)); - opt_val->data.x_ptr = payload->data.x_ptr; - } else if (is_opt_err_set(opt_val->type)) { - assert(payload->type->id == ZigTypeIdErrorSet); - opt_val->data.x_err_set = payload->data.x_err_set; - } else { - opt_val->data.x_optional = payload; - } -} - -static Stage1AirInst *ir_evaluate_bin_op_cmp(IrAnalyze *ira, ZigType *resolved_type, - ZigValue *op1_val, ZigValue *op2_val, Scope *scope, AstNode *source_node, IrBinOp op_id, - bool one_possible_value) -{ - if (op1_val->special == ConstValSpecialUndef || - op2_val->special == ConstValSpecialUndef) - return ir_const_undef(ira, scope, source_node, resolved_type); - if (resolved_type->id == ZigTypeIdPointer && op_id != IrBinOpCmpEq && op_id != IrBinOpCmpNotEq) { - if ((op1_val->data.x_ptr.special == ConstPtrSpecialHardCodedAddr || - op1_val->data.x_ptr.special == ConstPtrSpecialNull) && - (op2_val->data.x_ptr.special == ConstPtrSpecialHardCodedAddr || - op2_val->data.x_ptr.special == ConstPtrSpecialNull)) - { - uint64_t op1_addr = op1_val->data.x_ptr.special == ConstPtrSpecialNull ? - 0 : op1_val->data.x_ptr.data.hard_coded_addr.addr; - uint64_t op2_addr = op2_val->data.x_ptr.special == ConstPtrSpecialNull ? - 0 : op2_val->data.x_ptr.data.hard_coded_addr.addr; - Cmp cmp_result; - if (op1_addr > op2_addr) { - cmp_result = CmpGT; - } else if (op1_addr < op2_addr) { - cmp_result = CmpLT; - } else { - cmp_result = CmpEQ; - } - bool answer = resolve_cmp_op_id(op_id, cmp_result); - return ir_const_bool(ira, scope, source_node, answer); - } - } else { - bool are_equal = one_possible_value || const_values_equal(ira->codegen, op1_val, op2_val); - bool answer; - if (op_id == IrBinOpCmpEq) { - answer = are_equal; - } else if (op_id == IrBinOpCmpNotEq) { - answer = !are_equal; - } else { - zig_unreachable(); - } - return ir_const_bool(ira, scope, source_node, answer); - } - zig_unreachable(); -} - -static Stage1AirInst *ir_try_evaluate_bin_op_cmp_const(IrAnalyze *ira, Scope *scope, AstNode *source_node, Stage1AirInst *op1, Stage1AirInst *op2, - ZigType *resolved_type, IrBinOp op_id) -{ - assert(op1->value->type == resolved_type && op2->value->type == resolved_type); - bool one_possible_value; - switch (type_has_one_possible_value(ira->codegen, resolved_type)) { - case OnePossibleValueInvalid: - return ira->codegen->invalid_inst_gen; - case OnePossibleValueYes: - one_possible_value = true; - break; - case OnePossibleValueNo: - one_possible_value = false; - break; - } - - if (one_possible_value || (instr_is_comptime(op1) && instr_is_comptime(op2))) { - ZigValue *op1_val = one_possible_value ? op1->value : ir_resolve_const(ira, op1, UndefBad); - if (op1_val == nullptr) - return ira->codegen->invalid_inst_gen; - ZigValue *op2_val = one_possible_value ? op2->value : ir_resolve_const(ira, op2, UndefBad); - if (op2_val == nullptr) - return ira->codegen->invalid_inst_gen; - if (resolved_type->id != ZigTypeIdVector) - return ir_evaluate_bin_op_cmp(ira, resolved_type, op1_val, op2_val, scope, source_node, op_id, one_possible_value); - Stage1AirInst *result = ir_const(ira, scope, source_node, - get_vector_type(ira->codegen, resolved_type->data.vector.len, ira->codegen->builtin_types.entry_bool)); - result->value->data.x_array.data.s_none.elements = - ira->codegen->pass1_arena->allocate(resolved_type->data.vector.len); - - expand_undef_array(ira->codegen, result->value); - for (size_t i = 0;i < resolved_type->data.vector.len;i++) { - Stage1AirInst *cur_res = ir_evaluate_bin_op_cmp(ira, resolved_type->data.vector.elem_type, - &op1_val->data.x_array.data.s_none.elements[i], - &op2_val->data.x_array.data.s_none.elements[i], - scope, source_node, op_id, one_possible_value); - copy_const_val(ira->codegen, &result->value->data.x_array.data.s_none.elements[i], cur_res->value); - } - return result; - } else { - return nullptr; - } -} - -// Returns ErrorNotLazy when the value cannot be determined -static Error lazy_cmp_zero(CodeGen *codegen, AstNode *source_node, ZigValue *val, Cmp *result) { - Error err; - - switch (type_has_one_possible_value(codegen, val->type)) { - case OnePossibleValueInvalid: - return ErrorSemanticAnalyzeFail; - case OnePossibleValueNo: - break; - case OnePossibleValueYes: - switch (val->type->id) { - case ZigTypeIdInt: - src_assert(val->type->data.integral.bit_count == 0, source_node); - *result = CmpEQ; - return ErrorNone; - case ZigTypeIdUndefined: - return ErrorNotLazy; - default: - zig_unreachable(); - } - } - - switch (val->special) { - case ConstValSpecialRuntime: - case ConstValSpecialUndef: - return ErrorNotLazy; - case ConstValSpecialStatic: - switch (val->type->id) { - case ZigTypeIdComptimeInt: - case ZigTypeIdInt: - *result = bigint_cmp_zero(&val->data.x_bigint); - return ErrorNone; - case ZigTypeIdComptimeFloat: - case ZigTypeIdFloat: - if (float_is_nan(val)) - return ErrorNotLazy; - *result = float_cmp_zero(val); - return ErrorNone; - default: - return ErrorNotLazy; - } - case ConstValSpecialLazy: - switch (val->data.x_lazy->id) { - case LazyValueIdInvalid: - zig_unreachable(); - case LazyValueIdAlignOf: { - LazyValueAlignOf *lazy_align_of = reinterpret_cast(val->data.x_lazy); - IrAnalyze *ira = lazy_align_of->ira; - - bool is_zero_bits; - if ((err = type_val_resolve_zero_bits(ira->codegen, lazy_align_of->target_type->value, - nullptr, nullptr, &is_zero_bits))) - { - return err; - } - - *result = is_zero_bits ? CmpEQ : CmpGT; - return ErrorNone; - } - case LazyValueIdSizeOf: { - LazyValueSizeOf *lazy_size_of = reinterpret_cast(val->data.x_lazy); - IrAnalyze *ira = lazy_size_of->ira; - bool is_zero_bits; - if ((err = type_val_resolve_zero_bits(ira->codegen, lazy_size_of->target_type->value, - nullptr, nullptr, &is_zero_bits))) - { - return err; - } - *result = is_zero_bits ? CmpEQ : CmpGT; - return ErrorNone; - } - default: - return ErrorNotLazy; - } - } - zig_unreachable(); -} - -static ErrorMsg *ir_eval_bin_op_cmp_scalar(IrAnalyze *ira, Scope *scope, AstNode *source_node, - ZigValue *op1_val, IrBinOp op_id, ZigValue *op2_val, ZigValue *out_val) -{ - Error err; - { - // Before resolving the values, we special case comparisons against zero. These can often - // be done without resolving lazy values, preventing potential dependency loops. - Cmp op1_cmp_zero; - if ((err = lazy_cmp_zero(ira->codegen, source_node, op1_val, &op1_cmp_zero))) { - if (err == ErrorNotLazy) goto never_mind_just_calculate_it_normally; - return ira->codegen->trace_err; - } - Cmp op2_cmp_zero; - if ((err = lazy_cmp_zero(ira->codegen, source_node, op2_val, &op2_cmp_zero))) { - if (err == ErrorNotLazy) goto never_mind_just_calculate_it_normally; - return ira->codegen->trace_err; - } - bool can_cmp_zero = false; - Cmp cmp_result; - if (op1_cmp_zero == CmpEQ && op2_cmp_zero == CmpEQ) { - can_cmp_zero = true; - cmp_result = CmpEQ; - } else if (op1_cmp_zero == CmpGT && op2_cmp_zero == CmpEQ) { - can_cmp_zero = true; - cmp_result = CmpGT; - } else if (op1_cmp_zero == CmpEQ && op2_cmp_zero == CmpGT) { - can_cmp_zero = true; - cmp_result = CmpLT; - } else if (op1_cmp_zero == CmpLT && op2_cmp_zero == CmpEQ) { - can_cmp_zero = true; - cmp_result = CmpLT; - } else if (op1_cmp_zero == CmpEQ && op2_cmp_zero == CmpLT) { - can_cmp_zero = true; - cmp_result = CmpGT; - } else if (op1_cmp_zero == CmpLT && op2_cmp_zero == CmpGT) { - can_cmp_zero = true; - cmp_result = CmpLT; - } else if (op1_cmp_zero == CmpGT && op2_cmp_zero == CmpLT) { - can_cmp_zero = true; - cmp_result = CmpGT; - } - if (can_cmp_zero) { - bool answer = resolve_cmp_op_id(op_id, cmp_result); - out_val->special = ConstValSpecialStatic; - out_val->data.x_bool = answer; - return nullptr; - } - } -never_mind_just_calculate_it_normally: - - if ((err = ir_resolve_const_val(ira->codegen, ira->new_irb.exec, source_node, - op1_val, UndefOk))) - { - return ira->codegen->trace_err; - } - if ((err = ir_resolve_const_val(ira->codegen, ira->new_irb.exec, source_node, - op2_val, UndefOk))) - { - return ira->codegen->trace_err; - } - - - if (op1_val->special == ConstValSpecialUndef || op2_val->special == ConstValSpecialUndef || - op1_val->type->id == ZigTypeIdUndefined || op2_val->type->id == ZigTypeIdUndefined) - { - out_val->special = ConstValSpecialUndef; - return nullptr; - } - - bool op1_is_float = op1_val->type->id == ZigTypeIdFloat || op1_val->type->id == ZigTypeIdComptimeFloat; - bool op2_is_float = op2_val->type->id == ZigTypeIdFloat || op2_val->type->id == ZigTypeIdComptimeFloat; - if (op1_is_float && op2_is_float) { - if (float_is_nan(op1_val) || float_is_nan(op2_val)) { - out_val->special = ConstValSpecialStatic; - out_val->data.x_bool = op_id == IrBinOpCmpNotEq; - return nullptr; - } - if (op1_val->type->id == ZigTypeIdComptimeFloat) { - Stage1AirInst *tmp = ir_const_noval(ira, scope, source_node); - tmp->value = op1_val; - Stage1AirInst *casted = ir_implicit_cast(ira, tmp, op2_val->type); - op1_val = casted->value; - } else if (op2_val->type->id == ZigTypeIdComptimeFloat) { - Stage1AirInst *tmp = ir_const_noval(ira, scope, source_node); - tmp->value = op2_val; - Stage1AirInst *casted = ir_implicit_cast(ira, tmp, op1_val->type); - op2_val = casted->value; - } - Cmp cmp_result = float_cmp(op1_val, op2_val); - out_val->special = ConstValSpecialStatic; - out_val->data.x_bool = resolve_cmp_op_id(op_id, cmp_result); - return nullptr; - } - - bool op1_is_int = op1_val->type->id == ZigTypeIdInt || op1_val->type->id == ZigTypeIdComptimeInt; - bool op2_is_int = op2_val->type->id == ZigTypeIdInt || op2_val->type->id == ZigTypeIdComptimeInt; - - if (op1_is_int && op2_is_int) { - Cmp cmp_result = bigint_cmp(&op1_val->data.x_bigint, &op2_val->data.x_bigint); - out_val->special = ConstValSpecialStatic; - out_val->data.x_bool = resolve_cmp_op_id(op_id, cmp_result); - - return nullptr; - } - - // Handle the case where one of the two operands is a fp value and the other - // is an integer value - ZigValue *float_val; - if (op1_is_int && op2_is_float) { - float_val = op2_val; - } else if (op1_is_float && op2_is_int) { - float_val = op1_val; - } else { - zig_unreachable(); - } - - // They can never be equal if the fp value has a non-zero decimal part - if (op_id == IrBinOpCmpEq || op_id == IrBinOpCmpNotEq) { - if (float_has_fraction(float_val)) { - out_val->special = ConstValSpecialStatic; - out_val->data.x_bool = op_id == IrBinOpCmpNotEq; - return nullptr; - } - } - - // Cast the integer operand into a fp value to perform the comparison - BigFloat op1_bigfloat; - BigFloat op2_bigfloat; - value_to_bigfloat(&op1_bigfloat, op1_val); - value_to_bigfloat(&op2_bigfloat, op2_val); - - Cmp cmp_result = bigfloat_cmp(&op1_bigfloat, &op2_bigfloat); - out_val->special = ConstValSpecialStatic; - out_val->data.x_bool = resolve_cmp_op_id(op_id, cmp_result); - - return nullptr; -} - -static Stage1AirInst *ir_analyze_bin_op_cmp_numeric(IrAnalyze *ira, Scope *scope, AstNode *source_node, - Stage1AirInst *op1, Stage1AirInst *op2, IrBinOp op_id) -{ - Error err; - - ZigType *scalar_result_type = ira->codegen->builtin_types.entry_bool; - ZigType *result_type = scalar_result_type; - ZigType *op1_scalar_type = op1->value->type; - ZigType *op2_scalar_type = op2->value->type; - if (op1->value->type->id == ZigTypeIdVector && op2->value->type->id == ZigTypeIdVector) { - if (op1->value->type->data.vector.len != op2->value->type->data.vector.len) { - ir_add_error_node(ira, source_node, - buf_sprintf("vector length mismatch: %" PRIu64 " and %" PRIu64, - op1->value->type->data.vector.len, op2->value->type->data.vector.len)); - return ira->codegen->invalid_inst_gen; - } - result_type = get_vector_type(ira->codegen, op1->value->type->data.vector.len, scalar_result_type); - op1_scalar_type = op1->value->type->data.vector.elem_type; - op2_scalar_type = op2->value->type->data.vector.elem_type; - } else if (op1->value->type->id == ZigTypeIdVector || op2->value->type->id == ZigTypeIdVector) { - ir_add_error_node(ira, source_node, - buf_sprintf("mixed scalar and vector operands to comparison operator: '%s' and '%s'", - buf_ptr(&op1->value->type->name), buf_ptr(&op2->value->type->name))); - return ira->codegen->invalid_inst_gen; - } - - bool opv_op1; - switch (type_has_one_possible_value(ira->codegen, op1->value->type)) { - case OnePossibleValueInvalid: - return ira->codegen->invalid_inst_gen; - case OnePossibleValueYes: - opv_op1 = true; - break; - case OnePossibleValueNo: - opv_op1 = false; - break; - } - bool opv_op2; - switch (type_has_one_possible_value(ira->codegen, op2->value->type)) { - case OnePossibleValueInvalid: - return ira->codegen->invalid_inst_gen; - case OnePossibleValueYes: - opv_op2 = true; - break; - case OnePossibleValueNo: - opv_op2 = false; - break; - } - Cmp op1_cmp_zero; - bool have_op1_cmp_zero = false; - if ((err = lazy_cmp_zero(ira->codegen, source_node, op1->value, &op1_cmp_zero))) { - if (err != ErrorNotLazy) return ira->codegen->invalid_inst_gen; - } else { - have_op1_cmp_zero = true; - } - Cmp op2_cmp_zero; - bool have_op2_cmp_zero = false; - if ((err = lazy_cmp_zero(ira->codegen, source_node, op2->value, &op2_cmp_zero))) { - if (err != ErrorNotLazy) return ira->codegen->invalid_inst_gen; - } else { - have_op2_cmp_zero = true; - } - if (((opv_op1 || instr_is_comptime(op1)) && (opv_op2 || instr_is_comptime(op2))) || - (have_op1_cmp_zero && have_op2_cmp_zero)) - { - Stage1AirInst *result_instruction = ir_const(ira, scope, source_node, result_type); - ZigValue *out_val = result_instruction->value; - if (result_type->id == ZigTypeIdVector) { - size_t len = result_type->data.vector.len; - expand_undef_array(ira->codegen, op1->value); - expand_undef_array(ira->codegen, op2->value); - out_val->special = ConstValSpecialUndef; - expand_undef_array(ira->codegen, out_val); - for (size_t i = 0; i < len; i += 1) { - ZigValue *scalar_op1_val = &op1->value->data.x_array.data.s_none.elements[i]; - ZigValue *scalar_op2_val = &op2->value->data.x_array.data.s_none.elements[i]; - ZigValue *scalar_out_val = &out_val->data.x_array.data.s_none.elements[i]; - assert(scalar_out_val->type == scalar_result_type); - ErrorMsg *msg = ir_eval_bin_op_cmp_scalar(ira, scope, source_node, - scalar_op1_val, op_id, scalar_op2_val, scalar_out_val); - if (msg != nullptr) { - add_error_note(ira->codegen, msg, source_node, - buf_sprintf("when computing vector element at index %" ZIG_PRI_usize, i)); - return ira->codegen->invalid_inst_gen; - } - } - out_val->type = result_type; - out_val->special = ConstValSpecialStatic; - } else { - if (ir_eval_bin_op_cmp_scalar(ira, scope, source_node, op1->value, op_id, - op2->value, out_val) != nullptr) - { - return ira->codegen->invalid_inst_gen; - } - } - return result_instruction; - } - - // If one operand has a comptime-known comparison with 0, and the other operand is unsigned, we might - // know the answer, depending on the operator. - // TODO make this work with vectors - if (have_op1_cmp_zero && op2_scalar_type->id == ZigTypeIdInt && !op2_scalar_type->data.integral.is_signed) { - if (op1_cmp_zero == CmpEQ) { - // 0 <= unsigned_x // true - // 0 > unsigned_x // false - switch (op_id) { - case IrBinOpCmpLessOrEq: - return ir_const_bool(ira, scope, source_node, true); - case IrBinOpCmpGreaterThan: - return ir_const_bool(ira, scope, source_node, false); - default: - break; - } - } else if (op1_cmp_zero == CmpLT) { - // -1 != unsigned_x // true - // -1 <= unsigned_x // true - // -1 < unsigned_x // true - // -1 == unsigned_x // false - // -1 >= unsigned_x // false - // -1 > unsigned_x // false - switch (op_id) { - case IrBinOpCmpNotEq: - case IrBinOpCmpLessOrEq: - case IrBinOpCmpLessThan: - return ir_const_bool(ira, scope, source_node, true); - case IrBinOpCmpEq: - case IrBinOpCmpGreaterOrEq: - case IrBinOpCmpGreaterThan: - return ir_const_bool(ira, scope, source_node, false); - default: - break; - } - } - } - if (have_op2_cmp_zero && op1_scalar_type->id == ZigTypeIdInt && !op1_scalar_type->data.integral.is_signed) { - if (op2_cmp_zero == CmpEQ) { - // unsigned_x < 0 // false - // unsigned_x >= 0 // true - switch (op_id) { - case IrBinOpCmpLessThan: - return ir_const_bool(ira, scope, source_node, false); - case IrBinOpCmpGreaterOrEq: - return ir_const_bool(ira, scope, source_node, true); - default: - break; - } - } else if (op2_cmp_zero == CmpLT) { - // unsigned_x != -1 // true - // unsigned_x >= -1 // true - // unsigned_x > -1 // true - // unsigned_x == -1 // false - // unsigned_x < -1 // false - // unsigned_x <= -1 // false - switch (op_id) { - case IrBinOpCmpNotEq: - case IrBinOpCmpGreaterOrEq: - case IrBinOpCmpGreaterThan: - return ir_const_bool(ira, scope, source_node, true); - case IrBinOpCmpEq: - case IrBinOpCmpLessThan: - case IrBinOpCmpLessOrEq: - return ir_const_bool(ira, scope, source_node, false); - default: - break; - } - } - } - - // It must be a runtime comparison. - // For floats, emit a float comparison instruction. - bool op1_is_float = op1_scalar_type->id == ZigTypeIdFloat || op1_scalar_type->id == ZigTypeIdComptimeFloat; - bool op2_is_float = op2_scalar_type->id == ZigTypeIdFloat || op2_scalar_type->id == ZigTypeIdComptimeFloat; - if (op1_is_float && op2_is_float) { - // Implicit cast the smaller one to the larger one. - ZigType *dest_scalar_type; - if (op1_scalar_type->id == ZigTypeIdComptimeFloat) { - dest_scalar_type = op2_scalar_type; - } else if (op2_scalar_type->id == ZigTypeIdComptimeFloat) { - dest_scalar_type = op1_scalar_type; - } else if (op1_scalar_type->data.floating.bit_count >= op2_scalar_type->data.floating.bit_count) { - dest_scalar_type = op1_scalar_type; - } else { - dest_scalar_type = op2_scalar_type; - } - ZigType *dest_type = (result_type->id == ZigTypeIdVector) ? - get_vector_type(ira->codegen, result_type->data.vector.len, dest_scalar_type) : dest_scalar_type; - Stage1AirInst *casted_op1 = ir_implicit_cast(ira, op1, dest_type); - Stage1AirInst *casted_op2 = ir_implicit_cast(ira, op2, dest_type); - if (type_is_invalid(casted_op1->value->type) || type_is_invalid(casted_op2->value->type)) - return ira->codegen->invalid_inst_gen; - return ir_build_bin_op_gen(ira, scope, source_node, result_type, op_id, casted_op1, casted_op2, true); - } - - // For mixed unsigned integer sizes, implicit cast both operands to the larger integer. - // For mixed signed and unsigned integers, implicit cast both operands to a signed - // integer with + 1 bit. - // For mixed floats and integers, extract the integer part from the float, cast that to - // a signed integer with mantissa bits + 1, and if there was any non-integral part of the float, - // add/subtract 1. - bool dest_int_is_signed = false; - if (have_op1_cmp_zero) { - if (op1_cmp_zero == CmpLT) dest_int_is_signed = true; - } else if (op1_is_float) { - dest_int_is_signed = true; - } else if (op1_scalar_type->id == ZigTypeIdInt && op1_scalar_type->data.integral.is_signed) { - dest_int_is_signed = true; - } - if (have_op2_cmp_zero) { - if (op2_cmp_zero == CmpLT) dest_int_is_signed = true; - } else if (op2_is_float) { - dest_int_is_signed = true; - } else if (op2->value->type->id == ZigTypeIdInt && op2->value->type->data.integral.is_signed) { - dest_int_is_signed = true; - } - ZigType *dest_float_type = nullptr; - uint32_t op1_bits; - if (instr_is_comptime(op1) && result_type->id != ZigTypeIdVector) { - ZigValue *op1_val = ir_resolve_const(ira, op1, UndefOk); - if (op1_val == nullptr) - return ira->codegen->invalid_inst_gen; - if (op1_val->special == ConstValSpecialUndef) - return ir_const_undef(ira, scope, source_node, ira->codegen->builtin_types.entry_bool); - bool is_unsigned; - if (op1_is_float) { - BigInt bigint = {}; - float_init_bigint(&bigint, op1_val); - Cmp zcmp = float_cmp_zero(op1_val); - if (float_has_fraction(op1_val)) { - if (op_id == IrBinOpCmpEq || op_id == IrBinOpCmpNotEq) { - return ir_const_bool(ira, scope, source_node, op_id == IrBinOpCmpNotEq); - } - if (zcmp == CmpLT) { - bigint_decr(&bigint); - } else { - bigint_incr(&bigint); - } - } - op1_bits = bigint_bits_needed(&bigint); - is_unsigned = zcmp != CmpLT; - } else { - op1_bits = bigint_bits_needed(&op1_val->data.x_bigint); - is_unsigned = bigint_cmp_zero(&op1_val->data.x_bigint) != CmpLT; - } - if (is_unsigned && dest_int_is_signed) { - op1_bits += 1; - } - } else if (op1_is_float) { - src_assert(op1_scalar_type->id == ZigTypeIdFloat, source_node); - dest_float_type = op1_scalar_type; - } else { - src_assert(op1_scalar_type->id == ZigTypeIdInt, source_node); - op1_bits = op1_scalar_type->data.integral.bit_count; - if (!op1_scalar_type->data.integral.is_signed && dest_int_is_signed) { - op1_bits += 1; - } - } - uint32_t op2_bits; - if (instr_is_comptime(op2) && result_type->id != ZigTypeIdVector) { - ZigValue *op2_val = ir_resolve_const(ira, op2, UndefOk); - if (op2_val == nullptr) - return ira->codegen->invalid_inst_gen; - if (op2_val->special == ConstValSpecialUndef) - return ir_const_undef(ira, scope, source_node, ira->codegen->builtin_types.entry_bool); - bool is_unsigned; - if (op2_is_float) { - BigInt bigint = {}; - float_init_bigint(&bigint, op2_val); - Cmp zcmp = float_cmp_zero(op2_val); - if (float_has_fraction(op2_val)) { - if (op_id == IrBinOpCmpEq || op_id == IrBinOpCmpNotEq) { - return ir_const_bool(ira, scope, source_node, op_id == IrBinOpCmpNotEq); - } - if (zcmp == CmpLT) { - bigint_decr(&bigint); - } else { - bigint_incr(&bigint); - } - } - op2_bits = bigint_bits_needed(&bigint); - is_unsigned = zcmp != CmpLT; - } else { - op2_bits = bigint_bits_needed(&op2_val->data.x_bigint); - is_unsigned = bigint_cmp_zero(&op2_val->data.x_bigint) != CmpLT; - } - if (is_unsigned && dest_int_is_signed) { - op2_bits += 1; - } - } else if (op2_is_float) { - src_assert(op2_scalar_type->id == ZigTypeIdFloat, source_node); - dest_float_type = op2_scalar_type; - } else { - src_assert(op2_scalar_type->id == ZigTypeIdInt, source_node); - op2_bits = op2_scalar_type->data.integral.bit_count; - if (!op2_scalar_type->data.integral.is_signed && dest_int_is_signed) { - op2_bits += 1; - } - } - ZigType *dest_scalar_type = (dest_float_type == nullptr) ? - get_int_type(ira->codegen, dest_int_is_signed, (op1_bits > op2_bits) ? op1_bits : op2_bits) : - dest_float_type; - ZigType *dest_type = (result_type->id == ZigTypeIdVector) ? - get_vector_type(ira->codegen, result_type->data.vector.len, dest_scalar_type) : dest_scalar_type; - - Stage1AirInst *casted_op1 = ir_implicit_cast(ira, op1, dest_type); - if (type_is_invalid(casted_op1->value->type)) - return ira->codegen->invalid_inst_gen; - Stage1AirInst *casted_op2 = ir_implicit_cast(ira, op2, dest_type); - if (type_is_invalid(casted_op2->value->type)) - return ira->codegen->invalid_inst_gen; - return ir_build_bin_op_gen(ira, scope, source_node, result_type, op_id, casted_op1, casted_op2, true); -} - -static bool type_is_self_comparable(ZigType *ty, bool is_equality_cmp) { - if (type_is_numeric(ty)) { - return true; - } - switch (ty->id) { - case ZigTypeIdInvalid: - zig_unreachable(); - - case ZigTypeIdComptimeFloat: - case ZigTypeIdComptimeInt: - case ZigTypeIdInt: - case ZigTypeIdFloat: - zig_unreachable(); // handled with the type_is_numeric check above - - case ZigTypeIdVector: - // Not every case is handled by the type_is_numeric check above, - // vectors of bool trigger this code path - case ZigTypeIdBool: - case ZigTypeIdMetaType: - case ZigTypeIdVoid: - case ZigTypeIdErrorSet: - case ZigTypeIdFn: - case ZigTypeIdOpaque: - case ZigTypeIdBoundFn: - case ZigTypeIdEnum: - case ZigTypeIdEnumLiteral: - case ZigTypeIdAnyFrame: - return is_equality_cmp; - - case ZigTypeIdPointer: - return is_equality_cmp || (ty->data.pointer.ptr_len == PtrLenC); - - case ZigTypeIdUnreachable: - case ZigTypeIdArray: - case ZigTypeIdStruct: - case ZigTypeIdUndefined: - case ZigTypeIdNull: - case ZigTypeIdErrorUnion: - case ZigTypeIdUnion: - case ZigTypeIdFnFrame: - return false; - - case ZigTypeIdOptional: - return is_equality_cmp && get_src_ptr_type(ty) != nullptr; - } - zig_unreachable(); -} - -static Stage1AirInst *ir_try_evaluate_cmp_optional_non_optional_const(IrAnalyze *ira, Scope *scope, AstNode *source_node, ZigType *child_type, - Stage1AirInst *optional, Stage1AirInst *non_optional, IrBinOp op_id) -{ - assert(optional->value->type->id == ZigTypeIdOptional); - assert(optional->value->type->data.maybe.child_type == non_optional->value->type); - assert(non_optional->value->type == child_type); - assert(op_id == IrBinOpCmpEq || op_id == IrBinOpCmpNotEq); - - if (instr_is_comptime(optional) && instr_is_comptime(non_optional)) { - ZigValue *optional_val = ir_resolve_const(ira, optional, UndefBad); - if (!optional_val) { - return ira->codegen->invalid_inst_gen; - } - - ZigValue *non_optional_val = ir_resolve_const(ira, non_optional, UndefBad); - if (!non_optional_val) { - return ira->codegen->invalid_inst_gen; - } - - if (!optional_value_is_null(optional_val)) { - Stage1AirInst *optional_unwrapped = ir_analyze_optional_value_payload_value(ira, scope, source_node, optional, false); - if (type_is_invalid(optional_unwrapped->value->type)) { - return ira->codegen->invalid_inst_gen; - } - - Stage1AirInst *ret = ir_try_evaluate_bin_op_cmp_const(ira, scope, source_node, optional_unwrapped, non_optional, child_type, op_id); - assert(ret != nullptr); - return ret; - } - return ir_const_bool(ira, scope, source_node, (op_id != IrBinOpCmpEq)); - } else { - return nullptr; - } -} - -static Stage1AirInst *ir_evaluate_cmp_optional_non_optional(IrAnalyze *ira, Scope *scope, AstNode *source_node, ZigType *child_type, - Stage1AirInst *optional, Stage1AirInst *non_optional, IrBinOp op_id) -{ - assert(optional->value->type->id == ZigTypeIdOptional); - assert(optional->value->type->data.maybe.child_type == non_optional->value->type); - assert(non_optional->value->type == child_type); - assert(op_id == IrBinOpCmpEq || op_id == IrBinOpCmpNotEq); - - ZigType *result_type = ira->codegen->builtin_types.entry_bool; - ir_append_basic_block_gen(&ira->new_irb, ira->new_irb.current_basic_block); - - Stage1AirBasicBlock *null_block = ir_create_basic_block_gen(ira, scope, "CmpOptionalNonOptionalOptionalNull"); - Stage1AirBasicBlock *non_null_block = ir_create_basic_block_gen(ira, scope, "CmpOptionalNonOptionalOptionalNotNull"); - Stage1AirBasicBlock *end_block = ir_create_basic_block_gen(ira, scope, "CmpOptionalNonOptionalEnd"); - - Stage1AirInst *is_non_null = ir_build_test_non_null_gen(ira, scope, source_node, optional); - ir_build_cond_br_gen(ira, scope, source_node, is_non_null, non_null_block, null_block); - - ir_set_cursor_at_end_and_append_block_gen(&ira->new_irb, non_null_block); - Stage1AirInst *optional_unwrapped = ir_analyze_optional_value_payload_value(ira, scope, source_node, optional, false); - if (type_is_invalid(optional_unwrapped->value->type)) { - return ira->codegen->invalid_inst_gen; - } - Stage1AirInst *non_null_cmp_result = ir_build_bin_op_gen(ira, scope, source_node, result_type, op_id, - optional_unwrapped, non_optional, false); // safety check unnecessary for comparison operators - ir_build_br_gen(ira, scope, source_node, end_block); - - - ir_set_cursor_at_end_and_append_block_gen(&ira->new_irb, null_block); - Stage1AirInst *null_result = ir_const_bool(ira, scope, source_node, (op_id != IrBinOpCmpEq)); - ir_build_br_gen(ira, scope, source_node, end_block); - - ir_set_cursor_at_end_gen(&ira->new_irb, end_block); - int incoming_count = 2; - Stage1AirBasicBlock **incoming_blocks = heap::c_allocator.allocate_nonzero(incoming_count); - incoming_blocks[0] = null_block; - incoming_blocks[1] = non_null_block; - Stage1AirInst **incoming_values = heap::c_allocator.allocate_nonzero(incoming_count); - incoming_values[0] = null_result; - incoming_values[1] = non_null_cmp_result; - - const bool merge_comptime = false; - return ir_build_phi_gen(ira, scope, source_node, merge_comptime, incoming_count, incoming_blocks, incoming_values, result_type); -} - -static Stage1AirInst *ir_analyze_cmp_optional_non_optional(IrAnalyze *ira, Scope *scope, AstNode *source_node, - Stage1AirInst *op1, Stage1AirInst *op2, Stage1AirInst *optional, IrBinOp op_id) -{ - assert(op_id == IrBinOpCmpEq || op_id == IrBinOpCmpNotEq); - assert(optional->value->type->id == ZigTypeIdOptional); - assert(get_src_ptr_type(optional->value->type) == nullptr); - - Stage1AirInst *non_optional; - if (op1 == optional) { - non_optional = op2; - } else if (op2 == optional) { - non_optional = op1; - } else { - zig_unreachable(); - } - - ZigType *child_type = optional->value->type->data.maybe.child_type; - bool child_type_matches = (child_type == non_optional->value->type); - if (!child_type_matches || !type_is_self_comparable(child_type, true)) { - ErrorMsg *msg = ir_add_error_node(ira, source_node, buf_sprintf("cannot compare types '%s' and '%s'", - buf_ptr(&op1->value->type->name), - buf_ptr(&op2->value->type->name))); - - if (!child_type_matches) { - if (non_optional->value->type->id == ZigTypeIdOptional) { - add_error_note(ira->codegen, msg, source_node, buf_sprintf( - "optional to optional comparison is only supported for optional pointer types")); - } else { - add_error_note(ira->codegen, msg, source_node, - buf_sprintf("optional child type '%s' must be the same as non-optional type '%s'", - buf_ptr(&child_type->name), - buf_ptr(&non_optional->value->type->name))); - } - } else { - add_error_note(ira->codegen, msg, source_node, - buf_sprintf("operator not supported for type '%s'", - buf_ptr(&child_type->name))); - } - return ira->codegen->invalid_inst_gen; - } - - if (child_type->id == ZigTypeIdVector) { - ir_add_error_node(ira, source_node, buf_sprintf("TODO add comparison of optional vector")); - return ira->codegen->invalid_inst_gen; - } - - if (Stage1AirInst *const_result = ir_try_evaluate_cmp_optional_non_optional_const(ira, scope, source_node, child_type, - optional, non_optional, op_id)) - { - return const_result; - } - - return ir_evaluate_cmp_optional_non_optional(ira, scope, source_node, child_type, optional, non_optional, op_id); -} - -static Stage1AirInst *ir_analyze_bin_op_cmp(IrAnalyze *ira, Stage1ZirInstBinOp *bin_op_instruction) { - Stage1AirInst *op1 = bin_op_instruction->op1->child; - if (type_is_invalid(op1->value->type)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *op2 = bin_op_instruction->op2->child; - if (type_is_invalid(op2->value->type)) - return ira->codegen->invalid_inst_gen; - - AstNode *source_node = bin_op_instruction->base.source_node; - - IrBinOp op_id = bin_op_instruction->op_id; - bool is_equality_cmp = (op_id == IrBinOpCmpEq || op_id == IrBinOpCmpNotEq); - if (is_equality_cmp && op1->value->type->id == ZigTypeIdNull && op2->value->type->id == ZigTypeIdNull) { - return ir_const_bool(ira, bin_op_instruction->base.scope, - bin_op_instruction->base.source_node, (op_id == IrBinOpCmpEq)); - } else if (is_equality_cmp && - ((op1->value->type->id == ZigTypeIdNull && op2->value->type->id == ZigTypeIdOptional) || - (op2->value->type->id == ZigTypeIdNull && op1->value->type->id == ZigTypeIdOptional))) - { - Stage1AirInst *maybe_op; - if (op1->value->type->id == ZigTypeIdNull) { - maybe_op = op2; - } else if (op2->value->type->id == ZigTypeIdNull) { - maybe_op = op1; - } else { - zig_unreachable(); - } - if (instr_is_comptime(maybe_op)) { - ZigValue *maybe_val = ir_resolve_const(ira, maybe_op, UndefBad); - if (!maybe_val) - return ira->codegen->invalid_inst_gen; - bool is_null = optional_value_is_null(maybe_val); - bool bool_result = (op_id == IrBinOpCmpEq) ? is_null : !is_null; - return ir_const_bool(ira, bin_op_instruction->base.scope, - bin_op_instruction->base.source_node, bool_result); - } - - Stage1AirInst *is_non_null = ir_build_test_non_null_gen(ira, bin_op_instruction->base.scope, - bin_op_instruction->base.source_node, maybe_op); - - if (op_id == IrBinOpCmpEq) { - return ir_build_bool_not_gen(ira, bin_op_instruction->base.scope, - bin_op_instruction->base.source_node, is_non_null); - } else { - return is_non_null; - } - } else if (is_equality_cmp && - ((op1->value->type->id == ZigTypeIdNull && op2->value->type->id == ZigTypeIdPointer && - op2->value->type->data.pointer.ptr_len == PtrLenC) || - (op2->value->type->id == ZigTypeIdNull && op1->value->type->id == ZigTypeIdPointer && - op1->value->type->data.pointer.ptr_len == PtrLenC))) - { - Stage1AirInst *c_ptr_op; - if (op1->value->type->id == ZigTypeIdNull) { - c_ptr_op = op2; - } else if (op2->value->type->id == ZigTypeIdNull) { - c_ptr_op = op1; - } else { - zig_unreachable(); - } - if (instr_is_comptime(c_ptr_op)) { - ZigValue *c_ptr_val = ir_resolve_const(ira, c_ptr_op, UndefOk); - if (!c_ptr_val) - return ira->codegen->invalid_inst_gen; - if (c_ptr_val->special == ConstValSpecialUndef) - return ir_const_undef(ira, bin_op_instruction->base.scope, bin_op_instruction->base.source_node, ira->codegen->builtin_types.entry_bool); - bool is_null = c_ptr_val->data.x_ptr.special == ConstPtrSpecialNull || - (c_ptr_val->data.x_ptr.special == ConstPtrSpecialHardCodedAddr && - c_ptr_val->data.x_ptr.data.hard_coded_addr.addr == 0); - bool bool_result = (op_id == IrBinOpCmpEq) ? is_null : !is_null; - return ir_const_bool(ira, bin_op_instruction->base.scope, bin_op_instruction->base.source_node, bool_result); - } - Stage1AirInst *is_non_null = ir_build_test_non_null_gen(ira, bin_op_instruction->base.scope, bin_op_instruction->base.source_node, c_ptr_op); - - if (op_id == IrBinOpCmpEq) { - return ir_build_bool_not_gen(ira, bin_op_instruction->base.scope, bin_op_instruction->base.source_node, is_non_null); - } else { - return is_non_null; - } - } else if (is_equality_cmp && - (op1->value->type->id == ZigTypeIdOptional && get_src_ptr_type(op1->value->type) == nullptr)) - { - return ir_analyze_cmp_optional_non_optional(ira, bin_op_instruction->base.scope, bin_op_instruction->base.source_node, op1, op2, op1, op_id); - } else if(is_equality_cmp && - (op2->value->type->id == ZigTypeIdOptional && get_src_ptr_type(op2->value->type) == nullptr)) - { - return ir_analyze_cmp_optional_non_optional(ira, bin_op_instruction->base.scope, bin_op_instruction->base.source_node, op1, op2, op2, op_id); - } else if (op1->value->type->id == ZigTypeIdNull || op2->value->type->id == ZigTypeIdNull) { - ZigType *non_null_type = (op1->value->type->id == ZigTypeIdNull) ? op2->value->type : op1->value->type; - ir_add_error_node(ira, source_node, buf_sprintf("comparison of '%s' with null", - buf_ptr(&non_null_type->name))); - return ira->codegen->invalid_inst_gen; - } else if (is_equality_cmp && ( - (op1->value->type->id == ZigTypeIdEnumLiteral && op2->value->type->id == ZigTypeIdUnion) || - (op2->value->type->id == ZigTypeIdEnumLiteral && op1->value->type->id == ZigTypeIdUnion))) - { - // Support equality comparison between a union's tag value and a enum literal - Stage1AirInst *union_val = op1->value->type->id == ZigTypeIdUnion ? op1 : op2; - Stage1AirInst *enum_val = op1->value->type->id == ZigTypeIdUnion ? op2 : op1; - - if (!is_tagged_union(union_val->value->type)) { - ErrorMsg *msg = ir_add_error_node(ira, source_node, - buf_sprintf("comparison of union and enum literal is only valid for tagged union types")); - add_error_note(ira->codegen, msg, union_val->value->type->data.unionation.decl_node, - buf_sprintf("type %s is not a tagged union", - buf_ptr(&union_val->value->type->name))); - return ira->codegen->invalid_inst_gen; - } - - ZigType *tag_type = union_val->value->type->data.unionation.tag_type; - assert(tag_type != nullptr); - - Stage1AirInst *casted_union = ir_implicit_cast(ira, union_val, tag_type); - if (type_is_invalid(casted_union->value->type)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *casted_val = ir_implicit_cast(ira, enum_val, tag_type); - if (type_is_invalid(casted_val->value->type)) - return ira->codegen->invalid_inst_gen; - - if (instr_is_comptime(casted_union)) { - ZigValue *const_union_val = ir_resolve_const(ira, casted_union, UndefBad); - if (!const_union_val) - return ira->codegen->invalid_inst_gen; - - ZigValue *const_enum_val = ir_resolve_const(ira, casted_val, UndefBad); - if (!const_enum_val) - return ira->codegen->invalid_inst_gen; - - Cmp cmp_result = bigint_cmp(&const_union_val->data.x_union.tag, &const_enum_val->data.x_enum_tag); - bool bool_result = (op_id == IrBinOpCmpEq) ? cmp_result == CmpEQ : cmp_result != CmpEQ; - - return ir_const_bool(ira, bin_op_instruction->base.scope, bin_op_instruction->base.source_node, bool_result); - } - - return ir_build_bin_op_gen(ira, bin_op_instruction->base.scope, bin_op_instruction->base.source_node, ira->codegen->builtin_types.entry_bool, - op_id, casted_union, casted_val, bin_op_instruction->safety_check_on); - } - - if (op1->value->type->id == ZigTypeIdErrorSet && op2->value->type->id == ZigTypeIdErrorSet) { - if (!is_equality_cmp) { - ir_add_error_node(ira, source_node, buf_sprintf("operator not allowed for errors")); - return ira->codegen->invalid_inst_gen; - } - ZigType *intersect_type = get_error_set_intersection(ira, op1->value->type, op2->value->type, source_node); - if (type_is_invalid(intersect_type)) { - return ira->codegen->invalid_inst_gen; - } - - if (!resolve_inferred_error_set(ira->codegen, intersect_type, source_node)) { - return ira->codegen->invalid_inst_gen; - } - - // exception if one of the operators has the type of the empty error set, we allow the comparison - // (and make it comptime known) - // this is a function which is evaluated at comptime and returns an inferred error set will have an empty - // error set. - if (op1->value->type->data.error_set.err_count == 0 || op2->value->type->data.error_set.err_count == 0) { - bool are_equal = false; - bool answer; - if (op_id == IrBinOpCmpEq) { - answer = are_equal; - } else if (op_id == IrBinOpCmpNotEq) { - answer = !are_equal; - } else { - zig_unreachable(); - } - return ir_const_bool(ira, bin_op_instruction->base.scope, bin_op_instruction->base.source_node, answer); - } - - if (!type_is_global_error_set(intersect_type)) { - if (intersect_type->data.error_set.err_count == 0) { - ir_add_error_node(ira, source_node, - buf_sprintf("error sets '%s' and '%s' have no common errors", - buf_ptr(&op1->value->type->name), buf_ptr(&op2->value->type->name))); - return ira->codegen->invalid_inst_gen; - } - if (op1->value->type->data.error_set.err_count == 1 && op2->value->type->data.error_set.err_count == 1) { - bool are_equal = true; - bool answer; - if (op_id == IrBinOpCmpEq) { - answer = are_equal; - } else if (op_id == IrBinOpCmpNotEq) { - answer = !are_equal; - } else { - zig_unreachable(); - } - return ir_const_bool(ira, bin_op_instruction->base.scope, bin_op_instruction->base.source_node, answer); - } - } - - if (instr_is_comptime(op1) && instr_is_comptime(op2)) { - ZigValue *op1_val = ir_resolve_const(ira, op1, UndefBad); - if (op1_val == nullptr) - return ira->codegen->invalid_inst_gen; - ZigValue *op2_val = ir_resolve_const(ira, op2, UndefBad); - if (op2_val == nullptr) - return ira->codegen->invalid_inst_gen; - - bool answer; - bool are_equal = op1_val->data.x_err_set->value == op2_val->data.x_err_set->value; - if (op_id == IrBinOpCmpEq) { - answer = are_equal; - } else if (op_id == IrBinOpCmpNotEq) { - answer = !are_equal; - } else { - zig_unreachable(); - } - - return ir_const_bool(ira, bin_op_instruction->base.scope, bin_op_instruction->base.source_node, answer); - } - - return ir_build_bin_op_gen(ira, bin_op_instruction->base.scope, bin_op_instruction->base.source_node, ira->codegen->builtin_types.entry_bool, - op_id, op1, op2, bin_op_instruction->safety_check_on); - } - - if (type_is_numeric(op1->value->type) && type_is_numeric(op2->value->type)) { - // This operation allows any combination of integer and float types, regardless of the - // signed-ness, comptime-ness, and bit-width. So peer type resolution is incorrect for - // numeric types. - return ir_analyze_bin_op_cmp_numeric(ira, bin_op_instruction->base.scope, bin_op_instruction->base.source_node, op1, op2, op_id); - } - - Stage1AirInst *instructions[] = {op1, op2}; - ZigType *resolved_type = ir_resolve_peer_types(ira, source_node, nullptr, instructions, 2); - if (type_is_invalid(resolved_type)) - return ira->codegen->invalid_inst_gen; - - bool operator_allowed = type_is_self_comparable(resolved_type, is_equality_cmp); - - if (!operator_allowed) { - ir_add_error_node(ira, source_node, - buf_sprintf("operator not allowed for type '%s'", buf_ptr(&resolved_type->name))); - return ira->codegen->invalid_inst_gen; - } - - Stage1AirInst *casted_op1 = ir_implicit_cast(ira, op1, resolved_type); - if (type_is_invalid(casted_op1->value->type)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *casted_op2 = ir_implicit_cast(ira, op2, resolved_type); - if (type_is_invalid(casted_op2->value->type)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *resolve_const_result = ir_try_evaluate_bin_op_cmp_const(ira, bin_op_instruction->base.scope, bin_op_instruction->base.source_node, casted_op1, - casted_op2, resolved_type, op_id); - if (resolve_const_result != nullptr) { - return resolve_const_result; - } - - ZigType *res_type = (resolved_type->id == ZigTypeIdVector) ? - get_vector_type(ira->codegen, resolved_type->data.vector.len, ira->codegen->builtin_types.entry_bool) : - ira->codegen->builtin_types.entry_bool; - return ir_build_bin_op_gen(ira, bin_op_instruction->base.scope, bin_op_instruction->base.source_node, res_type, - op_id, casted_op1, casted_op2, bin_op_instruction->safety_check_on); -} - -static ErrorMsg *ir_eval_math_op_scalar(IrAnalyze *ira, Scope *scope, AstNode *source_node, ZigType *type_entry, - ZigValue *op1_val, IrBinOp op_id, ZigValue *op2_val, ZigValue *out_val) -{ - bool is_int; - bool is_float; - Cmp op2_zcmp; - if (type_entry->id == ZigTypeIdInt || type_entry->id == ZigTypeIdComptimeInt) { - is_int = true; - is_float = false; - op2_zcmp = bigint_cmp_zero(&op2_val->data.x_bigint); - } else if (type_entry->id == ZigTypeIdFloat || - type_entry->id == ZigTypeIdComptimeFloat) - { - is_int = false; - is_float = true; - op2_zcmp = float_cmp_zero(op2_val); - } else { - zig_unreachable(); - } - - if ((op_id == IrBinOpDivUnspecified || op_id == IrBinOpRemRem || op_id == IrBinOpRemMod || - op_id == IrBinOpDivTrunc || op_id == IrBinOpDivFloor) && op2_zcmp == CmpEQ) - { - return ir_add_error_node(ira, source_node, buf_sprintf("division by zero")); - } - if ((op_id == IrBinOpRemRem || op_id == IrBinOpRemMod) && op2_zcmp == CmpLT) { - return ir_add_error_node(ira, source_node, buf_sprintf("negative denominator")); - } - - switch (op_id) { - case IrBinOpInvalid: - case IrBinOpBoolOr: - case IrBinOpBoolAnd: - case IrBinOpCmpEq: - case IrBinOpCmpNotEq: - case IrBinOpCmpLessThan: - case IrBinOpCmpGreaterThan: - case IrBinOpCmpLessOrEq: - case IrBinOpCmpGreaterOrEq: - case IrBinOpArrayCat: - case IrBinOpArrayMult: - case IrBinOpRemUnspecified: - zig_unreachable(); - case IrBinOpBinOr: - assert(is_int); - bigint_or(&out_val->data.x_bigint, &op1_val->data.x_bigint, &op2_val->data.x_bigint); - break; - case IrBinOpBinXor: - assert(is_int); - bigint_xor(&out_val->data.x_bigint, &op1_val->data.x_bigint, &op2_val->data.x_bigint); - break; - case IrBinOpBinAnd: - assert(is_int); - bigint_and(&out_val->data.x_bigint, &op1_val->data.x_bigint, &op2_val->data.x_bigint); - break; - case IrBinOpBitShiftLeftExact: - assert(is_int); - bigint_shl(&out_val->data.x_bigint, &op1_val->data.x_bigint, &op2_val->data.x_bigint); - break; - case IrBinOpBitShiftLeftLossy: - assert(type_entry->id == ZigTypeIdInt); - bigint_shl_trunc(&out_val->data.x_bigint, &op1_val->data.x_bigint, &op2_val->data.x_bigint, - type_entry->data.integral.bit_count, type_entry->data.integral.is_signed); - break; - case IrBinOpBitShiftRightExact: - { - assert(is_int); - bigint_shr(&out_val->data.x_bigint, &op1_val->data.x_bigint, &op2_val->data.x_bigint); - BigInt orig_bigint; - bigint_shl(&orig_bigint, &out_val->data.x_bigint, &op2_val->data.x_bigint); - if (bigint_cmp(&op1_val->data.x_bigint, &orig_bigint) != CmpEQ) { - return ir_add_error_node(ira, source_node, buf_sprintf("exact shift shifted out 1 bits")); - } - break; - } - case IrBinOpBitShiftRightLossy: - assert(is_int); - bigint_shr(&out_val->data.x_bigint, &op1_val->data.x_bigint, &op2_val->data.x_bigint); - break; - case IrBinOpAdd: - if (is_int) { - bigint_add(&out_val->data.x_bigint, &op1_val->data.x_bigint, &op2_val->data.x_bigint); - } else { - float_add(out_val, op1_val, op2_val); - } - break; - case IrBinOpAddWrap: - assert(type_entry->id == ZigTypeIdInt); - bigint_add_wrap(&out_val->data.x_bigint, &op1_val->data.x_bigint, &op2_val->data.x_bigint, - type_entry->data.integral.bit_count, type_entry->data.integral.is_signed); - break; - case IrBinOpSub: - if (is_int) { - bigint_sub(&out_val->data.x_bigint, &op1_val->data.x_bigint, &op2_val->data.x_bigint); - } else { - float_sub(out_val, op1_val, op2_val); - } - break; - case IrBinOpSubWrap: - assert(type_entry->id == ZigTypeIdInt); - bigint_sub_wrap(&out_val->data.x_bigint, &op1_val->data.x_bigint, &op2_val->data.x_bigint, - type_entry->data.integral.bit_count, type_entry->data.integral.is_signed); - break; - case IrBinOpMult: - if (is_int) { - bigint_mul(&out_val->data.x_bigint, &op1_val->data.x_bigint, &op2_val->data.x_bigint); - } else { - float_mul(out_val, op1_val, op2_val); - } - break; - case IrBinOpMultWrap: - assert(type_entry->id == ZigTypeIdInt); - bigint_mul_wrap(&out_val->data.x_bigint, &op1_val->data.x_bigint, &op2_val->data.x_bigint, - type_entry->data.integral.bit_count, type_entry->data.integral.is_signed); - break; - case IrBinOpDivUnspecified: - assert(is_float); - float_div(out_val, op1_val, op2_val); - break; - case IrBinOpDivTrunc: - if (is_int) { - bigint_div_trunc(&out_val->data.x_bigint, &op1_val->data.x_bigint, &op2_val->data.x_bigint); - } else { - float_div_trunc(out_val, op1_val, op2_val); - } - break; - case IrBinOpDivFloor: - if (is_int) { - bigint_div_floor(&out_val->data.x_bigint, &op1_val->data.x_bigint, &op2_val->data.x_bigint); - } else { - float_div_floor(out_val, op1_val, op2_val); - } - break; - case IrBinOpDivExact: - if (is_int) { - bigint_div_trunc(&out_val->data.x_bigint, &op1_val->data.x_bigint, &op2_val->data.x_bigint); - BigInt remainder; - bigint_rem(&remainder, &op1_val->data.x_bigint, &op2_val->data.x_bigint); - if (bigint_cmp_zero(&remainder) != CmpEQ) { - return ir_add_error_node(ira, source_node, buf_sprintf("exact division had a remainder")); - } - } else { - float_div_trunc(out_val, op1_val, op2_val); - ZigValue remainder = {}; - float_rem(&remainder, op1_val, op2_val); - if (float_cmp_zero(&remainder) != CmpEQ) { - return ir_add_error_node(ira, source_node, buf_sprintf("exact division had a remainder")); - } - } - break; - case IrBinOpRemRem: - if (is_int) { - bigint_rem(&out_val->data.x_bigint, &op1_val->data.x_bigint, &op2_val->data.x_bigint); - } else { - float_rem(out_val, op1_val, op2_val); - } - break; - case IrBinOpRemMod: - if (is_int) { - bigint_mod(&out_val->data.x_bigint, &op1_val->data.x_bigint, &op2_val->data.x_bigint); - } else { - float_mod(out_val, op1_val, op2_val); - } - break; - case IrBinOpMax: - if (is_int) { - bigint_max(&out_val->data.x_bigint, &op1_val->data.x_bigint, &op2_val->data.x_bigint); - } else { - float_max(out_val, op1_val, op2_val); - } - break; - case IrBinOpMin: - if (is_int) { - bigint_min(&out_val->data.x_bigint, &op1_val->data.x_bigint, &op2_val->data.x_bigint); - } else { - float_min(out_val, op1_val, op2_val); - } - break; - case IrBinOpAddSat: - if (is_int) { - bigint_add_sat(&out_val->data.x_bigint, &op1_val->data.x_bigint, &op2_val->data.x_bigint, type_entry->data.integral.bit_count, type_entry->data.integral.is_signed); - } else { - zig_unreachable(); - } - break; - case IrBinOpSubSat: - if (is_int) { - bigint_sub_sat(&out_val->data.x_bigint, &op1_val->data.x_bigint, &op2_val->data.x_bigint, type_entry->data.integral.bit_count, type_entry->data.integral.is_signed); - } else { - zig_unreachable(); - } - break; - case IrBinOpMultSat: - if (is_int) { - bigint_mul_sat(&out_val->data.x_bigint, &op1_val->data.x_bigint, &op2_val->data.x_bigint, type_entry->data.integral.bit_count, type_entry->data.integral.is_signed); - } else { - zig_unreachable(); - } - break; - case IrBinOpShlSat: - if (is_int) { - bigint_shl_sat(&out_val->data.x_bigint, &op1_val->data.x_bigint, &op2_val->data.x_bigint, type_entry->data.integral.bit_count, type_entry->data.integral.is_signed); - } else { - zig_unreachable(); - } - break; - } - - if (type_entry->id == ZigTypeIdInt) { - if (!bigint_fits_in_bits(&out_val->data.x_bigint, type_entry->data.integral.bit_count, - type_entry->data.integral.is_signed)) - { - return ir_add_error_node(ira, source_node, buf_sprintf("operation caused overflow")); - } - } - - out_val->type = type_entry; - out_val->special = ConstValSpecialStatic; - return nullptr; -} - -// This works on operands that have already been checked to be comptime known. -static Stage1AirInst *ir_analyze_math_op(IrAnalyze *ira, Scope *scope, AstNode *source_node, - ZigType *type_entry, ZigValue *op1_val, IrBinOp op_id, ZigValue *op2_val) -{ - Stage1AirInst *result_instruction = ir_const(ira, scope, source_node, type_entry); - ZigValue *out_val = result_instruction->value; - if (type_entry->id == ZigTypeIdVector) { - expand_undef_array(ira->codegen, op1_val); - expand_undef_array(ira->codegen, op2_val); - out_val->special = ConstValSpecialUndef; - expand_undef_array(ira->codegen, out_val); - size_t len = type_entry->data.vector.len; - ZigType *scalar_type = type_entry->data.vector.elem_type; - for (size_t i = 0; i < len; i += 1) { - ZigValue *scalar_op1_val = &op1_val->data.x_array.data.s_none.elements[i]; - ZigValue *scalar_op2_val = &op2_val->data.x_array.data.s_none.elements[i]; - ZigValue *scalar_out_val = &out_val->data.x_array.data.s_none.elements[i]; - assert(scalar_op1_val->type == scalar_type); - assert(scalar_out_val->type == scalar_type); - ErrorMsg *msg = ir_eval_math_op_scalar(ira, scope, source_node, scalar_type, - scalar_op1_val, op_id, scalar_op2_val, scalar_out_val); - if (msg != nullptr) { - add_error_note(ira->codegen, msg, source_node, - buf_sprintf("when computing vector element at index %" ZIG_PRI_usize, i)); - return ira->codegen->invalid_inst_gen; - } - } - out_val->type = type_entry; - out_val->special = ConstValSpecialStatic; - } else { - if (ir_eval_math_op_scalar(ira, scope, source_node, type_entry, op1_val, op_id, op2_val, out_val) != nullptr) { - return ira->codegen->invalid_inst_gen; - } - } - return ir_implicit_cast(ira, result_instruction, type_entry); -} - -static Stage1AirInst *ir_analyze_truncate(IrAnalyze *ira, Scope *scope, AstNode *source_node, - ZigType *dest_scalar_type, AstNode *dest_type_node, - Stage1AirInst *operand, AstNode *operand_node) -{ - if (dest_scalar_type->id != ZigTypeIdInt && - dest_scalar_type->id != ZigTypeIdComptimeInt) - { - ir_add_error_node(ira, dest_type_node, - buf_sprintf("expected integer type, found '%s'", buf_ptr(&dest_scalar_type->name))); - return ira->codegen->invalid_inst_gen; - } - - ZigType *src_type = operand->value->type; - bool is_vector = (src_type->id == ZigTypeIdVector); - ZigType *src_scalar_type = is_vector ? - src_type->data.vector.elem_type : src_type; - - ZigType *dest_type = is_vector ? - get_vector_type(ira->codegen, src_type->data.vector.len, dest_scalar_type) : - dest_scalar_type; - - if (src_scalar_type->id != ZigTypeIdInt && src_scalar_type->id != ZigTypeIdComptimeInt) { - ir_add_error_node(ira, operand_node, - buf_sprintf("expected integer type, found '%s'", buf_ptr(&src_scalar_type->name))); - return ira->codegen->invalid_inst_gen; - } - - if (dest_scalar_type->id == ZigTypeIdComptimeInt) { - return ir_implicit_cast2(ira, scope, operand_node, operand, dest_type); - } - - if (src_scalar_type->id != ZigTypeIdComptimeInt) { - if (src_scalar_type->data.integral.is_signed != dest_scalar_type->data.integral.is_signed) { - const char *sign_str = dest_scalar_type->data.integral.is_signed ? "signed" : "unsigned"; - ir_add_error_node(ira, operand_node, buf_sprintf("expected %s integer type, found '%s'", sign_str, buf_ptr(&src_scalar_type->name))); - return ira->codegen->invalid_inst_gen; - } else if (src_scalar_type->data.integral.bit_count > 0 && src_scalar_type->data.integral.bit_count < dest_scalar_type->data.integral.bit_count) { - ir_add_error_node(ira, operand_node, buf_sprintf("type '%s' has fewer bits than destination type '%s'", - buf_ptr(&src_scalar_type->name), buf_ptr(&dest_scalar_type->name))); - return ira->codegen->invalid_inst_gen; - } - } - - if (instr_is_comptime(operand)) { - ZigValue *val = ir_resolve_const(ira, operand, UndefBad); - if (val == nullptr) - return ira->codegen->invalid_inst_gen; - - if (!is_vector) { - Stage1AirInst *result = ir_const(ira, scope, source_node, dest_type); - bigint_truncate(&result->value->data.x_bigint, &val->data.x_bigint, - dest_scalar_type->data.integral.bit_count, - dest_scalar_type->data.integral.is_signed); - return result; - } - - Stage1AirInst *result_instruction = ir_const(ira, scope, source_node, dest_type); - ZigValue *out_val = result_instruction->value; - expand_undef_array(ira->codegen, operand->value); - out_val->special = ConstValSpecialUndef; - expand_undef_array(ira->codegen, out_val); - size_t len = dest_type->data.vector.len; - for (size_t i = 0; i < len; i += 1) { - ZigValue *scalar_operand_val = &operand->value->data.x_array.data.s_none.elements[i]; - ZigValue *scalar_out_val = &out_val->data.x_array.data.s_none.elements[i]; - assert(scalar_operand_val->type == dest_scalar_type); - assert(scalar_out_val->type == dest_scalar_type); - - bigint_truncate(&scalar_out_val->data.x_bigint, - &scalar_operand_val->data.x_bigint, - dest_scalar_type->data.integral.bit_count, - dest_scalar_type->data.integral.is_signed); - - scalar_out_val->type = dest_scalar_type; - scalar_out_val->special = ConstValSpecialStatic; - } - out_val->type = dest_type; - out_val->special = ConstValSpecialStatic; - return result_instruction; - } - - if (src_scalar_type->data.integral.bit_count == 0 || - dest_scalar_type->data.integral.bit_count == 0) - { - Stage1AirInst *result = ir_const(ira, scope, source_node, dest_type); - if (!is_vector) { - bigint_init_unsigned(&result->value->data.x_bigint, 0); - } - return result; - } - - return ir_build_truncate_gen(ira, scope, source_node, dest_type, operand); -} - -static Stage1AirInst *ir_analyze_bit_shift(IrAnalyze *ira, Stage1ZirInstBinOp *bin_op_instruction) { - Stage1AirInst *op1 = bin_op_instruction->op1->child; - if (type_is_invalid(op1->value->type)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *op2 = bin_op_instruction->op2->child; - if (type_is_invalid(op2->value->type)) - return ira->codegen->invalid_inst_gen; - - ZigType *op1_type = op1->value->type; - ZigType *op2_type = op2->value->type; - - if (op1_type->id == ZigTypeIdVector && op2_type->id != ZigTypeIdVector) { - ir_add_error_node(ira, bin_op_instruction->op1->source_node, - buf_sprintf("bit shifting operation expected vector type, found '%s'", - buf_ptr(&op2_type->name))); - return ira->codegen->invalid_inst_gen; - } - - if (op1_type->id != ZigTypeIdVector && op2_type->id == ZigTypeIdVector) { - ir_add_error_node(ira, bin_op_instruction->op1->source_node, - buf_sprintf("bit shifting operation expected vector type, found '%s'", - buf_ptr(&op1_type->name))); - return ira->codegen->invalid_inst_gen; - } - - ZigType *op1_scalar_type = (op1_type->id == ZigTypeIdVector) ? - op1_type->data.vector.elem_type : op1_type; - ZigType *op2_scalar_type = (op2_type->id == ZigTypeIdVector) ? - op2_type->data.vector.elem_type : op2_type; - - if (op1_scalar_type->id != ZigTypeIdInt && op1_scalar_type->id != ZigTypeIdComptimeInt) { - ir_add_error_node(ira, bin_op_instruction->op1->source_node, - buf_sprintf("bit shifting operation expected integer type, found '%s'", - buf_ptr(&op1_scalar_type->name))); - return ira->codegen->invalid_inst_gen; - } - - if (op2_scalar_type->id != ZigTypeIdInt && op2_scalar_type->id != ZigTypeIdComptimeInt) { - ir_add_error_node(ira, bin_op_instruction->op2->source_node, - buf_sprintf("shift amount has to be an integer type, but found '%s'", - buf_ptr(&op2_scalar_type->name))); - return ira->codegen->invalid_inst_gen; - } - - Stage1AirInst *casted_op2; - IrBinOp op_id = bin_op_instruction->op_id; - if (op1_scalar_type->id == ZigTypeIdComptimeInt) { - // comptime_int has no finite bit width - casted_op2 = op2; - - if (op_id == IrBinOpBitShiftLeftLossy || op_id == IrBinOpShlSat) { - op_id = IrBinOpBitShiftLeftExact; - } - - if (!instr_is_comptime(op2)) { - ir_add_error_node(ira, bin_op_instruction->base.source_node, - buf_sprintf("LHS of shift must be a fixed-width integer type, or RHS must be compile-time known")); - return ira->codegen->invalid_inst_gen; - } - - ZigValue *op2_val = ir_resolve_const(ira, casted_op2, UndefBad); - if (op2_val == nullptr) - return ira->codegen->invalid_inst_gen; - - if (op2_val->data.x_bigint.is_negative) { - Buf *val_buf = buf_alloc(); - bigint_append_buf(val_buf, &op2_val->data.x_bigint, 10); - ir_add_error(ira, casted_op2, - buf_sprintf("shift by negative value %s", buf_ptr(val_buf))); - return ira->codegen->invalid_inst_gen; - } - } else if (op_id == IrBinOpShlSat) { - casted_op2 = ir_analyze_truncate(ira, - bin_op_instruction->base.scope, bin_op_instruction->base.source_node, - op1_scalar_type, bin_op_instruction->op1->source_node, - op2, bin_op_instruction->op2->source_node); - if (type_is_invalid(casted_op2->value->type)) - return ira->codegen->invalid_inst_gen; - } else { - const unsigned bit_count = op1_scalar_type->data.integral.bit_count; - ZigType *shift_amt_type = get_smallest_unsigned_int_type(ira->codegen, - bit_count > 0 ? bit_count - 1 : 0); - - if (op1_type->id == ZigTypeIdVector) { - shift_amt_type = get_vector_type(ira->codegen, op1_type->data.vector.len, - shift_amt_type); - } - - casted_op2 = ir_implicit_cast(ira, op2, shift_amt_type); - if (type_is_invalid(casted_op2->value->type)) - return ira->codegen->invalid_inst_gen; - - // This check is only valid iff op1 has at least one bit - if (bit_count > 0 && instr_is_comptime(casted_op2)) { - ZigValue *op2_val = ir_resolve_const(ira, casted_op2, UndefBad); - if (op2_val == nullptr) - return ira->codegen->invalid_inst_gen; - - ZigValue bit_count_value = {}; - init_const_usize(ira->codegen, &bit_count_value, bit_count); - - if (!value_cmp_numeric_val_all(op2_val, CmpLT, &bit_count_value)) { - ErrorMsg* msg = ir_add_error_node(ira, - bin_op_instruction->base.source_node, - buf_sprintf("RHS of shift is too large for LHS type")); - add_error_note(ira->codegen, msg, op1->source_node, - buf_sprintf("type %s has only %u bits", - buf_ptr(&op1->value->type->name), bit_count)); - - return ira->codegen->invalid_inst_gen; - } - } - } - - // Fast path for zero RHS - if (instr_is_comptime(casted_op2)) { - ZigValue *op2_val = ir_resolve_const(ira, casted_op2, UndefBad); - if (op2_val == nullptr) - return ira->codegen->invalid_inst_gen; - - if (op2_val->type->id == ZigTypeIdVector) { - expand_undef_array(ira->codegen, op2_val); - size_t len = op2_val->type->data.vector.len; - for (size_t i = 0; i < len; i += 1) { - ZigValue *scalar_val = &op2_val->data.x_array.data.s_none.elements[i]; - if (scalar_val->data.x_bigint.is_negative) { - Buf *val_buf = buf_alloc(); - bigint_append_buf(val_buf, &scalar_val->data.x_bigint, 10); - ir_add_error(ira, casted_op2, - buf_sprintf("shift by negative value %s at vector index %zu", - buf_ptr(val_buf), i)); - return ira->codegen->invalid_inst_gen; - } - } - } else { - if (op2_val->data.x_bigint.is_negative) { - Buf *val_buf = buf_alloc(); - bigint_append_buf(val_buf, &op2_val->data.x_bigint, 10); - ir_add_error(ira, casted_op2, - buf_sprintf("shift by negative value %s", buf_ptr(val_buf))); - return ira->codegen->invalid_inst_gen; - } - } - - if (value_cmp_numeric_val_all(op2_val, CmpEQ, nullptr)) - return ir_analyze_cast(ira, bin_op_instruction->base.scope, bin_op_instruction->base.source_node, op1->value->type, op1); - } - - if (instr_is_comptime(op1) && instr_is_comptime(casted_op2)) { - ZigValue *op1_val = ir_resolve_const(ira, op1, UndefBad); - if (op1_val == nullptr) - return ira->codegen->invalid_inst_gen; - - ZigValue *op2_val = ir_resolve_const(ira, casted_op2, UndefBad); - if (op2_val == nullptr) - return ira->codegen->invalid_inst_gen; - - return ir_analyze_math_op(ira, bin_op_instruction->base.scope, bin_op_instruction->base.source_node, op1_type, op1_val, op_id, op2_val); - } - - return ir_build_bin_op_gen(ira, - bin_op_instruction->base.scope, bin_op_instruction->base.source_node, - op1->value->type, op_id, op1, casted_op2, bin_op_instruction->safety_check_on); -} - -static bool ok_float_op(IrBinOp op) { - switch (op) { - case IrBinOpInvalid: - zig_unreachable(); - case IrBinOpAdd: - case IrBinOpSub: - case IrBinOpMult: - case IrBinOpDivUnspecified: - case IrBinOpDivTrunc: - case IrBinOpDivFloor: - case IrBinOpDivExact: - case IrBinOpRemRem: - case IrBinOpRemMod: - case IrBinOpRemUnspecified: - case IrBinOpMax: - case IrBinOpMin: - return true; - - case IrBinOpBoolOr: - case IrBinOpBoolAnd: - case IrBinOpCmpEq: - case IrBinOpCmpNotEq: - case IrBinOpCmpLessThan: - case IrBinOpCmpGreaterThan: - case IrBinOpCmpLessOrEq: - case IrBinOpCmpGreaterOrEq: - case IrBinOpBinOr: - case IrBinOpBinXor: - case IrBinOpBinAnd: - case IrBinOpBitShiftLeftLossy: - case IrBinOpBitShiftLeftExact: - case IrBinOpBitShiftRightLossy: - case IrBinOpBitShiftRightExact: - case IrBinOpAddWrap: - case IrBinOpSubWrap: - case IrBinOpAddSat: - case IrBinOpSubSat: - case IrBinOpMultSat: - case IrBinOpShlSat: - case IrBinOpMultWrap: - case IrBinOpArrayCat: - case IrBinOpArrayMult: - return false; - } - zig_unreachable(); -} - -static IrBinOp map_comptime_arithmetic_op(IrBinOp op) { - switch (op) { - case IrBinOpAddWrap: - case IrBinOpAddSat: - return IrBinOpAdd; - - case IrBinOpSubWrap: - case IrBinOpSubSat: - return IrBinOpSub; - - case IrBinOpMultWrap: - case IrBinOpMultSat: - return IrBinOpMult; - - default: - return op; - } -} - -static bool is_pointer_arithmetic_allowed(ZigType *lhs_type, IrBinOp op) { - switch (op) { - case IrBinOpAdd: - case IrBinOpSub: - break; - default: - return false; - } - if (lhs_type->id != ZigTypeIdPointer) - return false; - switch (lhs_type->data.pointer.ptr_len) { - case PtrLenSingle: - return false; - case PtrLenUnknown: - case PtrLenC: - return true; - } - zig_unreachable(); -} - -// Returns true if integer `value` can be converted to `type_entry` without -// losing data. -// If `value` is a vector the function returns true if this is valid for every -// element. -static bool value_numeric_fits_in_type(ZigValue *value, ZigType *type_entry) { - assert(value->special == ConstValSpecialStatic); - assert(type_entry->id == ZigTypeIdInt); - - switch (value->type->id) { - case ZigTypeIdComptimeInt: - case ZigTypeIdInt: { - return bigint_fits_in_bits(&value->data.x_bigint, type_entry->data.integral.bit_count, - type_entry->data.integral.is_signed); - } - case ZigTypeIdVector: { - for (size_t i = 0; i < value->type->data.vector.len; i++) { - ZigValue *scalar_value = &value->data.x_array.data.s_none.elements[i]; - const bool result = bigint_fits_in_bits(&scalar_value->data.x_bigint, - type_entry->data.integral.bit_count, type_entry->data.integral.is_signed); - if (!result) return false; - } - return true; - } - default: zig_unreachable(); - } -} - -static bool value_cmp_numeric_val(ZigValue *left, Cmp predicate, ZigValue *right, bool any) { - assert(left->special == ConstValSpecialStatic); - assert(right == nullptr || right->special == ConstValSpecialStatic); - - switch (left->type->id) { - case ZigTypeIdComptimeInt: - case ZigTypeIdInt: { - const Cmp result = right ? - bigint_cmp(&left->data.x_bigint, &right->data.x_bigint) : - bigint_cmp_zero(&left->data.x_bigint); - return result == predicate; - } - case ZigTypeIdComptimeFloat: - case ZigTypeIdFloat: { - if (float_is_nan(left)) - return false; - if (right != nullptr && float_is_nan(right)) - return false; - - const Cmp result = right ? float_cmp(left, right) : float_cmp_zero(left); - return result == predicate; - } - case ZigTypeIdVector: { - for (size_t i = 0; i < left->type->data.vector.len; i++) { - ZigValue *scalar_val = &left->data.x_array.data.s_none.elements[i]; - const bool result = value_cmp_numeric_val(scalar_val, predicate, right, any); - - if (any && result) - return true; // This element satisfies the predicate - else if (!any && !result) - return false; // This element doesn't satisfy the predicate - } - return any ? false : true; - } - default: - zig_unreachable(); - } -} - -static bool value_cmp_numeric_val_any(ZigValue *left, Cmp predicate, ZigValue *right) { - return value_cmp_numeric_val(left, predicate, right, true); -} - -static bool value_cmp_numeric_val_all(ZigValue *left, Cmp predicate, ZigValue *right) { - return value_cmp_numeric_val(left, predicate, right, false); -} - -static Stage1AirInst *ir_analyze_bin_op_math(IrAnalyze *ira, Stage1ZirInstBinOp *instruction) { - Error err; - - Stage1AirInst *op1 = instruction->op1->child; - if (type_is_invalid(op1->value->type)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *op2 = instruction->op2->child; - if (type_is_invalid(op2->value->type)) - return ira->codegen->invalid_inst_gen; - - IrBinOp op_id = instruction->op_id; - - // look for pointer math - if (is_pointer_arithmetic_allowed(op1->value->type, op_id)) { - Stage1AirInst *casted_op2 = ir_implicit_cast(ira, op2, ira->codegen->builtin_types.entry_usize); - if (type_is_invalid(casted_op2->value->type)) - return ira->codegen->invalid_inst_gen; - - // If either operand is undef, result is undef. - ZigValue *op1_val = nullptr; - ZigValue *op2_val = nullptr; - if (instr_is_comptime(op1)) { - op1_val = ir_resolve_const(ira, op1, UndefOk); - if (op1_val == nullptr) - return ira->codegen->invalid_inst_gen; - if (op1_val->special == ConstValSpecialUndef) - return ir_const_undef(ira, instruction->base.scope, instruction->base.source_node, op1->value->type); - } - if (instr_is_comptime(casted_op2)) { - op2_val = ir_resolve_const(ira, casted_op2, UndefOk); - if (op2_val == nullptr) - return ira->codegen->invalid_inst_gen; - if (op2_val->special == ConstValSpecialUndef) - return ir_const_undef(ira, instruction->base.scope, instruction->base.source_node, op1->value->type); - } - - ZigType *elem_type = op1->value->type->data.pointer.child_type; - if ((err = type_resolve(ira->codegen, elem_type, ResolveStatusSizeKnown))) - return ira->codegen->invalid_inst_gen; - - // NOTE: this variable is meaningful iff op2_val is not null! - uint64_t byte_offset; - if (op2_val != nullptr) { - uint64_t elem_offset; - if (!ir_resolve_usize(ira, casted_op2, &elem_offset)) - return ira->codegen->invalid_inst_gen; - - byte_offset = type_size(ira->codegen, elem_type) * elem_offset; - } - - // Fast path for cases where the RHS is zero - if (op2_val != nullptr && byte_offset == 0) { - return op1; - } - - ZigType *result_type = op1->value->type; - // Calculate the new alignment of the pointer - { - uint32_t align_bytes; - if ((err = resolve_ptr_align(ira, op1->value->type, &align_bytes))) - return ira->codegen->invalid_inst_gen; - - // If the addend is not a comptime-known value we can still count on - // it being a multiple of the type size - uint32_t addend = op2_val ? byte_offset : type_size(ira->codegen, elem_type); - - // The resulting pointer is aligned to the lcd between the - // offset (an arbitrary number) and the alignment factor (always - // a power of two, non zero) - uint32_t new_align = 1 << ctzll(addend | align_bytes); - // Rough guard to prevent overflows - assert(new_align); - result_type = adjust_ptr_align(ira->codegen, result_type, new_align); - } - - if (op2_val != nullptr && op1_val != nullptr && - (op1->value->data.x_ptr.special == ConstPtrSpecialHardCodedAddr || - op1->value->data.x_ptr.special == ConstPtrSpecialNull)) - { - uint64_t start_addr = (op1_val->data.x_ptr.special == ConstPtrSpecialNull) ? - 0 : op1_val->data.x_ptr.data.hard_coded_addr.addr; - uint64_t new_addr; - if (op_id == IrBinOpAdd) { - new_addr = start_addr + byte_offset; - } else if (op_id == IrBinOpSub) { - new_addr = start_addr - byte_offset; - } else { - zig_unreachable(); - } - Stage1AirInst *result = ir_const(ira, instruction->base.scope, instruction->base.source_node, result_type); - result->value->data.x_ptr.special = ConstPtrSpecialHardCodedAddr; - result->value->data.x_ptr.mut = ConstPtrMutRuntimeVar; - result->value->data.x_ptr.data.hard_coded_addr.addr = new_addr; - return result; - } - - return ir_build_bin_op_gen(ira, instruction->base.scope, instruction->base.source_node, result_type, op_id, op1, casted_op2, true); - } - - Stage1AirInst *instructions[] = {op1, op2}; - ZigType *resolved_type = ir_resolve_peer_types(ira, instruction->base.source_node, nullptr, instructions, 2); - if (type_is_invalid(resolved_type)) - return ira->codegen->invalid_inst_gen; - - ZigType *scalar_type = (resolved_type->id == ZigTypeIdVector) ? - resolved_type->data.vector.elem_type : resolved_type; - - bool is_int = scalar_type->id == ZigTypeIdInt || scalar_type->id == ZigTypeIdComptimeInt; - bool is_float = scalar_type->id == ZigTypeIdFloat || scalar_type->id == ZigTypeIdComptimeFloat; - - if (!is_int && !(is_float && ok_float_op(op_id))) { - AstNode *source_node = instruction->base.source_node; - ir_add_error_node(ira, source_node, - buf_sprintf("invalid operands to binary expression: '%s' and '%s'", - buf_ptr(&op1->value->type->name), - buf_ptr(&op2->value->type->name))); - return ira->codegen->invalid_inst_gen; - } - - Stage1AirInst *casted_op1 = ir_implicit_cast(ira, op1, resolved_type); - if (type_is_invalid(casted_op1->value->type)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *casted_op2 = ir_implicit_cast(ira, op2, resolved_type); - if (type_is_invalid(casted_op2->value->type)) - return ira->codegen->invalid_inst_gen; - - // Comptime integers have no fixed size, so wrapping or saturating operations should be mapped - // to their non wrapping or saturating equivalents - if (scalar_type->id == ZigTypeIdComptimeInt) { - op_id = map_comptime_arithmetic_op(op_id); - } - - if (instr_is_comptime(casted_op1) && instr_is_comptime(casted_op2)) { - ZigValue *op1_val = ir_resolve_const(ira, casted_op1, UndefBad); - if (op1_val == nullptr) - return ira->codegen->invalid_inst_gen; - - ZigValue *op2_val = ir_resolve_const(ira, casted_op2, UndefBad); - if (op2_val == nullptr) - return ira->codegen->invalid_inst_gen; - - // Promote division with negative numbers to signed - bool is_signed_div = value_cmp_numeric_val_any(op1_val, CmpLT, nullptr) || - value_cmp_numeric_val_any(op2_val, CmpLT, nullptr); - - if (op_id == IrBinOpDivUnspecified && is_int) { - // Default to truncating division and check if it's valid for the - // given operands if signed - op_id = IrBinOpDivTrunc; - - if (is_signed_div) { - bool ok = false; - - if (value_cmp_numeric_val_any(op2_val, CmpEQ, nullptr)) { - // the division by zero error will be caught later, but we don't have a - // division function ambiguity problem. - ok = true; - } else { - Stage1AirInst *trunc_val = ir_analyze_math_op(ira, instruction->base.scope, instruction->base.source_node, resolved_type, - op1_val, IrBinOpDivTrunc, op2_val); - if (type_is_invalid(trunc_val->value->type)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *floor_val = ir_analyze_math_op(ira, instruction->base.scope, instruction->base.source_node, resolved_type, - op1_val, IrBinOpDivFloor, op2_val); - if (type_is_invalid(floor_val->value->type)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *cmp_val = ir_analyze_bin_op_cmp_numeric(ira, instruction->base.scope, instruction->base.source_node, - trunc_val, floor_val, IrBinOpCmpEq); - if (type_is_invalid(cmp_val->value->type)) - return ira->codegen->invalid_inst_gen; - - // We can "upgrade" the operator only if trunc(a/b) == floor(a/b) - if (!ir_resolve_bool(ira, cmp_val, &ok)) - return ira->codegen->invalid_inst_gen; - } - - if (!ok) { - ir_add_error_node(ira, instruction->base.source_node, - buf_sprintf("division with '%s' and '%s': signed integers must use @divTrunc, @divFloor, or @divExact", - buf_ptr(&op1->value->type->name), - buf_ptr(&op2->value->type->name))); - return ira->codegen->invalid_inst_gen; - } - } - } else if (op_id == IrBinOpRemUnspecified) { - op_id = IrBinOpRemRem; - - if (is_signed_div) { - bool ok = false; - - if (value_cmp_numeric_val_any(op2_val, CmpEQ, nullptr)) { - // the division by zero error will be caught later, but we don't have a - // division function ambiguity problem. - ok = true; - } else { - Stage1AirInst *rem_val = ir_analyze_math_op(ira, instruction->base.scope, instruction->base.source_node, resolved_type, - op1_val, IrBinOpRemRem, op2_val); - if (type_is_invalid(rem_val->value->type)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *mod_val = ir_analyze_math_op(ira, instruction->base.scope, instruction->base.source_node, resolved_type, - op1_val, IrBinOpRemMod, op2_val); - if (type_is_invalid(mod_val->value->type)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *cmp_val = ir_analyze_bin_op_cmp_numeric(ira, instruction->base.scope, instruction->base.source_node, - rem_val, mod_val, IrBinOpCmpEq); - if (type_is_invalid(cmp_val->value->type)) - return ira->codegen->invalid_inst_gen; - - // We can "upgrade" the operator only if mod(a,b) == rem(a,b) - if (!ir_resolve_bool(ira, cmp_val, &ok)) - return ira->codegen->invalid_inst_gen; - } - - if (!ok) { - ir_add_error_node(ira, instruction->base.source_node, - buf_sprintf("remainder division with '%s' and '%s': signed integers and floats must use @rem or @mod", - buf_ptr(&op1->value->type->name), - buf_ptr(&op2->value->type->name))); - return ira->codegen->invalid_inst_gen; - } - } - } - - return ir_analyze_math_op(ira, instruction->base.scope, instruction->base.source_node, resolved_type, op1_val, op_id, op2_val); - } - - const bool is_signed_div = - (scalar_type->id == ZigTypeIdInt && scalar_type->data.integral.is_signed) || - scalar_type->id == ZigTypeIdFloat; - - // Warn the user to use the proper operators here - if (op_id == IrBinOpDivUnspecified && is_int) { - op_id = IrBinOpDivTrunc; - - if (is_signed_div) { - ir_add_error_node(ira, instruction->base.source_node, - buf_sprintf("division with '%s' and '%s': signed integers must use @divTrunc, @divFloor, or @divExact", - buf_ptr(&op1->value->type->name), - buf_ptr(&op2->value->type->name))); - return ira->codegen->invalid_inst_gen; - } - } else if (op_id == IrBinOpRemUnspecified) { - op_id = IrBinOpRemRem; - - if (is_signed_div) { - ir_add_error_node(ira, instruction->base.source_node, - buf_sprintf("remainder division with '%s' and '%s': signed integers and floats must use @rem or @mod", - buf_ptr(&op1->value->type->name), - buf_ptr(&op2->value->type->name))); - return ira->codegen->invalid_inst_gen; - } - } - - return ir_build_bin_op_gen(ira, instruction->base.scope, instruction->base.source_node, resolved_type, - op_id, casted_op1, casted_op2, instruction->safety_check_on); -} - -static Stage1AirInst *ir_analyze_tuple_cat(IrAnalyze *ira, Scope *scope, AstNode *source_node, - Stage1AirInst *op1, Stage1AirInst *op2) -{ - Error err; - ZigType *op1_type = op1->value->type; - ZigType *op2_type = op2->value->type; - - uint32_t op1_field_count = op1_type->data.structure.src_field_count; - uint32_t op2_field_count = op2_type->data.structure.src_field_count; - - Buf *bare_name = buf_alloc(); - Buf *name = get_anon_type_name(ira->codegen, nullptr, container_string(ContainerKindStruct), - scope, source_node, bare_name, nullptr); - ZigType *new_type = get_partial_container_type(ira->codegen, scope, - ContainerKindStruct, source_node, buf_ptr(name), bare_name, ContainerLayoutAuto); - new_type->data.structure.special = StructSpecialInferredTuple; - new_type->data.structure.resolve_status = ResolveStatusBeingInferred; - uint32_t new_field_count = op1_field_count + op2_field_count; - - new_type->data.structure.src_field_count = new_field_count; - new_type->data.structure.fields = realloc_type_struct_fields(new_type->data.structure.fields, - 0, new_field_count); - - Stage1AirInst *new_struct_ptr = ir_resolve_result(ira, ira->suspend_source_instr, no_result_loc(), - new_type, nullptr, false, true); - - for (uint32_t i = 0; i < new_field_count; i += 1) { - TypeStructField *src_field; - if (i < op1_field_count) { - src_field = op1_type->data.structure.fields[i]; - } else { - src_field = op2_type->data.structure.fields[i - op1_field_count]; - } - TypeStructField *new_field = new_type->data.structure.fields[i]; - new_field->name = buf_sprintf("%" PRIu32, i); - new_field->type_entry = src_field->type_entry; - new_field->type_val = src_field->type_val; - new_field->src_index = i; - new_field->decl_node = src_field->decl_node; - new_field->init_val = src_field->init_val; - new_field->is_comptime = src_field->is_comptime; - } - if ((err = type_resolve(ira->codegen, new_type, ResolveStatusZeroBitsKnown))) - return ira->codegen->invalid_inst_gen; - - ZigList const_ptrs = {}; - for (uint32_t i = 0; i < new_field_count; i += 1) { - TypeStructField *dst_field = new_type->data.structure.fields[i]; - Stage1AirInst *src_struct_op; - TypeStructField *src_field; - if (i < op1_field_count) { - src_field = op1_type->data.structure.fields[i]; - src_struct_op = op1; - } else { - src_field = op2_type->data.structure.fields[i - op1_field_count]; - src_struct_op = op2; - } - Stage1AirInst *field_value = ir_analyze_struct_value_field_value(ira, scope, source_node, - src_struct_op, src_field); - if (type_is_invalid(field_value->value->type)) - return ira->codegen->invalid_inst_gen; - Stage1AirInst *dest_ptr = ir_analyze_struct_field_ptr(ira, scope, source_node, dst_field, - new_struct_ptr, new_type, true); - if (type_is_invalid(dest_ptr->value->type)) - return ira->codegen->invalid_inst_gen; - if (instr_is_comptime(field_value)) { - const_ptrs.append(dest_ptr); - } - Stage1AirInst *store_ptr_inst = ir_analyze_store_ptr(ira, scope, source_node, dest_ptr, field_value, - true); - if (type_is_invalid(store_ptr_inst->value->type)) - return ira->codegen->invalid_inst_gen; - } - if (const_ptrs.length != new_field_count) { - new_struct_ptr->value->special = ConstValSpecialRuntime; - for (size_t i = 0; i < const_ptrs.length; i += 1) { - Stage1AirInst *elem_result_loc = const_ptrs.at(i); - assert(elem_result_loc->value->special == ConstValSpecialStatic); - if (elem_result_loc->value->type->data.pointer.inferred_struct_field != nullptr) { - // This field will be generated comptime; no need to do this. - continue; - } - Stage1AirInst *deref = ir_get_deref(ira, elem_result_loc->scope, - elem_result_loc->source_node, elem_result_loc, nullptr); - if (!type_requires_comptime(ira->codegen, elem_result_loc->value->type->data.pointer.child_type)) { - elem_result_loc->value->special = ConstValSpecialRuntime; - } - ir_analyze_store_ptr(ira, elem_result_loc->scope, elem_result_loc->source_node, elem_result_loc, deref, true); - } - } - - const_ptrs.deinit(); - - return ir_get_deref(ira, scope, source_node, new_struct_ptr, nullptr); -} - -static Stage1AirInst *ir_analyze_array_cat(IrAnalyze *ira, Stage1ZirInstBinOp *instruction) { - Stage1AirInst *op1 = instruction->op1->child; - ZigType *op1_type = op1->value->type; - if (type_is_invalid(op1_type)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *op2 = instruction->op2->child; - ZigType *op2_type = op2->value->type; - if (type_is_invalid(op2_type)) - return ira->codegen->invalid_inst_gen; - - if (is_tuple(op1_type) && is_tuple(op2_type)) { - return ir_analyze_tuple_cat(ira, instruction->base.scope, instruction->base.source_node, op1, op2); - } - - ZigValue *op1_val = ir_resolve_const(ira, op1, UndefBad); - if (!op1_val) - return ira->codegen->invalid_inst_gen; - - ZigValue *op2_val = ir_resolve_const(ira, op2, UndefBad); - if (!op2_val) - return ira->codegen->invalid_inst_gen; - - ZigValue *sentinel1 = nullptr; - ZigValue *op1_array_val; - size_t op1_array_index; - size_t op1_array_end; - ZigType *child_type; - if (op1_type->id == ZigTypeIdArray) { - child_type = op1_type->data.array.child_type; - op1_array_val = op1_val; - op1_array_index = 0; - op1_array_end = op1_type->data.array.len; - sentinel1 = op1_type->data.array.sentinel; - } else if (op1_type->id == ZigTypeIdPointer && - op1_type->data.pointer.child_type == ira->codegen->builtin_types.entry_u8 && - op1_type->data.pointer.sentinel != nullptr && - op1_val->data.x_ptr.special == ConstPtrSpecialBaseArray) - { - child_type = op1_type->data.pointer.child_type; - op1_array_val = op1_val->data.x_ptr.data.base_array.array_val; - op1_array_index = op1_val->data.x_ptr.data.base_array.elem_index; - op1_array_end = op1_array_val->type->data.array.len; - sentinel1 = op1_type->data.pointer.sentinel; - } else if (is_slice(op1_type)) { - ZigType *ptr_type = op1_type->data.structure.fields[slice_ptr_index]->type_entry; - child_type = ptr_type->data.pointer.child_type; - ZigValue *ptr_val = op1_val->data.x_struct.fields[slice_ptr_index]; - assert(ptr_val->data.x_ptr.special == ConstPtrSpecialBaseArray); - op1_array_val = ptr_val->data.x_ptr.data.base_array.array_val; - op1_array_index = ptr_val->data.x_ptr.data.base_array.elem_index; - ZigValue *len_val = op1_val->data.x_struct.fields[slice_len_index]; - op1_array_end = op1_array_index + bigint_as_usize(&len_val->data.x_bigint); - sentinel1 = ptr_type->data.pointer.sentinel; - } else if (op1_type->id == ZigTypeIdPointer && - op1_type->data.pointer.ptr_len == PtrLenSingle && - op1_type->data.pointer.child_type->id == ZigTypeIdArray) - { - ZigType *array_type = op1_type->data.pointer.child_type; - child_type = array_type->data.array.child_type; - op1_array_val = const_ptr_pointee(ira, ira->codegen, op1_val, op1->source_node); - if (op1_array_val == nullptr) - return ira->codegen->invalid_inst_gen; - op1_array_index = 0; - op1_array_end = array_type->data.array.len; - sentinel1 = array_type->data.array.sentinel; - } else { - ir_add_error(ira, op1, buf_sprintf("expected array, found '%s'", buf_ptr(&op1->value->type->name))); - return ira->codegen->invalid_inst_gen; - } - - ZigValue *sentinel2 = nullptr; - ZigValue *op2_array_val; - size_t op2_array_index; - size_t op2_array_end; - bool op2_type_valid; - if (op2_type->id == ZigTypeIdArray) { - op2_type_valid = op2_type->data.array.child_type == child_type; - op2_array_val = op2_val; - op2_array_index = 0; - op2_array_end = op2_array_val->type->data.array.len; - sentinel2 = op2_type->data.array.sentinel; - } else if (op2_type->id == ZigTypeIdPointer && - op2_type->data.pointer.sentinel != nullptr && - op2_val->data.x_ptr.special == ConstPtrSpecialBaseArray) - { - op2_type_valid = op2_type->data.pointer.child_type == child_type; - op2_array_val = op2_val->data.x_ptr.data.base_array.array_val; - op2_array_index = op2_val->data.x_ptr.data.base_array.elem_index; - op2_array_end = op2_array_val->type->data.array.len; - - sentinel2 = op2_type->data.pointer.sentinel; - } else if (is_slice(op2_type)) { - ZigType *ptr_type = op2_type->data.structure.fields[slice_ptr_index]->type_entry; - op2_type_valid = ptr_type->data.pointer.child_type == child_type; - ZigValue *ptr_val = op2_val->data.x_struct.fields[slice_ptr_index]; - assert(ptr_val->data.x_ptr.special == ConstPtrSpecialBaseArray); - op2_array_val = ptr_val->data.x_ptr.data.base_array.array_val; - op2_array_index = ptr_val->data.x_ptr.data.base_array.elem_index; - ZigValue *len_val = op2_val->data.x_struct.fields[slice_len_index]; - op2_array_end = op2_array_index + bigint_as_usize(&len_val->data.x_bigint); - - sentinel2 = ptr_type->data.pointer.sentinel; - } else if (op2_type->id == ZigTypeIdPointer && op2_type->data.pointer.ptr_len == PtrLenSingle && - op2_type->data.pointer.child_type->id == ZigTypeIdArray) - { - ZigType *array_type = op2_type->data.pointer.child_type; - op2_type_valid = array_type->data.array.child_type == child_type; - op2_array_val = const_ptr_pointee(ira, ira->codegen, op2_val, op2->source_node); - if (op2_array_val == nullptr) - return ira->codegen->invalid_inst_gen; - op2_array_index = 0; - op2_array_end = array_type->data.array.len; - - sentinel2 = array_type->data.array.sentinel; - } else { - ir_add_error(ira, op2, - buf_sprintf("expected array or C string literal, found '%s'", buf_ptr(&op2->value->type->name))); - return ira->codegen->invalid_inst_gen; - } - if (!op2_type_valid) { - ir_add_error(ira, op2, buf_sprintf("expected array of type '%s', found '%s'", - buf_ptr(&child_type->name), - buf_ptr(&op2->value->type->name))); - return ira->codegen->invalid_inst_gen; - } - - ZigValue *sentinel; - if (sentinel1 != nullptr && sentinel2 != nullptr) { - // When there is a sentinel mismatch, no sentinel on the result. The type system - // will catch this if it is a problem. - sentinel = const_values_equal(ira->codegen, sentinel1, sentinel2) ? sentinel1 : nullptr; - } else if (sentinel1 != nullptr) { - sentinel = sentinel1; - } else if (sentinel2 != nullptr) { - sentinel = sentinel2; - } else { - sentinel = nullptr; - } - - // The type of result is populated in the following if blocks - Stage1AirInst *result = ir_const(ira, instruction->base.scope, instruction->base.source_node, nullptr); - ZigValue *out_val = result->value; - - ZigValue *out_array_val; - size_t new_len = (op1_array_end - op1_array_index) + (op2_array_end - op2_array_index); - if (op1_type->id == ZigTypeIdPointer || op2_type->id == ZigTypeIdPointer) { - out_array_val = ira->codegen->pass1_arena->create(); - out_array_val->special = ConstValSpecialStatic; - out_array_val->type = get_array_type(ira->codegen, child_type, new_len, sentinel); - - out_val->data.x_ptr.special = ConstPtrSpecialRef; - out_val->data.x_ptr.data.ref.pointee = out_array_val; - out_val->type = get_pointer_to_type(ira->codegen, out_array_val->type, true); - } else if (is_slice(op1_type) || is_slice(op2_type)) { - ZigType *ptr_type = get_pointer_to_type_extra2(ira->codegen, child_type, - true, false, PtrLenUnknown, 0, 0, 0, false, - VECTOR_INDEX_NONE, nullptr, sentinel); - result->value->type = get_slice_type(ira->codegen, ptr_type); - out_array_val = ira->codegen->pass1_arena->create(); - out_array_val->special = ConstValSpecialStatic; - out_array_val->type = get_array_type(ira->codegen, child_type, new_len, sentinel); - - out_val->data.x_struct.fields = alloc_const_vals_ptrs(ira->codegen, 2); - - out_val->data.x_struct.fields[slice_ptr_index]->type = ptr_type; - out_val->data.x_struct.fields[slice_ptr_index]->special = ConstValSpecialStatic; - out_val->data.x_struct.fields[slice_ptr_index]->data.x_ptr.special = ConstPtrSpecialBaseArray; - out_val->data.x_struct.fields[slice_ptr_index]->data.x_ptr.data.base_array.array_val = out_array_val; - out_val->data.x_struct.fields[slice_ptr_index]->data.x_ptr.data.base_array.elem_index = 0; - - out_val->data.x_struct.fields[slice_len_index]->type = ira->codegen->builtin_types.entry_usize; - out_val->data.x_struct.fields[slice_len_index]->special = ConstValSpecialStatic; - bigint_init_unsigned(&out_val->data.x_struct.fields[slice_len_index]->data.x_bigint, new_len); - } else if (op1_type->id == ZigTypeIdArray || op2_type->id == ZigTypeIdArray) { - result->value->type = get_array_type(ira->codegen, child_type, new_len, sentinel); - out_array_val = out_val; - } else { - result->value->type = get_pointer_to_type_extra2(ira->codegen, child_type, true, false, PtrLenUnknown, - 0, 0, 0, false, VECTOR_INDEX_NONE, nullptr, sentinel); - out_array_val = ira->codegen->pass1_arena->create(); - out_array_val->special = ConstValSpecialStatic; - out_array_val->type = get_array_type(ira->codegen, child_type, new_len, sentinel); - out_val->data.x_ptr.special = ConstPtrSpecialBaseArray; - out_val->data.x_ptr.data.base_array.array_val = out_array_val; - out_val->data.x_ptr.data.base_array.elem_index = 0; - } - - if (op1_array_val->data.x_array.special == ConstArraySpecialUndef && - op2_array_val->data.x_array.special == ConstArraySpecialUndef) - { - out_array_val->data.x_array.special = ConstArraySpecialUndef; - return result; - } - - uint64_t full_len = new_len + ((sentinel != nullptr) ? 1 : 0); - out_array_val->data.x_array.data.s_none.elements = ira->codegen->pass1_arena->allocate(full_len); - // TODO handle the buf case here for an optimization - expand_undef_array(ira->codegen, op1_array_val); - expand_undef_array(ira->codegen, op2_array_val); - - size_t next_index = 0; - for (size_t i = op1_array_index; i < op1_array_end; i += 1, next_index += 1) { - ZigValue *elem_dest_val = &out_array_val->data.x_array.data.s_none.elements[next_index]; - copy_const_val(ira->codegen, elem_dest_val, &op1_array_val->data.x_array.data.s_none.elements[i]); - elem_dest_val->parent.id = ConstParentIdArray; - elem_dest_val->parent.data.p_array.array_val = out_array_val; - elem_dest_val->parent.data.p_array.elem_index = next_index; - } - for (size_t i = op2_array_index; i < op2_array_end; i += 1, next_index += 1) { - ZigValue *elem_dest_val = &out_array_val->data.x_array.data.s_none.elements[next_index]; - copy_const_val(ira->codegen, elem_dest_val, &op2_array_val->data.x_array.data.s_none.elements[i]); - elem_dest_val->parent.id = ConstParentIdArray; - elem_dest_val->parent.data.p_array.array_val = out_array_val; - elem_dest_val->parent.data.p_array.elem_index = next_index; - } - if (next_index < full_len) { - ZigValue *elem_dest_val = &out_array_val->data.x_array.data.s_none.elements[next_index]; - copy_const_val(ira->codegen, elem_dest_val, sentinel); - elem_dest_val->parent.id = ConstParentIdArray; - elem_dest_val->parent.data.p_array.array_val = out_array_val; - elem_dest_val->parent.data.p_array.elem_index = next_index; - next_index += 1; - } - assert(next_index == full_len); - - return result; -} - -static Stage1AirInst *ir_analyze_tuple_mult(IrAnalyze *ira, Scope *scope, AstNode *source_node, - Stage1AirInst *op1, Stage1AirInst *op2) -{ - Error err; - ZigType *op1_type = op1->value->type; - uint64_t op1_field_count = op1_type->data.structure.src_field_count; - - uint64_t mult_amt; - if (!ir_resolve_usize(ira, op2, &mult_amt)) - return ira->codegen->invalid_inst_gen; - - uint64_t new_field_count; - if (mul_u64_overflow(op1_field_count, mult_amt, &new_field_count)) { - ir_add_error_node(ira, source_node, buf_sprintf("operation results in overflow")); - return ira->codegen->invalid_inst_gen; - } - - Buf *bare_name = buf_alloc(); - Buf *name = get_anon_type_name(ira->codegen, nullptr, container_string(ContainerKindStruct), - scope, source_node, bare_name, nullptr); - ZigType *new_type = get_partial_container_type(ira->codegen, scope, - ContainerKindStruct, source_node, buf_ptr(name), bare_name, ContainerLayoutAuto); - new_type->data.structure.special = StructSpecialInferredTuple; - new_type->data.structure.resolve_status = ResolveStatusBeingInferred; - new_type->data.structure.src_field_count = new_field_count; - new_type->data.structure.fields = realloc_type_struct_fields( - new_type->data.structure.fields, 0, new_field_count); - - Stage1AirInst *new_struct_ptr = ir_resolve_result(ira, ira->suspend_source_instr, no_result_loc(), - new_type, nullptr, false, true); - - for (uint64_t i = 0; i < new_field_count; i += 1) { - TypeStructField *src_field = op1_type->data.structure.fields[i % op1_field_count]; - TypeStructField *new_field = new_type->data.structure.fields[i]; - - new_field->name = buf_sprintf("%" ZIG_PRI_u64, i); - new_field->type_entry = src_field->type_entry; - new_field->type_val = src_field->type_val; - new_field->src_index = i; - new_field->decl_node = src_field->decl_node; - new_field->init_val = src_field->init_val; - new_field->is_comptime = src_field->is_comptime; - } - - if ((err = type_resolve(ira->codegen, new_type, ResolveStatusZeroBitsKnown))) - return ira->codegen->invalid_inst_gen; - - ZigList const_ptrs = {}; - for (uint64_t i = 0; i < new_field_count; i += 1) { - TypeStructField *src_field = op1_type->data.structure.fields[i % op1_field_count]; - TypeStructField *dst_field = new_type->data.structure.fields[i]; - - Stage1AirInst *field_value = ir_analyze_struct_value_field_value( - ira, scope, source_node, op1, src_field); - if (type_is_invalid(field_value->value->type)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *dest_ptr = ir_analyze_struct_field_ptr( - ira, scope, source_node, dst_field, new_struct_ptr, new_type, true); - if (type_is_invalid(dest_ptr->value->type)) - return ira->codegen->invalid_inst_gen; - - if (instr_is_comptime(field_value)) { - const_ptrs.append(dest_ptr); - } - - Stage1AirInst *store_ptr_inst = ir_analyze_store_ptr( - ira, scope, source_node, dest_ptr, field_value, true); - if (type_is_invalid(store_ptr_inst->value->type)) - return ira->codegen->invalid_inst_gen; - } - - if (const_ptrs.length != new_field_count) { - new_struct_ptr->value->special = ConstValSpecialRuntime; - for (size_t i = 0; i < const_ptrs.length; i += 1) { - Stage1AirInst *elem_result_loc = const_ptrs.at(i); - assert(elem_result_loc->value->special == ConstValSpecialStatic); - if (elem_result_loc->value->type->data.pointer.inferred_struct_field != nullptr) { - // This field will be generated comptime; no need to do this. - continue; - } - Stage1AirInst *deref = ir_get_deref(ira, elem_result_loc->scope, - elem_result_loc->source_node, elem_result_loc, nullptr); - if (!type_requires_comptime(ira->codegen, elem_result_loc->value->type->data.pointer.child_type)) { - elem_result_loc->value->special = ConstValSpecialRuntime; - } - Stage1AirInst *store_ptr_inst = ir_analyze_store_ptr(ira, elem_result_loc->scope, - elem_result_loc->source_node, elem_result_loc, deref, true); - if (type_is_invalid(store_ptr_inst->value->type)) - return ira->codegen->invalid_inst_gen; - } - } - - const_ptrs.deinit(); - - return ir_get_deref(ira, scope, source_node, new_struct_ptr, nullptr); -} - -static Stage1AirInst *ir_analyze_array_mult(IrAnalyze *ira, Stage1ZirInstBinOp *instruction) { - Stage1AirInst *op1 = instruction->op1->child; - if (type_is_invalid(op1->value->type)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *op2 = instruction->op2->child; - if (type_is_invalid(op2->value->type)) - return ira->codegen->invalid_inst_gen; - - bool want_ptr_to_array = false; - ZigType *array_type; - ZigValue *array_val; - if (op1->value->type->id == ZigTypeIdArray) { - array_type = op1->value->type; - array_val = ir_resolve_const(ira, op1, UndefOk); - if (array_val == nullptr) - return ira->codegen->invalid_inst_gen; - } else if (op1->value->type->id == ZigTypeIdPointer && - op1->value->type->data.pointer.ptr_len == PtrLenSingle && - op1->value->type->data.pointer.child_type->id == ZigTypeIdArray) - { - array_type = op1->value->type->data.pointer.child_type; - Stage1AirInst *array_inst = ir_get_deref(ira, op1->scope, op1->source_node, op1, nullptr); - if (type_is_invalid(array_inst->value->type)) - return ira->codegen->invalid_inst_gen; - array_val = ir_resolve_const(ira, array_inst, UndefOk); - if (array_val == nullptr) - return ira->codegen->invalid_inst_gen; - want_ptr_to_array = true; - } else if (is_tuple(op1->value->type)) { - return ir_analyze_tuple_mult(ira, instruction->base.scope, instruction->base.source_node, op1, op2); - } else { - ir_add_error(ira, op1, buf_sprintf("expected array type, found '%s'", buf_ptr(&op1->value->type->name))); - return ira->codegen->invalid_inst_gen; - } - - uint64_t mult_amt; - if (!ir_resolve_usize(ira, op2, &mult_amt)) - return ira->codegen->invalid_inst_gen; - - uint64_t old_array_len = array_type->data.array.len; - uint64_t new_array_len; - - if (mul_u64_overflow(old_array_len, mult_amt, &new_array_len)) { - ir_add_error_node(ira, instruction->base.source_node, buf_sprintf("operation results in overflow")); - return ira->codegen->invalid_inst_gen; - } - - ZigType *child_type = array_type->data.array.child_type; - ZigType *result_array_type = get_array_type(ira->codegen, child_type, new_array_len, - array_type->data.array.sentinel); - - Stage1AirInst *array_result; - if (array_val->special == ConstValSpecialUndef || array_val->data.x_array.special == ConstArraySpecialUndef) { - array_result = ir_const_undef(ira, instruction->base.scope, instruction->base.source_node, result_array_type); - } else { - array_result = ir_const(ira, instruction->base.scope, instruction->base.source_node, result_array_type); - ZigValue *out_val = array_result->value; - - switch (type_has_one_possible_value(ira->codegen, result_array_type)) { - case OnePossibleValueInvalid: - return ira->codegen->invalid_inst_gen; - case OnePossibleValueYes: - goto skip_computation; - case OnePossibleValueNo: - break; - } - - // TODO optimize the buf case - expand_undef_array(ira->codegen, array_val); - size_t extra_null_term = (array_type->data.array.sentinel != nullptr) ? 1 : 0; - out_val->data.x_array.data.s_none.elements = ira->codegen->pass1_arena->allocate(new_array_len + extra_null_term); - - uint64_t i = 0; - for (uint64_t x = 0; x < mult_amt; x += 1) { - for (uint64_t y = 0; y < old_array_len; y += 1) { - ZigValue *elem_dest_val = &out_val->data.x_array.data.s_none.elements[i]; - copy_const_val(ira->codegen, elem_dest_val, &array_val->data.x_array.data.s_none.elements[y]); - elem_dest_val->parent.id = ConstParentIdArray; - elem_dest_val->parent.data.p_array.array_val = out_val; - elem_dest_val->parent.data.p_array.elem_index = i; - i += 1; - } - } - assert(i == new_array_len); - - if (array_type->data.array.sentinel != nullptr) { - ZigValue *elem_dest_val = &out_val->data.x_array.data.s_none.elements[i]; - copy_const_val(ira->codegen, elem_dest_val, array_type->data.array.sentinel); - elem_dest_val->parent.id = ConstParentIdArray; - elem_dest_val->parent.data.p_array.array_val = out_val; - elem_dest_val->parent.data.p_array.elem_index = i; - i += 1; - } - } -skip_computation: - if (want_ptr_to_array) { - return ir_get_ref(ira, instruction->base.scope, instruction->base.source_node, array_result, true, false); - } else { - return array_result; - } -} - -static Stage1AirInst *ir_analyze_instruction_merge_err_sets(IrAnalyze *ira, - Stage1ZirInstMergeErrSets *instruction) -{ - ZigType *op1_type = ir_resolve_error_set_type(ira, instruction->base.source_node, instruction->op1->child); - if (type_is_invalid(op1_type)) - return ira->codegen->invalid_inst_gen; - - ZigType *op2_type = ir_resolve_error_set_type(ira, instruction->base.source_node, instruction->op2->child); - if (type_is_invalid(op2_type)) - return ira->codegen->invalid_inst_gen; - - if (!resolve_inferred_error_set(ira->codegen, op1_type, instruction->op1->child->source_node)) { - return ira->codegen->invalid_inst_gen; - } - - if (!resolve_inferred_error_set(ira->codegen, op2_type, instruction->op2->child->source_node)) { - return ira->codegen->invalid_inst_gen; - } - - if (type_is_global_error_set(op1_type) || - type_is_global_error_set(op2_type)) - { - return ir_const_type(ira, instruction->base.scope, instruction->base.source_node, ira->codegen->builtin_types.entry_global_error_set); - } - - size_t errors_count = ira->codegen->errors_by_index.length; - ErrorTableEntry **errors = heap::c_allocator.allocate(errors_count); - for (uint32_t i = 0, count = op1_type->data.error_set.err_count; i < count; i += 1) { - ErrorTableEntry *error_entry = op1_type->data.error_set.errors[i]; - assert(errors[error_entry->value] == nullptr); - errors[error_entry->value] = error_entry; - } - ZigType *result_type = get_error_set_union(ira->codegen, errors, op1_type, op2_type, instruction->type_name); - heap::c_allocator.deallocate(errors, errors_count); - - return ir_const_type(ira, instruction->base.scope, instruction->base.source_node, result_type); -} - - -static Stage1AirInst *ir_analyze_instruction_bin_op(IrAnalyze *ira, Stage1ZirInstBinOp *bin_op_instruction) { - IrBinOp op_id = bin_op_instruction->op_id; - switch (op_id) { - case IrBinOpInvalid: - zig_unreachable(); - case IrBinOpBoolOr: - case IrBinOpBoolAnd: - return ir_analyze_bin_op_bool(ira, bin_op_instruction); - case IrBinOpCmpEq: - case IrBinOpCmpNotEq: - case IrBinOpCmpLessThan: - case IrBinOpCmpGreaterThan: - case IrBinOpCmpLessOrEq: - case IrBinOpCmpGreaterOrEq: - return ir_analyze_bin_op_cmp(ira, bin_op_instruction); - case IrBinOpBitShiftLeftLossy: - case IrBinOpBitShiftLeftExact: - case IrBinOpBitShiftRightLossy: - case IrBinOpBitShiftRightExact: - case IrBinOpShlSat: - return ir_analyze_bit_shift(ira, bin_op_instruction); - case IrBinOpBinOr: - case IrBinOpBinXor: - case IrBinOpBinAnd: - case IrBinOpAdd: - case IrBinOpAddWrap: - case IrBinOpSub: - case IrBinOpSubWrap: - case IrBinOpMult: - case IrBinOpMultWrap: - case IrBinOpDivUnspecified: - case IrBinOpDivTrunc: - case IrBinOpDivFloor: - case IrBinOpDivExact: - case IrBinOpRemUnspecified: - case IrBinOpRemRem: - case IrBinOpRemMod: - case IrBinOpMax: - case IrBinOpMin: - case IrBinOpAddSat: - case IrBinOpSubSat: - case IrBinOpMultSat: - return ir_analyze_bin_op_math(ira, bin_op_instruction); - case IrBinOpArrayCat: - return ir_analyze_array_cat(ira, bin_op_instruction); - case IrBinOpArrayMult: - return ir_analyze_array_mult(ira, bin_op_instruction); - } - zig_unreachable(); -} - -static Stage1AirInst *ir_analyze_instruction_decl_var(IrAnalyze *ira, Stage1ZirInstDeclVar *decl_var_instruction) { - Error err; - ZigVar *var = decl_var_instruction->var; - - ZigType *explicit_type = nullptr; - Stage1AirInst *var_type = nullptr; - if (decl_var_instruction->var_type != nullptr) { - var_type = decl_var_instruction->var_type->child; - ZigType *proposed_type = ir_resolve_type(ira, var_type); - explicit_type = validate_var_type(ira->codegen, &var->decl_node->data.variable_declaration, proposed_type); - if (type_is_invalid(explicit_type)) { - var->var_type = ira->codegen->builtin_types.entry_invalid; - return ira->codegen->invalid_inst_gen; - } - } - - AstNode *source_node = decl_var_instruction->base.source_node; - - bool is_comptime_var = ir_get_var_is_comptime(var); - - bool var_class_requires_const = false; - - Stage1AirInst *var_ptr = decl_var_instruction->ptr->child; - // if this is null, a compiler error happened and did not initialize the variable. - // if there are no compile errors there may be a missing ir_expr_wrap in pass1 IR generation. - if (var_ptr == nullptr || type_is_invalid(var_ptr->value->type)) { - src_assert(var_ptr != nullptr || ira->codegen->errors.length != 0, - decl_var_instruction->base.source_node); - var->var_type = ira->codegen->builtin_types.entry_invalid; - return ira->codegen->invalid_inst_gen; - } - - // The ir_build_var_decl_src call is supposed to pass a pointer to the allocation, not an initialization value. - src_assert(var_ptr->value->type->id == ZigTypeIdPointer, decl_var_instruction->base.source_node); - - ZigType *result_type = var_ptr->value->type->data.pointer.child_type; - if (type_is_invalid(result_type)) { - result_type = ira->codegen->builtin_types.entry_invalid; - } else if (result_type->id == ZigTypeIdUnreachable || result_type->id == ZigTypeIdOpaque) { - zig_unreachable(); - } - - ZigValue *init_val = nullptr; - if (instr_is_comptime(var_ptr) && var_ptr->value->data.x_ptr.mut != ConstPtrMutRuntimeVar) { - ZigValue *ptr_val = ir_resolve_const(ira, var_ptr, UndefBad); - if (ptr_val == nullptr) - return ira->codegen->invalid_inst_gen; - - init_val = const_ptr_pointee(ira, ira->codegen, ptr_val, decl_var_instruction->base.source_node); - if (init_val == nullptr) - return ira->codegen->invalid_inst_gen; - - if (is_comptime_var) { - if (var->gen_is_const) { - var->const_value = init_val; - } else { - var->const_value = ira->codegen->pass1_arena->create(); - copy_const_val(ira->codegen, var->const_value, init_val); - } - } - } - - switch (type_requires_comptime(ira->codegen, result_type)) { - case ReqCompTimeInvalid: - result_type = ira->codegen->builtin_types.entry_invalid; - break; - case ReqCompTimeYes: - var_class_requires_const = true; - if (!var->gen_is_const && !is_comptime_var) { - ErrorMsg *msg = ir_add_error_node(ira, source_node, - buf_sprintf("variable of type '%s' must be const or comptime", - buf_ptr(&result_type->name))); - if(result_type->id == ZigTypeIdComptimeInt || result_type -> id == ZigTypeIdComptimeFloat) { - add_error_note(ira->codegen, msg, source_node, buf_sprintf("to modify this variable at runtime, it must be given an explicit fixed-size number type")); - } - result_type = ira->codegen->builtin_types.entry_invalid; - } - break; - case ReqCompTimeNo: - if (init_val != nullptr && value_is_comptime(init_val)) { - if ((err = ir_resolve_const_val(ira->codegen, ira->new_irb.exec, - decl_var_instruction->base.source_node, init_val, UndefOk))) - { - result_type = ira->codegen->builtin_types.entry_invalid; - } else if (init_val->type->id == ZigTypeIdFn && - init_val->special != ConstValSpecialUndef && - init_val->data.x_ptr.special == ConstPtrSpecialFunction && - init_val->data.x_ptr.data.fn.fn_entry->type_entry->data.fn.fn_type_id.cc == CallingConventionInline) - { - var_class_requires_const = true; - if (!var->src_is_const && !is_comptime_var) { - ErrorMsg *msg = ir_add_error_node(ira, source_node, - buf_sprintf("functions marked inline must be stored in const or comptime var")); - AstNode *proto_node = init_val->data.x_ptr.data.fn.fn_entry->proto_node; - add_error_note(ira->codegen, msg, proto_node, buf_sprintf("declared here")); - result_type = ira->codegen->builtin_types.entry_invalid; - } - } - } - break; - } - - while (var->next_var != nullptr) { - var = var->next_var; - } - - // This must be done after possibly creating a new variable above - var->ref_count = 0; - - var->ptr_instruction = var_ptr; - var->var_type = result_type; - assert(var->var_type); - - if (type_is_invalid(result_type)) { - return ir_const_void(ira, decl_var_instruction->base.scope, decl_var_instruction->base.source_node); - } - - if (decl_var_instruction->align_value == nullptr) { - if ((err = type_resolve(ira->codegen, result_type, ResolveStatusAlignmentKnown))) { - var->var_type = ira->codegen->builtin_types.entry_invalid; - return ir_const_void(ira, decl_var_instruction->base.scope, decl_var_instruction->base.source_node); - } - var->align_bytes = get_ptr_align(ira->codegen, var_ptr->value->type); - } else { - if (!ir_resolve_align(ira, decl_var_instruction->align_value->child, nullptr, &var->align_bytes)) { - var->var_type = ira->codegen->builtin_types.entry_invalid; - } - } - - if (init_val != nullptr && value_is_comptime(init_val)) { - // Resolve ConstPtrMutInfer - if (var->gen_is_const) { - var_ptr->value->data.x_ptr.mut = ConstPtrMutComptimeConst; - } else if (is_comptime_var) { - var_ptr->value->data.x_ptr.mut = ConstPtrMutComptimeVar; - } else { - // we need a runtime ptr but we have a comptime val. - // since it's a comptime val there are no instructions for it. - // we memcpy the init value here - Stage1AirInst *deref = ir_get_deref(ira, var_ptr->scope, var_ptr->source_node, var_ptr, nullptr); - if (type_is_invalid(deref->value->type)) { - var->var_type = ira->codegen->builtin_types.entry_invalid; - return ira->codegen->invalid_inst_gen; - } - // If this assertion trips, something is wrong with the IR instructions, because - // we expected the above deref to return a constant value, but it created a runtime - // instruction. - assert(deref->value->special != ConstValSpecialRuntime); - var_ptr->value->special = ConstValSpecialRuntime; - ir_analyze_store_ptr(ira, var_ptr->scope, var_ptr->source_node, var_ptr, deref, false); - } - if (instr_is_comptime(var_ptr) && (is_comptime_var || (var_class_requires_const && var->gen_is_const))) { - return ir_const_void(ira, decl_var_instruction->base.scope, decl_var_instruction->base.source_node); - } - } else if (is_comptime_var) { - ir_add_error_node(ira, decl_var_instruction->base.source_node, - buf_sprintf("cannot store runtime value in compile time variable")); - var->var_type = ira->codegen->builtin_types.entry_invalid; - return ira->codegen->invalid_inst_gen; - } - - ZigFn *fn_entry = ira->fn; - if (fn_entry) - fn_entry->variable_list.append(var); - - return ir_build_var_decl_gen(ira, decl_var_instruction->base.scope, decl_var_instruction->base.source_node, var, var_ptr); -} - -static Stage1AirInst *ir_analyze_instruction_export(IrAnalyze *ira, Stage1ZirInstExport *instruction) { - Stage1AirInst *target = instruction->target->child; - if (type_is_invalid(target->value->type)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *options = instruction->options->child; - if (type_is_invalid(options->value->type)) - return ira->codegen->invalid_inst_gen; - - ZigType *options_type = options->value->type; - assert(options_type->id == ZigTypeIdStruct); - - TypeStructField *name_field = find_struct_type_field(options_type, buf_create_from_str("name")); - src_assert(name_field != nullptr, instruction->base.source_node); - Stage1AirInst *name_inst = ir_analyze_struct_value_field_value(ira, instruction->base.scope, instruction->base.source_node, options, name_field); - if (type_is_invalid(name_inst->value->type)) - return ira->codegen->invalid_inst_gen; - - TypeStructField *linkage_field = find_struct_type_field(options_type, buf_create_from_str("linkage")); - src_assert(linkage_field != nullptr, instruction->base.source_node); - Stage1AirInst *linkage_inst = ir_analyze_struct_value_field_value(ira, instruction->base.scope, instruction->base.source_node, options, linkage_field); - if (type_is_invalid(linkage_inst->value->type)) - return ira->codegen->invalid_inst_gen; - - TypeStructField *section_field = find_struct_type_field(options_type, buf_create_from_str("section")); - src_assert(section_field != nullptr, instruction->base.source_node); - Stage1AirInst *section_inst = ir_analyze_struct_value_field_value(ira, instruction->base.scope, instruction->base.source_node, options, section_field); - if (type_is_invalid(section_inst->value->type)) - return ira->codegen->invalid_inst_gen; - - // The `section` field is optional, we have to unwrap it first - Stage1AirInst *non_null_check = ir_analyze_test_non_null(ira, instruction->base.scope, instruction->base.source_node, section_inst); - bool is_non_null; - if (!ir_resolve_bool(ira, non_null_check, &is_non_null)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *section_str_inst = nullptr; - if (is_non_null) { - section_str_inst = ir_analyze_optional_value_payload_value(ira, instruction->base.scope, instruction->base.source_node, section_inst, false); - if (type_is_invalid(section_str_inst->value->type)) - return ira->codegen->invalid_inst_gen; - } - - // Resolve all the comptime values - Buf *symbol_name = ir_resolve_str(ira, name_inst); - if (!symbol_name) - return ira->codegen->invalid_inst_gen; - - if (buf_len(symbol_name) < 1) { - ir_add_error(ira, name_inst, - buf_sprintf("exported symbol name cannot be empty")); - return ira->codegen->invalid_inst_gen; - } - - GlobalLinkageId global_linkage_id; - if (!ir_resolve_global_linkage(ira, linkage_inst, &global_linkage_id)) - return ira->codegen->invalid_inst_gen; - - Buf *section_name = nullptr; - if (section_str_inst != nullptr && !(section_name = ir_resolve_str(ira, section_str_inst))) - return ira->codegen->invalid_inst_gen; - - // TODO: This function needs to be audited. - // It's not clear how all the different types are supposed to be handled. - // Need comprehensive tests for exporting one thing in one file and declaring an extern var - // in another file. - TldFn *tld_fn = heap::c_allocator.create(); - tld_fn->base.id = TldIdFn; - tld_fn->base.source_node = instruction->base.source_node; - - auto entry = ira->codegen->exported_symbol_names.put_unique(symbol_name, &tld_fn->base); - if (entry) { - AstNode *other_export_node = entry->value->source_node; - ErrorMsg *msg = ir_add_error_node(ira, instruction->base.source_node, - buf_sprintf("exported symbol collision: '%s'", buf_ptr(symbol_name))); - add_error_note(ira->codegen, msg, other_export_node, buf_sprintf("other symbol here")); - return ira->codegen->invalid_inst_gen; - } - - Error err; - bool want_var_export = false; - switch (target->value->type->id) { - case ZigTypeIdInvalid: - case ZigTypeIdUnreachable: - zig_unreachable(); - case ZigTypeIdFn: { - assert(target->value->data.x_ptr.special == ConstPtrSpecialFunction); - ZigFn *fn_entry = target->value->data.x_ptr.data.fn.fn_entry; - tld_fn->fn_entry = fn_entry; - CallingConvention cc = fn_entry->type_entry->data.fn.fn_type_id.cc; - switch (cc) { - case CallingConventionUnspecified: { - ErrorMsg *msg = ir_add_error(ira, target, - buf_sprintf("exported function must specify calling convention")); - add_error_note(ira->codegen, msg, fn_entry->proto_node, buf_sprintf("declared here")); - } break; - case CallingConventionAsync: { - ErrorMsg *msg = ir_add_error(ira, target, - buf_sprintf("exported function cannot be async")); - add_error_note(ira->codegen, msg, fn_entry->proto_node, buf_sprintf("declared here")); - } break; - case CallingConventionInline: { - ErrorMsg *msg = ir_add_error(ira, target, - buf_sprintf("exported function cannot be inline")); - add_error_note(ira->codegen, msg, fn_entry->proto_node, buf_sprintf("declared here")); - } break; - case CallingConventionC: - case CallingConventionNaked: - case CallingConventionInterrupt: - case CallingConventionSignal: - case CallingConventionStdcall: - case CallingConventionFastcall: - case CallingConventionVectorcall: - case CallingConventionThiscall: - case CallingConventionAPCS: - case CallingConventionAAPCS: - case CallingConventionAAPCSVFP: - case CallingConventionSysV: - case CallingConventionWin64: - case CallingConventionPtxKernel: - case CallingConventionAmdgpuKernel: - add_fn_export(ira->codegen, fn_entry, buf_ptr(symbol_name), global_linkage_id, cc); - fn_entry->section_name = section_name; - break; - } - } break; - case ZigTypeIdStruct: - if (is_slice(target->value->type)) { - ir_add_error(ira, target, - buf_sprintf("unable to export value of type '%s'", buf_ptr(&target->value->type->name))); - } else if (target->value->type->data.structure.layout != ContainerLayoutExtern) { - ErrorMsg *msg = ir_add_error(ira, target, - buf_sprintf("exported struct value must be declared extern")); - add_error_note(ira->codegen, msg, target->value->type->data.structure.decl_node, buf_sprintf("declared here")); - } else { - want_var_export = true; - } - break; - case ZigTypeIdUnion: - if (target->value->type->data.unionation.layout != ContainerLayoutExtern) { - ErrorMsg *msg = ir_add_error(ira, target, - buf_sprintf("exported union value must be declared extern")); - add_error_note(ira->codegen, msg, target->value->type->data.unionation.decl_node, buf_sprintf("declared here")); - } else { - want_var_export = true; - } - break; - case ZigTypeIdEnum: - if ((err = type_resolve(ira->codegen, target->value->type, ResolveStatusZeroBitsKnown))) - return ira->codegen->invalid_inst_gen; - if (!target->value->type->data.enumeration.has_explicit_tag_type) { - ErrorMsg *msg = ir_add_error(ira, target, - buf_sprintf("exported enum value without explicit integer tag type")); - add_error_note(ira->codegen, msg, target->value->type->data.enumeration.decl_node, buf_sprintf("declared here")); - } else { - want_var_export = true; - } - break; - case ZigTypeIdArray: { - bool ok_type; - if ((err = type_allowed_in_extern(ira->codegen, target->value->type->data.array.child_type, ExternPositionOther, &ok_type))) - return ira->codegen->invalid_inst_gen; - - if (!ok_type) { - ir_add_error(ira, target, - buf_sprintf("array element type '%s' not extern-compatible", - buf_ptr(&target->value->type->data.array.child_type->name))); - } else { - want_var_export = true; - } - break; - } - case ZigTypeIdMetaType: { - ZigType *type_value = target->value->data.x_type; - switch (type_value->id) { - case ZigTypeIdInvalid: - zig_unreachable(); - case ZigTypeIdStruct: - if (is_slice(type_value)) { - ir_add_error(ira, target, - buf_sprintf("unable to export type '%s'", buf_ptr(&type_value->name))); - } else if (type_value->data.structure.layout != ContainerLayoutExtern) { - ErrorMsg *msg = ir_add_error(ira, target, - buf_sprintf("exported struct must be declared extern")); - add_error_note(ira->codegen, msg, type_value->data.structure.decl_node, buf_sprintf("declared here")); - } - break; - case ZigTypeIdUnion: - if (type_value->data.unionation.layout != ContainerLayoutExtern) { - ErrorMsg *msg = ir_add_error(ira, target, - buf_sprintf("exported union must be declared extern")); - add_error_note(ira->codegen, msg, type_value->data.unionation.decl_node, buf_sprintf("declared here")); - } - break; - case ZigTypeIdEnum: - if ((err = type_resolve(ira->codegen, type_value, ResolveStatusZeroBitsKnown))) - return ira->codegen->invalid_inst_gen; - if (!type_value->data.enumeration.has_explicit_tag_type) { - ErrorMsg *msg = ir_add_error(ira, target, - buf_sprintf("exported enum without explicit integer tag type")); - add_error_note(ira->codegen, msg, type_value->data.enumeration.decl_node, buf_sprintf("declared here")); - } - break; - case ZigTypeIdFn: { - if (type_value->data.fn.fn_type_id.cc == CallingConventionUnspecified) { - ir_add_error(ira, target, - buf_sprintf("exported function type must specify calling convention")); - } - } break; - case ZigTypeIdInt: - case ZigTypeIdFloat: - case ZigTypeIdPointer: - case ZigTypeIdArray: - case ZigTypeIdBool: - case ZigTypeIdVector: - break; - case ZigTypeIdMetaType: - case ZigTypeIdVoid: - case ZigTypeIdUnreachable: - case ZigTypeIdComptimeFloat: - case ZigTypeIdComptimeInt: - case ZigTypeIdEnumLiteral: - case ZigTypeIdUndefined: - case ZigTypeIdNull: - case ZigTypeIdOptional: - case ZigTypeIdErrorUnion: - case ZigTypeIdErrorSet: - case ZigTypeIdBoundFn: - case ZigTypeIdOpaque: - case ZigTypeIdFnFrame: - case ZigTypeIdAnyFrame: - ir_add_error(ira, target, - buf_sprintf("invalid export target '%s'", buf_ptr(&type_value->name))); - break; - } - } break; - case ZigTypeIdInt: - want_var_export = true; - break; - case ZigTypeIdVoid: - case ZigTypeIdBool: - case ZigTypeIdFloat: - case ZigTypeIdPointer: - case ZigTypeIdComptimeFloat: - case ZigTypeIdComptimeInt: - case ZigTypeIdUndefined: - case ZigTypeIdNull: - case ZigTypeIdOptional: - case ZigTypeIdErrorUnion: - case ZigTypeIdErrorSet: - case ZigTypeIdVector: - zig_panic("TODO export const value of type %s", buf_ptr(&target->value->type->name)); - case ZigTypeIdBoundFn: - case ZigTypeIdOpaque: - case ZigTypeIdEnumLiteral: - case ZigTypeIdFnFrame: - case ZigTypeIdAnyFrame: - ir_add_error(ira, target, - buf_sprintf("invalid export target type '%s'", buf_ptr(&target->value->type->name))); - break; - } - - // TODO audit the various ways to use @export - if (want_var_export && target->id == Stage1AirInstIdLoadPtr) { - Stage1AirInstLoadPtr *load_ptr = reinterpret_cast(target); - if (load_ptr->ptr->id == Stage1AirInstIdVarPtr) { - Stage1AirInstVarPtr *var_ptr = reinterpret_cast(load_ptr->ptr); - ZigVar *var = var_ptr->var; - add_var_export(ira->codegen, var, buf_ptr(symbol_name), global_linkage_id); - var->section_name = section_name; - } - } - - return ir_const_void(ira, instruction->base.scope, instruction->base.source_node); -} - -static void add_link_lib_symbol(IrAnalyze *ira, Buf *lib_name, Buf *symbol_name, AstNode *source_node); - -static Stage1AirInst *ir_analyze_instruction_extern(IrAnalyze *ira, Stage1ZirInstExtern *instruction) { - Stage1AirInst *type_inst = instruction->type->child; - if (type_is_invalid(type_inst->value->type)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *options = instruction->options->child; - if (type_is_invalid(options->value->type)) - return ira->codegen->invalid_inst_gen; - - ZigType *options_type = options->value->type; - assert(options_type->id == ZigTypeIdStruct); - - TypeStructField *name_field = find_struct_type_field(options_type, buf_create_from_str("name")); - src_assert(name_field != nullptr, instruction->base.source_node); - Stage1AirInst *name_inst = ir_analyze_struct_value_field_value(ira, instruction->base.scope, instruction->base.source_node, options, name_field); - if (type_is_invalid(name_inst->value->type)) - return ira->codegen->invalid_inst_gen; - - TypeStructField *linkage_field = find_struct_type_field(options_type, buf_create_from_str("linkage")); - src_assert(linkage_field != nullptr, instruction->base.source_node); - Stage1AirInst *linkage_inst = ir_analyze_struct_value_field_value(ira, instruction->base.scope, instruction->base.source_node, options, linkage_field); - if (type_is_invalid(linkage_inst->value->type)) - return ira->codegen->invalid_inst_gen; - - TypeStructField *is_thread_local_field = find_struct_type_field(options_type, buf_create_from_str("is_thread_local")); - src_assert(is_thread_local_field != nullptr, instruction->base.source_node); - Stage1AirInst *is_thread_local_inst = ir_analyze_struct_value_field_value(ira, instruction->base.scope, instruction->base.source_node, options, is_thread_local_field); - if (type_is_invalid(is_thread_local_inst->value->type)) - return ira->codegen->invalid_inst_gen; - - TypeStructField *library_name_field = find_struct_type_field(options_type, buf_create_from_str("library_name")); - src_assert(library_name_field != nullptr, instruction->base.source_node); - Stage1AirInst *library_name_inst = ir_analyze_struct_value_field_value(ira, instruction->base.scope, instruction->base.source_node, options, library_name_field); - if (type_is_invalid(library_name_inst->value->type)) - return ira->codegen->invalid_inst_gen; - - // The `library_name` field is optional, we have to unwrap it first - Stage1AirInst *non_null_check = ir_analyze_test_non_null(ira, instruction->base.scope, instruction->base.source_node, library_name_inst); - bool is_non_null; - if (!ir_resolve_bool(ira, non_null_check, &is_non_null)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *library_name_val_inst = nullptr; - if (is_non_null) { - library_name_val_inst = ir_analyze_optional_value_payload_value(ira, instruction->base.scope, instruction->base.source_node, library_name_inst, false); - if (type_is_invalid(library_name_val_inst->value->type)) - return ira->codegen->invalid_inst_gen; - } - - // Resolve all the comptime values - ZigType *value_type = ir_resolve_type(ira, type_inst); - if (type_is_invalid(value_type)) - return ira->codegen->invalid_inst_gen; - - if (get_src_ptr_type(value_type) == nullptr) { - ir_add_error(ira, name_inst, - buf_sprintf("expected (optional) pointer type or function")); - return ira->codegen->invalid_inst_gen; - } - - Buf *symbol_name = ir_resolve_str(ira, name_inst); - if (!symbol_name) - return ira->codegen->invalid_inst_gen; - - if (buf_len(symbol_name) == 0) { - ir_add_error(ira, name_inst, - buf_sprintf("extern symbol name cannot be empty")); - return ira->codegen->invalid_inst_gen; - } - - Buf *library_name = nullptr; - if (library_name_val_inst) { - library_name = ir_resolve_str(ira, library_name_val_inst); - if (!library_name) - return ira->codegen->invalid_inst_gen; - - if (buf_len(library_name) == 0) { - ir_add_error(ira, library_name_inst, - buf_sprintf("library name name cannot be empty")); - return ira->codegen->invalid_inst_gen; - } - - add_link_lib_symbol(ira, library_name, symbol_name, instruction->base.source_node); - - buf_destroy(library_name); - } - - GlobalLinkageId global_linkage_id; - if (!ir_resolve_global_linkage(ira, linkage_inst, &global_linkage_id)) - return ira->codegen->invalid_inst_gen; - - bool is_thread_local; - if (!ir_resolve_bool(ira, is_thread_local_inst, &is_thread_local)) - return ira->codegen->invalid_inst_gen; - - ZigType *expr_type = value_type; - if (global_linkage_id == GlobalLinkageIdWeak && value_type->id != ZigTypeIdOptional) - expr_type = get_optional_type(ira->codegen, expr_type); - - // Create a bogus Tld object to keep track of the extern symbol. - // XXX: Find a better way to do this (in stage2). - TldFn *tld_fn = heap::c_allocator.create(); - tld_fn->base.id = TldIdFn; - tld_fn->base.source_node = instruction->base.source_node; - - auto entry = ira->codegen->external_symbol_names.put_unique(symbol_name, &tld_fn->base); - if (entry) { - AstNode *other_extern_node = entry->value->source_node; - ErrorMsg *msg = ir_add_error_node(ira, instruction->base.source_node, - buf_sprintf("extern symbol collision: '%s'", buf_ptr(symbol_name))); - add_error_note(ira->codegen, msg, other_extern_node, buf_sprintf("other symbol here")); - return ira->codegen->invalid_inst_gen; - } - - return ir_build_extern_gen(ira, instruction->base.scope, instruction->base.source_node, symbol_name, global_linkage_id, - is_thread_local, expr_type); -} - -static bool ira_has_err_ret_trace(IrAnalyze *ira) { - ZigFn *fn = ira->fn; - return fn != nullptr && fn->calls_or_awaits_errorable_fn && ira->codegen->have_err_ret_tracing; -} - -static Stage1AirInst *ir_analyze_instruction_error_return_trace(IrAnalyze *ira, - Stage1ZirInstErrorReturnTrace *instruction) -{ - ZigType *ptr_to_stack_trace_type = get_pointer_to_type(ira->codegen, get_stack_trace_type(ira->codegen), false); - if (instruction->optional == IrInstErrorReturnTraceNull) { - ZigType *optional_type = get_optional_type(ira->codegen, ptr_to_stack_trace_type); - if (!ira_has_err_ret_trace(ira)) { - Stage1AirInst *result = ir_const(ira, instruction->base.scope, instruction->base.source_node, optional_type); - ZigValue *out_val = result->value; - assert(get_src_ptr_type(optional_type) != nullptr); - out_val->data.x_ptr.special = ConstPtrSpecialHardCodedAddr; - out_val->data.x_ptr.data.hard_coded_addr.addr = 0; - return result; - } - return ir_build_error_return_trace_gen(ira, instruction->base.scope, - instruction->base.source_node, instruction->optional, optional_type); - } else { - assert(ira->codegen->have_err_ret_tracing); - return ir_build_error_return_trace_gen(ira, instruction->base.scope, - instruction->base.source_node, instruction->optional, ptr_to_stack_trace_type); - } -} - -static Stage1AirInst *ir_analyze_instruction_error_union(IrAnalyze *ira, Stage1ZirInstErrorUnion *instruction) { - Stage1AirInst *result = ir_const(ira, instruction->base.scope, instruction->base.source_node, ira->codegen->builtin_types.entry_type); - result->value->special = ConstValSpecialLazy; - - LazyValueErrUnionType *lazy_err_union_type = heap::c_allocator.create(); - lazy_err_union_type->ira = ira; ira_ref(ira); - result->value->data.x_lazy = &lazy_err_union_type->base; - lazy_err_union_type->base.id = LazyValueIdErrUnionType; - - lazy_err_union_type->err_set_type = instruction->err_set->child; - if (ir_resolve_type_lazy(ira, lazy_err_union_type->err_set_type) == nullptr) - return ira->codegen->invalid_inst_gen; - - lazy_err_union_type->payload_type = instruction->payload->child; - if (ir_resolve_type_lazy(ira, lazy_err_union_type->payload_type) == nullptr) - return ira->codegen->invalid_inst_gen; - - return result; -} - -static Stage1AirInst *ir_analyze_alloca(IrAnalyze *ira, Scope *scope, AstNode *source_node, ZigType *var_type, - uint32_t align, const char *name_hint, bool force_comptime) -{ - Error err; - - ZigValue *pointee = ira->codegen->pass1_arena->create(); - pointee->special = ConstValSpecialUndef; - pointee->llvm_align = align; - - Stage1AirInstAlloca *result = ir_build_alloca_gen(ira, scope, source_node, align, name_hint); - result->base.value->special = ConstValSpecialStatic; - result->base.value->data.x_ptr.special = ConstPtrSpecialRef; - result->base.value->data.x_ptr.mut = force_comptime ? ConstPtrMutComptimeVar : ConstPtrMutInfer; - result->base.value->data.x_ptr.data.ref.pointee = pointee; - - bool var_type_has_bits; - if ((err = type_has_bits2(ira->codegen, var_type, &var_type_has_bits))) - return ira->codegen->invalid_inst_gen; - if (align != 0) { - if ((err = type_resolve(ira->codegen, var_type, ResolveStatusAlignmentKnown))) - return ira->codegen->invalid_inst_gen; - if (!var_type_has_bits) { - ir_add_error_node(ira, source_node, - buf_sprintf("variable '%s' of zero-bit type '%s' has no in-memory representation, it cannot be aligned", - name_hint, buf_ptr(&var_type->name))); - return ira->codegen->invalid_inst_gen; - } - } - assert(result->base.value->data.x_ptr.special != ConstPtrSpecialInvalid); - - pointee->type = var_type; - result->base.value->type = get_pointer_to_type_extra(ira->codegen, var_type, false, false, - PtrLenSingle, align, 0, 0, false); - - if (!force_comptime) { - ZigFn *fn_entry = ira->fn; - if (fn_entry != nullptr) { - fn_entry->alloca_gen_list.append(result); - } - } - return &result->base; -} - -static ZigType *ir_result_loc_expected_type(IrAnalyze *ira, ResultLoc *result_loc) { - switch (result_loc->id) { - case ResultLocIdInvalid: - case ResultLocIdPeerParent: - zig_unreachable(); - case ResultLocIdNone: - case ResultLocIdVar: - case ResultLocIdBitCast: - case ResultLocIdCast: - return nullptr; - case ResultLocIdInstruction: - return result_loc->source_instruction->child->value->type; - case ResultLocIdReturn: - return ira->explicit_return_type; - case ResultLocIdPeer: - return reinterpret_cast(result_loc)->parent->resolved_type; - } - zig_unreachable(); -} - -static bool type_can_bit_cast(ZigType *t) { - switch (t->id) { - case ZigTypeIdInvalid: - zig_unreachable(); - case ZigTypeIdMetaType: - case ZigTypeIdOpaque: - case ZigTypeIdBoundFn: - case ZigTypeIdUnreachable: - case ZigTypeIdComptimeFloat: - case ZigTypeIdComptimeInt: - case ZigTypeIdEnumLiteral: - case ZigTypeIdUndefined: - case ZigTypeIdNull: - case ZigTypeIdPointer: - return false; - default: - // TODO list these types out explicitly, there are probably some other invalid ones here - return true; - } -} - -static void set_up_result_loc_for_inferred_comptime(IrAnalyze *ira, Stage1AirInst *ptr) { - ZigValue *undef_child = ira->codegen->pass1_arena->create(); - undef_child->type = ptr->value->type->data.pointer.child_type; - undef_child->special = ConstValSpecialUndef; - ptr->value->special = ConstValSpecialStatic; - ptr->value->data.x_ptr.mut = ConstPtrMutInfer; - ptr->value->data.x_ptr.special = ConstPtrSpecialRef; - ptr->value->data.x_ptr.data.ref.pointee = undef_child; -} - -static Error ir_result_has_type(IrAnalyze *ira, ResultLoc *result_loc, bool *out) { - switch (result_loc->id) { - case ResultLocIdInvalid: - case ResultLocIdPeerParent: - zig_unreachable(); - case ResultLocIdNone: - case ResultLocIdPeer: - *out = false; - return ErrorNone; - case ResultLocIdReturn: - case ResultLocIdInstruction: - case ResultLocIdBitCast: - *out = true; - return ErrorNone; - case ResultLocIdCast: { - ResultLocCast *result_cast = reinterpret_cast(result_loc); - ZigType *dest_type = ir_resolve_type(ira, result_cast->base.source_instruction->child); - if (type_is_invalid(dest_type)) - return ErrorSemanticAnalyzeFail; - *out = (dest_type != ira->codegen->builtin_types.entry_anytype); - return ErrorNone; - } - case ResultLocIdVar: - *out = reinterpret_cast(result_loc)->var->decl_node->data.variable_declaration.type != nullptr; - return ErrorNone; - } - zig_unreachable(); -} - -static Stage1AirInst *ir_resolve_no_result_loc(IrAnalyze *ira, Stage1ZirInst *suspend_source_instr, - ResultLoc *result_loc, ZigType *value_type) -{ - if (type_is_invalid(value_type)) - return ira->codegen->invalid_inst_gen; - Stage1AirInstAlloca *alloca_gen = ir_build_alloca_gen(ira, suspend_source_instr->scope, - suspend_source_instr->source_node, 0, ""); - alloca_gen->base.value->type = get_pointer_to_type_extra(ira->codegen, value_type, false, false, - PtrLenSingle, 0, 0, 0, false); - set_up_result_loc_for_inferred_comptime(ira, &alloca_gen->base); - ZigFn *fn_entry = ira->fn; - if (fn_entry != nullptr && get_scope_typeof(suspend_source_instr->scope) == nullptr) { - fn_entry->alloca_gen_list.append(alloca_gen); - } - result_loc->written = true; - result_loc->resolved_loc = &alloca_gen->base; - return result_loc->resolved_loc; -} - -static bool result_loc_is_discard(ResultLoc *result_loc_pass1) { - if (result_loc_pass1->id == ResultLocIdInstruction && - result_loc_pass1->source_instruction->id == Stage1ZirInstIdConst) - { - Stage1ZirInstConst *const_inst = reinterpret_cast(result_loc_pass1->source_instruction); - if (value_is_comptime(const_inst->value) && - const_inst->value->type->id == ZigTypeIdPointer && - const_inst->value->data.x_ptr.special == ConstPtrSpecialDiscard) - { - return true; - } - } - return false; -} - -// when calling this function, at the callsite must check for result type noreturn and propagate it up -static Stage1AirInst *ir_resolve_result_raw(IrAnalyze *ira, Stage1ZirInst *suspend_source_instr, - ResultLoc *result_loc, ZigType *value_type, Stage1AirInst *value, bool force_runtime, - bool allow_discard) -{ - Error err; - if (result_loc->resolved_loc != nullptr) { - // allow to redo the result location if the value is known and comptime and the previous one isn't - if (value == nullptr || !instr_is_comptime(value) || instr_is_comptime(result_loc->resolved_loc)) { - return result_loc->resolved_loc; - } - } - result_loc->gen_instruction = value; - result_loc->implicit_elem_type = value_type; - switch (result_loc->id) { - case ResultLocIdInvalid: - case ResultLocIdPeerParent: - zig_unreachable(); - case ResultLocIdNone: { - if (value != nullptr) { - return nullptr; - } - // need to return a result location and don't have one. use a stack allocation - return ir_resolve_no_result_loc(ira, suspend_source_instr, result_loc, value_type); - } - case ResultLocIdVar: { - ResultLocVar *result_loc_var = reinterpret_cast(result_loc); - assert(result_loc->source_instruction->id == Stage1ZirInstIdAlloca); - Stage1ZirInstAlloca *alloca_src = reinterpret_cast(result_loc->source_instruction); - - ZigVar *var = result_loc_var->var; - if (var->var_type != nullptr && !ir_get_var_is_comptime(var)) { - // This is at least the second time we've seen this variable declaration during analysis. - // This means that this is actually a different variable due to, e.g. an inline while loop. - // We make a new variable so that it can hold a different type, and so the debug info can - // be distinct. - ZigVar *new_var = create_local_var(ira->codegen, var->decl_node, var->child_scope, - buf_create_from_str(var->name), var->src_is_const, var->gen_is_const, - var->shadowable, var->is_comptime, true); - new_var->align_bytes = var->align_bytes; - - var->next_var = new_var; - var = new_var; - } - if (value_type->id == ZigTypeIdUnreachable || value_type->id == ZigTypeIdOpaque) { - ir_add_error_node(ira, result_loc->source_instruction->source_node, - buf_sprintf("variable of type '%s' not allowed", buf_ptr(&value_type->name))); - return ira->codegen->invalid_inst_gen; - } - if (alloca_src->base.child == nullptr || var->ptr_instruction == nullptr) { - bool force_comptime; - if (!ir_resolve_comptime(ira, alloca_src->is_comptime->child, &force_comptime)) - return ira->codegen->invalid_inst_gen; - uint32_t align = 0; - if (alloca_src->align != nullptr && !ir_resolve_align(ira, alloca_src->align->child, nullptr, &align)) { - return ira->codegen->invalid_inst_gen; - } - Stage1AirInst *alloca_gen = ir_analyze_alloca(ira, - result_loc->source_instruction->scope, - result_loc->source_instruction->source_node, value_type, - align, alloca_src->name_hint, force_comptime); - if (force_runtime) { - alloca_gen->value->data.x_ptr.mut = ConstPtrMutRuntimeVar; - alloca_gen->value->special = ConstValSpecialRuntime; - } - if (alloca_src->base.child != nullptr && !result_loc->written) { - alloca_src->base.child->ref_count = 0; - } - alloca_src->base.child = alloca_gen; - var->ptr_instruction = alloca_gen; - } - result_loc->written = true; - result_loc->resolved_loc = alloca_src->base.child; - return alloca_src->base.child; - } - case ResultLocIdInstruction: { - result_loc->written = true; - result_loc->resolved_loc = result_loc->source_instruction->child; - return result_loc->resolved_loc; - } - case ResultLocIdReturn: { - if (value != nullptr) { - reinterpret_cast(result_loc)->implicit_return_type_done = true; - ira->src_implicit_return_type_list.append(value); - } - result_loc->written = true; - result_loc->resolved_loc = ira->return_ptr; - return result_loc->resolved_loc; - } - case ResultLocIdPeer: { - ResultLocPeer *result_peer = reinterpret_cast(result_loc); - ResultLocPeerParent *peer_parent = result_peer->parent; - - if (peer_parent->peers.length == 1) { - Stage1AirInst *parent_result_loc = ir_resolve_result(ira, suspend_source_instr, peer_parent->parent, - value_type, value, force_runtime, true); - result_peer->suspend_pos.basic_block_index = SIZE_MAX; - result_peer->suspend_pos.instruction_index = SIZE_MAX; - if (parent_result_loc == nullptr || type_is_invalid(parent_result_loc->value->type) || - parent_result_loc->value->type->id == ZigTypeIdUnreachable) - { - return parent_result_loc; - } - result_loc->written = true; - result_loc->resolved_loc = parent_result_loc; - return result_loc->resolved_loc; - } - - bool is_condition_comptime; - if (!ir_resolve_comptime(ira, peer_parent->is_comptime->child, &is_condition_comptime)) - return ira->codegen->invalid_inst_gen; - if (is_condition_comptime) { - peer_parent->skipped = true; - return ir_resolve_result(ira, suspend_source_instr, peer_parent->parent, - value_type, value, force_runtime, true); - } - bool peer_parent_has_type; - if ((err = ir_result_has_type(ira, peer_parent->parent, &peer_parent_has_type))) - return ira->codegen->invalid_inst_gen; - if (peer_parent_has_type) { - peer_parent->skipped = true; - Stage1AirInst *parent_result_loc = ir_resolve_result(ira, suspend_source_instr, peer_parent->parent, - value_type, value, force_runtime || !is_condition_comptime, true); - if (parent_result_loc == nullptr || type_is_invalid(parent_result_loc->value->type) || - parent_result_loc->value->type->id == ZigTypeIdUnreachable) - { - return parent_result_loc; - } - peer_parent->parent->written = true; - result_loc->written = true; - result_loc->resolved_loc = parent_result_loc; - return result_loc->resolved_loc; - } - - if (peer_parent->resolved_type == nullptr) { - if (peer_parent->end_bb->suspend_instruction_ref == nullptr) { - peer_parent->end_bb->suspend_instruction_ref = suspend_source_instr; - } - Stage1AirInst *unreach_inst = ira_suspend(ira, suspend_source_instr, result_peer->next_bb, - &result_peer->suspend_pos); - if (result_peer->next_bb == nullptr) { - ir_start_next_bb(ira); - } - return unreach_inst; - } - - Stage1AirInst *parent_result_loc = ir_resolve_result(ira, suspend_source_instr, peer_parent->parent, - peer_parent->resolved_type, nullptr, force_runtime, true); - if (parent_result_loc == nullptr || type_is_invalid(parent_result_loc->value->type) || - parent_result_loc->value->type->id == ZigTypeIdUnreachable) - { - return parent_result_loc; - } - // because is_condition_comptime is false, we mark this a runtime pointer - parent_result_loc->value->special = ConstValSpecialRuntime; - result_loc->written = true; - result_loc->resolved_loc = parent_result_loc; - return result_loc->resolved_loc; - } - case ResultLocIdCast: { - ResultLocCast *result_cast = reinterpret_cast(result_loc); - ZigType *dest_type = ir_resolve_type(ira, result_cast->base.source_instruction->child); - if (type_is_invalid(dest_type)) - return ira->codegen->invalid_inst_gen; - - if (dest_type == ira->codegen->builtin_types.entry_anytype) { - return ir_resolve_no_result_loc(ira, suspend_source_instr, result_loc, value_type); - } - - Stage1AirInst *casted_value; - if (value != nullptr) { - casted_value = ir_implicit_cast2(ira, suspend_source_instr->scope, - suspend_source_instr->source_node, value, dest_type); - if (type_is_invalid(casted_value->value->type)) - return ira->codegen->invalid_inst_gen; - dest_type = casted_value->value->type; - } else { - casted_value = nullptr; - } - - Stage1AirInst *parent_result_loc = ir_resolve_result(ira, suspend_source_instr, result_cast->parent, - dest_type, casted_value, force_runtime, true); - if (parent_result_loc == nullptr || type_is_invalid(parent_result_loc->value->type) || - parent_result_loc->value->type->id == ZigTypeIdUnreachable) - { - return parent_result_loc; - } - - ZigType *parent_ptr_type = parent_result_loc->value->type; - assert(parent_ptr_type->id == ZigTypeIdPointer); - - if ((err = type_resolve(ira->codegen, parent_ptr_type->data.pointer.child_type, - ResolveStatusAlignmentKnown))) - { - return ira->codegen->invalid_inst_gen; - } - uint64_t parent_ptr_align = get_ptr_align(ira->codegen, parent_ptr_type); - if ((err = type_resolve(ira->codegen, value_type, ResolveStatusAlignmentKnown))) { - return ira->codegen->invalid_inst_gen; - } - if (!type_has_bits(ira->codegen, value_type)) { - parent_ptr_align = 0; - } - // If we're casting from a sentinel-terminated array to a non-sentinel-terminated array, - // we actually need the result location pointer to *not* have a sentinel. Otherwise the generated - // memcpy will write an extra byte to the destination, and THAT'S NO GOOD. - ZigType *ptr_elem_type; - if (value_type->id == ZigTypeIdArray && value_type->data.array.sentinel != nullptr && - dest_type->id == ZigTypeIdArray && dest_type->data.array.sentinel == nullptr) - { - ptr_elem_type = get_array_type(ira->codegen, value_type->data.array.child_type, - value_type->data.array.len, nullptr); - } else { - ptr_elem_type = value_type; - } - ZigType *ptr_type = get_pointer_to_type_extra(ira->codegen, ptr_elem_type, - parent_ptr_type->data.pointer.is_const, parent_ptr_type->data.pointer.is_volatile, PtrLenSingle, - parent_ptr_align, 0, 0, parent_ptr_type->data.pointer.allow_zero); - - ConstCastOnly const_cast_result = types_match_const_cast_only(ira, - parent_result_loc->value->type, ptr_type, - result_cast->base.source_instruction->source_node, false); - if (const_cast_result.id == ConstCastResultIdInvalid) - return ira->codegen->invalid_inst_gen; - if (const_cast_result.id != ConstCastResultIdOk) { - if (allow_discard) { - return parent_result_loc; - } - // We will not be able to provide a result location for this value. Create - // a new result location. - result_cast->parent->written = false; - return ir_resolve_no_result_loc(ira, suspend_source_instr, result_loc, value_type); - } - - result_loc->written = true; - result_loc->resolved_loc = ir_analyze_ptr_cast(ira, suspend_source_instr->scope, - suspend_source_instr->source_node, parent_result_loc, - parent_result_loc->source_node, ptr_type, - result_cast->base.source_instruction->source_node, false, false); - return result_loc->resolved_loc; - } - case ResultLocIdBitCast: { - ResultLocBitCast *result_bit_cast = reinterpret_cast(result_loc); - ZigType *dest_type = ir_resolve_type(ira, result_bit_cast->base.source_instruction->child); - if (type_is_invalid(dest_type)) - return ira->codegen->invalid_inst_gen; - - ZigType *dest_cg_ptr_type; - if ((err = get_codegen_ptr_type(ira->codegen, dest_type, &dest_cg_ptr_type))) - return ira->codegen->invalid_inst_gen; - if (dest_cg_ptr_type != nullptr) { - ir_add_error_node(ira, result_loc->source_instruction->source_node, - buf_sprintf("unable to @bitCast to pointer type '%s'", buf_ptr(&dest_type->name))); - return ira->codegen->invalid_inst_gen; - } - - if (!type_can_bit_cast(dest_type)) { - ir_add_error_node(ira, result_loc->source_instruction->source_node, - buf_sprintf("unable to @bitCast to type '%s'", buf_ptr(&dest_type->name))); - return ira->codegen->invalid_inst_gen; - } - - ZigType *value_cg_ptr_type; - if ((err = get_codegen_ptr_type(ira->codegen, value_type, &value_cg_ptr_type))) - return ira->codegen->invalid_inst_gen; - if (value_cg_ptr_type != nullptr) { - ir_add_error_node(ira, suspend_source_instr->source_node, - buf_sprintf("unable to @bitCast from pointer type '%s'", buf_ptr(&value_type->name))); - return ira->codegen->invalid_inst_gen; - } - - if (!type_can_bit_cast(value_type)) { - ir_add_error_node(ira, suspend_source_instr->source_node, - buf_sprintf("unable to @bitCast from type '%s'", buf_ptr(&value_type->name))); - return ira->codegen->invalid_inst_gen; - } - - Stage1AirInst *bitcasted_value; - if (value != nullptr) { - bitcasted_value = ir_analyze_bit_cast(ira, result_loc->source_instruction->scope, - result_loc->source_instruction->source_node, value, dest_type); - dest_type = bitcasted_value->value->type; - } else { - bitcasted_value = nullptr; - } - - if (bitcasted_value != nullptr && type_is_invalid(bitcasted_value->value->type)) { - return bitcasted_value; - } - - bool parent_was_written = result_bit_cast->parent->written; - Stage1AirInst *parent_result_loc = ir_resolve_result(ira, suspend_source_instr, result_bit_cast->parent, - dest_type, bitcasted_value, force_runtime, true); - if (parent_result_loc == nullptr || type_is_invalid(parent_result_loc->value->type) || - parent_result_loc->value->type->id == ZigTypeIdUnreachable) - { - return parent_result_loc; - } - ZigType *parent_ptr_type = parent_result_loc->value->type; - assert(parent_ptr_type->id == ZigTypeIdPointer); - ZigType *child_type = parent_ptr_type->data.pointer.child_type; - - if (result_loc_is_discard(result_bit_cast->parent)) { - assert(allow_discard); - return parent_result_loc; - } - - if ((err = type_resolve(ira->codegen, child_type, ResolveStatusSizeKnown))) { - return ira->codegen->invalid_inst_gen; - } - - if ((err = type_resolve(ira->codegen, value_type, ResolveStatusSizeKnown))) { - return ira->codegen->invalid_inst_gen; - } - - if (child_type != ira->codegen->builtin_types.entry_anytype) { - if (type_size(ira->codegen, child_type) != type_size(ira->codegen, value_type)) { - // pointer cast won't work; we need a temporary location. - result_bit_cast->parent->written = parent_was_written; - result_loc->written = true; - result_loc->resolved_loc = ir_resolve_result(ira, suspend_source_instr, no_result_loc(), - value_type, bitcasted_value, force_runtime, true); - return result_loc->resolved_loc; - } - } - uint64_t parent_ptr_align = 0; - if (type_has_bits(ira->codegen, value_type)) parent_ptr_align = get_ptr_align(ira->codegen, parent_ptr_type); - ZigType *ptr_type = get_pointer_to_type_extra(ira->codegen, value_type, - parent_ptr_type->data.pointer.is_const, parent_ptr_type->data.pointer.is_volatile, PtrLenSingle, - parent_ptr_align, 0, 0, parent_ptr_type->data.pointer.allow_zero); - - result_loc->written = true; - result_loc->resolved_loc = ir_analyze_ptr_cast(ira, suspend_source_instr->scope, - suspend_source_instr->source_node, parent_result_loc, - parent_result_loc->source_node, ptr_type, - result_bit_cast->base.source_instruction->source_node, false, false); - return result_loc->resolved_loc; - } - } - zig_unreachable(); -} - -static Stage1AirInst *ir_resolve_result(IrAnalyze *ira, Stage1ZirInst *suspend_source_instr, - ResultLoc *result_loc_pass1, ZigType *value_type, Stage1AirInst *value, bool force_runtime, - bool allow_discard) -{ - if (!allow_discard && result_loc_is_discard(result_loc_pass1)) { - result_loc_pass1 = no_result_loc(); - } - bool was_written = result_loc_pass1->written; - Stage1AirInst *result_loc = ir_resolve_result_raw(ira, suspend_source_instr, result_loc_pass1, value_type, - value, force_runtime, allow_discard); - if (result_loc == nullptr || result_loc->value->type->id == ZigTypeIdUnreachable || - type_is_invalid(result_loc->value->type)) - { - return result_loc; - } - - if ((force_runtime || (value != nullptr && !instr_is_comptime(value))) && - result_loc_pass1->written && result_loc->value->data.x_ptr.mut == ConstPtrMutInfer) - { - result_loc->value->special = ConstValSpecialRuntime; - } - - InferredStructField *isf = result_loc->value->type->data.pointer.inferred_struct_field; - if (isf != nullptr) { - TypeStructField *field; - Stage1AirInst *casted_ptr; - if (isf->already_resolved) { - field = find_struct_type_field(isf->inferred_struct_type, isf->field_name); - casted_ptr = result_loc; - } else { - isf->already_resolved = true; - // Now it's time to add the field to the struct type. - uint32_t old_field_count = isf->inferred_struct_type->data.structure.src_field_count; - uint32_t new_field_count = old_field_count + 1; - isf->inferred_struct_type->data.structure.src_field_count = new_field_count; - isf->inferred_struct_type->data.structure.fields = realloc_type_struct_fields( - isf->inferred_struct_type->data.structure.fields, old_field_count, new_field_count); - - field = isf->inferred_struct_type->data.structure.fields[old_field_count]; - field->name = isf->field_name; - field->type_entry = value_type; - field->type_val = create_const_type(ira->codegen, field->type_entry); - field->src_index = old_field_count; - field->decl_node = value ? value->source_node : suspend_source_instr->source_node; - if (value && instr_is_comptime(value)) { - ZigValue *val = ir_resolve_const(ira, value, UndefOk); - if (!val) - return ira->codegen->invalid_inst_gen; - field->is_comptime = true; - field->init_val = ira->codegen->pass1_arena->create(); - copy_const_val(ira->codegen, field->init_val, val); - return result_loc; - } - - ZigType *struct_ptr_type = get_pointer_to_type(ira->codegen, isf->inferred_struct_type, false); - if (instr_is_comptime(result_loc)) { - casted_ptr = ir_const(ira, suspend_source_instr->scope, - suspend_source_instr->source_node, struct_ptr_type); - copy_const_val(ira->codegen, casted_ptr->value, result_loc->value); - casted_ptr->value->type = struct_ptr_type; - } else { - casted_ptr = result_loc; - } - if (instr_is_comptime(casted_ptr)) { - ZigValue *ptr_val = ir_resolve_const(ira, casted_ptr, UndefBad); - if (!ptr_val) - return ira->codegen->invalid_inst_gen; - if (ptr_val->data.x_ptr.special != ConstPtrSpecialHardCodedAddr) { - ZigValue *struct_val = const_ptr_pointee(ira, ira->codegen, ptr_val, - suspend_source_instr->source_node); - struct_val->special = ConstValSpecialStatic; - struct_val->data.x_struct.fields = realloc_const_vals_ptrs(ira->codegen, - struct_val->data.x_struct.fields, old_field_count, new_field_count); - - ZigValue *field_val = struct_val->data.x_struct.fields[old_field_count]; - field_val->special = ConstValSpecialUndef; - field_val->type = field->type_entry; - field_val->parent.id = ConstParentIdStruct; - field_val->parent.data.p_struct.struct_val = struct_val; - field_val->parent.data.p_struct.field_index = old_field_count; - } - } - } - - result_loc = ir_analyze_struct_field_ptr(ira, suspend_source_instr->scope, - suspend_source_instr->source_node, field, casted_ptr, - isf->inferred_struct_type, true); - if (type_is_invalid(result_loc->value->type)) { - return result_loc; - } - result_loc_pass1->resolved_loc = result_loc; - } - - if (was_written) { - return result_loc; - } - - src_assert(result_loc->value->type->id == ZigTypeIdPointer, suspend_source_instr->source_node); - ZigType *actual_elem_type = result_loc->value->type->data.pointer.child_type; - if (actual_elem_type->id == ZigTypeIdOptional && value_type->id != ZigTypeIdOptional && - value_type->id != ZigTypeIdNull && value_type->id != ZigTypeIdUndefined) - { - bool same_comptime_repr = types_have_same_zig_comptime_repr(ira->codegen, actual_elem_type, value_type); - if (!same_comptime_repr) { - result_loc_pass1->written = was_written; - return ir_analyze_unwrap_optional_payload(ira, suspend_source_instr->scope, - suspend_source_instr->source_node, result_loc, false, true); - } - } else if (actual_elem_type->id == ZigTypeIdErrorUnion && value_type->id != ZigTypeIdErrorUnion && - value_type->id != ZigTypeIdUndefined) - { - if (value_type->id == ZigTypeIdErrorSet) { - return ir_analyze_unwrap_err_code(ira, suspend_source_instr->scope, - suspend_source_instr->source_node, result_loc, true); - } else { - Stage1AirInst *unwrapped_err_ptr = ir_analyze_unwrap_error_payload(ira, - suspend_source_instr->scope, suspend_source_instr->source_node, - result_loc, false, true); - ZigType *actual_payload_type = actual_elem_type->data.error_union.payload_type; - if (actual_payload_type->id == ZigTypeIdOptional && value_type->id != ZigTypeIdOptional && - value_type->id != ZigTypeIdNull && value_type->id != ZigTypeIdUndefined) - { - return ir_analyze_unwrap_optional_payload(ira, suspend_source_instr->scope, - suspend_source_instr->source_node, unwrapped_err_ptr, false, true); - } else { - return unwrapped_err_ptr; - } - } - } - return result_loc; -} - -static Stage1AirInst *ir_analyze_instruction_resolve_result(IrAnalyze *ira, Stage1ZirInstResolveResult *instruction) { - ZigType *implicit_elem_type; - if (instruction->ty == nullptr) { - if (instruction->result_loc->id == ResultLocIdCast) { - implicit_elem_type = ir_resolve_type(ira, - instruction->result_loc->source_instruction->child); - if (type_is_invalid(implicit_elem_type)) - return ira->codegen->invalid_inst_gen; - } else if (instruction->result_loc->id == ResultLocIdReturn) { - implicit_elem_type = ira->explicit_return_type; - if (type_is_invalid(implicit_elem_type)) - return ira->codegen->invalid_inst_gen; - } else { - implicit_elem_type = ira->codegen->builtin_types.entry_anytype; - } - if (implicit_elem_type == ira->codegen->builtin_types.entry_anytype) { - Buf *bare_name = buf_alloc(); - Buf *name = get_anon_type_name(ira->codegen, nullptr, container_string(ContainerKindStruct), - instruction->base.scope, instruction->base.source_node, bare_name, nullptr); - - StructSpecial struct_special = StructSpecialInferredStruct; - if (instruction->base.source_node->type == NodeTypeContainerInitExpr && - instruction->base.source_node->data.container_init_expr.kind == ContainerInitKindArray) - { - struct_special = StructSpecialInferredTuple; - } - - ZigType *inferred_struct_type = get_partial_container_type(ira->codegen, - instruction->base.scope, ContainerKindStruct, instruction->base.source_node, - buf_ptr(name), bare_name, ContainerLayoutAuto); - inferred_struct_type->data.structure.special = struct_special; - inferred_struct_type->data.structure.resolve_status = ResolveStatusBeingInferred; - implicit_elem_type = inferred_struct_type; - } - } else { - implicit_elem_type = ir_resolve_type(ira, instruction->ty->child); - if (type_is_invalid(implicit_elem_type)) - return ira->codegen->invalid_inst_gen; - } - Stage1AirInst *result_loc = ir_resolve_result(ira, &instruction->base, instruction->result_loc, - implicit_elem_type, nullptr, false, true); - if (result_loc != nullptr) - return result_loc; - - ZigFn *fn = ira->fn; - if (fn != nullptr && fn->type_entry->data.fn.fn_type_id.cc == CallingConventionAsync && - instruction->result_loc->id == ResultLocIdReturn) - { - result_loc = ir_resolve_result(ira, &instruction->base, no_result_loc(), - implicit_elem_type, nullptr, false, true); - if (result_loc != nullptr && - (type_is_invalid(result_loc->value->type) || result_loc->value->type->id == ZigTypeIdUnreachable)) - { - return result_loc; - } - result_loc->value->special = ConstValSpecialRuntime; - return result_loc; - } - - Stage1AirInst *result = ir_const(ira, instruction->base.scope, instruction->base.source_node, implicit_elem_type); - result->value->special = ConstValSpecialUndef; - Stage1AirInst *ptr = ir_get_ref(ira, instruction->base.scope, instruction->base.source_node, result, false, false); - ptr->value->data.x_ptr.mut = ConstPtrMutComptimeVar; - return ptr; -} - -static void ir_reset_result(ResultLoc *result_loc) { - result_loc->written = false; - result_loc->resolved_loc = nullptr; - result_loc->gen_instruction = nullptr; - result_loc->implicit_elem_type = nullptr; - switch (result_loc->id) { - case ResultLocIdInvalid: - zig_unreachable(); - case ResultLocIdPeerParent: { - ResultLocPeerParent *peer_parent = reinterpret_cast(result_loc); - peer_parent->skipped = false; - peer_parent->done_resuming = false; - peer_parent->resolved_type = nullptr; - for (size_t i = 0; i < peer_parent->peers.length; i += 1) { - ir_reset_result(&peer_parent->peers.at(i)->base); - } - break; - } - case ResultLocIdVar: { - Stage1ZirInstAlloca *alloca_src = reinterpret_cast(result_loc->source_instruction); - alloca_src->base.child = nullptr; - break; - } - case ResultLocIdReturn: - reinterpret_cast(result_loc)->implicit_return_type_done = false; - break; - case ResultLocIdPeer: - case ResultLocIdNone: - case ResultLocIdInstruction: - case ResultLocIdBitCast: - case ResultLocIdCast: - break; - } -} - -static Stage1AirInst *ir_analyze_instruction_reset_result(IrAnalyze *ira, Stage1ZirInstResetResult *instruction) { - ir_reset_result(instruction->result_loc); - return ir_const_void(ira, instruction->base.scope, instruction->base.source_node); -} - -static Stage1AirInst *get_async_call_result_loc(IrAnalyze *ira, Scope *scope, AstNode *source_node, - ZigType *fn_ret_type, bool is_async_call_builtin, Stage1AirInst **args_ptr, size_t args_len, - Stage1AirInst *ret_ptr_uncasted) -{ - src_assert(is_async_call_builtin, source_node); - if (type_is_invalid(ret_ptr_uncasted->value->type)) - return ira->codegen->invalid_inst_gen; - if (ret_ptr_uncasted->value->type->id == ZigTypeIdVoid) { - // Result location will be inside the async frame. - return nullptr; - } - return ir_implicit_cast(ira, ret_ptr_uncasted, get_pointer_to_type(ira->codegen, fn_ret_type, false)); -} - -static Stage1AirInst *ir_analyze_async_call(IrAnalyze *ira, Scope *scope, AstNode *source_node, ZigFn *fn_entry, - ZigType *fn_type, Stage1AirInst *fn_ref, Stage1AirInst **casted_args, size_t arg_count, - Stage1AirInst *casted_new_stack, bool is_async_call_builtin, Stage1AirInst *ret_ptr_uncasted, - ResultLoc *call_result_loc) -{ - if (fn_entry == nullptr) { - if (fn_type->data.fn.fn_type_id.cc != CallingConventionAsync) { - ir_add_error(ira, fn_ref, - buf_sprintf("expected async function, found '%s'", buf_ptr(&fn_type->name))); - return ira->codegen->invalid_inst_gen; - } - if (casted_new_stack == nullptr) { - ir_add_error(ira, fn_ref, buf_sprintf("function is not comptime-known; @asyncCall required")); - return ira->codegen->invalid_inst_gen; - } - } - if (casted_new_stack != nullptr) { - ZigType *fn_ret_type = fn_type->data.fn.fn_type_id.return_type; - Stage1AirInst *ret_ptr = get_async_call_result_loc(ira, scope, source_node, fn_ret_type, is_async_call_builtin, - casted_args, arg_count, ret_ptr_uncasted); - if (ret_ptr != nullptr && type_is_invalid(ret_ptr->value->type)) - return ira->codegen->invalid_inst_gen; - - ZigType *anyframe_type = get_any_frame_type(ira->codegen, fn_ret_type); - - Stage1AirInstCall *call_gen = ir_build_call_gen(ira, scope, source_node, fn_entry, fn_ref, - arg_count, casted_args, CallModifierAsync, casted_new_stack, - is_async_call_builtin, ret_ptr, anyframe_type); - return &call_gen->base; - } else { - ZigType *frame_type = get_fn_frame_type(ira->codegen, fn_entry); - Stage1AirInst *result_loc = ir_resolve_result(ira, ira->suspend_source_instr, call_result_loc, - frame_type, nullptr, true, false); - if (type_is_invalid(result_loc->value->type) || result_loc->value->type->id == ZigTypeIdUnreachable) { - return result_loc; - } - result_loc = ir_implicit_cast2(ira, scope, source_node, result_loc, - get_pointer_to_type(ira->codegen, frame_type, false)); - if (type_is_invalid(result_loc->value->type)) - return ira->codegen->invalid_inst_gen; - return &ir_build_call_gen(ira, scope, source_node, fn_entry, fn_ref, arg_count, - casted_args, CallModifierAsync, casted_new_stack, - is_async_call_builtin, result_loc, frame_type)->base; - } -} -static bool ir_analyze_fn_call_inline_arg(IrAnalyze *ira, AstNode *fn_proto_node, - Stage1AirInst *arg, Scope **exec_scope, size_t *next_proto_i) -{ - AstNode *param_decl_node = fn_proto_node->data.fn_proto.params.at(*next_proto_i); - assert(param_decl_node->type == NodeTypeParamDecl); - - Stage1AirInst *casted_arg; - if (param_decl_node->data.param_decl.anytype_token == 0) { - AstNode *param_type_node = param_decl_node->data.param_decl.type; - ZigType *param_type = ir_analyze_type_expr(ira, *exec_scope, param_type_node); - if (type_is_invalid(param_type)) - return false; - - casted_arg = ir_implicit_cast(ira, arg, param_type); - if (type_is_invalid(casted_arg->value->type)) - return false; - } else { - casted_arg = arg; - } - - ZigValue *arg_val = ir_resolve_const(ira, casted_arg, UndefOk); - if (!arg_val) - return false; - - Buf *param_name = param_decl_node->data.param_decl.name; - ZigVar *var = add_variable(ira->codegen, param_decl_node, - *exec_scope, param_name, true, arg_val, nullptr, arg_val->type); - *exec_scope = var->child_scope; - *next_proto_i += 1; - - return true; -} - -static bool ir_analyze_fn_call_generic_arg(IrAnalyze *ira, AstNode *fn_proto_node, - Stage1AirInst *arg, AstNode *arg_src, Scope **child_scope, size_t *next_proto_i, - GenericFnTypeId *generic_id, FnTypeId *fn_type_id, Stage1AirInst **casted_args, - ZigFn *impl_fn) -{ - AstNode *param_decl_node = fn_proto_node->data.fn_proto.params.at(*next_proto_i); - assert(param_decl_node->type == NodeTypeParamDecl); - bool is_var_args = param_decl_node->data.param_decl.is_var_args; - bool arg_part_of_generic_id = false; - Stage1AirInst *casted_arg; - - ZigType *param_info_type = nullptr; - if (is_var_args) { - arg_part_of_generic_id = true; - casted_arg = arg; - param_info_type = arg->value->type; - } else { - if (param_decl_node->data.param_decl.anytype_token == 0) { - AstNode *param_type_node = param_decl_node->data.param_decl.type; - ZigType *param_type = ir_analyze_type_expr(ira, *child_scope, param_type_node); - if (type_is_invalid(param_type)) - return false; - - casted_arg = ir_implicit_cast2(ira, arg->scope, arg_src, arg, param_type); - if (type_is_invalid(casted_arg->value->type)) - return false; - - param_info_type = param_type; - } else { - arg_part_of_generic_id = true; - casted_arg = arg; - param_info_type = arg->value->type; - } - } - - bool comptime_arg = param_decl_node->data.param_decl.is_comptime; - if (!comptime_arg) { - switch (type_requires_comptime(ira->codegen, casted_arg->value->type)) { - case ReqCompTimeInvalid: - return false; - case ReqCompTimeYes: - comptime_arg = true; - break; - case ReqCompTimeNo: - break; - } - } - - ZigValue *arg_val; - - if (comptime_arg && !instr_is_comptime(casted_arg)) { - ir_add_error(ira, casted_arg, - buf_sprintf("runtime value cannot be passed to comptime arg")); - return false; - } - if (comptime_arg) { - arg_part_of_generic_id = true; - arg_val = ir_resolve_const(ira, casted_arg, UndefBad); - if (!arg_val) - return false; - } else { - arg_val = create_const_runtime(ira->codegen, casted_arg->value->type); - } - if (arg_part_of_generic_id) { - copy_const_val(ira->codegen, &generic_id->params[generic_id->param_count], arg_val); - generic_id->param_count += 1; - } - - Buf *param_name = param_decl_node->data.param_decl.name; - if (!param_name) return false; - if (!is_var_args) { - ZigVar *var = add_variable(ira->codegen, param_decl_node, - *child_scope, param_name, true, arg_val, nullptr, arg_val->type); - *child_scope = var->child_scope; - var->shadowable = !comptime_arg; - - *next_proto_i += 1; - } else if (casted_arg->value->type->id == ZigTypeIdComptimeInt || - casted_arg->value->type->id == ZigTypeIdComptimeFloat) - { - ir_add_error(ira, casted_arg, - buf_sprintf("compiler bug: integer and float literals in var args function must be casted. https://github.com/ziglang/zig/issues/557")); - return false; - } - - if (!comptime_arg) { - casted_args[fn_type_id->param_count] = casted_arg; - FnTypeParamInfo *param_info = &fn_type_id->param_info[fn_type_id->param_count]; - param_info->type = param_info_type; - param_info->is_noalias = param_decl_node->data.param_decl.is_noalias; - impl_fn->param_source_nodes[fn_type_id->param_count] = param_decl_node; - fn_type_id->param_count += 1; - } - - return true; -} - -static Stage1AirInst *ir_get_var_ptr(IrAnalyze *ira, Scope *scope, AstNode *source_node, ZigVar *var) { - while (var->next_var != nullptr) { - var = var->next_var; - } - - if (var->var_type == nullptr || type_is_invalid(var->var_type)) - return ira->codegen->invalid_inst_gen; - - bool is_volatile = false; - ZigType *var_ptr_type = get_pointer_to_type_extra(ira->codegen, var->var_type, - var->src_is_const, is_volatile, PtrLenSingle, var->align_bytes, 0, 0, false); - - if (var->ptr_instruction != nullptr) { - return ir_implicit_cast(ira, var->ptr_instruction, var_ptr_type); - } - - bool comptime_var_mem = ir_get_var_is_comptime(var); - bool linkage_makes_it_runtime = var->decl_node->data.variable_declaration.is_extern; - - Stage1AirInst *result = ir_build_var_ptr_gen(ira, scope, source_node, var); - result->value->type = var_ptr_type; - - if (!linkage_makes_it_runtime && !var->is_thread_local && value_is_comptime(var->const_value)) { - ZigValue *val = var->const_value; - switch (val->special) { - case ConstValSpecialRuntime: - break; - case ConstValSpecialStatic: // fallthrough - case ConstValSpecialLazy: // fallthrough - case ConstValSpecialUndef: { - ConstPtrMut ptr_mut; - if (comptime_var_mem) { - ptr_mut = ConstPtrMutComptimeVar; - } else if (var->gen_is_const) { - ptr_mut = ConstPtrMutComptimeConst; - } else { - assert(!comptime_var_mem); - ptr_mut = ConstPtrMutRuntimeVar; - } - result->value->special = ConstValSpecialStatic; - result->value->data.x_ptr.mut = ptr_mut; - result->value->data.x_ptr.special = ConstPtrSpecialRef; - result->value->data.x_ptr.data.ref.pointee = val; - return result; - } - } - } - - bool in_fn_scope = (scope_fn_entry(var->parent_scope) != nullptr); - result->value->data.rh_ptr = in_fn_scope ? RuntimeHintPtrStack : RuntimeHintPtrNonStack; - - return result; -} - -// This function is called when a comptime value becomes accessible at runtime. -static void mark_comptime_value_escape(IrAnalyze *ira, Scope *scope, AstNode *source_node, ZigValue *val) { - src_assert(value_is_comptime(val), source_node); - if (val->special == ConstValSpecialUndef) - return; - - if (val->type->id == ZigTypeIdFn && val->type->data.fn.fn_type_id.cc == CallingConventionUnspecified) { - src_assert(val->data.x_ptr.special == ConstPtrSpecialFunction, source_node); - if (val->data.x_ptr.data.fn.fn_entry->non_async_node == nullptr) { - val->data.x_ptr.data.fn.fn_entry->non_async_node = source_node; - } - } -} - -static Stage1AirInst *ir_analyze_store_ptr(IrAnalyze *ira, Scope *scope, AstNode *source_node, - Stage1AirInst *ptr, Stage1AirInst *uncasted_value, bool allow_write_through_const) -{ - assert(ptr->value->type->id == ZigTypeIdPointer); - - if (ptr->value->data.x_ptr.special == ConstPtrSpecialDiscard) { - if (uncasted_value->value->type->id == ZigTypeIdErrorUnion || - uncasted_value->value->type->id == ZigTypeIdErrorSet) - { - ir_add_error_node(ira, source_node, buf_sprintf("error is discarded. consider using `try`, `catch`, or `if`")); - return ira->codegen->invalid_inst_gen; - } - return ir_const_void(ira, scope, source_node); - } - - if (ptr->value->type->data.pointer.is_const && !allow_write_through_const) { - ir_add_error_node(ira, source_node, buf_sprintf("cannot assign to constant")); - return ira->codegen->invalid_inst_gen; - } - - ZigType *child_type = ptr->value->type->data.pointer.child_type; - Stage1AirInst *value = ir_implicit_cast(ira, uncasted_value, child_type); - if (type_is_invalid(value->value->type)) - return ira->codegen->invalid_inst_gen; - - switch (type_has_one_possible_value(ira->codegen, child_type)) { - case OnePossibleValueInvalid: - return ira->codegen->invalid_inst_gen; - case OnePossibleValueYes: - return ir_const_void(ira, scope, source_node); - case OnePossibleValueNo: - break; - } - - if (instr_is_comptime(ptr) && ptr->value->data.x_ptr.special != ConstPtrSpecialHardCodedAddr) { - if (!allow_write_through_const && ptr->value->data.x_ptr.mut == ConstPtrMutComptimeConst) { - ir_add_error_node(ira, source_node, buf_sprintf("cannot assign to constant")); - return ira->codegen->invalid_inst_gen; - } - if ((allow_write_through_const && ptr->value->data.x_ptr.mut == ConstPtrMutComptimeConst) || - ptr->value->data.x_ptr.mut == ConstPtrMutComptimeVar || - ptr->value->data.x_ptr.mut == ConstPtrMutInfer) - { - if (instr_is_comptime(value)) { - ZigValue *dest_val = const_ptr_pointee(ira, ira->codegen, ptr->value, source_node); - if (dest_val == nullptr) - return ira->codegen->invalid_inst_gen; - if (dest_val->special != ConstValSpecialRuntime) { - copy_const_val(ira->codegen, dest_val, value->value); - - if (ptr->value->data.x_ptr.mut == ConstPtrMutComptimeVar && - ira->new_irb.current_basic_block->must_be_comptime_source_node == nullptr) - { - ira->new_irb.current_basic_block->must_be_comptime_source_node = source_node; - } - return ir_const_void(ira, scope, source_node); - } - } - if (ptr->value->data.x_ptr.mut == ConstPtrMutInfer) { - ptr->value->special = ConstValSpecialRuntime; - } else { - ir_add_error_node(ira, source_node, - buf_sprintf("cannot store runtime value in compile time variable")); - ZigValue *dest_val = const_ptr_pointee_unchecked(ira->codegen, ptr->value); - dest_val->type = ira->codegen->builtin_types.entry_invalid; - - return ira->codegen->invalid_inst_gen; - } - } - } - - if (ptr->value->type->data.pointer.inferred_struct_field != nullptr && - child_type == ira->codegen->builtin_types.entry_anytype) - { - child_type = ptr->value->type->data.pointer.inferred_struct_field->inferred_struct_type; - } - - switch (type_requires_comptime(ira->codegen, child_type)) { - case ReqCompTimeInvalid: - return ira->codegen->invalid_inst_gen; - case ReqCompTimeYes: - switch (type_has_one_possible_value(ira->codegen, ptr->value->type)) { - case OnePossibleValueInvalid: - return ira->codegen->invalid_inst_gen; - case OnePossibleValueNo: - ir_add_error_node(ira, source_node, - buf_sprintf("cannot store runtime value in type '%s'", buf_ptr(&child_type->name))); - return ira->codegen->invalid_inst_gen; - case OnePossibleValueYes: - return ir_const_void(ira, scope, source_node); - } - zig_unreachable(); - case ReqCompTimeNo: - break; - } - - if (instr_is_comptime(value)) { - mark_comptime_value_escape(ira, scope, source_node, value->value); - } - - // If this is a store to a pointer with a runtime-known vector index, - // we have to figure out the Stage1AirInst which represents the index and - // emit a Stage1AirInstVectorStoreElem, or emit a compile error - // explaining why it is impossible for this store to work. Which is that - // the pointer address is of the vector; without the element index being known - // we cannot properly perform the insertion. - if (ptr->value->type->data.pointer.vector_index == VECTOR_INDEX_RUNTIME) { - if (ptr->id == Stage1AirInstIdElemPtr) { - Stage1AirInstElemPtr *elem_ptr = (Stage1AirInstElemPtr *)ptr; - return ir_build_vector_store_elem(ira, scope, source_node, elem_ptr->array_ptr, - elem_ptr->elem_index, value); - } - ir_add_error(ira, ptr, - buf_sprintf("unable to determine vector element index of type '%s'", - buf_ptr(&ptr->value->type->name))); - return ira->codegen->invalid_inst_gen; - } - - return ir_build_store_ptr_gen(ira, scope, source_node, ptr, value); -} - -static Stage1AirInst *analyze_casted_new_stack(IrAnalyze *ira, Scope *scope, AstNode *source_node, - Stage1AirInst *new_stack, AstNode *new_stack_src, bool is_async_call_builtin, ZigFn *fn_entry) -{ - if (new_stack == nullptr) - return nullptr; - - if (!is_async_call_builtin && - arch_stack_pointer_register_name(ira->codegen->zig_target->arch) == nullptr) - { - ir_add_error_node(ira, source_node, - buf_sprintf("target arch '%s' does not support calling with a new stack", - target_arch_name(ira->codegen->zig_target->arch))); - } - - if (is_async_call_builtin && - fn_entry != nullptr && new_stack->value->type->id == ZigTypeIdPointer && - new_stack->value->type->data.pointer.child_type->id == ZigTypeIdFnFrame) - { - ZigType *needed_frame_type = get_pointer_to_type(ira->codegen, - get_fn_frame_type(ira->codegen, fn_entry), false); - return ir_implicit_cast(ira, new_stack, needed_frame_type); - } else { - // XXX The stack alignment is hardcoded to 16 here and in - // std.Target.stack_align. - const uint32_t required_align = is_async_call_builtin ? - get_async_frame_align_bytes(ira->codegen) : 16; - ZigType *u8_ptr = get_pointer_to_type_extra(ira->codegen, ira->codegen->builtin_types.entry_u8, - false, false, PtrLenUnknown, required_align, 0, 0, false); - ZigType *u8_slice = get_slice_type(ira->codegen, u8_ptr); - ira->codegen->need_frame_size_prefix_data = true; - return ir_implicit_cast2(ira, new_stack->scope, new_stack_src, new_stack, u8_slice); - } -} - -static Stage1AirInst *ir_analyze_fn_call(IrAnalyze *ira, Scope *scope, AstNode *source_node, - ZigFn *fn_entry, ZigType *fn_type, Stage1AirInst *fn_ref, - Stage1AirInst *first_arg_ptr, AstNode *first_arg_ptr_src, CallModifier modifier, - Stage1AirInst *new_stack, AstNode *new_stack_src, bool is_async_call_builtin, - Stage1AirInst **args_ptr, size_t args_len, Stage1AirInst *ret_ptr, ResultLoc *call_result_loc) -{ - Error err; - FnTypeId *fn_type_id = &fn_type->data.fn.fn_type_id; - size_t first_arg_1_or_0 = first_arg_ptr ? 1 : 0; - - // for extern functions, the var args argument is not counted. - // for zig functions, it is. - size_t var_args_1_or_0; - if (fn_type_id->cc == CallingConventionC) { - var_args_1_or_0 = 0; - } else { - var_args_1_or_0 = fn_type_id->is_var_args ? 1 : 0; - } - size_t src_param_count = fn_type_id->param_count - var_args_1_or_0; - size_t call_param_count = args_len + first_arg_1_or_0; - - AstNode *fn_proto_node = fn_entry ? fn_entry->proto_node : nullptr;; - - if (fn_type_id->cc == CallingConventionNaked) { - ErrorMsg *msg = ir_add_error(ira, fn_ref, buf_sprintf("unable to call function with naked calling convention")); - if (fn_proto_node) { - add_error_note(ira->codegen, msg, fn_proto_node, buf_sprintf("declared here")); - } - return ira->codegen->invalid_inst_gen; - } - - if (fn_type_id->is_var_args) { - if (call_param_count < src_param_count) { - ErrorMsg *msg = ir_add_error_node(ira, source_node, - buf_sprintf("expected at least %" ZIG_PRI_usize " argument(s), found %" ZIG_PRI_usize "", - src_param_count, call_param_count)); - if (fn_proto_node) { - add_error_note(ira->codegen, msg, fn_proto_node, - buf_sprintf("declared here")); - } - return ira->codegen->invalid_inst_gen; - } - } else if (src_param_count != call_param_count) { - ErrorMsg *msg = ir_add_error_node(ira, source_node, - buf_sprintf("expected %" ZIG_PRI_usize " argument(s), found %" ZIG_PRI_usize "", - src_param_count, call_param_count)); - if (fn_proto_node) { - add_error_note(ira->codegen, msg, fn_proto_node, - buf_sprintf("declared here")); - } - return ira->codegen->invalid_inst_gen; - } - - if (modifier == CallModifierCompileTime) { - // If we are evaluating an extern function in a TypeOf call, we can return an undefined value - // of its return type. - if (fn_entry != nullptr && get_scope_typeof(scope) != nullptr && - fn_proto_node->data.fn_proto.is_extern) { - - assert(fn_entry->body_node == nullptr); - AstNode *return_type_node = fn_proto_node->data.fn_proto.return_type; - ZigType *return_type = ir_analyze_type_expr(ira, scope, return_type_node); - if (type_is_invalid(return_type)) - return ira->codegen->invalid_inst_gen; - - return ir_const_undef(ira, scope, source_node, return_type); - } - - // No special handling is needed for compile time evaluation of generic functions. - if (!fn_entry || fn_entry->body_node == nullptr) { - ir_add_error(ira, fn_ref, buf_sprintf("unable to evaluate constant expression")); - return ira->codegen->invalid_inst_gen; - } - - if (!ir_emit_backward_branch(ira, source_node)) - return ira->codegen->invalid_inst_gen; - - // Fork a scope of the function with known values for the parameters. - Scope *exec_scope = &fn_entry->fndef_scope->base; - - size_t next_proto_i = 0; - if (first_arg_ptr) { - assert(first_arg_ptr->value->type->id == ZigTypeIdPointer); - - bool first_arg_known_bare = false; - if (fn_type_id->next_param_index >= 1) { - ZigType *param_type = fn_type_id->param_info[next_proto_i].type; - if (type_is_invalid(param_type)) - return ira->codegen->invalid_inst_gen; - first_arg_known_bare = param_type->id != ZigTypeIdPointer; - } - - Stage1AirInst *first_arg; - if (!first_arg_known_bare) { - first_arg = first_arg_ptr; - } else { - first_arg = ir_get_deref(ira, first_arg_ptr->scope, first_arg_ptr->source_node, first_arg_ptr, nullptr); - if (type_is_invalid(first_arg->value->type)) - return ira->codegen->invalid_inst_gen; - } - - if (!ir_analyze_fn_call_inline_arg(ira, fn_proto_node, first_arg, &exec_scope, &next_proto_i)) - return ira->codegen->invalid_inst_gen; - } - - for (size_t call_i = 0; call_i < args_len; call_i += 1) { - Stage1AirInst *old_arg = args_ptr[call_i]; - - if (!ir_analyze_fn_call_inline_arg(ira, fn_proto_node, old_arg, &exec_scope, &next_proto_i)) - return ira->codegen->invalid_inst_gen; - } - - AstNode *return_type_node = fn_proto_node->data.fn_proto.return_type; - if (return_type_node == nullptr) { - ir_add_error(ira, fn_ref, - buf_sprintf("TODO implement inferred return types https://github.com/ziglang/zig/issues/447")); - return ira->codegen->invalid_inst_gen; - } - ZigType *specified_return_type = ir_analyze_type_expr(ira, exec_scope, return_type_node); - if (type_is_invalid(specified_return_type)) - return ira->codegen->invalid_inst_gen; - ZigType *return_type; - ZigType *inferred_err_set_type = nullptr; - if (fn_proto_node->data.fn_proto.auto_err_set) { - inferred_err_set_type = get_auto_err_set_type(ira->codegen, fn_entry); - if ((err = type_resolve(ira->codegen, specified_return_type, ResolveStatusSizeKnown))) - return ira->codegen->invalid_inst_gen; - return_type = get_error_union_type(ira->codegen, inferred_err_set_type, specified_return_type); - } else { - return_type = specified_return_type; - } - - bool cacheable = fn_eval_cacheable(exec_scope, return_type); - ZigValue *result = nullptr; - if (cacheable) { - // We are about to put ZigValues into a hash map. The hash of a lazy value and a - // fully resolved value must equal, and so we must resolve the lazy values here. - // The hash function asserts that none of the values are lazy. - { - Scope *scope = exec_scope; - while (scope) { - if (scope->id == ScopeIdVarDecl) { - ScopeVarDecl *var_scope = (ScopeVarDecl *)scope; - if ((err = ir_resolve_lazy_recurse( - var_scope->var->decl_node, - var_scope->var->const_value))) - { - return ira->codegen->invalid_inst_gen; - } - } else if (scope->id == ScopeIdFnDef) { - break; - } else { - zig_unreachable(); - } - scope = scope->parent; - } - } - - auto entry = ira->codegen->memoized_fn_eval_table.maybe_get(exec_scope); - if (entry) - result = entry->value; - } - - if (result == nullptr) { - // Analyze the fn body block like any other constant expression. - AstNode *body_node = fn_entry->body_node; - ZigValue *result_ptr; - create_result_ptr(ira->codegen, return_type, &result, &result_ptr); - - if ((err = ir_eval_const_value(ira->codegen, exec_scope, body_node, result_ptr, - ira->backward_branch_count, ira->backward_branch_quota, - fn_entry, nullptr, source_node, nullptr, ira->new_irb.exec, return_type_node, - UndefOk))) - { - return ira->codegen->invalid_inst_gen; - } - - if (inferred_err_set_type != nullptr) { - inferred_err_set_type->data.error_set.incomplete = false; - if (result->type->id == ZigTypeIdErrorUnion) { - ErrorTableEntry *err = result->data.x_err_union.error_set->data.x_err_set; - if (err != nullptr) { - inferred_err_set_type->data.error_set.err_count = 1; - inferred_err_set_type->data.error_set.errors = heap::c_allocator.create(); - inferred_err_set_type->data.error_set.errors[0] = err; - } - ZigType *fn_inferred_err_set_type = result->type->data.error_union.err_set_type; - inferred_err_set_type->data.error_set.err_count = fn_inferred_err_set_type->data.error_set.err_count; - inferred_err_set_type->data.error_set.errors = fn_inferred_err_set_type->data.error_set.errors; - } else if (result->type->id == ZigTypeIdErrorSet) { - inferred_err_set_type->data.error_set.err_count = result->type->data.error_set.err_count; - inferred_err_set_type->data.error_set.errors = result->type->data.error_set.errors; - } - } - - if (cacheable) { - ira->codegen->memoized_fn_eval_table.put(exec_scope, result); - } - - if (type_is_invalid(result->type)) { - return ira->codegen->invalid_inst_gen; - } - } - - Stage1AirInst *new_instruction = ir_const_move(ira, scope, source_node, result); - return ir_finish_anal(ira, new_instruction); - } - - if (fn_type->data.fn.is_generic) { - if (!fn_entry) { - ir_add_error(ira, fn_ref, - buf_sprintf("calling a generic function requires compile-time known function value")); - return ira->codegen->invalid_inst_gen; - } - - size_t new_fn_arg_count = first_arg_1_or_0 + args_len; - - Stage1AirInst **casted_args = heap::c_allocator.allocate(new_fn_arg_count); - - // Fork a scope of the function with known values for the parameters. - Scope *parent_scope = fn_entry->fndef_scope->base.parent; - ZigFn *impl_fn = create_fn(ira->codegen, fn_proto_node); - impl_fn->param_source_nodes = heap::c_allocator.allocate(new_fn_arg_count); - buf_init_from_buf(&impl_fn->symbol_name, &fn_entry->symbol_name); - impl_fn->fndef_scope = create_fndef_scope(ira->codegen, impl_fn->body_node, parent_scope, impl_fn); - impl_fn->child_scope = &impl_fn->fndef_scope->base; - FnTypeId inst_fn_type_id = {0}; - init_fn_type_id(&inst_fn_type_id, fn_proto_node, fn_type_id->cc, new_fn_arg_count); - inst_fn_type_id.param_count = 0; - inst_fn_type_id.is_var_args = false; - - // TODO maybe GenericFnTypeId can be replaced with using the child_scope directly - // as the key in generic_table - GenericFnTypeId *generic_id = heap::c_allocator.create(); - generic_id->fn_entry = fn_entry; - generic_id->param_count = 0; - generic_id->params = ira->codegen->pass1_arena->allocate(new_fn_arg_count); - size_t next_proto_i = 0; - - if (first_arg_ptr) { - assert(first_arg_ptr->value->type->id == ZigTypeIdPointer); - - bool first_arg_known_bare = false; - if (fn_type_id->next_param_index >= 1) { - ZigType *param_type = fn_type_id->param_info[next_proto_i].type; - if (type_is_invalid(param_type)) - return ira->codegen->invalid_inst_gen; - first_arg_known_bare = param_type->id != ZigTypeIdPointer; - } - - Stage1AirInst *first_arg; - if (!first_arg_known_bare) { - first_arg = first_arg_ptr; - } else { - first_arg = ir_get_deref(ira, first_arg_ptr->scope, first_arg_ptr->source_node, - first_arg_ptr, nullptr); - if (type_is_invalid(first_arg->value->type)) - return ira->codegen->invalid_inst_gen; - } - - if (!ir_analyze_fn_call_generic_arg(ira, fn_proto_node, first_arg, first_arg_ptr_src, - &impl_fn->child_scope, &next_proto_i, generic_id, &inst_fn_type_id, casted_args, impl_fn)) - { - return ira->codegen->invalid_inst_gen; - } - } - - ZigFn *parent_fn_entry = ira->fn; - assert(parent_fn_entry); - for (size_t call_i = 0; call_i < args_len; call_i += 1) { - Stage1AirInst *arg = args_ptr[call_i]; - - AstNode *param_decl_node = fn_proto_node->data.fn_proto.params.at(next_proto_i); - assert(param_decl_node->type == NodeTypeParamDecl); - - if (!ir_analyze_fn_call_generic_arg(ira, fn_proto_node, arg, arg->source_node, - &impl_fn->child_scope, - &next_proto_i, generic_id, &inst_fn_type_id, casted_args, impl_fn)) - { - return ira->codegen->invalid_inst_gen; - } - } - - if (fn_proto_node->data.fn_proto.align_expr != nullptr) { - ZigValue *align_result; - ZigValue *result_ptr; - create_result_ptr(ira->codegen, get_align_amt_type(ira->codegen), &align_result, &result_ptr); - if ((err = ir_eval_const_value(ira->codegen, impl_fn->child_scope, - fn_proto_node->data.fn_proto.align_expr, result_ptr, - ira->backward_branch_count, ira->backward_branch_quota, - nullptr, nullptr, fn_proto_node->data.fn_proto.align_expr, nullptr, ira->new_irb.exec, - nullptr, UndefBad))) - { - return ira->codegen->invalid_inst_gen; - } - Stage1AirInstConst *const_instruction = ir_create_inst_noval(&ira->new_irb, - impl_fn->child_scope, fn_proto_node->data.fn_proto.align_expr); - const_instruction->base.value = align_result; - - uint32_t align_bytes = 0; - ir_resolve_align(ira, &const_instruction->base, nullptr, &align_bytes); - impl_fn->align_bytes = align_bytes; - inst_fn_type_id.alignment = align_bytes; - } - - AstNode *return_type_node = fn_proto_node->data.fn_proto.return_type; - ZigType *specified_return_type = ir_analyze_type_expr(ira, impl_fn->child_scope, return_type_node); - if (type_is_invalid(specified_return_type)) - return ira->codegen->invalid_inst_gen; - - if(!is_valid_return_type(specified_return_type)){ - ErrorMsg *msg = ir_add_error_node(ira, source_node, - buf_sprintf("call to generic function with %s return type '%s' not allowed", type_id_name(specified_return_type->id), buf_ptr(&specified_return_type->name))); - add_error_note(ira->codegen, msg, fn_proto_node, buf_sprintf("function declared here")); - - Tld *tld = find_decl(ira->codegen, &fn_entry->fndef_scope->base, &specified_return_type->name); - if (tld != nullptr) { - add_error_note(ira->codegen, msg, tld->source_node, buf_sprintf("type declared here")); - } - return ira->codegen->invalid_inst_gen; - } - - if (fn_proto_node->data.fn_proto.auto_err_set) { - ZigType *inferred_err_set_type = get_auto_err_set_type(ira->codegen, impl_fn); - if ((err = type_resolve(ira->codegen, specified_return_type, ResolveStatusSizeKnown))) - return ira->codegen->invalid_inst_gen; - inst_fn_type_id.return_type = get_error_union_type(ira->codegen, inferred_err_set_type, specified_return_type); - } else { - inst_fn_type_id.return_type = specified_return_type; - } - - switch (type_requires_comptime(ira->codegen, specified_return_type)) { - case ReqCompTimeYes: - // Throw out our work and call the function as if it were comptime. - return ir_analyze_fn_call(ira, scope, source_node, fn_entry, fn_type, fn_ref, first_arg_ptr, - first_arg_ptr_src, CallModifierCompileTime, new_stack, new_stack_src, is_async_call_builtin, - args_ptr, args_len, ret_ptr, call_result_loc); - case ReqCompTimeInvalid: - return ira->codegen->invalid_inst_gen; - case ReqCompTimeNo: - break; - } - - // We are about to put ZigValues into a hash map. The hash of a lazy value and a - // fully resolved value must equal, and so we must resolve the lazy values here. - // The hash function asserts that none of the values are lazy. - for (size_t i = 0; i < generic_id->param_count; i += 1) { - ZigValue *generic_param = &generic_id->params[i]; - if (generic_param->special != ConstValSpecialRuntime) { - if ((err = ir_resolve_lazy_recurse(source_node, generic_param))) { - return ira->codegen->invalid_inst_gen; - } - } - } - - auto existing_entry = ira->codegen->generic_table.put_unique(generic_id, impl_fn); - if (existing_entry) { - // throw away all our work and use the existing function - impl_fn = existing_entry->value; - } else { - // finish instantiating the function - impl_fn->type_entry = get_fn_type(ira->codegen, &inst_fn_type_id); - if (type_is_invalid(impl_fn->type_entry)) - return ira->codegen->invalid_inst_gen; - - impl_fn->analyzed_executable.source_node = source_node; - impl_fn->analyzed_executable.parent_exec = ira->new_irb.exec; - impl_fn->branch_quota = *ira->backward_branch_quota; - - ira->codegen->fn_defs.append(impl_fn); - } - - FnTypeId *impl_fn_type_id = &impl_fn->type_entry->data.fn.fn_type_id; - - if (fn_type_can_fail(impl_fn_type_id)) { - parent_fn_entry->calls_or_awaits_errorable_fn = true; - } - - Stage1AirInst *casted_new_stack = analyze_casted_new_stack(ira, scope, source_node, new_stack, - new_stack_src, is_async_call_builtin, impl_fn); - if (casted_new_stack != nullptr && type_is_invalid(casted_new_stack->value->type)) - return ira->codegen->invalid_inst_gen; - - size_t impl_param_count = impl_fn_type_id->param_count; - if (modifier == CallModifierAsync) { - Stage1AirInst *result = ir_analyze_async_call(ira, scope, source_node, impl_fn, impl_fn->type_entry, - nullptr, casted_args, impl_param_count, casted_new_stack, is_async_call_builtin, ret_ptr, - call_result_loc); - return ir_finish_anal(ira, result); - } - - Stage1AirInst *result_loc; - if (handle_is_ptr(ira->codegen, impl_fn_type_id->return_type)) { - result_loc = ir_resolve_result(ira, ira->suspend_source_instr, call_result_loc, - impl_fn_type_id->return_type, nullptr, true, false); - if (result_loc != nullptr) { - if (type_is_invalid(result_loc->value->type) || result_loc->value->type->id == ZigTypeIdUnreachable) { - return result_loc; - } - if (result_loc->value->type->data.pointer.is_const) { - ir_add_error_node(ira, source_node, buf_sprintf("cannot assign to constant")); - return ira->codegen->invalid_inst_gen; - } - - Stage1AirInst *dummy_value = ir_const(ira, scope, source_node, impl_fn_type_id->return_type); - dummy_value->value->special = ConstValSpecialRuntime; - Stage1AirInst *dummy_result = ir_implicit_cast2(ira, scope, source_node, - dummy_value, result_loc->value->type->data.pointer.child_type); - if (type_is_invalid(dummy_result->value->type)) - return ira->codegen->invalid_inst_gen; - ZigType *res_child_type = result_loc->value->type->data.pointer.child_type; - if (res_child_type == ira->codegen->builtin_types.entry_anytype) { - res_child_type = impl_fn_type_id->return_type; - } - if (!handle_is_ptr(ira->codegen, res_child_type)) { - ir_reset_result(call_result_loc); - result_loc = nullptr; - } - } - } else if (is_async_call_builtin) { - result_loc = get_async_call_result_loc(ira, scope, source_node, impl_fn_type_id->return_type, - is_async_call_builtin, args_ptr, args_len, ret_ptr); - if (result_loc != nullptr && type_is_invalid(result_loc->value->type)) - return ira->codegen->invalid_inst_gen; - } else { - result_loc = nullptr; - } - - if (impl_fn_type_id->cc == CallingConventionAsync && - parent_fn_entry->inferred_async_node == nullptr && - modifier != CallModifierNoSuspend) - { - parent_fn_entry->inferred_async_node = fn_ref->source_node; - parent_fn_entry->inferred_async_fn = impl_fn; - } - - Stage1AirInstCall *new_call_instruction = ir_build_call_gen(ira, scope, source_node, - impl_fn, nullptr, impl_param_count, casted_args, modifier, casted_new_stack, - is_async_call_builtin, result_loc, impl_fn_type_id->return_type); - - if (get_scope_typeof(scope) == nullptr) { - parent_fn_entry->call_list.append(new_call_instruction); - } - - return ir_finish_anal(ira, &new_call_instruction->base); - } - - ZigFn *parent_fn_entry = ira->fn; - assert(fn_type_id->return_type != nullptr); - assert(parent_fn_entry != nullptr); - if (fn_type_can_fail(fn_type_id)) { - parent_fn_entry->calls_or_awaits_errorable_fn = true; - } - - - Stage1AirInst **casted_args = heap::c_allocator.allocate(call_param_count); - size_t next_arg_index = 0; - if (first_arg_ptr) { - assert(first_arg_ptr->value->type->id == ZigTypeIdPointer); - - ZigType *param_type = fn_type_id->param_info[next_arg_index].type; - if (type_is_invalid(param_type)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *first_arg; - if (param_type->id == ZigTypeIdPointer) { - first_arg = first_arg_ptr; - } else { - first_arg = ir_get_deref(ira, first_arg_ptr->scope, first_arg_ptr->source_node, - first_arg_ptr, nullptr); - if (type_is_invalid(first_arg->value->type)) - return ira->codegen->invalid_inst_gen; - } - - Stage1AirInst *casted_arg = ir_implicit_cast2(ira, first_arg->scope, first_arg_ptr_src, first_arg, param_type); - if (type_is_invalid(casted_arg->value->type)) - return ira->codegen->invalid_inst_gen; - - casted_args[next_arg_index] = casted_arg; - next_arg_index += 1; - } - for (size_t call_i = 0; call_i < args_len; call_i += 1) { - Stage1AirInst *old_arg = args_ptr[call_i]; - if (type_is_invalid(old_arg->value->type)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *casted_arg; - if (next_arg_index < src_param_count) { - ZigType *param_type = fn_type_id->param_info[next_arg_index].type; - if (type_is_invalid(param_type)) - return ira->codegen->invalid_inst_gen; - casted_arg = ir_implicit_cast(ira, old_arg, param_type); - if (type_is_invalid(casted_arg->value->type)) - return ira->codegen->invalid_inst_gen; - } else { - casted_arg = old_arg; - } - - casted_args[next_arg_index] = casted_arg; - next_arg_index += 1; - } - - assert(next_arg_index == call_param_count); - - ZigType *return_type = fn_type_id->return_type; - if (type_is_invalid(return_type)) - return ira->codegen->invalid_inst_gen; - - if (fn_entry != nullptr && fn_type_id->cc == CallingConventionInline && modifier == CallModifierNeverInline) { - ir_add_error_node(ira, source_node, - buf_sprintf("no-inline call of inline function")); - return ira->codegen->invalid_inst_gen; - } - - Stage1AirInst *casted_new_stack = analyze_casted_new_stack(ira, scope, source_node, new_stack, new_stack_src, - is_async_call_builtin, fn_entry); - if (casted_new_stack != nullptr && type_is_invalid(casted_new_stack->value->type)) - return ira->codegen->invalid_inst_gen; - - if (modifier == CallModifierAsync) { - Stage1AirInst *result = ir_analyze_async_call(ira, scope, source_node, fn_entry, fn_type, fn_ref, - casted_args, call_param_count, casted_new_stack, is_async_call_builtin, ret_ptr, call_result_loc); - return ir_finish_anal(ira, result); - } - - if (fn_type_id->cc == CallingConventionAsync && - parent_fn_entry->inferred_async_node == nullptr && - modifier != CallModifierNoSuspend) - { - parent_fn_entry->inferred_async_node = fn_ref->source_node; - parent_fn_entry->inferred_async_fn = fn_entry; - } - - Stage1AirInst *result_loc; - if (handle_is_ptr(ira->codegen, return_type)) { - result_loc = ir_resolve_result(ira, ira->suspend_source_instr, call_result_loc, - return_type, nullptr, true, false); - if (result_loc != nullptr) { - if (type_is_invalid(result_loc->value->type) || result_loc->value->type->id == ZigTypeIdUnreachable) { - return result_loc; - } - if (result_loc->value->type->data.pointer.is_const) { - ir_add_error_node(ira, source_node, buf_sprintf("cannot assign to constant")); - return ira->codegen->invalid_inst_gen; - } - - ZigType *expected_return_type = result_loc->value->type->data.pointer.child_type; - - Stage1AirInst *dummy_value = ir_const(ira, scope, source_node, return_type); - dummy_value->value->special = ConstValSpecialRuntime; - Stage1AirInst *dummy_result = ir_implicit_cast2(ira, scope, source_node, - dummy_value, expected_return_type); - if (type_is_invalid(dummy_result->value->type)) { - if ((return_type->id == ZigTypeIdErrorUnion || return_type->id == ZigTypeIdErrorSet) && - expected_return_type->id != ZigTypeIdErrorUnion && expected_return_type->id != ZigTypeIdErrorSet) - { - if (call_result_loc->id == ResultLocIdReturn) { - add_error_note(ira->codegen, ira->new_irb.exec->first_err_trace_msg, - ira->explicit_return_type_source_node, buf_sprintf("function cannot return an error")); - } else { - add_error_note(ira->codegen, ira->new_irb.exec->first_err_trace_msg, result_loc->source_node, - buf_sprintf("cannot store an error in type '%s'", buf_ptr(&expected_return_type->name))); - } - } - return ira->codegen->invalid_inst_gen; - } - if (expected_return_type == ira->codegen->builtin_types.entry_anytype) { - expected_return_type = return_type; - } - if (!handle_is_ptr(ira->codegen, expected_return_type)) { - ir_reset_result(call_result_loc); - result_loc = nullptr; - } - } - } else if (is_async_call_builtin) { - result_loc = get_async_call_result_loc(ira, scope, source_node, return_type, is_async_call_builtin, - args_ptr, args_len, ret_ptr); - if (result_loc != nullptr && type_is_invalid(result_loc->value->type)) - return ira->codegen->invalid_inst_gen; - } else { - result_loc = nullptr; - } - - Stage1AirInstCall *new_call_instruction = ir_build_call_gen(ira, scope, source_node, fn_entry, fn_ref, - call_param_count, casted_args, modifier, casted_new_stack, - is_async_call_builtin, result_loc, return_type); - if (get_scope_typeof(scope) == nullptr) { - parent_fn_entry->call_list.append(new_call_instruction); - } - return ir_finish_anal(ira, &new_call_instruction->base); -} - -static Stage1AirInst *ir_analyze_fn_call_src(IrAnalyze *ira, Stage1ZirInstCall *call_instruction, - ZigFn *fn_entry, ZigType *fn_type, Stage1AirInst *fn_ref, - Stage1AirInst *first_arg_ptr, AstNode *first_arg_ptr_src, CallModifier modifier) -{ - Stage1AirInst *new_stack = nullptr; - AstNode *new_stack_src = nullptr; - if (call_instruction->new_stack) { - new_stack = call_instruction->new_stack->child; - if (type_is_invalid(new_stack->value->type)) - return ira->codegen->invalid_inst_gen; - new_stack_src = call_instruction->new_stack->source_node; - } - Stage1AirInst **args_ptr = heap::c_allocator.allocate(call_instruction->arg_count); - for (size_t i = 0; i < call_instruction->arg_count; i += 1) { - args_ptr[i] = call_instruction->args[i]->child; - if (type_is_invalid(args_ptr[i]->value->type)) - return ira->codegen->invalid_inst_gen; - } - Stage1AirInst *ret_ptr = nullptr; - if (call_instruction->ret_ptr != nullptr) { - ret_ptr = call_instruction->ret_ptr->child; - if (type_is_invalid(ret_ptr->value->type)) - return ira->codegen->invalid_inst_gen; - } - Stage1AirInst *result = ir_analyze_fn_call(ira, call_instruction->base.scope, - call_instruction->base.source_node, fn_entry, fn_type, fn_ref, - first_arg_ptr, first_arg_ptr_src, modifier, new_stack, new_stack_src, - call_instruction->is_async_call_builtin, args_ptr, call_instruction->arg_count, ret_ptr, - call_instruction->result_loc); - heap::c_allocator.deallocate(args_ptr, call_instruction->arg_count); - return result; -} - -static Stage1AirInst *ir_analyze_call_extra(IrAnalyze *ira, Scope *scope, AstNode *source_node, - Stage1ZirInst *pass1_options, Stage1ZirInst *pass1_fn_ref, Stage1AirInst **args_ptr, size_t args_len, - ResultLoc *result_loc) -{ - Stage1AirInst *options = pass1_options->child; - if (type_is_invalid(options->value->type)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *fn_ref = pass1_fn_ref->child; - if (type_is_invalid(fn_ref->value->type)) - return ira->codegen->invalid_inst_gen; - - TypeStructField *modifier_field = find_struct_type_field(options->value->type, buf_create_from_str("modifier")); - src_assert(modifier_field != nullptr, source_node); - Stage1AirInst *modifier_inst = ir_analyze_struct_value_field_value(ira, scope, source_node, options, modifier_field); - ZigValue *modifier_val = ir_resolve_const(ira, modifier_inst, UndefBad); - if (modifier_val == nullptr) - return ira->codegen->invalid_inst_gen; - CallModifier modifier = (CallModifier)bigint_as_u32(&modifier_val->data.x_enum_tag); - - if (ir_should_inline(ira->zir, scope)) { - switch (modifier) { - case CallModifierBuiltin: - zig_unreachable(); - case CallModifierAsync: - ir_add_error_node(ira, source_node, buf_sprintf("TODO: comptime @call with async modifier")); - return ira->codegen->invalid_inst_gen; - case CallModifierCompileTime: - case CallModifierNone: - case CallModifierAlwaysInline: - case CallModifierAlwaysTail: - case CallModifierNoSuspend: - modifier = CallModifierCompileTime; - break; - case CallModifierNeverInline: - ir_add_error_node(ira, source_node, - buf_sprintf("unable to perform 'never_inline' call at compile-time")); - return ira->codegen->invalid_inst_gen; - case CallModifierNeverTail: - ir_add_error_node(ira, source_node, - buf_sprintf("unable to perform 'never_tail' call at compile-time")); - return ira->codegen->invalid_inst_gen; - } - } - - Stage1AirInst *first_arg_ptr = nullptr; - AstNode *first_arg_ptr_src = nullptr; - ZigFn *fn = nullptr; - if (instr_is_comptime(fn_ref)) { - if (fn_ref->value->type->id == ZigTypeIdBoundFn) { - assert(fn_ref->value->special == ConstValSpecialStatic); - fn = fn_ref->value->data.x_bound_fn.fn; - first_arg_ptr = fn_ref->value->data.x_bound_fn.first_arg; - first_arg_ptr_src = fn_ref->value->data.x_bound_fn.first_arg_src; - if (type_is_invalid(first_arg_ptr->value->type)) - return ira->codegen->invalid_inst_gen; - } else { - fn = ir_resolve_fn(ira, fn_ref); - } - } - - // Some modifiers require the callee to be comptime-known - switch (modifier) { - case CallModifierCompileTime: - case CallModifierAlwaysInline: - case CallModifierAsync: - if (fn == nullptr) { - ir_add_error(ira, modifier_inst, - buf_sprintf("the specified modifier requires a comptime-known function")); - return ira->codegen->invalid_inst_gen; - } - ZIG_FALLTHROUGH; - default: - break; - } - - ZigType *fn_type = (fn != nullptr) ? fn->type_entry : fn_ref->value->type; - - TypeStructField *stack_field = find_struct_type_field(options->value->type, buf_create_from_str("stack")); - src_assert(stack_field != nullptr, source_node); - Stage1AirInst *opt_stack = ir_analyze_struct_value_field_value(ira, scope, source_node, options, stack_field); - if (type_is_invalid(opt_stack->value->type)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *stack_is_non_null_inst = ir_analyze_test_non_null(ira, scope, source_node, opt_stack); - bool stack_is_non_null; - if (!ir_resolve_bool(ira, stack_is_non_null_inst, &stack_is_non_null)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *stack = nullptr; - AstNode *stack_src = nullptr; - if (stack_is_non_null) { - stack = ir_analyze_optional_value_payload_value(ira, scope, source_node, opt_stack, false); - if (type_is_invalid(stack->value->type)) - return ira->codegen->invalid_inst_gen; - stack_src = stack->source_node; - } - - return ir_analyze_fn_call(ira, scope, source_node, fn, fn_type, fn_ref, first_arg_ptr, first_arg_ptr_src, - modifier, stack, stack_src, false, args_ptr, args_len, nullptr, result_loc); -} - -static Stage1AirInst *ir_analyze_async_call_extra(IrAnalyze *ira, Scope *scope, AstNode *source_node, CallModifier modifier, - Stage1ZirInst *pass1_fn_ref, Stage1ZirInst *ret_ptr, Stage1ZirInst *new_stack, Stage1AirInst **args_ptr, size_t args_len, ResultLoc *result_loc) -{ - Stage1AirInst *fn_ref = pass1_fn_ref->child; - if (type_is_invalid(fn_ref->value->type)) - return ira->codegen->invalid_inst_gen; - - if (ir_should_inline(ira->zir, scope)) { - ir_add_error_node(ira, source_node, buf_sprintf("TODO: comptime @asyncCall")); - return ira->codegen->invalid_inst_gen; - } - - Stage1AirInst *first_arg_ptr = nullptr; - AstNode *first_arg_ptr_src = nullptr; - ZigFn *fn = nullptr; - if (instr_is_comptime(fn_ref)) { - if (fn_ref->value->type->id == ZigTypeIdBoundFn) { - assert(fn_ref->value->special == ConstValSpecialStatic); - fn = fn_ref->value->data.x_bound_fn.fn; - first_arg_ptr = fn_ref->value->data.x_bound_fn.first_arg; - first_arg_ptr_src = fn_ref->value->data.x_bound_fn.first_arg_src; - if (type_is_invalid(first_arg_ptr->value->type)) - return ira->codegen->invalid_inst_gen; - } else { - fn = ir_resolve_fn(ira, fn_ref); - } - } - - Stage1AirInst *ret_ptr_uncasted = nullptr; - if (ret_ptr != nullptr) { - ret_ptr_uncasted = ret_ptr->child; - if (type_is_invalid(ret_ptr_uncasted->value->type)) - return ira->codegen->invalid_inst_gen; - } - - ZigType *fn_type = (fn != nullptr) ? fn->type_entry : fn_ref->value->type; - Stage1AirInst *casted_new_stack = analyze_casted_new_stack(ira, scope, source_node, - new_stack->child, new_stack->source_node, true, fn); - if (casted_new_stack != nullptr && type_is_invalid(casted_new_stack->value->type)) - return ira->codegen->invalid_inst_gen; - - return ir_analyze_fn_call(ira, scope, source_node, fn, fn_type, fn_ref, first_arg_ptr, - first_arg_ptr_src, modifier, casted_new_stack, new_stack->source_node, true, args_ptr, - args_len, ret_ptr_uncasted, result_loc); -} - -static bool ir_extract_tuple_call_args(IrAnalyze *ira, Scope *scope, AstNode *source_node, Stage1AirInst *args, Stage1AirInst ***args_ptr, size_t *args_len) { - ZigType *args_type = args->value->type; - if (type_is_invalid(args_type)) - return false; - - if (args_type->id != ZigTypeIdStruct) { - ir_add_error(ira, args, - buf_sprintf("expected tuple or struct, found '%s'", buf_ptr(&args_type->name))); - return false; - } - - if (is_tuple(args_type)) { - *args_len = args_type->data.structure.src_field_count; - *args_ptr = heap::c_allocator.allocate(*args_len); - for (size_t i = 0; i < *args_len; i += 1) { - TypeStructField *arg_field = args_type->data.structure.fields[i]; - (*args_ptr)[i] = ir_analyze_struct_value_field_value(ira, scope, source_node, args, arg_field); - if (type_is_invalid((*args_ptr)[i]->value->type)) - return false; - } - } else { - ir_add_error(ira, args, buf_sprintf("TODO: struct args")); - return false; - } - return true; -} - -static Stage1AirInst *ir_analyze_instruction_call_extra(IrAnalyze *ira, Stage1ZirInstCallExtra *instruction) { - Stage1AirInst *args = instruction->args->child; - Stage1AirInst **args_ptr = nullptr; - size_t args_len = 0; - if (!ir_extract_tuple_call_args(ira, instruction->base.scope, instruction->base.source_node, args, &args_ptr, &args_len)) { - return ira->codegen->invalid_inst_gen; - } - - Stage1AirInst *result = ir_analyze_call_extra(ira, instruction->base.scope, instruction->base.source_node, instruction->options, - instruction->fn_ref, args_ptr, args_len, instruction->result_loc); - heap::c_allocator.deallocate(args_ptr, args_len); - return result; -} - -static Stage1AirInst *ir_analyze_instruction_async_call_extra(IrAnalyze *ira, Stage1ZirInstAsyncCallExtra *instruction) { - Stage1AirInst *args = instruction->args->child; - Stage1AirInst **args_ptr = nullptr; - size_t args_len = 0; - if (!ir_extract_tuple_call_args(ira, instruction->base.scope, instruction->base.source_node, args, &args_ptr, &args_len)) { - return ira->codegen->invalid_inst_gen; - } - - Stage1AirInst *result = ir_analyze_async_call_extra(ira, instruction->base.scope, instruction->base.source_node, instruction->modifier, - instruction->fn_ref, instruction->ret_ptr, instruction->new_stack, args_ptr, args_len, instruction->result_loc); - heap::c_allocator.deallocate(args_ptr, args_len); - return result; -} - -static Stage1AirInst *ir_analyze_instruction_call_args(IrAnalyze *ira, Stage1ZirInstCallArgs *instruction) { - Stage1AirInst **args_ptr = heap::c_allocator.allocate(instruction->args_len); - for (size_t i = 0; i < instruction->args_len; i += 1) { - args_ptr[i] = instruction->args_ptr[i]->child; - if (type_is_invalid(args_ptr[i]->value->type)) - return ira->codegen->invalid_inst_gen; - } - - Stage1AirInst *result = ir_analyze_call_extra(ira, instruction->base.scope, instruction->base.source_node, instruction->options, - instruction->fn_ref, args_ptr, instruction->args_len, instruction->result_loc); - heap::c_allocator.deallocate(args_ptr, instruction->args_len); - return result; -} - -static Stage1AirInst *ir_analyze_instruction_call(IrAnalyze *ira, Stage1ZirInstCall *call_instruction) { - Stage1AirInst *fn_ref = call_instruction->fn_ref->child; - if (type_is_invalid(fn_ref->value->type)) - return ira->codegen->invalid_inst_gen; - - bool is_comptime = (call_instruction->modifier == CallModifierCompileTime) || - ir_should_inline(ira->zir, call_instruction->base.scope); - CallModifier modifier = is_comptime ? CallModifierCompileTime : call_instruction->modifier; - - if (is_comptime || instr_is_comptime(fn_ref)) { - if (fn_ref->value->type->id == ZigTypeIdMetaType) { - ZigType *ty = ir_resolve_type(ira, fn_ref); - if (ty == nullptr) - return ira->codegen->invalid_inst_gen; - ErrorMsg *msg = ir_add_error(ira, fn_ref, - buf_sprintf("type '%s' not a function", buf_ptr(&ty->name))); - add_error_note(ira->codegen, msg, call_instruction->base.source_node, - buf_sprintf("use @as builtin for type coercion")); - return ira->codegen->invalid_inst_gen; - } else if (fn_ref->value->type->id == ZigTypeIdFn) { - ZigFn *fn_table_entry = ir_resolve_fn(ira, fn_ref); - ZigType *fn_type = fn_table_entry ? fn_table_entry->type_entry : fn_ref->value->type; - CallModifier modifier = is_comptime ? CallModifierCompileTime : call_instruction->modifier; - return ir_analyze_fn_call_src(ira, call_instruction, fn_table_entry, fn_type, - fn_ref, nullptr, nullptr, modifier); - } else if (fn_ref->value->type->id == ZigTypeIdBoundFn) { - assert(fn_ref->value->special == ConstValSpecialStatic); - ZigFn *fn_table_entry = fn_ref->value->data.x_bound_fn.fn; - Stage1AirInst *first_arg_ptr = fn_ref->value->data.x_bound_fn.first_arg; - AstNode *first_arg_ptr_src = fn_ref->value->data.x_bound_fn.first_arg_src; - CallModifier modifier = is_comptime ? CallModifierCompileTime : call_instruction->modifier; - return ir_analyze_fn_call_src(ira, call_instruction, fn_table_entry, fn_table_entry->type_entry, - fn_ref, first_arg_ptr, first_arg_ptr_src, modifier); - } else { - ir_add_error(ira, fn_ref, - buf_sprintf("type '%s' not a function", buf_ptr(&fn_ref->value->type->name))); - return ira->codegen->invalid_inst_gen; - } - } - - if (fn_ref->value->type->id == ZigTypeIdFn) { - return ir_analyze_fn_call_src(ira, call_instruction, nullptr, fn_ref->value->type, - fn_ref, nullptr, nullptr, modifier); - } else { - ir_add_error(ira, fn_ref, - buf_sprintf("type '%s' not a function", buf_ptr(&fn_ref->value->type->name))); - return ira->codegen->invalid_inst_gen; - } -} - -// out_val->type must be the type to read the pointer as -// if the type is different than the actual type then it does a comptime byte reinterpretation -static Error ir_read_const_ptr(IrAnalyze *ira, CodeGen *codegen, AstNode *source_node, - ZigValue *out_val, ZigValue *ptr_val) -{ - Error err; - assert(out_val->type != nullptr); - - ZigValue *pointee = const_ptr_pointee_unchecked(codegen, ptr_val); - src_assert(pointee->type != nullptr, source_node); - - if ((err = type_resolve(codegen, pointee->type, ResolveStatusSizeKnown))) - return ErrorSemanticAnalyzeFail; - if ((err = type_resolve(codegen, out_val->type, ResolveStatusSizeKnown))) - return ErrorSemanticAnalyzeFail; - - size_t src_size = type_size(codegen, pointee->type); - size_t dst_size = type_size(codegen, out_val->type); - - if (dst_size <= src_size) { - if (src_size == dst_size && types_have_same_zig_comptime_repr(codegen, out_val->type, pointee->type)) { - copy_const_val(codegen, out_val, pointee); - return ErrorNone; - } - Buf buf = BUF_INIT; - buf_resize(&buf, src_size); - buf_write_value_bytes(codegen, (uint8_t*)buf_ptr(&buf), pointee); - if ((err = buf_read_value_bytes(ira, codegen, source_node, (uint8_t*)buf_ptr(&buf), out_val))) - return err; - buf_deinit(&buf); - return ErrorNone; - } - - switch (ptr_val->data.x_ptr.special) { - case ConstPtrSpecialInvalid: - zig_unreachable(); - case ConstPtrSpecialNull: - if (dst_size == 0) - return ErrorNone; - opt_ir_add_error_node(ira, codegen, source_node, - buf_sprintf("attempt to read %" ZIG_PRI_usize " bytes from null pointer", - dst_size)); - return ErrorSemanticAnalyzeFail; - case ConstPtrSpecialRef: { - opt_ir_add_error_node(ira, codegen, source_node, - buf_sprintf("attempt to read %" ZIG_PRI_usize " bytes from pointer to %s which is %" ZIG_PRI_usize " bytes", - dst_size, buf_ptr(&pointee->type->name), src_size)); - return ErrorSemanticAnalyzeFail; - } - case ConstPtrSpecialSubArray: { - ZigValue *array_val = ptr_val->data.x_ptr.data.base_array.array_val; - assert(array_val->type->id == ZigTypeIdArray); - if (array_val->data.x_array.special != ConstArraySpecialNone) - zig_panic("TODO: ir_read_const_ptr ConstPtrSpecialSubArray !ConstArraySpecialNone"); - if (dst_size > src_size) { - size_t elem_index = ptr_val->data.x_ptr.data.base_array.elem_index; - opt_ir_add_error_node(ira, codegen, source_node, - buf_sprintf("attempt to read %" ZIG_PRI_usize " bytes from %s at index %" ZIG_PRI_usize " which is %" ZIG_PRI_usize " bytes", - dst_size, buf_ptr(&array_val->type->name), elem_index, src_size)); - return ErrorSemanticAnalyzeFail; - } - size_t elem_size = src_size; - size_t elem_count = (dst_size % elem_size == 0) ? (dst_size / elem_size) : (dst_size / elem_size + 1); - Buf buf = BUF_INIT; - buf_resize(&buf, elem_count * elem_size); - for (size_t i = 0; i < elem_count; i += 1) { - ZigValue *elem_val = &array_val->data.x_array.data.s_none.elements[i]; - buf_write_value_bytes(codegen, (uint8_t*)buf_ptr(&buf) + (i * elem_size), elem_val); - } - if ((err = buf_read_value_bytes(ira, codegen, source_node, (uint8_t*)buf_ptr(&buf), out_val))) - return err; - buf_deinit(&buf); - return ErrorNone; - } - case ConstPtrSpecialBaseArray: { - ZigValue *array_val = ptr_val->data.x_ptr.data.base_array.array_val; - assert(array_val->type->id == ZigTypeIdArray); - if (array_val->data.x_array.special != ConstArraySpecialNone) - zig_panic("TODO: ir_read_const_ptr ConstPtrSpecialBaseArray !ConstArraySpecialNone"); - size_t elem_size = src_size; - size_t elem_index = ptr_val->data.x_ptr.data.base_array.elem_index; - src_size = elem_size * (array_val->type->data.array.len - elem_index); - if (dst_size > src_size) { - opt_ir_add_error_node(ira, codegen, source_node, - buf_sprintf("attempt to read %" ZIG_PRI_usize " bytes from %s at index %" ZIG_PRI_usize " which is %" ZIG_PRI_usize " bytes", - dst_size, buf_ptr(&array_val->type->name), elem_index, src_size)); - return ErrorSemanticAnalyzeFail; - } - size_t elem_count = (dst_size % elem_size == 0) ? (dst_size / elem_size) : (dst_size / elem_size + 1); - Buf buf = BUF_INIT; - buf_resize(&buf, elem_count * elem_size); - for (size_t i = 0; i < elem_count; i += 1) { - ZigValue *elem_val = &array_val->data.x_array.data.s_none.elements[elem_index + i]; - buf_write_value_bytes(codegen, (uint8_t*)buf_ptr(&buf) + (i * elem_size), elem_val); - } - if ((err = buf_read_value_bytes(ira, codegen, source_node, (uint8_t*)buf_ptr(&buf), out_val))) - return err; - buf_deinit(&buf); - return ErrorNone; - } - case ConstPtrSpecialBaseStruct: - case ConstPtrSpecialBaseErrorUnionCode: - case ConstPtrSpecialBaseErrorUnionPayload: - case ConstPtrSpecialBaseOptionalPayload: - case ConstPtrSpecialDiscard: - case ConstPtrSpecialHardCodedAddr: - case ConstPtrSpecialFunction: - zig_panic("TODO: ir_read_const_ptr"); - } - zig_unreachable(); -} - -static Stage1AirInst *ir_analyze_optional_type(IrAnalyze *ira, Stage1ZirInstUnOp *instruction) { - Stage1AirInst *result = ir_const(ira, instruction->base.scope, instruction->base.source_node, ira->codegen->builtin_types.entry_type); - result->value->special = ConstValSpecialLazy; - - LazyValueOptType *lazy_opt_type = heap::c_allocator.create(); - lazy_opt_type->ira = ira; ira_ref(ira); - result->value->data.x_lazy = &lazy_opt_type->base; - lazy_opt_type->base.id = LazyValueIdOptType; - - lazy_opt_type->payload_type = instruction->value->child; - if (ir_resolve_type_lazy(ira, lazy_opt_type->payload_type) == nullptr) - return ira->codegen->invalid_inst_gen; - - return result; -} - -static ErrorMsg *ir_eval_negation_scalar(IrAnalyze *ira, Scope *scope, AstNode *source_node, ZigType *scalar_type, - ZigValue *operand_val, ZigValue *scalar_out_val, bool is_wrap_op) -{ - bool is_float = (scalar_type->id == ZigTypeIdFloat || scalar_type->id == ZigTypeIdComptimeFloat); - - bool ok_type = scalar_type->id == ZigTypeIdInt || scalar_type->id == ZigTypeIdComptimeInt || - (is_float && !is_wrap_op); - - if (!ok_type) { - const char *fmt = is_wrap_op ? "invalid wrapping negation type: '%s'" : "invalid negation type: '%s'"; - return ir_add_error_node(ira, source_node, buf_sprintf(fmt, buf_ptr(&scalar_type->name))); - } - - if (is_float) { - float_negate(scalar_out_val, operand_val); - } else if (is_wrap_op) { - bigint_negate_wrap(&scalar_out_val->data.x_bigint, &operand_val->data.x_bigint, - scalar_type->data.integral.bit_count, scalar_type->data.integral.is_signed); - } else { - bigint_negate(&scalar_out_val->data.x_bigint, &operand_val->data.x_bigint); - } - - scalar_out_val->type = scalar_type; - scalar_out_val->special = ConstValSpecialStatic; - - if (is_wrap_op || is_float || scalar_type->id == ZigTypeIdComptimeInt) { - return nullptr; - } - - if (!bigint_fits_in_bits(&scalar_out_val->data.x_bigint, scalar_type->data.integral.bit_count, true)) { - return ir_add_error_node(ira, source_node, buf_sprintf("negation caused overflow")); - } - return nullptr; -} - -static Stage1AirInst *ir_analyze_negation(IrAnalyze *ira, Stage1ZirInstUnOp *instruction) { - Stage1AirInst *value = instruction->value->child; - ZigType *expr_type = value->value->type; - if (type_is_invalid(expr_type)) - return ira->codegen->invalid_inst_gen; - - bool is_wrap_op = (instruction->op_id == IrUnOpNegationWrap); - - ZigType *scalar_type = (expr_type->id == ZigTypeIdVector) ? - expr_type->data.vector.elem_type : expr_type; - - switch (scalar_type->id) { - case ZigTypeIdComptimeInt: - case ZigTypeIdFloat: - case ZigTypeIdComptimeFloat: - break; - case ZigTypeIdInt: - if (is_wrap_op || scalar_type->data.integral.is_signed) - break; - ZIG_FALLTHROUGH; - default: - ir_add_error_node(ira, instruction->base.source_node, - buf_sprintf("negation of type '%s'", buf_ptr(&scalar_type->name))); - return ira->codegen->invalid_inst_gen; - } - - if (instr_is_comptime(value)) { - ZigValue *operand_val = ir_resolve_const(ira, value, UndefBad); - if (!operand_val) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *result_instruction = ir_const(ira, instruction->base.scope, instruction->base.source_node, expr_type); - ZigValue *out_val = result_instruction->value; - if (expr_type->id == ZigTypeIdVector) { - expand_undef_array(ira->codegen, operand_val); - out_val->special = ConstValSpecialUndef; - expand_undef_array(ira->codegen, out_val); - size_t len = expr_type->data.vector.len; - for (size_t i = 0; i < len; i += 1) { - ZigValue *scalar_operand_val = &operand_val->data.x_array.data.s_none.elements[i]; - ZigValue *scalar_out_val = &out_val->data.x_array.data.s_none.elements[i]; - assert(scalar_operand_val->type == scalar_type); - assert(scalar_out_val->type == scalar_type); - ErrorMsg *msg = ir_eval_negation_scalar(ira, instruction->base.scope, instruction->base.source_node, scalar_type, - scalar_operand_val, scalar_out_val, is_wrap_op); - if (msg != nullptr) { - add_error_note(ira->codegen, msg, instruction->base.source_node, - buf_sprintf("when computing vector element at index %" ZIG_PRI_usize, i)); - return ira->codegen->invalid_inst_gen; - } - } - out_val->type = expr_type; - out_val->special = ConstValSpecialStatic; - } else { - if (ir_eval_negation_scalar(ira, instruction->base.scope, instruction->base.source_node, scalar_type, operand_val, out_val, - is_wrap_op) != nullptr) - { - return ira->codegen->invalid_inst_gen; - } - } - return result_instruction; - } - - return ir_build_negation(ira, instruction->base.scope, instruction->base.source_node, value, expr_type, is_wrap_op); -} - -static Stage1AirInst *ir_analyze_bin_not(IrAnalyze *ira, Stage1ZirInstUnOp *instruction) { - Stage1AirInst *value = instruction->value->child; - ZigType *expr_type = value->value->type; - if (type_is_invalid(expr_type)) - return ira->codegen->invalid_inst_gen; - - ZigType *scalar_type = (expr_type->id == ZigTypeIdVector) ? - expr_type->data.vector.elem_type : expr_type; - - if (scalar_type->id != ZigTypeIdInt) { - ir_add_error_node(ira, instruction->base.source_node, - buf_sprintf("unable to perform binary not operation on type '%s'", buf_ptr(&expr_type->name))); - return ira->codegen->invalid_inst_gen; - } - - if (instr_is_comptime(value)) { - ZigValue *expr_val = ir_resolve_const(ira, value, UndefBad); - if (expr_val == nullptr) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *result = ir_const(ira, instruction->base.scope, instruction->base.source_node, expr_type); - - if (expr_type->id == ZigTypeIdVector) { - expand_undef_array(ira->codegen, expr_val); - result->value->special = ConstValSpecialUndef; - expand_undef_array(ira->codegen, result->value); - - for (size_t i = 0; i < expr_type->data.vector.len; i++) { - ZigValue *src_val = &expr_val->data.x_array.data.s_none.elements[i]; - ZigValue *dst_val = &result->value->data.x_array.data.s_none.elements[i]; - - dst_val->type = scalar_type; - dst_val->special = ConstValSpecialStatic; - bigint_not(&dst_val->data.x_bigint, &src_val->data.x_bigint, - scalar_type->data.integral.bit_count, scalar_type->data.integral.is_signed); - } - } else { - bigint_not(&result->value->data.x_bigint, &expr_val->data.x_bigint, - scalar_type->data.integral.bit_count, scalar_type->data.integral.is_signed); - } - - return result; - } - - return ir_build_binary_not(ira, instruction->base.scope, instruction->base.source_node, value, expr_type); -} - -static Stage1AirInst *ir_analyze_instruction_un_op(IrAnalyze *ira, Stage1ZirInstUnOp *instruction) { - IrUnOp op_id = instruction->op_id; - switch (op_id) { - case IrUnOpInvalid: - zig_unreachable(); - case IrUnOpBinNot: - return ir_analyze_bin_not(ira, instruction); - case IrUnOpNegation: - case IrUnOpNegationWrap: - return ir_analyze_negation(ira, instruction); - case IrUnOpDereference: { - Stage1AirInst *ptr = instruction->value->child; - if (type_is_invalid(ptr->value->type)) - return ira->codegen->invalid_inst_gen; - ZigType *ptr_type = ptr->value->type; - if (ptr_type->id == ZigTypeIdPointer && ptr_type->data.pointer.ptr_len == PtrLenUnknown) { - ir_add_error_node(ira, instruction->base.source_node, - buf_sprintf("index syntax required for unknown-length pointer type '%s'", - buf_ptr(&ptr_type->name))); - return ira->codegen->invalid_inst_gen; - } - - Stage1AirInst *result = ir_get_deref(ira, instruction->base.scope, - instruction->base.source_node, ptr, instruction->result_loc); - if (type_is_invalid(result->value->type)) - return ira->codegen->invalid_inst_gen; - - // If the result needs to be an lvalue, type check it - if (instruction->lval != LValNone && result->value->type->id != ZigTypeIdPointer) { - ir_add_error_node(ira, instruction->base.source_node, - buf_sprintf("attempt to dereference non-pointer type '%s'", buf_ptr(&result->value->type->name))); - return ira->codegen->invalid_inst_gen; - } - - return result; - } - case IrUnOpOptional: - return ir_analyze_optional_type(ira, instruction); - } - zig_unreachable(); -} - -static void ir_push_resume(IrAnalyze *ira, IrSuspendPosition pos) { - Stage1ZirBasicBlock *old_bb = ira->zir->basic_block_list.at(pos.basic_block_index); - if (old_bb->in_resume_stack) return; - ira->resume_stack.append(pos); - old_bb->in_resume_stack = true; -} - -static void ir_push_resume_block(IrAnalyze *ira, Stage1ZirBasicBlock *old_bb) { - if (ira->resume_stack.length != 0) { - ir_push_resume(ira, {old_bb->index, 0}); - } -} - -static Stage1AirInst *ir_analyze_instruction_br(IrAnalyze *ira, Stage1ZirInstBr *br_instruction) { - Stage1ZirBasicBlock *old_dest_block = br_instruction->dest_block; - - bool is_comptime; - if (!ir_resolve_comptime(ira, br_instruction->is_comptime->child, &is_comptime)) - return ir_unreach_error(ira); - - if (is_comptime || (old_dest_block->ref_count == 1 && old_dest_block->suspend_instruction_ref == nullptr)) - return ir_inline_bb(ira, br_instruction->base.source_node, old_dest_block); - - Stage1AirBasicBlock *new_bb = ir_get_new_bb_runtime(ira, old_dest_block, &br_instruction->base); - if (new_bb == nullptr) - return ir_unreach_error(ira); - - ir_push_resume_block(ira, old_dest_block); - - Stage1AirInst *result = ir_build_br_gen(ira, br_instruction->base.scope, br_instruction->base.source_node, new_bb); - return ir_finish_anal(ira, result); -} - -static Stage1AirInst *ir_analyze_instruction_cond_br(IrAnalyze *ira, Stage1ZirInstCondBr *cond_br_instruction) { - Stage1AirInst *condition = cond_br_instruction->condition->child; - if (type_is_invalid(condition->value->type)) - return ir_unreach_error(ira); - - bool is_comptime; - if (!ir_resolve_comptime(ira, cond_br_instruction->is_comptime->child, &is_comptime)) - return ir_unreach_error(ira); - - ZigType *bool_type = ira->codegen->builtin_types.entry_bool; - Stage1AirInst *casted_condition = ir_implicit_cast(ira, condition, bool_type); - if (type_is_invalid(casted_condition->value->type)) - return ir_unreach_error(ira); - - if (is_comptime || instr_is_comptime(casted_condition)) { - bool cond_is_true; - if (!ir_resolve_bool(ira, casted_condition, &cond_is_true)) - return ir_unreach_error(ira); - - Stage1ZirBasicBlock *old_dest_block = cond_is_true ? - cond_br_instruction->then_block : cond_br_instruction->else_block; - - if (is_comptime || (old_dest_block->ref_count == 1 && old_dest_block->suspend_instruction_ref == nullptr)) - return ir_inline_bb(ira, cond_br_instruction->base.source_node, old_dest_block); - - Stage1AirBasicBlock *new_dest_block = ir_get_new_bb_runtime(ira, old_dest_block, &cond_br_instruction->base); - if (new_dest_block == nullptr) - return ir_unreach_error(ira); - - ir_push_resume_block(ira, old_dest_block); - - Stage1AirInst *result = ir_build_br_gen(ira, cond_br_instruction->base.scope, - cond_br_instruction->base.source_node, new_dest_block); - return ir_finish_anal(ira, result); - } - - assert(cond_br_instruction->then_block != cond_br_instruction->else_block); - Stage1AirBasicBlock *new_then_block = ir_get_new_bb_runtime(ira, cond_br_instruction->then_block, &cond_br_instruction->base); - if (new_then_block == nullptr) - return ir_unreach_error(ira); - - Stage1AirBasicBlock *new_else_block = ir_get_new_bb_runtime(ira, cond_br_instruction->else_block, &cond_br_instruction->base); - if (new_else_block == nullptr) - return ir_unreach_error(ira); - - ir_push_resume_block(ira, cond_br_instruction->else_block); - ir_push_resume_block(ira, cond_br_instruction->then_block); - - Stage1AirInst *result = ir_build_cond_br_gen(ira, cond_br_instruction->base.scope, - cond_br_instruction->base.source_node, casted_condition, new_then_block, - new_else_block); - return ir_finish_anal(ira, result); -} - -static Stage1AirInst *ir_analyze_instruction_unreachable(IrAnalyze *ira, - Stage1ZirInstUnreachable *unreachable_instruction) -{ - if (ir_should_inline(ira->zir, unreachable_instruction->base.scope)) { - ir_add_error_node(ira, unreachable_instruction->base.source_node, - buf_sprintf("reached unreachable code")); - return ir_unreach_error(ira); - } - - Stage1AirInst *result = ir_build_unreachable_gen(ira, unreachable_instruction->base.scope, - unreachable_instruction->base.source_node); - return ir_finish_anal(ira, result); -} - -static Stage1AirInst *ir_analyze_instruction_phi(IrAnalyze *ira, Stage1ZirInstPhi *phi_instruction) { - Error err; - - if (ira->const_predecessor_bb) { - for (size_t i = 0; i < phi_instruction->incoming_count; i += 1) { - Stage1ZirBasicBlock *predecessor = phi_instruction->incoming_blocks[i]; - if (predecessor != ira->const_predecessor_bb) - continue; - Stage1AirInst *value = phi_instruction->incoming_values[i]->child; - assert(value->value->type); - if (type_is_invalid(value->value->type)) - return ira->codegen->invalid_inst_gen; - - if (value->value->special != ConstValSpecialRuntime) { - Stage1AirInst *result = ir_const(ira, phi_instruction->base.scope, - phi_instruction->base.source_node, nullptr); - copy_const_val(ira->codegen, result->value, value->value); - return result; - } else { - return value; - } - } - zig_unreachable(); - } - - ResultLocPeerParent *peer_parent = phi_instruction->peer_parent; - if (peer_parent != nullptr && !peer_parent->skipped && !peer_parent->done_resuming && - peer_parent->peers.length >= 2) - { - if (peer_parent->resolved_type == nullptr) { - Stage1AirInst **instructions = heap::c_allocator.allocate(peer_parent->peers.length); - for (size_t i = 0; i < peer_parent->peers.length; i += 1) { - ResultLocPeer *this_peer = peer_parent->peers.at(i); - - Stage1AirInst *gen_instruction = this_peer->base.gen_instruction; - if (gen_instruction == nullptr) { - // unreachable instructions will cause implicit_elem_type to be null - if (this_peer->base.implicit_elem_type == nullptr) { - instructions[i] = ir_const_unreachable(ira, this_peer->base.source_instruction->scope, this_peer->base.source_instruction->source_node); - } else { - instructions[i] = ir_const(ira, this_peer->base.source_instruction->scope, - this_peer->base.source_instruction->source_node, - this_peer->base.implicit_elem_type); - instructions[i]->value->special = ConstValSpecialRuntime; - } - } else { - instructions[i] = gen_instruction; - } - - } - ZigType *expected_type = ir_result_loc_expected_type(ira, peer_parent->parent); - peer_parent->resolved_type = ir_resolve_peer_types(ira, - peer_parent->base.source_instruction->source_node, expected_type, instructions, - peer_parent->peers.length); - if (type_is_invalid(peer_parent->resolved_type)) - return ira->codegen->invalid_inst_gen; - - // the logic below assumes there are no instructions in the new current basic block yet - src_assert(ira->new_irb.current_basic_block->instruction_list.length == 0, - phi_instruction->base.source_node); - - // In case resolving the parent activates a suspend, do it now - Stage1AirInst *parent_result_loc = ir_resolve_result(ira, &phi_instruction->base, peer_parent->parent, - peer_parent->resolved_type, nullptr, false, true); - if (parent_result_loc != nullptr && - (type_is_invalid(parent_result_loc->value->type) || parent_result_loc->value->type->id == ZigTypeIdUnreachable)) - { - return parent_result_loc; - } - // If the above code generated any instructions in the current basic block, we need - // to move them to the peer parent predecessor. - ZigList instrs_to_move = {}; - while (ira->new_irb.current_basic_block->instruction_list.length != 0) { - instrs_to_move.append(ira->new_irb.current_basic_block->instruction_list.pop()); - } - if (instrs_to_move.length != 0) { - Stage1AirBasicBlock *predecessor = peer_parent->base.source_instruction->owner_bb->child; - Stage1AirInst *branch_instruction = predecessor->instruction_list.pop(); - src_assert(branch_instruction->value->type->id == ZigTypeIdUnreachable, - phi_instruction->base.source_node); - while (instrs_to_move.length != 0) { - predecessor->instruction_list.append(instrs_to_move.pop()); - } - predecessor->instruction_list.append(branch_instruction); - instrs_to_move.deinit(); - } - } - - IrSuspendPosition suspend_pos; - ira_suspend(ira, &phi_instruction->base, nullptr, &suspend_pos); - ir_push_resume(ira, suspend_pos); - - for (size_t i = 0; i < peer_parent->peers.length; i += 1) { - ResultLocPeer *opposite_peer = peer_parent->peers.at(peer_parent->peers.length - i - 1); - if (opposite_peer->base.implicit_elem_type != nullptr && - opposite_peer->base.implicit_elem_type->id != ZigTypeIdUnreachable) - { - ir_push_resume(ira, opposite_peer->suspend_pos); - } - } - - peer_parent->done_resuming = true; - return ira_resume(ira); - } - - ZigList new_incoming_blocks = {0}; - ZigList new_incoming_values = {0}; - - for (size_t i = 0; i < phi_instruction->incoming_count; i += 1) { - Stage1ZirBasicBlock *predecessor = phi_instruction->incoming_blocks[i]; - if (predecessor->ref_count == 0) - continue; - - - Stage1ZirInst *old_value = phi_instruction->incoming_values[i]; - assert(old_value); - Stage1AirInst *new_value = old_value->child; - if (!new_value || new_value->value->type->id == ZigTypeIdUnreachable || predecessor->child == nullptr) - continue; - - if (type_is_invalid(new_value->value->type)) - return ira->codegen->invalid_inst_gen; - - - assert(predecessor->child); - new_incoming_blocks.append(predecessor->child); - new_incoming_values.append(new_value); - } - - if (new_incoming_blocks.length == 0) { - Stage1AirInst *result = ir_build_unreachable_gen(ira, phi_instruction->base.scope, - phi_instruction->base.source_node); - return ir_finish_anal(ira, result); - } - - if (new_incoming_blocks.length == 1) { - Stage1AirInst *incoming_value = new_incoming_values.at(0); - new_incoming_blocks.deinit(); - new_incoming_values.deinit(); - return incoming_value; - } - - ZigType *resolved_type = nullptr; - if (peer_parent != nullptr) { - bool peer_parent_has_type; - if ((err = ir_result_has_type(ira, peer_parent->parent, &peer_parent_has_type))) - return ira->codegen->invalid_inst_gen; - if (peer_parent_has_type) { - if (peer_parent->parent->id == ResultLocIdReturn) { - resolved_type = ira->explicit_return_type; - } else if (peer_parent->parent->id == ResultLocIdCast) { - resolved_type = ir_resolve_type(ira, peer_parent->parent->source_instruction->child); - } else if (peer_parent->parent->resolved_loc) { - ZigType *resolved_loc_ptr_type = peer_parent->parent->resolved_loc->value->type; - src_assert(resolved_loc_ptr_type->id == ZigTypeIdPointer, - phi_instruction->base.source_node); - resolved_type = resolved_loc_ptr_type->data.pointer.child_type; - } - - if (resolved_type != nullptr && type_is_invalid(resolved_type)) - return ira->codegen->invalid_inst_gen; - } - } - - if (resolved_type == nullptr) { - resolved_type = ir_resolve_peer_types(ira, phi_instruction->base.source_node, nullptr, - new_incoming_values.items, new_incoming_values.length); - if (type_is_invalid(resolved_type)) - return ira->codegen->invalid_inst_gen; - } - - switch (type_has_one_possible_value(ira->codegen, resolved_type)) { - case OnePossibleValueInvalid: - return ira->codegen->invalid_inst_gen; - case OnePossibleValueYes: - return ir_const_move(ira, phi_instruction->base.scope, phi_instruction->base.source_node, - get_the_one_possible_value(ira->codegen, resolved_type)); - case OnePossibleValueNo: - break; - } - - switch (type_requires_comptime(ira->codegen, resolved_type)) { - case ReqCompTimeInvalid: - return ira->codegen->invalid_inst_gen; - case ReqCompTimeYes: - ir_add_error_node(ira, phi_instruction->base.source_node, - buf_sprintf("values of type '%s' must be comptime known", buf_ptr(&resolved_type->name))); - return ira->codegen->invalid_inst_gen; - case ReqCompTimeNo: - break; - } - - bool all_stack_ptrs = (resolved_type->id == ZigTypeIdPointer); - - // cast all values to the resolved type. however we can't put cast instructions in front of the phi instruction. - // so we go back and insert the casts as the last instruction in the corresponding predecessor blocks, and - // then make sure the branch instruction is preserved. - Stage1AirBasicBlock *cur_bb = ira->new_irb.current_basic_block; - for (size_t i = 0; i < new_incoming_values.length; i += 1) { - Stage1AirInst *new_value = new_incoming_values.at(i); - Stage1AirBasicBlock *predecessor = new_incoming_blocks.at(i); - src_assert(predecessor->instruction_list.length != 0, phi_instruction->base.source_node); - Stage1AirInst *branch_instruction = predecessor->instruction_list.pop(); - ir_set_cursor_at_end_gen(&ira->new_irb, predecessor); - Stage1AirInst *casted_value = ir_implicit_cast(ira, new_value, resolved_type); - if (type_is_invalid(casted_value->value->type)) { - return ira->codegen->invalid_inst_gen; - } - new_incoming_values.items[i] = casted_value; - predecessor->instruction_list.append(branch_instruction); - - if (all_stack_ptrs && (casted_value->value->special != ConstValSpecialRuntime || - casted_value->value->data.rh_ptr != RuntimeHintPtrStack)) - { - all_stack_ptrs = false; - } - } - ir_set_cursor_at_end_gen(&ira->new_irb, cur_bb); - - Stage1AirInst *result = ir_build_phi_gen(ira, phi_instruction->base.scope, - phi_instruction->base.source_node, phi_instruction->merge_comptime, - new_incoming_blocks.length, new_incoming_blocks.items, new_incoming_values.items, resolved_type); - - if (all_stack_ptrs) { - assert(result->value->special == ConstValSpecialRuntime); - result->value->data.rh_ptr = RuntimeHintPtrStack; - } - - return result; -} - -static Stage1AirInst *ir_analyze_instruction_var_ptr(IrAnalyze *ira, Stage1ZirInstVarPtr *instruction) { - ZigVar *var = instruction->var; - Stage1AirInst *result = ir_get_var_ptr(ira, instruction->base.scope, instruction->base.source_node, var); - if (instruction->crossed_fndef_scope != nullptr && !instr_is_comptime(result)) { - ErrorMsg *msg = ir_add_error_node(ira, instruction->base.source_node, - buf_sprintf("'%s' not accessible from inner function", var->name)); - add_error_note(ira->codegen, msg, instruction->crossed_fndef_scope->base.source_node, - buf_sprintf("crossed function definition here")); - add_error_note(ira->codegen, msg, var->decl_node, - buf_sprintf("declared here")); - return ira->codegen->invalid_inst_gen; - } - return result; -} - -static ZigType *adjust_ptr_align(CodeGen *g, ZigType *ptr_type, uint32_t new_align) { - assert(ptr_type->id == ZigTypeIdPointer); - return get_pointer_to_type_extra2(g, - ptr_type->data.pointer.child_type, - ptr_type->data.pointer.is_const, ptr_type->data.pointer.is_volatile, - ptr_type->data.pointer.ptr_len, - new_align, - ptr_type->data.pointer.bit_offset_in_host, ptr_type->data.pointer.host_int_bytes, - ptr_type->data.pointer.allow_zero, - ptr_type->data.pointer.vector_index, - ptr_type->data.pointer.inferred_struct_field, - ptr_type->data.pointer.sentinel); -} - -static ZigType *adjust_ptr_sentinel(CodeGen *g, ZigType *ptr_type, ZigValue *new_sentinel) { - assert(ptr_type->id == ZigTypeIdPointer); - return get_pointer_to_type_extra2(g, - ptr_type->data.pointer.child_type, - ptr_type->data.pointer.is_const, ptr_type->data.pointer.is_volatile, - ptr_type->data.pointer.ptr_len, - ptr_type->data.pointer.explicit_alignment, - ptr_type->data.pointer.bit_offset_in_host, ptr_type->data.pointer.host_int_bytes, - ptr_type->data.pointer.allow_zero, - ptr_type->data.pointer.vector_index, - ptr_type->data.pointer.inferred_struct_field, - new_sentinel); -} - -static ZigType *adjust_slice_align(CodeGen *g, ZigType *slice_type, uint32_t new_align) { - assert(is_slice(slice_type)); - ZigType *ptr_type = adjust_ptr_align(g, slice_type->data.structure.fields[slice_ptr_index]->type_entry, - new_align); - return get_slice_type(g, ptr_type); -} - -static ZigType *adjust_ptr_len(CodeGen *g, ZigType *ptr_type, PtrLen ptr_len) { - assert(ptr_type->id == ZigTypeIdPointer); - return get_pointer_to_type_extra2(g, - ptr_type->data.pointer.child_type, - ptr_type->data.pointer.is_const, ptr_type->data.pointer.is_volatile, - ptr_len, - ptr_type->data.pointer.explicit_alignment, - ptr_type->data.pointer.bit_offset_in_host, ptr_type->data.pointer.host_int_bytes, - ptr_type->data.pointer.allow_zero, - ptr_type->data.pointer.vector_index, - ptr_type->data.pointer.inferred_struct_field, - (ptr_len != PtrLenUnknown) ? nullptr : ptr_type->data.pointer.sentinel); -} - -static ZigType *adjust_ptr_allow_zero(CodeGen *g, ZigType *ptr_type, bool allow_zero) { - assert(ptr_type->id == ZigTypeIdPointer); - return get_pointer_to_type_extra2(g, - ptr_type->data.pointer.child_type, - ptr_type->data.pointer.is_const, ptr_type->data.pointer.is_volatile, - ptr_type->data.pointer.ptr_len, - ptr_type->data.pointer.explicit_alignment, - ptr_type->data.pointer.bit_offset_in_host, ptr_type->data.pointer.host_int_bytes, - allow_zero, - ptr_type->data.pointer.vector_index, - ptr_type->data.pointer.inferred_struct_field, - ptr_type->data.pointer.sentinel); -} - -static ZigType *adjust_ptr_const(CodeGen *g, ZigType *ptr_type, bool is_const) { - assert(ptr_type->id == ZigTypeIdPointer); - return get_pointer_to_type_extra2(g, - ptr_type->data.pointer.child_type, - is_const, ptr_type->data.pointer.is_volatile, - ptr_type->data.pointer.ptr_len, - ptr_type->data.pointer.explicit_alignment, - ptr_type->data.pointer.bit_offset_in_host, ptr_type->data.pointer.host_int_bytes, - ptr_type->data.pointer.allow_zero, - ptr_type->data.pointer.vector_index, - ptr_type->data.pointer.inferred_struct_field, - ptr_type->data.pointer.sentinel); -} - -static Error compute_elem_align(IrAnalyze *ira, ZigType *elem_type, uint32_t base_ptr_align, - uint64_t elem_index, uint32_t *result) -{ - Error err; - - if (base_ptr_align == 0) { - *result = 0; - return ErrorNone; - } - - // figure out the largest alignment possible - if ((err = type_resolve(ira->codegen, elem_type, ResolveStatusSizeKnown))) - return err; - - uint64_t elem_size = type_size(ira->codegen, elem_type); - uint64_t abi_align = get_abi_alignment(ira->codegen, elem_type); - uint64_t ptr_align = base_ptr_align; - - uint64_t chosen_align = abi_align; - if (ptr_align >= abi_align) { - while (ptr_align > abi_align) { - if ((elem_index * elem_size) % ptr_align == 0) { - chosen_align = ptr_align; - break; - } - ptr_align >>= 1; - } - } else if (elem_size >= ptr_align && elem_size % ptr_align == 0) { - chosen_align = ptr_align; - } else { - // can't get here because guaranteed elem_size >= abi_align - zig_unreachable(); - } - - *result = chosen_align; - return ErrorNone; -} - -static Stage1AirInst *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, Stage1ZirInstElemPtr *elem_ptr_instruction) { - Error err; - Stage1AirInst *array_ptr = elem_ptr_instruction->array_ptr->child; - if (type_is_invalid(array_ptr->value->type)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *elem_index = elem_ptr_instruction->elem_index->child; - if (type_is_invalid(elem_index->value->type)) - return ira->codegen->invalid_inst_gen; - - ZigValue *orig_array_ptr_val = array_ptr->value; - - ZigType *ptr_type = orig_array_ptr_val->type; - assert(ptr_type->id == ZigTypeIdPointer); - - ZigType *array_type = ptr_type->data.pointer.child_type; - - // At first return_type will be the pointer type we want to return, except with an optimistic alignment. - // We will adjust return_type's alignment before returning it. - ZigType *return_type; - - if (type_is_invalid(array_type)) - return ira->codegen->invalid_inst_gen; - - if (array_type->id == ZigTypeIdPointer && - array_type->data.pointer.ptr_len == PtrLenSingle && - array_type->data.pointer.child_type->id == ZigTypeIdArray) - { - Stage1AirInst *ptr_value = ir_get_deref(ira, elem_ptr_instruction->base.scope, - elem_ptr_instruction->base.source_node, array_ptr, nullptr); - if (type_is_invalid(ptr_value->value->type)) - return ira->codegen->invalid_inst_gen; - - array_type = array_type->data.pointer.child_type; - ptr_type = ptr_type->data.pointer.child_type; - - orig_array_ptr_val = ptr_value->value; - } - - if (array_type->id == ZigTypeIdArray) { - if(array_type->data.array.len == 0 && array_type->data.array.sentinel == nullptr){ - ir_add_error_node(ira, elem_ptr_instruction->base.source_node, - buf_sprintf("accessing a zero length array is not allowed")); - return ira->codegen->invalid_inst_gen; - } - - ZigType *child_type = array_type->data.array.child_type; - if (ptr_type->data.pointer.host_int_bytes == 0) { - return_type = get_pointer_to_type_extra(ira->codegen, child_type, - ptr_type->data.pointer.is_const, ptr_type->data.pointer.is_volatile, - elem_ptr_instruction->ptr_len, - ptr_type->data.pointer.explicit_alignment, 0, 0, false); - } else { - uint64_t elem_val_scalar; - if (!ir_resolve_usize(ira, elem_index, &elem_val_scalar)) - return ira->codegen->invalid_inst_gen; - - size_t bit_width = type_size_bits(ira->codegen, child_type); - size_t bit_offset = bit_width * elem_val_scalar; - - return_type = get_pointer_to_type_extra(ira->codegen, child_type, - ptr_type->data.pointer.is_const, ptr_type->data.pointer.is_volatile, - elem_ptr_instruction->ptr_len, - 1, (uint32_t)bit_offset, ptr_type->data.pointer.host_int_bytes, false); - } - } else if (array_type->id == ZigTypeIdPointer) { - if (array_type->data.pointer.ptr_len == PtrLenSingle) { - ir_add_error_node(ira, elem_ptr_instruction->base.source_node, - buf_sprintf("index of single-item pointer")); - return ira->codegen->invalid_inst_gen; - } - return_type = adjust_ptr_len(ira->codegen, array_type, elem_ptr_instruction->ptr_len); - } else if (is_slice(array_type)) { - return_type = adjust_ptr_len(ira->codegen, array_type->data.structure.fields[slice_ptr_index]->type_entry, - elem_ptr_instruction->ptr_len); - } else if (array_type->id == ZigTypeIdVector) { - // This depends on whether the element index is comptime, so it is computed later. - return_type = nullptr; - } else if (elem_ptr_instruction->init_array_type_source_node != nullptr && - array_type->id == ZigTypeIdStruct && - array_type->data.structure.resolve_status == ResolveStatusBeingInferred) - { - ZigType *usize = ira->codegen->builtin_types.entry_usize; - Stage1AirInst *casted_elem_index = ir_implicit_cast(ira, elem_index, usize); - if (type_is_invalid(casted_elem_index->value->type)) - return ira->codegen->invalid_inst_gen; - src_assert(instr_is_comptime(casted_elem_index), elem_ptr_instruction->base.source_node); - Buf *field_name = buf_alloc(); - bigint_append_buf(field_name, &casted_elem_index->value->data.x_bigint, 10); - return ir_analyze_inferred_field_ptr(ira, field_name, elem_ptr_instruction->base.scope, elem_ptr_instruction->base.source_node, - array_ptr, array_type); - } else if (is_tuple(array_type)) { - uint64_t elem_index_scalar; - if (!ir_resolve_usize(ira, elem_index, &elem_index_scalar)) - return ira->codegen->invalid_inst_gen; - if (elem_index_scalar >= array_type->data.structure.src_field_count) { - ir_add_error_node(ira, elem_ptr_instruction->base.source_node, buf_sprintf( - "field index %" ZIG_PRI_u64 " outside tuple '%s' which has %" PRIu32 " fields", - elem_index_scalar, buf_ptr(&array_type->name), - array_type->data.structure.src_field_count)); - return ira->codegen->invalid_inst_gen; - } - TypeStructField *field = array_type->data.structure.fields[elem_index_scalar]; - return ir_analyze_struct_field_ptr(ira, elem_ptr_instruction->base.scope, elem_ptr_instruction->base.source_node, field, array_ptr, - array_type, false); - } else { - ir_add_error_node(ira, elem_ptr_instruction->base.source_node, - buf_sprintf("array access of non-array type '%s'", buf_ptr(&array_type->name))); - return ira->codegen->invalid_inst_gen; - } - - ZigType *usize = ira->codegen->builtin_types.entry_usize; - Stage1AirInst *casted_elem_index = ir_implicit_cast(ira, elem_index, usize); - if (type_is_invalid(casted_elem_index->value->type)) - return ira->codegen->invalid_inst_gen; - - bool safety_check_on = elem_ptr_instruction->safety_check_on; - if (instr_is_comptime(casted_elem_index)) { - ZigValue *index_val = ir_resolve_const(ira, casted_elem_index, UndefBad); - if (index_val == nullptr) - return ira->codegen->invalid_inst_gen; - uint64_t index = bigint_as_u64(&index_val->data.x_bigint); - - if (array_type->id == ZigTypeIdArray) { - uint64_t array_len = array_type->data.array.len + - (array_type->data.array.sentinel != nullptr); - if (index >= array_len) { - ir_add_error_node(ira, elem_ptr_instruction->base.source_node, - buf_sprintf("index %" ZIG_PRI_u64 " outside array of size %" ZIG_PRI_u64, - index, array_len)); - return ira->codegen->invalid_inst_gen; - } - safety_check_on = false; - } else if (array_type->id == ZigTypeIdVector) { - uint64_t vector_len = array_type->data.vector.len; - if (index >= vector_len) { - ir_add_error_node(ira, elem_ptr_instruction->base.source_node, - buf_sprintf("index %" ZIG_PRI_u64 " outside vector of size %" ZIG_PRI_u64, - index, vector_len)); - return ira->codegen->invalid_inst_gen; - } - safety_check_on = false; - } - - if (array_type->id == ZigTypeIdVector) { - ZigType *elem_type = array_type->data.vector.elem_type; - uint32_t host_vec_len = array_type->data.vector.len; - return_type = get_pointer_to_type_extra2(ira->codegen, elem_type, - ptr_type->data.pointer.is_const, ptr_type->data.pointer.is_volatile, - elem_ptr_instruction->ptr_len, - get_ptr_align(ira->codegen, ptr_type), 0, host_vec_len, false, (uint32_t)index, - nullptr, nullptr); - } else if (return_type->data.pointer.explicit_alignment != 0) { - uint32_t chosen_align; - if ((err = compute_elem_align(ira, return_type->data.pointer.child_type, - return_type->data.pointer.explicit_alignment, index, &chosen_align))) - { - return ira->codegen->invalid_inst_gen; - } - return_type = adjust_ptr_align(ira->codegen, return_type, chosen_align); - } - - // TODO The `array_type->id == ZigTypeIdArray` exception here should not be an exception; - // the `orig_array_ptr_val->data.x_ptr.mut != ConstPtrMutRuntimeVar` clause should be omitted completely. - // However there are bugs to fix before this improvement can be made. - if (orig_array_ptr_val->special != ConstValSpecialRuntime && - orig_array_ptr_val->data.x_ptr.special != ConstPtrSpecialHardCodedAddr && - (orig_array_ptr_val->data.x_ptr.mut != ConstPtrMutRuntimeVar || array_type->id == ZigTypeIdArray)) - { - if ((err = ir_resolve_const_val(ira->codegen, ira->new_irb.exec, - elem_ptr_instruction->base.source_node, orig_array_ptr_val, UndefBad))) - { - return ira->codegen->invalid_inst_gen; - } - - ZigValue *array_ptr_val = const_ptr_pointee(ira, ira->codegen, orig_array_ptr_val, - elem_ptr_instruction->base.source_node); - if (array_ptr_val == nullptr) - return ira->codegen->invalid_inst_gen; - - if (array_ptr_val->special == ConstValSpecialUndef && - elem_ptr_instruction->init_array_type_source_node != nullptr) - { - if (array_type->id == ZigTypeIdArray || array_type->id == ZigTypeIdVector) { - array_ptr_val->data.x_array.special = ConstArraySpecialNone; - array_ptr_val->data.x_array.data.s_none.elements = ira->codegen->pass1_arena->allocate(array_type->data.array.len); - array_ptr_val->special = ConstValSpecialStatic; - for (size_t i = 0; i < array_type->data.array.len; i += 1) { - ZigValue *elem_val = &array_ptr_val->data.x_array.data.s_none.elements[i]; - elem_val->special = ConstValSpecialUndef; - elem_val->type = array_type->data.array.child_type; - elem_val->parent.id = ConstParentIdArray; - elem_val->parent.data.p_array.array_val = array_ptr_val; - elem_val->parent.data.p_array.elem_index = i; - } - } else if (is_slice(array_type)) { - src_assert(array_ptr->value->type->id == ZigTypeIdPointer, elem_ptr_instruction->base.source_node); - ZigType *actual_array_type = array_ptr->value->type->data.pointer.child_type; - - if (type_is_invalid(actual_array_type)) - return ira->codegen->invalid_inst_gen; - if (actual_array_type->id != ZigTypeIdArray) { - ir_add_error_node(ira, elem_ptr_instruction->init_array_type_source_node, - buf_sprintf("array literal requires address-of operator (&) to coerce to slice type '%s'", - buf_ptr(&actual_array_type->name))); - return ira->codegen->invalid_inst_gen; - } - - ZigValue *array_init_val = ira->codegen->pass1_arena->create(); - array_init_val->special = ConstValSpecialStatic; - array_init_val->type = actual_array_type; - array_init_val->data.x_array.special = ConstArraySpecialNone; - array_init_val->data.x_array.data.s_none.elements = ira->codegen->pass1_arena->allocate(actual_array_type->data.array.len); - array_init_val->special = ConstValSpecialStatic; - for (size_t i = 0; i < actual_array_type->data.array.len; i += 1) { - ZigValue *elem_val = &array_init_val->data.x_array.data.s_none.elements[i]; - elem_val->special = ConstValSpecialUndef; - elem_val->type = actual_array_type->data.array.child_type; - elem_val->parent.id = ConstParentIdArray; - elem_val->parent.data.p_array.array_val = array_init_val; - elem_val->parent.data.p_array.elem_index = i; - } - - init_const_slice(ira->codegen, array_ptr_val, array_init_val, 0, actual_array_type->data.array.len, - false, nullptr); - array_ptr_val->data.x_struct.fields[slice_ptr_index]->data.x_ptr.mut = ConstPtrMutInfer; - } else { - ir_add_error_node(ira, elem_ptr_instruction->init_array_type_source_node, - buf_sprintf("expected array type or [_], found '%s'", - buf_ptr(&array_type->name))); - return ira->codegen->invalid_inst_gen; - } - } - - if (array_ptr_val->special != ConstValSpecialRuntime && - (array_type->id != ZigTypeIdPointer || - array_ptr_val->data.x_ptr.special != ConstPtrSpecialHardCodedAddr)) - { - if ((err = ir_resolve_const_val(ira->codegen, ira->new_irb.exec, - elem_ptr_instruction->base.source_node, array_ptr_val, UndefOk))) - { - return ira->codegen->invalid_inst_gen; - } - if (array_type->id == ZigTypeIdPointer) { - Stage1AirInst *result = ir_const(ira, elem_ptr_instruction->base.scope, elem_ptr_instruction->base.source_node, return_type); - ZigValue *out_val = result->value; - out_val->data.x_ptr.mut = array_ptr_val->data.x_ptr.mut; - size_t new_index; - size_t mem_size; - size_t old_size; - switch (array_ptr_val->data.x_ptr.special) { - case ConstPtrSpecialInvalid: - case ConstPtrSpecialDiscard: - zig_unreachable(); - case ConstPtrSpecialRef: - if (array_ptr_val->data.x_ptr.data.ref.pointee->type->id == ZigTypeIdArray) { - ZigValue *array_val = array_ptr_val->data.x_ptr.data.ref.pointee; - new_index = index; - ZigType *array_type = array_val->type; - mem_size = array_type->data.array.len; - if (array_type->data.array.sentinel != nullptr) { - mem_size += 1; - } - old_size = mem_size; - - out_val->data.x_ptr.special = ConstPtrSpecialBaseArray; - out_val->data.x_ptr.data.base_array.array_val = array_val; - out_val->data.x_ptr.data.base_array.elem_index = new_index; - } else { - mem_size = 1; - old_size = 1; - new_index = index; - - out_val->data.x_ptr.special = ConstPtrSpecialRef; - out_val->data.x_ptr.data.ref.pointee = array_ptr_val->data.x_ptr.data.ref.pointee; - } - break; - case ConstPtrSpecialBaseArray: - case ConstPtrSpecialSubArray: - { - size_t offset = array_ptr_val->data.x_ptr.data.base_array.elem_index; - new_index = offset + index; - ZigType *array_type = array_ptr_val->data.x_ptr.data.base_array.array_val->type; - mem_size = array_type->data.array.len; - if (array_type->data.array.sentinel != nullptr) { - mem_size += 1; - } - old_size = mem_size - offset; - - assert(array_ptr_val->data.x_ptr.data.base_array.array_val); - - out_val->data.x_ptr.special = ConstPtrSpecialBaseArray; - out_val->data.x_ptr.data.base_array.array_val = - array_ptr_val->data.x_ptr.data.base_array.array_val; - out_val->data.x_ptr.data.base_array.elem_index = new_index; - - break; - } - case ConstPtrSpecialBaseStruct: - zig_panic("TODO elem ptr on a const inner struct"); - case ConstPtrSpecialBaseErrorUnionCode: - zig_panic("TODO elem ptr on a const inner error union code"); - case ConstPtrSpecialBaseErrorUnionPayload: - zig_panic("TODO elem ptr on a const inner error union payload"); - case ConstPtrSpecialBaseOptionalPayload: - zig_panic("TODO elem ptr on a const inner optional payload"); - case ConstPtrSpecialHardCodedAddr: - zig_unreachable(); - case ConstPtrSpecialFunction: - zig_panic("TODO element ptr of a function casted to a ptr"); - case ConstPtrSpecialNull: - zig_panic("TODO elem ptr on a null pointer"); - } - if (new_index >= mem_size) { - ir_add_error_node(ira, elem_ptr_instruction->base.source_node, - buf_sprintf("index %" ZIG_PRI_u64 " outside pointer of size %" ZIG_PRI_usize "", index, old_size)); - return ira->codegen->invalid_inst_gen; - } - return result; - } else if (is_slice(array_type)) { - expand_undef_struct(ira->codegen, array_ptr_val); - - ZigValue *ptr_field = array_ptr_val->data.x_struct.fields[slice_ptr_index]; - src_assert(ptr_field != nullptr, elem_ptr_instruction->base.source_node); - if (ptr_field->data.x_ptr.special == ConstPtrSpecialHardCodedAddr) { - return ir_build_elem_ptr_gen(ira, elem_ptr_instruction->base.scope, - elem_ptr_instruction->base.source_node, array_ptr, casted_elem_index, false, - return_type); - } - ZigValue *len_field = array_ptr_val->data.x_struct.fields[slice_len_index]; - Stage1AirInst *result = ir_const(ira, elem_ptr_instruction->base.scope, - elem_ptr_instruction->base.source_node, return_type); - ZigValue *out_val = result->value; - ZigType *slice_ptr_type = array_type->data.structure.fields[slice_ptr_index]->type_entry; - uint64_t slice_len = bigint_as_u64(&len_field->data.x_bigint); - uint64_t full_slice_len = slice_len + - ((slice_ptr_type->data.pointer.sentinel != nullptr) ? 1 : 0); - if (index >= full_slice_len) { - ir_add_error_node(ira, elem_ptr_instruction->base.source_node, - buf_sprintf("index %" ZIG_PRI_u64 " outside slice of size %" ZIG_PRI_u64, - index, slice_len)); - return ira->codegen->invalid_inst_gen; - } - out_val->data.x_ptr.mut = ptr_field->data.x_ptr.mut; - switch (ptr_field->data.x_ptr.special) { - case ConstPtrSpecialInvalid: - case ConstPtrSpecialDiscard: - zig_unreachable(); - case ConstPtrSpecialRef: - out_val->data.x_ptr.special = ConstPtrSpecialRef; - out_val->data.x_ptr.data.ref.pointee = ptr_field->data.x_ptr.data.ref.pointee; - break; - case ConstPtrSpecialSubArray: - case ConstPtrSpecialBaseArray: - { - uint64_t array_len = ptr_field->data.x_ptr.data.base_array.array_val->type->data.array.len; - if (ptr_field->data.x_ptr.data.base_array.array_val->type->data.array.sentinel != nullptr) { - array_len += 1; - } - size_t offset = ptr_field->data.x_ptr.data.base_array.elem_index; - uint64_t new_index = offset + index; - if (ptr_field->data.x_ptr.data.base_array.array_val->data.x_array.special != - ConstArraySpecialBuf) - { - if (new_index >= array_len) { - ir_add_error_node(ira, elem_ptr_instruction->base.source_node, buf_sprintf("out of bounds slice")); - return ira->codegen->invalid_inst_gen; - } - } - out_val->data.x_ptr.special = ConstPtrSpecialBaseArray; - out_val->data.x_ptr.data.base_array.array_val = - ptr_field->data.x_ptr.data.base_array.array_val; - out_val->data.x_ptr.data.base_array.elem_index = new_index; - break; - } - case ConstPtrSpecialBaseStruct: - zig_panic("TODO elem ptr on a slice backed by const inner struct"); - case ConstPtrSpecialBaseErrorUnionCode: - zig_panic("TODO elem ptr on a slice backed by const inner error union code"); - case ConstPtrSpecialBaseErrorUnionPayload: - zig_panic("TODO elem ptr on a slice backed by const inner error union payload"); - case ConstPtrSpecialBaseOptionalPayload: - zig_panic("TODO elem ptr on a slice backed by const optional payload"); - case ConstPtrSpecialHardCodedAddr: - zig_unreachable(); - case ConstPtrSpecialFunction: - zig_panic("TODO elem ptr on a slice that was ptrcast from a function"); - case ConstPtrSpecialNull: - zig_panic("TODO elem ptr on a slice has a null pointer"); - } - return result; - } else if (array_type->id == ZigTypeIdArray || array_type->id == ZigTypeIdVector) { - expand_undef_array(ira->codegen, array_ptr_val); - - Stage1AirInst *result; - if (orig_array_ptr_val->data.x_ptr.mut == ConstPtrMutInfer) { - result = ir_build_elem_ptr_gen(ira, elem_ptr_instruction->base.scope, - elem_ptr_instruction->base.source_node, array_ptr, casted_elem_index, - false, return_type); - result->value->special = ConstValSpecialStatic; - } else { - result = ir_const(ira, elem_ptr_instruction->base.scope, elem_ptr_instruction->base.source_node, return_type); - } - ZigValue *out_val = result->value; - out_val->data.x_ptr.special = ConstPtrSpecialBaseArray; - out_val->data.x_ptr.mut = orig_array_ptr_val->data.x_ptr.mut; - out_val->data.x_ptr.data.base_array.array_val = array_ptr_val; - out_val->data.x_ptr.data.base_array.elem_index = index; - return result; - } else { - zig_unreachable(); - } - } - } - } else if (array_type->id == ZigTypeIdVector) { - // runtime known element index - ZigType *elem_type = array_type->data.vector.elem_type; - uint32_t host_vec_len = array_type->data.vector.len; - return_type = get_pointer_to_type_extra2(ira->codegen, elem_type, - ptr_type->data.pointer.is_const, ptr_type->data.pointer.is_volatile, - elem_ptr_instruction->ptr_len, - get_ptr_align(ira->codegen, ptr_type), 0, host_vec_len, false, VECTOR_INDEX_RUNTIME, - nullptr, nullptr); - } else { - // runtime known element index - switch (type_requires_comptime(ira->codegen, return_type)) { - case ReqCompTimeYes: - ir_add_error(ira, elem_index, - buf_sprintf("values of type '%s' must be comptime known, but index value is runtime known", - buf_ptr(&return_type->data.pointer.child_type->name))); - return ira->codegen->invalid_inst_gen; - case ReqCompTimeInvalid: - return ira->codegen->invalid_inst_gen; - case ReqCompTimeNo: - break; - } - - if (return_type->data.pointer.explicit_alignment != 0) { - if ((err = type_resolve(ira->codegen, return_type->data.pointer.child_type, ResolveStatusSizeKnown))) - return ira->codegen->invalid_inst_gen; - - uint64_t elem_size = type_size(ira->codegen, return_type->data.pointer.child_type); - uint64_t abi_align = get_abi_alignment(ira->codegen, return_type->data.pointer.child_type); - uint64_t ptr_align = get_ptr_align(ira->codegen, return_type); - if (ptr_align < abi_align) { - if (elem_size >= ptr_align && elem_size % ptr_align == 0) { - return_type = adjust_ptr_align(ira->codegen, return_type, ptr_align); - } else { - // can't get here because guaranteed elem_size >= abi_align - zig_unreachable(); - } - } else { - return_type = adjust_ptr_align(ira->codegen, return_type, abi_align); - } - } - } - - return ir_build_elem_ptr_gen(ira, elem_ptr_instruction->base.scope, - elem_ptr_instruction->base.source_node, array_ptr, casted_elem_index, safety_check_on, return_type); -} - -static Stage1AirInst *ir_analyze_container_member_access_inner(IrAnalyze *ira, - ZigType *bare_struct_type, Buf *field_name, Scope *scope, AstNode *source_node, - Stage1AirInst *container_ptr, AstNode *container_ptr_src, ZigType *container_type) -{ - if (!is_slice(bare_struct_type)) { - ScopeDecls *container_scope = get_container_scope(bare_struct_type); - assert(container_scope != nullptr); - auto tld = find_container_decl(ira->codegen, container_scope, field_name); - if (tld) { - if (tld->id == TldIdFn) { - resolve_top_level_decl(ira->codegen, tld, source_node, false); - if (tld->resolution == TldResolutionInvalid) - return ira->codegen->invalid_inst_gen; - if (tld->resolution == TldResolutionResolving) - return ir_error_dependency_loop(ira, source_node); - - if (tld->visib_mod == VisibModPrivate && - tld->import != get_scope_import(scope)) - { - ErrorMsg *msg = ir_add_error_node(ira, source_node, - buf_sprintf("'%s' is private", buf_ptr(field_name))); - add_error_note(ira->codegen, msg, tld->source_node, buf_sprintf("declared here")); - return ira->codegen->invalid_inst_gen; - } - - TldFn *tld_fn = (TldFn *)tld; - ZigFn *fn_entry = tld_fn->fn_entry; - assert(fn_entry != nullptr); - - if (type_is_invalid(fn_entry->type_entry)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *bound_fn_value = ir_const_bound_fn(ira, scope, source_node, fn_entry, container_ptr, - container_ptr_src); - return ir_get_ref(ira, scope, source_node, bound_fn_value, true, false); - } else if (tld->id == TldIdVar) { - resolve_top_level_decl(ira->codegen, tld, source_node, false); - if (tld->resolution == TldResolutionInvalid) - return ira->codegen->invalid_inst_gen; - if (tld->resolution == TldResolutionResolving) - return ir_error_dependency_loop(ira, source_node); - - TldVar *tld_var = (TldVar *)tld; - ZigVar *var = tld_var->var; - assert(var != nullptr); - - if (type_is_invalid(var->var_type)) - return ira->codegen->invalid_inst_gen; - - if (var->const_value->type->id == ZigTypeIdFn) { - src_assert(var->const_value->data.x_ptr.special == ConstPtrSpecialFunction, source_node); - ZigFn *fn = var->const_value->data.x_ptr.data.fn.fn_entry; - Stage1AirInst *bound_fn_value = ir_const_bound_fn(ira, scope, source_node, fn, container_ptr, - container_ptr_src); - return ir_get_ref(ira, scope, source_node, bound_fn_value, true, false); - } - } - } - } - const char *prefix_name; - if (is_slice(bare_struct_type)) { - prefix_name = ""; - } else if (bare_struct_type->id == ZigTypeIdStruct) { - prefix_name = "struct "; - } else if (bare_struct_type->id == ZigTypeIdEnum) { - prefix_name = "enum "; - } else if (bare_struct_type->id == ZigTypeIdUnion) { - prefix_name = "union "; - } else if (bare_struct_type->id == ZigTypeIdOpaque) { - prefix_name = "opaque type "; - } else { - prefix_name = ""; - } - ir_add_error_node(ira, source_node, - buf_sprintf("no member named '%s' in %s'%s'", buf_ptr(field_name), prefix_name, buf_ptr(&bare_struct_type->name))); - return ira->codegen->invalid_inst_gen; -} - -static void memoize_field_init_val(CodeGen *codegen, ZigType *container_type, TypeStructField *field) { - if (field->init_val != nullptr) return; - if (field->decl_node == nullptr) return; - if (field->decl_node->type != NodeTypeStructField) return; - AstNode *init_node = field->decl_node->data.struct_field.value; - if (init_node == nullptr) return; - // scope is not the scope of the struct init, it's the scope of the struct type decl - Scope *analyze_scope = &get_container_scope(container_type)->base; - // memoize it - field->init_val = analyze_const_value(codegen, analyze_scope, init_node, - field->type_entry, nullptr, UndefOk); -} - -static Stage1AirInst *ir_analyze_struct_field_ptr(IrAnalyze *ira, Scope *scope, AstNode *source_node, - TypeStructField *field, Stage1AirInst *struct_ptr, ZigType *struct_type, bool initializing) -{ - Error err; - ZigType *field_type = resolve_struct_field_type(ira->codegen, field); - if (field_type == nullptr) - return ira->codegen->invalid_inst_gen; - if (field->is_comptime) { - Stage1AirInst *elem = ir_const(ira, scope, source_node, field_type); - memoize_field_init_val(ira->codegen, struct_type, field); - if(field->init_val != nullptr && type_is_invalid(field->init_val->type)){ - return ira->codegen->invalid_inst_gen; - } - copy_const_val(ira->codegen, elem->value, field->init_val); - return ir_get_ref2(ira, scope, source_node, elem, field_type, true, false); - } - switch (type_has_one_possible_value(ira->codegen, field_type)) { - case OnePossibleValueInvalid: - return ira->codegen->invalid_inst_gen; - case OnePossibleValueYes: { - Stage1AirInst *elem = ir_const_move(ira, scope, source_node, - get_the_one_possible_value(ira->codegen, field_type)); - return ir_get_ref(ira, scope, source_node, elem, - struct_ptr->value->type->data.pointer.is_const, - struct_ptr->value->type->data.pointer.is_volatile); - } - case OnePossibleValueNo: - break; - } - bool is_const = struct_ptr->value->type->data.pointer.is_const; - bool is_volatile = struct_ptr->value->type->data.pointer.is_volatile; - ZigType *ptr_type; - if (is_anon_container(struct_type)) { - ptr_type = get_pointer_to_type_extra(ira->codegen, field_type, - is_const, is_volatile, PtrLenSingle, 0, 0, 0, false); - } else { - ResolveStatus needed_resolve_status = - (struct_type->data.structure.layout == ContainerLayoutAuto) ? - ResolveStatusZeroBitsKnown : ResolveStatusSizeKnown; - if ((err = type_resolve(ira->codegen, struct_type, needed_resolve_status))) - return ira->codegen->invalid_inst_gen; - assert(struct_ptr->value->type->id == ZigTypeIdPointer); - uint32_t ptr_bit_offset = struct_ptr->value->type->data.pointer.bit_offset_in_host; - uint32_t ptr_host_int_bytes = struct_ptr->value->type->data.pointer.host_int_bytes; - if (ptr_host_int_bytes > 0) { - ptr_bit_offset += field->offset * 8; - } - uint32_t host_int_bytes_for_result_type = (ptr_host_int_bytes == 0) ? - get_host_int_bytes(ira->codegen, struct_type, field) : ptr_host_int_bytes; - ptr_type = get_pointer_to_type_extra(ira->codegen, field_type, - is_const, is_volatile, PtrLenSingle, field->align, - (uint32_t)(ptr_bit_offset + field->bit_offset_in_host), - (uint32_t)host_int_bytes_for_result_type, false); - - if (field == struct_type->data.structure.misaligned_field) { - // If field is the last single misaligned field it will be represented as array - // of bytes in LLVM but get_pointer_to_type_extra will set its host_int_bytes to 0. - // We need it not to be 0 so later stage would generate proper bit casting code. - ptr_type->data.pointer.host_int_bytes = host_int_bytes_for_result_type; - } - } - if (instr_is_comptime(struct_ptr)) { - ZigValue *ptr_val = ir_resolve_const(ira, struct_ptr, UndefBad); - if (!ptr_val) - return ira->codegen->invalid_inst_gen; - - if (ptr_val->data.x_ptr.special != ConstPtrSpecialHardCodedAddr) { - ZigValue *struct_val = const_ptr_pointee(ira, ira->codegen, ptr_val, source_node); - if (struct_val == nullptr) - return ira->codegen->invalid_inst_gen; - if (type_is_invalid(struct_val->type)) - return ira->codegen->invalid_inst_gen; - - // This to allow lazy values to be resolved. - if ((err = ir_resolve_const_val(ira->codegen, ira->new_irb.exec, - source_node, struct_val, UndefOk))) - { - return ira->codegen->invalid_inst_gen; - } - if (initializing && struct_val->special == ConstValSpecialUndef) { - struct_val->data.x_struct.fields = alloc_const_vals_ptrs(ira->codegen, struct_type->data.structure.src_field_count); - struct_val->special = ConstValSpecialStatic; - for (size_t i = 0; i < struct_type->data.structure.src_field_count; i += 1) { - if (struct_type->data.structure.fields[i]->is_comptime) - continue; - ZigValue *field_val = struct_val->data.x_struct.fields[i]; - field_val->special = ConstValSpecialUndef; - field_val->type = resolve_struct_field_type(ira->codegen, - struct_type->data.structure.fields[i]); - field_val->parent.id = ConstParentIdStruct; - field_val->parent.data.p_struct.struct_val = struct_val; - field_val->parent.data.p_struct.field_index = i; - } - } - Stage1AirInst *result; - if (ptr_val->data.x_ptr.mut == ConstPtrMutInfer) { - result = ir_build_struct_field_ptr(ira, scope, source_node, struct_ptr, field, ptr_type); - result->value->special = ConstValSpecialStatic; - } else { - result = ir_const(ira, scope, source_node, ptr_type); - } - ZigValue *const_val = result->value; - const_val->data.x_ptr.special = ConstPtrSpecialBaseStruct; - const_val->data.x_ptr.mut = ptr_val->data.x_ptr.mut; - const_val->data.x_ptr.data.base_struct.struct_val = struct_val; - const_val->data.x_ptr.data.base_struct.field_index = field->src_index; - return result; - } - } - return ir_build_struct_field_ptr(ira, scope, source_node, struct_ptr, field, ptr_type); -} - -static Stage1AirInst *ir_analyze_inferred_field_ptr(IrAnalyze *ira, Buf *field_name, - Scope *scope, AstNode *source_node, Stage1AirInst *container_ptr, ZigType *container_type) -{ - // The type of the field is not available until a store using this pointer happens. - // So, here we create a special pointer type which has the inferred struct type and - // field name encoded in the type. Later, when there is a store via this pointer, - // the field type will then be available, and the field will be added to the inferred - // struct. - - ZigType *container_ptr_type = container_ptr->value->type; - src_assert(container_ptr_type->id == ZigTypeIdPointer, source_node); - - InferredStructField *inferred_struct_field = heap::c_allocator.create(); - inferred_struct_field->inferred_struct_type = container_type; - inferred_struct_field->field_name = field_name; - - ZigType *elem_type = ira->codegen->builtin_types.entry_anytype; - ZigType *field_ptr_type = get_pointer_to_type_extra2(ira->codegen, elem_type, - container_ptr_type->data.pointer.is_const, container_ptr_type->data.pointer.is_volatile, - PtrLenSingle, 0, 0, 0, false, VECTOR_INDEX_NONE, inferred_struct_field, nullptr); - - if (instr_is_comptime(container_ptr)) { - ZigValue *ptr_val = ir_resolve_const(ira, container_ptr, UndefBad); - if (ptr_val == nullptr) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *result; - if (ptr_val->data.x_ptr.mut == ConstPtrMutInfer) { - result = ir_build_cast(ira, scope, source_node, container_ptr_type, container_ptr, CastOpNoop); - } else { - result = ir_const(ira, scope, source_node, field_ptr_type); - } - copy_const_val(ira->codegen, result->value, ptr_val); - result->value->type = field_ptr_type; - return result; - } - - return ir_build_cast(ira, scope, source_node, field_ptr_type, container_ptr, CastOpNoop); -} - -static Stage1AirInst *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field_name, - Scope *scope, AstNode *source_node, Stage1AirInst *container_ptr, AstNode *container_ptr_src, - ZigType *container_type, bool initializing) -{ - Error err; - - ZigType *bare_type = container_ref_type(container_type); - - if (initializing && bare_type->id == ZigTypeIdStruct && - bare_type->data.structure.resolve_status == ResolveStatusBeingInferred) - { - return ir_analyze_inferred_field_ptr(ira, field_name, scope, source_node, container_ptr, bare_type); - } - - // Tracks whether we should return an undefined value of the correct type. - // We do this if the container pointer is undefined and we are in a TypeOf call. - bool return_undef = container_ptr->value->special == ConstValSpecialUndef && \ - get_scope_typeof(scope) != nullptr; - - if ((err = type_resolve(ira->codegen, bare_type, ResolveStatusZeroBitsKnown))) - return ira->codegen->invalid_inst_gen; - - assert(container_ptr->value->type->id == ZigTypeIdPointer); - if (bare_type->id == ZigTypeIdStruct) { - TypeStructField *field = find_struct_type_field(bare_type, field_name); - if (field != nullptr) { - if (return_undef) { - ZigType *field_ptr_type = get_pointer_to_type(ira->codegen, resolve_struct_field_type(ira->codegen, field), - container_ptr->value->type->data.pointer.is_const); - return ir_const_undef(ira, scope, source_node, field_ptr_type); - } - - return ir_analyze_struct_field_ptr(ira, scope, source_node, field, container_ptr, bare_type, initializing); - } else { - return ir_analyze_container_member_access_inner(ira, bare_type, field_name, - scope, source_node, container_ptr, container_ptr_src, container_type); - } - } - - if (bare_type->id == ZigTypeIdEnum || bare_type->id == ZigTypeIdOpaque) { - return ir_analyze_container_member_access_inner(ira, bare_type, field_name, - scope, source_node, container_ptr, container_ptr_src, container_type); - } - - if (bare_type->id == ZigTypeIdUnion) { - bool is_const = container_ptr->value->type->data.pointer.is_const; - bool is_volatile = container_ptr->value->type->data.pointer.is_volatile; - - TypeUnionField *field = find_union_type_field(bare_type, field_name); - if (field == nullptr) { - return ir_analyze_container_member_access_inner(ira, bare_type, field_name, - scope, source_node, container_ptr, container_ptr_src, container_type); - } - - ZigType *field_type = resolve_union_field_type(ira->codegen, field); - if (field_type == nullptr) - return ira->codegen->invalid_inst_gen; - - ZigType *ptr_type = get_pointer_to_type_extra(ira->codegen, field_type, - is_const, is_volatile, PtrLenSingle, 0, 0, 0, false); - if (instr_is_comptime(container_ptr)) { - ZigValue *ptr_val = ir_resolve_const(ira, container_ptr, UndefBad); - if (!ptr_val) - return ira->codegen->invalid_inst_gen; - - if (ptr_val->data.x_ptr.mut != ConstPtrMutRuntimeVar && - ptr_val->data.x_ptr.special != ConstPtrSpecialHardCodedAddr) { - ZigValue *union_val = const_ptr_pointee(ira, ira->codegen, ptr_val, source_node); - if (union_val == nullptr) - return ira->codegen->invalid_inst_gen; - if (type_is_invalid(union_val->type)) - return ira->codegen->invalid_inst_gen; - - // Reject undefined values unless we're initializing the union: - // a undefined union means also the tag is undefined, accessing - // its payload slot is UB. - const UndefAllowed allow_undef = initializing ? UndefOk : UndefBad; - if ((err = ir_resolve_const_val(ira->codegen, ira->new_irb.exec, - source_node, union_val, allow_undef))) - { - return ira->codegen->invalid_inst_gen; - } - - if (initializing) { - ZigValue *payload_val = ira->codegen->pass1_arena->create(); - payload_val->special = ConstValSpecialUndef; - payload_val->type = field_type; - payload_val->parent.id = ConstParentIdUnion; - payload_val->parent.data.p_union.union_val = union_val; - - union_val->special = ConstValSpecialStatic; - bigint_init_bigint(&union_val->data.x_union.tag, &field->enum_field->value); - union_val->data.x_union.payload = payload_val; - } else if (bare_type->data.unionation.layout != ContainerLayoutExtern) { - TypeUnionField *actual_field = find_union_field_by_tag(bare_type, &union_val->data.x_union.tag); - if (actual_field == nullptr) - zig_unreachable(); - - if (field != actual_field) { - ir_add_error_node(ira, source_node, - buf_sprintf("accessing union field '%s' while field '%s' is set", buf_ptr(field_name), - buf_ptr(actual_field->name))); - return ira->codegen->invalid_inst_gen; - } - } - - ZigValue *payload_val = union_val->data.x_union.payload; - assert(payload_val); - - Stage1AirInst *result; - if (ptr_val->data.x_ptr.mut == ConstPtrMutInfer) { - result = ir_build_union_field_ptr(ira, scope, source_node, container_ptr, field, true, - initializing, ptr_type); - result->value->special = ConstValSpecialStatic; - } else { - result = ir_const(ira, scope, source_node, ptr_type); - } - ZigValue *const_val = result->value; - const_val->data.x_ptr.special = ConstPtrSpecialRef; - const_val->data.x_ptr.mut = container_ptr->value->data.x_ptr.mut; - const_val->data.x_ptr.data.ref.pointee = payload_val; - return result; - } - } - - return ir_build_union_field_ptr(ira, scope, source_node, container_ptr, field, true, initializing, ptr_type); - } - - zig_unreachable(); -} - -static void add_link_lib_symbol(IrAnalyze *ira, Buf *lib_name, Buf *symbol_name, AstNode *source_node) { - const char *msg = stage2_add_link_lib(&ira->codegen->stage1, buf_ptr(lib_name), buf_len(lib_name), - buf_ptr(symbol_name), buf_len(symbol_name)); - if (msg != nullptr) { - ir_add_error_node(ira, source_node, buf_create_from_str(msg)); - ira->codegen->reported_bad_link_libc_error = true; - } -} - -static Stage1AirInst *ir_error_dependency_loop(IrAnalyze *ira, AstNode* source_node) { - ir_add_error_node(ira, source_node, buf_sprintf("dependency loop detected")); - return ira->codegen->invalid_inst_gen; -} - -static Stage1AirInst *ir_analyze_decl_ref(IrAnalyze *ira, Scope *scope, AstNode *source_node, Tld *tld) { - resolve_top_level_decl(ira->codegen, tld, source_node, true); - if (tld->resolution == TldResolutionInvalid) { - return ira->codegen->invalid_inst_gen; - } - if (tld->resolution == TldResolutionResolving) - return ir_error_dependency_loop(ira, source_node); - - switch (tld->id) { - case TldIdContainer: - case TldIdCompTime: - case TldIdUsingNamespace: - zig_unreachable(); - case TldIdVar: { - TldVar *tld_var = (TldVar *)tld; - ZigVar *var = tld_var->var; - assert(var != nullptr); - - if (tld_var->extern_lib_name != nullptr) { - add_link_lib_symbol(ira, tld_var->extern_lib_name, buf_create_from_str(var->name), - source_node); - } - - return ir_get_var_ptr(ira, scope, source_node, var); - } - case TldIdFn: { - TldFn *tld_fn = (TldFn *)tld; - ZigFn *fn_entry = tld_fn->fn_entry; - assert(fn_entry->type_entry != nullptr); - - if (type_is_invalid(fn_entry->type_entry)) - return ira->codegen->invalid_inst_gen; - - if (tld_fn->extern_lib_name != nullptr) { - add_link_lib_symbol(ira, tld_fn->extern_lib_name, &fn_entry->symbol_name, source_node); - } - - Stage1AirInst *fn_inst = ir_const_fn(ira, scope, source_node, fn_entry); - return ir_get_ref(ira, scope, source_node, fn_inst, true, false); - } - } - zig_unreachable(); -} - -static ErrorTableEntry *find_err_table_entry(ZigType *err_set_type, Buf *field_name) { - assert(err_set_type->id == ZigTypeIdErrorSet); - for (uint32_t i = 0; i < err_set_type->data.error_set.err_count; i += 1) { - ErrorTableEntry *err_table_entry = err_set_type->data.error_set.errors[i]; - if (buf_eql_buf(&err_table_entry->name, field_name)) { - return err_table_entry; - } - } - return nullptr; -} - -static Stage1AirInst *ir_analyze_instruction_field_ptr(IrAnalyze *ira, Stage1ZirInstFieldPtr *field_ptr_instruction) { - Error err; - Stage1AirInst *container_ptr = field_ptr_instruction->container_ptr->child; - if (type_is_invalid(container_ptr->value->type)) - return ira->codegen->invalid_inst_gen; - - ZigType *container_type = container_ptr->value->type->data.pointer.child_type; - - Buf *field_name = field_ptr_instruction->field_name_buffer; - if (!field_name) { - Stage1AirInst *field_name_expr = field_ptr_instruction->field_name_expr->child; - field_name = ir_resolve_str(ira, field_name_expr); - if (!field_name) - return ira->codegen->invalid_inst_gen; - } - - - AstNode *source_node = field_ptr_instruction->base.source_node; - - if (type_is_invalid(container_type)) { - return ira->codegen->invalid_inst_gen; - } else if (is_tuple(container_type) && !field_ptr_instruction->initializing && buf_eql_str(field_name, "len")) { - Stage1AirInst *len_inst = ir_const_unsigned(ira, field_ptr_instruction->base.scope, field_ptr_instruction->base.source_node, - container_type->data.structure.src_field_count); - return ir_get_ref(ira, field_ptr_instruction->base.scope, field_ptr_instruction->base.source_node, len_inst, true, false); - } else if (is_slice(container_type) || is_container_ref(container_type)) { - assert(container_ptr->value->type->id == ZigTypeIdPointer); - if (container_type->id == ZigTypeIdPointer) { - ZigType *bare_type = container_ref_type(container_type); - Stage1AirInst *container_child = ir_get_deref(ira, field_ptr_instruction->base.scope, - field_ptr_instruction->base.source_node, container_ptr, nullptr); - Stage1AirInst *result = ir_analyze_container_field_ptr(ira, field_name, - field_ptr_instruction->base.scope, field_ptr_instruction->base.source_node, - container_child, field_ptr_instruction->container_ptr->source_node, bare_type, - field_ptr_instruction->initializing); - return result; - } else { - Stage1AirInst *result = ir_analyze_container_field_ptr(ira, field_name, - field_ptr_instruction->base.scope, field_ptr_instruction->base.source_node, - container_ptr, field_ptr_instruction->container_ptr->source_node, - container_type, field_ptr_instruction->initializing); - return result; - } - } else if (is_array_ref(container_type) && !field_ptr_instruction->initializing) { - if (buf_eql_str(field_name, "len")) { - ZigValue *len_val = ira->codegen->pass1_arena->create(); - if (container_type->id == ZigTypeIdPointer) { - init_const_usize(ira->codegen, len_val, container_type->data.pointer.child_type->data.array.len); - } else { - init_const_usize(ira->codegen, len_val, container_type->data.array.len); - } - - ZigType *usize = ira->codegen->builtin_types.entry_usize; - bool ptr_is_const = true; - bool ptr_is_volatile = false; - return ir_get_const_ptr(ira, field_ptr_instruction->base.scope, field_ptr_instruction->base.source_node, len_val, - usize, ConstPtrMutComptimeConst, ptr_is_const, ptr_is_volatile, 0); - } else { - ir_add_error_node(ira, source_node, - buf_sprintf("no field named '%s' in '%s'", buf_ptr(field_name), - buf_ptr(&container_type->name))); - return ira->codegen->invalid_inst_gen; - } - } else if (container_type->id == ZigTypeIdMetaType) { - ZigValue *container_ptr_val = ir_resolve_const(ira, container_ptr, UndefBad); - if (!container_ptr_val) - return ira->codegen->invalid_inst_gen; - - assert(container_ptr->value->type->id == ZigTypeIdPointer); - ZigValue *child_val = const_ptr_pointee(ira, ira->codegen, container_ptr_val, source_node); - if (child_val == nullptr) - return ira->codegen->invalid_inst_gen; - if ((err = ir_resolve_const_val(ira->codegen, ira->new_irb.exec, - field_ptr_instruction->base.source_node, child_val, UndefBad))) - { - return ira->codegen->invalid_inst_gen; - } - ZigType *child_type = child_val->data.x_type; - - if (type_is_invalid(child_type)) { - return ira->codegen->invalid_inst_gen; - } else if (is_container(child_type)) { - if (child_type->id == ZigTypeIdEnum) { - if ((err = type_resolve(ira->codegen, child_type, ResolveStatusSizeKnown))) - return ira->codegen->invalid_inst_gen; - - TypeEnumField *field = find_enum_type_field(child_type, field_name); - if (field) { - bool ptr_is_const = true; - bool ptr_is_volatile = false; - return ir_get_const_ptr(ira, field_ptr_instruction->base.scope, field_ptr_instruction->base.source_node, - create_const_enum(ira->codegen, child_type, &field->value), child_type, - ConstPtrMutComptimeConst, ptr_is_const, ptr_is_volatile, 0); - } - } - ScopeDecls *container_scope = get_container_scope(child_type); - Tld *tld = find_container_decl(ira->codegen, container_scope, field_name); - if (tld) { - if (tld->visib_mod == VisibModPrivate && - tld->import != get_scope_import(field_ptr_instruction->base.scope)) - { - ErrorMsg *msg = ir_add_error_node(ira, field_ptr_instruction->base.source_node, - buf_sprintf("'%s' is private", buf_ptr(field_name))); - add_error_note(ira->codegen, msg, tld->source_node, buf_sprintf("declared here")); - return ira->codegen->invalid_inst_gen; - } - return ir_analyze_decl_ref(ira, field_ptr_instruction->base.scope, field_ptr_instruction->base.source_node, tld); - } - if (is_tagged_union(child_type)) { - if ((err = type_resolve(ira->codegen, child_type, ResolveStatusSizeKnown))) - return ira->codegen->invalid_inst_gen; - TypeUnionField *field = find_union_type_field(child_type, field_name); - if (field) { - ZigType *enum_type = child_type->data.unionation.tag_type; - bool ptr_is_const = true; - bool ptr_is_volatile = false; - return ir_get_const_ptr(ira, field_ptr_instruction->base.scope, field_ptr_instruction->base.source_node, - create_const_enum(ira->codegen, enum_type, &field->enum_field->value), enum_type, - ConstPtrMutComptimeConst, ptr_is_const, ptr_is_volatile, 0); - } - } - const char *container_name = (child_type == ira->codegen->root_import) ? - "root source file" : buf_ptr(buf_sprintf("container '%s'", buf_ptr(&child_type->name))); - ir_add_error_node(ira, field_ptr_instruction->base.source_node, - buf_sprintf("%s has no member called '%s'", - container_name, buf_ptr(field_name))); - return ira->codegen->invalid_inst_gen; - } else if (child_type->id == ZigTypeIdErrorSet) { - ErrorTableEntry *err_entry; - ZigType *err_set_type; - if (type_is_global_error_set(child_type)) { - auto existing_entry = ira->codegen->error_table.maybe_get(field_name); - if (existing_entry) { - err_entry = existing_entry->value; - } else { - err_entry = heap::c_allocator.create(); - err_entry->decl_node = field_ptr_instruction->base.source_node; - buf_init_from_buf(&err_entry->name, field_name); - size_t error_value_count = ira->codegen->errors_by_index.length; - assert((uint32_t)error_value_count < (((uint32_t)1) << (uint32_t)ira->codegen->err_tag_type->data.integral.bit_count)); - err_entry->value = error_value_count; - ira->codegen->errors_by_index.append(err_entry); - ira->codegen->error_table.put(field_name, err_entry); - } - if (err_entry->set_with_only_this_in_it == nullptr) { - err_entry->set_with_only_this_in_it = make_err_set_with_one_item(ira->codegen, - field_ptr_instruction->base.scope, field_ptr_instruction->base.source_node, - err_entry); - } - err_set_type = err_entry->set_with_only_this_in_it; - } else { - if (!resolve_inferred_error_set(ira->codegen, child_type, field_ptr_instruction->base.source_node)) { - return ira->codegen->invalid_inst_gen; - } - err_entry = find_err_table_entry(child_type, field_name); - if (err_entry == nullptr) { - ir_add_error_node(ira, field_ptr_instruction->base.source_node, - buf_sprintf("no error named '%s' in '%s'", buf_ptr(field_name), buf_ptr(&child_type->name))); - return ira->codegen->invalid_inst_gen; - } - err_set_type = child_type; - } - ZigValue *const_val = ira->codegen->pass1_arena->create(); - const_val->special = ConstValSpecialStatic; - const_val->type = err_set_type; - const_val->data.x_err_set = err_entry; - - bool ptr_is_const = true; - bool ptr_is_volatile = false; - return ir_get_const_ptr(ira, field_ptr_instruction->base.scope, - field_ptr_instruction->base.source_node, const_val, - err_set_type, ConstPtrMutComptimeConst, ptr_is_const, ptr_is_volatile, 0); - } else { - ir_add_error_node(ira, field_ptr_instruction->base.source_node, - buf_sprintf("type '%s' does not support field access", buf_ptr(&container_type->name))); - return ira->codegen->invalid_inst_gen; - } - } else if (field_ptr_instruction->initializing) { - ir_add_error_node(ira, field_ptr_instruction->base.source_node, - buf_sprintf("type '%s' does not support struct initialization syntax", buf_ptr(&container_type->name))); - return ira->codegen->invalid_inst_gen; - } else { - ir_add_error_node(ira, field_ptr_instruction->base.source_node, - buf_sprintf("type '%s' does not support field access", buf_ptr(&container_type->name))); - return ira->codegen->invalid_inst_gen; - } -} - -static Stage1AirInst *ir_analyze_instruction_store_ptr(IrAnalyze *ira, Stage1ZirInstStorePtr *instruction) { - Stage1AirInst *ptr = instruction->ptr->child; - if (type_is_invalid(ptr->value->type)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *value = instruction->value->child; - if (type_is_invalid(value->value->type)) - return ira->codegen->invalid_inst_gen; - - return ir_analyze_store_ptr(ira, instruction->base.scope, instruction->base.source_node, ptr, value, instruction->allow_write_through_const); -} - -static Stage1AirInst *ir_analyze_instruction_load_ptr(IrAnalyze *ira, Stage1ZirInstLoadPtr *instruction) { - Stage1AirInst *ptr = instruction->ptr->child; - if (type_is_invalid(ptr->value->type)) - return ira->codegen->invalid_inst_gen; - return ir_get_deref(ira, instruction->base.scope, instruction->base.source_node, ptr, nullptr); -} - -static Stage1AirInst *ir_analyze_instruction_typeof(IrAnalyze *ira, Stage1ZirInstTypeOf *typeof_instruction) { - ZigType *type_entry; - - const size_t value_count = typeof_instruction->value_count; - - // Fast path for the common case of TypeOf with a single argument - if (value_count < 2) { - type_entry = typeof_instruction->value.scalar->child->value->type; - } else { - Stage1AirInst **args = heap::c_allocator.allocate(value_count); - for (size_t i = 0; i < value_count; i += 1) { - Stage1AirInst *value = typeof_instruction->value.list[i]->child; - if (type_is_invalid(value->value->type)) - return ira->codegen->invalid_inst_gen; - args[i] = value; - } - - type_entry = ir_resolve_peer_types(ira, typeof_instruction->base.source_node, - nullptr, args, value_count); - - heap::c_allocator.deallocate(args, value_count); - } - - if (type_is_invalid(type_entry)) - return ira->codegen->invalid_inst_gen; - - return ir_const_type(ira, typeof_instruction->base.scope, typeof_instruction->base.source_node, type_entry); -} - -static Stage1AirInst *ir_analyze_instruction_set_cold(IrAnalyze *ira, Stage1ZirInstSetCold *instruction) { - if (ira->new_irb.exec->is_inline) { - // ignore setCold when running functions at compile time - return ir_const_void(ira, instruction->base.scope, instruction->base.source_node); - } - - Stage1AirInst *is_cold_value = instruction->is_cold->child; - bool want_cold; - if (!ir_resolve_bool(ira, is_cold_value, &want_cold)) - return ira->codegen->invalid_inst_gen; - - ZigFn *fn_entry = scope_fn_entry(instruction->base.scope); - if (fn_entry == nullptr) { - ir_add_error_node(ira, instruction->base.source_node, buf_sprintf("@setCold outside function")); - return ira->codegen->invalid_inst_gen; - } - - if (fn_entry->set_cold_node != nullptr) { - ErrorMsg *msg = ir_add_error_node(ira, instruction->base.source_node, buf_sprintf("cold set twice in same function")); - add_error_note(ira->codegen, msg, fn_entry->set_cold_node, buf_sprintf("first set here")); - return ira->codegen->invalid_inst_gen; - } - - fn_entry->set_cold_node = instruction->base.source_node; - fn_entry->is_cold = want_cold; - - return ir_const_void(ira, instruction->base.scope, instruction->base.source_node); -} - -static Stage1AirInst *ir_analyze_instruction_set_runtime_safety(IrAnalyze *ira, - Stage1ZirInstSetRuntimeSafety *set_runtime_safety_instruction) -{ - if (ira->new_irb.exec->is_inline) { - // ignore setRuntimeSafety when running functions at compile time - return ir_const_void(ira, set_runtime_safety_instruction->base.scope, - set_runtime_safety_instruction->base.source_node); - } - - bool *safety_off_ptr; - AstNode **safety_set_node_ptr; - - Scope *scope = set_runtime_safety_instruction->base.scope; - while (scope != nullptr) { - if (scope->id == ScopeIdBlock) { - ScopeBlock *block_scope = (ScopeBlock *)scope; - safety_off_ptr = &block_scope->safety_off; - safety_set_node_ptr = &block_scope->safety_set_node; - break; - } else if (scope->id == ScopeIdFnDef) { - ScopeFnDef *def_scope = (ScopeFnDef *)scope; - ZigFn *target_fn = def_scope->fn_entry; - assert(target_fn->def_scope != nullptr); - safety_off_ptr = &target_fn->def_scope->safety_off; - safety_set_node_ptr = &target_fn->def_scope->safety_set_node; - break; - } else if (scope->id == ScopeIdDecls) { - ScopeDecls *decls_scope = (ScopeDecls *)scope; - safety_off_ptr = &decls_scope->safety_off; - safety_set_node_ptr = &decls_scope->safety_set_node; - break; - } else { - scope = scope->parent; - continue; - } - } - assert(scope != nullptr); - - Stage1AirInst *safety_on_value = set_runtime_safety_instruction->safety_on->child; - bool want_runtime_safety; - if (!ir_resolve_bool(ira, safety_on_value, &want_runtime_safety)) - return ira->codegen->invalid_inst_gen; - - AstNode *source_node = set_runtime_safety_instruction->base.source_node; - if (*safety_set_node_ptr) { - ErrorMsg *msg = ir_add_error_node(ira, source_node, - buf_sprintf("runtime safety set twice for same scope")); - add_error_note(ira->codegen, msg, *safety_set_node_ptr, buf_sprintf("first set here")); - return ira->codegen->invalid_inst_gen; - } - *safety_set_node_ptr = source_node; - *safety_off_ptr = !want_runtime_safety; - - return ir_const_void(ira, set_runtime_safety_instruction->base.scope, - set_runtime_safety_instruction->base.source_node); -} - -static Stage1AirInst *ir_analyze_instruction_set_float_mode(IrAnalyze *ira, - Stage1ZirInstSetFloatMode *instruction) -{ - if (ira->new_irb.exec->is_inline) { - // ignore setFloatMode when running functions at compile time - return ir_const_void(ira, instruction->base.scope, instruction->base.source_node); - } - - bool *fast_math_on_ptr; - AstNode **fast_math_set_node_ptr; - - Scope *scope = instruction->base.scope; - while (scope != nullptr) { - if (scope->id == ScopeIdBlock) { - ScopeBlock *block_scope = (ScopeBlock *)scope; - fast_math_on_ptr = &block_scope->fast_math_on; - fast_math_set_node_ptr = &block_scope->fast_math_set_node; - break; - } else if (scope->id == ScopeIdFnDef) { - ScopeFnDef *def_scope = (ScopeFnDef *)scope; - ZigFn *target_fn = def_scope->fn_entry; - assert(target_fn->def_scope != nullptr); - fast_math_on_ptr = &target_fn->def_scope->fast_math_on; - fast_math_set_node_ptr = &target_fn->def_scope->fast_math_set_node; - break; - } else if (scope->id == ScopeIdDecls) { - ScopeDecls *decls_scope = (ScopeDecls *)scope; - fast_math_on_ptr = &decls_scope->fast_math_on; - fast_math_set_node_ptr = &decls_scope->fast_math_set_node; - break; - } else { - scope = scope->parent; - continue; - } - } - assert(scope != nullptr); - - Stage1AirInst *float_mode_value = instruction->mode_value->child; - FloatMode float_mode_scalar; - if (!ir_resolve_float_mode(ira, float_mode_value, &float_mode_scalar)) - return ira->codegen->invalid_inst_gen; - - AstNode *source_node = instruction->base.source_node; - if (*fast_math_set_node_ptr) { - ErrorMsg *msg = ir_add_error_node(ira, source_node, - buf_sprintf("float mode set twice for same scope")); - add_error_note(ira->codegen, msg, *fast_math_set_node_ptr, buf_sprintf("first set here")); - return ira->codegen->invalid_inst_gen; - } - *fast_math_set_node_ptr = source_node; - *fast_math_on_ptr = (float_mode_scalar == FloatModeOptimized); - - return ir_const_void(ira, instruction->base.scope, instruction->base.source_node); -} - -static Stage1AirInst *ir_analyze_instruction_any_frame_type(IrAnalyze *ira, Stage1ZirInstAnyFrameType *instruction) { - ZigType *payload_type = nullptr; - if (instruction->payload_type != nullptr) { - payload_type = ir_resolve_type(ira, instruction->payload_type->child); - if (type_is_invalid(payload_type)) - return ira->codegen->invalid_inst_gen; - } - - ZigType *any_frame_type = get_any_frame_type(ira->codegen, payload_type); - return ir_const_type(ira, instruction->base.scope, instruction->base.source_node, any_frame_type); -} - -static Stage1AirInst *ir_analyze_instruction_slice_type(IrAnalyze *ira, Stage1ZirInstSliceType *slice_type_instruction) { - Stage1AirInst *result = ir_const(ira, slice_type_instruction->base.scope, - slice_type_instruction->base.source_node, ira->codegen->builtin_types.entry_type); - result->value->special = ConstValSpecialLazy; - - LazyValueSliceType *lazy_slice_type = heap::c_allocator.create(); - lazy_slice_type->ira = ira; ira_ref(ira); - result->value->data.x_lazy = &lazy_slice_type->base; - lazy_slice_type->base.id = LazyValueIdSliceType; - - if (slice_type_instruction->align_value != nullptr) { - lazy_slice_type->align_inst = slice_type_instruction->align_value->child; - if (ir_resolve_const(ira, lazy_slice_type->align_inst, LazyOk) == nullptr) - return ira->codegen->invalid_inst_gen; - } - - if (slice_type_instruction->sentinel != nullptr) { - lazy_slice_type->sentinel = slice_type_instruction->sentinel->child; - if (ir_resolve_const(ira, lazy_slice_type->sentinel, LazyOk) == nullptr) - return ira->codegen->invalid_inst_gen; - } - - lazy_slice_type->elem_type = slice_type_instruction->child_type->child; - if (ir_resolve_type_lazy(ira, lazy_slice_type->elem_type) == nullptr) - return ira->codegen->invalid_inst_gen; - - lazy_slice_type->is_const = slice_type_instruction->is_const; - lazy_slice_type->is_volatile = slice_type_instruction->is_volatile; - lazy_slice_type->is_allowzero = slice_type_instruction->is_allow_zero; - - return result; -} - -static size_t find_asm_index(CodeGen *g, AstNode *node, AsmToken *tok, Buf *src_template) { - const char *ptr = buf_ptr(src_template) + tok->start + 2; - size_t len = tok->end - tok->start - 2; - size_t result = 0; - for (size_t i = 0; i < node->data.asm_expr.output_list.length; i += 1, result += 1) { - AsmOutput *asm_output = node->data.asm_expr.output_list.at(i); - if (buf_eql_mem(asm_output->asm_symbolic_name, ptr, len)) { - return result; - } - } - for (size_t i = 0; i < node->data.asm_expr.input_list.length; i += 1, result += 1) { - AsmInput *asm_input = node->data.asm_expr.input_list.at(i); - if (buf_eql_mem(asm_input->asm_symbolic_name, ptr, len)) { - return result; - } - } - return SIZE_MAX; -} - -static Stage1AirInst *ir_analyze_instruction_asm(IrAnalyze *ira, Stage1ZirInstAsm *asm_instruction) { - Error err; - - assert(asm_instruction->base.source_node->type == NodeTypeAsmExpr); - - AstNode *node = asm_instruction->base.source_node; - AstNodeAsmExpr *asm_expr = &asm_instruction->base.source_node->data.asm_expr; - - Buf *template_buf = ir_resolve_str(ira, asm_instruction->asm_template->child); - if (template_buf == nullptr) - return ira->codegen->invalid_inst_gen; - - if (asm_instruction->is_global) { - buf_append_char(&ira->codegen->global_asm, '\n'); - buf_append_buf(&ira->codegen->global_asm, template_buf); - - return ir_const_void(ira, asm_instruction->base.scope, asm_instruction->base.source_node); - } - - if (!ir_emit_global_runtime_side_effect(ira, &asm_instruction->base)) - return ira->codegen->invalid_inst_gen; - - ZigList tok_list = {}; - if ((err = parse_asm_template(ira, node, template_buf, &tok_list))) { - return ira->codegen->invalid_inst_gen; - } - - for (size_t token_i = 0; token_i < tok_list.length; token_i += 1) { - AsmToken asm_token = tok_list.at(token_i); - if (asm_token.id == AsmTokenIdVar) { - size_t index = find_asm_index(ira->codegen, node, &asm_token, template_buf); - if (index == SIZE_MAX) { - const char *ptr = buf_ptr(template_buf) + asm_token.start + 2; - uint32_t len = asm_token.end - asm_token.start - 2; - - add_node_error(ira->codegen, node, - buf_sprintf("could not find '%.*s' in the inputs or outputs", - len, ptr)); - return ira->codegen->invalid_inst_gen; - } - } - } - - // TODO validate the output types and variable types - - Stage1AirInst **input_list = heap::c_allocator.allocate(asm_expr->input_list.length); - Stage1AirInst **output_types = heap::c_allocator.allocate(asm_expr->output_list.length); - - ZigType *return_type = ira->codegen->builtin_types.entry_void; - for (size_t i = 0; i < asm_expr->output_list.length; i += 1) { - AsmOutput *asm_output = asm_expr->output_list.at(i); - if (asm_output->return_type) { - output_types[i] = asm_instruction->output_types[i]->child; - return_type = ir_resolve_type(ira, output_types[i]); - if (type_is_invalid(return_type)) - return ira->codegen->invalid_inst_gen; - } - } - - for (size_t i = 0; i < asm_expr->input_list.length; i += 1) { - Stage1AirInst *const input_value = asm_instruction->input_list[i]->child; - if (type_is_invalid(input_value->value->type)) - return ira->codegen->invalid_inst_gen; - - if (instr_is_comptime(input_value) && - (input_value->value->type->id == ZigTypeIdComptimeInt || - input_value->value->type->id == ZigTypeIdComptimeFloat)) { - ir_add_error(ira, input_value, - buf_sprintf("expected sized integer or sized float, found %s", buf_ptr(&input_value->value->type->name))); - return ira->codegen->invalid_inst_gen; - } - - input_list[i] = input_value; - } - - return ir_build_asm_gen(ira, asm_instruction->base.scope, asm_instruction->base.source_node, - template_buf, tok_list.items, tok_list.length, - input_list, output_types, asm_instruction->output_vars, asm_instruction->return_count, - asm_instruction->has_side_effects, return_type); -} - -static Stage1AirInst *ir_analyze_instruction_array_type(IrAnalyze *ira, Stage1ZirInstArrayType *array_type_instruction) { - Stage1AirInst *result = ir_const(ira, array_type_instruction->base.scope, - array_type_instruction->base.source_node, ira->codegen->builtin_types.entry_type); - result->value->special = ConstValSpecialLazy; - - LazyValueArrayType *lazy_array_type = heap::c_allocator.create(); - lazy_array_type->ira = ira; ira_ref(ira); - result->value->data.x_lazy = &lazy_array_type->base; - lazy_array_type->base.id = LazyValueIdArrayType; - - lazy_array_type->elem_type = array_type_instruction->child_type->child; - if (ir_resolve_type_lazy(ira, lazy_array_type->elem_type) == nullptr) - return ira->codegen->invalid_inst_gen; - - if (!ir_resolve_usize(ira, array_type_instruction->size->child, &lazy_array_type->length)) - return ira->codegen->invalid_inst_gen; - - if (array_type_instruction->sentinel != nullptr) { - lazy_array_type->sentinel = array_type_instruction->sentinel->child; - if (ir_resolve_const(ira, lazy_array_type->sentinel, LazyOk) == nullptr) - return ira->codegen->invalid_inst_gen; - } - - return result; -} - -static Stage1AirInst *ir_analyze_instruction_size_of(IrAnalyze *ira, Stage1ZirInstSizeOf *instruction) { - Stage1AirInst *result = ir_const(ira, instruction->base.scope, instruction->base.source_node, ira->codegen->builtin_types.entry_num_lit_int); - result->value->special = ConstValSpecialLazy; - - LazyValueSizeOf *lazy_size_of = heap::c_allocator.create(); - lazy_size_of->ira = ira; ira_ref(ira); - result->value->data.x_lazy = &lazy_size_of->base; - lazy_size_of->base.id = LazyValueIdSizeOf; - lazy_size_of->bit_size = instruction->bit_size; - - lazy_size_of->target_type = instruction->type_value->child; - if (ir_resolve_type_lazy(ira, lazy_size_of->target_type) == nullptr) - return ira->codegen->invalid_inst_gen; - - return result; -} - -static Stage1AirInst *ir_analyze_test_non_null(IrAnalyze *ira, Scope *scope, AstNode *source_node, Stage1AirInst *value) { - ZigType *type_entry = value->value->type; - - if (type_entry->id == ZigTypeIdPointer && type_entry->data.pointer.allow_zero) { - if (instr_is_comptime(value)) { - ZigValue *c_ptr_val = ir_resolve_const(ira, value, UndefOk); - if (c_ptr_val == nullptr) - return ira->codegen->invalid_inst_gen; - if (c_ptr_val->special == ConstValSpecialUndef) - return ir_const_undef(ira, scope, source_node, ira->codegen->builtin_types.entry_bool); - bool is_null = c_ptr_val->data.x_ptr.special == ConstPtrSpecialNull || - (c_ptr_val->data.x_ptr.special == ConstPtrSpecialHardCodedAddr && - c_ptr_val->data.x_ptr.data.hard_coded_addr.addr == 0); - return ir_const_bool(ira, scope, source_node, !is_null); - } - - return ir_build_test_non_null_gen(ira, scope, source_node, value); - } else if (type_entry->id == ZigTypeIdOptional) { - if (instr_is_comptime(value)) { - ZigValue *maybe_val = ir_resolve_const(ira, value, UndefOk); - if (maybe_val == nullptr) - return ira->codegen->invalid_inst_gen; - if (maybe_val->special == ConstValSpecialUndef) - return ir_const_undef(ira, scope, source_node, ira->codegen->builtin_types.entry_bool); - - return ir_const_bool(ira, scope, source_node, !optional_value_is_null(maybe_val)); - } - - return ir_build_test_non_null_gen(ira, scope, source_node, value); - } else if (type_entry->id == ZigTypeIdNull) { - return ir_const_bool(ira, scope, source_node, false); - } else { - return ir_const_bool(ira, scope, source_node, true); - } -} - -static Stage1AirInst *ir_analyze_instruction_test_non_null(IrAnalyze *ira, Stage1ZirInstTestNonNull *instruction) { - Stage1AirInst *value = instruction->value->child; - if (type_is_invalid(value->value->type)) - return ira->codegen->invalid_inst_gen; - - return ir_analyze_test_non_null(ira, instruction->base.scope, instruction->base.source_node, value); -} - -static Stage1AirInst *ir_analyze_unwrap_optional_payload(IrAnalyze *ira, Scope *scope, AstNode *source_node, - Stage1AirInst *base_ptr, bool safety_check_on, bool initializing) -{ - Error err; - - ZigType *type_entry = get_ptr_elem_type(ira->codegen, base_ptr); - if (type_is_invalid(type_entry)) - return ira->codegen->invalid_inst_gen; - - if (type_entry->id == ZigTypeIdPointer && type_entry->data.pointer.ptr_len == PtrLenC) { - if (instr_is_comptime(base_ptr)) { - ZigValue *val = ir_resolve_const(ira, base_ptr, UndefBad); - if (!val) - return ira->codegen->invalid_inst_gen; - if (val->data.x_ptr.mut != ConstPtrMutRuntimeVar) { - ZigValue *c_ptr_val = const_ptr_pointee(ira, ira->codegen, val, source_node); - if (c_ptr_val == nullptr) - return ira->codegen->invalid_inst_gen; - bool is_null = c_ptr_val->data.x_ptr.special == ConstPtrSpecialNull || - (c_ptr_val->data.x_ptr.special == ConstPtrSpecialHardCodedAddr && - c_ptr_val->data.x_ptr.data.hard_coded_addr.addr == 0); - if (is_null) { - ir_add_error_node(ira, source_node, buf_sprintf("unable to unwrap null")); - return ira->codegen->invalid_inst_gen; - } - return base_ptr; - } - } - if (!safety_check_on) - return base_ptr; - Stage1AirInst *c_ptr_val = ir_get_deref(ira, scope, source_node, base_ptr, nullptr); - ir_build_assert_non_null(ira, scope, source_node, c_ptr_val); - return base_ptr; - } - - if (type_entry->id != ZigTypeIdOptional) { - ir_add_error(ira, base_ptr, - buf_sprintf("expected optional type, found '%s'", buf_ptr(&type_entry->name))); - return ira->codegen->invalid_inst_gen; - } - - ZigType *child_type = type_entry->data.maybe.child_type; - ZigType *result_type = get_pointer_to_type_extra(ira->codegen, child_type, - base_ptr->value->type->data.pointer.is_const, base_ptr->value->type->data.pointer.is_volatile, - PtrLenSingle, 0, 0, 0, false); - - bool same_comptime_repr = types_have_same_zig_comptime_repr(ira->codegen, child_type, type_entry); - - if (instr_is_comptime(base_ptr)) { - ZigValue *ptr_val = ir_resolve_const(ira, base_ptr, UndefBad); - if (ptr_val == nullptr) - return ira->codegen->invalid_inst_gen; - if (ptr_val->data.x_ptr.mut != ConstPtrMutRuntimeVar) { - ZigValue *optional_val = const_ptr_pointee(ira, ira->codegen, ptr_val, source_node); - if (optional_val == nullptr) - return ira->codegen->invalid_inst_gen; - - if (initializing) { - switch (type_has_one_possible_value(ira->codegen, child_type)) { - case OnePossibleValueInvalid: - return ira->codegen->invalid_inst_gen; - case OnePossibleValueNo: - if (!same_comptime_repr) { - ZigValue *payload_val = ira->codegen->pass1_arena->create(); - payload_val->type = child_type; - payload_val->special = ConstValSpecialUndef; - payload_val->parent.id = ConstParentIdOptionalPayload; - payload_val->parent.data.p_optional_payload.optional_val = optional_val; - - optional_val->data.x_optional = payload_val; - optional_val->special = ConstValSpecialStatic; - } - break; - case OnePossibleValueYes: { - optional_val->special = ConstValSpecialStatic; - optional_val->data.x_optional = get_the_one_possible_value(ira->codegen, child_type); - break; - } - } - } else { - if ((err = ir_resolve_const_val(ira->codegen, ira->new_irb.exec, - source_node, optional_val, UndefBad))) - return ira->codegen->invalid_inst_gen; - if (optional_value_is_null(optional_val)) { - ir_add_error_node(ira, source_node, buf_sprintf("unable to unwrap null")); - return ira->codegen->invalid_inst_gen; - } - } - - Stage1AirInst *result; - if (ptr_val->data.x_ptr.mut == ConstPtrMutInfer) { - result = ir_build_optional_unwrap_ptr_gen(ira, scope, source_node, base_ptr, false, - initializing, result_type); - result->value->special = ConstValSpecialStatic; - } else { - result = ir_const(ira, scope, source_node, result_type); - } - ZigValue *result_val = result->value; - result_val->data.x_ptr.special = ConstPtrSpecialRef; - result_val->data.x_ptr.mut = ptr_val->data.x_ptr.mut; - switch (type_has_one_possible_value(ira->codegen, child_type)) { - case OnePossibleValueInvalid: - return ira->codegen->invalid_inst_gen; - case OnePossibleValueNo: - if (same_comptime_repr) { - result_val->data.x_ptr.data.ref.pointee = optional_val; - } else { - assert(optional_val->data.x_optional != nullptr); - result_val->data.x_ptr.data.ref.pointee = optional_val->data.x_optional; - } - break; - case OnePossibleValueYes: - assert(optional_val->data.x_optional != nullptr); - result_val->data.x_ptr.data.ref.pointee = optional_val->data.x_optional; - break; - } - return result; - } - } - - return ir_build_optional_unwrap_ptr_gen(ira, scope, source_node, base_ptr, safety_check_on, - initializing, result_type); -} - -static Stage1AirInst *ir_analyze_instruction_optional_unwrap_ptr(IrAnalyze *ira, - Stage1ZirInstOptionalUnwrapPtr *instruction) -{ - Stage1AirInst *base_ptr = instruction->base_ptr->child; - if (type_is_invalid(base_ptr->value->type)) - return ira->codegen->invalid_inst_gen; - - return ir_analyze_unwrap_optional_payload(ira, instruction->base.scope, instruction->base.source_node, base_ptr, - instruction->safety_check_on, false); -} - -static Stage1AirInst *ir_analyze_instruction_ctz(IrAnalyze *ira, Stage1ZirInstCtz *instruction) { - Error err; - - ZigType *int_type = ir_resolve_int_type(ira, instruction->type->child); - if (type_is_invalid(int_type)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *uncasted_op = instruction->op->child; - if (type_is_invalid(uncasted_op->value->type)) - return ira->codegen->invalid_inst_gen; - - uint32_t vector_len = UINT32_MAX; // means not a vector - if (uncasted_op->value->type->id == ZigTypeIdArray) { - bool can_be_vec_elem; - if ((err = is_valid_vector_elem_type(ira->codegen, uncasted_op->value->type->data.array.child_type, - &can_be_vec_elem))) - { - return ira->codegen->invalid_inst_gen; - } - if (can_be_vec_elem) { - vector_len = uncasted_op->value->type->data.array.len; - } - } else if (uncasted_op->value->type->id == ZigTypeIdVector) { - vector_len = uncasted_op->value->type->data.vector.len; - } - - bool is_vector = (vector_len != UINT32_MAX); - ZigType *op_type = is_vector ? get_vector_type(ira->codegen, vector_len, int_type) : int_type; - - Stage1AirInst *op = ir_implicit_cast(ira, uncasted_op, op_type); - if (type_is_invalid(op->value->type)) - return ira->codegen->invalid_inst_gen; - - if (int_type->data.integral.bit_count == 0) - return ir_const_unsigned(ira, instruction->base.scope, instruction->base.source_node, 0); - - ZigType *smallest_type = get_smallest_unsigned_int_type(ira->codegen, int_type->data.integral.bit_count); - - if (instr_is_comptime(op)) { - ZigValue *val = ir_resolve_const(ira, op, UndefOk); - if (val == nullptr) - return ira->codegen->invalid_inst_gen; - if (val->special == ConstValSpecialUndef) - return ir_const_undef(ira, instruction->base.scope, instruction->base.source_node, ira->codegen->builtin_types.entry_num_lit_int); - - if (is_vector) { - ZigType *smallest_vec_type = get_vector_type(ira->codegen, vector_len, smallest_type); - Stage1AirInst *result = ir_const(ira, instruction->base.scope, instruction->base.source_node, smallest_vec_type); - expand_undef_array(ira->codegen, val); - result->value->data.x_array.data.s_none.elements = ira->codegen->pass1_arena->allocate(smallest_vec_type->data.vector.len); - for (unsigned i = 0; i < smallest_vec_type->data.vector.len; i += 1) { - ZigValue *op_elem_val = &val->data.x_array.data.s_none.elements[i]; - if ((err = ir_resolve_const_val(ira->codegen, ira->new_irb.exec, instruction->base.source_node, - op_elem_val, UndefOk))) - { - return ira->codegen->invalid_inst_gen; - } - ZigValue *result_elem_val = &result->value->data.x_array.data.s_none.elements[i]; - result_elem_val->type = smallest_type; - result_elem_val->special = op_elem_val->special; - if (op_elem_val->special == ConstValSpecialUndef) - continue; - size_t value = bigint_ctz(&op_elem_val->data.x_bigint, int_type->data.integral.bit_count); - bigint_init_unsigned(&result->value->data.x_array.data.s_none.elements[i].data.x_bigint, value); - } - return result; - } else { - size_t result_usize = bigint_ctz(&op->value->data.x_bigint, int_type->data.integral.bit_count); - return ir_const_unsigned(ira, instruction->base.scope, instruction->base.source_node, result_usize); - } - } - - ZigType *return_type = is_vector ? get_vector_type(ira->codegen, vector_len, smallest_type) : smallest_type; - return ir_build_ctz_gen(ira, instruction->base.scope, instruction->base.source_node, return_type, op); -} - -static Stage1AirInst *ir_analyze_instruction_clz(IrAnalyze *ira, Stage1ZirInstClz *instruction) { - Error err; - - ZigType *int_type = ir_resolve_int_type(ira, instruction->type->child); - if (type_is_invalid(int_type)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *uncasted_op = instruction->op->child; - if (type_is_invalid(uncasted_op->value->type)) - return ira->codegen->invalid_inst_gen; - - uint32_t vector_len = UINT32_MAX; // means not a vector - if (uncasted_op->value->type->id == ZigTypeIdArray) { - bool can_be_vec_elem; - if ((err = is_valid_vector_elem_type(ira->codegen, uncasted_op->value->type->data.array.child_type, - &can_be_vec_elem))) - { - return ira->codegen->invalid_inst_gen; - } - if (can_be_vec_elem) { - vector_len = uncasted_op->value->type->data.array.len; - } - } else if (uncasted_op->value->type->id == ZigTypeIdVector) { - vector_len = uncasted_op->value->type->data.vector.len; - } - - bool is_vector = (vector_len != UINT32_MAX); - ZigType *op_type = is_vector ? get_vector_type(ira->codegen, vector_len, int_type) : int_type; - - Stage1AirInst *op = ir_implicit_cast(ira, uncasted_op, op_type); - if (type_is_invalid(op->value->type)) - return ira->codegen->invalid_inst_gen; - - if (int_type->data.integral.bit_count == 0) - return ir_const_unsigned(ira, instruction->base.scope, instruction->base.source_node, 0); - - ZigType *smallest_type = get_smallest_unsigned_int_type(ira->codegen, int_type->data.integral.bit_count); - - if (instr_is_comptime(op)) { - ZigValue *val = ir_resolve_const(ira, op, UndefOk); - if (val == nullptr) - return ira->codegen->invalid_inst_gen; - if (val->special == ConstValSpecialUndef) - return ir_const_undef(ira, instruction->base.scope, instruction->base.source_node, ira->codegen->builtin_types.entry_num_lit_int); - - if (is_vector) { - ZigType *smallest_vec_type = get_vector_type(ira->codegen, vector_len, smallest_type); - Stage1AirInst *result = ir_const(ira, instruction->base.scope, instruction->base.source_node, smallest_vec_type); - expand_undef_array(ira->codegen, val); - result->value->data.x_array.data.s_none.elements = ira->codegen->pass1_arena->allocate(smallest_vec_type->data.vector.len); - for (unsigned i = 0; i < smallest_vec_type->data.vector.len; i += 1) { - ZigValue *op_elem_val = &val->data.x_array.data.s_none.elements[i]; - if ((err = ir_resolve_const_val(ira->codegen, ira->new_irb.exec, instruction->base.source_node, - op_elem_val, UndefOk))) - { - return ira->codegen->invalid_inst_gen; - } - ZigValue *result_elem_val = &result->value->data.x_array.data.s_none.elements[i]; - result_elem_val->type = smallest_type; - result_elem_val->special = op_elem_val->special; - if (op_elem_val->special == ConstValSpecialUndef) - continue; - size_t value = bigint_clz(&op_elem_val->data.x_bigint, int_type->data.integral.bit_count); - bigint_init_unsigned(&result->value->data.x_array.data.s_none.elements[i].data.x_bigint, value); - } - return result; - } else { - size_t result_usize = bigint_clz(&op->value->data.x_bigint, int_type->data.integral.bit_count); - return ir_const_unsigned(ira, instruction->base.scope, instruction->base.source_node, result_usize); - } - } - - ZigType *return_type = is_vector ? get_vector_type(ira->codegen, vector_len, smallest_type) : smallest_type; - return ir_build_clz_gen(ira, instruction->base.scope, instruction->base.source_node, return_type, op); -} - -static Stage1AirInst *ir_analyze_instruction_pop_count(IrAnalyze *ira, Stage1ZirInstPopCount *instruction) { - Error err; - - ZigType *int_type = ir_resolve_int_type(ira, instruction->type->child); - if (type_is_invalid(int_type)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *uncasted_op = instruction->op->child; - if (type_is_invalid(uncasted_op->value->type)) - return ira->codegen->invalid_inst_gen; - - uint32_t vector_len = UINT32_MAX; // means not a vector - if (uncasted_op->value->type->id == ZigTypeIdArray) { - bool can_be_vec_elem; - if ((err = is_valid_vector_elem_type(ira->codegen, uncasted_op->value->type->data.array.child_type, - &can_be_vec_elem))) - { - return ira->codegen->invalid_inst_gen; - } - if (can_be_vec_elem) { - vector_len = uncasted_op->value->type->data.array.len; - } - } else if (uncasted_op->value->type->id == ZigTypeIdVector) { - vector_len = uncasted_op->value->type->data.vector.len; - } - - bool is_vector = (vector_len != UINT32_MAX); - ZigType *op_type = is_vector ? get_vector_type(ira->codegen, vector_len, int_type) : int_type; - - Stage1AirInst *op = ir_implicit_cast(ira, uncasted_op, op_type); - if (type_is_invalid(op->value->type)) - return ira->codegen->invalid_inst_gen; - - if (int_type->data.integral.bit_count == 0) - return ir_const_unsigned(ira, instruction->base.scope, instruction->base.source_node, 0); - - ZigType *smallest_type = get_smallest_unsigned_int_type(ira->codegen, int_type->data.integral.bit_count); - - if (instr_is_comptime(op)) { - ZigValue *val = ir_resolve_const(ira, op, UndefOk); - if (val == nullptr) - return ira->codegen->invalid_inst_gen; - if (val->special == ConstValSpecialUndef) - return ir_const_undef(ira, instruction->base.scope, instruction->base.source_node, ira->codegen->builtin_types.entry_num_lit_int); - - if (is_vector) { - ZigType *smallest_vec_type = get_vector_type(ira->codegen, vector_len, smallest_type); - Stage1AirInst *result = ir_const(ira, instruction->base.scope, instruction->base.source_node, smallest_vec_type); - expand_undef_array(ira->codegen, val); - result->value->data.x_array.data.s_none.elements = ira->codegen->pass1_arena->allocate(smallest_vec_type->data.vector.len); - for (unsigned i = 0; i < smallest_vec_type->data.vector.len; i += 1) { - ZigValue *op_elem_val = &val->data.x_array.data.s_none.elements[i]; - if ((err = ir_resolve_const_val(ira->codegen, ira->new_irb.exec, instruction->base.source_node, - op_elem_val, UndefOk))) - { - return ira->codegen->invalid_inst_gen; - } - ZigValue *result_elem_val = &result->value->data.x_array.data.s_none.elements[i]; - result_elem_val->type = smallest_type; - result_elem_val->special = op_elem_val->special; - if (op_elem_val->special == ConstValSpecialUndef) - continue; - - if (bigint_cmp_zero(&op_elem_val->data.x_bigint) != CmpLT) { - size_t value = bigint_popcount_unsigned(&op_elem_val->data.x_bigint); - bigint_init_unsigned(&result->value->data.x_array.data.s_none.elements[i].data.x_bigint, value); - } - size_t value = bigint_popcount_signed(&op_elem_val->data.x_bigint, int_type->data.integral.bit_count); - bigint_init_unsigned(&result->value->data.x_array.data.s_none.elements[i].data.x_bigint, value); - } - return result; - } else { - if (bigint_cmp_zero(&val->data.x_bigint) != CmpLT) { - size_t result = bigint_popcount_unsigned(&val->data.x_bigint); - return ir_const_unsigned(ira, instruction->base.scope, instruction->base.source_node, result); - } - size_t result = bigint_popcount_signed(&val->data.x_bigint, int_type->data.integral.bit_count); - return ir_const_unsigned(ira, instruction->base.scope, instruction->base.source_node, result); - } - } - - ZigType *return_type = is_vector ? get_vector_type(ira->codegen, vector_len, smallest_type) : smallest_type; - return ir_build_pop_count_gen(ira, instruction->base.scope, instruction->base.source_node, return_type, op); -} - -static Stage1AirInst *ir_analyze_union_tag(IrAnalyze *ira, Scope *scope, AstNode *source_node, Stage1AirInst *value) { - if (type_is_invalid(value->value->type)) - return ira->codegen->invalid_inst_gen; - - if (value->value->type->id != ZigTypeIdUnion) { - ir_add_error(ira, value, - buf_sprintf("expected enum or union type, found '%s'", buf_ptr(&value->value->type->name))); - return ira->codegen->invalid_inst_gen; - } - if (!value->value->type->data.unionation.have_explicit_tag_type) { - ErrorMsg *msg = ir_add_error_node(ira, source_node, buf_sprintf("union has no associated enum")); - if (value->value->type->data.unionation.decl_node != nullptr) { - add_error_note(ira->codegen, msg, value->value->type->data.unionation.decl_node, - buf_sprintf("declared here")); - } - return ira->codegen->invalid_inst_gen; - } - - ZigType *tag_type = value->value->type->data.unionation.tag_type; - assert(tag_type->id == ZigTypeIdEnum); - - if (instr_is_comptime(value)) { - ZigValue *val = ir_resolve_const(ira, value, UndefBad); - if (!val) - return ira->codegen->invalid_inst_gen; - - Stage1AirInstConst *const_instruction = ir_create_inst_gen(&ira->new_irb, - scope, source_node); - const_instruction->base.value->type = tag_type; - const_instruction->base.value->special = ConstValSpecialStatic; - bigint_init_bigint(&const_instruction->base.value->data.x_enum_tag, &val->data.x_union.tag); - return &const_instruction->base; - } - - return ir_build_union_tag(ira, scope, source_node, value, tag_type); -} - -static Stage1AirInst *ir_analyze_instruction_switch_br(IrAnalyze *ira, - Stage1ZirInstSwitchBr *switch_br_instruction) -{ - Stage1AirInst *target_value = switch_br_instruction->target_value->child; - if (type_is_invalid(target_value->value->type)) - return ir_unreach_error(ira); - - if (switch_br_instruction->switch_prongs_void != nullptr) { - if (type_is_invalid(switch_br_instruction->switch_prongs_void->child->value->type)) { - return ir_unreach_error(ira); - } - } - - - size_t case_count = switch_br_instruction->case_count; - - bool is_comptime; - if (!ir_resolve_comptime(ira, switch_br_instruction->is_comptime->child, &is_comptime)) - return ira->codegen->invalid_inst_gen; - - if (is_comptime || instr_is_comptime(target_value)) { - ZigValue *target_val = ir_resolve_const(ira, target_value, UndefBad); - if (!target_val) - return ir_unreach_error(ira); - - Stage1ZirBasicBlock *old_dest_block = switch_br_instruction->else_block; - for (size_t i = 0; i < case_count; i += 1) { - Stage1ZirInstSwitchBrCase *old_case = &switch_br_instruction->cases[i]; - Stage1AirInst *case_value = old_case->value->child; - if (type_is_invalid(case_value->value->type)) - return ir_unreach_error(ira); - - Stage1AirInst *casted_case_value = ir_implicit_cast(ira, case_value, target_value->value->type); - if (type_is_invalid(casted_case_value->value->type)) - return ir_unreach_error(ira); - - ZigValue *case_val = ir_resolve_const(ira, casted_case_value, UndefBad); - if (!case_val) - return ir_unreach_error(ira); - - if (const_values_equal(ira->codegen, target_val, case_val)) { - old_dest_block = old_case->block; - break; - } - } - - if (is_comptime || old_dest_block->ref_count == 1) { - return ir_inline_bb(ira, switch_br_instruction->base.source_node, old_dest_block); - } else { - Stage1AirBasicBlock *new_dest_block = ir_get_new_bb(ira, old_dest_block, &switch_br_instruction->base); - Stage1AirInst *result = ir_build_br_gen(ira, switch_br_instruction->base.scope, - switch_br_instruction->base.source_node, new_dest_block); - return ir_finish_anal(ira, result); - } - } - - Stage1AirInstSwitchBrCase *cases = heap::c_allocator.allocate(case_count); - for (size_t i = 0; i < case_count; i += 1) { - Stage1ZirInstSwitchBrCase *old_case = &switch_br_instruction->cases[i]; - Stage1AirInstSwitchBrCase *new_case = &cases[i]; - new_case->block = ir_get_new_bb(ira, old_case->block, &switch_br_instruction->base); - new_case->value = ira->codegen->invalid_inst_gen; - - // Calling ir_get_new_bb set the ref_instruction on the new basic block. - // However a switch br may branch to the same basic block which would trigger an - // incorrect re-generation of the block. So we set it to null here and assign - // it back after the loop. - new_case->block->ref_instruction = nullptr; - - Stage1ZirInst *old_value = old_case->value; - Stage1AirInst *new_value = old_value->child; - if (type_is_invalid(new_value->value->type)) - continue; - - Stage1AirInst *casted_new_value = ir_implicit_cast(ira, new_value, target_value->value->type); - if (type_is_invalid(casted_new_value->value->type)) - continue; - - if (!ir_resolve_const(ira, casted_new_value, UndefBad)) - continue; - - new_case->value = casted_new_value; - } - - for (size_t i = 0; i < case_count; i += 1) { - Stage1AirInstSwitchBrCase *new_case = &cases[i]; - if (type_is_invalid(new_case->value->value->type)) - return ir_unreach_error(ira); - new_case->block->ref_instruction = &switch_br_instruction->base; - } - - Stage1AirBasicBlock *new_else_block = ir_get_new_bb(ira, switch_br_instruction->else_block, &switch_br_instruction->base); - Stage1AirInstSwitchBr *switch_br = ir_build_switch_br_gen(ira, switch_br_instruction->base.scope, - switch_br_instruction->base.source_node, target_value, new_else_block, case_count, cases); - return ir_finish_anal(ira, &switch_br->base); -} - -static Stage1AirInst *ir_analyze_instruction_switch_target(IrAnalyze *ira, - Stage1ZirInstSwitchTarget *switch_target_instruction) -{ - Error err; - Stage1AirInst *target_value_ptr = switch_target_instruction->target_value_ptr->child; - if (type_is_invalid(target_value_ptr->value->type)) - return ira->codegen->invalid_inst_gen; - - if (target_value_ptr->value->type->id == ZigTypeIdMetaType) { - assert(instr_is_comptime(target_value_ptr)); - ZigType *ptr_type = target_value_ptr->value->data.x_type; - assert(ptr_type->id == ZigTypeIdPointer); - return ir_const_type(ira, switch_target_instruction->base.scope, - switch_target_instruction->base.source_node, ptr_type->data.pointer.child_type); - } - - ZigType *target_type = target_value_ptr->value->type->data.pointer.child_type; - ZigValue *pointee_val = nullptr; - if (instr_is_comptime(target_value_ptr) && target_value_ptr->value->data.x_ptr.mut != ConstPtrMutRuntimeVar) { - pointee_val = const_ptr_pointee(ira, ira->codegen, target_value_ptr->value, target_value_ptr->source_node); - if (pointee_val == nullptr) - return ira->codegen->invalid_inst_gen; - - if (pointee_val->special == ConstValSpecialRuntime) - pointee_val = nullptr; - } - if ((err = type_resolve(ira->codegen, target_type, ResolveStatusSizeKnown))) - return ira->codegen->invalid_inst_gen; - - switch (target_type->id) { - case ZigTypeIdInvalid: - zig_unreachable(); - case ZigTypeIdMetaType: - case ZigTypeIdVoid: - case ZigTypeIdBool: - case ZigTypeIdInt: - case ZigTypeIdFloat: - case ZigTypeIdComptimeFloat: - case ZigTypeIdComptimeInt: - case ZigTypeIdEnumLiteral: - case ZigTypeIdPointer: - case ZigTypeIdFn: - case ZigTypeIdErrorSet: { - if (pointee_val) { - Stage1AirInst *result = ir_const(ira, switch_target_instruction->base.scope, - switch_target_instruction->base.source_node, nullptr); - copy_const_val(ira->codegen, result->value, pointee_val); - result->value->type = target_type; - return result; - } - - Stage1AirInst *result = ir_get_deref(ira, switch_target_instruction->base.scope, - switch_target_instruction->base.source_node, target_value_ptr, nullptr); - result->value->type = target_type; - return result; - } - case ZigTypeIdUnion: { - AstNode *decl_node = target_type->data.unionation.decl_node; - if (!decl_node->data.container_decl.auto_enum && - decl_node->data.container_decl.init_arg_expr == nullptr) - { - ErrorMsg *msg = ir_add_error(ira, target_value_ptr, - buf_sprintf("switch on union which has no attached enum")); - add_error_note(ira->codegen, msg, decl_node, - buf_sprintf("consider 'union(enum)' here")); - return ira->codegen->invalid_inst_gen; - } - ZigType *tag_type = target_type->data.unionation.tag_type; - assert(tag_type != nullptr); - assert(tag_type->id == ZigTypeIdEnum); - if (pointee_val) { - Stage1AirInst *result = ir_const(ira, switch_target_instruction->base.scope, switch_target_instruction->base.source_node, tag_type); - bigint_init_bigint(&result->value->data.x_enum_tag, &pointee_val->data.x_union.tag); - return result; - } - - if (can_fold_enum_type(tag_type)) { - Stage1AirInst *result = ir_const(ira, switch_target_instruction->base.scope, switch_target_instruction->base.source_node, tag_type); - TypeEnumField *only_field = &tag_type->data.enumeration.fields[0]; - bigint_init_bigint(&result->value->data.x_enum_tag, &only_field->value); - return result; - } - - Stage1AirInst *union_value = ir_get_deref(ira, switch_target_instruction->base.scope, - switch_target_instruction->base.source_node, target_value_ptr, nullptr); - union_value->value->type = target_type; - - return ir_build_union_tag(ira, switch_target_instruction->base.scope, switch_target_instruction->base.source_node, union_value, tag_type); - } - case ZigTypeIdEnum: { - if ((err = type_resolve(ira->codegen, target_type, ResolveStatusZeroBitsKnown))) - return ira->codegen->invalid_inst_gen; - - if (can_fold_enum_type(target_type)) { - TypeEnumField *only_field = &target_type->data.enumeration.fields[0]; - Stage1AirInst *result = ir_const(ira, switch_target_instruction->base.scope, switch_target_instruction->base.source_node, target_type); - bigint_init_bigint(&result->value->data.x_enum_tag, &only_field->value); - return result; - } - - if (pointee_val) { - Stage1AirInst *result = ir_const(ira, switch_target_instruction->base.scope, switch_target_instruction->base.source_node, target_type); - bigint_init_bigint(&result->value->data.x_enum_tag, &pointee_val->data.x_enum_tag); - return result; - } - - Stage1AirInst *enum_value = ir_get_deref(ira, switch_target_instruction->base.scope, - switch_target_instruction->base.source_node, target_value_ptr, nullptr); - enum_value->value->type = target_type; - return enum_value; - } - case ZigTypeIdErrorUnion: - case ZigTypeIdUnreachable: - case ZigTypeIdArray: - case ZigTypeIdStruct: - case ZigTypeIdUndefined: - case ZigTypeIdNull: - case ZigTypeIdOptional: - case ZigTypeIdBoundFn: - case ZigTypeIdOpaque: - case ZigTypeIdVector: - case ZigTypeIdFnFrame: - case ZigTypeIdAnyFrame: - ir_add_error_node(ira, switch_target_instruction->base.source_node, - buf_sprintf("invalid switch target type '%s'", buf_ptr(&target_type->name))); - return ira->codegen->invalid_inst_gen; - } - zig_unreachable(); -} - -static Stage1AirInst *ir_analyze_instruction_switch_var(IrAnalyze *ira, Stage1ZirInstSwitchVar *instruction) { - Stage1AirInst *target_value_ptr = instruction->target_value_ptr->child; - if (type_is_invalid(target_value_ptr->value->type)) - return ira->codegen->invalid_inst_gen; - - ZigType *ref_type = target_value_ptr->value->type; - assert(ref_type->id == ZigTypeIdPointer); - ZigType *target_type = target_value_ptr->value->type->data.pointer.child_type; - if (target_type->id == ZigTypeIdUnion) { - ZigType *enum_type = target_type->data.unionation.tag_type; - assert(enum_type != nullptr); - assert(enum_type->id == ZigTypeIdEnum); - assert(instruction->prongs_len > 0); - - Stage1AirInst *first_prong_value = instruction->prongs_ptr[0]->child; - if (type_is_invalid(first_prong_value->value->type)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *first_casted_prong_value = ir_implicit_cast(ira, first_prong_value, enum_type); - if (type_is_invalid(first_casted_prong_value->value->type)) - return ira->codegen->invalid_inst_gen; - - ZigValue *first_prong_val = ir_resolve_const(ira, first_casted_prong_value, UndefBad); - if (first_prong_val == nullptr) - return ira->codegen->invalid_inst_gen; - - TypeUnionField *first_field = find_union_field_by_tag(target_type, &first_prong_val->data.x_enum_tag); - - ErrorMsg *invalid_payload_msg = nullptr; - for (size_t prong_i = 1; prong_i < instruction->prongs_len; prong_i += 1) { - Stage1AirInst *this_prong_inst = instruction->prongs_ptr[prong_i]->child; - if (type_is_invalid(this_prong_inst->value->type)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *this_casted_prong_value = ir_implicit_cast(ira, this_prong_inst, enum_type); - if (type_is_invalid(this_casted_prong_value->value->type)) - return ira->codegen->invalid_inst_gen; - - ZigValue *this_prong = ir_resolve_const(ira, this_casted_prong_value, UndefBad); - if (this_prong == nullptr) - return ira->codegen->invalid_inst_gen; - - TypeUnionField *payload_field = find_union_field_by_tag(target_type, &this_prong->data.x_enum_tag); - ZigType *payload_type = payload_field->type_entry; - if (first_field->type_entry != payload_type) { - if (invalid_payload_msg == nullptr) { - invalid_payload_msg = ir_add_error_node(ira, instruction->base.source_node, - buf_sprintf("capture group with incompatible types")); - add_error_note(ira->codegen, invalid_payload_msg, first_prong_value->source_node, - buf_sprintf("type '%s' here", buf_ptr(&first_field->type_entry->name))); - } - add_error_note(ira->codegen, invalid_payload_msg, this_prong_inst->source_node, - buf_sprintf("type '%s' here", buf_ptr(&payload_field->type_entry->name))); - } - } - - if (invalid_payload_msg != nullptr) { - return ira->codegen->invalid_inst_gen; - } - - if (instr_is_comptime(target_value_ptr)) { - ZigValue *target_val_ptr = ir_resolve_const(ira, target_value_ptr, UndefBad); - if (!target_value_ptr) - return ira->codegen->invalid_inst_gen; - - ZigValue *pointee_val = const_ptr_pointee(ira, ira->codegen, target_val_ptr, instruction->base.source_node); - if (pointee_val == nullptr) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *result = ir_const(ira, instruction->base.scope, instruction->base.source_node, - get_pointer_to_type(ira->codegen, first_field->type_entry, - target_val_ptr->type->data.pointer.is_const)); - ZigValue *out_val = result->value; - out_val->data.x_ptr.special = ConstPtrSpecialRef; - out_val->data.x_ptr.mut = target_val_ptr->data.x_ptr.mut; - out_val->data.x_ptr.data.ref.pointee = pointee_val->data.x_union.payload; - return result; - } - - ZigType *result_type = get_pointer_to_type(ira->codegen, first_field->type_entry, - target_value_ptr->value->type->data.pointer.is_const); - return ir_build_union_field_ptr(ira, instruction->base.scope, instruction->base.source_node, target_value_ptr, first_field, - false, false, result_type); - } else if (target_type->id == ZigTypeIdErrorSet) { - // construct an error set from the prong values - ZigType *err_set_type = new_type_table_entry(ZigTypeIdErrorSet); - err_set_type->size_in_bits = ira->codegen->builtin_types.entry_global_error_set->size_in_bits; - err_set_type->abi_align = ira->codegen->builtin_types.entry_global_error_set->abi_align; - err_set_type->abi_size = ira->codegen->builtin_types.entry_global_error_set->abi_size; - ZigList error_list = {}; - buf_resize(&err_set_type->name, 0); - buf_appendf(&err_set_type->name, "error{"); - for (size_t i = 0; i < instruction->prongs_len; i += 1) { - ErrorTableEntry *err = ir_resolve_error(ira, instruction->prongs_ptr[i]->child); - if (err == nullptr) - return ira->codegen->invalid_inst_gen; - error_list.append(err); - buf_appendf(&err_set_type->name, "%s,", buf_ptr(&err->name)); - } - err_set_type->data.error_set.errors = error_list.items; - err_set_type->data.error_set.err_count = error_list.length; - buf_appendf(&err_set_type->name, "}"); - - - ZigType *new_target_value_ptr_type = get_pointer_to_type_extra(ira->codegen, - err_set_type, - ref_type->data.pointer.is_const, ref_type->data.pointer.is_volatile, - ref_type->data.pointer.ptr_len, - ref_type->data.pointer.explicit_alignment, - ref_type->data.pointer.bit_offset_in_host, ref_type->data.pointer.host_int_bytes, - ref_type->data.pointer.allow_zero); - return ir_analyze_ptr_cast(ira, instruction->base.scope, instruction->base.source_node, - target_value_ptr, instruction->target_value_ptr->source_node, - new_target_value_ptr_type, instruction->base.source_node, false, false); - } else if (instruction->prongs_len > 1) { - return target_value_ptr; - } else { - ir_add_error_node(ira, instruction->base.source_node, - buf_sprintf("switch on type '%s' provides no expression parameter", buf_ptr(&target_type->name))); - return ira->codegen->invalid_inst_gen; - } -} - -static Stage1AirInst *ir_analyze_instruction_switch_else_var(IrAnalyze *ira, - Stage1ZirInstSwitchElseVar *instruction) -{ - Stage1AirInst *target_value_ptr = instruction->target_value_ptr->child; - if (type_is_invalid(target_value_ptr->value->type)) - return ira->codegen->invalid_inst_gen; - - ZigType *ref_type = target_value_ptr->value->type; - assert(ref_type->id == ZigTypeIdPointer); - ZigType *target_type = target_value_ptr->value->type->data.pointer.child_type; - if (target_type->id == ZigTypeIdErrorSet) { - // make a new set that has the other cases removed - if (!resolve_inferred_error_set(ira->codegen, target_type, instruction->base.source_node)) { - return ira->codegen->invalid_inst_gen; - } - if (type_is_global_error_set(target_type)) { - // the type of the else capture variable still has to be the global error set. - // once the runtime hint system is more sophisticated, we could add some hint information here. - return target_value_ptr; - } - // Make note of the errors handled by other cases - ErrorTableEntry **errors = heap::c_allocator.allocate(ira->codegen->errors_by_index.length); - // We may not have any case in the switch if this is a lone else - const size_t switch_cases = instruction->switch_br ? instruction->switch_br->case_count : 0; - for (size_t case_i = 0; case_i < switch_cases; case_i += 1) { - Stage1ZirInstSwitchBrCase *br_case = &instruction->switch_br->cases[case_i]; - Stage1AirInst *case_expr = br_case->value->child; - if (case_expr->value->type->id == ZigTypeIdErrorSet) { - ErrorTableEntry *err = ir_resolve_error(ira, case_expr); - if (err == nullptr) - return ira->codegen->invalid_inst_gen; - errors[err->value] = err; - } else if (case_expr->value->type->id == ZigTypeIdMetaType) { - ZigType *err_set_type = ir_resolve_type(ira, case_expr); - if (type_is_invalid(err_set_type)) - return ira->codegen->invalid_inst_gen; - populate_error_set_table(errors, err_set_type); - } else { - zig_unreachable(); - } - } - ZigList result_list = {}; - - ZigType *err_set_type = new_type_table_entry(ZigTypeIdErrorSet); - buf_resize(&err_set_type->name, 0); - buf_appendf(&err_set_type->name, "error{"); - - // Look at all the errors in the type switched on and add them to the result_list - // if they are not handled by cases. - for (uint32_t i = 0; i < target_type->data.error_set.err_count; i += 1) { - ErrorTableEntry *error_entry = target_type->data.error_set.errors[i]; - ErrorTableEntry *existing_entry = errors[error_entry->value]; - if (existing_entry == nullptr) { - result_list.append(error_entry); - buf_appendf(&err_set_type->name, "%s,", buf_ptr(&error_entry->name)); - } - } - heap::c_allocator.deallocate(errors, ira->codegen->errors_by_index.length); - - err_set_type->data.error_set.err_count = result_list.length; - err_set_type->data.error_set.errors = result_list.items; - err_set_type->size_in_bits = ira->codegen->builtin_types.entry_global_error_set->size_in_bits; - err_set_type->abi_align = ira->codegen->builtin_types.entry_global_error_set->abi_align; - err_set_type->abi_size = ira->codegen->builtin_types.entry_global_error_set->abi_size; - - buf_appendf(&err_set_type->name, "}"); - - ZigType *new_target_value_ptr_type = get_pointer_to_type_extra(ira->codegen, - err_set_type, - ref_type->data.pointer.is_const, ref_type->data.pointer.is_volatile, - ref_type->data.pointer.ptr_len, - ref_type->data.pointer.explicit_alignment, - ref_type->data.pointer.bit_offset_in_host, ref_type->data.pointer.host_int_bytes, - ref_type->data.pointer.allow_zero); - return ir_analyze_ptr_cast(ira, instruction->base.scope, instruction->base.source_node, - target_value_ptr, instruction->target_value_ptr->source_node, - new_target_value_ptr_type, instruction->base.source_node, false, false); - } - - return target_value_ptr; -} - -static Stage1AirInst *ir_analyze_instruction_import(IrAnalyze *ira, Stage1ZirInstImport *import_instruction) { - Error err; - - Stage1AirInst *name_value = import_instruction->name->child; - Buf *import_target_str = ir_resolve_str(ira, name_value); - if (!import_target_str) - return ira->codegen->invalid_inst_gen; - - AstNode *source_node = import_instruction->base.source_node; - ZigType *import = source_node->owner; - - ZigType *target_import; - Buf *import_target_path; - Buf full_path = BUF_INIT; - if ((err = analyze_import(ira->codegen, import, import_target_str, &target_import, - &import_target_path, &full_path))) - { - if (err == ErrorImportOutsidePkgPath) { - ir_add_error_node(ira, source_node, - buf_sprintf("import of file outside package path: '%s'", - buf_ptr(import_target_path))); - return ira->codegen->invalid_inst_gen; - } else if (err == ErrorFileNotFound) { - ir_add_error_node(ira, source_node, - buf_sprintf("unable to find '%s'", buf_ptr(import_target_path))); - return ira->codegen->invalid_inst_gen; - } else { - ir_add_error_node(ira, source_node, - buf_sprintf("unable to open '%s': %s", buf_ptr(&full_path), err_str(err))); - return ira->codegen->invalid_inst_gen; - } - } - - return ir_const_type(ira, import_instruction->base.scope, import_instruction->base.source_node, target_import); -} - -static Stage1AirInst *ir_analyze_instruction_ref(IrAnalyze *ira, Stage1ZirInstRef *ref_instruction) { - Stage1AirInst *value = ref_instruction->value->child; - if (type_is_invalid(value->value->type)) - return ira->codegen->invalid_inst_gen; - - bool is_const = false; - bool is_volatile = false; - - ZigValue *child_value = value->value; - if (child_value->special == ConstValSpecialStatic) { - is_const = true; - } - - return ir_get_ref(ira, ref_instruction->base.scope, ref_instruction->base.source_node, value, is_const, is_volatile); -} - -static Stage1AirInst *ir_analyze_union_init(IrAnalyze *ira, Scope *scope, AstNode *source_node, - AstNode *field_source_node, ZigType *union_type, Buf *field_name, Stage1AirInst *field_result_loc, - Stage1AirInst *result_loc) -{ - Error err; - assert(union_type->id == ZigTypeIdUnion); - - if ((err = type_resolve(ira->codegen, union_type, ResolveStatusZeroBitsKnown))) - return ira->codegen->invalid_inst_gen; - - TypeUnionField *type_field = find_union_type_field(union_type, field_name); - if (type_field == nullptr) { - ir_add_error_node(ira, field_source_node, - buf_sprintf("no field named '%s' in union '%s'", - buf_ptr(field_name), buf_ptr(&union_type->name))); - return ira->codegen->invalid_inst_gen; - } - - if (type_is_invalid(type_field->type_entry)) - return ira->codegen->invalid_inst_gen; - - if (result_loc->value->data.x_ptr.mut == ConstPtrMutInfer) { - if (instr_is_comptime(field_result_loc) && - field_result_loc->value->data.x_ptr.mut != ConstPtrMutRuntimeVar) - { - // nothing - } else { - result_loc->value->special = ConstValSpecialRuntime; - } - } - - bool is_comptime = ir_should_inline(ira->zir, scope) - || type_requires_comptime(ira->codegen, union_type) == ReqCompTimeYes; - - Stage1AirInst *result = ir_get_deref(ira, scope, source_node, result_loc, nullptr); - if (is_comptime && !instr_is_comptime(result)) { - ir_add_error(ira, field_result_loc, - buf_sprintf("unable to evaluate constant expression")); - return ira->codegen->invalid_inst_gen; - } - return result; -} - -static Stage1AirInst *ir_analyze_container_init_fields(IrAnalyze *ira, Scope *scope, AstNode *source_node, - ZigType *container_type, size_t instr_field_count, Stage1ZirInstContainerInitFieldsField *fields, - Stage1AirInst *result_loc) -{ - Error err; - if (container_type->id == ZigTypeIdUnion) { - if (instr_field_count != 1) { - ir_add_error_node(ira, source_node, - buf_sprintf("union initialization expects exactly one field")); - return ira->codegen->invalid_inst_gen; - } - Stage1ZirInstContainerInitFieldsField *field = &fields[0]; - Stage1AirInst *field_result_loc = field->result_loc->child; - if (type_is_invalid(field_result_loc->value->type)) - return ira->codegen->invalid_inst_gen; - - return ir_analyze_union_init(ira, scope, source_node, field->source_node, container_type, field->name, - field_result_loc, result_loc); - } - if (container_type->id != ZigTypeIdStruct || is_slice(container_type)) { - ir_add_error_node(ira, source_node, - buf_sprintf("type '%s' does not support struct initialization syntax", - buf_ptr(&container_type->name))); - return ira->codegen->invalid_inst_gen; - } - - if (container_type->data.structure.resolve_status == ResolveStatusBeingInferred) { - // We're now done inferring the type. - container_type->data.structure.resolve_status = ResolveStatusUnstarted; - } - - if ((err = type_resolve(ira->codegen, container_type, ResolveStatusSizeKnown))) - return ira->codegen->invalid_inst_gen; - - size_t actual_field_count = container_type->data.structure.src_field_count; - - Stage1AirInst *first_non_const_instruction = nullptr; - - AstNode **field_assign_nodes = heap::c_allocator.allocate(actual_field_count); - ZigList const_ptrs = {}; - - bool is_comptime = ir_should_inline(ira->zir, scope) - || type_requires_comptime(ira->codegen, container_type) == ReqCompTimeYes; - - - // Here we iterate over the fields that have been initialized, and emit - // compile errors for missing fields and duplicate fields. - // It is only now that we find out whether the struct initialization can be a comptime - // value, but we have already emitted runtime instructions for the fields that - // were initialized with runtime values, and have omitted instructions that would have - // initialized fields with comptime values. - // So now we must clean up this situation. If it turns out the struct initialization can - // be a comptime value, overwrite ConstPtrMutInfer with ConstPtrMutComptimeConst. - // Otherwise, we must emit instructions to runtime-initialize the fields that have - // comptime-known values. - - for (size_t i = 0; i < instr_field_count; i += 1) { - Stage1ZirInstContainerInitFieldsField *field = &fields[i]; - - Stage1AirInst *field_result_loc = field->result_loc->child; - if (type_is_invalid(field_result_loc->value->type)) - return ira->codegen->invalid_inst_gen; - - TypeStructField *type_field = find_struct_type_field(container_type, field->name); - if (!type_field) { - ir_add_error_node(ira, field->source_node, - buf_sprintf("no field named '%s' in struct '%s'", - buf_ptr(field->name), buf_ptr(&container_type->name))); - return ira->codegen->invalid_inst_gen; - } - - if (type_is_invalid(type_field->type_entry)) - return ira->codegen->invalid_inst_gen; - - size_t field_index = type_field->src_index; - AstNode *existing_assign_node = field_assign_nodes[field_index]; - if (existing_assign_node) { - ErrorMsg *msg = ir_add_error_node(ira, field->source_node, buf_sprintf("duplicate field")); - add_error_note(ira->codegen, msg, existing_assign_node, buf_sprintf("other field here")); - return ira->codegen->invalid_inst_gen; - } - field_assign_nodes[field_index] = field->source_node; - - if (instr_is_comptime(field_result_loc) && - field_result_loc->value->data.x_ptr.mut != ConstPtrMutRuntimeVar) - { - const_ptrs.append(field_result_loc); - } else { - first_non_const_instruction = field_result_loc; - } - } - - bool any_missing = false; - for (size_t i = 0; i < actual_field_count; i += 1) { - if (field_assign_nodes[i] != nullptr) continue; - - // look for a default field value - TypeStructField *field = container_type->data.structure.fields[i]; - memoize_field_init_val(ira->codegen, container_type, field); - if (field->init_val == nullptr) { - ir_add_error_node(ira, source_node, - buf_sprintf("missing field: '%s'", buf_ptr(field->name))); - any_missing = true; - continue; - } - if (type_is_invalid(field->init_val->type)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *runtime_inst = ir_const(ira, scope, source_node, field->init_val->type); - copy_const_val(ira->codegen, runtime_inst->value, field->init_val); - - Stage1AirInst *field_ptr = ir_analyze_struct_field_ptr(ira, scope, source_node, field, result_loc, - container_type, true); - ir_analyze_store_ptr(ira, scope, source_node, field_ptr, runtime_inst, false); - if (instr_is_comptime(field_ptr) && field_ptr->value->data.x_ptr.mut != ConstPtrMutRuntimeVar) { - const_ptrs.append(field_ptr); - } else { - first_non_const_instruction = result_loc; - } - } - heap::c_allocator.deallocate(field_assign_nodes, actual_field_count); - if (any_missing) - return ira->codegen->invalid_inst_gen; - - if (result_loc->value->data.x_ptr.mut == ConstPtrMutInfer) { - if (const_ptrs.length != actual_field_count) { - result_loc->value->special = ConstValSpecialRuntime; - for (size_t i = 0; i < const_ptrs.length; i += 1) { - Stage1AirInst *field_result_loc = const_ptrs.at(i); - Stage1AirInst *deref = ir_get_deref(ira, field_result_loc->scope, - field_result_loc->source_node, field_result_loc, nullptr); - field_result_loc->value->special = ConstValSpecialRuntime; - ir_analyze_store_ptr(ira, field_result_loc->scope, field_result_loc->source_node, - field_result_loc, deref, false); - } - } - } - - const_ptrs.deinit(); - Stage1AirInst *result = ir_get_deref(ira, scope, source_node, result_loc, nullptr); - - if (is_comptime && !instr_is_comptime(result)) { - ir_add_error_node(ira, first_non_const_instruction->source_node, - buf_sprintf("unable to evaluate constant expression")); - return ira->codegen->invalid_inst_gen; - } - - return result; -} - -static Stage1AirInst *ir_analyze_instruction_container_init_list(IrAnalyze *ira, - Stage1ZirInstContainerInitList *instruction) -{ - src_assert(instruction->result_loc != nullptr, instruction->base.source_node); - Stage1AirInst *result_loc = instruction->result_loc->child; - if (type_is_invalid(result_loc->value->type)) - return result_loc; - - src_assert(result_loc->value->type->id == ZigTypeIdPointer, instruction->base.source_node); - if (result_loc->value->type->data.pointer.is_const) { - ir_add_error_node(ira, instruction->base.source_node, buf_sprintf("cannot assign to constant")); - return ira->codegen->invalid_inst_gen; - } - - ZigType *container_type = result_loc->value->type->data.pointer.child_type; - size_t elem_count = instruction->item_count; - - if (is_slice(container_type)) { - ir_add_error_node(ira, instruction->init_array_type_source_node, - buf_sprintf("array literal requires address-of operator (&) to coerce to slice type '%s'", - buf_ptr(&container_type->name))); - return ira->codegen->invalid_inst_gen; - } - - if (container_type->id == ZigTypeIdVoid) { - if (elem_count != 0) { - ir_add_error_node(ira, instruction->base.source_node, - buf_sprintf("void expression expects no arguments")); - return ira->codegen->invalid_inst_gen; - } - return ir_const_void(ira, instruction->base.scope, instruction->base.source_node); - } - - if (container_type->id == ZigTypeIdStruct && elem_count == 0) { - src_assert(instruction->result_loc != nullptr, instruction->base.source_node); - Stage1AirInst *result_loc = instruction->result_loc->child; - if (type_is_invalid(result_loc->value->type)) - return result_loc; - return ir_analyze_container_init_fields(ira, instruction->base.scope, instruction->base.source_node, container_type, 0, nullptr, result_loc); - } - - if (container_type->id == ZigTypeIdArray) { - ZigType *child_type = container_type->data.array.child_type; - if (container_type->data.array.len != elem_count) { - ZigType *literal_type = get_array_type(ira->codegen, child_type, elem_count, nullptr); - - ir_add_error_node(ira, instruction->base.source_node, - buf_sprintf("expected %s literal, found %s literal", - buf_ptr(&container_type->name), buf_ptr(&literal_type->name))); - return ira->codegen->invalid_inst_gen; - } - } else if (container_type->id == ZigTypeIdStruct && - container_type->data.structure.resolve_status == ResolveStatusBeingInferred) - { - // We're now done inferring the type. - container_type->data.structure.resolve_status = ResolveStatusUnstarted; - } else if (container_type->id == ZigTypeIdVector || is_tuple(container_type)) { - // OK - } else { - ir_add_error_node(ira, instruction->base.source_node, - buf_sprintf("type '%s' does not support array initialization", - buf_ptr(&container_type->name))); - return ira->codegen->invalid_inst_gen; - } - - switch (type_has_one_possible_value(ira->codegen, container_type)) { - case OnePossibleValueInvalid: - return ira->codegen->invalid_inst_gen; - case OnePossibleValueYes: - return ir_const_move(ira, instruction->base.scope, instruction->base.source_node, - get_the_one_possible_value(ira->codegen, container_type)); - case OnePossibleValueNo: - break; - } - - bool is_comptime; - switch (type_requires_comptime(ira->codegen, container_type)) { - case ReqCompTimeInvalid: - return ira->codegen->invalid_inst_gen; - case ReqCompTimeNo: - is_comptime = ir_should_inline(ira->zir, instruction->base.scope); - break; - case ReqCompTimeYes: - is_comptime = true; - break; - } - - Stage1AirInst *first_non_const_instruction = nullptr; - - // The Result Location Mechanism has already emitted runtime instructions to - // initialize runtime elements and has omitted instructions for the comptime - // elements. However it is only now that we find out whether the array initialization - // can be a comptime value. So we must clean up the situation. If it turns out - // array initialization can be a comptime value, overwrite ConstPtrMutInfer with - // ConstPtrMutComptimeConst. Otherwise, emit instructions to runtime-initialize the - // elements that have comptime-known values. - ZigList const_ptrs = {}; - - for (size_t i = 0; i < elem_count; i += 1) { - Stage1AirInst *elem_result_loc = instruction->elem_result_loc_list[i]->child; - if (type_is_invalid(elem_result_loc->value->type)) - return ira->codegen->invalid_inst_gen; - - assert(elem_result_loc->value->type->id == ZigTypeIdPointer); - - if (instr_is_comptime(elem_result_loc) && - elem_result_loc->value->data.x_ptr.mut != ConstPtrMutRuntimeVar) - { - const_ptrs.append(elem_result_loc); - } else { - first_non_const_instruction = elem_result_loc; - } - } - - if (result_loc->value->data.x_ptr.mut == ConstPtrMutInfer) { - if (const_ptrs.length != elem_count) { - result_loc->value->special = ConstValSpecialRuntime; - for (size_t i = 0; i < const_ptrs.length; i += 1) { - Stage1AirInst *elem_result_loc = const_ptrs.at(i); - assert(elem_result_loc->value->special == ConstValSpecialStatic); - if (elem_result_loc->value->type->data.pointer.inferred_struct_field != nullptr) { - // This field will be generated comptime; no need to do this. - continue; - } - Stage1AirInst *deref = ir_get_deref(ira, elem_result_loc->scope, - elem_result_loc->source_node, elem_result_loc, nullptr); - elem_result_loc->value->special = ConstValSpecialRuntime; - ir_analyze_store_ptr(ira, elem_result_loc->scope, elem_result_loc->source_node, - elem_result_loc, deref, false); - } - } - } - - const_ptrs.deinit(); - - Stage1AirInst *result = ir_get_deref(ira, instruction->base.scope, instruction->base.source_node, - result_loc, nullptr); - // If the result is a tuple, we are allowed to return a struct that uses ConstValSpecialRuntime fields at comptime. - if (instr_is_comptime(result) || is_tuple(container_type)) - return result; - - if (is_comptime) { - ir_add_error(ira, first_non_const_instruction, - buf_sprintf("unable to evaluate constant expression")); - return ira->codegen->invalid_inst_gen; - } - - ZigType *result_elem_type = result_loc->value->type->data.pointer.child_type; - if (is_slice(result_elem_type)) { - ErrorMsg *msg = ir_add_error_node(ira, instruction->base.source_node, - buf_sprintf("runtime-initialized array cannot be casted to slice type '%s'", - buf_ptr(&result_elem_type->name))); - add_error_note(ira->codegen, msg, first_non_const_instruction->source_node, - buf_sprintf("this value is not comptime-known")); - return ira->codegen->invalid_inst_gen; - } - return result; -} - -static Stage1AirInst *ir_analyze_instruction_container_init_fields(IrAnalyze *ira, - Stage1ZirInstContainerInitFields *instruction) -{ - src_assert(instruction->result_loc != nullptr, instruction->base.source_node); - Stage1AirInst *result_loc = instruction->result_loc->child; - if (type_is_invalid(result_loc->value->type)) - return result_loc; - - src_assert(result_loc->value->type->id == ZigTypeIdPointer, instruction->base.source_node); - if (result_loc->value->type->data.pointer.is_const) { - ir_add_error_node(ira, instruction->base.source_node, buf_sprintf("cannot assign to constant")); - return ira->codegen->invalid_inst_gen; - } - - ZigType *container_type = result_loc->value->type->data.pointer.child_type; - - return ir_analyze_container_init_fields(ira, instruction->base.scope, instruction->base.source_node, container_type, - instruction->field_count, instruction->fields, result_loc); -} - -static Stage1AirInst *ir_analyze_instruction_compile_err(IrAnalyze *ira, Stage1ZirInstCompileErr *instruction) { - Stage1AirInst *msg_value = instruction->msg->child; - Buf *msg_buf = ir_resolve_str(ira, msg_value); - if (!msg_buf) - return ira->codegen->invalid_inst_gen; - - ir_add_error_node(ira, instruction->base.source_node, msg_buf); - - return ira->codegen->invalid_inst_gen; -} - -static Stage1AirInst *ir_analyze_instruction_compile_log(IrAnalyze *ira, Stage1ZirInstCompileLog *instruction) { - Buf buf = BUF_INIT; - fprintf(stderr, "| "); - for (size_t i = 0; i < instruction->msg_count; i += 1) { - Stage1AirInst *msg = instruction->msg_list[i]->child; - if (type_is_invalid(msg->value->type)) - return ira->codegen->invalid_inst_gen; - buf_resize(&buf, 0); - if (msg->value->special == ConstValSpecialLazy) { - // Resolve any lazy value that's passed, we need its value - if (ir_resolve_lazy(ira->codegen, msg->source_node, msg->value)) - return ira->codegen->invalid_inst_gen; - } - render_const_value(ira->codegen, &buf, msg->value); - const char *comma_str = (i != 0) ? ", " : ""; - fprintf(stderr, "%s%s", comma_str, buf_ptr(&buf)); - } - fprintf(stderr, "\n"); - - auto *expr = &instruction->base.source_node->data.fn_call_expr; - if (!expr->seen) { - // Here we bypass higher level functions such as ir_add_error because we do not want - // invalidate_exec to be called. - add_node_error(ira->codegen, instruction->base.source_node, buf_sprintf("found compile log statement")); - } - expr->seen = true; - - return ir_const_void(ira, instruction->base.scope, instruction->base.source_node); -} - -static Stage1AirInst *ir_analyze_instruction_err_name(IrAnalyze *ira, Stage1ZirInstErrName *instruction) { - Stage1AirInst *value = instruction->value->child; - if (type_is_invalid(value->value->type)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *casted_value = ir_implicit_cast(ira, value, ira->codegen->builtin_types.entry_global_error_set); - if (type_is_invalid(casted_value->value->type)) - return ira->codegen->invalid_inst_gen; - - if (instr_is_comptime(casted_value)) { - ZigValue *val = ir_resolve_const(ira, casted_value, UndefBad); - if (val == nullptr) - return ira->codegen->invalid_inst_gen; - ErrorTableEntry *err = casted_value->value->data.x_err_set; - if (!err->cached_error_name_val) { - err->cached_error_name_val = create_sentineled_str_lit( - ira->codegen, &err->name, - ira->codegen->intern.for_zero_byte()); - } - Stage1AirInst *result = ir_const(ira, instruction->base.scope, instruction->base.source_node, nullptr); - result->value = err->cached_error_name_val; - return result; - } - - ira->codegen->generate_error_name_table = true; - - ZigType *u8_ptr_type = get_pointer_to_type_extra2(ira->codegen, ira->codegen->builtin_types.entry_u8, - true, false, PtrLenUnknown, 0, 0, 0, false, - VECTOR_INDEX_NONE, nullptr, ira->codegen->intern.for_zero_byte()); - ZigType *str_type = get_slice_type(ira->codegen, u8_ptr_type); - return ir_build_err_name_gen(ira, instruction->base.scope, instruction->base.source_node, value, str_type); -} - -static Stage1AirInst *ir_analyze_instruction_enum_tag_name(IrAnalyze *ira, Stage1ZirInstTagName *instruction) { - Error err; - Stage1AirInst *target = instruction->target->child; - if (type_is_invalid(target->value->type)) - return ira->codegen->invalid_inst_gen; - - ZigType *target_type = target->value->type; - - if (target_type->id == ZigTypeIdEnumLiteral) { - Stage1AirInst *result = ir_const(ira, instruction->base.scope, instruction->base.source_node, nullptr); - Buf *field_name = target->value->data.x_enum_literal; - result->value = create_sentineled_str_lit( - ira->codegen, field_name, - ira->codegen->intern.for_zero_byte()); - return result; - } - - if (target_type->id == ZigTypeIdUnion) { - target = ir_analyze_union_tag(ira, instruction->base.scope, instruction->base.source_node, target); - if (type_is_invalid(target->value->type)) - return ira->codegen->invalid_inst_gen; - target_type = target->value->type; - } - - if (target_type->id != ZigTypeIdEnum) { - ir_add_error(ira, target, - buf_sprintf("expected enum tag, found '%s'", buf_ptr(&target_type->name))); - return ira->codegen->invalid_inst_gen; - } - - if (can_fold_enum_type(target_type)) { - TypeEnumField *only_field = &target_type->data.enumeration.fields[0]; - Stage1AirInst *result = ir_const(ira, instruction->base.scope, instruction->base.source_node, nullptr); - result->value = create_sentineled_str_lit( - ira->codegen, only_field->name, - ira->codegen->intern.for_zero_byte()); - return result; - } - - if (instr_is_comptime(target)) { - if ((err = type_resolve(ira->codegen, target_type, ResolveStatusZeroBitsKnown))) - return ira->codegen->invalid_inst_gen; - TypeEnumField *field = find_enum_field_by_tag(target_type, &target->value->data.x_bigint); - if (field == nullptr) { - Buf *int_buf = buf_alloc(); - bigint_append_buf(int_buf, &target->value->data.x_bigint, 10); - - ir_add_error(ira, target, - buf_sprintf("no tag by value %s", buf_ptr(int_buf))); - return ira->codegen->invalid_inst_gen; - } - Stage1AirInst *result = ir_const(ira, instruction->base.scope, instruction->base.source_node, nullptr); - result->value = create_sentineled_str_lit( - ira->codegen, field->name, - ira->codegen->intern.for_zero_byte()); - return result; - } - - ZigType *u8_ptr_type = get_pointer_to_type_extra2( - ira->codegen, ira->codegen->builtin_types.entry_u8, - true, false, PtrLenUnknown, 0, 0, 0, false, - VECTOR_INDEX_NONE, nullptr, ira->codegen->intern.for_zero_byte()); - ZigType *result_type = get_slice_type(ira->codegen, u8_ptr_type); - return ir_build_tag_name_gen(ira, instruction->base.scope, instruction->base.source_node, target, result_type); -} - -static Stage1AirInst *ir_analyze_instruction_field_parent_ptr(IrAnalyze *ira, - Stage1ZirInstFieldParentPtr *instruction) -{ - Error err; - Stage1AirInst *type_value = instruction->type_value->child; - ZigType *container_type = ir_resolve_type(ira, type_value); - if (type_is_invalid(container_type)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *field_name_value = instruction->field_name->child; - Buf *field_name = ir_resolve_str(ira, field_name_value); - if (!field_name) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *field_ptr = instruction->field_ptr->child; - if (type_is_invalid(field_ptr->value->type)) - return ira->codegen->invalid_inst_gen; - - if (container_type->id != ZigTypeIdStruct) { - ir_add_error(ira, type_value, - buf_sprintf("expected struct type, found '%s'", buf_ptr(&container_type->name))); - return ira->codegen->invalid_inst_gen; - } - - if ((err = type_resolve(ira->codegen, container_type, ResolveStatusSizeKnown))) - return ira->codegen->invalid_inst_gen; - - TypeStructField *field = find_struct_type_field(container_type, field_name); - if (field == nullptr) { - ir_add_error(ira, field_name_value, - buf_sprintf("struct '%s' has no field '%s'", - buf_ptr(&container_type->name), buf_ptr(field_name))); - return ira->codegen->invalid_inst_gen; - } - - if (field_ptr->value->type->id != ZigTypeIdPointer) { - ir_add_error(ira, field_ptr, - buf_sprintf("expected pointer, found '%s'", buf_ptr(&field_ptr->value->type->name))); - return ira->codegen->invalid_inst_gen; - } - - bool is_packed = (container_type->data.structure.layout == ContainerLayoutPacked); - uint32_t field_ptr_align = is_packed ? 1 : get_abi_alignment(ira->codegen, field->type_entry); - uint32_t parent_ptr_align = is_packed ? 1 : get_abi_alignment(ira->codegen, container_type); - - ZigType *field_ptr_type = get_pointer_to_type_extra(ira->codegen, field->type_entry, - field_ptr->value->type->data.pointer.is_const, - field_ptr->value->type->data.pointer.is_volatile, - PtrLenSingle, - field_ptr_align, 0, 0, false); - Stage1AirInst *casted_field_ptr = ir_implicit_cast(ira, field_ptr, field_ptr_type); - if (type_is_invalid(casted_field_ptr->value->type)) - return ira->codegen->invalid_inst_gen; - - ZigType *result_type = get_pointer_to_type_extra(ira->codegen, container_type, - casted_field_ptr->value->type->data.pointer.is_const, - casted_field_ptr->value->type->data.pointer.is_volatile, - PtrLenSingle, - parent_ptr_align, 0, 0, false); - - if (instr_is_comptime(casted_field_ptr)) { - ZigValue *field_ptr_val = ir_resolve_const(ira, casted_field_ptr, UndefBad); - if (!field_ptr_val) - return ira->codegen->invalid_inst_gen; - - if (field_ptr_val->data.x_ptr.special != ConstPtrSpecialBaseStruct) { - ir_add_error(ira, field_ptr, buf_sprintf("pointer value not based on parent struct")); - return ira->codegen->invalid_inst_gen; - } - - size_t ptr_field_index = field_ptr_val->data.x_ptr.data.base_struct.field_index; - if (ptr_field_index != field->src_index) { - ir_add_error_node(ira, instruction->base.source_node, - buf_sprintf("field '%s' has index %" ZIG_PRI_usize " but pointer value is index %" ZIG_PRI_usize " of struct '%s'", - buf_ptr(field->name), field->src_index, - ptr_field_index, buf_ptr(&container_type->name))); - return ira->codegen->invalid_inst_gen; - } - - Stage1AirInst *result = ir_const(ira, instruction->base.scope, instruction->base.source_node, result_type); - ZigValue *out_val = result->value; - out_val->data.x_ptr.special = ConstPtrSpecialRef; - out_val->data.x_ptr.data.ref.pointee = field_ptr_val->data.x_ptr.data.base_struct.struct_val; - out_val->data.x_ptr.mut = field_ptr_val->data.x_ptr.mut; - return result; - } - - return ir_build_field_parent_ptr_gen(ira, instruction->base.scope, instruction->base.source_node, casted_field_ptr, field, result_type); -} - -static TypeStructField *validate_host_int_byte_offset(IrAnalyze *ira, - Stage1AirInst *type_value, - Stage1AirInst *field_name_value, - size_t *byte_offset) -{ - ZigType *container_type = ir_resolve_type(ira, type_value); - if (type_is_invalid(container_type)) - return nullptr; - - Error err; - if ((err = type_resolve(ira->codegen, container_type, ResolveStatusSizeKnown))) - return nullptr; - - Buf *field_name = ir_resolve_str(ira, field_name_value); - if (!field_name) - return nullptr; - - if (container_type->id != ZigTypeIdStruct) { - ir_add_error(ira, type_value, - buf_sprintf("expected struct type, found '%s'", buf_ptr(&container_type->name))); - return nullptr; - } - - TypeStructField *field = find_struct_type_field(container_type, field_name); - if (field == nullptr) { - ir_add_error(ira, field_name_value, - buf_sprintf("struct '%s' has no field '%s'", - buf_ptr(&container_type->name), buf_ptr(field_name))); - return nullptr; - } - - if (!type_has_bits(ira->codegen, field->type_entry)) { - ir_add_error(ira, field_name_value, - buf_sprintf("zero-bit field '%s' in struct '%s' has no offset", - buf_ptr(field_name), buf_ptr(&container_type->name))); - return nullptr; - } - - *byte_offset = field->offset; - return field; -} - -static Stage1AirInst *ir_analyze_instruction_offset_of(IrAnalyze *ira, Stage1ZirInstOffsetOf *instruction) { - Stage1AirInst *type_value = instruction->type_value->child; - if (type_is_invalid(type_value->value->type)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *field_name_value = instruction->field_name->child; - size_t host_int_byte_offset = 0; - TypeStructField *field = nullptr; - if (!(field = validate_host_int_byte_offset(ira, type_value, field_name_value, &host_int_byte_offset))) - return ira->codegen->invalid_inst_gen; - - size_t byte_offset = host_int_byte_offset + (field->bit_offset_in_host / 8); - return ir_const_unsigned(ira, instruction->base.scope, instruction->base.source_node, byte_offset); -} - -static Stage1AirInst *ir_analyze_instruction_bit_offset_of(IrAnalyze *ira, Stage1ZirInstBitOffsetOf *instruction) { - Stage1AirInst *type_value = instruction->type_value->child; - if (type_is_invalid(type_value->value->type)) - return ira->codegen->invalid_inst_gen; - Stage1AirInst *field_name_value = instruction->field_name->child; - size_t host_int_byte_offset = 0; - TypeStructField *field = nullptr; - if (!(field = validate_host_int_byte_offset(ira, type_value, field_name_value, &host_int_byte_offset))) - return ira->codegen->invalid_inst_gen; - - size_t bit_offset = host_int_byte_offset * 8 + field->bit_offset_in_host; - return ir_const_unsigned(ira, instruction->base.scope, instruction->base.source_node, bit_offset); -} - -static void ensure_field_index(ZigType *type, const char *field_name, size_t index) { - Buf *field_name_buf; - - assert(type != nullptr && !type_is_invalid(type)); - field_name_buf = buf_create_from_str(field_name); - TypeStructField *field = find_struct_type_field(type, field_name_buf); - buf_deinit(field_name_buf); - - if (field == nullptr || field->src_index != index) - zig_panic("reference to unknown field %s", field_name); -} - -static ZigType *ir_type_info_get_type(IrAnalyze *ira, const char *type_name, ZigType *root) { - Error err; - ZigType *type_info_type = get_builtin_type(ira->codegen, "Type"); - assert(type_info_type->id == ZigTypeIdUnion); - if ((err = type_resolve(ira->codegen, type_info_type, ResolveStatusSizeKnown))) { - zig_unreachable(); - } - - if (type_name == nullptr && root == nullptr) - return type_info_type; - else if (type_name == nullptr) - return root; - - ZigType *root_type = (root == nullptr) ? type_info_type : root; - - ScopeDecls *type_info_scope = get_container_scope(root_type); - assert(type_info_scope != nullptr); - - Buf field_name = BUF_INIT; - buf_init_from_str(&field_name, type_name); - auto entry = type_info_scope->decl_table.get(&field_name); - buf_deinit(&field_name); - - TldVar *tld = (TldVar *)entry; - assert(tld->base.id == TldIdVar); - - ZigVar *var = tld->var; - - assert(var->const_value->type->id == ZigTypeIdMetaType); - - return ir_resolve_const_type(ira->codegen, ira->new_irb.exec, nullptr, var->const_value); -} - -static Error ir_make_type_info_decls(IrAnalyze *ira, AstNode *source_node, ZigValue *out_val, - ScopeDecls *decls_scope, bool resolve_types) -{ - Error err; - ZigType *type_info_declaration_type = ir_type_info_get_type(ira, "Declaration", nullptr); - if ((err = type_resolve(ira->codegen, type_info_declaration_type, ResolveStatusSizeKnown))) - return err; - - ensure_field_index(type_info_declaration_type, "name", 0); - ensure_field_index(type_info_declaration_type, "is_pub", 1); - - if (!resolve_types) { - ZigType *ptr_type = get_pointer_to_type_extra(ira->codegen, type_info_declaration_type, - false, false, PtrLenUnknown, 0, 0, 0, false); - - out_val->special = ConstValSpecialLazy; - out_val->type = get_slice_type(ira->codegen, ptr_type); - - LazyValueTypeInfoDecls *lazy_type_info_decls = heap::c_allocator.create(); - lazy_type_info_decls->ira = ira; ira_ref(ira); - out_val->data.x_lazy = &lazy_type_info_decls->base; - lazy_type_info_decls->base.id = LazyValueIdTypeInfoDecls; - - lazy_type_info_decls->source_node = source_node; - lazy_type_info_decls->decls_scope = decls_scope; - - return ErrorNone; - } - - resolve_container_usingnamespace_decls(ira->codegen, decls_scope); - - // Loop through our declarations once to figure out how many declarations - // we will generate info for. - int declaration_count = 0; - auto decl_it = decls_scope->decl_table.entry_iterator(); - decltype(decls_scope->decl_table)::Entry *curr_entry = nullptr; - while ((curr_entry = decl_it.next()) != nullptr) { - // Skip comptime blocks and test functions. - if (curr_entry->value->id == TldIdCompTime) - continue; - - if (curr_entry->value->id == TldIdFn && - curr_entry->value->source_node->type == NodeTypeTestDecl) - { - continue; - } - - if (curr_entry->value->resolution == TldResolutionInvalid) - return ErrorSemanticAnalyzeFail; - - declaration_count += 1; - } - - ZigValue *declaration_array = ira->codegen->pass1_arena->create(); - declaration_array->special = ConstValSpecialStatic; - declaration_array->type = get_array_type(ira->codegen, type_info_declaration_type, declaration_count, nullptr); - declaration_array->data.x_array.special = ConstArraySpecialNone; - declaration_array->data.x_array.data.s_none.elements = ira->codegen->pass1_arena->allocate(declaration_count); - init_const_slice(ira->codegen, out_val, declaration_array, 0, declaration_count, false, nullptr); - - // Loop through the declarations and generate info. - decl_it = decls_scope->decl_table.entry_iterator(); - curr_entry = nullptr; - int declaration_index = 0; - while ((curr_entry = decl_it.next()) != nullptr) { - // Skip comptime blocks and test functions. - if (curr_entry->value->id == TldIdCompTime) { - continue; - } - if (curr_entry->value->id == TldIdFn && - curr_entry->value->source_node->type == NodeTypeTestDecl) - { - continue; - } - - ZigValue *declaration_val = &declaration_array->data.x_array.data.s_none.elements[declaration_index]; - - declaration_val->special = ConstValSpecialStatic; - declaration_val->type = type_info_declaration_type; - - ZigValue **inner_fields = alloc_const_vals_ptrs(ira->codegen, 2); - ZigValue *name = create_const_str_lit(ira->codegen, curr_entry->key)->data.x_ptr.data.ref.pointee; - init_const_slice(ira->codegen, inner_fields[0], name, 0, buf_len(curr_entry->key), true, nullptr); - inner_fields[1]->special = ConstValSpecialStatic; - inner_fields[1]->type = ira->codegen->builtin_types.entry_bool; - inner_fields[1]->data.x_bool = curr_entry->value->visib_mod == VisibModPub; - - declaration_val->data.x_struct.fields = inner_fields; - declaration_index += 1; - } - - assert(declaration_index == declaration_count); - return ErrorNone; -} - -static BuiltinPtrSize ptr_len_to_size_enum_index(PtrLen ptr_len) { - switch (ptr_len) { - case PtrLenSingle: - return BuiltinPtrSizeOne; - case PtrLenUnknown: - return BuiltinPtrSizeMany; - case PtrLenC: - return BuiltinPtrSizeC; - } - zig_unreachable(); -} - -static PtrLen size_enum_index_to_ptr_len(BuiltinPtrSize size_enum_index) { - switch (size_enum_index) { - case BuiltinPtrSizeOne: - return PtrLenSingle; - case BuiltinPtrSizeMany: - case BuiltinPtrSizeSlice: - return PtrLenUnknown; - case BuiltinPtrSizeC: - return PtrLenC; - } - zig_unreachable(); -} - -static ZigValue *create_ptr_like_type_info(IrAnalyze *ira, Scope *scope, AstNode *source_node, ZigType *ptr_type_entry) { - CodeGen *g = ira->codegen; - ZigType *attrs_type; - BuiltinPtrSize size_enum_index; - if (is_slice(ptr_type_entry)) { - TypeStructField *ptr_field = ptr_type_entry->data.structure.fields[slice_ptr_index]; - attrs_type = resolve_struct_field_type(g, ptr_field); - size_enum_index = BuiltinPtrSizeSlice; - } else if (ptr_type_entry->id == ZigTypeIdPointer) { - attrs_type = ptr_type_entry; - size_enum_index = ptr_len_to_size_enum_index(ptr_type_entry->data.pointer.ptr_len); - } else { - zig_unreachable(); - } - - ZigType *type_info_pointer_type = ir_type_info_get_type(ira, "Pointer", nullptr); - assertNoError(type_resolve(g, type_info_pointer_type, ResolveStatusSizeKnown)); - - ZigValue *result = g->pass1_arena->create(); - result->special = ConstValSpecialStatic; - result->type = type_info_pointer_type; - - ZigValue **fields = alloc_const_vals_ptrs(g, 8); - result->data.x_struct.fields = fields; - - // size: Size - ensure_field_index(result->type, "size", 0); - ZigType *type_info_pointer_size_type = ir_type_info_get_type(ira, "Size", type_info_pointer_type); - assertNoError(type_resolve(g, type_info_pointer_size_type, ResolveStatusSizeKnown)); - fields[0]->special = ConstValSpecialStatic; - fields[0]->type = type_info_pointer_size_type; - bigint_init_unsigned(&fields[0]->data.x_enum_tag, size_enum_index); - - // is_const: bool - ensure_field_index(result->type, "is_const", 1); - fields[1]->special = ConstValSpecialStatic; - fields[1]->type = g->builtin_types.entry_bool; - fields[1]->data.x_bool = attrs_type->data.pointer.is_const; - // is_volatile: bool - ensure_field_index(result->type, "is_volatile", 2); - fields[2]->special = ConstValSpecialStatic; - fields[2]->type = g->builtin_types.entry_bool; - fields[2]->data.x_bool = attrs_type->data.pointer.is_volatile; - // alignment: comptime_int - ensure_field_index(result->type, "alignment", 3); - fields[3]->type = g->builtin_types.entry_num_lit_int; - if (attrs_type->data.pointer.explicit_alignment != 0) { - fields[3]->special = ConstValSpecialStatic; - bigint_init_unsigned(&fields[3]->data.x_bigint, attrs_type->data.pointer.explicit_alignment); - } else { - LazyValueAlignOf *lazy_align_of = heap::c_allocator.create(); - lazy_align_of->ira = ira; ira_ref(ira); - fields[3]->special = ConstValSpecialLazy; - fields[3]->data.x_lazy = &lazy_align_of->base; - lazy_align_of->base.id = LazyValueIdAlignOf; - lazy_align_of->target_type = ir_const_type(ira, scope, source_node, attrs_type->data.pointer.child_type); - } - // address_space: AddressSpace, - ensure_field_index(result->type, "address_space", 4); - fields[4]->special = ConstValSpecialStatic; - fields[4]->type = get_builtin_type(g, "AddressSpace"); - bigint_init_unsigned(&fields[4]->data.x_enum_tag, AddressSpaceGeneric); - // child: type - ensure_field_index(result->type, "child", 5); - fields[5]->special = ConstValSpecialStatic; - fields[5]->type = g->builtin_types.entry_type; - fields[5]->data.x_type = attrs_type->data.pointer.child_type; - // is_allowzero: bool - ensure_field_index(result->type, "is_allowzero", 6); - fields[6]->special = ConstValSpecialStatic; - fields[6]->type = g->builtin_types.entry_bool; - fields[6]->data.x_bool = attrs_type->data.pointer.allow_zero; - // sentinel: ?*const anyopaque - ensure_field_index(result->type, "sentinel", 7); - fields[7]->special = ConstValSpecialStatic; - fields[7]->type = g->builtin_types.entry_opt_ptr_const_anyopaque; - ZigValue *ptr_to_sent = (attrs_type->data.pointer.sentinel == nullptr) ? nullptr : - create_const_ptr_ref(g, attrs_type->data.pointer.sentinel, true); - set_optional_payload(fields[7], ptr_to_sent); - - return result; -}; - -static void make_enum_field_val(IrAnalyze *ira, ZigValue *enum_field_val, TypeEnumField *enum_field, - ZigType *type_info_enum_field_type) -{ - enum_field_val->special = ConstValSpecialStatic; - enum_field_val->type = type_info_enum_field_type; - - ZigValue **inner_fields = alloc_const_vals_ptrs(ira->codegen, 2); - inner_fields[1]->special = ConstValSpecialStatic; - inner_fields[1]->type = ira->codegen->builtin_types.entry_num_lit_int; - - ZigValue *name = create_const_str_lit(ira->codegen, enum_field->name)->data.x_ptr.data.ref.pointee; - init_const_slice(ira->codegen, inner_fields[0], name, 0, buf_len(enum_field->name), true, nullptr); - - bigint_init_bigint(&inner_fields[1]->data.x_bigint, &enum_field->value); - - enum_field_val->data.x_struct.fields = inner_fields; -} - -static Error ir_make_type_info_value(IrAnalyze *ira, Scope *scope, AstNode *source_node, ZigType *type_entry, - ZigValue **out) -{ - Error err; - assert(type_entry != nullptr); - assert(!type_is_invalid(type_entry)); - - CodeGen *g = ira->codegen; - - auto entry = g->type_info_cache.maybe_get(type_entry); - if (entry != nullptr) { - *out = entry->value; - return ErrorNone; - } - - ZigValue *result = nullptr; - switch (type_entry->id) { - case ZigTypeIdInvalid: - zig_unreachable(); - case ZigTypeIdMetaType: - case ZigTypeIdVoid: - case ZigTypeIdBool: - case ZigTypeIdUnreachable: - case ZigTypeIdComptimeFloat: - case ZigTypeIdComptimeInt: - case ZigTypeIdEnumLiteral: - case ZigTypeIdUndefined: - case ZigTypeIdNull: - result = g->intern.for_void(); - break; - case ZigTypeIdInt: - { - result = g->pass1_arena->create(); - result->special = ConstValSpecialStatic; - result->type = ir_type_info_get_type(ira, "Int", nullptr); - - ZigValue **fields = alloc_const_vals_ptrs(g, 2); - result->data.x_struct.fields = fields; - - // is_signed: Signedness - ensure_field_index(result->type, "signedness", 0); - fields[0]->special = ConstValSpecialStatic; - fields[0]->type = get_builtin_type(g, "Signedness"); - bigint_init_unsigned(&fields[0]->data.x_enum_tag, !type_entry->data.integral.is_signed); - // bits: u8 - ensure_field_index(result->type, "bits", 1); - fields[1]->special = ConstValSpecialStatic; - fields[1]->type = g->builtin_types.entry_num_lit_int; - bigint_init_unsigned(&fields[1]->data.x_bigint, type_entry->data.integral.bit_count); - - break; - } - case ZigTypeIdFloat: - { - result = g->pass1_arena->create(); - result->special = ConstValSpecialStatic; - result->type = ir_type_info_get_type(ira, "Float", nullptr); - - ZigValue **fields = alloc_const_vals_ptrs(g, 1); - result->data.x_struct.fields = fields; - - // bits: u8 - ensure_field_index(result->type, "bits", 0); - fields[0]->special = ConstValSpecialStatic; - fields[0]->type = g->builtin_types.entry_num_lit_int; - bigint_init_unsigned(&fields[0]->data.x_bigint, type_entry->data.floating.bit_count); - - break; - } - case ZigTypeIdPointer: - { - result = create_ptr_like_type_info(ira, scope, source_node, type_entry); - if (result == nullptr) - return ErrorSemanticAnalyzeFail; - break; - } - case ZigTypeIdArray: - { - result = g->pass1_arena->create(); - result->special = ConstValSpecialStatic; - result->type = ir_type_info_get_type(ira, "Array", nullptr); - - ZigValue **fields = alloc_const_vals_ptrs(g, 3); - result->data.x_struct.fields = fields; - - // len: usize - ensure_field_index(result->type, "len", 0); - fields[0]->special = ConstValSpecialStatic; - fields[0]->type = g->builtin_types.entry_num_lit_int; - bigint_init_unsigned(&fields[0]->data.x_bigint, type_entry->data.array.len); - // child: type - ensure_field_index(result->type, "child", 1); - fields[1]->special = ConstValSpecialStatic; - fields[1]->type = g->builtin_types.entry_type; - fields[1]->data.x_type = type_entry->data.array.child_type; - src_assert(type_entry->data.array.child_type != nullptr, source_node); - // sentinel: ?*const anyopaque - fields[2]->special = ConstValSpecialStatic; - fields[2]->type = g->builtin_types.entry_opt_ptr_const_anyopaque; - ZigValue *ptr_to_sent = (type_entry->data.array.sentinel == nullptr) ? nullptr : - create_const_ptr_ref(g, type_entry->data.array.sentinel, true); - set_optional_payload(fields[2], ptr_to_sent); - break; - } - case ZigTypeIdVector: { - result = g->pass1_arena->create(); - result->special = ConstValSpecialStatic; - result->type = ir_type_info_get_type(ira, "Vector", nullptr); - - ZigValue **fields = alloc_const_vals_ptrs(g, 2); - result->data.x_struct.fields = fields; - - // len: usize - ensure_field_index(result->type, "len", 0); - fields[0]->special = ConstValSpecialStatic; - fields[0]->type = g->builtin_types.entry_num_lit_int; - bigint_init_unsigned(&fields[0]->data.x_bigint, type_entry->data.vector.len); - // child: type - ensure_field_index(result->type, "child", 1); - fields[1]->special = ConstValSpecialStatic; - fields[1]->type = g->builtin_types.entry_type; - fields[1]->data.x_type = type_entry->data.vector.elem_type; - - break; - } - case ZigTypeIdOptional: - { - result = g->pass1_arena->create(); - result->special = ConstValSpecialStatic; - result->type = ir_type_info_get_type(ira, "Optional", nullptr); - - ZigValue **fields = alloc_const_vals_ptrs(g, 1); - result->data.x_struct.fields = fields; - - // child: type - ensure_field_index(result->type, "child", 0); - fields[0]->special = ConstValSpecialStatic; - fields[0]->type = g->builtin_types.entry_type; - fields[0]->data.x_type = type_entry->data.maybe.child_type; - - break; - } - case ZigTypeIdAnyFrame: { - result = g->pass1_arena->create(); - result->special = ConstValSpecialStatic; - result->type = ir_type_info_get_type(ira, "AnyFrame", nullptr); - - ZigValue **fields = alloc_const_vals_ptrs(g, 1); - result->data.x_struct.fields = fields; - - // child: ?type - ensure_field_index(result->type, "child", 0); - fields[0]->special = ConstValSpecialStatic; - fields[0]->type = get_optional_type(g, g->builtin_types.entry_type); - fields[0]->data.x_optional = (type_entry->data.any_frame.result_type == nullptr) ? nullptr : - create_const_type(g, type_entry->data.any_frame.result_type); - break; - } - case ZigTypeIdEnum: - { - if ((err = type_resolve(g, type_entry, ResolveStatusSizeKnown))) - return err; - - result = g->pass1_arena->create(); - result->special = ConstValSpecialStatic; - result->type = ir_type_info_get_type(ira, "Enum", nullptr); - - ZigValue **fields = alloc_const_vals_ptrs(g, 5); - result->data.x_struct.fields = fields; - - // layout: ContainerLayout - ensure_field_index(result->type, "layout", 0); - fields[0]->special = ConstValSpecialStatic; - fields[0]->type = ir_type_info_get_type(ira, "ContainerLayout", nullptr); - bigint_init_unsigned(&fields[0]->data.x_enum_tag, type_entry->data.enumeration.layout); - // tag_type: type - ensure_field_index(result->type, "tag_type", 1); - fields[1]->special = ConstValSpecialStatic; - fields[1]->type = g->builtin_types.entry_type; - fields[1]->data.x_type = type_entry->data.enumeration.tag_int_type; - // fields: []Type.EnumField - ensure_field_index(result->type, "fields", 2); - - ZigType *type_info_enum_field_type = ir_type_info_get_type(ira, "EnumField", nullptr); - if ((err = type_resolve(g, type_info_enum_field_type, ResolveStatusSizeKnown))) { - zig_unreachable(); - } - uint32_t enum_field_count = type_entry->data.enumeration.src_field_count; - - ZigValue *enum_field_array = g->pass1_arena->create(); - enum_field_array->special = ConstValSpecialStatic; - enum_field_array->type = get_array_type(g, type_info_enum_field_type, enum_field_count, nullptr); - enum_field_array->data.x_array.special = ConstArraySpecialNone; - enum_field_array->data.x_array.data.s_none.elements = g->pass1_arena->allocate(enum_field_count); - - init_const_slice(g, fields[2], enum_field_array, 0, enum_field_count, false, nullptr); - - for (uint32_t enum_field_index = 0; enum_field_index < enum_field_count; enum_field_index++) - { - TypeEnumField *enum_field = &type_entry->data.enumeration.fields[enum_field_index]; - ZigValue *enum_field_val = &enum_field_array->data.x_array.data.s_none.elements[enum_field_index]; - make_enum_field_val(ira, enum_field_val, enum_field, type_info_enum_field_type); - enum_field_val->parent.id = ConstParentIdArray; - enum_field_val->parent.data.p_array.array_val = enum_field_array; - enum_field_val->parent.data.p_array.elem_index = enum_field_index; - } - // decls: []Type.Declaration - ensure_field_index(result->type, "decls", 3); - if ((err = ir_make_type_info_decls(ira, source_node, fields[3], - type_entry->data.enumeration.decls_scope, false))) - { - return err; - } - // is_exhaustive: bool - ensure_field_index(result->type, "is_exhaustive", 4); - fields[4]->special = ConstValSpecialStatic; - fields[4]->type = g->builtin_types.entry_bool; - fields[4]->data.x_bool = !type_entry->data.enumeration.non_exhaustive; - - break; - } - case ZigTypeIdErrorSet: - { - result = g->pass1_arena->create(); - result->special = ConstValSpecialStatic; - result->type = ir_type_info_get_type(ira, "ErrorSet", nullptr); - - ZigType *type_info_error_type = ir_type_info_get_type(ira, "Error", nullptr); - if (!resolve_inferred_error_set(g, type_entry, source_node)) { - return ErrorSemanticAnalyzeFail; - } - if (type_is_global_error_set(type_entry)) { - result->data.x_optional = nullptr; - break; - } - if ((err = type_resolve(g, type_info_error_type, ResolveStatusSizeKnown))) { - zig_unreachable(); - } - ZigValue *slice_val = g->pass1_arena->create(); - result->data.x_optional = slice_val; - - uint32_t error_count = type_entry->data.error_set.err_count; - ZigValue *error_array = g->pass1_arena->create(); - error_array->special = ConstValSpecialStatic; - error_array->type = get_array_type(g, type_info_error_type, error_count, nullptr); - error_array->data.x_array.special = ConstArraySpecialNone; - error_array->data.x_array.data.s_none.elements = g->pass1_arena->allocate(error_count); - - init_const_slice(g, slice_val, error_array, 0, error_count, false, nullptr); - for (uint32_t error_index = 0; error_index < error_count; error_index++) { - ErrorTableEntry *error = type_entry->data.error_set.errors[error_index]; - ZigValue *error_val = &error_array->data.x_array.data.s_none.elements[error_index]; - - error_val->special = ConstValSpecialStatic; - error_val->type = type_info_error_type; - - ZigValue **inner_fields = alloc_const_vals_ptrs(g, 1); - - ZigValue *name = nullptr; - if (error->cached_error_name_val != nullptr) - name = error->cached_error_name_val; - if (name == nullptr) - name = create_const_str_lit(g, &error->name)->data.x_ptr.data.ref.pointee; - init_const_slice(g, inner_fields[0], name, 0, buf_len(&error->name), true, nullptr); - - error_val->data.x_struct.fields = inner_fields; - error_val->parent.id = ConstParentIdArray; - error_val->parent.data.p_array.array_val = error_array; - error_val->parent.data.p_array.elem_index = error_index; - } - - break; - } - case ZigTypeIdErrorUnion: - { - result = g->pass1_arena->create(); - result->special = ConstValSpecialStatic; - result->type = ir_type_info_get_type(ira, "ErrorUnion", nullptr); - - ZigValue **fields = alloc_const_vals_ptrs(g, 2); - result->data.x_struct.fields = fields; - - // error_set: type - ensure_field_index(result->type, "error_set", 0); - fields[0]->special = ConstValSpecialStatic; - fields[0]->type = g->builtin_types.entry_type; - fields[0]->data.x_type = type_entry->data.error_union.err_set_type; - - // payload: type - ensure_field_index(result->type, "payload", 1); - fields[1]->special = ConstValSpecialStatic; - fields[1]->type = g->builtin_types.entry_type; - fields[1]->data.x_type = type_entry->data.error_union.payload_type; - - break; - } - case ZigTypeIdUnion: - { - if ((err = type_resolve(g, type_entry, ResolveStatusSizeKnown))) - return err; - - result = g->pass1_arena->create(); - result->special = ConstValSpecialStatic; - result->type = ir_type_info_get_type(ira, "Union", nullptr); - - ZigValue **fields = alloc_const_vals_ptrs(g, 4); - result->data.x_struct.fields = fields; - - // layout: ContainerLayout - ensure_field_index(result->type, "layout", 0); - fields[0]->special = ConstValSpecialStatic; - fields[0]->type = ir_type_info_get_type(ira, "ContainerLayout", nullptr); - bigint_init_unsigned(&fields[0]->data.x_enum_tag, type_entry->data.unionation.layout); - // tag_type: ?type - ensure_field_index(result->type, "tag_type", 1); - fields[1]->special = ConstValSpecialStatic; - fields[1]->type = get_optional_type(g, g->builtin_types.entry_type); - - AstNode *union_decl_node = type_entry->data.unionation.decl_node; - if (union_decl_node->data.container_decl.auto_enum || - union_decl_node->data.container_decl.init_arg_expr != nullptr) - { - ZigValue *tag_type = g->pass1_arena->create(); - tag_type->special = ConstValSpecialStatic; - tag_type->type = g->builtin_types.entry_type; - tag_type->data.x_type = type_entry->data.unionation.tag_type; - fields[1]->data.x_optional = tag_type; - } else { - fields[1]->data.x_optional = nullptr; - } - // fields: []Type.UnionField - ensure_field_index(result->type, "fields", 2); - - ZigType *type_info_union_field_type = ir_type_info_get_type(ira, "UnionField", nullptr); - if ((err = type_resolve(g, type_info_union_field_type, ResolveStatusSizeKnown))) - zig_unreachable(); - uint32_t union_field_count = type_entry->data.unionation.src_field_count; - - ZigValue *union_field_array = g->pass1_arena->create(); - union_field_array->special = ConstValSpecialStatic; - union_field_array->type = get_array_type(g, type_info_union_field_type, union_field_count, nullptr); - union_field_array->data.x_array.special = ConstArraySpecialNone; - union_field_array->data.x_array.data.s_none.elements = g->pass1_arena->allocate(union_field_count); - - init_const_slice(g, fields[2], union_field_array, 0, union_field_count, false, nullptr); - - for (uint32_t union_field_index = 0; union_field_index < union_field_count; union_field_index++) { - TypeUnionField *union_field = &type_entry->data.unionation.fields[union_field_index]; - ZigValue *union_field_val = &union_field_array->data.x_array.data.s_none.elements[union_field_index]; - - union_field_val->special = ConstValSpecialStatic; - union_field_val->type = type_info_union_field_type; - - ZigValue **inner_fields = alloc_const_vals_ptrs(g, 3); - // field_type: type - inner_fields[1]->special = ConstValSpecialStatic; - inner_fields[1]->type = g->builtin_types.entry_type; - inner_fields[1]->data.x_type = union_field->type_entry; - - // alignment: comptime_int - inner_fields[2]->special = ConstValSpecialStatic; - inner_fields[2]->type = g->builtin_types.entry_num_lit_int; - bigint_init_unsigned(&inner_fields[2]->data.x_bigint, union_field->align); - - ZigValue *name = create_const_str_lit(g, union_field->name)->data.x_ptr.data.ref.pointee; - init_const_slice(g, inner_fields[0], name, 0, buf_len(union_field->name), true, nullptr); - - union_field_val->data.x_struct.fields = inner_fields; - union_field_val->parent.id = ConstParentIdArray; - union_field_val->parent.data.p_array.array_val = union_field_array; - union_field_val->parent.data.p_array.elem_index = union_field_index; - } - // decls: []Type.Declaration - ensure_field_index(result->type, "decls", 3); - if ((err = ir_make_type_info_decls(ira, source_node, fields[3], - type_entry->data.unionation.decls_scope, false))) - { - return err; - } - - break; - } - case ZigTypeIdStruct: - { - if (type_entry->data.structure.special == StructSpecialSlice) { - result = create_ptr_like_type_info(ira, scope, source_node, type_entry); - if (result == nullptr) - return ErrorSemanticAnalyzeFail; - break; - } - - if ((err = type_resolve(g, type_entry, ResolveStatusSizeKnown))) - return err; - - result = g->pass1_arena->create(); - result->special = ConstValSpecialStatic; - result->type = ir_type_info_get_type(ira, "Struct", nullptr); - - ZigValue **fields = alloc_const_vals_ptrs(g, 5); - result->data.x_struct.fields = fields; - - // layout: ContainerLayout - ensure_field_index(result->type, "layout", 0); - fields[0]->special = ConstValSpecialStatic; - fields[0]->type = ir_type_info_get_type(ira, "ContainerLayout", nullptr); - bigint_init_unsigned(&fields[0]->data.x_enum_tag, type_entry->data.structure.layout); - - // backing_integer: ?type - ensure_field_index(result->type, "backing_integer", 1); - fields[1]->special = ConstValSpecialStatic; - fields[1]->type = get_optional_type(g, g->builtin_types.entry_type); - // This is always null in stage1, as stage1 does not support explicit backing integers - // for packed structs. - fields[1]->data.x_optional = nullptr; - - // fields: []Type.StructField - ensure_field_index(result->type, "fields", 2); - - ZigType *type_info_struct_field_type = ir_type_info_get_type(ira, "StructField", nullptr); - if ((err = type_resolve(g, type_info_struct_field_type, ResolveStatusSizeKnown))) { - zig_unreachable(); - } - uint32_t struct_field_count = type_entry->data.structure.src_field_count; - - ZigValue *struct_field_array = g->pass1_arena->create(); - struct_field_array->special = ConstValSpecialStatic; - struct_field_array->type = get_array_type(g, type_info_struct_field_type, struct_field_count, nullptr); - struct_field_array->data.x_array.special = ConstArraySpecialNone; - struct_field_array->data.x_array.data.s_none.elements = g->pass1_arena->allocate(struct_field_count); - - init_const_slice(g, fields[2], struct_field_array, 0, struct_field_count, false, nullptr); - - for (uint32_t struct_field_index = 0; struct_field_index < struct_field_count; struct_field_index++) { - TypeStructField *struct_field = type_entry->data.structure.fields[struct_field_index]; - ZigValue *struct_field_val = &struct_field_array->data.x_array.data.s_none.elements[struct_field_index]; - - struct_field_val->special = ConstValSpecialStatic; - struct_field_val->type = type_info_struct_field_type; - - ZigValue **inner_fields = alloc_const_vals_ptrs(g, 5); - - inner_fields[1]->special = ConstValSpecialStatic; - inner_fields[1]->type = g->builtin_types.entry_type; - inner_fields[1]->data.x_type = struct_field->type_entry; - - // default_value: ?*const anyopaque - inner_fields[2]->special = ConstValSpecialStatic; - inner_fields[2]->type = g->builtin_types.entry_opt_ptr_const_anyopaque; - memoize_field_init_val(g, type_entry, struct_field); - if (struct_field->init_val != nullptr && - type_is_invalid(struct_field->init_val->type)) - { - return ErrorSemanticAnalyzeFail; - } - ZigValue *ptr_to_sent = (struct_field->init_val == nullptr) ? nullptr : - create_const_ptr_ref(g, struct_field->init_val, true); - set_optional_payload(inner_fields[2], ptr_to_sent); - - // is_comptime: bool - inner_fields[3]->special = ConstValSpecialStatic; - inner_fields[3]->type = g->builtin_types.entry_bool; - inner_fields[3]->data.x_bool = struct_field->is_comptime; - - // alignment: comptime_int - inner_fields[4]->special = ConstValSpecialStatic; - inner_fields[4]->type = g->builtin_types.entry_num_lit_int; - bigint_init_unsigned(&inner_fields[4]->data.x_bigint, struct_field->align); - - ZigValue *name = create_const_str_lit(g, struct_field->name)->data.x_ptr.data.ref.pointee; - init_const_slice(g, inner_fields[0], name, 0, buf_len(struct_field->name), true, nullptr); - - struct_field_val->data.x_struct.fields = inner_fields; - struct_field_val->parent.id = ConstParentIdArray; - struct_field_val->parent.data.p_array.array_val = struct_field_array; - struct_field_val->parent.data.p_array.elem_index = struct_field_index; - } - // decls: []Type.Declaration - ensure_field_index(result->type, "decls", 3); - if ((err = ir_make_type_info_decls(ira, source_node, fields[3], - type_entry->data.structure.decls_scope, false))) - { - return err; - } - - // is_tuple: bool - ensure_field_index(result->type, "is_tuple", 4); - fields[4]->special = ConstValSpecialStatic; - fields[4]->type = g->builtin_types.entry_bool; - fields[4]->data.x_bool = is_tuple(type_entry); - - break; - } - case ZigTypeIdFn: - { - result = g->pass1_arena->create(); - result->special = ConstValSpecialStatic; - result->type = ir_type_info_get_type(ira, "Fn", nullptr); - - ZigValue **fields = alloc_const_vals_ptrs(g, 7); - result->data.x_struct.fields = fields; - - // calling_convention: Type.CallingConvention - ensure_field_index(result->type, "calling_convention", 0); - fields[0]->special = ConstValSpecialStatic; - fields[0]->type = get_builtin_type(g, "CallingConvention"); - bigint_init_unsigned(&fields[0]->data.x_enum_tag, type_entry->data.fn.fn_type_id.cc); - // alignment: comptime_int - ensure_field_index(result->type, "alignment", 1); - fields[1]->special = ConstValSpecialStatic; - fields[1]->type = g->builtin_types.entry_num_lit_int; - bigint_init_unsigned(&fields[1]->data.x_bigint, get_ptr_align(g, type_entry)); - // is_generic: bool - ensure_field_index(result->type, "is_generic", 2); - bool is_generic = type_entry->data.fn.is_generic; - fields[2]->special = ConstValSpecialStatic; - fields[2]->type = g->builtin_types.entry_bool; - fields[2]->data.x_bool = is_generic; - // is_varargs: bool - ensure_field_index(result->type, "is_var_args", 3); - bool is_varargs = type_entry->data.fn.fn_type_id.is_var_args; - fields[3]->special = ConstValSpecialStatic; - fields[3]->type = g->builtin_types.entry_bool; - fields[3]->data.x_bool = is_varargs; - // return_type: ?type - ensure_field_index(result->type, "return_type", 4); - fields[4]->special = ConstValSpecialStatic; - fields[4]->type = get_optional_type(g, g->builtin_types.entry_type); - if (type_entry->data.fn.fn_type_id.return_type == nullptr) - fields[4]->data.x_optional = nullptr; - else { - ZigValue *return_type = g->pass1_arena->create(); - return_type->special = ConstValSpecialStatic; - return_type->type = g->builtin_types.entry_type; - return_type->data.x_type = type_entry->data.fn.fn_type_id.return_type; - fields[4]->data.x_optional = return_type; - } - // args: []Type.Fn.Param - ZigType *type_info_fn_arg_type = ir_type_info_get_type(ira, "Param", result->type); - if ((err = type_resolve(g, type_info_fn_arg_type, ResolveStatusSizeKnown))) { - zig_unreachable(); - } - size_t fn_arg_count = type_entry->data.fn.fn_type_id.param_count; - - ZigValue *fn_arg_array = g->pass1_arena->create(); - fn_arg_array->special = ConstValSpecialStatic; - fn_arg_array->type = get_array_type(g, type_info_fn_arg_type, fn_arg_count, nullptr); - fn_arg_array->data.x_array.special = ConstArraySpecialNone; - fn_arg_array->data.x_array.data.s_none.elements = g->pass1_arena->allocate(fn_arg_count); - - init_const_slice(g, fields[5], fn_arg_array, 0, fn_arg_count, false, nullptr); - - for (size_t fn_arg_index = 0; fn_arg_index < fn_arg_count; fn_arg_index++) { - FnTypeParamInfo *fn_param_info = &type_entry->data.fn.fn_type_id.param_info[fn_arg_index]; - ZigValue *fn_arg_val = &fn_arg_array->data.x_array.data.s_none.elements[fn_arg_index]; - - fn_arg_val->special = ConstValSpecialStatic; - fn_arg_val->type = type_info_fn_arg_type; - - bool arg_is_generic = fn_param_info->type == nullptr; - if (arg_is_generic) assert(is_generic); - - ZigValue **inner_fields = alloc_const_vals_ptrs(g, 3); - inner_fields[0]->special = ConstValSpecialStatic; - inner_fields[0]->type = g->builtin_types.entry_bool; - inner_fields[0]->data.x_bool = arg_is_generic; - inner_fields[1]->special = ConstValSpecialStatic; - inner_fields[1]->type = g->builtin_types.entry_bool; - inner_fields[1]->data.x_bool = fn_param_info->is_noalias; - inner_fields[2]->special = ConstValSpecialStatic; - inner_fields[2]->type = get_optional_type(g, g->builtin_types.entry_type); - - if (arg_is_generic) - inner_fields[2]->data.x_optional = nullptr; - else { - ZigValue *arg_type = g->pass1_arena->create(); - arg_type->special = ConstValSpecialStatic; - arg_type->type = g->builtin_types.entry_type; - arg_type->data.x_type = fn_param_info->type; - inner_fields[2]->data.x_optional = arg_type; - } - - fn_arg_val->data.x_struct.fields = inner_fields; - fn_arg_val->parent.id = ConstParentIdArray; - fn_arg_val->parent.data.p_array.array_val = fn_arg_array; - fn_arg_val->parent.data.p_array.elem_index = fn_arg_index; - } - - break; - } - case ZigTypeIdBoundFn: - { - ZigType *fn_type = type_entry->data.bound_fn.fn_type; - assert(fn_type->id == ZigTypeIdFn); - if ((err = ir_make_type_info_value(ira, scope, source_node, fn_type, &result))) - return err; - - break; - } - case ZigTypeIdOpaque: - { - result = g->pass1_arena->create(); - result->special = ConstValSpecialStatic; - result->type = ir_type_info_get_type(ira, "Opaque", nullptr); - - ZigValue **fields = alloc_const_vals_ptrs(g, 1); - result->data.x_struct.fields = fields; - - // decls: []Type.Declaration - ensure_field_index(result->type, "decls", 0); - if ((err = ir_make_type_info_decls(ira, source_node, fields[0], - type_entry->data.opaque.decls_scope, false))) - { - return err; - } - - break; - } - case ZigTypeIdFnFrame: - { - result = g->pass1_arena->create(); - result->special = ConstValSpecialStatic; - result->type = ir_type_info_get_type(ira, "Frame", nullptr); - ZigValue **fields = alloc_const_vals_ptrs(g, 1); - result->data.x_struct.fields = fields; - ZigFn *fn = type_entry->data.frame.fn; - // function: ?*const anyopaque - ensure_field_index(result->type, "function", 0); - fields[0]->special = ConstValSpecialStatic; - fields[0]->type = get_pointer_to_type(g, g->builtin_types.entry_anyopaque, true); - fields[0]->data.x_ptr.special = ConstPtrSpecialFunction; - fields[0]->data.x_ptr.data.fn.fn_entry = fn; - break; - } - } - - assert(result != nullptr); - g->type_info_cache.put(type_entry, result); - *out = result; - return ErrorNone; -} - -static Stage1AirInst *ir_analyze_instruction_type_info(IrAnalyze *ira, Stage1ZirInstTypeInfo *instruction) { - Error err; - Stage1AirInst *type_value = instruction->type_value->child; - ZigType *type_entry = ir_resolve_type(ira, type_value); - if (type_is_invalid(type_entry)) - return ira->codegen->invalid_inst_gen; - - ZigType *result_type = ir_type_info_get_type(ira, nullptr, nullptr); - - ZigValue *payload; - if ((err = ir_make_type_info_value(ira, instruction->base.scope, instruction->base.source_node, type_entry, &payload))) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *result = ir_const(ira, instruction->base.scope, instruction->base.source_node, result_type); - ZigValue *out_val = result->value; - bigint_init_unsigned(&out_val->data.x_union.tag, type_id_index(type_entry)); - out_val->data.x_union.payload = payload; - - if (payload != nullptr) { - payload->parent.id = ConstParentIdUnion; - payload->parent.data.p_union.union_val = out_val; - } - - return result; -} - -static ZigValue *get_const_field(IrAnalyze *ira, AstNode *source_node, ZigValue *struct_value, - const char *name, size_t field_index) -{ - Error err; - ensure_field_index(struct_value->type, name, field_index); - TypeStructField *field = struct_value->type->data.structure.fields[field_index]; - ZigValue *val = field->is_comptime ? field->init_val : - struct_value->data.x_struct.fields[field_index]; - if ((err = ir_resolve_const_val(ira->codegen, ira->new_irb.exec, source_node, val, UndefBad))) - return nullptr; - return val; -} - -static Error get_const_field_sentinel(IrAnalyze *ira, Scope *scope, AstNode *source_node, - ZigValue *struct_value, const char *name, size_t field_index, ZigType *elem_type, - ZigValue **result) -{ - ZigValue *field_val = get_const_field(ira, source_node, struct_value, name, field_index); - if (field_val == nullptr) - return ErrorSemanticAnalyzeFail; - - // type of `field_val` is `?*const anyopaque`. - if (field_val->data.x_ptr.special == ConstPtrSpecialNull) { - *result = nullptr; - return ErrorNone; - } - - ZigValue *pointee = const_ptr_pointee_unchecked_no_isf(ira->codegen, field_val); - if (pointee == nullptr) - return ErrorSemanticAnalyzeFail; - - *result = pointee; - return ErrorNone; -} - -static Error get_const_field_bool(IrAnalyze *ira, AstNode *source_node, ZigValue *struct_value, - const char *name, size_t field_index, bool *out) -{ - ZigValue *value = get_const_field(ira, source_node, struct_value, name, field_index); - if (value == nullptr) - return ErrorSemanticAnalyzeFail; - assert(value->type == ira->codegen->builtin_types.entry_bool); - *out = value->data.x_bool; - return ErrorNone; -} - -static BigInt *get_const_field_lit_int(IrAnalyze *ira, AstNode *source_node, ZigValue *struct_value, const char *name, size_t field_index) -{ - ZigValue *value = get_const_field(ira, source_node, struct_value, name, field_index); - if (value == nullptr) - return nullptr; - assert(value->type == ira->codegen->builtin_types.entry_num_lit_int); - return &value->data.x_bigint; -} - -static ZigType *get_const_field_meta_type(IrAnalyze *ira, AstNode *source_node, ZigValue *struct_value, const char *name, size_t field_index) -{ - ZigValue *value = get_const_field(ira, source_node, struct_value, name, field_index); - if (value == nullptr) - return ira->codegen->invalid_inst_gen->value->type; - assert(value->type == ira->codegen->builtin_types.entry_type); - return value->data.x_type; -} - -static ZigType *get_const_field_meta_type_optional(IrAnalyze *ira, AstNode *source_node, - ZigValue *struct_value, const char *name, size_t field_index) -{ - ZigValue *value = get_const_field(ira, source_node, struct_value, name, field_index); - if (value == nullptr) - return ira->codegen->invalid_inst_gen->value->type; - assert(value->type->id == ZigTypeIdOptional); - assert(value->type->data.maybe.child_type == ira->codegen->builtin_types.entry_type); - if (value->data.x_optional == nullptr) - return nullptr; - return value->data.x_optional->data.x_type; -} - -static Error get_const_field_buf(IrAnalyze *ira, AstNode *source_node, ZigValue *struct_value, - const char *name, size_t field_index, Buf *out) -{ - ZigValue *slice = get_const_field(ira, source_node, struct_value, name, field_index); - ZigValue *ptr = slice->data.x_struct.fields[slice_ptr_index]; - ZigValue *len = slice->data.x_struct.fields[slice_len_index]; - assert(ptr->data.x_ptr.special == ConstPtrSpecialBaseArray); - ZigValue *arr = ptr->data.x_ptr.data.base_array.array_val; - assert(arr->special == ConstValSpecialStatic); - - const size_t start_value = ptr->data.x_ptr.data.base_array.elem_index; - const size_t len_value = bigint_as_usize(&len->data.x_bigint); - - switch (arr->data.x_array.special) { - case ConstArraySpecialUndef: - return ErrorSemanticAnalyzeFail; - case ConstArraySpecialNone: { - assert(start_value <= arr->type->data.array.len); - assert(start_value + len_value <= arr->type->data.array.len); - buf_resize(out, 0); - for (size_t j = 0; j < len_value; j++) { - ZigValue *ch_val = &arr->data.x_array.data.s_none.elements[start_value + j]; - unsigned ch = bigint_as_u32(&ch_val->data.x_bigint); - buf_append_char(out, ch); - } - break; - } - case ConstArraySpecialBuf: - assert(start_value <= buf_len(arr->data.x_array.data.s_buf)); - assert(start_value + len_value <= buf_len(arr->data.x_array.data.s_buf)); - buf_init_from_mem(out, buf_ptr(arr->data.x_array.data.s_buf) + start_value, len_value); - break; - } - return ErrorNone; -} - -static ZigType *type_info_to_type(IrAnalyze *ira, Scope *scope, AstNode *source_node, ZigTypeId tagTypeId, ZigValue *payload) { - Error err; - switch (tagTypeId) { - case ZigTypeIdInvalid: - zig_unreachable(); - case ZigTypeIdMetaType: - return ira->codegen->builtin_types.entry_type; - case ZigTypeIdVoid: - return ira->codegen->builtin_types.entry_void; - case ZigTypeIdBool: - return ira->codegen->builtin_types.entry_bool; - case ZigTypeIdUnreachable: - return ira->codegen->builtin_types.entry_unreachable; - case ZigTypeIdComptimeFloat: - return ira->codegen->builtin_types.entry_num_lit_float; - case ZigTypeIdComptimeInt: - return ira->codegen->builtin_types.entry_num_lit_int; - case ZigTypeIdUndefined: - return ira->codegen->builtin_types.entry_undef; - case ZigTypeIdNull: - return ira->codegen->builtin_types.entry_null; - case ZigTypeIdEnumLiteral: - return ira->codegen->builtin_types.entry_enum_literal; - default: - if ((err = ir_resolve_const_val(ira->codegen, ira->new_irb.exec, source_node, payload, UndefBad))) - return ira->codegen->invalid_inst_gen->value->type; - } - switch (tagTypeId) { - case ZigTypeIdInvalid: - case ZigTypeIdMetaType: - case ZigTypeIdVoid: - case ZigTypeIdBool: - case ZigTypeIdUnreachable: - case ZigTypeIdComptimeFloat: - case ZigTypeIdComptimeInt: - case ZigTypeIdUndefined: - case ZigTypeIdNull: - case ZigTypeIdEnumLiteral: - zig_unreachable(); - case ZigTypeIdInt: { - assert(payload->special == ConstValSpecialStatic); - assert(payload->type == ir_type_info_get_type(ira, "Int", nullptr)); - BigInt *bi = get_const_field_lit_int(ira, source_node, payload, "bits", 1); - if (bi == nullptr) - return ira->codegen->invalid_inst_gen->value->type; - ZigValue *value = get_const_field(ira, source_node, payload, "signedness", 0); - if (value == nullptr) - return ira->codegen->invalid_inst_gen->value->type; - assert(value->type == get_builtin_type(ira->codegen, "Signedness")); - bool is_signed = !bigint_as_u32(&value->data.x_enum_tag); - return get_int_type(ira->codegen, is_signed, bigint_as_u32(bi)); - } - case ZigTypeIdFloat: - { - assert(payload->special == ConstValSpecialStatic); - assert(payload->type == ir_type_info_get_type(ira, "Float", nullptr)); - BigInt *bi = get_const_field_lit_int(ira, source_node, payload, "bits", 0); - if (bi == nullptr) - return ira->codegen->invalid_inst_gen->value->type; - uint32_t bits = bigint_as_u32(bi); - switch (bits) { - case 16: return ira->codegen->builtin_types.entry_f16; - case 32: return ira->codegen->builtin_types.entry_f32; - case 64: return ira->codegen->builtin_types.entry_f64; - case 80: return ira->codegen->builtin_types.entry_f80; - case 128: return ira->codegen->builtin_types.entry_f128; - } - ir_add_error_node(ira, source_node, buf_sprintf("%d-bit float unsupported", bits)); - return ira->codegen->invalid_inst_gen->value->type; - } - case ZigTypeIdPointer: - { - ZigType *type_info_pointer_type = ir_type_info_get_type(ira, "Pointer", nullptr); - assert(payload->special == ConstValSpecialStatic); - assert(payload->type == type_info_pointer_type); - ZigValue *size_value = get_const_field(ira, source_node, payload, "size", 0); - if (size_value == nullptr) - return ira->codegen->invalid_inst_gen->value->type; - - assert(size_value->type == ir_type_info_get_type(ira, "Size", type_info_pointer_type)); - BuiltinPtrSize size_enum_index = (BuiltinPtrSize)bigint_as_u32(&size_value->data.x_enum_tag); - PtrLen ptr_len = size_enum_index_to_ptr_len(size_enum_index); - ZigType *elem_type = get_const_field_meta_type(ira, source_node, payload, "child", 5); - if (type_is_invalid(elem_type)) - return ira->codegen->invalid_inst_gen->value->type; - ZigValue *sentinel; - if ((err = get_const_field_sentinel(ira, scope, source_node, payload, "sentinel", 7, - elem_type, &sentinel))) - { - return ira->codegen->invalid_inst_gen->value->type; - } - if (sentinel != nullptr && (size_enum_index == BuiltinPtrSizeOne || size_enum_index == BuiltinPtrSizeC)) { - ir_add_error_node(ira, source_node, - buf_sprintf("sentinels are only allowed on slices and unknown-length pointers")); - return ira->codegen->invalid_inst_gen->value->type; - } - - BigInt *alignment = get_const_field_lit_int(ira, source_node, payload, "alignment", 3); - if (alignment == nullptr) - return ira->codegen->invalid_inst_gen->value->type; - - ZigValue *as_value = get_const_field(ira, source_node, payload, "address_space", 4); - if (as_value == nullptr) - return ira->codegen->invalid_inst_gen->value->type; - assert(as_value->special == ConstValSpecialStatic); - assert(as_value->type == get_builtin_type(ira->codegen, "AddressSpace")); - AddressSpace as = (AddressSpace)bigint_as_u32(&as_value->data.x_enum_tag); - if (as != AddressSpaceGeneric) { - ir_add_error_node(ira, source_node, buf_sprintf( - "address space '%s' not available in stage 1 compiler, must be .generic", - address_space_name(as))); - return ira->codegen->invalid_inst_gen->value->type; - } - - bool is_const; - if ((err = get_const_field_bool(ira, source_node, payload, "is_const", 1, &is_const))) - return ira->codegen->invalid_inst_gen->value->type; - - bool is_volatile; - if ((err = get_const_field_bool(ira, source_node, payload, "is_volatile", 2, - &is_volatile))) - { - return ira->codegen->invalid_inst_gen->value->type; - } - - bool is_allowzero; - if ((err = get_const_field_bool(ira, source_node, payload, "is_allowzero", 6, - &is_allowzero))) - { - return ira->codegen->invalid_inst_gen->value->type; - } - - if ((err = type_resolve(ira->codegen, elem_type, ResolveStatusAlignmentKnown))) { - return ira->codegen->invalid_inst_gen->value->type; - } - - ZigType *ptr_type = get_pointer_to_type_extra2(ira->codegen, - elem_type, - is_const, - is_volatile, - ptr_len, - bigint_as_u32(alignment), - 0, // bit_offset_in_host - 0, // host_int_bytes - is_allowzero, - VECTOR_INDEX_NONE, nullptr, sentinel); - if (size_enum_index != BuiltinPtrSizeSlice) - return ptr_type; - return get_slice_type(ira->codegen, ptr_type); - } - case ZigTypeIdArray: { - assert(payload->special == ConstValSpecialStatic); - assert(payload->type == ir_type_info_get_type(ira, "Array", nullptr)); - ZigType *elem_type = get_const_field_meta_type(ira, source_node, payload, "child", 1); - if (type_is_invalid(elem_type)) - return ira->codegen->invalid_inst_gen->value->type; - ZigValue *sentinel; - if ((err = get_const_field_sentinel(ira, scope, source_node, payload, "sentinel", 2, - elem_type, &sentinel))) - { - return ira->codegen->invalid_inst_gen->value->type; - } - BigInt *bi = get_const_field_lit_int(ira, source_node, payload, "len", 0); - if (bi == nullptr) - return ira->codegen->invalid_inst_gen->value->type; - return get_array_type(ira->codegen, elem_type, bigint_as_u64(bi), sentinel); - } - case ZigTypeIdOptional: { - assert(payload->special == ConstValSpecialStatic); - assert(payload->type == ir_type_info_get_type(ira, "Optional", nullptr)); - ZigType *child_type = get_const_field_meta_type(ira, source_node, payload, "child", 0); - if (type_is_invalid(child_type)) - return ira->codegen->invalid_inst_gen->value->type; - return get_optional_type(ira->codegen, child_type); - } - case ZigTypeIdErrorUnion: { - assert(payload->special == ConstValSpecialStatic); - assert(payload->type == ir_type_info_get_type(ira, "ErrorUnion", nullptr)); - ZigType *err_set_type = get_const_field_meta_type(ira, source_node, payload, "error_set", 0); - if (type_is_invalid(err_set_type)) - return ira->codegen->invalid_inst_gen->value->type; - - ZigType *payload_type = get_const_field_meta_type(ira, source_node, payload, "payload", 1); - if (type_is_invalid(payload_type)) - return ira->codegen->invalid_inst_gen->value->type; - - return get_error_union_type(ira->codegen, err_set_type, payload_type); - } - case ZigTypeIdOpaque: { - assert(payload->special == ConstValSpecialStatic); - assert(payload->type == ir_type_info_get_type(ira, "Opaque", nullptr)); - - ZigValue *decls_value = get_const_field(ira, source_node, payload, "decls", 0); - if (decls_value == nullptr) - return ira->codegen->invalid_inst_gen->value->type; - assert(decls_value->special == ConstValSpecialStatic); - assert(is_slice(decls_value->type)); - ZigValue *decls_len_value = decls_value->data.x_struct.fields[slice_len_index]; - size_t decls_len = bigint_as_usize(&decls_len_value->data.x_bigint); - if (decls_len != 0) { - ir_add_error_node(ira, source_node, buf_create_from_str("Type.Struct.decls must be empty for @Type")); - return ira->codegen->invalid_inst_gen->value->type; - } - - Buf *bare_name = buf_alloc(); - Buf *full_name = get_anon_type_name(ira->codegen, - ira->zir, "opaque", scope, source_node, bare_name, nullptr); - return get_opaque_type(ira->codegen, - scope, source_node, buf_ptr(full_name), bare_name); - } - case ZigTypeIdVector: { - assert(payload->special == ConstValSpecialStatic); - assert(payload->type == ir_type_info_get_type(ira, "Vector", nullptr)); - BigInt *len = get_const_field_lit_int(ira, source_node, payload, "len", 0); - if (len == nullptr) - return ira->codegen->invalid_inst_gen->value->type; - - ZigType *child_type = get_const_field_meta_type(ira, source_node, payload, "child", 1); - if ((err = ir_validate_vector_elem_type(ira, source_node, child_type))) { - return ira->codegen->invalid_inst_gen->value->type; - } - return get_vector_type(ira->codegen, bigint_as_u32(len), child_type); - } - case ZigTypeIdAnyFrame: { - assert(payload->special == ConstValSpecialStatic); - assert(payload->type == ir_type_info_get_type(ira, "AnyFrame", nullptr)); - ZigType *child_type = get_const_field_meta_type_optional(ira, source_node, payload, "child", 0); - if (child_type != nullptr && type_is_invalid(child_type)) - return ira->codegen->invalid_inst_gen->value->type; - - return get_any_frame_type(ira->codegen, child_type); - } - case ZigTypeIdFnFrame: { - ir_add_error_node(ira, source_node, - buf_sprintf("use the @Frame builtin instead of @Type")); - return ira->codegen->invalid_inst_gen->value->type; - } - case ZigTypeIdErrorSet: { - assert(payload->special == ConstValSpecialStatic); - assert(payload->type->id == ZigTypeIdOptional); - ZigValue *slice = payload->data.x_optional; - if (slice == nullptr) - return ira->codegen->builtin_types.entry_global_error_set; - assert(slice->special == ConstValSpecialStatic); - assert(is_slice(slice->type)); - ZigType *err_set_type = new_type_table_entry(ZigTypeIdErrorSet); - Buf bare_name = BUF_INIT; - buf_init_from_buf(&err_set_type->name, - get_anon_type_name(ira->codegen, ira->zir, "error", scope, source_node, &bare_name, nullptr)); - err_set_type->size_in_bits = ira->codegen->builtin_types.entry_global_error_set->size_in_bits; - err_set_type->abi_align = ira->codegen->builtin_types.entry_global_error_set->abi_align; - err_set_type->abi_size = ira->codegen->builtin_types.entry_global_error_set->abi_size; - ZigValue *ptr = slice->data.x_struct.fields[slice_ptr_index]; - assert(ptr->data.x_ptr.special == ConstPtrSpecialBaseArray);; - assert(ptr->data.x_ptr.data.base_array.elem_index == 0); - ZigValue *arr = ptr->data.x_ptr.data.base_array.array_val; - assert(arr->special == ConstValSpecialStatic); - assert(arr->data.x_array.special == ConstArraySpecialNone); - ZigValue *len = slice->data.x_struct.fields[slice_len_index]; - size_t count = bigint_as_usize(&len->data.x_bigint); - err_set_type->data.error_set.err_count = count; - err_set_type->data.error_set.errors = heap::c_allocator.allocate(count); - bool *already_set = heap::c_allocator.allocate(ira->codegen->errors_by_index.length + count); - for (size_t i = 0; i < count; i++) { - ZigValue *error = &arr->data.x_array.data.s_none.elements[i]; - assert(error->type == ir_type_info_get_type(ira, "Error", nullptr)); - ErrorTableEntry *err_entry = heap::c_allocator.create(); - err_entry->decl_node = source_node; - if ((err = get_const_field_buf(ira, source_node, error, "name", 0, &err_entry->name))) - return ira->codegen->invalid_inst_gen->value->type; - auto existing_entry = ira->codegen->error_table.put_unique(&err_entry->name, err_entry); - if (existing_entry) { - err_entry->value = existing_entry->value->value; - } else { - size_t error_value_count = ira->codegen->errors_by_index.length; - assert((uint32_t)error_value_count < (((uint32_t)1) << (uint32_t)ira->codegen->err_tag_type->data.integral.bit_count)); - err_entry->value = error_value_count; - ira->codegen->errors_by_index.append(err_entry); - } - if (already_set[err_entry->value]) { - ir_add_error_node(ira, source_node, buf_sprintf("duplicate error: %s", buf_ptr(&err_entry->name))); - return ira->codegen->invalid_inst_gen->value->type; - } else { - already_set[err_entry->value] = true; - } - err_set_type->data.error_set.errors[i] = err_entry; - } - return err_set_type; - } - case ZigTypeIdStruct: { - assert(payload->special == ConstValSpecialStatic); - assert(payload->type == ir_type_info_get_type(ira, "Struct", nullptr)); - - ZigValue *layout_value = get_const_field(ira, source_node, payload, "layout", 0); - if (layout_value == nullptr) - return ira->codegen->invalid_inst_gen->value->type; - assert(layout_value->special == ConstValSpecialStatic); - assert(layout_value->type == ir_type_info_get_type(ira, "ContainerLayout", nullptr)); - ContainerLayout layout = (ContainerLayout)bigint_as_u32(&layout_value->data.x_enum_tag); - - ZigType *tag_type = get_const_field_meta_type_optional(ira, source_node, payload, "backing_integer", 1); - if (tag_type != nullptr) { - ir_add_error_node(ira, source_node, buf_create_from_str( - "the stage1 compiler does not support explicit backing integer types on packed structs")); - return ira->codegen->invalid_inst_gen->value->type; - } - - ZigValue *fields_value = get_const_field(ira, source_node, payload, "fields", 2); - if (fields_value == nullptr) - return ira->codegen->invalid_inst_gen->value->type; - assert(fields_value->special == ConstValSpecialStatic); - assert(is_slice(fields_value->type)); - ZigValue *fields_ptr = fields_value->data.x_struct.fields[slice_ptr_index]; - ZigValue *fields_len_value = fields_value->data.x_struct.fields[slice_len_index]; - size_t fields_len = bigint_as_usize(&fields_len_value->data.x_bigint); - - ZigValue *decls_value = get_const_field(ira, source_node, payload, "decls", 3); - if (decls_value == nullptr) - return ira->codegen->invalid_inst_gen->value->type; - assert(decls_value->special == ConstValSpecialStatic); - assert(is_slice(decls_value->type)); - ZigValue *decls_len_value = decls_value->data.x_struct.fields[slice_len_index]; - size_t decls_len = bigint_as_usize(&decls_len_value->data.x_bigint); - if (decls_len != 0) { - ir_add_error_node(ira, source_node, buf_create_from_str("Type.Struct.decls must be empty for @Type")); - return ira->codegen->invalid_inst_gen->value->type; - } - - bool is_tuple; - if ((err = get_const_field_bool(ira, source_node, payload, "is_tuple", 4, &is_tuple))) - return ira->codegen->invalid_inst_gen->value->type; - - ZigType *entry = new_type_table_entry(ZigTypeIdStruct); - buf_init_from_buf(&entry->name, - get_anon_type_name(ira->codegen, ira->zir, "struct", scope, source_node, &entry->name, nullptr)); - entry->data.structure.decl_node = source_node; - entry->data.structure.fields = alloc_type_struct_fields(fields_len); - entry->data.structure.fields_by_name.init(fields_len); - entry->data.structure.src_field_count = fields_len; - entry->data.structure.layout = layout; - entry->data.structure.special = is_tuple ? StructSpecialInferredTuple : StructSpecialNone; - entry->data.structure.created_by_at_type = true; - entry->data.structure.decls_scope = create_decls_scope( - ira->codegen, source_node, scope, entry, get_scope_import(scope), &entry->name); - - assert(fields_ptr->data.x_ptr.special == ConstPtrSpecialBaseArray); - assert(fields_ptr->data.x_ptr.data.base_array.elem_index == 0); - ZigValue *fields_arr = fields_ptr->data.x_ptr.data.base_array.array_val; - assert(fields_arr->special == ConstValSpecialStatic); - assert(fields_arr->data.x_array.special == ConstArraySpecialNone); - for (size_t i = 0; i < fields_len; i++) { - ZigValue *field_value = &fields_arr->data.x_array.data.s_none.elements[i]; - assert(field_value->type == ir_type_info_get_type(ira, "StructField", nullptr)); - TypeStructField *field = entry->data.structure.fields[i]; - field->name = buf_alloc(); - if ((err = get_const_field_buf(ira, source_node, field_value, "name", 0, field->name))) - return ira->codegen->invalid_inst_gen->value->type; - field->decl_node = source_node; - ZigValue *type_value = get_const_field(ira, source_node, field_value, "field_type", 1); - if (type_value == nullptr) - return ira->codegen->invalid_inst_gen->value->type; - field->type_val = type_value; - field->type_entry = type_value->data.x_type; - if (entry->data.structure.fields_by_name.put_unique(field->name, field) != nullptr) { - ir_add_error_node(ira, source_node, buf_sprintf("duplicate struct field '%s'", buf_ptr(field->name))); - return ira->codegen->invalid_inst_gen->value->type; - } - ZigValue *default_value = get_const_field(ira, source_node, field_value, "default_value", 2); - if (default_value == nullptr) - return ira->codegen->invalid_inst_gen->value->type; - - // type of `default_value` is `?*const anyopaque`. - if (default_value->data.x_ptr.special == ConstPtrSpecialNull) { - field->init_val = nullptr; - } else { - ZigValue *pointee = const_ptr_pointee_unchecked_no_isf(ira->codegen, default_value); - if (pointee == nullptr) - return ira->codegen->invalid_inst_gen->value->type; - field->init_val = pointee; - } - - if ((err = get_const_field_bool(ira, source_node, field_value, "is_comptime", 3, &field->is_comptime))) - return ira->codegen->invalid_inst_gen->value->type; - BigInt *alignment = get_const_field_lit_int(ira, source_node, field_value, "alignment", 4); - if (alignment == nullptr) - return ira->codegen->invalid_inst_gen->value->type; - field->align = bigint_as_u32(alignment); - } - - return entry; - } - case ZigTypeIdEnum: { - assert(payload->special == ConstValSpecialStatic); - assert(payload->type == ir_type_info_get_type(ira, "Enum", nullptr)); - - ZigValue *layout_value = get_const_field(ira, source_node, payload, "layout", 0); - if (layout_value == nullptr) - return ira->codegen->invalid_inst_gen->value->type; - - assert(layout_value->special == ConstValSpecialStatic); - assert(layout_value->type == ir_type_info_get_type(ira, "ContainerLayout", nullptr)); - ContainerLayout layout = (ContainerLayout)bigint_as_u32(&layout_value->data.x_enum_tag); - - ZigType *tag_type = get_const_field_meta_type(ira, source_node, payload, "tag_type", 1); - if (type_is_invalid(tag_type)) - return ira->codegen->invalid_inst_gen->value->type; - if (tag_type->id != ZigTypeIdInt) { - ir_add_error_node(ira, source_node, buf_sprintf( - "Type.Enum.tag_type must be an integer type, not '%s'", buf_ptr(&tag_type->name))); - return ira->codegen->invalid_inst_gen->value->type; - } - - ZigValue *fields_value = get_const_field(ira, source_node, payload, "fields", 2); - if (fields_value == nullptr) - return ira->codegen->invalid_inst_gen->value->type; - - assert(fields_value->special == ConstValSpecialStatic); - assert(is_slice(fields_value->type)); - ZigValue *fields_ptr = fields_value->data.x_struct.fields[slice_ptr_index]; - ZigValue *fields_len_value = fields_value->data.x_struct.fields[slice_len_index]; - size_t fields_len = bigint_as_usize(&fields_len_value->data.x_bigint); - - ZigValue *decls_value = get_const_field(ira, source_node, payload, "decls", 3); - if (decls_value == nullptr) - return ira->codegen->invalid_inst_gen->value->type; - - assert(decls_value->special == ConstValSpecialStatic); - assert(is_slice(decls_value->type)); - ZigValue *decls_len_value = decls_value->data.x_struct.fields[slice_len_index]; - size_t decls_len = bigint_as_usize(&decls_len_value->data.x_bigint); - if (decls_len != 0) { - ir_add_error_node(ira, source_node, buf_create_from_str("Type.Enum.decls must be empty for @Type")); - return ira->codegen->invalid_inst_gen->value->type; - } - - Error err; - bool is_exhaustive; - if ((err = get_const_field_bool(ira, source_node, payload, "is_exhaustive", 4, &is_exhaustive))) - return ira->codegen->invalid_inst_gen->value->type; - - ZigType *entry = new_type_table_entry(ZigTypeIdEnum); - buf_init_from_buf(&entry->name, - get_anon_type_name(ira->codegen, ira->zir, "enum", scope, source_node, &entry->name, nullptr)); - entry->data.enumeration.decl_node = source_node; - entry->data.enumeration.tag_int_type = tag_type; - entry->data.enumeration.decls_scope = create_decls_scope( - ira->codegen, source_node, scope, entry, get_scope_import(scope), &entry->name); - entry->data.enumeration.fields = heap::c_allocator.allocate(fields_len); - entry->data.enumeration.fields_by_name.init(fields_len); - entry->data.enumeration.src_field_count = fields_len; - entry->data.enumeration.layout = layout; - entry->data.enumeration.non_exhaustive = !is_exhaustive; - - assert(fields_ptr->data.x_ptr.special == ConstPtrSpecialBaseArray); - assert(fields_ptr->data.x_ptr.data.base_array.elem_index == 0); - ZigValue *fields_arr = fields_ptr->data.x_ptr.data.base_array.array_val; - assert(fields_arr->special == ConstValSpecialStatic); - assert(fields_arr->data.x_array.special == ConstArraySpecialNone); - for (size_t i = 0; i < fields_len; i++) { - ZigValue *field_value = &fields_arr->data.x_array.data.s_none.elements[i]; - assert(field_value->type == ir_type_info_get_type(ira, "EnumField", nullptr)); - TypeEnumField *field = &entry->data.enumeration.fields[i]; - field->name = buf_alloc(); - if ((err = get_const_field_buf(ira, source_node, field_value, "name", 0, field->name))) - return ira->codegen->invalid_inst_gen->value->type; - field->decl_index = i; - field->decl_node = source_node; - if (entry->data.enumeration.fields_by_name.put_unique(field->name, field) != nullptr) { - ir_add_error_node(ira, source_node, buf_sprintf("duplicate enum field '%s'", buf_ptr(field->name))); - return ira->codegen->invalid_inst_gen->value->type; - } - BigInt *field_int_value = get_const_field_lit_int(ira, source_node, field_value, "value", 1); - if (field_int_value == nullptr) - return ira->codegen->invalid_inst_gen->value->type; - field->value = *field_int_value; - } - return entry; - } - case ZigTypeIdUnion: { - assert(payload->special == ConstValSpecialStatic); - assert(payload->type == ir_type_info_get_type(ira, "Union", nullptr)); - - ZigValue *layout_value = get_const_field(ira, source_node, payload, "layout", 0); - if (layout_value == nullptr) - return ira->codegen->invalid_inst_gen->value->type; - assert(layout_value->special == ConstValSpecialStatic); - assert(layout_value->type == ir_type_info_get_type(ira, "ContainerLayout", nullptr)); - ContainerLayout layout = (ContainerLayout)bigint_as_u32(&layout_value->data.x_enum_tag); - - ZigType *tag_type = get_const_field_meta_type_optional(ira, source_node, payload, "tag_type", 1); - if (tag_type != nullptr && type_is_invalid(tag_type)) { - return ira->codegen->invalid_inst_gen->value->type; - } - if (tag_type != nullptr && tag_type->id != ZigTypeIdEnum) { - ir_add_error_node(ira, source_node, buf_sprintf( - "expected enum type, found '%s'", type_id_name(tag_type->id))); - return ira->codegen->invalid_inst_gen->value->type; - } - - ZigValue *fields_value = get_const_field(ira, source_node, payload, "fields", 2); - if (fields_value == nullptr) - return ira->codegen->invalid_inst_gen->value->type; - - assert(fields_value->special == ConstValSpecialStatic); - assert(is_slice(fields_value->type)); - ZigValue *fields_ptr = fields_value->data.x_struct.fields[slice_ptr_index]; - ZigValue *fields_len_value = fields_value->data.x_struct.fields[slice_len_index]; - size_t fields_len = bigint_as_usize(&fields_len_value->data.x_bigint); - - ZigValue *decls_value = get_const_field(ira, source_node, payload, "decls", 3); - if (decls_value == nullptr) - return ira->codegen->invalid_inst_gen->value->type; - - assert(decls_value->special == ConstValSpecialStatic); - assert(is_slice(decls_value->type)); - ZigValue *decls_len_value = decls_value->data.x_struct.fields[slice_len_index]; - size_t decls_len = bigint_as_usize(&decls_len_value->data.x_bigint); - if (decls_len != 0) { - ir_add_error_node(ira, source_node, buf_create_from_str("Type.Union.decls must be empty for @Type")); - return ira->codegen->invalid_inst_gen->value->type; - } - - ZigType *entry = new_type_table_entry(ZigTypeIdUnion); - buf_init_from_buf(&entry->name, - get_anon_type_name(ira->codegen, ira->zir, "union", scope, source_node, &entry->name, nullptr)); - entry->data.unionation.decl_node = source_node; - entry->data.unionation.fields = heap::c_allocator.allocate(fields_len); - entry->data.unionation.fields_by_name.init(fields_len); - entry->data.unionation.decls_scope = create_decls_scope( - ira->codegen, source_node, scope, entry, get_scope_import(scope), &entry->name); - entry->data.unionation.tag_type = tag_type; - entry->data.unionation.src_field_count = fields_len; - entry->data.unionation.layout = layout; - - assert(fields_ptr->data.x_ptr.special == ConstPtrSpecialBaseArray); - assert(fields_ptr->data.x_ptr.data.base_array.elem_index == 0); - ZigValue *fields_arr = fields_ptr->data.x_ptr.data.base_array.array_val; - assert(fields_arr->special == ConstValSpecialStatic); - assert(fields_arr->data.x_array.special == ConstArraySpecialNone); - for (size_t i = 0; i < fields_len; i++) { - ZigValue *field_value = &fields_arr->data.x_array.data.s_none.elements[i]; - assert(field_value->type == ir_type_info_get_type(ira, "UnionField", nullptr)); - TypeUnionField *field = &entry->data.unionation.fields[i]; - field->name = buf_alloc(); - if ((err = get_const_field_buf(ira, source_node, field_value, "name", 0, field->name))) - return ira->codegen->invalid_inst_gen->value->type; - if (entry->data.unionation.fields_by_name.put_unique(field->name, field) != nullptr) { - ir_add_error_node(ira, source_node, buf_sprintf("duplicate union field '%s'", buf_ptr(field->name))); - return ira->codegen->invalid_inst_gen->value->type; - } - field->decl_node = source_node; - ZigValue *type_value = get_const_field(ira, source_node, field_value, "field_type", 1); - if (type_value == nullptr) - return ira->codegen->invalid_inst_gen->value->type; - field->type_val = type_value; - field->type_entry = type_value->data.x_type; - BigInt *alignment = get_const_field_lit_int(ira, source_node, field_value, "alignment", 2); - if (alignment == nullptr) - return ira->codegen->invalid_inst_gen->value->type; - field->align = bigint_as_u32(alignment); - } - return entry; - } - case ZigTypeIdFn: - case ZigTypeIdBoundFn: { - assert(payload->special == ConstValSpecialStatic); - assert(payload->type == ir_type_info_get_type(ira, "Fn", nullptr)); - - ZigValue *cc_value = get_const_field(ira, source_node, payload, "calling_convention", 0); - if (cc_value == nullptr) - return ira->codegen->invalid_inst_gen->value->type; - assert(cc_value->special == ConstValSpecialStatic); - assert(cc_value->type == get_builtin_type(ira->codegen, "CallingConvention")); - CallingConvention cc = (CallingConvention)bigint_as_u32(&cc_value->data.x_enum_tag); - - BigInt *alignment = get_const_field_lit_int(ira, source_node, payload, "alignment", 1); - if (alignment == nullptr) - return ira->codegen->invalid_inst_gen->value->type; - - Error err; - bool is_generic; - if ((err = get_const_field_bool(ira, source_node, payload, "is_generic", 2, &is_generic))) - return ira->codegen->invalid_inst_gen->value->type; - if (is_generic) { - ir_add_error_node(ira, source_node, buf_sprintf("Type.Fn.is_generic must be false for @Type")); - return ira->codegen->invalid_inst_gen->value->type; - } - - bool is_var_args; - if ((err = get_const_field_bool(ira, source_node, payload, "is_var_args", 3, &is_var_args))) - return ira->codegen->invalid_inst_gen->value->type; - if (is_var_args && cc != CallingConventionC) { - ir_add_error_node(ira, source_node, buf_sprintf("varargs functions must have C calling convention")); - return ira->codegen->invalid_inst_gen->value->type; - } - - ZigType *return_type = get_const_field_meta_type_optional(ira, source_node, payload, "return_type", 4); - if (return_type == nullptr) { - ir_add_error_node(ira, source_node, buf_sprintf("Type.Fn.return_type must be non-null for @Type")); - return ira->codegen->invalid_inst_gen->value->type; - } - - ZigValue *args_value = get_const_field(ira, source_node, payload, "args", 5); - if (args_value == nullptr) - return ira->codegen->invalid_inst_gen->value->type; - assert(args_value->special == ConstValSpecialStatic); - assert(is_slice(args_value->type)); - ZigValue *args_ptr = args_value->data.x_struct.fields[slice_ptr_index]; - ZigValue *args_len_value = args_value->data.x_struct.fields[slice_len_index]; - size_t args_len = bigint_as_usize(&args_len_value->data.x_bigint); - - FnTypeId fn_type_id = {}; - fn_type_id.return_type = return_type; - fn_type_id.param_info = heap::c_allocator.allocate(args_len); - fn_type_id.param_count = args_len; - fn_type_id.next_param_index = args_len; - fn_type_id.is_var_args = is_var_args; - fn_type_id.cc = cc; - fn_type_id.alignment = bigint_as_u32(alignment); - - assert(args_ptr->data.x_ptr.special == ConstPtrSpecialBaseArray); - assert(args_ptr->data.x_ptr.data.base_array.elem_index == 0); - ZigValue *args_arr = args_ptr->data.x_ptr.data.base_array.array_val; - assert(args_arr->special == ConstValSpecialStatic); - assert(args_arr->data.x_array.special == ConstArraySpecialNone); - for (size_t i = 0; i < args_len; i++) { - ZigValue *arg_value = &args_arr->data.x_array.data.s_none.elements[i]; - FnTypeParamInfo *info = &fn_type_id.param_info[i]; - Error err; - bool is_generic; - if ((err = get_const_field_bool(ira, source_node, arg_value, "is_generic", 0, &is_generic))) - return ira->codegen->invalid_inst_gen->value->type; - if (is_generic) { - ir_add_error_node(ira, source_node, buf_sprintf("Type.Fn.Param.is_generic must be false for @Type")); - return ira->codegen->invalid_inst_gen->value->type; - } - if ((err = get_const_field_bool(ira, source_node, arg_value, "is_noalias", 1, &info->is_noalias))) - return ira->codegen->invalid_inst_gen->value->type; - ZigType *type = get_const_field_meta_type_optional( - ira, source_node, arg_value, "arg_type", 2); - if (type == nullptr) { - ir_add_error_node(ira, source_node, buf_sprintf("Type.Fn.Param.arg_type must be non-null for @Type")); - return ira->codegen->invalid_inst_gen->value->type; - } - info->type = type; - } - - ZigType *entry = get_fn_type(ira->codegen, &fn_type_id); - - switch (tagTypeId) { - case ZigTypeIdFn: - return entry; - case ZigTypeIdBoundFn: { - ZigType *bound_fn_entry = new_type_table_entry(ZigTypeIdBoundFn); - bound_fn_entry->name = *buf_sprintf("(bound %s)", buf_ptr(&entry->name)); - bound_fn_entry->data.bound_fn.fn_type = entry; - return bound_fn_entry; - } - default: - zig_unreachable(); - } - } - } - zig_unreachable(); -} - -static Stage1AirInst *ir_analyze_instruction_type(IrAnalyze *ira, Stage1ZirInstType *instruction) { - Stage1AirInst *uncasted_type_info = instruction->type_info->child; - if (type_is_invalid(uncasted_type_info->value->type)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *type_info = ir_implicit_cast(ira, uncasted_type_info, ir_type_info_get_type(ira, nullptr, nullptr)); - if (type_is_invalid(type_info->value->type)) - return ira->codegen->invalid_inst_gen; - - ZigValue *type_info_val = ir_resolve_const(ira, type_info, UndefBad); - if (type_info_val == nullptr) - return ira->codegen->invalid_inst_gen; - ZigTypeId type_id_tag = type_id_at_index(bigint_as_usize(&type_info_val->data.x_union.tag)); - ZigType *type = type_info_to_type(ira, uncasted_type_info->scope, - uncasted_type_info->source_node, type_id_tag, type_info_val->data.x_union.payload); - if (type_is_invalid(type)) - return ira->codegen->invalid_inst_gen; - return ir_const_type(ira, instruction->base.scope, instruction->base.source_node, type); -} - -static Stage1AirInst *ir_analyze_instruction_set_eval_branch_quota(IrAnalyze *ira, - Stage1ZirInstSetEvalBranchQuota *instruction) -{ - uint64_t new_quota; - if (!ir_resolve_unsigned(ira, instruction->new_quota->child, ira->codegen->builtin_types.entry_u32, &new_quota)) - return ira->codegen->invalid_inst_gen; - - if (new_quota > *ira->backward_branch_quota) { - *ira->backward_branch_quota = new_quota; - } - - return ir_const_void(ira, instruction->base.scope, instruction->base.source_node); -} - -static Stage1AirInst *ir_analyze_instruction_type_name(IrAnalyze *ira, Stage1ZirInstTypeName *instruction) { - Stage1AirInst *type_value = instruction->type_value->child; - ZigType *type_entry = ir_resolve_type(ira, type_value); - if (type_is_invalid(type_entry)) - return ira->codegen->invalid_inst_gen; - - if (!type_entry->cached_const_name_val) { - type_entry->cached_const_name_val = create_const_str_lit(ira->codegen, type_bare_name(type_entry)); - } - Stage1AirInst *result = ir_const(ira, instruction->base.scope, instruction->base.source_node, nullptr); - copy_const_val(ira->codegen, result->value, type_entry->cached_const_name_val); - return result; -} - -static Stage1AirInst *ir_analyze_instruction_c_import(IrAnalyze *ira, Stage1ZirInstCImport *instruction) { - Error err; - AstNode *node = instruction->base.source_node; - assert(node->type == NodeTypeFnCallExpr); - AstNode *block_node = node->data.fn_call_expr.params.at(0); - - ScopeCImport *cimport_scope = create_cimport_scope(ira->codegen, node, instruction->base.scope); - - // Execute the C import block like an inline function - ZigType *void_type = ira->codegen->builtin_types.entry_void; - ZigValue *cimport_result; - ZigValue *result_ptr; - create_result_ptr(ira->codegen, void_type, &cimport_result, &result_ptr); - if ((err = ir_eval_const_value(ira->codegen, &cimport_scope->base, block_node, result_ptr, - ira->backward_branch_count, ira->backward_branch_quota, nullptr, - &cimport_scope->buf, block_node, nullptr, nullptr, nullptr, UndefBad))) - { - return ira->codegen->invalid_inst_gen; - } - if (type_is_invalid(cimport_result->type)) - return ira->codegen->invalid_inst_gen; - - ZigPackage *cur_scope_pkg = scope_package(instruction->base.scope); - RootStruct *root_struct = node->owner->data.structure.root_struct; - TokenLoc tok_loc = root_struct->token_locs[node->main_token]; - Buf *namespace_name = buf_sprintf("%s.cimport:%" PRIu32 ":%" PRIu32, - buf_ptr(&cur_scope_pkg->pkg_path), tok_loc.line + 1, tok_loc.column + 1); - - ZigPackage *cimport_pkg = new_anonymous_package(); - cimport_pkg->package_table.put(buf_create_from_str("builtin"), ira->codegen->compile_var_package); - cimport_pkg->package_table.put(buf_create_from_str("std"), ira->codegen->std_package); - buf_init_from_buf(&cimport_pkg->pkg_path, namespace_name); - - const char *out_zig_path_ptr; - size_t out_zig_path_len; - Stage2ErrorMsg *errors_ptr; - size_t errors_len; - if ((err = stage2_cimport(&ira->codegen->stage1, - buf_ptr(&cimport_scope->buf), buf_len(&cimport_scope->buf), - &out_zig_path_ptr, &out_zig_path_len, - &errors_ptr, &errors_len))) - { - if (err != ErrorCCompileErrors) { - ir_add_error_node(ira, node, buf_sprintf("C import failed: %s", err_str(err))); - return ira->codegen->invalid_inst_gen; - } - - ErrorMsg *parent_err_msg = ir_add_error_node(ira, node, buf_sprintf("C import failed")); - if (!ira->codegen->stage1.link_libc) { - add_error_note(ira->codegen, parent_err_msg, node, - buf_sprintf("libc headers not available; compilation does not link against libc")); - } - for (size_t i = 0; i < errors_len; i += 1) { - Stage2ErrorMsg *clang_err = &errors_ptr[i]; - // Clang can emit "too many errors, stopping now", in which case - // `source` and `filename_ptr` are null - if (clang_err->source && clang_err->filename_ptr) { - ErrorMsg *err_msg = err_msg_create_with_offset( - clang_err->filename_ptr ? - buf_create_from_mem(clang_err->filename_ptr, clang_err->filename_len) : - buf_alloc(), - clang_err->offset, clang_err->source, - buf_create_from_mem(clang_err->msg_ptr, clang_err->msg_len)); - err_msg_add_note(parent_err_msg, err_msg); - } - } - - return ira->codegen->invalid_inst_gen; - } - Buf *out_zig_path = buf_create_from_mem(out_zig_path_ptr, out_zig_path_len); - - Buf *import_code = buf_alloc(); - if ((err = file_fetch(ira->codegen, out_zig_path, import_code))) { - ir_add_error_node(ira, node, - buf_sprintf("unable to open '%s': %s", buf_ptr(out_zig_path), err_str(err))); - return ira->codegen->invalid_inst_gen; - } - ZigType *child_import = add_source_file(ira->codegen, cimport_pkg, out_zig_path, - import_code, SourceKindCImport); - return ir_const_type(ira, instruction->base.scope, instruction->base.source_node, child_import); -} - -static Stage1AirInst *ir_analyze_instruction_c_include(IrAnalyze *ira, Stage1ZirInstCInclude *instruction) { - Stage1AirInst *name_value = instruction->name->child; - if (type_is_invalid(name_value->value->type)) - return ira->codegen->invalid_inst_gen; - - Buf *include_name = ir_resolve_str(ira, name_value); - if (!include_name) - return ira->codegen->invalid_inst_gen; - - Buf *c_import_buf = ira->new_irb.exec->c_import_buf; - // We check for this error in pass1 - assert(c_import_buf); - - buf_appendf(c_import_buf, "#include <%s>\n", buf_ptr(include_name)); - - return ir_const_void(ira, instruction->base.scope, instruction->base.source_node); -} - -static Stage1AirInst *ir_analyze_instruction_c_define(IrAnalyze *ira, Stage1ZirInstCDefine *instruction) { - Stage1AirInst *name = instruction->name->child; - if (type_is_invalid(name->value->type)) - return ira->codegen->invalid_inst_gen; - - Buf *define_name = ir_resolve_str(ira, name); - if (!define_name) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *value = instruction->value->child; - if (type_is_invalid(value->value->type)) - return ira->codegen->invalid_inst_gen; - - Buf *define_value = nullptr; - // The second parameter is either a string or void (equivalent to "") - if (value->value->type->id != ZigTypeIdVoid) { - define_value = ir_resolve_str(ira, value); - if (!define_value) - return ira->codegen->invalid_inst_gen; - } - - Buf *c_import_buf = ira->new_irb.exec->c_import_buf; - // We check for this error in pass1 - assert(c_import_buf); - - buf_appendf(c_import_buf, "#define %s %s\n", buf_ptr(define_name), - define_value ? buf_ptr(define_value) : ""); - - return ir_const_void(ira, instruction->base.scope, instruction->base.source_node); -} - -static Stage1AirInst *ir_analyze_instruction_c_undef(IrAnalyze *ira, Stage1ZirInstCUndef *instruction) { - Stage1AirInst *name = instruction->name->child; - if (type_is_invalid(name->value->type)) - return ira->codegen->invalid_inst_gen; - - Buf *undef_name = ir_resolve_str(ira, name); - if (!undef_name) - return ira->codegen->invalid_inst_gen; - - Buf *c_import_buf = ira->new_irb.exec->c_import_buf; - // We check for this error in pass1 - assert(c_import_buf); - - buf_appendf(c_import_buf, "#undef %s\n", buf_ptr(undef_name)); - - return ir_const_void(ira, instruction->base.scope, instruction->base.source_node); -} - -static Stage1AirInst *ir_analyze_instruction_embed_file(IrAnalyze *ira, Stage1ZirInstEmbedFile *instruction) { - Stage1AirInst *name = instruction->name->child; - if (type_is_invalid(name->value->type)) - return ira->codegen->invalid_inst_gen; - - Buf *rel_file_path = ir_resolve_str(ira, name); - if (!rel_file_path) - return ira->codegen->invalid_inst_gen; - - ZigType *import = get_scope_import(instruction->base.scope); - // figure out absolute path to resource - Buf source_dir_path = BUF_INIT; - os_path_dirname(import->data.structure.root_struct->path, &source_dir_path); - - Buf *resolve_paths[] = { - &source_dir_path, - rel_file_path, - }; - Buf *file_path = buf_alloc(); - *file_path = os_path_resolve(resolve_paths, 2); - - // load from file system into const expr - Buf *file_contents = buf_alloc(); - Error err; - if ((err = file_fetch(ira->codegen, file_path, file_contents))) { - if (err == ErrorFileNotFound) { - ir_add_error_node(ira, instruction->name->source_node, - buf_sprintf("unable to find '%s'", buf_ptr(file_path))); - return ira->codegen->invalid_inst_gen; - } else { - ir_add_error_node(ira, instruction->name->source_node, - buf_sprintf("unable to open '%s': %s", buf_ptr(file_path), err_str(err))); - return ira->codegen->invalid_inst_gen; - } - } - - Stage1AirInst *result = ir_const(ira, instruction->base.scope, instruction->base.source_node, nullptr); - init_const_str_lit(ira->codegen, result->value, file_contents, true); - return result; -} - -static Stage1AirInst *ir_analyze_instruction_cmpxchg(IrAnalyze *ira, Stage1ZirInstCmpxchg *instruction) { - ZigType *operand_type = ir_resolve_atomic_operand_type(ira, instruction->type_value->child); - if (type_is_invalid(operand_type)) - return ira->codegen->invalid_inst_gen; - - if (operand_type->id == ZigTypeIdFloat) { - ir_add_error(ira, instruction->type_value->child, - buf_sprintf("expected bool, integer, enum or pointer type, found '%s'", buf_ptr(&operand_type->name))); - return ira->codegen->invalid_inst_gen; - } - - Stage1AirInst *ptr = instruction->ptr->child; - if (type_is_invalid(ptr->value->type)) - return ira->codegen->invalid_inst_gen; - - // TODO let this be volatile - ZigType *ptr_type = get_pointer_to_type(ira->codegen, operand_type, false); - Stage1AirInst *casted_ptr = ir_implicit_cast2(ira, instruction->ptr->scope, - instruction->ptr->source_node, ptr, ptr_type); - if (type_is_invalid(casted_ptr->value->type)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *cmp_value = instruction->cmp_value->child; - if (type_is_invalid(cmp_value->value->type)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *new_value = instruction->new_value->child; - if (type_is_invalid(new_value->value->type)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *success_order_value = instruction->success_order_value->child; - if (type_is_invalid(success_order_value->value->type)) - return ira->codegen->invalid_inst_gen; - - AtomicOrder success_order; - if (!ir_resolve_atomic_order(ira, success_order_value, &success_order)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *failure_order_value = instruction->failure_order_value->child; - if (type_is_invalid(failure_order_value->value->type)) - return ira->codegen->invalid_inst_gen; - - AtomicOrder failure_order; - if (!ir_resolve_atomic_order(ira, failure_order_value, &failure_order)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *casted_cmp_value = ir_implicit_cast2(ira, instruction->cmp_value->scope, - instruction->cmp_value->source_node, cmp_value, operand_type); - if (type_is_invalid(casted_cmp_value->value->type)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *casted_new_value = ir_implicit_cast2(ira, instruction->new_value->scope, - instruction->new_value->source_node, new_value, operand_type); - if (type_is_invalid(casted_new_value->value->type)) - return ira->codegen->invalid_inst_gen; - - if (success_order < AtomicOrderMonotonic) { - ir_add_error(ira, success_order_value, - buf_sprintf("success atomic ordering must be Monotonic or stricter")); - return ira->codegen->invalid_inst_gen; - } - if (failure_order < AtomicOrderMonotonic) { - ir_add_error(ira, failure_order_value, - buf_sprintf("failure atomic ordering must be Monotonic or stricter")); - return ira->codegen->invalid_inst_gen; - } - if (failure_order > success_order) { - ir_add_error(ira, failure_order_value, - buf_sprintf("failure atomic ordering must be no stricter than success")); - return ira->codegen->invalid_inst_gen; - } - if (failure_order == AtomicOrderRelease || failure_order == AtomicOrderAcqRel) { - ir_add_error(ira, failure_order_value, - buf_sprintf("failure atomic ordering must not be Release or AcqRel")); - return ira->codegen->invalid_inst_gen; - } - - ZigType *result_type = get_optional_type(ira->codegen, operand_type); - - // special case zero bit types - switch (type_has_one_possible_value(ira->codegen, operand_type)) { - case OnePossibleValueInvalid: - return ira->codegen->invalid_inst_gen; - case OnePossibleValueYes: { - Stage1AirInst *result = ir_const(ira, instruction->base.scope, instruction->base.source_node, result_type); - set_optional_value_to_null(result->value); - return result; - } - case OnePossibleValueNo: - break; - } - - if (instr_is_comptime(casted_ptr) && casted_ptr->value->data.x_ptr.mut != ConstPtrMutRuntimeVar && - instr_is_comptime(casted_cmp_value) && instr_is_comptime(casted_new_value)) { - ZigValue *ptr_val = ir_resolve_const(ira, casted_ptr, UndefBad); - if (ptr_val == nullptr) - return ira->codegen->invalid_inst_gen; - - ZigValue *stored_val = const_ptr_pointee(ira, ira->codegen, ptr_val, instruction->base.source_node); - if (stored_val == nullptr) - return ira->codegen->invalid_inst_gen; - - ZigValue *expected_val = ir_resolve_const(ira, casted_cmp_value, UndefBad); - if (expected_val == nullptr) - return ira->codegen->invalid_inst_gen; - - ZigValue *new_val = ir_resolve_const(ira, casted_new_value, UndefBad); - if (new_val == nullptr) - return ira->codegen->invalid_inst_gen; - - bool eql = const_values_equal(ira->codegen, stored_val, expected_val); - Stage1AirInst *result = ir_const(ira, instruction->base.scope, instruction->base.source_node, result_type); - if (eql) { - copy_const_val(ira->codegen, stored_val, new_val); - set_optional_value_to_null(result->value); - } else { - set_optional_payload(result->value, stored_val); - } - return result; - } - - Stage1AirInst *result_loc; - if (handle_is_ptr(ira->codegen, result_type)) { - result_loc = ir_resolve_result(ira, &instruction->base, instruction->result_loc, - result_type, nullptr, true, true); - if (type_is_invalid(result_loc->value->type) || result_loc->value->type->id == ZigTypeIdUnreachable) { - return result_loc; - } - } else { - result_loc = nullptr; - } - - return ir_build_cmpxchg_gen(ira, instruction->base.scope, instruction->base.source_node, result_type, - casted_ptr, casted_cmp_value, casted_new_value, - success_order, failure_order, instruction->is_weak, result_loc); -} - -static ErrorMsg *ir_eval_reduce(IrAnalyze *ira, Scope *scope, AstNode *source_node, ReduceOp op, ZigValue *value, ZigValue *out_value) { - assert(value->type->id == ZigTypeIdVector); - ZigType *scalar_type = value->type->data.vector.elem_type; - const size_t len = value->type->data.vector.len; - assert(len > 0); - - out_value->type = scalar_type; - out_value->special = ConstValSpecialStatic; - - if (scalar_type->id == ZigTypeIdBool) { - ZigValue *first_elem_val = &value->data.x_array.data.s_none.elements[0]; - - bool result = first_elem_val->data.x_bool; - for (size_t i = 1; i < len; i++) { - ZigValue *elem_val = &value->data.x_array.data.s_none.elements[i]; - - switch (op) { - case ReduceOp_and: - result = result && elem_val->data.x_bool; - if (!result) break; // Short circuit - break; - case ReduceOp_or: - result = result || elem_val->data.x_bool; - if (result) break; // Short circuit - break; - case ReduceOp_xor: - result = result != elem_val->data.x_bool; - break; - default: - zig_unreachable(); - } - } - - out_value->data.x_bool = result; - return nullptr; - } - - // Evaluate and/or/xor. - if (op == ReduceOp_and || op == ReduceOp_or || op == ReduceOp_xor) { - ZigValue *first_elem_val = &value->data.x_array.data.s_none.elements[0]; - - copy_const_val(ira->codegen, out_value, first_elem_val); - - for (size_t i = 1; i < len; i++) { - ZigValue *elem_val = &value->data.x_array.data.s_none.elements[i]; - - IrBinOp bin_op; - switch (op) { - case ReduceOp_and: bin_op = IrBinOpBinAnd; break; - case ReduceOp_or: bin_op = IrBinOpBinOr; break; - case ReduceOp_xor: bin_op = IrBinOpBinXor; break; - default: zig_unreachable(); - } - - ErrorMsg *msg = ir_eval_math_op_scalar(ira, scope, source_node, scalar_type, - out_value, bin_op, elem_val, out_value); - if (msg != nullptr) - return msg; - } - - return nullptr; - } - - // Evaluate add/sub. - // Perform the reduction sequentially, starting from the neutral value. - if (op == ReduceOp_add || op == ReduceOp_mul) { - if (scalar_type->id == ZigTypeIdInt) { - if (op == ReduceOp_add) { - bigint_init_unsigned(&out_value->data.x_bigint, 0); - } else { - bigint_init_unsigned(&out_value->data.x_bigint, 1); - } - } else { - if (op == ReduceOp_add) { - float_init_f64(out_value, -0.0); - } else { - float_init_f64(out_value, 1.0); - } - } - - for (size_t i = 0; i < len; i++) { - ZigValue *elem_val = &value->data.x_array.data.s_none.elements[i]; - - IrBinOp bin_op; - switch (op) { - case ReduceOp_add: bin_op = IrBinOpAdd; break; - case ReduceOp_mul: bin_op = IrBinOpMult; break; - default: zig_unreachable(); - } - - ErrorMsg *msg = ir_eval_math_op_scalar(ira, scope, source_node, scalar_type, - out_value, bin_op, elem_val, out_value); - if (msg != nullptr) - return msg; - } - - return nullptr; - } - - // Evaluate min/max. - ZigValue *candidate_elem_val = &value->data.x_array.data.s_none.elements[0]; - - ZigValue *dummy_cmp_value = ira->codegen->pass1_arena->create(); - for (size_t i = 1; i < len; i++) { - ZigValue *elem_val = &value->data.x_array.data.s_none.elements[i]; - - IrBinOp bin_op; - switch (op) { - case ReduceOp_min: bin_op = IrBinOpCmpLessThan; break; - case ReduceOp_max: bin_op = IrBinOpCmpGreaterThan; break; - default: zig_unreachable(); - } - - ErrorMsg *msg = ir_eval_bin_op_cmp_scalar(ira, scope, source_node, - elem_val, bin_op, candidate_elem_val, dummy_cmp_value); - if (msg != nullptr) - return msg; - - if (dummy_cmp_value->data.x_bool) - candidate_elem_val = elem_val; - } - - ira->codegen->pass1_arena->destroy(dummy_cmp_value); - copy_const_val(ira->codegen, out_value, candidate_elem_val); - - return nullptr; -} - -static Stage1AirInst *ir_analyze_instruction_reduce(IrAnalyze *ira, Stage1ZirInstReduce *instruction) { - Stage1AirInst *op_inst = instruction->op->child; - if (type_is_invalid(op_inst->value->type)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *value_inst = instruction->value->child; - if (type_is_invalid(value_inst->value->type)) - return ira->codegen->invalid_inst_gen; - - ZigType *value_type = value_inst->value->type; - if (value_type->id != ZigTypeIdVector) { - ir_add_error(ira, value_inst, - buf_sprintf("expected vector type, found '%s'", - buf_ptr(&value_type->name))); - return ira->codegen->invalid_inst_gen; - } - - ReduceOp op; - if (!ir_resolve_reduce_op(ira, op_inst, &op)) - return ira->codegen->invalid_inst_gen; - - ZigType *elem_type = value_type->data.vector.elem_type; - switch (elem_type->id) { - case ZigTypeIdInt: - break; - case ZigTypeIdBool: - if (op > ReduceOp_xor) { - ir_add_error(ira, op_inst, - buf_sprintf("invalid operation for '%s' type", - buf_ptr(&elem_type->name))); - return ira->codegen->invalid_inst_gen; - } break; - case ZigTypeIdFloat: - if (op < ReduceOp_min) { - ir_add_error(ira, op_inst, - buf_sprintf("invalid operation for '%s' type", - buf_ptr(&elem_type->name))); - return ira->codegen->invalid_inst_gen; - } break; - default: - // Vectors cannot have child types other than those listed above - zig_unreachable(); - } - - // special case zero bit types - switch (type_has_one_possible_value(ira->codegen, elem_type)) { - case OnePossibleValueInvalid: - return ira->codegen->invalid_inst_gen; - case OnePossibleValueYes: - return ir_const_move(ira, instruction->base.scope, instruction->base.source_node, - get_the_one_possible_value(ira->codegen, elem_type)); - case OnePossibleValueNo: - break; - } - - if (instr_is_comptime(value_inst)) { - Stage1AirInst *result = ir_const(ira, instruction->base.scope, instruction->base.source_node, elem_type); - if (ir_eval_reduce(ira, instruction->base.scope, instruction->base.source_node, op, value_inst->value, result->value)) - return ira->codegen->invalid_inst_gen; - return result; - } - - return ir_build_reduce_gen(ira, instruction->base.scope, instruction->base.source_node, op, value_inst, elem_type); -} - -static Stage1AirInst *ir_analyze_instruction_fence(IrAnalyze *ira, Stage1ZirInstFence *instruction) { - Stage1AirInst *order_inst = instruction->order->child; - if (type_is_invalid(order_inst->value->type)) - return ira->codegen->invalid_inst_gen; - - AtomicOrder order; - if (!ir_resolve_atomic_order(ira, order_inst, &order)) - return ira->codegen->invalid_inst_gen; - - if (order < AtomicOrderAcquire) { - ir_add_error(ira, order_inst, - buf_sprintf("atomic ordering must be Acquire or stricter")); - return ira->codegen->invalid_inst_gen; - } - - return ir_build_fence_gen(ira, instruction->base.scope, instruction->base.source_node, order); -} - -static Stage1AirInst *ir_analyze_instruction_truncate(IrAnalyze *ira, Stage1ZirInstTruncate *instruction) { - Stage1AirInst *dest_type_value = instruction->dest_type->child; - ZigType *dest_type = ir_resolve_type(ira, dest_type_value); - if (type_is_invalid(dest_type)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *operand = instruction->target->child; - if (type_is_invalid(operand->value->type)) - return ira->codegen->invalid_inst_gen; - - return ir_analyze_truncate(ira, instruction->base.scope, instruction->base.source_node, - dest_type, instruction->dest_type->source_node, - operand, instruction->target->source_node); -} - -static Stage1AirInst *ir_analyze_int_cast(IrAnalyze *ira, Scope *scope, AstNode *source_node, - ZigType *dest_type, AstNode *dest_type_src_node, - Stage1AirInst *target, AstNode *target_src_node) -{ - ZigType *scalar_dest_type = (dest_type->id == ZigTypeIdVector) ? - dest_type->data.vector.elem_type : dest_type; - - if (scalar_dest_type->id != ZigTypeIdInt && scalar_dest_type->id != ZigTypeIdComptimeInt) { - ir_add_error_node(ira, dest_type_src_node, - buf_sprintf("expected integer type, found '%s'", buf_ptr(&scalar_dest_type->name))); - return ira->codegen->invalid_inst_gen; - } - - ZigType *scalar_target_type = (target->value->type->id == ZigTypeIdVector) ? - target->value->type->data.vector.elem_type : target->value->type; - - if (scalar_target_type->id != ZigTypeIdInt && scalar_target_type->id != ZigTypeIdComptimeInt) { - ir_add_error_node(ira, target_src_node, buf_sprintf("expected integer type, found '%s'", - buf_ptr(&scalar_target_type->name))); - return ira->codegen->invalid_inst_gen; - } - - if (scalar_dest_type->id == ZigTypeIdComptimeInt) { - ZigValue *val = ir_resolve_const(ira, target, UndefBad); - if (val == nullptr) - return ira->codegen->invalid_inst_gen; - - return ir_implicit_cast2(ira, scope, target_src_node, target, dest_type); - } - - return ir_analyze_widen_or_shorten(ira, scope, source_node, target, dest_type); -} - -static Stage1AirInst *ir_analyze_instruction_int_cast(IrAnalyze *ira, Stage1ZirInstIntCast *instruction) { - ZigType *dest_type = ir_resolve_type(ira, instruction->dest_type->child); - if (type_is_invalid(dest_type)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *target = instruction->target->child; - if (type_is_invalid(target->value->type)) - return ira->codegen->invalid_inst_gen; - - return ir_analyze_int_cast(ira, instruction->base.scope, instruction->base.source_node, - dest_type, instruction->dest_type->source_node, - target, instruction->target->source_node); -} - -static Stage1AirInst *ir_analyze_instruction_float_cast(IrAnalyze *ira, Stage1ZirInstFloatCast *instruction) { - ZigType *dest_type = ir_resolve_type(ira, instruction->dest_type->child); - if (type_is_invalid(dest_type)) - return ira->codegen->invalid_inst_gen; - - if (dest_type->id != ZigTypeIdFloat && dest_type->id != ZigTypeIdComptimeFloat) { - ir_add_error_node(ira, instruction->dest_type->source_node, - buf_sprintf("expected float type, found '%s'", buf_ptr(&dest_type->name))); - return ira->codegen->invalid_inst_gen; - } - - Stage1AirInst *target = instruction->target->child; - if (type_is_invalid(target->value->type)) - return ira->codegen->invalid_inst_gen; - - if (target->value->type->id == ZigTypeIdComptimeInt || - target->value->type->id == ZigTypeIdComptimeFloat) - { - if (ir_num_lit_fits_in_other_type(ira, target, dest_type, true)) { - CastOp op; - if (target->value->type->id == ZigTypeIdComptimeInt) { - op = CastOpIntToFloat; - } else { - op = CastOpNumLitToConcrete; - } - return ir_resolve_cast(ira, instruction->base.scope, instruction->base.source_node, target, dest_type, op); - } else { - return ira->codegen->invalid_inst_gen; - } - } - - if (target->value->type->id != ZigTypeIdFloat) { - ir_add_error_node(ira, instruction->target->source_node, buf_sprintf("expected float type, found '%s'", - buf_ptr(&target->value->type->name))); - return ira->codegen->invalid_inst_gen; - } - - if (instr_is_comptime(target) || dest_type->id == ZigTypeIdComptimeFloat) { - ZigValue *val = ir_resolve_const(ira, target, UndefBad); - if (val == nullptr) - return ira->codegen->invalid_inst_gen; - - // XXX: This will trigger an assertion failure if dest_type is comptime_float - return ir_analyze_widen_or_shorten(ira, instruction->target->scope, - instruction->target->source_node, target, dest_type); - } - - return ir_analyze_widen_or_shorten(ira, instruction->base.scope, instruction->base.source_node, target, dest_type); -} - -static Stage1AirInst *ir_analyze_instruction_err_set_cast(IrAnalyze *ira, Stage1ZirInstErrSetCast *instruction) { - ZigType *dest_type = ir_resolve_type(ira, instruction->dest_type->child); - if (type_is_invalid(dest_type)) - return ira->codegen->invalid_inst_gen; - - if (dest_type->id != ZigTypeIdErrorSet) { - ir_add_error_node(ira, instruction->dest_type->source_node, - buf_sprintf("expected error set type, found '%s'", buf_ptr(&dest_type->name))); - return ira->codegen->invalid_inst_gen; - } - - Stage1AirInst *target = instruction->target->child; - if (type_is_invalid(target->value->type)) - return ira->codegen->invalid_inst_gen; - - if (target->value->type->id != ZigTypeIdErrorSet) { - ir_add_error_node(ira, instruction->target->source_node, - buf_sprintf("expected error set type, found '%s'", buf_ptr(&target->value->type->name))); - return ira->codegen->invalid_inst_gen; - } - - return ir_analyze_err_set_cast(ira, instruction->base.scope, instruction->base.source_node, target, dest_type); -} - -static Error resolve_ptr_align(IrAnalyze *ira, ZigType *ty, uint32_t *result_align) { - Error err; - - ZigType *ptr_type; - if (is_slice(ty)) { - TypeStructField *ptr_field = ty->data.structure.fields[slice_ptr_index]; - ptr_type = resolve_struct_field_type(ira->codegen, ptr_field); - } else { - ptr_type = get_src_ptr_type(ty); - } - assert(ptr_type != nullptr); - if (ptr_type->id == ZigTypeIdPointer) { - if ((err = type_resolve(ira->codegen, ptr_type->data.pointer.child_type, ResolveStatusAlignmentKnown))) - return err; - } else if (is_slice(ptr_type)) { - TypeStructField *ptr_field = ptr_type->data.structure.fields[slice_ptr_index]; - ZigType *slice_ptr_type = resolve_struct_field_type(ira->codegen, ptr_field); - if ((err = type_resolve(ira->codegen, slice_ptr_type->data.pointer.child_type, ResolveStatusAlignmentKnown))) - return err; - } - - *result_align = get_ptr_align(ira->codegen, ty); - return ErrorNone; -} - -static Stage1AirInst *ir_analyze_instruction_int_to_float(IrAnalyze *ira, Stage1ZirInstIntToFloat *instruction) { - ZigType *dest_type = ir_resolve_type(ira, instruction->dest_type->child); - if (type_is_invalid(dest_type)) - return ira->codegen->invalid_inst_gen; - - if (dest_type->id != ZigTypeIdFloat && dest_type->id != ZigTypeIdComptimeFloat) { - ir_add_error_node(ira, instruction->dest_type->source_node, - buf_sprintf("expected float type, found '%s'", buf_ptr(&dest_type->name))); - return ira->codegen->invalid_inst_gen; - } - - Stage1AirInst *target = instruction->target->child; - if (type_is_invalid(target->value->type)) - return ira->codegen->invalid_inst_gen; - - if (target->value->type->id != ZigTypeIdInt && target->value->type->id != ZigTypeIdComptimeInt) { - ir_add_error_node(ira, instruction->target->source_node, - buf_sprintf("expected int type, found '%s'", buf_ptr(&target->value->type->name))); - return ira->codegen->invalid_inst_gen; - } - - return ir_resolve_cast(ira, instruction->base.scope, instruction->base.source_node, target, dest_type, CastOpIntToFloat); -} - -static Stage1AirInst *ir_analyze_instruction_float_to_int(IrAnalyze *ira, Stage1ZirInstFloatToInt *instruction) { - ZigType *dest_type = ir_resolve_type(ira, instruction->dest_type->child); - if (type_is_invalid(dest_type)) - return ira->codegen->invalid_inst_gen; - - if (dest_type->id != ZigTypeIdInt && dest_type->id != ZigTypeIdComptimeInt) { - ir_add_error_node(ira, instruction->dest_type->source_node, - buf_sprintf("expected integer type, found '%s'", buf_ptr(&dest_type->name))); - return ira->codegen->invalid_inst_gen; - } - - Stage1AirInst *target = instruction->target->child; - if (type_is_invalid(target->value->type)) - return ira->codegen->invalid_inst_gen; - - if (target->value->type->id == ZigTypeIdComptimeInt) { - return ir_implicit_cast(ira, target, dest_type); - } - - if (target->value->type->id != ZigTypeIdFloat && target->value->type->id != ZigTypeIdComptimeFloat) { - ir_add_error_node(ira, target->source_node, buf_sprintf("expected float type, found '%s'", - buf_ptr(&target->value->type->name))); - return ira->codegen->invalid_inst_gen; - } - - return ir_resolve_cast(ira, instruction->base.scope, instruction->base.source_node, target, dest_type, CastOpFloatToInt); -} - -static Stage1AirInst *ir_analyze_instruction_err_to_int(IrAnalyze *ira, Stage1ZirInstErrToInt *instruction) { - Stage1AirInst *target = instruction->target->child; - if (type_is_invalid(target->value->type)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *casted_target; - if (target->value->type->id == ZigTypeIdErrorSet) { - casted_target = target; - } else { - casted_target = ir_implicit_cast(ira, target, ira->codegen->builtin_types.entry_global_error_set); - if (type_is_invalid(casted_target->value->type)) - return ira->codegen->invalid_inst_gen; - } - - return ir_analyze_err_to_int(ira, instruction->base.scope, instruction->base.source_node, casted_target, ira->codegen->err_tag_type); -} - -static Stage1AirInst *ir_analyze_instruction_int_to_err(IrAnalyze *ira, Stage1ZirInstIntToErr *instruction) { - Stage1AirInst *target = instruction->target->child; - if (type_is_invalid(target->value->type)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *casted_target = ir_implicit_cast(ira, target, ira->codegen->err_tag_type); - if (type_is_invalid(casted_target->value->type)) - return ira->codegen->invalid_inst_gen; - - return ir_analyze_int_to_err(ira, instruction->base.scope, instruction->base.source_node, casted_target, ira->codegen->builtin_types.entry_global_error_set); -} - -static Stage1AirInst *ir_analyze_instruction_bool_to_int(IrAnalyze *ira, Stage1ZirInstBoolToInt *instruction) { - Stage1AirInst *target = instruction->target->child; - if (type_is_invalid(target->value->type)) - return ira->codegen->invalid_inst_gen; - - if (target->value->type->id != ZigTypeIdBool) { - ir_add_error_node(ira, instruction->target->source_node, - buf_sprintf("expected bool, found '%s'", buf_ptr(&target->value->type->name))); - return ira->codegen->invalid_inst_gen; - } - - if (instr_is_comptime(target)) { - bool is_true; - if (!ir_resolve_bool(ira, target, &is_true)) - return ira->codegen->invalid_inst_gen; - - return ir_const_unsigned(ira, instruction->base.scope, instruction->base.source_node, is_true ? 1 : 0); - } - - ZigType *u1_type = get_int_type(ira->codegen, false, 1); - return ir_resolve_cast(ira, instruction->base.scope, instruction->base.source_node, target, u1_type, CastOpBoolToInt); -} - -static Stage1AirInst *ir_analyze_instruction_vector_type(IrAnalyze *ira, Stage1ZirInstVectorType *instruction) { - uint64_t len; - if (!ir_resolve_unsigned(ira, instruction->len->child, ira->codegen->builtin_types.entry_u32, &len)) - return ira->codegen->invalid_inst_gen; - - ZigType *elem_type = ir_resolve_vector_elem_type(ira, instruction->elem_type->child); - if (type_is_invalid(elem_type)) - return ira->codegen->invalid_inst_gen; - - ZigType *vector_type = get_vector_type(ira->codegen, len, elem_type); - - return ir_const_type(ira, instruction->base.scope, instruction->base.source_node, vector_type); -} - -static Stage1AirInst *ir_analyze_shuffle_vector(IrAnalyze *ira, Scope *scope, AstNode *source_node, - ZigType *scalar_type, Stage1AirInst *a, Stage1AirInst *b, Stage1AirInst *mask) -{ - Error err; - src_assert(source_node && scalar_type && a && b && mask, source_node); - - if ((err = ir_validate_vector_elem_type(ira, source_node, scalar_type))) - return ira->codegen->invalid_inst_gen; - - uint32_t len_mask; - if (mask->value->type->id == ZigTypeIdVector) { - len_mask = mask->value->type->data.vector.len; - } else if (mask->value->type->id == ZigTypeIdArray) { - len_mask = mask->value->type->data.array.len; - } else { - ir_add_error(ira, mask, - buf_sprintf("expected vector or array, found '%s'", - buf_ptr(&mask->value->type->name))); - return ira->codegen->invalid_inst_gen; - } - mask = ir_implicit_cast(ira, mask, get_vector_type(ira->codegen, len_mask, - ira->codegen->builtin_types.entry_i32)); - if (type_is_invalid(mask->value->type)) - return ira->codegen->invalid_inst_gen; - - uint32_t len_a; - if (a->value->type->id == ZigTypeIdVector) { - len_a = a->value->type->data.vector.len; - } else if (a->value->type->id == ZigTypeIdArray) { - len_a = a->value->type->data.array.len; - } else if (a->value->type->id == ZigTypeIdUndefined) { - len_a = UINT32_MAX; - } else { - ir_add_error(ira, a, - buf_sprintf("expected vector or array with element type '%s', found '%s'", - buf_ptr(&scalar_type->name), - buf_ptr(&a->value->type->name))); - return ira->codegen->invalid_inst_gen; - } - - uint32_t len_b; - if (b->value->type->id == ZigTypeIdVector) { - len_b = b->value->type->data.vector.len; - } else if (b->value->type->id == ZigTypeIdArray) { - len_b = b->value->type->data.array.len; - } else if (b->value->type->id == ZigTypeIdUndefined) { - len_b = UINT32_MAX; - } else { - ir_add_error(ira, b, - buf_sprintf("expected vector or array with element type '%s', found '%s'", - buf_ptr(&scalar_type->name), - buf_ptr(&b->value->type->name))); - return ira->codegen->invalid_inst_gen; - } - - if (len_a == UINT32_MAX && len_b == UINT32_MAX) { - return ir_const_undef(ira, a->scope, a->source_node, get_vector_type(ira->codegen, len_mask, scalar_type)); - } - - if (len_a == UINT32_MAX) { - len_a = len_b; - a = ir_const_undef(ira, a->scope, a->source_node, get_vector_type(ira->codegen, len_a, scalar_type)); - } else { - a = ir_implicit_cast(ira, a, get_vector_type(ira->codegen, len_a, scalar_type)); - if (type_is_invalid(a->value->type)) - return ira->codegen->invalid_inst_gen; - } - - if (len_b == UINT32_MAX) { - len_b = len_a; - b = ir_const_undef(ira, b->scope, b->source_node, get_vector_type(ira->codegen, len_b, scalar_type)); - } else { - b = ir_implicit_cast(ira, b, get_vector_type(ira->codegen, len_b, scalar_type)); - if (type_is_invalid(b->value->type)) - return ira->codegen->invalid_inst_gen; - } - - ZigValue *mask_val = ir_resolve_const(ira, mask, UndefOk); - if (mask_val == nullptr) - return ira->codegen->invalid_inst_gen; - - expand_undef_array(ira->codegen, mask_val); - - for (uint32_t i = 0; i < len_mask; i += 1) { - ZigValue *mask_elem_val = &mask_val->data.x_array.data.s_none.elements[i]; - if (mask_elem_val->special == ConstValSpecialUndef) - continue; - int32_t v_i32 = bigint_as_signed(&mask_elem_val->data.x_bigint); - uint32_t v; - Stage1AirInst *chosen_operand; - if (v_i32 >= 0) { - v = (uint32_t)v_i32; - chosen_operand = a; - } else { - v = (uint32_t)~v_i32; - chosen_operand = b; - } - if (v >= chosen_operand->value->type->data.vector.len) { - ErrorMsg *msg = ir_add_error(ira, mask, - buf_sprintf("mask index '%u' has out-of-bounds selection", i)); - add_error_note(ira->codegen, msg, chosen_operand->source_node, - buf_sprintf("selected index '%u' out of bounds of %s", v, - buf_ptr(&chosen_operand->value->type->name))); - if (chosen_operand == a && v < len_a + len_b) { - add_error_note(ira->codegen, msg, b->source_node, - buf_create_from_str("selections from the second vector are specified with negative numbers")); - } - return ira->codegen->invalid_inst_gen; - } - } - - ZigType *result_type = get_vector_type(ira->codegen, len_mask, scalar_type); - if (instr_is_comptime(a) && instr_is_comptime(b)) { - ZigValue *a_val = ir_resolve_const(ira, a, UndefOk); - if (a_val == nullptr) - return ira->codegen->invalid_inst_gen; - - ZigValue *b_val = ir_resolve_const(ira, b, UndefOk); - if (b_val == nullptr) - return ira->codegen->invalid_inst_gen; - - expand_undef_array(ira->codegen, a_val); - expand_undef_array(ira->codegen, b_val); - - Stage1AirInst *result = ir_const(ira, scope, source_node, result_type); - result->value->data.x_array.data.s_none.elements = ira->codegen->pass1_arena->allocate(len_mask); - for (uint32_t i = 0; i < mask_val->type->data.vector.len; i += 1) { - ZigValue *mask_elem_val = &mask_val->data.x_array.data.s_none.elements[i]; - ZigValue *result_elem_val = &result->value->data.x_array.data.s_none.elements[i]; - if (mask_elem_val->special == ConstValSpecialUndef) { - result_elem_val->special = ConstValSpecialUndef; - continue; - } - int32_t v = bigint_as_signed(&mask_elem_val->data.x_bigint); - // We've already checked for and emitted compile errors for index out of bounds here. - ZigValue *src_elem_val = (v >= 0) ? - &a->value->data.x_array.data.s_none.elements[v] : - &b->value->data.x_array.data.s_none.elements[~v]; - copy_const_val(ira->codegen, result_elem_val, src_elem_val); - - src_assert(result_elem_val->special == ConstValSpecialStatic, source_node); - } - result->value->special = ConstValSpecialStatic; - return result; - } - - // All static analysis passed, and not comptime. - // For runtime codegen, vectors a and b must be the same length. Here we - // recursively @shuffle the smaller vector to append undefined elements - // to it up to the length of the longer vector. This recursion terminates - // in 1 call because these calls to ir_analyze_shuffle_vector guarantee - // len_a == len_b. - if (len_a != len_b) { - uint32_t len_min = min(len_a, len_b); - uint32_t len_max = max(len_a, len_b); - - Stage1AirInst *expand_mask = ir_const(ira, mask->scope, mask->source_node, - get_vector_type(ira->codegen, len_max, ira->codegen->builtin_types.entry_i32)); - expand_mask->value->data.x_array.data.s_none.elements = ira->codegen->pass1_arena->allocate(len_max); - uint32_t i = 0; - for (; i < len_min; i += 1) - bigint_init_unsigned(&expand_mask->value->data.x_array.data.s_none.elements[i].data.x_bigint, i); - for (; i < len_max; i += 1) - bigint_init_signed(&expand_mask->value->data.x_array.data.s_none.elements[i].data.x_bigint, -1); - - Stage1AirInst *undef = ir_const_undef(ira, scope, source_node, - get_vector_type(ira->codegen, len_min, scalar_type)); - - if (len_b < len_a) { - b = ir_analyze_shuffle_vector(ira, scope, source_node, scalar_type, b, undef, expand_mask); - } else { - a = ir_analyze_shuffle_vector(ira, scope, source_node, scalar_type, a, undef, expand_mask); - } - } - - return ir_build_shuffle_vector_gen(ira, scope, source_node, - result_type, a, b, mask); -} - -static Stage1AirInst *ir_analyze_instruction_shuffle_vector(IrAnalyze *ira, Stage1ZirInstShuffleVector *instruction) { - ZigType *scalar_type = ir_resolve_vector_elem_type(ira, instruction->scalar_type->child); - if (type_is_invalid(scalar_type)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *a = instruction->a->child; - if (type_is_invalid(a->value->type)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *b = instruction->b->child; - if (type_is_invalid(b->value->type)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *mask = instruction->mask->child; - if (type_is_invalid(mask->value->type)) - return ira->codegen->invalid_inst_gen; - - return ir_analyze_shuffle_vector(ira, instruction->base.scope, instruction->base.source_node, scalar_type, a, b, mask); -} - -static Stage1AirInst *ir_analyze_instruction_select(IrAnalyze *ira, Stage1ZirInstSelect *instruction) { - Error err; - - ZigType *scalar_type = ir_resolve_vector_elem_type(ira, instruction->scalar_type->child); - if (type_is_invalid(scalar_type)) - return ira->codegen->invalid_inst_gen; - - if ((err = ir_validate_vector_elem_type(ira, instruction->base.source_node, scalar_type))) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *pred = instruction->pred->child; - if (type_is_invalid(pred->value->type)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *a = instruction->a->child; - if (type_is_invalid(a->value->type)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *b = instruction->b->child; - if (type_is_invalid(b->value->type)) - return ira->codegen->invalid_inst_gen; - - if (pred->value->type->id != ZigTypeIdVector) { - ir_add_error(ira, pred, - buf_sprintf("expected vector type, found '%s'", - buf_ptr(&pred->value->type->name))); - return ira->codegen->invalid_inst_gen; - } - - uint32_t pred_len = pred->value->type->data.vector.len; - pred = ir_implicit_cast(ira, pred, get_vector_type(ira->codegen, pred_len, - ira->codegen->builtin_types.entry_bool)); - if (type_is_invalid(pred->value->type)) - return ira->codegen->invalid_inst_gen; - - if (a->value->type->id != ZigTypeIdVector) { - ir_add_error(ira, a, - buf_sprintf("expected vector type, found '%s'", - buf_ptr(&a->value->type->name))); - return ira->codegen->invalid_inst_gen; - } - - if (b->value->type->id != ZigTypeIdVector) { - ir_add_error(ira, b, - buf_sprintf("expected vector type, found '%s'", - buf_ptr(&b->value->type->name))); - return ira->codegen->invalid_inst_gen; - } - - ZigType *result_type = get_vector_type(ira->codegen, pred_len, scalar_type); - - a = ir_implicit_cast(ira, a, result_type); - if (type_is_invalid(a->value->type)) - return ira->codegen->invalid_inst_gen; - - b = ir_implicit_cast(ira, b, result_type); - if (type_is_invalid(a->value->type)) - return ira->codegen->invalid_inst_gen; - - if (instr_is_comptime(pred) && instr_is_comptime(a) && instr_is_comptime(b)) { - ZigValue *pred_val = ir_resolve_const(ira, pred, UndefBad); - if (pred_val == nullptr) - return ira->codegen->invalid_inst_gen; - - ZigValue *a_val = ir_resolve_const(ira, a, UndefBad); - if (a_val == nullptr) - return ira->codegen->invalid_inst_gen; - - ZigValue *b_val = ir_resolve_const(ira, b, UndefBad); - if (b_val == nullptr) - return ira->codegen->invalid_inst_gen; - - expand_undef_array(ira->codegen, a_val); - expand_undef_array(ira->codegen, b_val); - - Stage1AirInst *result = ir_const(ira, instruction->base.scope, instruction->base.source_node, result_type); - result->value->data.x_array.data.s_none.elements = ira->codegen->pass1_arena->allocate(pred_len); - - for (uint64_t i = 0; i < pred_len; i += 1) { - ZigValue *dst_elem_val = &result->value->data.x_array.data.s_none.elements[i]; - ZigValue *pred_elem_val = &pred_val->data.x_array.data.s_none.elements[i]; - ZigValue *a_elem_val = &a_val->data.x_array.data.s_none.elements[i]; - ZigValue *b_elem_val = &b_val->data.x_array.data.s_none.elements[i]; - ZigValue *result_elem_val = pred_elem_val->data.x_bool ? a_elem_val : b_elem_val; - copy_const_val(ira->codegen, dst_elem_val, result_elem_val); - } - - result->value->special = ConstValSpecialStatic; - return result; - } - - return ir_build_select_gen(ira, instruction->base.scope, instruction->base.source_node, result_type, pred, a, b); -} - -static Stage1AirInst *ir_analyze_instruction_splat(IrAnalyze *ira, Stage1ZirInstSplat *instruction) { - Error err; - - Stage1AirInst *len = instruction->len->child; - if (type_is_invalid(len->value->type)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *scalar = instruction->scalar->child; - if (type_is_invalid(scalar->value->type)) - return ira->codegen->invalid_inst_gen; - - uint64_t len_u64; - if (!ir_resolve_unsigned(ira, len, ira->codegen->builtin_types.entry_u32, &len_u64)) - return ira->codegen->invalid_inst_gen; - uint32_t len_int = len_u64; - - if ((err = ir_validate_vector_elem_type(ira, scalar->source_node, scalar->value->type))) - return ira->codegen->invalid_inst_gen; - - ZigType *return_type = get_vector_type(ira->codegen, len_int, scalar->value->type); - - if (instr_is_comptime(scalar)) { - ZigValue *scalar_val = ir_resolve_const(ira, scalar, UndefOk); - if (scalar_val == nullptr) - return ira->codegen->invalid_inst_gen; - if (scalar_val->special == ConstValSpecialUndef) - return ir_const_undef(ira, instruction->base.scope, instruction->base.source_node, return_type); - - Stage1AirInst *result = ir_const(ira, instruction->base.scope, instruction->base.source_node, return_type); - result->value->data.x_array.data.s_none.elements = ira->codegen->pass1_arena->allocate(len_int); - for (uint32_t i = 0; i < len_int; i += 1) { - copy_const_val(ira->codegen, &result->value->data.x_array.data.s_none.elements[i], scalar_val); - } - return result; - } - - return ir_build_splat_gen(ira, instruction->base.scope, instruction->base.source_node, return_type, scalar); -} - -static Stage1AirInst *ir_analyze_instruction_bool_not(IrAnalyze *ira, Stage1ZirInstBoolNot *instruction) { - Stage1AirInst *value = instruction->value->child; - if (type_is_invalid(value->value->type)) - return ira->codegen->invalid_inst_gen; - - ZigType *bool_type = ira->codegen->builtin_types.entry_bool; - - Stage1AirInst *casted_value = ir_implicit_cast(ira, value, bool_type); - if (type_is_invalid(casted_value->value->type)) - return ira->codegen->invalid_inst_gen; - - if (instr_is_comptime(casted_value)) { - ZigValue *value = ir_resolve_const(ira, casted_value, UndefBad); - if (value == nullptr) - return ira->codegen->invalid_inst_gen; - - return ir_const_bool(ira, instruction->base.scope, instruction->base.source_node, !value->data.x_bool); - } - - return ir_build_bool_not_gen(ira, instruction->base.scope, instruction->base.source_node, casted_value); -} - -static Stage1AirInst *ir_analyze_instruction_memset(IrAnalyze *ira, Stage1ZirInstMemset *instruction) { - Error err; - - Stage1AirInst *dest_ptr = instruction->dest_ptr->child; - if (type_is_invalid(dest_ptr->value->type)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *byte_value = instruction->byte->child; - if (type_is_invalid(byte_value->value->type)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *count_value = instruction->count->child; - if (type_is_invalid(count_value->value->type)) - return ira->codegen->invalid_inst_gen; - - ZigType *dest_uncasted_type = dest_ptr->value->type; - bool dest_is_volatile = (dest_uncasted_type->id == ZigTypeIdPointer) && - dest_uncasted_type->data.pointer.is_volatile; - - ZigType *usize = ira->codegen->builtin_types.entry_usize; - ZigType *u8 = ira->codegen->builtin_types.entry_u8; - uint32_t dest_align; - if (dest_uncasted_type->id == ZigTypeIdPointer) { - if ((err = resolve_ptr_align(ira, dest_uncasted_type, &dest_align))) - return ira->codegen->invalid_inst_gen; - } else { - dest_align = get_abi_alignment(ira->codegen, u8); - } - ZigType *u8_ptr = get_pointer_to_type_extra(ira->codegen, u8, false, dest_is_volatile, - PtrLenUnknown, dest_align, 0, 0, false); - - Stage1AirInst *casted_dest_ptr = ir_implicit_cast(ira, dest_ptr, u8_ptr); - if (type_is_invalid(casted_dest_ptr->value->type)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *casted_byte = ir_implicit_cast(ira, byte_value, u8); - if (type_is_invalid(casted_byte->value->type)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *casted_count = ir_implicit_cast(ira, count_value, usize); - if (type_is_invalid(casted_count->value->type)) - return ira->codegen->invalid_inst_gen; - - // TODO test this at comptime with u8 and non-u8 types - if (instr_is_comptime(casted_dest_ptr) && - instr_is_comptime(casted_byte) && - instr_is_comptime(casted_count)) - { - ZigValue *dest_ptr_val = ir_resolve_const(ira, casted_dest_ptr, UndefBad); - if (dest_ptr_val == nullptr) - return ira->codegen->invalid_inst_gen; - - ZigValue *byte_val = ir_resolve_const(ira, casted_byte, UndefOk); - if (byte_val == nullptr) - return ira->codegen->invalid_inst_gen; - - ZigValue *count_val = ir_resolve_const(ira, casted_count, UndefBad); - if (count_val == nullptr) - return ira->codegen->invalid_inst_gen; - - if (casted_dest_ptr->value->data.x_ptr.special != ConstPtrSpecialHardCodedAddr && - casted_dest_ptr->value->data.x_ptr.mut != ConstPtrMutRuntimeVar) - { - ZigValue *dest_elements; - size_t start; - size_t bound_end; - switch (dest_ptr_val->data.x_ptr.special) { - case ConstPtrSpecialInvalid: - case ConstPtrSpecialDiscard: - zig_unreachable(); - case ConstPtrSpecialRef: - dest_elements = dest_ptr_val->data.x_ptr.data.ref.pointee; - start = 0; - bound_end = 1; - break; - case ConstPtrSpecialSubArray: - case ConstPtrSpecialBaseArray: - { - ZigValue *array_val = dest_ptr_val->data.x_ptr.data.base_array.array_val; - expand_undef_array(ira->codegen, array_val); - dest_elements = array_val->data.x_array.data.s_none.elements; - start = dest_ptr_val->data.x_ptr.data.base_array.elem_index; - bound_end = array_val->type->data.array.len; - break; - } - case ConstPtrSpecialBaseStruct: - zig_panic("TODO memset on const inner struct"); - case ConstPtrSpecialBaseErrorUnionCode: - zig_panic("TODO memset on const inner error union code"); - case ConstPtrSpecialBaseErrorUnionPayload: - zig_panic("TODO memset on const inner error union payload"); - case ConstPtrSpecialBaseOptionalPayload: - zig_panic("TODO memset on const inner optional payload"); - case ConstPtrSpecialHardCodedAddr: - zig_unreachable(); - case ConstPtrSpecialFunction: - zig_panic("TODO memset on ptr cast from function"); - case ConstPtrSpecialNull: - zig_panic("TODO memset on null ptr"); - } - - size_t count = bigint_as_usize(&count_val->data.x_bigint); - size_t end = start + count; - if (end > bound_end) { - ir_add_error(ira, count_value, buf_sprintf("out of bounds pointer access")); - return ira->codegen->invalid_inst_gen; - } - - for (size_t i = start; i < end; i += 1) { - copy_const_val(ira->codegen, &dest_elements[i], byte_val); - } - - return ir_const_void(ira, instruction->base.scope, instruction->base.source_node); - } - } - - return ir_build_memset_gen(ira, instruction->base.scope, instruction->base.source_node, casted_dest_ptr, casted_byte, casted_count); -} - -static Stage1AirInst *ir_analyze_instruction_memcpy(IrAnalyze *ira, Stage1ZirInstMemcpy *instruction) { - Error err; - - Stage1AirInst *dest_ptr = instruction->dest_ptr->child; - if (type_is_invalid(dest_ptr->value->type)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *src_ptr = instruction->src_ptr->child; - if (type_is_invalid(src_ptr->value->type)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *count_value = instruction->count->child; - if (type_is_invalid(count_value->value->type)) - return ira->codegen->invalid_inst_gen; - - ZigType *u8 = ira->codegen->builtin_types.entry_u8; - ZigType *dest_uncasted_type = dest_ptr->value->type; - ZigType *src_uncasted_type = src_ptr->value->type; - bool dest_is_volatile = (dest_uncasted_type->id == ZigTypeIdPointer) && - dest_uncasted_type->data.pointer.is_volatile; - bool src_is_volatile = (src_uncasted_type->id == ZigTypeIdPointer) && - src_uncasted_type->data.pointer.is_volatile; - - uint32_t dest_align; - if (dest_uncasted_type->id == ZigTypeIdPointer) { - if ((err = resolve_ptr_align(ira, dest_uncasted_type, &dest_align))) - return ira->codegen->invalid_inst_gen; - } else { - dest_align = get_abi_alignment(ira->codegen, u8); - } - - uint32_t src_align; - if (src_uncasted_type->id == ZigTypeIdPointer) { - if ((err = resolve_ptr_align(ira, src_uncasted_type, &src_align))) - return ira->codegen->invalid_inst_gen; - } else { - src_align = get_abi_alignment(ira->codegen, u8); - } - - ZigType *usize = ira->codegen->builtin_types.entry_usize; - ZigType *u8_ptr_mut = get_pointer_to_type_extra(ira->codegen, u8, false, dest_is_volatile, - PtrLenUnknown, dest_align, 0, 0, false); - ZigType *u8_ptr_const = get_pointer_to_type_extra(ira->codegen, u8, true, src_is_volatile, - PtrLenUnknown, src_align, 0, 0, false); - - Stage1AirInst *casted_dest_ptr = ir_implicit_cast(ira, dest_ptr, u8_ptr_mut); - if (type_is_invalid(casted_dest_ptr->value->type)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *casted_src_ptr = ir_implicit_cast(ira, src_ptr, u8_ptr_const); - if (type_is_invalid(casted_src_ptr->value->type)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *casted_count = ir_implicit_cast(ira, count_value, usize); - if (type_is_invalid(casted_count->value->type)) - return ira->codegen->invalid_inst_gen; - - // TODO test this at comptime with u8 and non-u8 types - // TODO test with dest ptr being a global runtime variable - if (instr_is_comptime(casted_dest_ptr) && - instr_is_comptime(casted_src_ptr) && - instr_is_comptime(casted_count)) - { - ZigValue *dest_ptr_val = ir_resolve_const(ira, casted_dest_ptr, UndefBad); - if (dest_ptr_val == nullptr) - return ira->codegen->invalid_inst_gen; - - ZigValue *src_ptr_val = ir_resolve_const(ira, casted_src_ptr, UndefBad); - if (src_ptr_val == nullptr) - return ira->codegen->invalid_inst_gen; - - ZigValue *count_val = ir_resolve_const(ira, casted_count, UndefBad); - if (count_val == nullptr) - return ira->codegen->invalid_inst_gen; - - if (dest_ptr_val->data.x_ptr.special != ConstPtrSpecialHardCodedAddr) { - size_t count = bigint_as_usize(&count_val->data.x_bigint); - - ZigValue *dest_elements; - size_t dest_start; - size_t dest_end; - switch (dest_ptr_val->data.x_ptr.special) { - case ConstPtrSpecialInvalid: - case ConstPtrSpecialDiscard: - zig_unreachable(); - case ConstPtrSpecialRef: - dest_elements = dest_ptr_val->data.x_ptr.data.ref.pointee; - dest_start = 0; - dest_end = 1; - break; - case ConstPtrSpecialSubArray: - case ConstPtrSpecialBaseArray: - { - ZigValue *array_val = dest_ptr_val->data.x_ptr.data.base_array.array_val; - expand_undef_array(ira->codegen, array_val); - dest_elements = array_val->data.x_array.data.s_none.elements; - dest_start = dest_ptr_val->data.x_ptr.data.base_array.elem_index; - dest_end = array_val->type->data.array.len; - break; - } - case ConstPtrSpecialBaseStruct: - zig_panic("TODO memcpy on const inner struct"); - case ConstPtrSpecialBaseErrorUnionCode: - zig_panic("TODO memcpy on const inner error union code"); - case ConstPtrSpecialBaseErrorUnionPayload: - zig_panic("TODO memcpy on const inner error union payload"); - case ConstPtrSpecialBaseOptionalPayload: - zig_panic("TODO memcpy on const inner optional payload"); - case ConstPtrSpecialHardCodedAddr: - zig_unreachable(); - case ConstPtrSpecialFunction: - zig_panic("TODO memcpy on ptr cast from function"); - case ConstPtrSpecialNull: - zig_panic("TODO memcpy on null ptr"); - } - - if (dest_start + count > dest_end) { - ir_add_error_node(ira, instruction->base.source_node, buf_sprintf("out of bounds pointer access")); - return ira->codegen->invalid_inst_gen; - } - - ZigValue *src_elements; - size_t src_start; - size_t src_end; - - switch (src_ptr_val->data.x_ptr.special) { - case ConstPtrSpecialInvalid: - case ConstPtrSpecialDiscard: - zig_unreachable(); - case ConstPtrSpecialRef: - src_elements = src_ptr_val->data.x_ptr.data.ref.pointee; - src_start = 0; - src_end = 1; - break; - case ConstPtrSpecialSubArray: - case ConstPtrSpecialBaseArray: - { - ZigValue *array_val = src_ptr_val->data.x_ptr.data.base_array.array_val; - expand_undef_array(ira->codegen, array_val); - src_elements = array_val->data.x_array.data.s_none.elements; - src_start = src_ptr_val->data.x_ptr.data.base_array.elem_index; - src_end = array_val->type->data.array.len; - break; - } - case ConstPtrSpecialBaseStruct: - zig_panic("TODO memcpy on const inner struct"); - case ConstPtrSpecialBaseErrorUnionCode: - zig_panic("TODO memcpy on const inner error union code"); - case ConstPtrSpecialBaseErrorUnionPayload: - zig_panic("TODO memcpy on const inner error union payload"); - case ConstPtrSpecialBaseOptionalPayload: - zig_panic("TODO memcpy on const inner optional payload"); - case ConstPtrSpecialHardCodedAddr: - zig_unreachable(); - case ConstPtrSpecialFunction: - zig_panic("TODO memcpy on ptr cast from function"); - case ConstPtrSpecialNull: - zig_panic("TODO memcpy on null ptr"); - } - - if (src_start + count > src_end) { - ir_add_error_node(ira, instruction->base.source_node, buf_sprintf("out of bounds pointer access")); - return ira->codegen->invalid_inst_gen; - } - - // TODO check for noalias violations - this should be generalized to work for any function - - for (size_t i = 0; i < count; i += 1) { - copy_const_val(ira->codegen, &dest_elements[dest_start + i], &src_elements[src_start + i]); - } - - return ir_const_void(ira, instruction->base.scope, instruction->base.source_node); - } - } - - return ir_build_memcpy_gen(ira, instruction->base.scope, instruction->base.source_node, casted_dest_ptr, casted_src_ptr, casted_count); -} - -static ZigType *get_result_loc_type(IrAnalyze *ira, ResultLoc *result_loc) { - if (result_loc == nullptr) return nullptr; - - if (result_loc->id == ResultLocIdCast) { - return ir_resolve_type(ira, result_loc->source_instruction->child); - } - - return nullptr; -} - -static Stage1AirInst *ir_analyze_instruction_slice(IrAnalyze *ira, Stage1ZirInstSlice *instruction) { - Error err; - - Stage1AirInst *ptr_ptr = instruction->ptr->child; - if (type_is_invalid(ptr_ptr->value->type)) - return ira->codegen->invalid_inst_gen; - - ZigType *ptr_ptr_type = ptr_ptr->value->type; - assert(ptr_ptr_type->id == ZigTypeIdPointer); - ZigType *array_type = ptr_ptr_type->data.pointer.child_type; - - Stage1AirInst *start = instruction->start->child; - if (type_is_invalid(start->value->type)) - return ira->codegen->invalid_inst_gen; - - ZigType *usize = ira->codegen->builtin_types.entry_usize; - Stage1AirInst *casted_start = ir_implicit_cast(ira, start, usize); - if (type_is_invalid(casted_start->value->type)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *end; - if (instruction->end) { - end = instruction->end->child; - if (type_is_invalid(end->value->type)) - return ira->codegen->invalid_inst_gen; - end = ir_implicit_cast(ira, end, usize); - if (type_is_invalid(end->value->type)) - return ira->codegen->invalid_inst_gen; - } else { - end = nullptr; - } - - ZigValue *slice_sentinel_val = nullptr; - ZigType *non_sentinel_slice_ptr_type; - ZigType *elem_type; - - bool generate_non_null_assert = false; - - if (array_type->id == ZigTypeIdArray) { - elem_type = array_type->data.array.child_type; - non_sentinel_slice_ptr_type = get_pointer_to_type_extra(ira->codegen, elem_type, - ptr_ptr_type->data.pointer.is_const, - ptr_ptr_type->data.pointer.is_volatile, - PtrLenUnknown, - ptr_ptr_type->data.pointer.explicit_alignment, 0, 0, false); - } else if (array_type->id == ZigTypeIdPointer) { - if (array_type->data.pointer.ptr_len == PtrLenSingle) { - ZigType *main_type = array_type->data.pointer.child_type; - if (main_type->id == ZigTypeIdArray) { - elem_type = main_type->data.pointer.child_type; - non_sentinel_slice_ptr_type = get_pointer_to_type_extra(ira->codegen, - elem_type, - array_type->data.pointer.is_const, array_type->data.pointer.is_volatile, - PtrLenUnknown, - array_type->data.pointer.explicit_alignment, 0, 0, false); - } else { - ir_add_error_node(ira, instruction->base.source_node, buf_sprintf("slice of single-item pointer")); - return ira->codegen->invalid_inst_gen; - } - } else { - elem_type = array_type->data.pointer.child_type; - if (array_type->data.pointer.ptr_len == PtrLenC) { - array_type = adjust_ptr_len(ira->codegen, array_type, PtrLenUnknown); - - // C pointers are allowzero by default. - // However, we want to be able to slice them without generating an allowzero slice (see issue #4401). - // To achieve this, we generate a runtime safety check and make the slice type non-allowzero. - if (array_type->data.pointer.allow_zero) { - array_type = adjust_ptr_allow_zero(ira->codegen, array_type, false); - generate_non_null_assert = true; - } - } - ZigType *maybe_sentineled_slice_ptr_type = array_type; - non_sentinel_slice_ptr_type = adjust_ptr_sentinel(ira->codegen, maybe_sentineled_slice_ptr_type, nullptr); - if (!end) { - ir_add_error_node(ira, instruction->base.source_node, buf_sprintf("slice of pointer must include end value")); - return ira->codegen->invalid_inst_gen; - } - } - } else if (is_slice(array_type)) { - ZigType *maybe_sentineled_slice_ptr_type = array_type->data.structure.fields[slice_ptr_index]->type_entry; - slice_sentinel_val = maybe_sentineled_slice_ptr_type->data.pointer.sentinel; - non_sentinel_slice_ptr_type = adjust_ptr_sentinel(ira->codegen, maybe_sentineled_slice_ptr_type, nullptr); - elem_type = non_sentinel_slice_ptr_type->data.pointer.child_type; - } else { - ir_add_error_node(ira, instruction->base.source_node, - buf_sprintf("slice of non-array type '%s'", buf_ptr(&array_type->name))); - return ira->codegen->invalid_inst_gen; - } - - ZigValue *sentinel_val = nullptr; - if (instruction->sentinel) { - Stage1AirInst *uncasted_sentinel = instruction->sentinel->child; - if (type_is_invalid(uncasted_sentinel->value->type)) - return ira->codegen->invalid_inst_gen; - Stage1AirInst *sentinel = ir_implicit_cast(ira, uncasted_sentinel, elem_type); - if (type_is_invalid(sentinel->value->type)) - return ira->codegen->invalid_inst_gen; - sentinel_val = ir_resolve_const(ira, sentinel, UndefBad); - if (sentinel_val == nullptr) - return ira->codegen->invalid_inst_gen; - } - - ZigType *child_array_type = (array_type->id == ZigTypeIdPointer && - array_type->data.pointer.ptr_len == PtrLenSingle) ? array_type->data.pointer.child_type : array_type; - - ZigType *return_type; - - // If start index and end index are both comptime known, then the result type is a pointer to array - // not a slice. However, if the start or end index is a lazy value, and the result location is a slice, - // then the pointer-to-array would be casted to a slice anyway. So, we preserve the laziness of these - // values by making the return type a slice. - ZigType *res_loc_type = get_result_loc_type(ira, instruction->result_loc); - bool result_loc_is_slice = (res_loc_type != nullptr && is_slice(res_loc_type)); - bool end_is_known = !result_loc_is_slice && - ((end != nullptr && value_is_comptime(end->value)) || - (end == nullptr && child_array_type->id == ZigTypeIdArray)); - - ZigValue *array_sentinel = sentinel_val; - if (end_is_known) { - uint64_t end_scalar; - if (end != nullptr) { - ZigValue *end_val = ir_resolve_const(ira, end, UndefBad); - if (!end_val) - return ira->codegen->invalid_inst_gen; - end_scalar = bigint_as_u64(&end_val->data.x_bigint); - } else { - end_scalar = child_array_type->data.array.len; - } - array_sentinel = (child_array_type->id == ZigTypeIdArray && end_scalar == child_array_type->data.array.len) - ? child_array_type->data.array.sentinel : sentinel_val; - - if (value_is_comptime(casted_start->value)) { - ZigValue *start_val = ir_resolve_const(ira, casted_start, UndefBad); - if (!start_val) - return ira->codegen->invalid_inst_gen; - - uint64_t start_scalar = bigint_as_u64(&start_val->data.x_bigint); - - if (start_scalar > end_scalar) { - ir_add_error_node(ira, instruction->base.source_node, buf_sprintf("out of bounds slice")); - return ira->codegen->invalid_inst_gen; - } - - uint32_t base_ptr_align = non_sentinel_slice_ptr_type->data.pointer.explicit_alignment; - uint32_t ptr_byte_alignment = 0; - if (end_scalar > start_scalar) { - if ((err = compute_elem_align(ira, elem_type, base_ptr_align, start_scalar, &ptr_byte_alignment))) - return ira->codegen->invalid_inst_gen; - } - - ZigType *return_array_type = get_array_type(ira->codegen, elem_type, end_scalar - start_scalar, - array_sentinel); - return_type = get_pointer_to_type_extra(ira->codegen, return_array_type, - non_sentinel_slice_ptr_type->data.pointer.is_const, - non_sentinel_slice_ptr_type->data.pointer.is_volatile, - PtrLenSingle, ptr_byte_alignment, 0, 0, false); - goto done_with_return_type; - } - } else if (array_sentinel == nullptr && end == nullptr) { - array_sentinel = slice_sentinel_val; - } - if (array_sentinel != nullptr) { - // TODO deal with non-abi-alignment here - ZigType *slice_ptr_type = adjust_ptr_sentinel(ira->codegen, non_sentinel_slice_ptr_type, array_sentinel); - return_type = get_slice_type(ira->codegen, slice_ptr_type); - } else { - // TODO deal with non-abi-alignment here - return_type = get_slice_type(ira->codegen, non_sentinel_slice_ptr_type); - } -done_with_return_type: - - if (instr_is_comptime(ptr_ptr) && - value_is_comptime(casted_start->value) && - (!end || value_is_comptime(end->value))) - { - ZigValue *array_val; - ZigValue *parent_ptr; - size_t abs_offset; - size_t rel_end; - bool ptr_is_undef = false; - if (child_array_type->id == ZigTypeIdArray) { - if (array_type->id == ZigTypeIdPointer) { - parent_ptr = const_ptr_pointee(ira, ira->codegen, ptr_ptr->value, instruction->base.source_node); - if (parent_ptr == nullptr) - return ira->codegen->invalid_inst_gen; - - if (parent_ptr->special == ConstValSpecialUndef) { - array_val = nullptr; - abs_offset = 0; - rel_end = SIZE_MAX; - ptr_is_undef = true; - } else if (parent_ptr->data.x_ptr.special == ConstPtrSpecialHardCodedAddr) { - array_val = nullptr; - abs_offset = 0; - rel_end = SIZE_MAX; - } else { - array_val = const_ptr_pointee(ira, ira->codegen, parent_ptr, instruction->base.source_node); - if (array_val == nullptr) - return ira->codegen->invalid_inst_gen; - - rel_end = child_array_type->data.array.len; - abs_offset = 0; - } - } else { - array_val = const_ptr_pointee(ira, ira->codegen, ptr_ptr->value, instruction->base.source_node); - if (array_val == nullptr) - return ira->codegen->invalid_inst_gen; - rel_end = array_type->data.array.len; - parent_ptr = nullptr; - abs_offset = 0; - } - } else if (array_type->id == ZigTypeIdPointer) { - assert(array_type->data.pointer.ptr_len == PtrLenUnknown); - parent_ptr = const_ptr_pointee(ira, ira->codegen, ptr_ptr->value, instruction->base.source_node); - if (parent_ptr == nullptr) - return ira->codegen->invalid_inst_gen; - - if (parent_ptr->special == ConstValSpecialUndef) { - array_val = nullptr; - abs_offset = 0; - rel_end = SIZE_MAX; - ptr_is_undef = true; - } else switch (parent_ptr->data.x_ptr.special) { - case ConstPtrSpecialInvalid: - case ConstPtrSpecialDiscard: - zig_unreachable(); - case ConstPtrSpecialRef: - if (parent_ptr->data.x_ptr.data.ref.pointee->type->id == ZigTypeIdArray) { - array_val = parent_ptr->data.x_ptr.data.ref.pointee; - abs_offset = 0; - rel_end = array_val->type->data.array.len; - } else { - array_val = nullptr; - abs_offset = SIZE_MAX; - rel_end = 1; - } - break; - case ConstPtrSpecialSubArray: - case ConstPtrSpecialBaseArray: - array_val = parent_ptr->data.x_ptr.data.base_array.array_val; - abs_offset = parent_ptr->data.x_ptr.data.base_array.elem_index; - rel_end = array_val->type->data.array.len - abs_offset; - break; - case ConstPtrSpecialBaseStruct: - zig_panic("TODO slice const inner struct"); - case ConstPtrSpecialBaseErrorUnionCode: - zig_panic("TODO slice const inner error union code"); - case ConstPtrSpecialBaseErrorUnionPayload: - zig_panic("TODO slice const inner error union payload"); - case ConstPtrSpecialBaseOptionalPayload: - zig_panic("TODO slice const inner optional payload"); - case ConstPtrSpecialHardCodedAddr: - array_val = nullptr; - abs_offset = 0; - rel_end = SIZE_MAX; - break; - case ConstPtrSpecialFunction: - zig_panic("TODO slice of ptr cast from function"); - case ConstPtrSpecialNull: - zig_panic("TODO slice of null ptr"); - } - } else if (is_slice(array_type)) { - ZigValue *slice_ptr = const_ptr_pointee(ira, ira->codegen, ptr_ptr->value, instruction->base.source_node); - if (slice_ptr == nullptr) - return ira->codegen->invalid_inst_gen; - - if (slice_ptr->special == ConstValSpecialUndef) { - ir_add_error_node(ira, instruction->base.source_node, buf_sprintf("slice of undefined")); - return ira->codegen->invalid_inst_gen; - } - - parent_ptr = slice_ptr->data.x_struct.fields[slice_ptr_index]; - if (parent_ptr->special == ConstValSpecialUndef) { - ir_add_error_node(ira, instruction->base.source_node, buf_sprintf("slice of undefined")); - return ira->codegen->invalid_inst_gen; - } - - ZigValue *len_val = slice_ptr->data.x_struct.fields[slice_len_index]; - - switch (parent_ptr->data.x_ptr.special) { - case ConstPtrSpecialInvalid: - case ConstPtrSpecialDiscard: - zig_unreachable(); - case ConstPtrSpecialRef: - array_val = nullptr; - abs_offset = SIZE_MAX; - rel_end = 1; - break; - case ConstPtrSpecialSubArray: - case ConstPtrSpecialBaseArray: - array_val = parent_ptr->data.x_ptr.data.base_array.array_val; - abs_offset = parent_ptr->data.x_ptr.data.base_array.elem_index; - rel_end = bigint_as_usize(&len_val->data.x_bigint); - break; - case ConstPtrSpecialBaseStruct: - zig_panic("TODO slice const inner struct"); - case ConstPtrSpecialBaseErrorUnionCode: - zig_panic("TODO slice const inner error union code"); - case ConstPtrSpecialBaseErrorUnionPayload: - zig_panic("TODO slice const inner error union payload"); - case ConstPtrSpecialBaseOptionalPayload: - zig_panic("TODO slice const inner optional payload"); - case ConstPtrSpecialHardCodedAddr: - array_val = nullptr; - abs_offset = 0; - rel_end = bigint_as_usize(&len_val->data.x_bigint); - break; - case ConstPtrSpecialFunction: - zig_panic("TODO slice of slice cast from function"); - case ConstPtrSpecialNull: - zig_panic("TODO slice of null"); - } - } else { - zig_unreachable(); - } - - ZigValue *start_val = ir_resolve_const(ira, casted_start, UndefBad); - if (!start_val) - return ira->codegen->invalid_inst_gen; - - uint64_t start_scalar = bigint_as_u64(&start_val->data.x_bigint); - if (!ptr_is_undef && start_scalar > rel_end) { - ir_add_error_node(ira, instruction->base.source_node, buf_sprintf("out of bounds slice")); - return ira->codegen->invalid_inst_gen; - } - - uint64_t end_scalar = rel_end; - if (end) { - ZigValue *end_val = ir_resolve_const(ira, end, UndefBad); - if (!end_val) - return ira->codegen->invalid_inst_gen; - end_scalar = bigint_as_u64(&end_val->data.x_bigint); - } - if (!ptr_is_undef) { - if (end_scalar > rel_end) { - ir_add_error_node(ira, instruction->base.source_node, buf_sprintf("out of bounds slice")); - return ira->codegen->invalid_inst_gen; - } - if (start_scalar > end_scalar) { - ir_add_error_node(ira, instruction->base.source_node, buf_sprintf("slice start is greater than end")); - return ira->codegen->invalid_inst_gen; - } - } - if (ptr_is_undef && start_scalar != end_scalar) { - ir_add_error_node(ira, instruction->base.source_node, buf_sprintf("non-zero length slice of undefined pointer")); - return ira->codegen->invalid_inst_gen; - } - - // check sentinel when target is comptime-known - { - if (!sentinel_val) - goto exit_check_sentinel; - - switch (ptr_ptr->value->data.x_ptr.mut) { - case ConstPtrMutComptimeConst: - case ConstPtrMutComptimeVar: - break; - case ConstPtrMutRuntimeVar: - case ConstPtrMutInfer: - goto exit_check_sentinel; - } - - // prepare check parameters - ZigValue *target = const_ptr_pointee(ira, ira->codegen, ptr_ptr->value, instruction->base.source_node); - if (target == nullptr) - return ira->codegen->invalid_inst_gen; - - uint64_t target_len = 0; - ZigValue *target_sentinel = nullptr; - ZigValue *target_elements = nullptr; - - for (;;) { - if (target->type->id == ZigTypeIdArray) { - // handle `[N]T` - target_len = target->type->data.array.len; - target_sentinel = target->type->data.array.sentinel; - expand_undef_array(ira->codegen, target); - target_elements = target->data.x_array.data.s_none.elements; - break; - } else if (target->type->id == ZigTypeIdPointer && target->type->data.pointer.child_type->id == ZigTypeIdArray) { - // handle `*[N]T` - target = const_ptr_pointee(ira, ira->codegen, target, instruction->base.source_node); - if (target == nullptr) - return ira->codegen->invalid_inst_gen; - assert(target->type->id == ZigTypeIdArray); - continue; - } else if (target->type->id == ZigTypeIdPointer) { - // handle `[*]T` - // handle `[*c]T` - switch (target->data.x_ptr.special) { - case ConstPtrSpecialInvalid: - case ConstPtrSpecialDiscard: - zig_unreachable(); - case ConstPtrSpecialRef: - target = target->data.x_ptr.data.ref.pointee; - assert(target->type->id == ZigTypeIdArray); - continue; - case ConstPtrSpecialBaseArray: - case ConstPtrSpecialSubArray: - target = target->data.x_ptr.data.base_array.array_val; - assert(target->type->id == ZigTypeIdArray); - continue; - case ConstPtrSpecialBaseStruct: - zig_panic("TODO slice const inner struct"); - case ConstPtrSpecialBaseErrorUnionCode: - zig_panic("TODO slice const inner error union code"); - case ConstPtrSpecialBaseErrorUnionPayload: - zig_panic("TODO slice const inner error union payload"); - case ConstPtrSpecialBaseOptionalPayload: - zig_panic("TODO slice const inner optional payload"); - case ConstPtrSpecialHardCodedAddr: - // skip check - goto exit_check_sentinel; - case ConstPtrSpecialFunction: - zig_panic("TODO slice of ptr cast from function"); - case ConstPtrSpecialNull: - zig_panic("TODO slice of null ptr"); - } - break; - } else if (is_slice(target->type)) { - // handle `[]T` - target = target->data.x_struct.fields[slice_ptr_index]; - assert(target->type->id == ZigTypeIdPointer); - continue; - } - - zig_unreachable(); - } - - // perform check - if (target_sentinel == nullptr) { - if (end_scalar >= target_len) { - ir_add_error_node(ira, instruction->base.source_node, buf_sprintf("slice-sentinel is out of bounds")); - return ira->codegen->invalid_inst_gen; - } - if (!const_values_equal(ira->codegen, sentinel_val, &target_elements[end_scalar])) { - ir_add_error_node(ira, instruction->base.source_node, buf_sprintf("slice-sentinel does not match memory at target index")); - return ira->codegen->invalid_inst_gen; - } - } else { - assert(end_scalar <= target_len); - if (end_scalar == target_len) { - if (!const_values_equal(ira->codegen, sentinel_val, target_sentinel)) { - ir_add_error_node(ira, instruction->base.source_node, buf_sprintf("slice-sentinel does not match target-sentinel")); - return ira->codegen->invalid_inst_gen; - } - } else { - if (!const_values_equal(ira->codegen, sentinel_val, &target_elements[end_scalar])) { - ir_add_error_node(ira, instruction->base.source_node, buf_sprintf("slice-sentinel does not match memory at target index")); - return ira->codegen->invalid_inst_gen; - } - } - } - } - exit_check_sentinel: - - Stage1AirInst *result = ir_const(ira, instruction->base.scope, instruction->base.source_node, return_type); - - ZigValue *ptr_val; - if (return_type->id == ZigTypeIdPointer) { - // pointer to array - ptr_val = result->value; - } else { - // slice - result->value->data.x_struct.fields = alloc_const_vals_ptrs(ira->codegen, 2); - - ptr_val = result->value->data.x_struct.fields[slice_ptr_index]; - - ZigValue *len_val = result->value->data.x_struct.fields[slice_len_index]; - init_const_usize(ira->codegen, len_val, end_scalar - start_scalar); - } - - bool return_type_is_const = non_sentinel_slice_ptr_type->data.pointer.is_const; - if (array_val) { - size_t index = abs_offset + start_scalar; - init_const_ptr_array(ira->codegen, ptr_val, array_val, index, return_type_is_const, PtrLenUnknown); - if (return_type->id == ZigTypeIdPointer) { - ptr_val->data.x_ptr.special = ConstPtrSpecialSubArray; - } - if (array_type->id == ZigTypeIdArray) { - ptr_val->data.x_ptr.mut = ptr_ptr->value->data.x_ptr.mut; - } else if (is_slice(array_type)) { - ptr_val->data.x_ptr.mut = parent_ptr->data.x_ptr.mut; - } else if (array_type->id == ZigTypeIdPointer) { - ptr_val->data.x_ptr.mut = parent_ptr->data.x_ptr.mut; - } - } else if (ptr_is_undef) { - ptr_val->type = get_pointer_to_type(ira->codegen, parent_ptr->type->data.pointer.child_type, - return_type_is_const); - ptr_val->special = ConstValSpecialUndef; - } else switch (parent_ptr->data.x_ptr.special) { - case ConstPtrSpecialInvalid: - case ConstPtrSpecialDiscard: - zig_unreachable(); - case ConstPtrSpecialRef: - init_const_ptr_ref(ira->codegen, ptr_val, parent_ptr->data.x_ptr.data.ref.pointee, - return_type_is_const); - break; - case ConstPtrSpecialSubArray: - case ConstPtrSpecialBaseArray: - zig_unreachable(); - case ConstPtrSpecialBaseStruct: - zig_panic("TODO: ir_analyze_instruction_slice ConstPtrSpecialBaseStruct"); - case ConstPtrSpecialBaseErrorUnionCode: - zig_panic("TODO: ir_analyze_instruction_slice ConstPtrSpecialBaseErrorUnionCode"); - case ConstPtrSpecialBaseErrorUnionPayload: - zig_panic("TODO: ir_analyze_instruction_slice ConstPtrSpecialBaseErrorUnionPayload"); - case ConstPtrSpecialBaseOptionalPayload: - zig_panic("TODO: ir_analyze_instruction_slice ConstPtrSpecialBaseOptionalPayload"); - case ConstPtrSpecialHardCodedAddr: - init_const_ptr_hard_coded_addr(ira->codegen, ptr_val, - parent_ptr->type->data.pointer.child_type, - parent_ptr->data.x_ptr.data.hard_coded_addr.addr + start_scalar, - return_type_is_const); - break; - case ConstPtrSpecialFunction: - zig_panic("TODO: ir_analyze_instruction_slice ConstPtrSpecialFunction"); - case ConstPtrSpecialNull: - zig_panic("TODO: ir_analyze_instruction_slice ConstPtrSpecialNull"); - } - - // In the case of pointer-to-array, we must restore this because above it overwrites ptr_val->type - result->value->type = return_type; - return result; - } - - if (generate_non_null_assert) { - Stage1AirInst *ptr_val = ir_get_deref(ira, instruction->base.scope, - instruction->base.source_node, ptr_ptr, nullptr); - - if (type_is_invalid(ptr_val->value->type)) - return ira->codegen->invalid_inst_gen; - - ir_build_assert_non_null(ira, instruction->base.scope, instruction->base.source_node, ptr_val); - } - - Stage1AirInst *result_loc = nullptr; - - if (return_type->id != ZigTypeIdPointer) { - result_loc = ir_resolve_result(ira, &instruction->base, instruction->result_loc, - return_type, nullptr, true, true); - if (result_loc != nullptr) { - if (type_is_invalid(result_loc->value->type) || result_loc->value->type->id == ZigTypeIdUnreachable) { - return result_loc; - } - - src_assert(result_loc->value->type->id == ZigTypeIdPointer, instruction->base.source_node); - if (result_loc->value->type->data.pointer.is_const) { - ir_add_error_node(ira, instruction->base.source_node, buf_sprintf("cannot assign to constant")); - return ira->codegen->invalid_inst_gen; - } - - Stage1AirInst *dummy_value = ir_const(ira, instruction->base.scope, instruction->base.source_node, return_type); - dummy_value->value->special = ConstValSpecialRuntime; - Stage1AirInst *dummy_result = ir_implicit_cast2(ira, - instruction->base.scope, instruction->base.source_node, - dummy_value, result_loc->value->type->data.pointer.child_type); - if (type_is_invalid(dummy_result->value->type)) - return ira->codegen->invalid_inst_gen; - } - } - - return ir_build_slice_gen(ira, instruction->base.scope, instruction->base.source_node, return_type, ptr_ptr, - casted_start, end, instruction->safety_check_on, result_loc, sentinel_val); -} - -static Stage1AirInst *ir_analyze_instruction_has_field(IrAnalyze *ira, Stage1ZirInstHasField *instruction) { - Error err; - ZigType *container_type = ir_resolve_type(ira, instruction->container_type->child); - if (type_is_invalid(container_type)) - return ira->codegen->invalid_inst_gen; - - if ((err = type_resolve(ira->codegen, container_type, ResolveStatusZeroBitsKnown))) - return ira->codegen->invalid_inst_gen; - - Buf *field_name = ir_resolve_str(ira, instruction->field_name->child); - if (field_name == nullptr) - return ira->codegen->invalid_inst_gen; - - bool result; - if (container_type->id == ZigTypeIdStruct) { - result = find_struct_type_field(container_type, field_name) != nullptr; - } else if (container_type->id == ZigTypeIdEnum) { - result = find_enum_type_field(container_type, field_name) != nullptr; - } else if (container_type->id == ZigTypeIdUnion) { - result = find_union_type_field(container_type, field_name) != nullptr; - } else { - ir_add_error_node(ira, instruction->container_type->source_node, - buf_sprintf("type '%s' does not support @hasField", buf_ptr(&container_type->name))); - return ira->codegen->invalid_inst_gen; - } - return ir_const_bool(ira, instruction->base.scope, instruction->base.source_node, result); -} - -static Stage1AirInst *ir_analyze_instruction_wasm_memory_size(IrAnalyze *ira, Stage1ZirInstWasmMemorySize *instruction) { - // TODO generate compile error for target_arch different than 32bit - if (!target_is_wasm(ira->codegen->zig_target)) { - ir_add_error_node(ira, instruction->base.source_node, - buf_sprintf("@wasmMemorySize is a wasm32 feature only")); - return ira->codegen->invalid_inst_gen; - } - - Stage1AirInst *index = instruction->index->child; - if (type_is_invalid(index->value->type)) - return ira->codegen->invalid_inst_gen; - - ZigType *u32 = ira->codegen->builtin_types.entry_u32; - - Stage1AirInst *casted_index = ir_implicit_cast(ira, index, u32); - if (type_is_invalid(casted_index->value->type)) - return ira->codegen->invalid_inst_gen; - - return ir_build_wasm_memory_size_gen(ira, instruction->base.scope, instruction->base.source_node, casted_index); -} - -static Stage1AirInst *ir_analyze_instruction_wasm_memory_grow(IrAnalyze *ira, Stage1ZirInstWasmMemoryGrow *instruction) { - // TODO generate compile error for target_arch different than 32bit - if (!target_is_wasm(ira->codegen->zig_target)) { - ir_add_error_node(ira, instruction->base.source_node, - buf_sprintf("@wasmMemoryGrow is a wasm32 feature only")); - return ira->codegen->invalid_inst_gen; - } - - Stage1AirInst *index = instruction->index->child; - if (type_is_invalid(index->value->type)) - return ira->codegen->invalid_inst_gen; - - ZigType *u32 = ira->codegen->builtin_types.entry_u32; - - Stage1AirInst *casted_index = ir_implicit_cast(ira, index, u32); - if (type_is_invalid(casted_index->value->type)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *delta = instruction->delta->child; - if (type_is_invalid(delta->value->type)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *casted_delta = ir_implicit_cast(ira, delta, u32); - if (type_is_invalid(casted_delta->value->type)) - return ira->codegen->invalid_inst_gen; - - return ir_build_wasm_memory_grow_gen(ira, instruction->base.scope, instruction->base.source_node, casted_index, casted_delta); -} - -static Stage1AirInst *ir_analyze_instruction_breakpoint(IrAnalyze *ira, Stage1ZirInstBreakpoint *instruction) { - return ir_build_breakpoint_gen(ira, instruction->base.scope, instruction->base.source_node); -} - -static Stage1AirInst *ir_analyze_instruction_return_address(IrAnalyze *ira, Stage1ZirInstReturnAddress *instruction) { - return ir_build_return_address_gen(ira, instruction->base.scope, instruction->base.source_node); -} - -static Stage1AirInst *ir_analyze_instruction_frame_address(IrAnalyze *ira, Stage1ZirInstFrameAddress *instruction) { - return ir_build_frame_address_gen(ira, instruction->base.scope, instruction->base.source_node); -} - -static Stage1AirInst *ir_analyze_instruction_frame_handle(IrAnalyze *ira, Stage1ZirInstFrameHandle *instruction) { - ZigFn *fn = ira->fn; - src_assert(fn != nullptr, instruction->base.source_node); - - if (fn->inferred_async_node == nullptr) { - fn->inferred_async_node = instruction->base.source_node; - } - - ZigType *frame_type = get_fn_frame_type(ira->codegen, fn); - ZigType *ptr_frame_type = get_pointer_to_type(ira->codegen, frame_type, false); - - return ir_build_handle_gen(ira, instruction->base.scope, instruction->base.source_node, ptr_frame_type); -} - -static Stage1AirInst *ir_analyze_instruction_frame_type(IrAnalyze *ira, Stage1ZirInstFrameType *instruction) { - ZigFn *fn = ir_resolve_fn(ira, instruction->fn->child); - if (fn == nullptr) - return ira->codegen->invalid_inst_gen; - - if (fn->type_entry->data.fn.is_generic) { - ir_add_error_node(ira, instruction->base.source_node, - buf_sprintf("@Frame() of generic function")); - return ira->codegen->invalid_inst_gen; - } - - ZigType *ty = get_fn_frame_type(ira->codegen, fn); - return ir_const_type(ira, instruction->base.scope, instruction->base.source_node, ty); -} - -static Stage1AirInst *ir_analyze_instruction_frame_size(IrAnalyze *ira, Stage1ZirInstFrameSize *instruction) { - Stage1AirInst *fn = instruction->fn->child; - if (type_is_invalid(fn->value->type)) - return ira->codegen->invalid_inst_gen; - - if (fn->value->type->id != ZigTypeIdFn) { - ir_add_error(ira, fn, - buf_sprintf("expected function, found '%s'", buf_ptr(&fn->value->type->name))); - return ira->codegen->invalid_inst_gen; - } - - ira->codegen->need_frame_size_prefix_data = true; - - return ir_build_frame_size_gen(ira, instruction->base.scope, instruction->base.source_node, fn); -} - -static Stage1AirInst *ir_analyze_instruction_align_of(IrAnalyze *ira, Stage1ZirInstAlignOf *instruction) { - // Here we create a lazy value in order to avoid resolving the alignment of the type - // immediately. This avoids false positive dependency loops such as: - // const Node = struct { - // field: []align(@alignOf(Node)) Node, - // }; - Stage1AirInst *result = ir_const(ira, instruction->base.scope, instruction->base.source_node, ira->codegen->builtin_types.entry_num_lit_int); - result->value->special = ConstValSpecialLazy; - - LazyValueAlignOf *lazy_align_of = heap::c_allocator.create(); - lazy_align_of->ira = ira; ira_ref(ira); - result->value->data.x_lazy = &lazy_align_of->base; - lazy_align_of->base.id = LazyValueIdAlignOf; - - lazy_align_of->target_type = instruction->type_value->child; - if (ir_resolve_type_lazy(ira, lazy_align_of->target_type) == nullptr) - return ira->codegen->invalid_inst_gen; - - return result; -} - -static Stage1AirInst *ir_analyze_instruction_overflow_op(IrAnalyze *ira, Stage1ZirInstOverflowOp *instruction) { - Error err; - - Stage1AirInst *type_value = instruction->type_value->child; - if (type_is_invalid(type_value->value->type)) - return ira->codegen->invalid_inst_gen; - - ZigType *dest_type = ir_resolve_type(ira, type_value); - if (type_is_invalid(dest_type)) - return ira->codegen->invalid_inst_gen; - - if (dest_type->id != ZigTypeIdInt) { - ir_add_error(ira, type_value, - buf_sprintf("expected integer type, found '%s'", buf_ptr(&dest_type->name))); - return ira->codegen->invalid_inst_gen; - } - - Stage1AirInst *op1 = instruction->op1->child; - if (type_is_invalid(op1->value->type)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *casted_op1 = ir_implicit_cast(ira, op1, dest_type); - if (type_is_invalid(casted_op1->value->type)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *op2 = instruction->op2->child; - if (type_is_invalid(op2->value->type)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *casted_op2; - if (instruction->op == IrOverflowOpShl) { - ZigType *shift_amt_type = get_smallest_unsigned_int_type(ira->codegen, - dest_type->data.integral.bit_count - 1); - casted_op2 = ir_implicit_cast(ira, op2, shift_amt_type); - } else { - casted_op2 = ir_implicit_cast(ira, op2, dest_type); - } - if (type_is_invalid(casted_op2->value->type)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *result_ptr = instruction->result_ptr->child; - if (type_is_invalid(result_ptr->value->type)) - return ira->codegen->invalid_inst_gen; - - ZigType *expected_ptr_type; - if (result_ptr->value->type->id == ZigTypeIdPointer) { - uint32_t alignment; - if ((err = resolve_ptr_align(ira, result_ptr->value->type, &alignment))) - return ira->codegen->invalid_inst_gen; - expected_ptr_type = get_pointer_to_type_extra(ira->codegen, dest_type, - false, result_ptr->value->type->data.pointer.is_volatile, - PtrLenSingle, - alignment, 0, 0, false); - } else { - expected_ptr_type = get_pointer_to_type(ira->codegen, dest_type, false); - } - - Stage1AirInst *casted_result_ptr = ir_implicit_cast(ira, result_ptr, expected_ptr_type); - if (type_is_invalid(casted_result_ptr->value->type)) - return ira->codegen->invalid_inst_gen; - - // Don't write anything to the result pointer. - if (dest_type->data.integral.bit_count == 0) - return ir_const_bool(ira, instruction->base.scope, instruction->base.source_node, false); - - if (instr_is_comptime(casted_op1) && - instr_is_comptime(casted_op2) && - instr_is_comptime(casted_result_ptr)) - { - ZigValue *op1_val = ir_resolve_const(ira, casted_op1, UndefBad); - if (op1_val == nullptr) - return ira->codegen->invalid_inst_gen; - - ZigValue *op2_val = ir_resolve_const(ira, casted_op2, UndefBad); - if (op2_val == nullptr) - return ira->codegen->invalid_inst_gen; - - ZigValue *result_val = ir_resolve_const(ira, casted_result_ptr, UndefBad); - if (result_val == nullptr) - return ira->codegen->invalid_inst_gen; - - BigInt *op1_bigint = &op1_val->data.x_bigint; - BigInt *op2_bigint = &op2_val->data.x_bigint; - ZigValue *pointee_val = const_ptr_pointee(ira, ira->codegen, result_val, - casted_result_ptr->source_node); - if (pointee_val == nullptr) - return ira->codegen->invalid_inst_gen; - BigInt *dest_bigint = &pointee_val->data.x_bigint; - switch (instruction->op) { - case IrOverflowOpAdd: - bigint_add(dest_bigint, op1_bigint, op2_bigint); - break; - case IrOverflowOpSub: - bigint_sub(dest_bigint, op1_bigint, op2_bigint); - break; - case IrOverflowOpMul: - bigint_mul(dest_bigint, op1_bigint, op2_bigint); - break; - case IrOverflowOpShl: - bigint_shl(dest_bigint, op1_bigint, op2_bigint); - break; - } - bool result_bool = false; - if (!bigint_fits_in_bits(dest_bigint, dest_type->data.integral.bit_count, - dest_type->data.integral.is_signed)) - { - result_bool = true; - BigInt tmp_bigint; - bigint_init_bigint(&tmp_bigint, dest_bigint); - bigint_truncate(dest_bigint, &tmp_bigint, dest_type->data.integral.bit_count, - dest_type->data.integral.is_signed); - } - pointee_val->special = ConstValSpecialStatic; - return ir_const_bool(ira, instruction->base.scope, instruction->base.source_node, result_bool); - } - - return ir_build_overflow_op_gen(ira, instruction->base.scope, instruction->base.source_node, instruction->op, - casted_op1, casted_op2, casted_result_ptr, dest_type); -} - -static void ir_eval_mul_add(IrAnalyze *ira, ZigType *float_type, - ZigValue *op1, ZigValue *op2, ZigValue *op3, ZigValue *out_val) { - if (float_type->id == ZigTypeIdComptimeFloat) { - f128M_mulAdd(&out_val->data.x_bigfloat.value, &op1->data.x_bigfloat.value, &op2->data.x_bigfloat.value, - &op3->data.x_bigfloat.value); - } else if (float_type->id == ZigTypeIdFloat) { - switch (float_type->data.floating.bit_count) { - case 16: - out_val->data.x_f16 = f16_mulAdd(op1->data.x_f16, op2->data.x_f16, op3->data.x_f16); - break; - case 32: - out_val->data.x_f32 = fmaf(op1->data.x_f32, op2->data.x_f32, op3->data.x_f32); - break; - case 64: - out_val->data.x_f64 = fma(op1->data.x_f64, op2->data.x_f64, op3->data.x_f64); - break; - case 80: - zig_panic("compiler bug: TODO: implement 'mulAdd' for type 'f80'. See https://github.com/ziglang/zig/issues/4026"); - case 128: - f128M_mulAdd(&op1->data.x_f128, &op2->data.x_f128, &op3->data.x_f128, &out_val->data.x_f128); - break; - default: - zig_unreachable(); - } - } else { - zig_unreachable(); - } -} - -static Stage1AirInst *ir_analyze_instruction_mul_add(IrAnalyze *ira, Stage1ZirInstMulAdd *instruction) { - Stage1AirInst *type_value = instruction->type_value->child; - if (type_is_invalid(type_value->value->type)) - return ira->codegen->invalid_inst_gen; - - ZigType *expr_type = ir_resolve_type(ira, type_value); - if (type_is_invalid(expr_type)) - return ira->codegen->invalid_inst_gen; - - // Only allow float types, and vectors of floats. - ZigType *float_type = (expr_type->id == ZigTypeIdVector) ? expr_type->data.vector.elem_type : expr_type; - if (float_type->id != ZigTypeIdFloat) { - ir_add_error(ira, type_value, - buf_sprintf("expected float or vector of float type, found '%s'", buf_ptr(&float_type->name))); - return ira->codegen->invalid_inst_gen; - } - - Stage1AirInst *op1 = instruction->op1->child; - if (type_is_invalid(op1->value->type)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *casted_op1 = ir_implicit_cast(ira, op1, expr_type); - if (type_is_invalid(casted_op1->value->type)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *op2 = instruction->op2->child; - if (type_is_invalid(op2->value->type)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *casted_op2 = ir_implicit_cast(ira, op2, expr_type); - if (type_is_invalid(casted_op2->value->type)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *op3 = instruction->op3->child; - if (type_is_invalid(op3->value->type)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *casted_op3 = ir_implicit_cast(ira, op3, expr_type); - if (type_is_invalid(casted_op3->value->type)) - return ira->codegen->invalid_inst_gen; - - if (instr_is_comptime(casted_op1) && - instr_is_comptime(casted_op2) && - instr_is_comptime(casted_op3)) { - ZigValue *op1_const = ir_resolve_const(ira, casted_op1, UndefBad); - if (!op1_const) - return ira->codegen->invalid_inst_gen; - ZigValue *op2_const = ir_resolve_const(ira, casted_op2, UndefBad); - if (!op2_const) - return ira->codegen->invalid_inst_gen; - ZigValue *op3_const = ir_resolve_const(ira, casted_op3, UndefBad); - if (!op3_const) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *result = ir_const(ira, instruction->base.scope, instruction->base.source_node, expr_type); - ZigValue *out_val = result->value; - - if (expr_type->id == ZigTypeIdVector) { - expand_undef_array(ira->codegen, op1_const); - expand_undef_array(ira->codegen, op2_const); - expand_undef_array(ira->codegen, op3_const); - out_val->special = ConstValSpecialUndef; - expand_undef_array(ira->codegen, out_val); - size_t len = expr_type->data.vector.len; - for (size_t i = 0; i < len; i += 1) { - ZigValue *float_operand_op1 = &op1_const->data.x_array.data.s_none.elements[i]; - ZigValue *float_operand_op2 = &op2_const->data.x_array.data.s_none.elements[i]; - ZigValue *float_operand_op3 = &op3_const->data.x_array.data.s_none.elements[i]; - ZigValue *float_out_val = &out_val->data.x_array.data.s_none.elements[i]; - assert(float_operand_op1->type == float_type); - assert(float_operand_op2->type == float_type); - assert(float_operand_op3->type == float_type); - assert(float_out_val->type == float_type); - ir_eval_mul_add(ira, float_type, - op1_const, op2_const, op3_const, float_out_val); - float_out_val->type = float_type; - } - out_val->type = expr_type; - out_val->special = ConstValSpecialStatic; - } else { - ir_eval_mul_add(ira, float_type, op1_const, op2_const, op3_const, out_val); - } - return result; - } - - return ir_build_mul_add_gen(ira, instruction->base.scope, instruction->base.source_node, casted_op1, casted_op2, casted_op3, expr_type); -} - -static Stage1AirInst *ir_analyze_instruction_test_err(IrAnalyze *ira, Stage1ZirInstTestErr *instruction) { - Stage1AirInst *base_ptr = instruction->base_ptr->child; - if (type_is_invalid(base_ptr->value->type)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *value; - if (instruction->base_ptr_is_payload) { - value = base_ptr; - } else { - value = ir_get_deref(ira, instruction->base.scope, instruction->base.source_node, - base_ptr, nullptr); - } - - ZigType *type_entry = value->value->type; - if (type_is_invalid(type_entry)) - return ira->codegen->invalid_inst_gen; - if (type_entry->id == ZigTypeIdErrorUnion) { - if (instr_is_comptime(value)) { - ZigValue *err_union_val = ir_resolve_const(ira, value, UndefBad); - if (!err_union_val) - return ira->codegen->invalid_inst_gen; - - if (err_union_val->special != ConstValSpecialRuntime) { - ErrorTableEntry *err = err_union_val->data.x_err_union.error_set->data.x_err_set; - return ir_const_bool(ira, instruction->base.scope, instruction->base.source_node, (err != nullptr)); - } - } - - if (instruction->resolve_err_set) { - ZigType *err_set_type = type_entry->data.error_union.err_set_type; - if (!resolve_inferred_error_set(ira->codegen, err_set_type, instruction->base.source_node)) { - return ira->codegen->invalid_inst_gen; - } - if (!type_is_global_error_set(err_set_type) && - err_set_type->data.error_set.err_count == 0) - { - assert(!err_set_type->data.error_set.incomplete); - return ir_const_bool(ira, instruction->base.scope, instruction->base.source_node, false); - } - } - - return ir_build_test_err_gen(ira, instruction->base.scope, instruction->base.source_node, value); - } else if (type_entry->id == ZigTypeIdErrorSet) { - return ir_const_bool(ira, instruction->base.scope, instruction->base.source_node, true); - } else { - return ir_const_bool(ira, instruction->base.scope, instruction->base.source_node, false); - } -} - -static Stage1AirInst *ir_analyze_unwrap_err_code(IrAnalyze *ira, Scope *scope, AstNode *source_node, - Stage1AirInst *base_ptr, bool initializing) -{ - ZigType *ptr_type = base_ptr->value->type; - - // This will be a pointer type because unwrap err payload IR instruction operates on a pointer to a thing. - assert(ptr_type->id == ZigTypeIdPointer); - - ZigType *type_entry = ptr_type->data.pointer.child_type; - if (type_is_invalid(type_entry)) - return ira->codegen->invalid_inst_gen; - - if (type_entry->id != ZigTypeIdErrorUnion) { - ir_add_error(ira, base_ptr, - buf_sprintf("expected error union type, found '%s'", buf_ptr(&type_entry->name))); - return ira->codegen->invalid_inst_gen; - } - - ZigType *err_set_type = type_entry->data.error_union.err_set_type; - ZigType *result_type = get_pointer_to_type_extra(ira->codegen, err_set_type, - ptr_type->data.pointer.is_const, ptr_type->data.pointer.is_volatile, PtrLenSingle, - ptr_type->data.pointer.explicit_alignment, 0, 0, false); - - if (instr_is_comptime(base_ptr)) { - ZigValue *ptr_val = ir_resolve_const(ira, base_ptr, UndefBad); - if (!ptr_val) - return ira->codegen->invalid_inst_gen; - if (ptr_val->data.x_ptr.mut != ConstPtrMutRuntimeVar && - ptr_val->data.x_ptr.special != ConstPtrSpecialHardCodedAddr) - { - ZigValue *err_union_val = const_ptr_pointee(ira, ira->codegen, ptr_val, source_node); - if (err_union_val == nullptr) - return ira->codegen->invalid_inst_gen; - - if (initializing && err_union_val->special == ConstValSpecialUndef) { - ZigValue *vals = ira->codegen->pass1_arena->allocate(2); - ZigValue *err_set_val = &vals[0]; - ZigValue *payload_val = &vals[1]; - - err_set_val->special = ConstValSpecialUndef; - err_set_val->type = err_set_type; - err_set_val->parent.id = ConstParentIdErrUnionCode; - err_set_val->parent.data.p_err_union_code.err_union_val = err_union_val; - - payload_val->special = ConstValSpecialUndef; - payload_val->type = type_entry->data.error_union.payload_type; - payload_val->parent.id = ConstParentIdErrUnionPayload; - payload_val->parent.data.p_err_union_payload.err_union_val = err_union_val; - - err_union_val->special = ConstValSpecialStatic; - err_union_val->data.x_err_union.error_set = err_set_val; - err_union_val->data.x_err_union.payload = payload_val; - } - src_assert(err_union_val->special != ConstValSpecialRuntime, source_node); - - Stage1AirInst *result; - if (ptr_val->data.x_ptr.mut == ConstPtrMutInfer) { - result = ir_build_unwrap_err_code_gen(ira, scope, - source_node, base_ptr, result_type); - result->value->special = ConstValSpecialStatic; - } else { - result = ir_const(ira, scope, source_node, result_type); - } - ZigValue *const_val = result->value; - const_val->data.x_ptr.special = ConstPtrSpecialBaseErrorUnionCode; - const_val->data.x_ptr.data.base_err_union_code.err_union_val = err_union_val; - const_val->data.x_ptr.mut = ptr_val->data.x_ptr.mut; - return result; - } - } - - return ir_build_unwrap_err_code_gen(ira, scope, source_node, base_ptr, result_type); -} - -static Stage1AirInst *ir_analyze_instruction_unwrap_err_code(IrAnalyze *ira, Stage1ZirInstUnwrapErrCode *instruction) { - Stage1AirInst *base_ptr = instruction->err_union_ptr->child; - if (type_is_invalid(base_ptr->value->type)) - return ira->codegen->invalid_inst_gen; - return ir_analyze_unwrap_err_code(ira, instruction->base.scope, instruction->base.source_node, base_ptr, false); -} - -static Stage1AirInst *ir_analyze_unwrap_error_payload(IrAnalyze *ira, Scope *scope, AstNode *source_node, - Stage1AirInst *base_ptr, bool safety_check_on, bool initializing) -{ - ZigType *ptr_type = base_ptr->value->type; - - // This will be a pointer type because unwrap err payload IR instruction operates on a pointer to a thing. - assert(ptr_type->id == ZigTypeIdPointer); - - ZigType *type_entry = ptr_type->data.pointer.child_type; - if (type_is_invalid(type_entry)) - return ira->codegen->invalid_inst_gen; - - if (type_entry->id != ZigTypeIdErrorUnion) { - ir_add_error(ira, base_ptr, - buf_sprintf("expected error union type, found '%s'", buf_ptr(&type_entry->name))); - return ira->codegen->invalid_inst_gen; - } - - ZigType *payload_type = type_entry->data.error_union.payload_type; - if (type_is_invalid(payload_type)) - return ira->codegen->invalid_inst_gen; - - ZigType *result_type = get_pointer_to_type_extra(ira->codegen, payload_type, - ptr_type->data.pointer.is_const, ptr_type->data.pointer.is_volatile, - PtrLenSingle, 0, 0, 0, false); - - if (instr_is_comptime(base_ptr)) { - ZigValue *ptr_val = ir_resolve_const(ira, base_ptr, UndefBad); - if (!ptr_val) - return ira->codegen->invalid_inst_gen; - if (ptr_val->data.x_ptr.mut != ConstPtrMutRuntimeVar) { - ZigValue *err_union_val = const_ptr_pointee(ira, ira->codegen, ptr_val, source_node); - if (err_union_val == nullptr) - return ira->codegen->invalid_inst_gen; - if (initializing && err_union_val->special == ConstValSpecialUndef) { - ZigValue *vals = ira->codegen->pass1_arena->allocate(2); - ZigValue *err_set_val = &vals[0]; - ZigValue *payload_val = &vals[1]; - - err_set_val->special = ConstValSpecialStatic; - err_set_val->type = type_entry->data.error_union.err_set_type; - err_set_val->data.x_err_set = nullptr; - - payload_val->special = ConstValSpecialUndef; - payload_val->type = payload_type; - - err_union_val->special = ConstValSpecialStatic; - err_union_val->data.x_err_union.error_set = err_set_val; - err_union_val->data.x_err_union.payload = payload_val; - } - - if (err_union_val->special != ConstValSpecialRuntime) { - ErrorTableEntry *err = err_union_val->data.x_err_union.error_set->data.x_err_set; - if (err != nullptr) { - ir_add_error_node(ira, source_node, - buf_sprintf("caught unexpected error '%s'", buf_ptr(&err->name))); - return ira->codegen->invalid_inst_gen; - } - - Stage1AirInst *result; - if (ptr_val->data.x_ptr.mut == ConstPtrMutInfer) { - result = ir_build_unwrap_err_payload_gen(ira, scope, - source_node, base_ptr, safety_check_on, initializing, result_type); - result->value->special = ConstValSpecialStatic; - } else { - result = ir_const(ira, scope, source_node, result_type); - } - result->value->data.x_ptr.special = ConstPtrSpecialRef; - result->value->data.x_ptr.data.ref.pointee = err_union_val->data.x_err_union.payload; - result->value->data.x_ptr.mut = ptr_val->data.x_ptr.mut; - return result; - } - } - } - - return ir_build_unwrap_err_payload_gen(ira, scope, source_node, - base_ptr, safety_check_on, initializing, result_type); -} - -static Stage1AirInst *ir_analyze_instruction_unwrap_err_payload(IrAnalyze *ira, - Stage1ZirInstUnwrapErrPayload *instruction) -{ - assert(instruction->value->child); - Stage1AirInst *value = instruction->value->child; - if (type_is_invalid(value->value->type)) - return ira->codegen->invalid_inst_gen; - - return ir_analyze_unwrap_error_payload(ira, instruction->base.scope, instruction->base.source_node, value, instruction->safety_check_on, false); -} - -static Stage1AirInst *ir_analyze_instruction_fn_proto(IrAnalyze *ira, Stage1ZirInstFnProto *instruction) { - AstNode *proto_node = instruction->base.source_node; - assert(proto_node->type == NodeTypeFnProto); - - Stage1AirInst *result = ir_const(ira, instruction->base.scope, instruction->base.source_node, ira->codegen->builtin_types.entry_type); - result->value->special = ConstValSpecialLazy; - - LazyValueFnType *lazy_fn_type = heap::c_allocator.create(); - lazy_fn_type->ira = ira; ira_ref(ira); - result->value->data.x_lazy = &lazy_fn_type->base; - lazy_fn_type->base.id = LazyValueIdFnType; - - if (proto_node->data.fn_proto.auto_err_set) { - ir_add_error_node(ira, instruction->base.source_node, - buf_sprintf("inferring error set of return type valid only for function definitions")); - return ira->codegen->invalid_inst_gen; - } - - lazy_fn_type->cc = cc_from_fn_proto(&proto_node->data.fn_proto); - if (instruction->callconv_value != nullptr) { - ZigType *cc_enum_type = get_builtin_type(ira->codegen, "CallingConvention"); - - Stage1AirInst *casted_value = ir_implicit_cast(ira, instruction->callconv_value->child, cc_enum_type); - if (type_is_invalid(casted_value->value->type)) - return ira->codegen->invalid_inst_gen; - - ZigValue *const_value = ir_resolve_const(ira, casted_value, UndefBad); - if (const_value == nullptr) - return ira->codegen->invalid_inst_gen; - - lazy_fn_type->cc = (CallingConvention)bigint_as_u32(&const_value->data.x_enum_tag); - } - - size_t param_count = proto_node->data.fn_proto.params.length; - lazy_fn_type->proto_node = proto_node; - lazy_fn_type->param_types = heap::c_allocator.allocate(param_count); - - for (size_t param_index = 0; param_index < param_count; param_index += 1) { - AstNode *param_node = proto_node->data.fn_proto.params.at(param_index); - assert(param_node->type == NodeTypeParamDecl); - - bool param_is_var_args = param_node->data.param_decl.is_var_args; - if (param_is_var_args) { - const CallingConvention cc = lazy_fn_type->cc; - - if (cc == CallingConventionC) { - break; - } else { - ir_add_error_node(ira, instruction->base.source_node, - buf_sprintf("var args only allowed in functions with C calling convention")); - return ira->codegen->invalid_inst_gen; - } - } - - if (instruction->param_types[param_index] == nullptr) { - lazy_fn_type->is_generic = true; - return result; - } - - Stage1AirInst *param_type_value = instruction->param_types[param_index]->child; - if (type_is_invalid(param_type_value->value->type)) - return ira->codegen->invalid_inst_gen; - if (ir_resolve_const(ira, param_type_value, LazyOk) == nullptr) - return ira->codegen->invalid_inst_gen; - lazy_fn_type->param_types[param_index] = param_type_value; - } - - if (instruction->align_value != nullptr) { - lazy_fn_type->align_inst = instruction->align_value->child; - if (ir_resolve_const(ira, lazy_fn_type->align_inst, LazyOk) == nullptr) - return ira->codegen->invalid_inst_gen; - } - - lazy_fn_type->return_type = instruction->return_type->child; - if (ir_resolve_const(ira, lazy_fn_type->return_type, LazyOk) == nullptr) - return ira->codegen->invalid_inst_gen; - - return result; -} - -static Stage1AirInst *ir_analyze_instruction_test_comptime(IrAnalyze *ira, Stage1ZirInstTestComptime *instruction) { - Stage1AirInst *value = instruction->value->child; - if (type_is_invalid(value->value->type)) - return ira->codegen->invalid_inst_gen; - - return ir_const_bool(ira, instruction->base.scope, instruction->base.source_node, instr_is_comptime(value)); -} - -static Stage1AirInst *ir_analyze_instruction_check_switch_prongs(IrAnalyze *ira, - Stage1ZirInstCheckSwitchProngs *instruction, bool have_underscore_prong) -{ - Stage1AirInst *target_value = instruction->target_value->child; - ZigType *switch_type = target_value->value->type; - if (type_is_invalid(switch_type)) - return ira->codegen->invalid_inst_gen; - - ZigValue *original_value = ((Stage1ZirInstSwitchTarget *)(instruction->target_value))->target_value_ptr->child->value; - bool target_is_originally_union = original_value->type->id == ZigTypeIdPointer && - original_value->type->data.pointer.child_type->id == ZigTypeIdUnion; - - if (switch_type->id == ZigTypeIdEnum) { - HashMap field_prev_uses = {}; - field_prev_uses.init(switch_type->data.enumeration.src_field_count); - - for (size_t range_i = 0; range_i < instruction->range_count; range_i += 1) { - Stage1ZirInstCheckSwitchProngsRange *range = &instruction->ranges[range_i]; - - Stage1AirInst *start_value_uncasted = range->start->child; - if (type_is_invalid(start_value_uncasted->value->type)) - return ira->codegen->invalid_inst_gen; - Stage1AirInst *start_value = ir_implicit_cast(ira, start_value_uncasted, switch_type); - if (type_is_invalid(start_value->value->type)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *end_value_uncasted = range->end->child; - if (type_is_invalid(end_value_uncasted->value->type)) - return ira->codegen->invalid_inst_gen; - Stage1AirInst *end_value = ir_implicit_cast(ira, end_value_uncasted, switch_type); - if (type_is_invalid(end_value->value->type)) - return ira->codegen->invalid_inst_gen; - - assert(start_value->value->type->id == ZigTypeIdEnum); - BigInt start_index; - bigint_init_bigint(&start_index, &start_value->value->data.x_enum_tag); - - assert(end_value->value->type->id == ZigTypeIdEnum); - BigInt end_index; - bigint_init_bigint(&end_index, &end_value->value->data.x_enum_tag); - - if (bigint_cmp(&start_index, &end_index) == CmpGT) { - ir_add_error(ira, start_value, - buf_sprintf("range start value is greater than the end value")); - } - - BigInt field_index; - bigint_init_bigint(&field_index, &start_index); - for (;;) { - Cmp cmp = bigint_cmp(&field_index, &end_index); - if (cmp == CmpGT) { - break; - } - auto entry = field_prev_uses.put_unique(field_index, start_value->source_node); - if (entry) { - AstNode *prev_node = entry->value; - TypeEnumField *enum_field = find_enum_field_by_tag(switch_type, &field_index); - assert(enum_field != nullptr); - ErrorMsg *msg = ir_add_error(ira, start_value, - buf_sprintf("duplicate switch value: '%s.%s'", buf_ptr(&switch_type->name), - buf_ptr(enum_field->name))); - add_error_note(ira->codegen, msg, prev_node, buf_sprintf("other value here")); - } - bigint_incr(&field_index); - } - } - if (have_underscore_prong) { - if (!switch_type->data.enumeration.non_exhaustive) { - ir_add_error_node(ira, instruction->base.source_node, - buf_sprintf("switch on exhaustive enum has `_` prong")); - } else if (target_is_originally_union) { - ir_add_error_node(ira, instruction->base.source_node, - buf_sprintf("`_` prong not allowed when switching on tagged union")); - } - for (uint32_t i = 0; i < switch_type->data.enumeration.src_field_count; i += 1) { - TypeEnumField *enum_field = &switch_type->data.enumeration.fields[i]; - if (buf_eql_str(enum_field->name, "_")) - continue; - - auto entry = field_prev_uses.maybe_get(enum_field->value); - if (!entry) { - ir_add_error_node(ira, instruction->base.source_node, - buf_sprintf("enumeration value '%s.%s' not handled in switch", buf_ptr(&switch_type->name), - buf_ptr(enum_field->name))); - } - } - } else if (instruction->else_prong == nullptr) { - if (switch_type->data.enumeration.non_exhaustive && !target_is_originally_union) { - ir_add_error_node(ira, instruction->base.source_node, - buf_sprintf("switch on non-exhaustive enum must include `else` or `_` prong")); - } - for (uint32_t i = 0; i < switch_type->data.enumeration.src_field_count; i += 1) { - TypeEnumField *enum_field = &switch_type->data.enumeration.fields[i]; - - auto entry = field_prev_uses.maybe_get(enum_field->value); - if (!entry) { - ir_add_error_node(ira, instruction->base.source_node, - buf_sprintf("enumeration value '%s.%s' not handled in switch", buf_ptr(&switch_type->name), - buf_ptr(enum_field->name))); - } - } - } else if(!switch_type->data.enumeration.non_exhaustive && switch_type->data.enumeration.src_field_count == instruction->range_count) { - ir_add_error_node(ira, instruction->else_prong, - buf_sprintf("unreachable else prong, all cases already handled")); - return ira->codegen->invalid_inst_gen; - } - } else if (switch_type->id == ZigTypeIdErrorSet) { - if (!resolve_inferred_error_set(ira->codegen, switch_type, target_value->source_node)) { - return ira->codegen->invalid_inst_gen; - } - - size_t field_prev_uses_count = ira->codegen->errors_by_index.length; - AstNode **field_prev_uses = heap::c_allocator.allocate(field_prev_uses_count); - - for (size_t range_i = 0; range_i < instruction->range_count; range_i += 1) { - Stage1ZirInstCheckSwitchProngsRange *range = &instruction->ranges[range_i]; - - Stage1AirInst *start_value_uncasted = range->start->child; - if (type_is_invalid(start_value_uncasted->value->type)) - return ira->codegen->invalid_inst_gen; - Stage1AirInst *start_value = ir_implicit_cast(ira, start_value_uncasted, switch_type); - if (type_is_invalid(start_value->value->type)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *end_value_uncasted = range->end->child; - if (type_is_invalid(end_value_uncasted->value->type)) - return ira->codegen->invalid_inst_gen; - Stage1AirInst *end_value = ir_implicit_cast(ira, end_value_uncasted, switch_type); - if (type_is_invalid(end_value->value->type)) - return ira->codegen->invalid_inst_gen; - - src_assert(start_value->value->type->id == ZigTypeIdErrorSet, instruction->base.source_node); - uint32_t start_index = start_value->value->data.x_err_set->value; - - src_assert(end_value->value->type->id == ZigTypeIdErrorSet, instruction->base.source_node); - uint32_t end_index = end_value->value->data.x_err_set->value; - - if (start_index != end_index) { - ir_add_error(ira, end_value, buf_sprintf("ranges not allowed when switching on errors")); - return ira->codegen->invalid_inst_gen; - } - - AstNode *prev_node = field_prev_uses[start_index]; - if (prev_node != nullptr) { - Buf *err_name = &ira->codegen->errors_by_index.at(start_index)->name; - ErrorMsg *msg = ir_add_error(ira, start_value, - buf_sprintf("duplicate switch value: '%s.%s'", buf_ptr(&switch_type->name), buf_ptr(err_name))); - add_error_note(ira->codegen, msg, prev_node, buf_sprintf("other value here")); - } - field_prev_uses[start_index] = start_value->source_node; - } - if (instruction->else_prong == nullptr) { - if (type_is_global_error_set(switch_type)) { - ir_add_error_node(ira, instruction->base.source_node, - buf_sprintf("else prong required when switching on type 'anyerror'")); - return ira->codegen->invalid_inst_gen; - } else { - for (uint32_t i = 0; i < switch_type->data.error_set.err_count; i += 1) { - ErrorTableEntry *err_entry = switch_type->data.error_set.errors[i]; - - AstNode *prev_node = field_prev_uses[err_entry->value]; - if (prev_node == nullptr) { - ir_add_error_node(ira, instruction->base.source_node, - buf_sprintf("error.%s not handled in switch", buf_ptr(&err_entry->name))); - } - } - } - } - - heap::c_allocator.deallocate(field_prev_uses, field_prev_uses_count); - } else if (switch_type->id == ZigTypeIdInt) { - RangeSet rs = {0}; - for (size_t range_i = 0; range_i < instruction->range_count; range_i += 1) { - Stage1ZirInstCheckSwitchProngsRange *range = &instruction->ranges[range_i]; - - Stage1AirInst *start_value = range->start->child; - if (type_is_invalid(start_value->value->type)) - return ira->codegen->invalid_inst_gen; - Stage1AirInst *casted_start_value = ir_implicit_cast(ira, start_value, switch_type); - if (type_is_invalid(casted_start_value->value->type)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *end_value = range->end->child; - if (type_is_invalid(end_value->value->type)) - return ira->codegen->invalid_inst_gen; - Stage1AirInst *casted_end_value = ir_implicit_cast(ira, end_value, switch_type); - if (type_is_invalid(casted_end_value->value->type)) - return ira->codegen->invalid_inst_gen; - - ZigValue *start_val = ir_resolve_const(ira, casted_start_value, UndefBad); - if (!start_val) - return ira->codegen->invalid_inst_gen; - - ZigValue *end_val = ir_resolve_const(ira, casted_end_value, UndefBad); - if (!end_val) - return ira->codegen->invalid_inst_gen; - - assert(start_val->type->id == ZigTypeIdInt || start_val->type->id == ZigTypeIdComptimeInt); - assert(end_val->type->id == ZigTypeIdInt || end_val->type->id == ZigTypeIdComptimeInt); - - if (bigint_cmp(&start_val->data.x_bigint, &end_val->data.x_bigint) == CmpGT) { - ir_add_error(ira, start_value, - buf_sprintf("range start value is greater than the end value")); - } - - AstNode *prev_node = rangeset_add_range(&rs, &start_val->data.x_bigint, &end_val->data.x_bigint, - start_value->source_node); - if (prev_node != nullptr) { - ErrorMsg *msg = ir_add_error(ira, start_value, buf_sprintf("duplicate switch value")); - add_error_note(ira->codegen, msg, prev_node, buf_sprintf("previous value here")); - return ira->codegen->invalid_inst_gen; - } - } - - BigInt min_val; - eval_min_max_value_int(ira->codegen, switch_type, &min_val, false); - BigInt max_val; - eval_min_max_value_int(ira->codegen, switch_type, &max_val, true); - bool handles_all_cases = rangeset_spans(&rs, &min_val, &max_val); - if (!handles_all_cases && instruction->else_prong == nullptr) { - ir_add_error_node(ira, instruction->base.source_node, buf_sprintf("switch must handle all possibilities")); - return ira->codegen->invalid_inst_gen; - } else if(handles_all_cases && instruction->else_prong != nullptr) { - ir_add_error_node(ira, instruction->else_prong, - buf_sprintf("unreachable else prong, all cases already handled")); - return ira->codegen->invalid_inst_gen; - } - } else if (switch_type->id == ZigTypeIdBool) { - int seenTrue = 0; - int seenFalse = 0; - for (size_t range_i = 0; range_i < instruction->range_count; range_i += 1) { - Stage1ZirInstCheckSwitchProngsRange *range = &instruction->ranges[range_i]; - - Stage1AirInst *value = range->start->child; - - Stage1AirInst *casted_value = ir_implicit_cast(ira, value, switch_type); - if (type_is_invalid(casted_value->value->type)) - return ira->codegen->invalid_inst_gen; - - ZigValue *const_expr_val = ir_resolve_const(ira, casted_value, UndefBad); - if (!const_expr_val) - return ira->codegen->invalid_inst_gen; - - assert(const_expr_val->type->id == ZigTypeIdBool); - - if (const_expr_val->data.x_bool == true) { - seenTrue += 1; - } else { - seenFalse += 1; - } - - if ((seenTrue > 1) || (seenFalse > 1)) { - ir_add_error(ira, value, buf_sprintf("duplicate switch value")); - return ira->codegen->invalid_inst_gen; - } - } - if (((seenTrue < 1) || (seenFalse < 1)) && instruction->else_prong == nullptr) { - ir_add_error_node(ira, instruction->base.source_node, buf_sprintf("switch must handle all possibilities")); - return ira->codegen->invalid_inst_gen; - } - - if(seenTrue == 1 && seenFalse == 1 && instruction->else_prong != nullptr) { - ir_add_error_node(ira, instruction->else_prong, - buf_sprintf("unreachable else prong, all cases already handled")); - return ira->codegen->invalid_inst_gen; - } - } else if (instruction->else_prong == nullptr) { - ir_add_error_node(ira, instruction->base.source_node, - buf_sprintf("else prong required when switching on type '%s'", buf_ptr(&switch_type->name))); - return ira->codegen->invalid_inst_gen; - } else if(switch_type->id == ZigTypeIdMetaType) { - HashMap prevs; - // HashMap doubles capacity when reaching 60% capacity, - // because we know the size at init we can avoid reallocation by doubling it here - prevs.init(instruction->range_count * 2); - for (size_t range_i = 0; range_i < instruction->range_count; range_i += 1) { - Stage1ZirInstCheckSwitchProngsRange *range = &instruction->ranges[range_i]; - - Stage1AirInst *value = range->start->child; - Stage1AirInst *casted_value = ir_implicit_cast(ira, value, switch_type); - if (type_is_invalid(casted_value->value->type)) { - prevs.deinit(); - return ira->codegen->invalid_inst_gen; - } - - ZigValue *const_expr_val = ir_resolve_const(ira, casted_value, UndefBad); - if (!const_expr_val) { - prevs.deinit(); - return ira->codegen->invalid_inst_gen; - } - - auto entry = prevs.put_unique(const_expr_val->data.x_type, value); - if(entry != nullptr) { - ErrorMsg *msg = ir_add_error(ira, value, buf_sprintf("duplicate switch value")); - add_error_note(ira->codegen, msg, entry->value->source_node, buf_sprintf("previous value here")); - prevs.deinit(); - return ira->codegen->invalid_inst_gen; - } - } - prevs.deinit(); - } - return ir_const_void(ira, instruction->base.scope, instruction->base.source_node); -} - -static Stage1AirInst *ir_analyze_instruction_check_statement_is_void(IrAnalyze *ira, - Stage1ZirInstCheckStatementIsVoid *instruction) -{ - Stage1AirInst *statement_value = instruction->statement_value->child; - ZigType *statement_type = statement_value->value->type; - if (type_is_invalid(statement_type)) - return ira->codegen->invalid_inst_gen; - - if (statement_type->id != ZigTypeIdVoid && statement_type->id != ZigTypeIdUnreachable) { - if(statement_type->id == ZigTypeIdErrorUnion || statement_type->id == ZigTypeIdErrorSet) { - ir_add_error_node(ira, instruction->base.source_node, buf_sprintf("error is ignored. consider using `try`, `catch`, or `if`")); - }else{ - ir_add_error_node(ira, instruction->base.source_node, buf_sprintf("expression value is ignored")); - } - } - - return ir_const_void(ira, instruction->base.scope, instruction->base.source_node); -} - -static Stage1AirInst *ir_analyze_instruction_panic(IrAnalyze *ira, Stage1ZirInstPanic *instruction) { - Stage1AirInst *msg = instruction->msg->child; - if (type_is_invalid(msg->value->type)) - return ir_unreach_error(ira); - - if (ir_should_inline(ira->zir, instruction->base.scope)) { - ir_add_error_node(ira, instruction->base.source_node, buf_sprintf("encountered @panic at compile-time")); - return ir_unreach_error(ira); - } - - ZigType *u8_ptr_type = get_pointer_to_type_extra(ira->codegen, ira->codegen->builtin_types.entry_u8, - true, false, PtrLenUnknown, 0, 0, 0, false); - ZigType *str_type = get_slice_type(ira->codegen, u8_ptr_type); - Stage1AirInst *casted_msg = ir_implicit_cast(ira, msg, str_type); - if (type_is_invalid(casted_msg->value->type)) - return ir_unreach_error(ira); - - Stage1AirInst *new_instruction = ir_build_panic_gen(ira, instruction->base.scope, instruction->base.source_node, casted_msg); - return ir_finish_anal(ira, new_instruction); -} - -static Stage1AirInst *ir_align_cast(IrAnalyze *ira, Stage1AirInst *target, uint32_t align_bytes, bool safety_check_on) { - Error err; - - ZigType *target_type = target->value->type; - assert(!type_is_invalid(target_type)); - - ZigType *result_type; - uint32_t old_align_bytes; - - ZigType *actual_ptr = target_type; - if (actual_ptr->id == ZigTypeIdOptional) { - actual_ptr = actual_ptr->data.maybe.child_type; - } else if (is_slice(actual_ptr)) { - actual_ptr = actual_ptr->data.structure.fields[slice_ptr_index]->type_entry; - } - - if (safety_check_on && !type_has_bits(ira->codegen, actual_ptr)) { - ir_add_error(ira, target, - buf_sprintf("cannot adjust alignment of zero sized type '%s'", buf_ptr(&target_type->name))); - return ira->codegen->invalid_inst_gen; - } - - if (target_type->id == ZigTypeIdPointer) { - if ((err = resolve_ptr_align(ira, target_type, &old_align_bytes))) - return ira->codegen->invalid_inst_gen; - result_type = adjust_ptr_align(ira->codegen, target_type, align_bytes); - } else if (target_type->id == ZigTypeIdFn) { - FnTypeId fn_type_id = target_type->data.fn.fn_type_id; - old_align_bytes = fn_type_id.alignment; - fn_type_id.alignment = align_bytes; - result_type = get_fn_type(ira->codegen, &fn_type_id); - } else if (target_type->id == ZigTypeIdAnyFrame) { - if (align_bytes >= get_async_frame_align_bytes(ira->codegen)) { - result_type = target_type; - } else { - ir_add_error(ira, target, buf_sprintf("sub-aligned anyframe not allowed")); - return ira->codegen->invalid_inst_gen; - } - } else if (target_type->id == ZigTypeIdOptional && - target_type->data.maybe.child_type->id == ZigTypeIdPointer) - { - ZigType *ptr_type = target_type->data.maybe.child_type; - if ((err = resolve_ptr_align(ira, ptr_type, &old_align_bytes))) - return ira->codegen->invalid_inst_gen; - ZigType *better_ptr_type = adjust_ptr_align(ira->codegen, ptr_type, align_bytes); - - result_type = get_optional_type(ira->codegen, better_ptr_type); - } else if (target_type->id == ZigTypeIdOptional && - target_type->data.maybe.child_type->id == ZigTypeIdFn) - { - FnTypeId fn_type_id = target_type->data.maybe.child_type->data.fn.fn_type_id; - old_align_bytes = fn_type_id.alignment; - fn_type_id.alignment = align_bytes; - ZigType *fn_type = get_fn_type(ira->codegen, &fn_type_id); - result_type = get_optional_type(ira->codegen, fn_type); - } else if (is_slice(target_type)) { - ZigType *slice_ptr_type = target_type->data.structure.fields[slice_ptr_index]->type_entry; - if ((err = resolve_ptr_align(ira, slice_ptr_type, &old_align_bytes))) - return ira->codegen->invalid_inst_gen; - ZigType *result_ptr_type = adjust_ptr_align(ira->codegen, slice_ptr_type, align_bytes); - result_type = get_slice_type(ira->codegen, result_ptr_type); - } else { - ir_add_error(ira, target, - buf_sprintf("expected pointer or slice, found '%s'", buf_ptr(&target_type->name))); - return ira->codegen->invalid_inst_gen; - } - - if (instr_is_comptime(target)) { - ZigValue *val = ir_resolve_const(ira, target, UndefBad); - if (!val) - return ira->codegen->invalid_inst_gen; - - if (val->data.x_ptr.special == ConstPtrSpecialHardCodedAddr && - val->data.x_ptr.data.hard_coded_addr.addr % align_bytes != 0) - { - ir_add_error(ira, target, - buf_sprintf("pointer address 0x%" ZIG_PRI_x64 " is not aligned to %" PRIu32 " bytes", - val->data.x_ptr.data.hard_coded_addr.addr, align_bytes)); - return ira->codegen->invalid_inst_gen; - } - - Stage1AirInst *result = ir_const(ira, target->scope, target->source_node, result_type); - copy_const_val(ira->codegen, result->value, val); - result->value->type = result_type; - return result; - } - - if (safety_check_on && align_bytes > old_align_bytes && align_bytes != 1) { - return ir_build_align_cast_gen(ira, target->scope, target->source_node, target, result_type); - } else { - return ir_build_cast(ira, target->scope, target->source_node, result_type, target, CastOpNoop); - } -} - -static Stage1AirInst *ir_analyze_ptr_cast(IrAnalyze *ira, Scope *scope, AstNode *source_node, - Stage1AirInst *ptr, AstNode *ptr_src, ZigType *dest_type, AstNode *dest_type_src, - bool safety_check_on, bool keep_bigger_alignment) -{ - Error err; - - ZigType *src_type = ptr->value->type; - assert(!type_is_invalid(src_type)); - - if (src_type == dest_type) { - return ptr; - } - - // We have a check for zero bits later so we use get_src_ptr_type to - // validate src_type and dest_type. - - ZigType *if_slice_ptr_type; - if (is_slice(src_type)) { - TypeStructField *ptr_field = src_type->data.structure.fields[slice_ptr_index]; - if_slice_ptr_type = resolve_struct_field_type(ira->codegen, ptr_field); - } else { - if_slice_ptr_type = src_type; - - ZigType *src_ptr_type = get_src_ptr_type(src_type); - if (src_ptr_type == nullptr) { - ir_add_error_node(ira, ptr_src, - buf_sprintf("expected pointer, found '%s'", buf_ptr(&src_type->name))); - return ira->codegen->invalid_inst_gen; - } - } - - ZigType *dest_ptr_type = get_src_ptr_type(dest_type); - if (dest_ptr_type == nullptr) { - ir_add_error_node(ira, dest_type_src, - buf_sprintf("expected pointer, found '%s'", buf_ptr(&dest_type->name))); - return ira->codegen->invalid_inst_gen; - } - - if (get_ptr_const(ira->codegen, src_type) && !get_ptr_const(ira->codegen, dest_type)) { - ir_add_error_node(ira, source_node, buf_sprintf("cast discards const qualifier")); - return ira->codegen->invalid_inst_gen; - } - uint32_t dest_align_bytes; - if ((err = resolve_ptr_align(ira, dest_type, &dest_align_bytes))) - return ira->codegen->invalid_inst_gen; - - uint32_t src_align_bytes = 0; - if (keep_bigger_alignment || dest_align_bytes != 1) { - if ((err = resolve_ptr_align(ira, src_type, &src_align_bytes))) - return ira->codegen->invalid_inst_gen; - } - - if ((err = type_resolve(ira->codegen, dest_type, ResolveStatusZeroBitsKnown))) - return ira->codegen->invalid_inst_gen; - - if ((err = type_resolve(ira->codegen, src_type, ResolveStatusZeroBitsKnown))) - return ira->codegen->invalid_inst_gen; - - if (safety_check_on && - type_has_bits(ira->codegen, dest_type) && - !type_has_bits(ira->codegen, if_slice_ptr_type)) - { - ErrorMsg *msg = ir_add_error_node(ira, source_node, - buf_sprintf("'%s' and '%s' do not have the same in-memory representation", - buf_ptr(&src_type->name), buf_ptr(&dest_type->name))); - add_error_note(ira->codegen, msg, ptr_src, - buf_sprintf("'%s' has no in-memory bits", buf_ptr(&src_type->name))); - add_error_note(ira->codegen, msg, dest_type_src, - buf_sprintf("'%s' has in-memory bits", buf_ptr(&dest_type->name))); - return ira->codegen->invalid_inst_gen; - } - - // For slices, follow the `ptr` field. - if (is_slice(src_type)) { - TypeStructField *ptr_field = src_type->data.structure.fields[slice_ptr_index]; - Stage1AirInst *ptr_ref = ir_get_ref(ira, scope, source_node, ptr, true, false); - Stage1AirInst *ptr_ptr = ir_analyze_struct_field_ptr(ira, scope, source_node, ptr_field, ptr_ref, src_type, false); - ptr = ir_get_deref(ira, scope, source_node, ptr_ptr, nullptr); - } - - if (instr_is_comptime(ptr)) { - bool dest_allows_addr_zero = ptr_allows_addr_zero(dest_type); - UndefAllowed is_undef_allowed = dest_allows_addr_zero ? UndefOk : UndefBad; - ZigValue *val = ir_resolve_const(ira, ptr, is_undef_allowed); - if (val == nullptr) - return ira->codegen->invalid_inst_gen; - - if (value_is_comptime(val) && val->special != ConstValSpecialUndef) { - bool is_addr_zero = val->data.x_ptr.special == ConstPtrSpecialNull || - (val->data.x_ptr.special == ConstPtrSpecialHardCodedAddr && - val->data.x_ptr.data.hard_coded_addr.addr == 0); - if (is_addr_zero && !dest_allows_addr_zero) { - ir_add_error_node(ira, source_node, - buf_sprintf("null pointer casted to type '%s'", buf_ptr(&dest_type->name))); - return ira->codegen->invalid_inst_gen; - } - } - - Stage1AirInst *result; - if (val->data.x_ptr.mut == ConstPtrMutInfer) { - result = ir_build_ptr_cast_gen(ira, scope, source_node, dest_type, ptr, safety_check_on); - } else { - result = ir_const(ira, scope, source_node, dest_type); - } - InferredStructField *isf = (val->type->id == ZigTypeIdPointer) ? - val->type->data.pointer.inferred_struct_field : nullptr; - if (isf == nullptr) { - copy_const_val(ira->codegen, result->value, val); - } else { - // The destination value should have x_ptr struct pointing to underlying struct value - result->value->data.x_ptr.mut = val->data.x_ptr.mut; - TypeStructField *field = find_struct_type_field(isf->inferred_struct_type, isf->field_name); - assert(field != nullptr); - if (field->is_comptime) { - result->value->data.x_ptr.special = ConstPtrSpecialRef; - result->value->data.x_ptr.data.ref.pointee = field->init_val; - } else { - assert(val->data.x_ptr.special == ConstPtrSpecialRef); - result->value->data.x_ptr.special = ConstPtrSpecialBaseStruct; - result->value->data.x_ptr.data.base_struct.struct_val = val->data.x_ptr.data.ref.pointee; - result->value->data.x_ptr.data.base_struct.field_index = field->src_index; - } - result->value->special = ConstValSpecialStatic; - } - result->value->type = dest_type; - - // Keep the bigger alignment, it can only help- unless the target is zero bits. - if (keep_bigger_alignment && src_align_bytes > dest_align_bytes && type_has_bits(ira->codegen, dest_type)) { - result = ir_align_cast(ira, result, src_align_bytes, false); - } - - return result; - } - - if (src_align_bytes != 0 && dest_align_bytes > src_align_bytes) { - ErrorMsg *msg = ir_add_error_node(ira, source_node, buf_sprintf("cast increases pointer alignment")); - add_error_note(ira->codegen, msg, ptr_src, - buf_sprintf("'%s' has alignment %" PRIu32, buf_ptr(&src_type->name), src_align_bytes)); - add_error_note(ira->codegen, msg, dest_type_src, - buf_sprintf("'%s' has alignment %" PRIu32, buf_ptr(&dest_type->name), dest_align_bytes)); - return ira->codegen->invalid_inst_gen; - } - - Stage1AirInst *casted_ptr = ir_build_ptr_cast_gen(ira, scope, source_node, dest_type, ptr, safety_check_on); - - // Keep the bigger alignment, it can only help- unless the target is zero bits. - Stage1AirInst *result; - if (keep_bigger_alignment && src_align_bytes > dest_align_bytes && type_has_bits(ira->codegen, dest_type)) { - result = ir_align_cast(ira, casted_ptr, src_align_bytes, false); - if (type_is_invalid(result->value->type)) - return ira->codegen->invalid_inst_gen; - } else { - result = casted_ptr; - } - return result; -} - -static Stage1AirInst *ir_analyze_instruction_ptr_cast(IrAnalyze *ira, Stage1ZirInstPtrCast *instruction) { - Stage1AirInst *dest_type_value = instruction->dest_type->child; - ZigType *dest_type = ir_resolve_type(ira, dest_type_value); - if (type_is_invalid(dest_type)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *ptr = instruction->ptr->child; - ZigType *src_type = ptr->value->type; - if (type_is_invalid(src_type)) - return ira->codegen->invalid_inst_gen; - - // This logic is not quite right; this is just to get stage1 to accept valid code - // we use in the self-hosted compiler. - if (is_slice(dest_type) && is_slice(src_type)) { - return ir_analyze_bit_cast(ira, instruction->base.scope, instruction->base.source_node, ptr, dest_type); - } - - bool keep_bigger_alignment = true; - return ir_analyze_ptr_cast(ira, instruction->base.scope, instruction->base.source_node, ptr, - instruction->ptr->source_node, dest_type, dest_type_value->source_node, - instruction->safety_check_on, keep_bigger_alignment); -} - -static void buf_write_value_bytes_array(CodeGen *codegen, uint8_t *buf, ZigValue *val, size_t len) { - size_t buf_i = 0; - // TODO optimize the buf case - expand_undef_array(codegen, val); - for (size_t elem_i = 0; elem_i < val->type->data.array.len; elem_i += 1) { - ZigValue *elem = &val->data.x_array.data.s_none.elements[elem_i]; - buf_write_value_bytes(codegen, &buf[buf_i], elem); - buf_i += type_size(codegen, elem->type); - } - if (val->type->id == ZigTypeIdArray && val->type->data.array.sentinel != nullptr) { - buf_write_value_bytes(codegen, &buf[buf_i], val->type->data.array.sentinel); - } -} - -static void buf_write_value_bytes(CodeGen *codegen, uint8_t *buf, ZigValue *val) { - if (val->special == ConstValSpecialUndef) { - expand_undef_struct(codegen, val); - val->special = ConstValSpecialStatic; - } - assert(val->special == ConstValSpecialStatic); - switch (val->type->id) { - case ZigTypeIdInvalid: - case ZigTypeIdMetaType: - case ZigTypeIdOpaque: - case ZigTypeIdBoundFn: - case ZigTypeIdUnreachable: - case ZigTypeIdComptimeFloat: - case ZigTypeIdComptimeInt: - case ZigTypeIdEnumLiteral: - case ZigTypeIdUndefined: - case ZigTypeIdNull: - case ZigTypeIdErrorUnion: - case ZigTypeIdErrorSet: - zig_unreachable(); - case ZigTypeIdVoid: - return; - case ZigTypeIdBool: - buf[0] = val->data.x_bool ? 1 : 0; - return; - case ZigTypeIdInt: - bigint_write_twos_complement(&val->data.x_bigint, buf, val->type->data.integral.bit_count, - codegen->is_big_endian); - return; - case ZigTypeIdEnum: - bigint_write_twos_complement(&val->data.x_enum_tag, buf, - val->type->data.enumeration.tag_int_type->data.integral.bit_count, - codegen->is_big_endian); - return; - case ZigTypeIdFloat: - float_write_ieee597(val, buf, codegen->is_big_endian); - return; - case ZigTypeIdPointer: - if (val->data.x_ptr.special == ConstPtrSpecialHardCodedAddr) { - BigInt bn; - bigint_init_unsigned(&bn, val->data.x_ptr.data.hard_coded_addr.addr); - bigint_write_twos_complement(&bn, buf, codegen->builtin_types.entry_usize->data.integral.bit_count, codegen->is_big_endian); - return; - } else { - zig_unreachable(); - } - case ZigTypeIdArray: - return buf_write_value_bytes_array(codegen, buf, val, val->type->data.array.len); - case ZigTypeIdVector: - return buf_write_value_bytes_array(codegen, buf, val, val->type->data.vector.len); - case ZigTypeIdStruct: - switch (val->type->data.structure.layout) { - case ContainerLayoutAuto: - zig_unreachable(); - case ContainerLayoutExtern: { - size_t src_field_count = val->type->data.structure.src_field_count; - for (size_t field_i = 0; field_i < src_field_count; field_i += 1) { - TypeStructField *struct_field = val->type->data.structure.fields[field_i]; - if (struct_field->gen_index == SIZE_MAX || struct_field->is_comptime) - continue; - ZigValue *field_val = val->data.x_struct.fields[field_i]; - size_t offset = struct_field->offset; - buf_write_value_bytes(codegen, buf + offset, field_val); - } - return; - } - case ContainerLayoutPacked: { - size_t src_field_count = val->type->data.structure.src_field_count; - size_t gen_field_count = val->type->data.structure.gen_field_count; - size_t gen_i = 0; - size_t src_i = 0; - size_t offset = 0; - bool is_big_endian = codegen->is_big_endian; - uint8_t child_buf_prealloc[16]; - size_t child_buf_len = 16; - uint8_t *child_buf = child_buf_prealloc; - while (gen_i < gen_field_count) { - size_t big_int_byte_count = val->type->data.structure.host_int_bytes[gen_i]; - if (big_int_byte_count > child_buf_len) { - child_buf = heap::c_allocator.allocate_nonzero(big_int_byte_count); - child_buf_len = big_int_byte_count; - } - BigInt big_int; - bigint_init_unsigned(&big_int, 0); - size_t used_bits = 0; - while (src_i < src_field_count) { - TypeStructField *field = val->type->data.structure.fields[src_i]; - if (field->is_comptime) { - src_i += 1; - continue; - } - assert(field->gen_index != SIZE_MAX); - if (field->gen_index != gen_i) - break; - uint32_t packed_bits_size = type_size_bits(codegen, field->type_entry); - buf_write_value_bytes(codegen, child_buf, val->data.x_struct.fields[src_i]); - BigInt child_val; - bigint_read_twos_complement(&child_val, child_buf, packed_bits_size, is_big_endian, - false); - if (is_big_endian) { - BigInt shift_amt; - bigint_init_unsigned(&shift_amt, packed_bits_size); - BigInt shifted; - bigint_shl(&shifted, &big_int, &shift_amt); - bigint_or(&big_int, &shifted, &child_val); - } else { - BigInt shift_amt; - bigint_init_unsigned(&shift_amt, used_bits); - BigInt child_val_shifted; - bigint_shl(&child_val_shifted, &child_val, &shift_amt); - BigInt tmp; - bigint_or(&tmp, &big_int, &child_val_shifted); - big_int = tmp; - used_bits += packed_bits_size; - } - src_i += 1; - } - bigint_write_twos_complement(&big_int, buf + offset, big_int_byte_count * 8, is_big_endian); - offset += big_int_byte_count; - gen_i += 1; - } - return; - } - } - zig_unreachable(); - case ZigTypeIdOptional: - zig_panic("TODO buf_write_value_bytes maybe type"); - case ZigTypeIdFn: - zig_panic("TODO buf_write_value_bytes fn type"); - case ZigTypeIdUnion: - zig_panic("TODO buf_write_value_bytes union type"); - case ZigTypeIdFnFrame: - zig_panic("TODO buf_write_value_bytes async fn frame type"); - case ZigTypeIdAnyFrame: - zig_panic("TODO buf_write_value_bytes anyframe type"); - } - zig_unreachable(); -} - -static Error buf_read_value_bytes_array(IrAnalyze *ira, CodeGen *codegen, AstNode *source_node, uint8_t *buf, - ZigValue *val, ZigType *elem_type, size_t len) -{ - Error err; - uint64_t elem_size = type_size(codegen, elem_type); - - switch (val->data.x_array.special) { - case ConstArraySpecialNone: - val->data.x_array.data.s_none.elements = codegen->pass1_arena->allocate(len); - for (size_t i = 0; i < len; i++) { - ZigValue *elem = &val->data.x_array.data.s_none.elements[i]; - elem->special = ConstValSpecialStatic; - elem->type = elem_type; - if ((err = buf_read_value_bytes(ira, codegen, source_node, buf + (elem_size * i), elem))) - return err; - } - return ErrorNone; - case ConstArraySpecialUndef: - zig_panic("TODO buf_read_value_bytes ConstArraySpecialUndef array type"); - case ConstArraySpecialBuf: - zig_panic("TODO buf_read_value_bytes ConstArraySpecialBuf array type"); - } - zig_unreachable(); -} - -static Error buf_read_value_bytes(IrAnalyze *ira, CodeGen *codegen, AstNode *source_node, uint8_t *buf, ZigValue *val) { - Error err; - src_assert(val->special == ConstValSpecialStatic, source_node); - switch (val->type->id) { - case ZigTypeIdInvalid: - case ZigTypeIdMetaType: - case ZigTypeIdOpaque: - case ZigTypeIdBoundFn: - case ZigTypeIdUnreachable: - case ZigTypeIdComptimeFloat: - case ZigTypeIdComptimeInt: - case ZigTypeIdEnumLiteral: - case ZigTypeIdUndefined: - case ZigTypeIdNull: - zig_unreachable(); - case ZigTypeIdVoid: - return ErrorNone; - case ZigTypeIdBool: - val->data.x_bool = (buf[0] != 0); - return ErrorNone; - case ZigTypeIdInt: - bigint_read_twos_complement(&val->data.x_bigint, buf, val->type->data.integral.bit_count, - codegen->is_big_endian, val->type->data.integral.is_signed); - return ErrorNone; - case ZigTypeIdFloat: - float_read_ieee597(val, buf, codegen->is_big_endian); - return ErrorNone; - case ZigTypeIdPointer: - { - val->data.x_ptr.special = ConstPtrSpecialHardCodedAddr; - BigInt bn; - bigint_read_twos_complement(&bn, buf, codegen->builtin_types.entry_usize->data.integral.bit_count, - codegen->is_big_endian, false); - val->data.x_ptr.data.hard_coded_addr.addr = bigint_as_usize(&bn); - return ErrorNone; - } - case ZigTypeIdArray: - return buf_read_value_bytes_array(ira, codegen, source_node, buf, val, val->type->data.array.child_type, - val->type->data.array.len); - case ZigTypeIdVector: - return buf_read_value_bytes_array(ira, codegen, source_node, buf, val, val->type->data.vector.elem_type, - val->type->data.vector.len); - case ZigTypeIdEnum: { - ZigType *tag_int_type = val->type->data.enumeration.tag_int_type; - src_assert(tag_int_type->id == ZigTypeIdInt, source_node); - bigint_read_twos_complement(&val->data.x_enum_tag, buf, tag_int_type->data.integral.bit_count, - codegen->is_big_endian, tag_int_type->data.integral.is_signed); - return ErrorNone; - } case ZigTypeIdStruct: - switch (val->type->data.structure.layout) { - case ContainerLayoutAuto: { - switch(val->type->data.structure.special){ - case StructSpecialNone: - case StructSpecialInferredTuple: - case StructSpecialInferredStruct: { - ErrorMsg *msg = opt_ir_add_error_node(ira, codegen, source_node, - buf_sprintf("non-extern, non-packed struct '%s' cannot have its bytes reinterpreted", - buf_ptr(&val->type->name))); - add_error_note(codegen, msg, val->type->data.structure.decl_node, - buf_sprintf("declared here")); - break; - } - case StructSpecialSlice: { - opt_ir_add_error_node(ira, codegen, source_node, - buf_sprintf("slice '%s' cannot have its bytes reinterpreted", - buf_ptr(&val->type->name))); - break; - } - } - return ErrorSemanticAnalyzeFail; - } - case ContainerLayoutExtern: { - size_t src_field_count = val->type->data.structure.src_field_count; - val->data.x_struct.fields = alloc_const_vals_ptrs(codegen, src_field_count); - for (size_t field_i = 0; field_i < src_field_count; field_i += 1) { - TypeStructField *struct_field = val->type->data.structure.fields[field_i]; - if (struct_field->is_comptime) - continue; - ZigValue *field_val = val->data.x_struct.fields[field_i]; - field_val->special = ConstValSpecialStatic; - field_val->type = struct_field->type_entry; - if (struct_field->gen_index == SIZE_MAX) - continue; - size_t offset = struct_field->offset; - uint8_t *new_buf = buf + offset; - if ((err = buf_read_value_bytes(ira, codegen, source_node, new_buf, field_val))) - return err; - } - return ErrorNone; - } - case ContainerLayoutPacked: { - size_t src_field_count = val->type->data.structure.src_field_count; - val->data.x_struct.fields = alloc_const_vals_ptrs(codegen, src_field_count); - size_t gen_field_count = val->type->data.structure.gen_field_count; - size_t gen_i = 0; - size_t src_i = 0; - size_t offset = 0; - bool is_big_endian = codegen->is_big_endian; - uint8_t child_buf_prealloc[16]; - size_t child_buf_len = 16; - uint8_t *child_buf = child_buf_prealloc; - while (gen_i < gen_field_count) { - size_t big_int_byte_count = val->type->data.structure.host_int_bytes[gen_i]; - if (big_int_byte_count > child_buf_len) { - child_buf = heap::c_allocator.allocate_nonzero(big_int_byte_count); - child_buf_len = big_int_byte_count; - } - BigInt big_int; - bigint_read_twos_complement(&big_int, buf + offset, big_int_byte_count * 8, is_big_endian, false); - uint64_t bit_offset = 0; - while (src_i < src_field_count) { - TypeStructField *field = val->type->data.structure.fields[src_i]; - if (field->is_comptime) { - src_i += 1; - continue; - } - src_assert(field->gen_index != SIZE_MAX, source_node); - if (field->gen_index != gen_i) - break; - ZigValue *field_val = val->data.x_struct.fields[src_i]; - field_val->special = ConstValSpecialStatic; - field_val->type = field->type_entry; - uint32_t packed_bits_size = type_size_bits(codegen, field->type_entry); - - BigInt child_val; - if (is_big_endian) { - BigInt packed_bits_size_bi; - bigint_init_unsigned(&packed_bits_size_bi, big_int_byte_count * 8 - packed_bits_size - bit_offset); - BigInt tmp; - bigint_shr(&tmp, &big_int, &packed_bits_size_bi); - bigint_truncate(&child_val, &tmp, packed_bits_size, false); - } else { - BigInt packed_bits_size_bi; - bigint_init_unsigned(&packed_bits_size_bi, packed_bits_size); - bigint_truncate(&child_val, &big_int, packed_bits_size, false); - BigInt tmp; - bigint_shr(&tmp, &big_int, &packed_bits_size_bi); - big_int = tmp; - } - - bigint_write_twos_complement(&child_val, child_buf, packed_bits_size, is_big_endian); - if ((err = buf_read_value_bytes(ira, codegen, source_node, child_buf, field_val))) { - return err; - } - - bit_offset += packed_bits_size; - src_i += 1; - } - offset += big_int_byte_count; - gen_i += 1; - } - return ErrorNone; - } - } - zig_unreachable(); - case ZigTypeIdOptional: - zig_panic("TODO buf_read_value_bytes maybe type"); - case ZigTypeIdErrorUnion: - zig_panic("TODO buf_read_value_bytes error union"); - case ZigTypeIdErrorSet: - zig_panic("TODO buf_read_value_bytes pure error type"); - case ZigTypeIdFn: - zig_panic("TODO buf_read_value_bytes fn type"); - case ZigTypeIdUnion: - zig_panic("TODO buf_read_value_bytes union type"); - case ZigTypeIdFnFrame: - zig_panic("TODO buf_read_value_bytes async fn frame type"); - case ZigTypeIdAnyFrame: - zig_panic("TODO buf_read_value_bytes anyframe type"); - } - zig_unreachable(); -} - -static Stage1AirInst *ir_analyze_bit_cast(IrAnalyze *ira, Scope *scope, AstNode *source_node, Stage1AirInst *value, - ZigType *dest_type) -{ - Error err; - - ZigType *src_type = value->value->type; - src_assert(type_can_bit_cast(src_type), source_node); - src_assert(type_can_bit_cast(dest_type), source_node); - - if (dest_type->id == ZigTypeIdEnum) { - ErrorMsg *msg = ir_add_error_node(ira, source_node, - buf_sprintf("cannot cast a value of type '%s'", buf_ptr(&dest_type->name))); - add_error_note(ira->codegen, msg, source_node, - buf_sprintf("use @intToEnum for type coercion")); - return ira->codegen->invalid_inst_gen; - } - - if ((err = type_resolve(ira->codegen, dest_type, ResolveStatusSizeKnown))) - return ira->codegen->invalid_inst_gen; - - if ((err = type_resolve(ira->codegen, src_type, ResolveStatusSizeKnown))) - return ira->codegen->invalid_inst_gen; - - const bool src_is_ptr = handle_is_ptr(ira->codegen, src_type); - const bool dest_is_ptr = handle_is_ptr(ira->codegen, dest_type); - - const uint64_t dest_size_bytes = type_size(ira->codegen, dest_type); - const uint64_t src_size_bytes = type_size(ira->codegen, src_type); - if (dest_size_bytes != src_size_bytes) { - ir_add_error_node(ira, source_node, - buf_sprintf("destination type '%s' has size %" ZIG_PRI_u64 " but source type '%s' has size %" ZIG_PRI_u64, - buf_ptr(&dest_type->name), dest_size_bytes, - buf_ptr(&src_type->name), src_size_bytes)); - return ira->codegen->invalid_inst_gen; - } - - const uint64_t dest_size_bits = type_size_bits(ira->codegen, dest_type); - const uint64_t src_size_bits = type_size_bits(ira->codegen, src_type); - if (dest_size_bits != src_size_bits) { - ir_add_error_node(ira, source_node, - buf_sprintf("destination type '%s' has %" ZIG_PRI_u64 " bits but source type '%s' has %" ZIG_PRI_u64 " bits", - buf_ptr(&dest_type->name), dest_size_bits, - buf_ptr(&src_type->name), src_size_bits)); - return ira->codegen->invalid_inst_gen; - } - - if (instr_is_comptime(value)) { - ZigValue *val = ir_resolve_const(ira, value, UndefBad); - if (!val) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *result = ir_const(ira, scope, source_node, dest_type); - uint8_t *buf = heap::c_allocator.allocate_nonzero(src_size_bytes); - buf_write_value_bytes(ira->codegen, buf, val); - if ((err = buf_read_value_bytes(ira, ira->codegen, source_node, buf, result->value))) - return ira->codegen->invalid_inst_gen; - heap::c_allocator.deallocate(buf, src_size_bytes); - return result; - } - - if (dest_is_ptr && !src_is_ptr) { - // Spill the scalar into a local memory location and take its address - value = ir_get_ref(ira, scope, source_node, value, false, false); - } - - return ir_build_bit_cast_gen(ira, scope, source_node, value, dest_type); -} - -static Stage1AirInst *ir_analyze_int_to_ptr(IrAnalyze *ira, Scope *scope, AstNode *source_node, Stage1AirInst *target, - ZigType *ptr_type) -{ - Error err; - - src_assert(get_src_ptr_type(ptr_type) != nullptr, source_node); - src_assert(type_has_bits(ira->codegen, ptr_type), source_node); - - Stage1AirInst *casted_int = ir_implicit_cast(ira, target, ira->codegen->builtin_types.entry_usize); - if (type_is_invalid(casted_int->value->type)) - return ira->codegen->invalid_inst_gen; - - if (instr_is_comptime(casted_int)) { - ZigValue *val = ir_resolve_const(ira, casted_int, UndefBad); - if (!val) - return ira->codegen->invalid_inst_gen; - - uint64_t addr = bigint_as_u64(&val->data.x_bigint); - if (!ptr_allows_addr_zero(ptr_type) && addr == 0) { - ir_add_error_node(ira, source_node, - buf_sprintf("pointer type '%s' does not allow address zero", buf_ptr(&ptr_type->name))); - return ira->codegen->invalid_inst_gen; - } - - uint32_t align_bytes; - if ((err = resolve_ptr_align(ira, ptr_type, &align_bytes))) - return ira->codegen->invalid_inst_gen; - - if (addr != 0 && addr % align_bytes != 0) { - ir_add_error_node(ira, source_node, - buf_sprintf("pointer type '%s' requires aligned address", - buf_ptr(&ptr_type->name))); - return ira->codegen->invalid_inst_gen; - } - - Stage1AirInst *result = ir_const(ira, scope, source_node, ptr_type); - if (ptr_type->id == ZigTypeIdOptional && addr == 0) { - result->value->data.x_ptr.special = ConstPtrSpecialNull; - result->value->data.x_ptr.mut = ConstPtrMutComptimeConst; - } else { - result->value->data.x_ptr.special = ConstPtrSpecialHardCodedAddr; - result->value->data.x_ptr.mut = ConstPtrMutRuntimeVar; - result->value->data.x_ptr.data.hard_coded_addr.addr = addr; - } - - return result; - } - - return ir_build_int_to_ptr_gen(ira, scope, source_node, casted_int, ptr_type); -} - -static Stage1AirInst *ir_analyze_instruction_int_to_ptr(IrAnalyze *ira, Stage1ZirInstIntToPtr *instruction) { - Error err; - Stage1AirInst *dest_type_value = instruction->dest_type->child; - ZigType *dest_type = ir_resolve_type(ira, dest_type_value); - if (type_is_invalid(dest_type)) - return ira->codegen->invalid_inst_gen; - - // We explicitly check for the size, so we can use get_src_ptr_type - if (get_src_ptr_type(dest_type) == nullptr) { - ir_add_error(ira, dest_type_value, buf_sprintf("expected pointer, found '%s'", buf_ptr(&dest_type->name))); - return ira->codegen->invalid_inst_gen; - } - - bool has_bits; - if ((err = type_has_bits2(ira->codegen, dest_type, &has_bits))) - return ira->codegen->invalid_inst_gen; - - if (!has_bits) { - ir_add_error(ira, dest_type_value, - buf_sprintf("type '%s' has 0 bits and cannot store information", buf_ptr(&dest_type->name))); - return ira->codegen->invalid_inst_gen; - } - - Stage1AirInst *target = instruction->target->child; - if (type_is_invalid(target->value->type)) - return ira->codegen->invalid_inst_gen; - - return ir_analyze_int_to_ptr(ira, instruction->base.scope, instruction->base.source_node, target, dest_type); -} - -static Stage1AirInst *ir_analyze_instruction_decl_ref(IrAnalyze *ira, Stage1ZirInstDeclRef *instruction) { - Stage1AirInst *ref_instruction = ir_analyze_decl_ref(ira, instruction->base.scope, instruction->base.source_node, instruction->tld); - if (type_is_invalid(ref_instruction->value->type)) { - return ira->codegen->invalid_inst_gen; - } - - if (instruction->lval == LValPtr || instruction->lval == LValAssign) { - return ref_instruction; - } else { - return ir_get_deref(ira, instruction->base.scope, instruction->base.source_node, ref_instruction, nullptr); - } -} - -static Stage1AirInst *ir_analyze_instruction_ptr_to_int(IrAnalyze *ira, Stage1ZirInstPtrToInt *instruction) { - Error err; - Stage1AirInst *target = instruction->target->child; - if (type_is_invalid(target->value->type)) - return ira->codegen->invalid_inst_gen; - - ZigType *usize = ira->codegen->builtin_types.entry_usize; - - ZigType *src_ptr_type = get_src_ptr_type(target->value->type); - if (src_ptr_type == nullptr) { - ir_add_error(ira, target, - buf_sprintf("expected pointer, found '%s'", buf_ptr(&target->value->type->name))); - return ira->codegen->invalid_inst_gen; - } - - bool has_bits; - if ((err = type_has_bits2(ira->codegen, src_ptr_type, &has_bits))) - return ira->codegen->invalid_inst_gen; - - if (!has_bits) { - ir_add_error(ira, target, - buf_sprintf("pointer to size 0 type has no address")); - return ira->codegen->invalid_inst_gen; - } - - if (instr_is_comptime(target)) { - ZigValue *val = ir_resolve_const(ira, target, UndefBad); - if (!val) - return ira->codegen->invalid_inst_gen; - - // Since we've already run this type trough get_src_ptr_type it is - // safe to access the x_ptr fields - if (val->data.x_ptr.special == ConstPtrSpecialHardCodedAddr) { - Stage1AirInst *result = ir_const(ira, instruction->base.scope, instruction->base.source_node, usize); - bigint_init_unsigned(&result->value->data.x_bigint, val->data.x_ptr.data.hard_coded_addr.addr); - result->value->type = usize; - return result; - } else if (val->data.x_ptr.special == ConstPtrSpecialNull) { - Stage1AirInst *result = ir_const(ira, instruction->base.scope, instruction->base.source_node, usize); - bigint_init_unsigned(&result->value->data.x_bigint, 0); - result->value->type = usize; - return result; - } - } - - return ir_build_ptr_to_int_gen(ira, instruction->base.scope, instruction->base.source_node, target); -} - -static Stage1AirInst *ir_analyze_instruction_ptr_type_simple(IrAnalyze *ira, - Stage1ZirInstPtrTypeSimple *instruction, bool is_const) -{ - Stage1AirInst *result = ir_const(ira, instruction->base.scope, instruction->base.source_node, ira->codegen->builtin_types.entry_type); - result->value->special = ConstValSpecialLazy; - - LazyValuePtrTypeSimple *lazy_ptr_type = heap::c_allocator.create(); - lazy_ptr_type->ira = ira; ira_ref(ira); - result->value->data.x_lazy = &lazy_ptr_type->base; - lazy_ptr_type->base.id = is_const ? LazyValueIdPtrTypeSimpleConst : LazyValueIdPtrTypeSimple; - - lazy_ptr_type->elem_type = instruction->child_type->child; - if (ir_resolve_type_lazy(ira, lazy_ptr_type->elem_type) == nullptr) - return ira->codegen->invalid_inst_gen; - - return result; -} - -static Stage1AirInst *ir_analyze_instruction_ptr_type(IrAnalyze *ira, Stage1ZirInstPtrType *instruction) { - Stage1AirInst *result = ir_const(ira, instruction->base.scope, instruction->base.source_node, ira->codegen->builtin_types.entry_type); - result->value->special = ConstValSpecialLazy; - - LazyValuePtrType *lazy_ptr_type = heap::c_allocator.create(); - lazy_ptr_type->ira = ira; ira_ref(ira); - result->value->data.x_lazy = &lazy_ptr_type->base; - lazy_ptr_type->base.id = LazyValueIdPtrType; - - if (instruction->sentinel != nullptr) { - if (instruction->ptr_len != PtrLenUnknown) { - ir_add_error_node(ira, instruction->base.source_node, - buf_sprintf("sentinels are only allowed on unknown-length pointers")); - return ira->codegen->invalid_inst_gen; - } - - lazy_ptr_type->sentinel = instruction->sentinel->child; - if (ir_resolve_const(ira, lazy_ptr_type->sentinel, LazyOk) == nullptr) - return ira->codegen->invalid_inst_gen; - } - - lazy_ptr_type->elem_type = instruction->child_type->child; - if (ir_resolve_type_lazy(ira, lazy_ptr_type->elem_type) == nullptr) - return ira->codegen->invalid_inst_gen; - - if (instruction->align_value != nullptr) { - lazy_ptr_type->align_inst = instruction->align_value->child; - if (ir_resolve_const(ira, lazy_ptr_type->align_inst, LazyOk) == nullptr) - return ira->codegen->invalid_inst_gen; - } - - lazy_ptr_type->ptr_len = instruction->ptr_len; - lazy_ptr_type->is_const = instruction->is_const; - lazy_ptr_type->is_volatile = instruction->is_volatile; - lazy_ptr_type->is_allowzero = instruction->is_allow_zero; - lazy_ptr_type->bit_offset_in_host = instruction->bit_offset_start; - lazy_ptr_type->host_int_bytes = instruction->host_int_bytes; - - return result; -} - -static Stage1AirInst *ir_analyze_instruction_align_cast(IrAnalyze *ira, Stage1ZirInstAlignCast *instruction) { - Stage1AirInst *target = instruction->target->child; - if (type_is_invalid(target->value->type)) - return ira->codegen->invalid_inst_gen; - - ZigType *elem_type = nullptr; - if (is_slice(target->value->type)) { - ZigType *slice_ptr_type = target->value->type->data.structure.fields[slice_ptr_index]->type_entry; - elem_type = slice_ptr_type->data.pointer.child_type; - } else if (target->value->type->id == ZigTypeIdPointer) { - elem_type = target->value->type->data.pointer.child_type; - } - - uint32_t align_bytes; - Stage1AirInst *align_bytes_inst = instruction->align_bytes->child; - if (!ir_resolve_align(ira, align_bytes_inst, elem_type, &align_bytes)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *result = ir_align_cast(ira, target, align_bytes, true); - if (type_is_invalid(result->value->type)) - return ira->codegen->invalid_inst_gen; - - return result; -} - -static bool ir_resolve_addrspace(IrAnalyze *ira, Stage1AirInst *value, AddressSpace *out) { - if (type_is_invalid(value->value->type)) - return false; - - ZigType *addrspace_type = get_builtin_type(ira->codegen, "AddressSpace"); - - Stage1AirInst *casted_value = ir_implicit_cast(ira, value, addrspace_type); - if (type_is_invalid(casted_value->value->type)) - return false; - - ZigValue *const_val = ir_resolve_const(ira, casted_value, UndefBad); - if (!const_val) - return false; - - *out = (AddressSpace)bigint_as_u32(&const_val->data.x_enum_tag); - return true; -} - -static Stage1AirInst *ir_analyze_instruction_addrspace_cast(IrAnalyze *ira, Stage1ZirInstAddrSpaceCast *instruction) { - Stage1AirInst *ptr_inst = instruction->ptr->child; - ZigType *ptr_type = ptr_inst->value->type; - if (type_is_invalid(ptr_type)) - return ira->codegen->invalid_inst_gen; - - AddressSpace addrspace; - if (!ir_resolve_addrspace(ira, instruction->addrspace->child, &addrspace)) - return ira->codegen->invalid_inst_gen; - - if (addrspace != AddressSpaceGeneric) { - ir_add_error_node(ira, instruction->addrspace->source_node, buf_sprintf( - "address space '%s' not available in stage 1 compiler, must be .generic", - address_space_name(addrspace))); - return ira->codegen->invalid_inst_gen; - } - - if (is_slice(ptr_type) || get_src_ptr_type(ptr_type) != nullptr) { - ir_add_error_node(ira, instruction->ptr->source_node, - buf_sprintf("expected pointer or slice, found '%s'", buf_ptr(&ptr_type->name))); - return ira->codegen->invalid_inst_gen; - } - - return ptr_inst; -} - -static Stage1AirInst *ir_analyze_instruction_set_align_stack(IrAnalyze *ira, Stage1ZirInstSetAlignStack *instruction) { - uint32_t align_bytes; - Stage1AirInst *align_bytes_inst = instruction->align_bytes->child; - if (!ir_resolve_align(ira, align_bytes_inst, nullptr, &align_bytes)) - return ira->codegen->invalid_inst_gen; - - if (align_bytes > 256) { - ir_add_error_node(ira, instruction->base.source_node, buf_sprintf("attempt to @setAlignStack(%" PRIu32 "); maximum is 256", align_bytes)); - return ira->codegen->invalid_inst_gen; - } - - ZigFn *fn_entry = ira->fn; - if (fn_entry == nullptr) { - ir_add_error_node(ira, instruction->base.source_node, buf_sprintf("@setAlignStack outside function")); - return ira->codegen->invalid_inst_gen; - } - if (fn_entry->type_entry->data.fn.fn_type_id.cc == CallingConventionNaked) { - ir_add_error_node(ira, instruction->base.source_node, buf_sprintf("@setAlignStack in naked function")); - return ira->codegen->invalid_inst_gen; - } - - if (fn_entry->type_entry->data.fn.fn_type_id.cc == CallingConventionInline) { - ir_add_error_node(ira, instruction->base.source_node, buf_sprintf("@setAlignStack in inline function")); - return ira->codegen->invalid_inst_gen; - } - - if (fn_entry->set_alignstack_node != nullptr) { - ErrorMsg *msg = ir_add_error_node(ira, instruction->base.source_node, - buf_sprintf("alignstack set twice")); - add_error_note(ira->codegen, msg, fn_entry->set_alignstack_node, buf_sprintf("first set here")); - return ira->codegen->invalid_inst_gen; - } - - fn_entry->set_alignstack_node = instruction->base.source_node; - fn_entry->alignstack_value = align_bytes; - - return ir_const_void(ira, instruction->base.scope, instruction->base.source_node); -} - -static Stage1AirInst *ir_analyze_instruction_arg_type(IrAnalyze *ira, Stage1ZirInstArgType *instruction, - bool allow_var) -{ - Stage1AirInst *fn_type_inst = instruction->fn_type->child; - ZigType *fn_type = ir_resolve_type(ira, fn_type_inst); - if (type_is_invalid(fn_type)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *arg_index_inst = instruction->arg_index->child; - uint64_t arg_index; - if (!ir_resolve_usize(ira, arg_index_inst, &arg_index)) - return ira->codegen->invalid_inst_gen; - - if (fn_type->id == ZigTypeIdBoundFn) { - fn_type = fn_type->data.bound_fn.fn_type; - arg_index += 1; - } - if (fn_type->id != ZigTypeIdFn) { - ir_add_error(ira, fn_type_inst, buf_sprintf("expected function, found '%s'", buf_ptr(&fn_type->name))); - return ira->codegen->invalid_inst_gen; - } - - FnTypeId *fn_type_id = &fn_type->data.fn.fn_type_id; - if (arg_index >= fn_type_id->param_count) { - if (allow_var) { - // TODO remove this with var args - return ir_const_type(ira, instruction->base.scope, instruction->base.source_node, ira->codegen->builtin_types.entry_anytype); - } - ir_add_error(ira, arg_index_inst, - buf_sprintf("arg index %" ZIG_PRI_u64 " out of bounds; '%s' has %" ZIG_PRI_usize " argument(s)", - arg_index, buf_ptr(&fn_type->name), fn_type_id->param_count)); - return ira->codegen->invalid_inst_gen; - } - - ZigType *result_type = fn_type_id->param_info[arg_index].type; - if (result_type == nullptr) { - // Args are only unresolved if our function is generic. - src_assert(fn_type->data.fn.is_generic, instruction->base.source_node); - - if (allow_var) { - return ir_const_type(ira, instruction->base.scope, instruction->base.source_node, ira->codegen->builtin_types.entry_anytype); - } else { - ir_add_error(ira, arg_index_inst, - buf_sprintf("@ArgType could not resolve the type of arg %" ZIG_PRI_u64 " because '%s' is generic", - arg_index, buf_ptr(&fn_type->name))); - return ira->codegen->invalid_inst_gen; - } - } - return ir_const_type(ira, instruction->base.scope, instruction->base.source_node, result_type); -} - -static ZigType *ir_resolve_atomic_operand_type(IrAnalyze *ira, Stage1AirInst *op) { - ZigType *operand_type = ir_resolve_type(ira, op); - if (type_is_invalid(operand_type)) - return ira->codegen->builtin_types.entry_invalid; - - if (operand_type->id == ZigTypeIdInt || operand_type->id == ZigTypeIdEnum) { - ZigType *int_type; - if (operand_type->id == ZigTypeIdEnum) { - int_type = operand_type->data.enumeration.tag_int_type; - } else { - int_type = operand_type; - } - auto bit_count = int_type->data.integral.bit_count; - uint32_t max_atomic_bits = target_arch_largest_atomic_bits(ira->codegen->zig_target->arch); - - if (bit_count > max_atomic_bits) { - ir_add_error(ira, op, - buf_sprintf("expected %" PRIu32 "-bit integer type or smaller, found %" PRIu32 "-bit integer type", - max_atomic_bits, bit_count)); - return ira->codegen->builtin_types.entry_invalid; - } - } else if (operand_type->id == ZigTypeIdFloat) { - uint32_t max_atomic_bits = target_arch_largest_atomic_bits(ira->codegen->zig_target->arch); - if (operand_type->data.floating.bit_count > max_atomic_bits) { - ir_add_error(ira, op, - buf_sprintf("expected %" PRIu32 "-bit float or smaller, found %" PRIu32 "-bit float", - max_atomic_bits, (uint32_t) operand_type->data.floating.bit_count)); - return ira->codegen->builtin_types.entry_invalid; - } - } else if (operand_type->id == ZigTypeIdBool) { - // will be treated as u8 - } else { - Error err; - ZigType *operand_ptr_type; - if ((err = get_codegen_ptr_type(ira->codegen, operand_type, &operand_ptr_type))) - return ira->codegen->builtin_types.entry_invalid; - if (operand_ptr_type == nullptr) { - ir_add_error(ira, op, - buf_sprintf("expected bool, integer, float, enum or pointer type, found '%s'", - buf_ptr(&operand_type->name))); - return ira->codegen->builtin_types.entry_invalid; - } - } - - return operand_type; -} - -static Stage1AirInst *ir_analyze_instruction_atomic_rmw(IrAnalyze *ira, Stage1ZirInstAtomicRmw *instruction) { - ZigType *operand_type = ir_resolve_atomic_operand_type(ira, instruction->operand_type->child); - if (type_is_invalid(operand_type)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *ptr_inst = instruction->ptr->child; - if (type_is_invalid(ptr_inst->value->type)) - return ira->codegen->invalid_inst_gen; - - // TODO let this be volatile - ZigType *ptr_type = get_pointer_to_type(ira->codegen, operand_type, false); - Stage1AirInst *casted_ptr = ir_implicit_cast(ira, ptr_inst, ptr_type); - if (type_is_invalid(casted_ptr->value->type)) - return ira->codegen->invalid_inst_gen; - - AtomicRmwOp op; - if (!ir_resolve_atomic_rmw_op(ira, instruction->op->child, &op)) { - return ira->codegen->invalid_inst_gen; - } - - if (operand_type->id == ZigTypeIdEnum && op != AtomicRmwOp_xchg) { - ir_add_error_node(ira, instruction->op->source_node, - buf_sprintf("@atomicRmw with enum only allowed with .Xchg")); - return ira->codegen->invalid_inst_gen; - } else if (operand_type->id == ZigTypeIdBool && op != AtomicRmwOp_xchg) { - ir_add_error_node(ira, instruction->op->source_node, - buf_sprintf("@atomicRmw with bool only allowed with .Xchg")); - return ira->codegen->invalid_inst_gen; - } else if (operand_type->id == ZigTypeIdFloat && op > AtomicRmwOp_sub) { - ir_add_error_node(ira, instruction->op->source_node, - buf_sprintf("@atomicRmw with float only allowed with .Xchg, .Add and .Sub")); - return ira->codegen->invalid_inst_gen; - } - - Stage1AirInst *operand = instruction->operand->child; - if (type_is_invalid(operand->value->type)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *casted_operand = ir_implicit_cast(ira, operand, operand_type); - if (type_is_invalid(casted_operand->value->type)) - return ira->codegen->invalid_inst_gen; - - AtomicOrder ordering; - if (!ir_resolve_atomic_order(ira, instruction->ordering->child, &ordering)) - return ira->codegen->invalid_inst_gen; - if (ordering == AtomicOrderUnordered) { - ir_add_error_node(ira, instruction->ordering->source_node, - buf_sprintf("@atomicRmw atomic ordering must not be Unordered")); - return ira->codegen->invalid_inst_gen; - } - - // special case zero bit types - switch (type_has_one_possible_value(ira->codegen, operand_type)) { - case OnePossibleValueInvalid: - return ira->codegen->invalid_inst_gen; - case OnePossibleValueYes: - return ir_const_move(ira, instruction->base.scope, instruction->base.source_node, get_the_one_possible_value(ira->codegen, operand_type)); - case OnePossibleValueNo: - break; - } - - Scope *scope = instruction->base.scope; - AstNode *source_node = instruction->base.source_node; - if (instr_is_comptime(casted_operand) && instr_is_comptime(casted_ptr) && casted_ptr->value->data.x_ptr.mut == ConstPtrMutComptimeVar) { - ZigValue *ptr_val = ir_resolve_const(ira, casted_ptr, UndefBad); - if (ptr_val == nullptr) - return ira->codegen->invalid_inst_gen; - - ZigValue *op1_val = const_ptr_pointee(ira, ira->codegen, ptr_val, instruction->base.source_node); - if (op1_val == nullptr) - return ira->codegen->invalid_inst_gen; - - ZigValue *op2_val = ir_resolve_const(ira, casted_operand, UndefBad); - if (op2_val == nullptr) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *result = ir_const(ira, scope, source_node, operand_type); - copy_const_val(ira->codegen, result->value, op1_val); - if (op == AtomicRmwOp_xchg) { - copy_const_val(ira->codegen, op1_val, op2_val); - return result; - } - - if (operand_type->id == ZigTypeIdPointer || operand_type->id == ZigTypeIdOptional) { - ir_add_error_node(ira, instruction->ordering->source_node, - buf_sprintf("TODO comptime @atomicRmw with pointers other than .Xchg")); - return ira->codegen->invalid_inst_gen; - } - - ErrorMsg *msg; - if (op == AtomicRmwOp_min || op == AtomicRmwOp_max) { - IrBinOp bin_op; - if (op == AtomicRmwOp_min) - // store op2 if op2 < op1 - bin_op = IrBinOpCmpGreaterThan; - else - // store op2 if op2 > op1 - bin_op = IrBinOpCmpLessThan; - - Stage1AirInst *dummy_value = ir_const(ira, scope, source_node, operand_type); - msg = ir_eval_bin_op_cmp_scalar(ira, scope, source_node, op1_val, bin_op, op2_val, dummy_value->value); - if (msg != nullptr) { - return ira->codegen->invalid_inst_gen; - } - if (dummy_value->value->data.x_bool) - copy_const_val(ira->codegen, op1_val, op2_val); - } else { - IrBinOp bin_op; - switch (op) { - case AtomicRmwOp_xchg: - case AtomicRmwOp_max: - case AtomicRmwOp_min: - zig_unreachable(); - case AtomicRmwOp_add: - if (operand_type->id == ZigTypeIdFloat) - bin_op = IrBinOpAdd; - else - bin_op = IrBinOpAddWrap; - break; - case AtomicRmwOp_sub: - if (operand_type->id == ZigTypeIdFloat) - bin_op = IrBinOpSub; - else - bin_op = IrBinOpSubWrap; - break; - case AtomicRmwOp_and: - case AtomicRmwOp_nand: - bin_op = IrBinOpBinAnd; - break; - case AtomicRmwOp_or: - bin_op = IrBinOpBinOr; - break; - case AtomicRmwOp_xor: - bin_op = IrBinOpBinXor; - break; - } - msg = ir_eval_math_op_scalar(ira, scope, source_node, operand_type, op1_val, bin_op, op2_val, op1_val); - if (msg != nullptr) { - return ira->codegen->invalid_inst_gen; - } - if (op == AtomicRmwOp_nand) { - bigint_not(&op1_val->data.x_bigint, &op1_val->data.x_bigint, - operand_type->data.integral.bit_count, operand_type->data.integral.is_signed); - } - } - return result; - } - - return ir_build_atomic_rmw_gen(ira, scope, source_node, casted_ptr, casted_operand, op, - ordering, operand_type); -} - -static Stage1AirInst *ir_analyze_instruction_atomic_load(IrAnalyze *ira, Stage1ZirInstAtomicLoad *instruction) { - ZigType *operand_type = ir_resolve_atomic_operand_type(ira, instruction->operand_type->child); - if (type_is_invalid(operand_type)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *ptr_inst = instruction->ptr->child; - if (type_is_invalid(ptr_inst->value->type)) - return ira->codegen->invalid_inst_gen; - - ZigType *ptr_type = get_pointer_to_type(ira->codegen, operand_type, true); - Stage1AirInst *casted_ptr = ir_implicit_cast(ira, ptr_inst, ptr_type); - if (type_is_invalid(casted_ptr->value->type)) - return ira->codegen->invalid_inst_gen; - - AtomicOrder ordering; - if (!ir_resolve_atomic_order(ira, instruction->ordering->child, &ordering)) - return ira->codegen->invalid_inst_gen; - - if (ordering == AtomicOrderRelease || ordering == AtomicOrderAcqRel) { - src_assert(instruction->ordering != nullptr, instruction->base.source_node); - ir_add_error_node(ira, instruction->ordering->source_node, - buf_sprintf("@atomicLoad atomic ordering must not be Release or AcqRel")); - return ira->codegen->invalid_inst_gen; - } - - if (instr_is_comptime(casted_ptr)) { - Stage1AirInst *result = ir_get_deref(ira, instruction->base.scope, - instruction->base.source_node, casted_ptr, nullptr); - src_assert(result->value->type != nullptr, instruction->base.source_node); - return result; - } - - return ir_build_atomic_load_gen(ira, instruction->base.scope, instruction->base.source_node, casted_ptr, ordering, operand_type); -} - -static Stage1AirInst *ir_analyze_instruction_atomic_store(IrAnalyze *ira, Stage1ZirInstAtomicStore *instruction) { - ZigType *operand_type = ir_resolve_atomic_operand_type(ira, instruction->operand_type->child); - if (type_is_invalid(operand_type)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *ptr_inst = instruction->ptr->child; - if (type_is_invalid(ptr_inst->value->type)) - return ira->codegen->invalid_inst_gen; - - ZigType *ptr_type = get_pointer_to_type(ira->codegen, operand_type, false); - Stage1AirInst *casted_ptr = ir_implicit_cast(ira, ptr_inst, ptr_type); - if (type_is_invalid(casted_ptr->value->type)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *value = instruction->value->child; - if (type_is_invalid(value->value->type)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *casted_value = ir_implicit_cast(ira, value, operand_type); - if (type_is_invalid(casted_value->value->type)) - return ira->codegen->invalid_inst_gen; - - - AtomicOrder ordering; - if (!ir_resolve_atomic_order(ira, instruction->ordering->child, &ordering)) - return ira->codegen->invalid_inst_gen; - - if (ordering == AtomicOrderAcquire || ordering == AtomicOrderAcqRel) { - src_assert(instruction->ordering != nullptr, instruction->base.source_node); - ir_add_error_node(ira, instruction->ordering->source_node, - buf_sprintf("@atomicStore atomic ordering must not be Acquire or AcqRel")); - return ira->codegen->invalid_inst_gen; - } - - // special case zero bit types - switch (type_has_one_possible_value(ira->codegen, operand_type)) { - case OnePossibleValueInvalid: - return ira->codegen->invalid_inst_gen; - case OnePossibleValueYes: - return ir_const_void(ira, instruction->base.scope, instruction->base.source_node); - case OnePossibleValueNo: - break; - } - - if (instr_is_comptime(casted_value) && instr_is_comptime(casted_ptr)) { - Stage1AirInst *result = ir_analyze_store_ptr(ira, instruction->base.scope, instruction->base.source_node, casted_ptr, value, false); - result->value->type = ira->codegen->builtin_types.entry_void; - return result; - } - - return ir_build_atomic_store_gen(ira, instruction->base.scope, instruction->base.source_node, casted_ptr, casted_value, ordering); -} - -static Stage1AirInst *ir_analyze_instruction_save_err_ret_addr(IrAnalyze *ira, Stage1ZirInstSaveErrRetAddr *instruction) { - return ir_build_save_err_ret_addr_gen(ira, instruction->base.scope, instruction->base.source_node); -} - -static ErrorMsg *ir_eval_float_op(IrAnalyze *ira, Scope *scope, AstNode *source_node, BuiltinFnId fop, ZigType *float_type, - ZigValue *op, ZigValue *out_val) -{ - assert(ira && source_node && float_type && out_val && op); - assert(float_type->id == ZigTypeIdFloat || - float_type->id == ZigTypeIdComptimeFloat); - - unsigned bits; - - switch (float_type->id) { - case ZigTypeIdComptimeFloat: - bits = 128; - break; - case ZigTypeIdFloat: - bits = float_type->data.floating.bit_count; - break; - default: - zig_unreachable(); - } - - switch (bits) { - case 16: { - switch (fop) { - case BuiltinFnIdSqrt: - out_val->data.x_f16 = f16_sqrt(op->data.x_f16); - break; - case BuiltinFnIdSin: - out_val->data.x_f16 = zig_double_to_f16(sin(zig_f16_to_double(op->data.x_f16))); - break; - case BuiltinFnIdCos: - out_val->data.x_f16 = zig_double_to_f16(cos(zig_f16_to_double(op->data.x_f16))); - break; - case BuiltinFnIdTan: - out_val->data.x_f16 = zig_double_to_f16(tan(zig_f16_to_double(op->data.x_f16))); - break; - case BuiltinFnIdExp: - out_val->data.x_f16 = zig_double_to_f16(exp(zig_f16_to_double(op->data.x_f16))); - break; - case BuiltinFnIdExp2: - out_val->data.x_f16 = zig_double_to_f16(exp2(zig_f16_to_double(op->data.x_f16))); - break; - case BuiltinFnIdLog: - out_val->data.x_f16 = zig_double_to_f16(log(zig_f16_to_double(op->data.x_f16))); - break; - case BuiltinFnIdLog10: - out_val->data.x_f16 = zig_double_to_f16(log10(zig_f16_to_double(op->data.x_f16))); - break; - case BuiltinFnIdLog2: - out_val->data.x_f16 = zig_double_to_f16(log2(zig_f16_to_double(op->data.x_f16))); - break; - case BuiltinFnIdFabs: - out_val->data.x_f16 = zig_double_to_f16(fabs(zig_f16_to_double(op->data.x_f16))); - break; - case BuiltinFnIdFloor: - out_val->data.x_f16 = zig_double_to_f16(floor(zig_f16_to_double(op->data.x_f16))); - break; - case BuiltinFnIdCeil: - out_val->data.x_f16 = zig_double_to_f16(ceil(zig_f16_to_double(op->data.x_f16))); - break; - case BuiltinFnIdTrunc: - out_val->data.x_f16 = zig_double_to_f16(trunc(zig_f16_to_double(op->data.x_f16))); - break; - case BuiltinFnIdNearbyInt: - out_val->data.x_f16 = zig_double_to_f16(nearbyint(zig_f16_to_double(op->data.x_f16))); - break; - case BuiltinFnIdRound: - out_val->data.x_f16 = zig_double_to_f16(round(zig_f16_to_double(op->data.x_f16))); - break; - default: - zig_unreachable(); - }; - break; - } - case 32: { - switch (fop) { - case BuiltinFnIdSqrt: - out_val->data.x_f32 = sqrtf(op->data.x_f32); - break; - case BuiltinFnIdSin: - out_val->data.x_f32 = sinf(op->data.x_f32); - break; - case BuiltinFnIdCos: - out_val->data.x_f32 = cosf(op->data.x_f32); - break; - case BuiltinFnIdTan: - out_val->data.x_f32 = tanf(op->data.x_f32); - break; - case BuiltinFnIdExp: - out_val->data.x_f32 = expf(op->data.x_f32); - break; - case BuiltinFnIdExp2: - out_val->data.x_f32 = exp2f(op->data.x_f32); - break; - case BuiltinFnIdLog: - out_val->data.x_f32 = logf(op->data.x_f32); - break; - case BuiltinFnIdLog10: - out_val->data.x_f32 = log10f(op->data.x_f32); - break; - case BuiltinFnIdLog2: - out_val->data.x_f32 = log2f(op->data.x_f32); - break; - case BuiltinFnIdFabs: - out_val->data.x_f32 = fabsf(op->data.x_f32); - break; - case BuiltinFnIdFloor: - out_val->data.x_f32 = floorf(op->data.x_f32); - break; - case BuiltinFnIdCeil: - out_val->data.x_f32 = ceilf(op->data.x_f32); - break; - case BuiltinFnIdTrunc: - out_val->data.x_f32 = truncf(op->data.x_f32); - break; - case BuiltinFnIdNearbyInt: - out_val->data.x_f32 = nearbyintf(op->data.x_f32); - break; - case BuiltinFnIdRound: - out_val->data.x_f32 = roundf(op->data.x_f32); - break; - default: - zig_unreachable(); - }; - break; - } - case 64: { - switch (fop) { - case BuiltinFnIdSqrt: - out_val->data.x_f64 = sqrt(op->data.x_f64); - break; - case BuiltinFnIdSin: - out_val->data.x_f64 = sin(op->data.x_f64); - break; - case BuiltinFnIdCos: - out_val->data.x_f64 = cos(op->data.x_f64); - break; - case BuiltinFnIdTan: - out_val->data.x_f64 = tan(op->data.x_f64); - break; - case BuiltinFnIdExp: - out_val->data.x_f64 = exp(op->data.x_f64); - break; - case BuiltinFnIdExp2: - out_val->data.x_f64 = exp2(op->data.x_f64); - break; - case BuiltinFnIdLog: - out_val->data.x_f64 = log(op->data.x_f64); - break; - case BuiltinFnIdLog10: - out_val->data.x_f64 = log10(op->data.x_f64); - break; - case BuiltinFnIdLog2: - out_val->data.x_f64 = log2(op->data.x_f64); - break; - case BuiltinFnIdFabs: - out_val->data.x_f64 = fabs(op->data.x_f64); - break; - case BuiltinFnIdFloor: - out_val->data.x_f64 = floor(op->data.x_f64); - break; - case BuiltinFnIdCeil: - out_val->data.x_f64 = ceil(op->data.x_f64); - break; - case BuiltinFnIdTrunc: - out_val->data.x_f64 = trunc(op->data.x_f64); - break; - case BuiltinFnIdNearbyInt: - out_val->data.x_f64 = nearbyint(op->data.x_f64); - break; - case BuiltinFnIdRound: - out_val->data.x_f64 = round(op->data.x_f64); - break; - default: - zig_unreachable(); - } - break; - } - case 80: { - extFloat80_t *out = &out_val->data.x_f80; - extFloat80_t *in = &op->data.x_f80; - switch (fop) { - case BuiltinFnIdSqrt: - extF80M_sqrt(in, out); - break; - case BuiltinFnIdFabs: - extF80M_abs(in, out); - break; - case BuiltinFnIdFloor: - extF80M_roundToInt(in, softfloat_round_min, false, out); - break; - case BuiltinFnIdCeil: - extF80M_roundToInt(in, softfloat_round_max, false, out); - break; - case BuiltinFnIdTrunc: - extF80M_trunc(in, out); - break; - case BuiltinFnIdRound: - extF80M_roundToInt(in, softfloat_round_near_maxMag, false, out); - break; - case BuiltinFnIdNearbyInt: - case BuiltinFnIdSin: - case BuiltinFnIdCos: - case BuiltinFnIdTan: - case BuiltinFnIdExp: - case BuiltinFnIdExp2: - case BuiltinFnIdLog: - case BuiltinFnIdLog10: - case BuiltinFnIdLog2: - return ir_add_error_node(ira, source_node, - buf_sprintf("compiler bug: TODO: implement '%s' for type '%s'. See https://github.com/ziglang/zig/issues/4026", - float_un_op_to_name(fop), buf_ptr(&float_type->name))); - default: - zig_unreachable(); - } - break; - } - case 128: { - float128_t *out, *in; - if (float_type->id == ZigTypeIdComptimeFloat) { - out = &out_val->data.x_bigfloat.value; - in = &op->data.x_bigfloat.value; - } else { - out = &out_val->data.x_f128; - in = &op->data.x_f128; - } - switch (fop) { - case BuiltinFnIdSqrt: - f128M_sqrt(in, out); - break; - case BuiltinFnIdFabs: - f128M_abs(in, out); - break; - case BuiltinFnIdFloor: - f128M_roundToInt(in, softfloat_round_min, false, out); - break; - case BuiltinFnIdCeil: - f128M_roundToInt(in, softfloat_round_max, false, out); - break; - case BuiltinFnIdTrunc: - f128M_trunc(in, out); - break; - case BuiltinFnIdRound: - f128M_roundToInt(in, softfloat_round_near_maxMag, false, out); - break; - case BuiltinFnIdNearbyInt: { - float64_t f64_value = f128M_to_f64(in); - double double_value; - memcpy(&double_value, &f64_value, sizeof(double)); - double_value = nearbyint(double_value); - memcpy(&f64_value, &double_value, sizeof(double)); - f64_to_f128M(f64_value, out); - break; - } - case BuiltinFnIdSin: { - float64_t f64_value = f128M_to_f64(in); - double double_value; - memcpy(&double_value, &f64_value, sizeof(double)); - double_value = sin(double_value); - memcpy(&f64_value, &double_value, sizeof(double)); - f64_to_f128M(f64_value, out); - break; - } - case BuiltinFnIdCos: { - float64_t f64_value = f128M_to_f64(in); - double double_value; - memcpy(&double_value, &f64_value, sizeof(double)); - double_value = cos(double_value); - memcpy(&f64_value, &double_value, sizeof(double)); - f64_to_f128M(f64_value, out); - break; - } - case BuiltinFnIdTan: { - float64_t f64_value = f128M_to_f64(in); - double double_value; - memcpy(&double_value, &f64_value, sizeof(double)); - double_value = tan(double_value); - memcpy(&f64_value, &double_value, sizeof(double)); - f64_to_f128M(f64_value, out); - break; - } - case BuiltinFnIdExp: { - float64_t f64_value = f128M_to_f64(in); - double double_value; - memcpy(&double_value, &f64_value, sizeof(double)); - double_value = exp(double_value); - memcpy(&f64_value, &double_value, sizeof(double)); - f64_to_f128M(f64_value, out); - break; - } - case BuiltinFnIdExp2: { - float64_t f64_value = f128M_to_f64(in); - double double_value; - memcpy(&double_value, &f64_value, sizeof(double)); - double_value = exp2(double_value); - memcpy(&f64_value, &double_value, sizeof(double)); - f64_to_f128M(f64_value, out); - break; - } - case BuiltinFnIdLog: { - float64_t f64_value = f128M_to_f64(in); - double double_value; - memcpy(&double_value, &f64_value, sizeof(double)); - double_value = log(double_value); - memcpy(&f64_value, &double_value, sizeof(double)); - f64_to_f128M(f64_value, out); - break; - } - case BuiltinFnIdLog10: { - float64_t f64_value = f128M_to_f64(in); - double double_value; - memcpy(&double_value, &f64_value, sizeof(double)); - double_value = log10(double_value); - memcpy(&f64_value, &double_value, sizeof(double)); - f64_to_f128M(f64_value, out); - break; - } - case BuiltinFnIdLog2: { - float64_t f64_value = f128M_to_f64(in); - double double_value; - memcpy(&double_value, &f64_value, sizeof(double)); - double_value = log2(double_value); - memcpy(&f64_value, &double_value, sizeof(double)); - f64_to_f128M(f64_value, out); - break; - } - default: - zig_unreachable(); - } - break; - } - default: - zig_unreachable(); - } - out_val->special = ConstValSpecialStatic; - return nullptr; -} - -static Stage1AirInst *ir_analyze_instruction_float_op(IrAnalyze *ira, Stage1ZirInstFloatOp *instruction) { - Stage1AirInst *operand = instruction->operand->child; - ZigType *operand_type = operand->value->type; - if (type_is_invalid(operand_type)) - return ira->codegen->invalid_inst_gen; - - // This instruction accepts floats and vectors of floats. - ZigType *scalar_type = (operand_type->id == ZigTypeIdVector) ? - operand_type->data.vector.elem_type : operand_type; - - if (scalar_type->id != ZigTypeIdFloat && scalar_type->id != ZigTypeIdComptimeFloat) { - ir_add_error(ira, operand, - buf_sprintf("expected float type, found '%s'", buf_ptr(&scalar_type->name))); - return ira->codegen->invalid_inst_gen; - } - - if (instr_is_comptime(operand)) { - ZigValue *operand_val = ir_resolve_const(ira, operand, UndefOk); - if (operand_val == nullptr) - return ira->codegen->invalid_inst_gen; - if (operand_val->special == ConstValSpecialUndef) - return ir_const_undef(ira, instruction->base.scope, instruction->base.source_node, operand_type); - - Stage1AirInst *result = ir_const(ira, instruction->base.scope, instruction->base.source_node, operand_type); - ZigValue *out_val = result->value; - - if (operand_type->id == ZigTypeIdVector) { - expand_undef_array(ira->codegen, operand_val); - out_val->special = ConstValSpecialUndef; - expand_undef_array(ira->codegen, out_val); - size_t len = operand_type->data.vector.len; - for (size_t i = 0; i < len; i += 1) { - ZigValue *elem_operand = &operand_val->data.x_array.data.s_none.elements[i]; - ZigValue *float_out_val = &out_val->data.x_array.data.s_none.elements[i]; - src_assert(elem_operand->type == scalar_type, instruction->base.source_node); - src_assert(float_out_val->type == scalar_type, instruction->base.source_node); - ErrorMsg *msg = ir_eval_float_op(ira, instruction->base.scope, instruction->base.source_node, instruction->fn_id, scalar_type, - elem_operand, float_out_val); - if (msg != nullptr) { - add_error_note(ira->codegen, msg, instruction->base.source_node, - buf_sprintf("when computing vector element at index %" ZIG_PRI_usize, i)); - return ira->codegen->invalid_inst_gen; - } - float_out_val->type = scalar_type; - } - out_val->type = operand_type; - out_val->special = ConstValSpecialStatic; - } else { - if (ir_eval_float_op(ira, instruction->base.scope, instruction->base.source_node, instruction->fn_id, scalar_type, - operand_val, out_val) != nullptr) - { - return ira->codegen->invalid_inst_gen; - } - } - return result; - } - - src_assert(scalar_type->id == ZigTypeIdFloat, instruction->base.source_node); - - return ir_build_float_op_gen(ira, instruction->base.scope, instruction->base.source_node, operand, instruction->fn_id, operand_type); -} - -static Stage1AirInst *ir_analyze_instruction_bswap(IrAnalyze *ira, Stage1ZirInstBswap *instruction) { - Error err; - - ZigType *int_type = ir_resolve_int_type(ira, instruction->type->child); - if (type_is_invalid(int_type)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *uncasted_op = instruction->op->child; - if (type_is_invalid(uncasted_op->value->type)) - return ira->codegen->invalid_inst_gen; - - uint32_t vector_len = UINT32_MAX; // means not a vector - if (uncasted_op->value->type->id == ZigTypeIdArray) { - bool can_be_vec_elem; - if ((err = is_valid_vector_elem_type(ira->codegen, uncasted_op->value->type->data.array.child_type, - &can_be_vec_elem))) - { - return ira->codegen->invalid_inst_gen; - } - if (can_be_vec_elem) { - vector_len = uncasted_op->value->type->data.array.len; - } - } else if (uncasted_op->value->type->id == ZigTypeIdVector) { - vector_len = uncasted_op->value->type->data.vector.len; - } - - bool is_vector = (vector_len != UINT32_MAX); - ZigType *op_type = is_vector ? get_vector_type(ira->codegen, vector_len, int_type) : int_type; - - Stage1AirInst *op = ir_implicit_cast(ira, uncasted_op, op_type); - if (type_is_invalid(op->value->type)) - return ira->codegen->invalid_inst_gen; - - if (int_type->data.integral.bit_count == 8 || int_type->data.integral.bit_count == 0) - return op; - - if (int_type->data.integral.bit_count % 8 != 0) { - ir_add_error_node(ira, instruction->op->source_node, - buf_sprintf("@byteSwap integer type '%s' has %" PRIu32 " bits which is not evenly divisible by 8", - buf_ptr(&int_type->name), int_type->data.integral.bit_count)); - return ira->codegen->invalid_inst_gen; - } - - if (instr_is_comptime(op)) { - ZigValue *val = ir_resolve_const(ira, op, UndefOk); - if (val == nullptr) - return ira->codegen->invalid_inst_gen; - if (val->special == ConstValSpecialUndef) - return ir_const_undef(ira, instruction->base.scope, instruction->base.source_node, op_type); - - Stage1AirInst *result = ir_const(ira, instruction->base.scope, instruction->base.source_node, op_type); - const size_t buf_size = int_type->data.integral.bit_count / 8; - uint8_t *buf = heap::c_allocator.allocate_nonzero(buf_size); - if (is_vector) { - expand_undef_array(ira->codegen, val); - result->value->data.x_array.data.s_none.elements = ira->codegen->pass1_arena->allocate(op_type->data.vector.len); - for (unsigned i = 0; i < op_type->data.vector.len; i += 1) { - ZigValue *op_elem_val = &val->data.x_array.data.s_none.elements[i]; - if ((err = ir_resolve_const_val(ira->codegen, ira->new_irb.exec, instruction->base.source_node, - op_elem_val, UndefOk))) - { - return ira->codegen->invalid_inst_gen; - } - ZigValue *result_elem_val = &result->value->data.x_array.data.s_none.elements[i]; - result_elem_val->type = int_type; - result_elem_val->special = op_elem_val->special; - if (op_elem_val->special == ConstValSpecialUndef) - continue; - - bigint_write_twos_complement(&op_elem_val->data.x_bigint, buf, int_type->data.integral.bit_count, true); - bigint_read_twos_complement(&result->value->data.x_array.data.s_none.elements[i].data.x_bigint, - buf, int_type->data.integral.bit_count, false, - int_type->data.integral.is_signed); - } - } else { - bigint_write_twos_complement(&val->data.x_bigint, buf, int_type->data.integral.bit_count, true); - bigint_read_twos_complement(&result->value->data.x_bigint, buf, int_type->data.integral.bit_count, false, - int_type->data.integral.is_signed); - } - heap::c_allocator.deallocate(buf, buf_size); - return result; - } - - return ir_build_bswap_gen(ira, instruction->base.scope, instruction->base.source_node, op_type, op); -} - -static Stage1AirInst *ir_analyze_instruction_bit_reverse(IrAnalyze *ira, Stage1ZirInstBitReverse *instruction) { - ZigType *int_type = ir_resolve_int_type(ira, instruction->type->child); - if (type_is_invalid(int_type)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *op = ir_implicit_cast(ira, instruction->op->child, int_type); - if (type_is_invalid(op->value->type)) - return ira->codegen->invalid_inst_gen; - - if (int_type->data.integral.bit_count == 0) { - Stage1AirInst *result = ir_const(ira, instruction->base.scope, instruction->base.source_node, int_type); - bigint_init_unsigned(&result->value->data.x_bigint, 0); - return result; - } - - if (instr_is_comptime(op)) { - ZigValue *val = ir_resolve_const(ira, op, UndefOk); - if (val == nullptr) - return ira->codegen->invalid_inst_gen; - if (val->special == ConstValSpecialUndef) - return ir_const_undef(ira, instruction->base.scope, instruction->base.source_node, int_type); - - Stage1AirInst *result = ir_const(ira, instruction->base.scope, instruction->base.source_node, int_type); - size_t num_bits = int_type->data.integral.bit_count; - size_t buf_size = (num_bits + 7) / 8; - uint8_t *comptime_buf = heap::c_allocator.allocate_nonzero(buf_size); - uint8_t *result_buf = heap::c_allocator.allocate_nonzero(buf_size); - memset(comptime_buf,0,buf_size); - memset(result_buf,0,buf_size); - - bigint_write_twos_complement(&val->data.x_bigint,comptime_buf,num_bits,ira->codegen->is_big_endian); - - size_t bit_i = 0; - size_t bit_rev_i = num_bits - 1; - for (; bit_i < num_bits; bit_i++, bit_rev_i--) { - if (comptime_buf[bit_i / 8] & (1 << (bit_i % 8))) { - result_buf[bit_rev_i / 8] |= (1 << (bit_rev_i % 8)); - } - } - - bigint_read_twos_complement(&result->value->data.x_bigint, - result_buf, - int_type->data.integral.bit_count, - ira->codegen->is_big_endian, - int_type->data.integral.is_signed); - - heap::c_allocator.deallocate(comptime_buf, buf_size); - heap::c_allocator.deallocate(result_buf, buf_size); - return result; - } - - return ir_build_bit_reverse_gen(ira, instruction->base.scope, instruction->base.source_node, int_type, op); -} - - -static Stage1AirInst *ir_analyze_instruction_enum_to_int(IrAnalyze *ira, Stage1ZirInstEnumToInt *instruction) { - Stage1AirInst *target = instruction->target->child; - if (type_is_invalid(target->value->type)) - return ira->codegen->invalid_inst_gen; - - return ir_analyze_enum_to_int(ira, instruction->base.scope, instruction->base.source_node, target); -} - -static Stage1AirInst *ir_analyze_instruction_int_to_enum(IrAnalyze *ira, Stage1ZirInstIntToEnum *instruction) { - Error err; - Stage1AirInst *dest_type_value = instruction->dest_type->child; - ZigType *dest_type = ir_resolve_type(ira, dest_type_value); - if (type_is_invalid(dest_type)) - return ira->codegen->invalid_inst_gen; - - if (dest_type->id != ZigTypeIdEnum) { - ir_add_error_node(ira, instruction->dest_type->source_node, - buf_sprintf("expected enum, found type '%s'", buf_ptr(&dest_type->name))); - return ira->codegen->invalid_inst_gen; - } - - if ((err = type_resolve(ira->codegen, dest_type, ResolveStatusZeroBitsKnown))) - return ira->codegen->invalid_inst_gen; - - ZigType *tag_type = dest_type->data.enumeration.tag_int_type; - - Stage1AirInst *target = instruction->target->child; - if (type_is_invalid(target->value->type)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *casted_target = ir_analyze_int_cast(ira, instruction->base.scope, - instruction->base.source_node, tag_type, instruction->dest_type->source_node, - target, instruction->target->source_node); - if (type_is_invalid(casted_target->value->type)) - return ira->codegen->invalid_inst_gen; - - return ir_analyze_int_to_enum(ira, instruction->base.scope, instruction->base.source_node, casted_target, dest_type); -} - -static Stage1AirInst *ir_analyze_instruction_check_runtime_scope(IrAnalyze *ira, Stage1ZirInstCheckRuntimeScope *instruction) { - Stage1AirInst *block_comptime_inst = instruction->scope_is_comptime->child; - bool scope_is_comptime; - if (!ir_resolve_bool(ira, block_comptime_inst, &scope_is_comptime)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *is_comptime_inst = instruction->is_comptime->child; - bool is_comptime; - if (!ir_resolve_bool(ira, is_comptime_inst, &is_comptime)) - return ira->codegen->invalid_inst_gen; - - if (!scope_is_comptime && is_comptime) { - ErrorMsg *msg = ir_add_error_node(ira, instruction->base.source_node, - buf_sprintf("comptime control flow inside runtime block")); - add_error_note(ira->codegen, msg, block_comptime_inst->source_node, - buf_sprintf("runtime block created here")); - return ira->codegen->invalid_inst_gen; - } - - return ir_const_void(ira, instruction->base.scope, instruction->base.source_node); -} - -static Stage1AirInst *ir_analyze_instruction_has_decl(IrAnalyze *ira, Stage1ZirInstHasDecl *instruction) { - ZigType *container_type = ir_resolve_type(ira, instruction->container->child); - if (type_is_invalid(container_type)) - return ira->codegen->invalid_inst_gen; - - Buf *name = ir_resolve_str(ira, instruction->name->child); - if (name == nullptr) - return ira->codegen->invalid_inst_gen; - - if (!is_container(container_type)) { - ir_add_error_node(ira, instruction->container->source_node, - buf_sprintf("expected struct, enum, or union; found '%s'", buf_ptr(&container_type->name))); - return ira->codegen->invalid_inst_gen; - } - - ScopeDecls *container_scope = get_container_scope(container_type); - Tld *tld = find_container_decl(ira->codegen, container_scope, name); - if (tld == nullptr) - return ir_const_bool(ira, instruction->base.scope, instruction->base.source_node, false); - - if (tld->visib_mod == VisibModPrivate && tld->import != get_scope_import(instruction->base.scope)) { - return ir_const_bool(ira, instruction->base.scope, instruction->base.source_node, false); - } - - return ir_const_bool(ira, instruction->base.scope, instruction->base.source_node, true); -} - -static void populate_invalid_variable_in_scope(CodeGen *g, Scope *scope, AstNode *node, Buf *var_name) { - ScopeDecls *scope_decls = nullptr; - while (scope != nullptr) { - if (scope->id == ScopeIdDecls) { - scope_decls = reinterpret_cast(scope); - } - scope = scope->parent; - } - TldVar *tld_var = heap::c_allocator.create(); - init_tld(&tld_var->base, TldIdVar, var_name, VisibModPub, node, &scope_decls->base); - tld_var->base.resolution = TldResolutionInvalid; - tld_var->var = add_variable(g, node, &scope_decls->base, var_name, false, - g->invalid_inst_gen->value, &tld_var->base, g->builtin_types.entry_invalid); - scope_decls->decl_table.put(var_name, &tld_var->base); -} - -static Stage1AirInst *ir_analyze_instruction_undeclared_ident(IrAnalyze *ira, Stage1ZirInstUndeclaredIdent *instruction) { - // put a variable of same name with invalid type in global scope - // so that future references to this same name will find a variable with an invalid type - populate_invalid_variable_in_scope(ira->codegen, instruction->base.scope, - instruction->base.source_node, instruction->name); - ir_add_error_node(ira, instruction->base.source_node, - buf_sprintf("use of undeclared identifier '%s'", buf_ptr(instruction->name))); - return ira->codegen->invalid_inst_gen; -} - -static Stage1AirInst *ir_analyze_instruction_end_expr(IrAnalyze *ira, Stage1ZirInstEndExpr *instruction) { - Stage1AirInst *value = instruction->value->child; - if (type_is_invalid(value->value->type)) - return ira->codegen->invalid_inst_gen; - - bool was_written = instruction->result_loc->written; - Stage1AirInst *result_loc = ir_resolve_result(ira, &instruction->base, instruction->result_loc, - value->value->type, value, false, true); - if (result_loc != nullptr) { - if (type_is_invalid(result_loc->value->type)) - return ira->codegen->invalid_inst_gen; - if (result_loc->value->type->id == ZigTypeIdUnreachable) - return result_loc; - - if (!was_written || instruction->result_loc->id == ResultLocIdPeer) { - Stage1AirInst *store_ptr = ir_analyze_store_ptr(ira, instruction->base.scope, instruction->base.source_node, result_loc, value, - instruction->result_loc->allow_write_through_const); - if (type_is_invalid(store_ptr->value->type)) { - if (instruction->result_loc->id == ResultLocIdReturn && - (value->value->type->id == ZigTypeIdErrorUnion || value->value->type->id == ZigTypeIdErrorSet) && - ira->explicit_return_type->id != ZigTypeIdErrorUnion && ira->explicit_return_type->id != ZigTypeIdErrorSet && - // Only add error note if we have a node to attach it to - ira->explicit_return_type_source_node) - { - add_error_note(ira->codegen, ira->new_irb.exec->first_err_trace_msg, - ira->explicit_return_type_source_node, buf_create_from_str("function cannot return an error")); - } - return ira->codegen->invalid_inst_gen; - } - } - - if (result_loc->value->data.x_ptr.mut == ConstPtrMutInfer && - instruction->result_loc->id != ResultLocIdPeer) - { - if (instr_is_comptime(value)) { - result_loc->value->data.x_ptr.mut = ConstPtrMutComptimeConst; - } else { - result_loc->value->special = ConstValSpecialRuntime; - } - } - } - - return ir_const_void(ira, instruction->base.scope, instruction->base.source_node); -} - -static Stage1AirInst *ir_analyze_instruction_implicit_cast(IrAnalyze *ira, Stage1ZirInstImplicitCast *instruction) { - Stage1AirInst *operand = instruction->operand->child; - if (type_is_invalid(operand->value->type)) - return operand; - - ZigType *dest_type = ir_resolve_type(ira, instruction->result_loc_cast->base.source_instruction->child); - if (type_is_invalid(dest_type)) - return ira->codegen->invalid_inst_gen; - return ir_implicit_cast2(ira, instruction->base.scope, instruction->base.source_node, - operand, dest_type); -} - -static Stage1AirInst *ir_analyze_instruction_bit_cast_src(IrAnalyze *ira, Stage1ZirInstBitCast *instruction) { - Stage1AirInst *operand = instruction->operand->child; - if (type_is_invalid(operand->value->type)) - return operand; - - Stage1AirInst *result_loc = ir_resolve_result(ira, &instruction->base, - &instruction->result_loc_bit_cast->base, operand->value->type, operand, false, true); - if (result_loc != nullptr && - (type_is_invalid(result_loc->value->type) || result_loc->value->type->id == ZigTypeIdUnreachable)) - { - return result_loc; - } - - ZigType *dest_type = ir_resolve_type(ira, - instruction->result_loc_bit_cast->base.source_instruction->child); - if (type_is_invalid(dest_type)) - return ira->codegen->invalid_inst_gen; - return ir_analyze_bit_cast(ira, instruction->base.scope, instruction->base.source_node, operand, dest_type); -} - -static Stage1AirInst *ir_analyze_instruction_union_init_named_field(IrAnalyze *ira, - Stage1ZirInstUnionInitNamedField *instruction) -{ - ZigType *union_type = ir_resolve_type(ira, instruction->union_type->child); - if (type_is_invalid(union_type)) - return ira->codegen->invalid_inst_gen; - - if (union_type->id != ZigTypeIdUnion) { - ir_add_error_node(ira, instruction->union_type->source_node, - buf_sprintf("non-union type '%s' passed to @unionInit", buf_ptr(&union_type->name))); - return ira->codegen->invalid_inst_gen; - } - - Buf *field_name = ir_resolve_str(ira, instruction->field_name->child); - if (field_name == nullptr) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *field_result_loc = instruction->field_result_loc->child; - if (type_is_invalid(field_result_loc->value->type)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *result_loc = instruction->result_loc->child; - if (type_is_invalid(result_loc->value->type)) - return ira->codegen->invalid_inst_gen; - - return ir_analyze_union_init(ira, instruction->base.scope, instruction->base.source_node, instruction->base.source_node, - union_type, field_name, field_result_loc, result_loc); -} - -static Stage1AirInst *ir_analyze_instruction_suspend_begin(IrAnalyze *ira, Stage1ZirInstSuspendBegin *instruction) { - return ir_build_suspend_begin_gen(ira, instruction->base.scope, instruction->base.source_node); -} - -static Stage1AirInst *ir_analyze_instruction_suspend_finish(IrAnalyze *ira, Stage1ZirInstSuspendFinish *instruction) { - Stage1AirInst *begin_base = instruction->begin->base.child; - if (type_is_invalid(begin_base->value->type)) - return ira->codegen->invalid_inst_gen; - src_assert(begin_base->id == Stage1AirInstIdSuspendBegin, instruction->base.source_node); - Stage1AirInstSuspendBegin *begin = reinterpret_cast(begin_base); - - ZigFn *fn_entry = ira->fn; - src_assert(fn_entry != nullptr, instruction->base.source_node); - - if (fn_entry->inferred_async_node == nullptr) { - fn_entry->inferred_async_node = instruction->base.source_node; - } - - return ir_build_suspend_finish_gen(ira, instruction->base.scope, instruction->base.source_node, begin); -} - -static Stage1AirInst *analyze_frame_ptr_to_anyframe_T(IrAnalyze *ira, Scope *scope, AstNode *source_node, - Stage1AirInst *frame_ptr, ZigFn **target_fn) -{ - if (type_is_invalid(frame_ptr->value->type)) - return ira->codegen->invalid_inst_gen; - - *target_fn = nullptr; - - ZigType *result_type; - Stage1AirInst *frame; - if (frame_ptr->value->type->id == ZigTypeIdPointer && - frame_ptr->value->type->data.pointer.ptr_len == PtrLenSingle && - frame_ptr->value->type->data.pointer.child_type->id == ZigTypeIdFnFrame) - { - ZigFn *func = frame_ptr->value->type->data.pointer.child_type->data.frame.fn; - result_type = func->type_entry->data.fn.fn_type_id.return_type; - *target_fn = func; - frame = frame_ptr; - } else { - frame = ir_get_deref(ira, scope, source_node, frame_ptr, nullptr); - if (frame->value->type->id == ZigTypeIdPointer && - frame->value->type->data.pointer.ptr_len == PtrLenSingle && - frame->value->type->data.pointer.child_type->id == ZigTypeIdFnFrame) - { - ZigFn *func = frame->value->type->data.pointer.child_type->data.frame.fn; - result_type = func->type_entry->data.fn.fn_type_id.return_type; - *target_fn = func; - } else if (frame->value->type->id != ZigTypeIdAnyFrame || - frame->value->type->data.any_frame.result_type == nullptr) - { - ir_add_error_node(ira, source_node, - buf_sprintf("expected anyframe->T, found '%s'", buf_ptr(&frame->value->type->name))); - return ira->codegen->invalid_inst_gen; - } else { - result_type = frame->value->type->data.any_frame.result_type; - } - } - - ZigType *any_frame_type = get_any_frame_type(ira->codegen, result_type); - Stage1AirInst *casted_frame = ir_implicit_cast(ira, frame, any_frame_type); - if (type_is_invalid(casted_frame->value->type)) - return ira->codegen->invalid_inst_gen; - - return casted_frame; -} - -static Stage1AirInst *ir_analyze_instruction_await(IrAnalyze *ira, Stage1ZirInstAwait *instruction) { - Stage1AirInst *operand = instruction->frame->child; - if (type_is_invalid(operand->value->type)) - return ira->codegen->invalid_inst_gen; - ZigFn *target_fn; - Stage1AirInst *frame = analyze_frame_ptr_to_anyframe_T(ira, instruction->base.scope, instruction->base.source_node, operand, &target_fn); - if (type_is_invalid(frame->value->type)) - return ira->codegen->invalid_inst_gen; - - ZigType *result_type = frame->value->type->data.any_frame.result_type; - - ZigFn *fn_entry = ira->fn; - src_assert(fn_entry != nullptr, instruction->base.source_node); - - // If it's not @Frame(func) then it's definitely a suspend point - if (target_fn == nullptr && !instruction->is_nosuspend) { - if (fn_entry->inferred_async_node == nullptr) { - fn_entry->inferred_async_node = instruction->base.source_node; - } - } - - if (type_can_fail(result_type)) { - fn_entry->calls_or_awaits_errorable_fn = true; - } - - Stage1AirInst *result_loc; - if (type_has_bits(ira->codegen, result_type)) { - result_loc = ir_resolve_result(ira, &instruction->base, instruction->result_loc, - result_type, nullptr, true, true); - if (result_loc != nullptr && - (type_is_invalid(result_loc->value->type) || result_loc->value->type->id == ZigTypeIdUnreachable)) - { - return result_loc; - } - } else { - result_loc = nullptr; - } - - Stage1AirInstAwait *result = ir_build_await_gen(ira, instruction->base.scope, instruction->base.source_node, frame, result_type, result_loc, - instruction->is_nosuspend); - result->target_fn = target_fn; - fn_entry->await_list.append(result); - return ir_finish_anal(ira, &result->base); -} - -static Stage1AirInst *ir_analyze_instruction_resume(IrAnalyze *ira, Stage1ZirInstResume *instruction) { - Stage1AirInst *frame_ptr = instruction->frame->child; - if (type_is_invalid(frame_ptr->value->type)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *frame; - if (frame_ptr->value->type->id == ZigTypeIdPointer && - frame_ptr->value->type->data.pointer.ptr_len == PtrLenSingle && - frame_ptr->value->type->data.pointer.child_type->id == ZigTypeIdFnFrame) - { - frame = frame_ptr; - } else { - frame = ir_get_deref(ira, instruction->base.scope, instruction->base.source_node, - frame_ptr, nullptr); - } - - ZigType *any_frame_type = get_any_frame_type(ira->codegen, nullptr); - Stage1AirInst *casted_frame = ir_implicit_cast2(ira, instruction->frame->scope, - instruction->frame->source_node, frame, any_frame_type); - if (type_is_invalid(casted_frame->value->type)) - return ira->codegen->invalid_inst_gen; - - return ir_build_resume_gen(ira, instruction->base.scope, instruction->base.source_node, casted_frame); -} - -static Stage1AirInst *ir_analyze_instruction_spill_begin(IrAnalyze *ira, Stage1ZirInstSpillBegin *instruction) { - if (ir_should_inline(ira->zir, instruction->base.scope)) - return ir_const_void(ira, instruction->base.scope, instruction->base.source_node); - - Stage1AirInst *operand = instruction->operand->child; - if (type_is_invalid(operand->value->type)) - return ira->codegen->invalid_inst_gen; - - if (!type_has_bits(ira->codegen, operand->value->type)) - return ir_const_void(ira, instruction->base.scope, instruction->base.source_node); - - switch (instruction->spill_id) { - case SpillIdInvalid: - zig_unreachable(); - case SpillIdRetErrCode: - ira->new_irb.exec->need_err_code_spill = true; - break; - } - - return ir_build_spill_begin_gen(ira, instruction->base.scope, instruction->base.source_node, operand, instruction->spill_id); -} - -static Stage1AirInst *ir_analyze_instruction_spill_end(IrAnalyze *ira, Stage1ZirInstSpillEnd *instruction) { - Stage1AirInst *operand = instruction->begin->operand->child; - if (type_is_invalid(operand->value->type)) - return ira->codegen->invalid_inst_gen; - - if (ir_should_inline(ira->zir, instruction->base.scope) || - !type_has_bits(ira->codegen, operand->value->type) || - instr_is_comptime(operand)) - { - return operand; - } - - src_assert(instruction->begin->base.child->id == Stage1AirInstIdSpillBegin, instruction->base.source_node); - Stage1AirInstSpillBegin *begin = reinterpret_cast(instruction->begin->base.child); - - return ir_build_spill_end_gen(ira, instruction->base.scope, instruction->base.source_node, begin, operand->value->type); -} - -static Stage1AirInst *ir_analyze_instruction_src(IrAnalyze *ira, Stage1ZirInstSrc *instruction) { - ZigFn *fn_entry = scope_fn_entry(instruction->base.scope); - if (fn_entry == nullptr) { - ir_add_error_node(ira, instruction->base.source_node, buf_sprintf("@src outside function")); - return ira->codegen->invalid_inst_gen; - } - - ZigType *source_location_type = get_builtin_type(ira->codegen, "SourceLocation"); - if (type_resolve(ira->codegen, source_location_type, ResolveStatusSizeKnown)) { - zig_unreachable(); - } - - ZigValue *result = ira->codegen->pass1_arena->create(); - result->special = ConstValSpecialStatic; - result->type = source_location_type; - - ZigValue **fields = alloc_const_vals_ptrs(ira->codegen, 4); - result->data.x_struct.fields = fields; - - // file: [:0]const u8 - ensure_field_index(source_location_type, "file", 0); - fields[0]->special = ConstValSpecialStatic; - - ZigType *import = instruction->base.source_node->owner; - RootStruct *root_struct = import->data.structure.root_struct; - Buf *path = root_struct->path; - fields[0] = create_sentineled_str_lit( - ira->codegen, path, - ira->codegen->intern.for_zero_byte()); - - // fn_name: [:0]const u8 - ensure_field_index(source_location_type, "fn_name", 1); - fields[1]->special = ConstValSpecialStatic; - fields[1] = create_sentineled_str_lit( - ira->codegen, &fn_entry->symbol_name, - ira->codegen->intern.for_zero_byte()); - - TokenLoc tok_loc = root_struct->token_locs[instruction->base.source_node->main_token]; - - // line: u32 - ensure_field_index(source_location_type, "line", 2); - fields[2]->special = ConstValSpecialStatic; - fields[2]->type = ira->codegen->builtin_types.entry_u32; - bigint_init_unsigned(&fields[2]->data.x_bigint, tok_loc.line + 1); - - // column: u32 - ensure_field_index(source_location_type, "column", 3); - fields[3]->special = ConstValSpecialStatic; - fields[3]->type = ira->codegen->builtin_types.entry_u32; - bigint_init_unsigned(&fields[3]->data.x_bigint, tok_loc.column + 1); - - return ir_const_move(ira, instruction->base.scope, instruction->base.source_node, result); -} - -static Stage1AirInst *ir_analyze_instruction_prefetch(IrAnalyze *ira, Stage1ZirInstPrefetch *instruction) { - Stage1AirInst *ptr = instruction->ptr->child; - if (type_is_invalid(ptr->value->type)) - return ira->codegen->invalid_inst_gen; - - Stage1AirInst *raw_options_inst = instruction->options->child; - if (type_is_invalid(raw_options_inst->value->type)) - return ira->codegen->invalid_inst_gen; - - ZigType *options_type = get_builtin_type(ira->codegen, "PrefetchOptions"); - Stage1AirInst *options_inst = ir_implicit_cast(ira, raw_options_inst, options_type); - if (type_is_invalid(options_inst->value->type)) - return ira->codegen->invalid_inst_gen; - - ZigValue *options_val = ir_resolve_const(ira, options_inst, UndefBad); - if (options_val == nullptr) - return ira->codegen->invalid_inst_gen; - - ZigValue *rw_val = get_const_field(ira, options_inst->source_node, options_val, "rw", 0); - if (rw_val == nullptr) - return ira->codegen->invalid_inst_gen; - PrefetchRw rw = (PrefetchRw)bigint_as_u8(&rw_val->data.x_enum_tag); - - ZigValue *locality_val = get_const_field(ira, options_inst->source_node, options_val, "locality", 1); - if (locality_val == nullptr) - return ira->codegen->invalid_inst_gen; - uint8_t locality = bigint_as_u8(&locality_val->data.x_bigint); - assert(locality <= 3); - - ZigValue *cache_val = get_const_field(ira, options_inst->source_node, options_val, "cache", 2); - if (cache_val == nullptr) - return ira->codegen->invalid_inst_gen; - PrefetchCache cache = (PrefetchCache)bigint_as_u8(&cache_val->data.x_enum_tag); - - Stage1AirInstPrefetch *air_instruction = ir_build_inst_void(&ira->new_irb, - instruction->base.scope, instruction->base.source_node); - air_instruction->ptr = ptr; - air_instruction->rw = rw; - air_instruction->locality = locality; - air_instruction->cache = cache; - - ir_ref_inst_gen(ptr); - - return &air_instruction->base; -} - -static Stage1AirInst *ir_analyze_instruction_base(IrAnalyze *ira, Stage1ZirInst *instruction) { - switch (instruction->id) { - case Stage1ZirInstIdInvalid: - zig_unreachable(); - - case Stage1ZirInstIdReturn: - return ir_analyze_instruction_return(ira, (Stage1ZirInstReturn *)instruction); - case Stage1ZirInstIdConst: - return ir_analyze_instruction_const(ira, (Stage1ZirInstConst *)instruction); - case Stage1ZirInstIdUnOp: - return ir_analyze_instruction_un_op(ira, (Stage1ZirInstUnOp *)instruction); - case Stage1ZirInstIdBinOp: - return ir_analyze_instruction_bin_op(ira, (Stage1ZirInstBinOp *)instruction); - case Stage1ZirInstIdMergeErrSets: - return ir_analyze_instruction_merge_err_sets(ira, (Stage1ZirInstMergeErrSets *)instruction); - case Stage1ZirInstIdDeclVar: - return ir_analyze_instruction_decl_var(ira, (Stage1ZirInstDeclVar *)instruction); - case Stage1ZirInstIdLoadPtr: - return ir_analyze_instruction_load_ptr(ira, (Stage1ZirInstLoadPtr *)instruction); - case Stage1ZirInstIdStorePtr: - return ir_analyze_instruction_store_ptr(ira, (Stage1ZirInstStorePtr *)instruction); - case Stage1ZirInstIdElemPtr: - return ir_analyze_instruction_elem_ptr(ira, (Stage1ZirInstElemPtr *)instruction); - case Stage1ZirInstIdVarPtr: - return ir_analyze_instruction_var_ptr(ira, (Stage1ZirInstVarPtr *)instruction); - case Stage1ZirInstIdFieldPtr: - return ir_analyze_instruction_field_ptr(ira, (Stage1ZirInstFieldPtr *)instruction); - case Stage1ZirInstIdCall: - return ir_analyze_instruction_call(ira, (Stage1ZirInstCall *)instruction); - case Stage1ZirInstIdCallArgs: - return ir_analyze_instruction_call_args(ira, (Stage1ZirInstCallArgs *)instruction); - case Stage1ZirInstIdCallExtra: - return ir_analyze_instruction_call_extra(ira, (Stage1ZirInstCallExtra *)instruction); - case Stage1ZirInstIdAsyncCallExtra: - return ir_analyze_instruction_async_call_extra(ira, (Stage1ZirInstAsyncCallExtra *)instruction); - case Stage1ZirInstIdBr: - return ir_analyze_instruction_br(ira, (Stage1ZirInstBr *)instruction); - case Stage1ZirInstIdCondBr: - return ir_analyze_instruction_cond_br(ira, (Stage1ZirInstCondBr *)instruction); - case Stage1ZirInstIdUnreachable: - return ir_analyze_instruction_unreachable(ira, (Stage1ZirInstUnreachable *)instruction); - case Stage1ZirInstIdPhi: - return ir_analyze_instruction_phi(ira, (Stage1ZirInstPhi *)instruction); - case Stage1ZirInstIdTypeOf: - return ir_analyze_instruction_typeof(ira, (Stage1ZirInstTypeOf *)instruction); - case Stage1ZirInstIdSetCold: - return ir_analyze_instruction_set_cold(ira, (Stage1ZirInstSetCold *)instruction); - case Stage1ZirInstIdSetRuntimeSafety: - return ir_analyze_instruction_set_runtime_safety(ira, (Stage1ZirInstSetRuntimeSafety *)instruction); - case Stage1ZirInstIdSetFloatMode: - return ir_analyze_instruction_set_float_mode(ira, (Stage1ZirInstSetFloatMode *)instruction); - case Stage1ZirInstIdAnyFrameType: - return ir_analyze_instruction_any_frame_type(ira, (Stage1ZirInstAnyFrameType *)instruction); - case Stage1ZirInstIdSliceType: - return ir_analyze_instruction_slice_type(ira, (Stage1ZirInstSliceType *)instruction); - case Stage1ZirInstIdAsm: - return ir_analyze_instruction_asm(ira, (Stage1ZirInstAsm *)instruction); - case Stage1ZirInstIdArrayType: - return ir_analyze_instruction_array_type(ira, (Stage1ZirInstArrayType *)instruction); - case Stage1ZirInstIdSizeOf: - return ir_analyze_instruction_size_of(ira, (Stage1ZirInstSizeOf *)instruction); - case Stage1ZirInstIdTestNonNull: - return ir_analyze_instruction_test_non_null(ira, (Stage1ZirInstTestNonNull *)instruction); - case Stage1ZirInstIdOptionalUnwrapPtr: - return ir_analyze_instruction_optional_unwrap_ptr(ira, (Stage1ZirInstOptionalUnwrapPtr *)instruction); - case Stage1ZirInstIdClz: - return ir_analyze_instruction_clz(ira, (Stage1ZirInstClz *)instruction); - case Stage1ZirInstIdCtz: - return ir_analyze_instruction_ctz(ira, (Stage1ZirInstCtz *)instruction); - case Stage1ZirInstIdPopCount: - return ir_analyze_instruction_pop_count(ira, (Stage1ZirInstPopCount *)instruction); - case Stage1ZirInstIdBswap: - return ir_analyze_instruction_bswap(ira, (Stage1ZirInstBswap *)instruction); - case Stage1ZirInstIdBitReverse: - return ir_analyze_instruction_bit_reverse(ira, (Stage1ZirInstBitReverse *)instruction); - case Stage1ZirInstIdSwitchBr: - return ir_analyze_instruction_switch_br(ira, (Stage1ZirInstSwitchBr *)instruction); - case Stage1ZirInstIdSwitchTarget: - return ir_analyze_instruction_switch_target(ira, (Stage1ZirInstSwitchTarget *)instruction); - case Stage1ZirInstIdSwitchVar: - return ir_analyze_instruction_switch_var(ira, (Stage1ZirInstSwitchVar *)instruction); - case Stage1ZirInstIdSwitchElseVar: - return ir_analyze_instruction_switch_else_var(ira, (Stage1ZirInstSwitchElseVar *)instruction); - case Stage1ZirInstIdImport: - return ir_analyze_instruction_import(ira, (Stage1ZirInstImport *)instruction); - case Stage1ZirInstIdRef: - return ir_analyze_instruction_ref(ira, (Stage1ZirInstRef *)instruction); - case Stage1ZirInstIdContainerInitList: - return ir_analyze_instruction_container_init_list(ira, (Stage1ZirInstContainerInitList *)instruction); - case Stage1ZirInstIdContainerInitFields: - return ir_analyze_instruction_container_init_fields(ira, (Stage1ZirInstContainerInitFields *)instruction); - case Stage1ZirInstIdCompileErr: - return ir_analyze_instruction_compile_err(ira, (Stage1ZirInstCompileErr *)instruction); - case Stage1ZirInstIdCompileLog: - return ir_analyze_instruction_compile_log(ira, (Stage1ZirInstCompileLog *)instruction); - case Stage1ZirInstIdErrName: - return ir_analyze_instruction_err_name(ira, (Stage1ZirInstErrName *)instruction); - case Stage1ZirInstIdTypeName: - return ir_analyze_instruction_type_name(ira, (Stage1ZirInstTypeName *)instruction); - case Stage1ZirInstIdCImport: - return ir_analyze_instruction_c_import(ira, (Stage1ZirInstCImport *)instruction); - case Stage1ZirInstIdCInclude: - return ir_analyze_instruction_c_include(ira, (Stage1ZirInstCInclude *)instruction); - case Stage1ZirInstIdCDefine: - return ir_analyze_instruction_c_define(ira, (Stage1ZirInstCDefine *)instruction); - case Stage1ZirInstIdCUndef: - return ir_analyze_instruction_c_undef(ira, (Stage1ZirInstCUndef *)instruction); - case Stage1ZirInstIdEmbedFile: - return ir_analyze_instruction_embed_file(ira, (Stage1ZirInstEmbedFile *)instruction); - case Stage1ZirInstIdCmpxchg: - return ir_analyze_instruction_cmpxchg(ira, (Stage1ZirInstCmpxchg *)instruction); - case Stage1ZirInstIdFence: - return ir_analyze_instruction_fence(ira, (Stage1ZirInstFence *)instruction); - case Stage1ZirInstIdReduce: - return ir_analyze_instruction_reduce(ira, (Stage1ZirInstReduce *)instruction); - case Stage1ZirInstIdTruncate: - return ir_analyze_instruction_truncate(ira, (Stage1ZirInstTruncate *)instruction); - case Stage1ZirInstIdIntCast: - return ir_analyze_instruction_int_cast(ira, (Stage1ZirInstIntCast *)instruction); - case Stage1ZirInstIdFloatCast: - return ir_analyze_instruction_float_cast(ira, (Stage1ZirInstFloatCast *)instruction); - case Stage1ZirInstIdErrSetCast: - return ir_analyze_instruction_err_set_cast(ira, (Stage1ZirInstErrSetCast *)instruction); - case Stage1ZirInstIdIntToFloat: - return ir_analyze_instruction_int_to_float(ira, (Stage1ZirInstIntToFloat *)instruction); - case Stage1ZirInstIdFloatToInt: - return ir_analyze_instruction_float_to_int(ira, (Stage1ZirInstFloatToInt *)instruction); - case Stage1ZirInstIdBoolToInt: - return ir_analyze_instruction_bool_to_int(ira, (Stage1ZirInstBoolToInt *)instruction); - case Stage1ZirInstIdVectorType: - return ir_analyze_instruction_vector_type(ira, (Stage1ZirInstVectorType *)instruction); - case Stage1ZirInstIdShuffleVector: - return ir_analyze_instruction_shuffle_vector(ira, (Stage1ZirInstShuffleVector *)instruction); - case Stage1ZirInstIdSelect: - return ir_analyze_instruction_select(ira, (Stage1ZirInstSelect *)instruction); - case Stage1ZirInstIdSplat: - return ir_analyze_instruction_splat(ira, (Stage1ZirInstSplat *)instruction); - case Stage1ZirInstIdBoolNot: - return ir_analyze_instruction_bool_not(ira, (Stage1ZirInstBoolNot *)instruction); - case Stage1ZirInstIdMemset: - return ir_analyze_instruction_memset(ira, (Stage1ZirInstMemset *)instruction); - case Stage1ZirInstIdMemcpy: - return ir_analyze_instruction_memcpy(ira, (Stage1ZirInstMemcpy *)instruction); - case Stage1ZirInstIdSlice: - return ir_analyze_instruction_slice(ira, (Stage1ZirInstSlice *)instruction); - case Stage1ZirInstIdBreakpoint: - return ir_analyze_instruction_breakpoint(ira, (Stage1ZirInstBreakpoint *)instruction); - case Stage1ZirInstIdReturnAddress: - return ir_analyze_instruction_return_address(ira, (Stage1ZirInstReturnAddress *)instruction); - case Stage1ZirInstIdFrameAddress: - return ir_analyze_instruction_frame_address(ira, (Stage1ZirInstFrameAddress *)instruction); - case Stage1ZirInstIdFrameHandle: - return ir_analyze_instruction_frame_handle(ira, (Stage1ZirInstFrameHandle *)instruction); - case Stage1ZirInstIdFrameType: - return ir_analyze_instruction_frame_type(ira, (Stage1ZirInstFrameType *)instruction); - case Stage1ZirInstIdFrameSize: - return ir_analyze_instruction_frame_size(ira, (Stage1ZirInstFrameSize *)instruction); - case Stage1ZirInstIdAlignOf: - return ir_analyze_instruction_align_of(ira, (Stage1ZirInstAlignOf *)instruction); - case Stage1ZirInstIdOverflowOp: - return ir_analyze_instruction_overflow_op(ira, (Stage1ZirInstOverflowOp *)instruction); - case Stage1ZirInstIdTestErr: - return ir_analyze_instruction_test_err(ira, (Stage1ZirInstTestErr *)instruction); - case Stage1ZirInstIdUnwrapErrCode: - return ir_analyze_instruction_unwrap_err_code(ira, (Stage1ZirInstUnwrapErrCode *)instruction); - case Stage1ZirInstIdUnwrapErrPayload: - return ir_analyze_instruction_unwrap_err_payload(ira, (Stage1ZirInstUnwrapErrPayload *)instruction); - case Stage1ZirInstIdFnProto: - return ir_analyze_instruction_fn_proto(ira, (Stage1ZirInstFnProto *)instruction); - case Stage1ZirInstIdTestComptime: - return ir_analyze_instruction_test_comptime(ira, (Stage1ZirInstTestComptime *)instruction); - case Stage1ZirInstIdCheckSwitchProngsUnderNo: - return ir_analyze_instruction_check_switch_prongs(ira, (Stage1ZirInstCheckSwitchProngs *)instruction, false); - case Stage1ZirInstIdCheckSwitchProngsUnderYes: - return ir_analyze_instruction_check_switch_prongs(ira, (Stage1ZirInstCheckSwitchProngs *)instruction, true); - case Stage1ZirInstIdCheckStatementIsVoid: - return ir_analyze_instruction_check_statement_is_void(ira, (Stage1ZirInstCheckStatementIsVoid *)instruction); - case Stage1ZirInstIdDeclRef: - return ir_analyze_instruction_decl_ref(ira, (Stage1ZirInstDeclRef *)instruction); - case Stage1ZirInstIdPanic: - return ir_analyze_instruction_panic(ira, (Stage1ZirInstPanic *)instruction); - case Stage1ZirInstIdPtrCast: - return ir_analyze_instruction_ptr_cast(ira, (Stage1ZirInstPtrCast *)instruction); - case Stage1ZirInstIdIntToPtr: - return ir_analyze_instruction_int_to_ptr(ira, (Stage1ZirInstIntToPtr *)instruction); - case Stage1ZirInstIdPtrToInt: - return ir_analyze_instruction_ptr_to_int(ira, (Stage1ZirInstPtrToInt *)instruction); - case Stage1ZirInstIdTagName: - return ir_analyze_instruction_enum_tag_name(ira, (Stage1ZirInstTagName *)instruction); - case Stage1ZirInstIdFieldParentPtr: - return ir_analyze_instruction_field_parent_ptr(ira, (Stage1ZirInstFieldParentPtr *)instruction); - case Stage1ZirInstIdOffsetOf: - return ir_analyze_instruction_offset_of(ira, (Stage1ZirInstOffsetOf *)instruction); - case Stage1ZirInstIdBitOffsetOf: - return ir_analyze_instruction_bit_offset_of(ira, (Stage1ZirInstBitOffsetOf *)instruction); - case Stage1ZirInstIdTypeInfo: - return ir_analyze_instruction_type_info(ira, (Stage1ZirInstTypeInfo *) instruction); - case Stage1ZirInstIdType: - return ir_analyze_instruction_type(ira, (Stage1ZirInstType *)instruction); - case Stage1ZirInstIdHasField: - return ir_analyze_instruction_has_field(ira, (Stage1ZirInstHasField *) instruction); - case Stage1ZirInstIdSetEvalBranchQuota: - return ir_analyze_instruction_set_eval_branch_quota(ira, (Stage1ZirInstSetEvalBranchQuota *)instruction); - case Stage1ZirInstIdPtrType: - return ir_analyze_instruction_ptr_type(ira, (Stage1ZirInstPtrType *)instruction); - case Stage1ZirInstIdPtrTypeSimple: - return ir_analyze_instruction_ptr_type_simple(ira, (Stage1ZirInstPtrTypeSimple *)instruction, false); - case Stage1ZirInstIdPtrTypeSimpleConst: - return ir_analyze_instruction_ptr_type_simple(ira, (Stage1ZirInstPtrTypeSimple *)instruction, true); - case Stage1ZirInstIdAlignCast: - return ir_analyze_instruction_align_cast(ira, (Stage1ZirInstAlignCast *)instruction); - case Stage1ZirInstIdImplicitCast: - return ir_analyze_instruction_implicit_cast(ira, (Stage1ZirInstImplicitCast *)instruction); - case Stage1ZirInstIdResolveResult: - return ir_analyze_instruction_resolve_result(ira, (Stage1ZirInstResolveResult *)instruction); - case Stage1ZirInstIdResetResult: - return ir_analyze_instruction_reset_result(ira, (Stage1ZirInstResetResult *)instruction); - case Stage1ZirInstIdSetAlignStack: - return ir_analyze_instruction_set_align_stack(ira, (Stage1ZirInstSetAlignStack *)instruction); - case Stage1ZirInstIdArgTypeAllowVarFalse: - return ir_analyze_instruction_arg_type(ira, (Stage1ZirInstArgType *)instruction, false); - case Stage1ZirInstIdArgTypeAllowVarTrue: - return ir_analyze_instruction_arg_type(ira, (Stage1ZirInstArgType *)instruction, true); - case Stage1ZirInstIdExport: - return ir_analyze_instruction_export(ira, (Stage1ZirInstExport *)instruction); - case Stage1ZirInstIdExtern: - return ir_analyze_instruction_extern(ira, (Stage1ZirInstExtern *)instruction); - case Stage1ZirInstIdErrorReturnTrace: - return ir_analyze_instruction_error_return_trace(ira, (Stage1ZirInstErrorReturnTrace *)instruction); - case Stage1ZirInstIdErrorUnion: - return ir_analyze_instruction_error_union(ira, (Stage1ZirInstErrorUnion *)instruction); - case Stage1ZirInstIdAtomicRmw: - return ir_analyze_instruction_atomic_rmw(ira, (Stage1ZirInstAtomicRmw *)instruction); - case Stage1ZirInstIdAtomicLoad: - return ir_analyze_instruction_atomic_load(ira, (Stage1ZirInstAtomicLoad *)instruction); - case Stage1ZirInstIdAtomicStore: - return ir_analyze_instruction_atomic_store(ira, (Stage1ZirInstAtomicStore *)instruction); - case Stage1ZirInstIdSaveErrRetAddr: - return ir_analyze_instruction_save_err_ret_addr(ira, (Stage1ZirInstSaveErrRetAddr *)instruction); - case Stage1ZirInstIdAddImplicitReturnType: - return ir_analyze_instruction_add_implicit_return_type(ira, (Stage1ZirInstAddImplicitReturnType *)instruction); - case Stage1ZirInstIdFloatOp: - return ir_analyze_instruction_float_op(ira, (Stage1ZirInstFloatOp *)instruction); - case Stage1ZirInstIdMulAdd: - return ir_analyze_instruction_mul_add(ira, (Stage1ZirInstMulAdd *)instruction); - case Stage1ZirInstIdIntToErr: - return ir_analyze_instruction_int_to_err(ira, (Stage1ZirInstIntToErr *)instruction); - case Stage1ZirInstIdErrToInt: - return ir_analyze_instruction_err_to_int(ira, (Stage1ZirInstErrToInt *)instruction); - case Stage1ZirInstIdIntToEnum: - return ir_analyze_instruction_int_to_enum(ira, (Stage1ZirInstIntToEnum *)instruction); - case Stage1ZirInstIdEnumToInt: - return ir_analyze_instruction_enum_to_int(ira, (Stage1ZirInstEnumToInt *)instruction); - case Stage1ZirInstIdCheckRuntimeScope: - return ir_analyze_instruction_check_runtime_scope(ira, (Stage1ZirInstCheckRuntimeScope *)instruction); - case Stage1ZirInstIdHasDecl: - return ir_analyze_instruction_has_decl(ira, (Stage1ZirInstHasDecl *)instruction); - case Stage1ZirInstIdUndeclaredIdent: - return ir_analyze_instruction_undeclared_ident(ira, (Stage1ZirInstUndeclaredIdent *)instruction); - case Stage1ZirInstIdAlloca: - return nullptr; - case Stage1ZirInstIdEndExpr: - return ir_analyze_instruction_end_expr(ira, (Stage1ZirInstEndExpr *)instruction); - case Stage1ZirInstIdBitCast: - return ir_analyze_instruction_bit_cast_src(ira, (Stage1ZirInstBitCast *)instruction); - case Stage1ZirInstIdUnionInitNamedField: - return ir_analyze_instruction_union_init_named_field(ira, (Stage1ZirInstUnionInitNamedField *)instruction); - case Stage1ZirInstIdSuspendBegin: - return ir_analyze_instruction_suspend_begin(ira, (Stage1ZirInstSuspendBegin *)instruction); - case Stage1ZirInstIdSuspendFinish: - return ir_analyze_instruction_suspend_finish(ira, (Stage1ZirInstSuspendFinish *)instruction); - case Stage1ZirInstIdResume: - return ir_analyze_instruction_resume(ira, (Stage1ZirInstResume *)instruction); - case Stage1ZirInstIdAwait: - return ir_analyze_instruction_await(ira, (Stage1ZirInstAwait *)instruction); - case Stage1ZirInstIdSpillBegin: - return ir_analyze_instruction_spill_begin(ira, (Stage1ZirInstSpillBegin *)instruction); - case Stage1ZirInstIdSpillEnd: - return ir_analyze_instruction_spill_end(ira, (Stage1ZirInstSpillEnd *)instruction); - case Stage1ZirInstIdWasmMemorySize: - return ir_analyze_instruction_wasm_memory_size(ira, (Stage1ZirInstWasmMemorySize *)instruction); - case Stage1ZirInstIdWasmMemoryGrow: - return ir_analyze_instruction_wasm_memory_grow(ira, (Stage1ZirInstWasmMemoryGrow *)instruction); - case Stage1ZirInstIdSrc: - return ir_analyze_instruction_src(ira, (Stage1ZirInstSrc *)instruction); - case Stage1ZirInstIdPrefetch: - return ir_analyze_instruction_prefetch(ira, (Stage1ZirInstPrefetch *)instruction); - case Stage1ZirInstIdAddrSpaceCast: - return ir_analyze_instruction_addrspace_cast(ira, (Stage1ZirInstAddrSpaceCast *)instruction); - } - zig_unreachable(); -} - -// This function attempts to evaluate stage1 ZIR code while doing type checking and other analysis. -// It emits to a new Stage1Air which is partially evaluated IR code. -ZigType *ir_analyze(CodeGen *codegen, Stage1Zir *stage1_zir, Stage1Air *stage1_air, - size_t *backward_branch_count, size_t *backward_branch_quota, - ZigType *expected_type, AstNode *expected_type_source_node, ZigValue *result_ptr, ZigFn *fn) -{ - assert(stage1_zir->first_err_trace_msg == nullptr); - assert(expected_type == nullptr || !type_is_invalid(expected_type)); - - IrAnalyze *ira = heap::c_allocator.create(); - ira->fn = fn; - ira->backward_branch_count = backward_branch_count; - ira->backward_branch_quota = backward_branch_quota; - ira->ref_count = 1; - ira->codegen = codegen; - - ira->explicit_return_type = expected_type; - ira->explicit_return_type_source_node = expected_type_source_node; - - ira->zir = stage1_zir; - - ira->new_irb.codegen = codegen; - ira->new_irb.exec = stage1_air; - - Stage1ZirBasicBlock *old_entry_bb = ira->zir->basic_block_list.at(0); - Stage1AirBasicBlock *new_entry_bb = ir_get_new_bb(ira, old_entry_bb, nullptr); - ira->new_irb.current_basic_block = new_entry_bb; - ira->old_bb_index = 0; - - ir_start_bb(ira, old_entry_bb, nullptr); - - if (result_ptr != nullptr) { - assert(result_ptr->type->id == ZigTypeIdPointer); - Stage1AirInstConst *const_inst = ir_create_inst_noval( - &ira->new_irb, stage1_air->begin_scope, stage1_air->source_node); - const_inst->base.value = result_ptr; - ira->return_ptr = &const_inst->base; - } else { - assert(stage1_air->begin_scope != nullptr); - assert(stage1_air->source_node != nullptr); - ira->return_ptr = ir_build_return_ptr(ira, stage1_air->begin_scope, stage1_air->source_node, - get_pointer_to_type(codegen, expected_type, false)); - } - - while (ira->old_bb_index < ira->zir->basic_block_list.length) { - Stage1ZirInst *old_instruction = ira->zir_current_basic_block->instruction_list.at(ira->instruction_index); - - if (old_instruction->ref_count == 0 && !ir_inst_src_has_side_effects(old_instruction)) { - ira->instruction_index += 1; - continue; - } - - if (ira->codegen->verbose_ir) { - fprintf(stderr, "~ "); - old_instruction->src(); - fprintf(stderr, "~ "); - ir_print_inst_src(codegen, stderr, old_instruction, 0); - } - ira->suspend_source_instr = old_instruction; - Stage1AirInst *new_instruction = ir_analyze_instruction_base(ira, old_instruction); - if (new_instruction != nullptr) { - src_assert(new_instruction->value->type != nullptr || new_instruction->value->type != nullptr, old_instruction->source_node); - old_instruction->child = new_instruction; - - if (type_is_invalid(new_instruction->value->type)) { - if (ira->codegen->verbose_ir) { - fprintf(stderr, "-> (invalid)"); - } - - if (stage1_air->first_err_trace_msg != nullptr) { - ira->codegen->trace_err = stage1_air->first_err_trace_msg; - } else { - stage1_air->first_err_trace_msg = ira->codegen->trace_err; - } - return ira->codegen->builtin_types.entry_invalid; - } else if (ira->codegen->verbose_ir) { - fprintf(stderr, "-> "); - if (new_instruction->value->type->id == ZigTypeIdUnreachable) { - fprintf(stderr, "(noreturn)\n"); - } else { - ir_print_inst_gen(codegen, stderr, new_instruction, 0); - } - } - - // unreachable instructions do their own control flow. - if (new_instruction->value->type->id == ZigTypeIdUnreachable) - continue; - } else { - if (ira->codegen->verbose_ir) { - fprintf(stderr, "-> (null"); - } - } - - ira->instruction_index += 1; - } - - ZigType *res_type; - if (stage1_air->first_err_trace_msg != nullptr) { - codegen->trace_err = stage1_air->first_err_trace_msg; - res_type = ira->codegen->builtin_types.entry_invalid; - } else if (ira->src_implicit_return_type_list.length == 0) { - res_type = codegen->builtin_types.entry_unreachable; - } else { - res_type = ir_resolve_peer_types(ira, expected_type_source_node, expected_type, ira->src_implicit_return_type_list.items, - ira->src_implicit_return_type_list.length); - } - - // It is now safe to free Pass 1 IR instructions. - ira_deref(ira); - - return res_type; -} - -bool ir_inst_gen_has_side_effects(Stage1AirInst *instruction) { - switch (instruction->id) { - case Stage1AirInstIdInvalid: - zig_unreachable(); - case Stage1AirInstIdBr: - case Stage1AirInstIdCondBr: - case Stage1AirInstIdSwitchBr: - case Stage1AirInstIdDeclVar: - case Stage1AirInstIdStorePtr: - case Stage1AirInstIdVectorStoreElem: - case Stage1AirInstIdCall: - case Stage1AirInstIdReturn: - case Stage1AirInstIdUnreachable: - case Stage1AirInstIdFence: - case Stage1AirInstIdMemset: - case Stage1AirInstIdMemcpy: - case Stage1AirInstIdBreakpoint: - case Stage1AirInstIdOverflowOp: // TODO when we support multiple returns this can be side effect free - case Stage1AirInstIdPanic: - case Stage1AirInstIdSaveErrRetAddr: - case Stage1AirInstIdAtomicRmw: - case Stage1AirInstIdAtomicStore: - case Stage1AirInstIdCmpxchg: - case Stage1AirInstIdAssertZero: - case Stage1AirInstIdAssertNonNull: - case Stage1AirInstIdPtrOfArrayToSlice: - case Stage1AirInstIdSlice: - case Stage1AirInstIdOptionalWrap: - case Stage1AirInstIdVectorToArray: - case Stage1AirInstIdSuspendBegin: - case Stage1AirInstIdSuspendFinish: - case Stage1AirInstIdResume: - case Stage1AirInstIdAwait: - case Stage1AirInstIdSpillBegin: - case Stage1AirInstIdWasmMemoryGrow: - case Stage1AirInstIdExtern: - case Stage1AirInstIdPrefetch: - return true; - - case Stage1AirInstIdPhi: - case Stage1AirInstIdBinOp: - case Stage1AirInstIdConst: - case Stage1AirInstIdCast: - case Stage1AirInstIdElemPtr: - case Stage1AirInstIdVarPtr: - case Stage1AirInstIdReturnPtr: - case Stage1AirInstIdStructFieldPtr: - case Stage1AirInstIdTestNonNull: - case Stage1AirInstIdClz: - case Stage1AirInstIdCtz: - case Stage1AirInstIdPopCount: - case Stage1AirInstIdBswap: - case Stage1AirInstIdBitReverse: - case Stage1AirInstIdUnionTag: - case Stage1AirInstIdTruncate: - case Stage1AirInstIdShuffleVector: - case Stage1AirInstIdSelect: - case Stage1AirInstIdSplat: - case Stage1AirInstIdBoolNot: - case Stage1AirInstIdReturnAddress: - case Stage1AirInstIdFrameAddress: - case Stage1AirInstIdFrameHandle: - case Stage1AirInstIdFrameSize: - case Stage1AirInstIdTestErr: - case Stage1AirInstIdPtrCast: - case Stage1AirInstIdBitCast: - case Stage1AirInstIdWidenOrShorten: - case Stage1AirInstIdPtrToInt: - case Stage1AirInstIdIntToPtr: - case Stage1AirInstIdIntToEnum: - case Stage1AirInstIdIntToErr: - case Stage1AirInstIdErrToInt: - case Stage1AirInstIdErrName: - case Stage1AirInstIdTagName: - case Stage1AirInstIdFieldParentPtr: - case Stage1AirInstIdAlignCast: - case Stage1AirInstIdErrorReturnTrace: - case Stage1AirInstIdFloatOp: - case Stage1AirInstIdMulAdd: - case Stage1AirInstIdAtomicLoad: - case Stage1AirInstIdArrayToVector: - case Stage1AirInstIdAlloca: - case Stage1AirInstIdSpillEnd: - case Stage1AirInstIdVectorExtractElem: - case Stage1AirInstIdBinaryNot: - case Stage1AirInstIdNegation: - case Stage1AirInstIdWasmMemorySize: - case Stage1AirInstIdReduce: - return false; - - case Stage1AirInstIdAsm: - { - Stage1AirInstAsm *asm_instruction = (Stage1AirInstAsm *)instruction; - return asm_instruction->has_side_effects; - } - case Stage1AirInstIdUnwrapErrPayload: - { - Stage1AirInstUnwrapErrPayload *unwrap_err_payload_instruction = - (Stage1AirInstUnwrapErrPayload *)instruction; - return unwrap_err_payload_instruction->safety_check_on || - unwrap_err_payload_instruction->initializing; - } - case Stage1AirInstIdUnwrapErrCode: - return reinterpret_cast(instruction)->initializing; - case Stage1AirInstIdUnionFieldPtr: - return reinterpret_cast(instruction)->initializing; - case Stage1AirInstIdOptionalUnwrapPtr: - return reinterpret_cast(instruction)->initializing; - case Stage1AirInstIdErrWrapPayload: - return reinterpret_cast(instruction)->result_loc != nullptr; - case Stage1AirInstIdErrWrapCode: - return reinterpret_cast(instruction)->result_loc != nullptr; - case Stage1AirInstIdLoadPtr: - return reinterpret_cast(instruction)->result_loc != nullptr; - case Stage1AirInstIdRef: - return reinterpret_cast(instruction)->result_loc != nullptr; - } - zig_unreachable(); -} - -bool ir_inst_src_has_side_effects(Stage1ZirInst *instruction) { - switch (instruction->id) { - case Stage1ZirInstIdInvalid: - zig_unreachable(); - case Stage1ZirInstIdBr: - case Stage1ZirInstIdCondBr: - case Stage1ZirInstIdSwitchBr: - case Stage1ZirInstIdDeclVar: - case Stage1ZirInstIdStorePtr: - case Stage1ZirInstIdCallExtra: - case Stage1ZirInstIdAsyncCallExtra: - case Stage1ZirInstIdCall: - case Stage1ZirInstIdCallArgs: - case Stage1ZirInstIdReturn: - case Stage1ZirInstIdUnreachable: - case Stage1ZirInstIdSetCold: - case Stage1ZirInstIdSetRuntimeSafety: - case Stage1ZirInstIdSetFloatMode: - case Stage1ZirInstIdImport: - case Stage1ZirInstIdCompileErr: - case Stage1ZirInstIdCompileLog: - case Stage1ZirInstIdCImport: - case Stage1ZirInstIdCInclude: - case Stage1ZirInstIdCDefine: - case Stage1ZirInstIdCUndef: - case Stage1ZirInstIdFence: - case Stage1ZirInstIdMemset: - case Stage1ZirInstIdMemcpy: - case Stage1ZirInstIdBreakpoint: - case Stage1ZirInstIdOverflowOp: // TODO when we support multiple returns this can be side effect free - case Stage1ZirInstIdCheckSwitchProngsUnderNo: - case Stage1ZirInstIdCheckSwitchProngsUnderYes: - case Stage1ZirInstIdCheckStatementIsVoid: - case Stage1ZirInstIdCheckRuntimeScope: - case Stage1ZirInstIdPanic: - case Stage1ZirInstIdSetEvalBranchQuota: - case Stage1ZirInstIdPtrType: - case Stage1ZirInstIdPtrTypeSimple: - case Stage1ZirInstIdPtrTypeSimpleConst: - case Stage1ZirInstIdSetAlignStack: - case Stage1ZirInstIdExport: - case Stage1ZirInstIdExtern: - case Stage1ZirInstIdSaveErrRetAddr: - case Stage1ZirInstIdAddImplicitReturnType: - case Stage1ZirInstIdAtomicRmw: - case Stage1ZirInstIdAtomicStore: - case Stage1ZirInstIdCmpxchg: - case Stage1ZirInstIdUndeclaredIdent: - case Stage1ZirInstIdEndExpr: - case Stage1ZirInstIdResetResult: - case Stage1ZirInstIdSuspendBegin: - case Stage1ZirInstIdSuspendFinish: - case Stage1ZirInstIdResume: - case Stage1ZirInstIdAwait: - case Stage1ZirInstIdSpillBegin: - case Stage1ZirInstIdWasmMemoryGrow: - case Stage1ZirInstIdPrefetch: - return true; - - case Stage1ZirInstIdPhi: - case Stage1ZirInstIdUnOp: - case Stage1ZirInstIdBinOp: - case Stage1ZirInstIdMergeErrSets: - case Stage1ZirInstIdLoadPtr: - case Stage1ZirInstIdConst: - case Stage1ZirInstIdContainerInitList: - case Stage1ZirInstIdContainerInitFields: - case Stage1ZirInstIdUnionInitNamedField: - case Stage1ZirInstIdFieldPtr: - case Stage1ZirInstIdElemPtr: - case Stage1ZirInstIdVarPtr: - case Stage1ZirInstIdTypeOf: - case Stage1ZirInstIdArrayType: - case Stage1ZirInstIdSliceType: - case Stage1ZirInstIdAnyFrameType: - case Stage1ZirInstIdSizeOf: - case Stage1ZirInstIdTestNonNull: - case Stage1ZirInstIdOptionalUnwrapPtr: - case Stage1ZirInstIdClz: - case Stage1ZirInstIdCtz: - case Stage1ZirInstIdPopCount: - case Stage1ZirInstIdBswap: - case Stage1ZirInstIdBitReverse: - case Stage1ZirInstIdSwitchVar: - case Stage1ZirInstIdSwitchElseVar: - case Stage1ZirInstIdSwitchTarget: - case Stage1ZirInstIdRef: - case Stage1ZirInstIdEmbedFile: - case Stage1ZirInstIdTruncate: - case Stage1ZirInstIdVectorType: - case Stage1ZirInstIdShuffleVector: - case Stage1ZirInstIdSelect: - case Stage1ZirInstIdSplat: - case Stage1ZirInstIdBoolNot: - case Stage1ZirInstIdSlice: - case Stage1ZirInstIdAlignOf: - case Stage1ZirInstIdReturnAddress: - case Stage1ZirInstIdFrameAddress: - case Stage1ZirInstIdFrameHandle: - case Stage1ZirInstIdFrameType: - case Stage1ZirInstIdFrameSize: - case Stage1ZirInstIdTestErr: - case Stage1ZirInstIdFnProto: - case Stage1ZirInstIdTestComptime: - case Stage1ZirInstIdPtrCast: - case Stage1ZirInstIdBitCast: - case Stage1ZirInstIdPtrToInt: - case Stage1ZirInstIdIntToPtr: - case Stage1ZirInstIdIntToEnum: - case Stage1ZirInstIdIntToErr: - case Stage1ZirInstIdErrToInt: - case Stage1ZirInstIdDeclRef: - case Stage1ZirInstIdErrName: - case Stage1ZirInstIdTypeName: - case Stage1ZirInstIdTagName: - case Stage1ZirInstIdFieldParentPtr: - case Stage1ZirInstIdOffsetOf: - case Stage1ZirInstIdBitOffsetOf: - case Stage1ZirInstIdTypeInfo: - case Stage1ZirInstIdType: - case Stage1ZirInstIdHasField: - case Stage1ZirInstIdAlignCast: - case Stage1ZirInstIdImplicitCast: - case Stage1ZirInstIdResolveResult: - case Stage1ZirInstIdArgTypeAllowVarFalse: - case Stage1ZirInstIdArgTypeAllowVarTrue: - case Stage1ZirInstIdErrorReturnTrace: - case Stage1ZirInstIdErrorUnion: - case Stage1ZirInstIdFloatOp: - case Stage1ZirInstIdMulAdd: - case Stage1ZirInstIdAtomicLoad: - case Stage1ZirInstIdIntCast: - case Stage1ZirInstIdFloatCast: - case Stage1ZirInstIdErrSetCast: - case Stage1ZirInstIdIntToFloat: - case Stage1ZirInstIdFloatToInt: - case Stage1ZirInstIdBoolToInt: - case Stage1ZirInstIdEnumToInt: - case Stage1ZirInstIdHasDecl: - case Stage1ZirInstIdAlloca: - case Stage1ZirInstIdSpillEnd: - case Stage1ZirInstIdWasmMemorySize: - case Stage1ZirInstIdSrc: - case Stage1ZirInstIdReduce: - case Stage1ZirInstIdAddrSpaceCast: - return false; - - case Stage1ZirInstIdAsm: - { - Stage1ZirInstAsm *asm_instruction = (Stage1ZirInstAsm *)instruction; - return asm_instruction->has_side_effects; - } - - case Stage1ZirInstIdUnwrapErrPayload: - { - Stage1ZirInstUnwrapErrPayload *unwrap_err_payload_instruction = - (Stage1ZirInstUnwrapErrPayload *)instruction; - return unwrap_err_payload_instruction->safety_check_on || - unwrap_err_payload_instruction->initializing; - } - case Stage1ZirInstIdUnwrapErrCode: - return reinterpret_cast(instruction)->initializing; - } - zig_unreachable(); -} - -static ZigType *ir_resolve_lazy_fn_type(IrAnalyze *ira, AstNode *source_node, LazyValueFnType *lazy_fn_type) { - Error err; - AstNode *proto_node = lazy_fn_type->proto_node; - - FnTypeId fn_type_id = {0}; - init_fn_type_id(&fn_type_id, proto_node, lazy_fn_type->cc, proto_node->data.fn_proto.params.length); - - if (proto_node->data.fn_proto.callconv_expr != nullptr) { - if ((err = emit_error_unless_callconv_allowed_for_target(ira->codegen, proto_node->data.fn_proto.callconv_expr, lazy_fn_type->cc))) - return nullptr; - } - - for (; fn_type_id.next_param_index < fn_type_id.param_count; fn_type_id.next_param_index += 1) { - AstNode *param_node = proto_node->data.fn_proto.params.at(fn_type_id.next_param_index); - assert(param_node->type == NodeTypeParamDecl); - - bool param_is_var_args = param_node->data.param_decl.is_var_args; - if (param_is_var_args) { - if (fn_type_id.cc == CallingConventionC) { - fn_type_id.param_count = fn_type_id.next_param_index; - break; - } else { - ir_add_error_node(ira, param_node, - buf_sprintf("var args only allowed in functions with C calling convention")); - return nullptr; - } - } - FnTypeParamInfo *param_info = &fn_type_id.param_info[fn_type_id.next_param_index]; - param_info->is_noalias = param_node->data.param_decl.is_noalias; - - if (lazy_fn_type->param_types[fn_type_id.next_param_index] == nullptr) { - param_info->type = nullptr; - return get_generic_fn_type(ira->codegen, &fn_type_id); - } else { - Stage1AirInst *param_type_inst = lazy_fn_type->param_types[fn_type_id.next_param_index]; - ZigType *param_type = ir_resolve_type(ira, param_type_inst); - if (type_is_invalid(param_type)) - return nullptr; - - if(!is_valid_param_type(param_type)){ - if(param_type->id == ZigTypeIdOpaque){ - ir_add_error(ira, param_type_inst, - buf_sprintf("parameter of opaque type '%s' not allowed", buf_ptr(¶m_type->name))); - } else { - ir_add_error(ira, param_type_inst, - buf_sprintf("parameter of type '%s' not allowed", buf_ptr(¶m_type->name))); - } - - return nullptr; - } - - switch (type_requires_comptime(ira->codegen, param_type)) { - case ReqCompTimeYes: - if (!calling_convention_allows_zig_types(fn_type_id.cc)) { - ir_add_error(ira, param_type_inst, - buf_sprintf("parameter of type '%s' not allowed in function with calling convention '%s'", - buf_ptr(¶m_type->name), calling_convention_name(fn_type_id.cc))); - return nullptr; - } - param_info->type = param_type; - fn_type_id.next_param_index += 1; - return get_generic_fn_type(ira->codegen, &fn_type_id); - case ReqCompTimeInvalid: - return nullptr; - case ReqCompTimeNo: - break; - } - if (!calling_convention_allows_zig_types(fn_type_id.cc)) { - bool has_bits; - if ((err = type_has_bits2(ira->codegen, param_type, &has_bits))) - return nullptr; - if (!has_bits) { - ir_add_error(ira, param_type_inst, - buf_sprintf("parameter of type '%s' has 0 bits; not allowed in function with calling convention '%s'", - buf_ptr(¶m_type->name), calling_convention_name(fn_type_id.cc))); - return nullptr; - } - } - param_info->type = param_type; - } - } - - if (lazy_fn_type->align_inst != nullptr) { - if (!ir_resolve_align(ira, lazy_fn_type->align_inst, nullptr, &fn_type_id.alignment)) - return nullptr; - } - - fn_type_id.return_type = ir_resolve_type(ira, lazy_fn_type->return_type); - if (type_is_invalid(fn_type_id.return_type)) - return nullptr; - if (fn_type_id.return_type->id == ZigTypeIdOpaque) { - ir_add_error_node(ira, lazy_fn_type->return_type->source_node, - buf_create_from_str("return type cannot be opaque")); - return nullptr; - } - - return get_fn_type(ira->codegen, &fn_type_id); -} - -static Error ir_resolve_lazy_raw(AstNode *source_node, ZigValue *val) { - Error err; - if (val->special != ConstValSpecialLazy) - return ErrorNone; - switch (val->data.x_lazy->id) { - case LazyValueIdInvalid: - zig_unreachable(); - case LazyValueIdTypeInfoDecls: { - LazyValueTypeInfoDecls *type_info_decls = reinterpret_cast(val->data.x_lazy); - IrAnalyze *ira = type_info_decls->ira; - - if ((err = ir_make_type_info_decls(ira, type_info_decls->source_node, val, type_info_decls->decls_scope, true))) - { - return err; - }; - - // We can't free the lazy value here, because multiple other ZigValues might be pointing to it. - return ErrorNone; - } - case LazyValueIdAlignOf: { - LazyValueAlignOf *lazy_align_of = reinterpret_cast(val->data.x_lazy); - IrAnalyze *ira = lazy_align_of->ira; - - if (lazy_align_of->target_type->value->special == ConstValSpecialStatic) { - switch (lazy_align_of->target_type->value->data.x_type->id) { - case ZigTypeIdInvalid: - zig_unreachable(); - case ZigTypeIdMetaType: - case ZigTypeIdUnreachable: - case ZigTypeIdComptimeFloat: - case ZigTypeIdComptimeInt: - case ZigTypeIdEnumLiteral: - case ZigTypeIdUndefined: - case ZigTypeIdNull: - case ZigTypeIdBoundFn: - case ZigTypeIdVoid: - case ZigTypeIdOpaque: - ir_add_error_node(ira, source_node, - buf_sprintf("no align available for type '%s'", - buf_ptr(&lazy_align_of->target_type->value->data.x_type->name))); - return ErrorSemanticAnalyzeFail; - case ZigTypeIdBool: - case ZigTypeIdInt: - case ZigTypeIdFloat: - case ZigTypeIdPointer: - case ZigTypeIdArray: - case ZigTypeIdStruct: - case ZigTypeIdOptional: - case ZigTypeIdErrorUnion: - case ZigTypeIdErrorSet: - case ZigTypeIdEnum: - case ZigTypeIdUnion: - case ZigTypeIdFn: - case ZigTypeIdVector: - case ZigTypeIdFnFrame: - case ZigTypeIdAnyFrame: - break; - } - } - - uint32_t align_in_bytes; - if ((err = type_val_resolve_abi_align(ira->codegen, source_node, - lazy_align_of->target_type->value, &align_in_bytes))) - { - return err; - } - - val->special = ConstValSpecialStatic; - assert(val->type->id == ZigTypeIdComptimeInt || val->type->id == ZigTypeIdInt); - bigint_init_unsigned(&val->data.x_bigint, align_in_bytes); - - // We can't free the lazy value here, because multiple other ZigValues might be pointing to it. - return ErrorNone; - } - case LazyValueIdSizeOf: { - LazyValueSizeOf *lazy_size_of = reinterpret_cast(val->data.x_lazy); - IrAnalyze *ira = lazy_size_of->ira; - - if (lazy_size_of->target_type->value->special == ConstValSpecialStatic) { - switch (lazy_size_of->target_type->value->data.x_type->id) { - case ZigTypeIdInvalid: // handled above - zig_unreachable(); - case ZigTypeIdUnreachable: - case ZigTypeIdUndefined: - case ZigTypeIdNull: - case ZigTypeIdBoundFn: - case ZigTypeIdOpaque: - ir_add_error_node(ira, lazy_size_of->target_type->source_node, - buf_sprintf("no size available for type '%s'", - buf_ptr(&lazy_size_of->target_type->value->data.x_type->name))); - return ErrorSemanticAnalyzeFail; - case ZigTypeIdMetaType: - case ZigTypeIdEnumLiteral: - case ZigTypeIdComptimeFloat: - case ZigTypeIdComptimeInt: - case ZigTypeIdVoid: - case ZigTypeIdBool: - case ZigTypeIdInt: - case ZigTypeIdFloat: - case ZigTypeIdPointer: - case ZigTypeIdArray: - case ZigTypeIdStruct: - case ZigTypeIdOptional: - case ZigTypeIdErrorUnion: - case ZigTypeIdErrorSet: - case ZigTypeIdEnum: - case ZigTypeIdUnion: - case ZigTypeIdFn: - case ZigTypeIdVector: - case ZigTypeIdFnFrame: - case ZigTypeIdAnyFrame: - break; - } - } - - size_t abi_size; - size_t size_in_bits; - if ((err = type_val_resolve_abi_size(ira->codegen, source_node, lazy_size_of->target_type->value, - &abi_size, &size_in_bits))) - { - return err; - } - - val->special = ConstValSpecialStatic; - assert(val->type->id == ZigTypeIdComptimeInt || val->type->id == ZigTypeIdInt); - if (lazy_size_of->bit_size) - bigint_init_unsigned(&val->data.x_bigint, size_in_bits); - else - bigint_init_unsigned(&val->data.x_bigint, abi_size); - - // We can't free the lazy value here, because multiple other ZigValues might be pointing to it. - return ErrorNone; - } - case LazyValueIdSliceType: { - LazyValueSliceType *lazy_slice_type = reinterpret_cast(val->data.x_lazy); - IrAnalyze *ira = lazy_slice_type->ira; - - ZigType *elem_type = ir_resolve_type(ira, lazy_slice_type->elem_type); - if (type_is_invalid(elem_type)) - return ErrorSemanticAnalyzeFail; - - ZigValue *sentinel_val; - if (lazy_slice_type->sentinel != nullptr) { - if (type_is_invalid(lazy_slice_type->sentinel->value->type)) - return ErrorSemanticAnalyzeFail; - Stage1AirInst *sentinel = ir_implicit_cast(ira, lazy_slice_type->sentinel, elem_type); - if (type_is_invalid(sentinel->value->type)) - return ErrorSemanticAnalyzeFail; - sentinel_val = ir_resolve_const(ira, sentinel, UndefBad); - if (sentinel_val == nullptr) - return ErrorSemanticAnalyzeFail; - } else { - sentinel_val = nullptr; - } - - uint32_t align_bytes = 0; - if (lazy_slice_type->align_inst != nullptr) { - if (!ir_resolve_align(ira, lazy_slice_type->align_inst, elem_type, &align_bytes)) - return ErrorSemanticAnalyzeFail; - } - - switch (elem_type->id) { - case ZigTypeIdInvalid: // handled above - zig_unreachable(); - case ZigTypeIdUnreachable: - case ZigTypeIdUndefined: - case ZigTypeIdNull: - case ZigTypeIdOpaque: - ir_add_error_node(ira, lazy_slice_type->elem_type->source_node, - buf_sprintf("slice of type '%s' not allowed", buf_ptr(&elem_type->name))); - return ErrorSemanticAnalyzeFail; - case ZigTypeIdMetaType: - case ZigTypeIdVoid: - case ZigTypeIdBool: - case ZigTypeIdInt: - case ZigTypeIdFloat: - case ZigTypeIdPointer: - case ZigTypeIdArray: - case ZigTypeIdStruct: - case ZigTypeIdComptimeFloat: - case ZigTypeIdComptimeInt: - case ZigTypeIdEnumLiteral: - case ZigTypeIdOptional: - case ZigTypeIdErrorUnion: - case ZigTypeIdErrorSet: - case ZigTypeIdEnum: - case ZigTypeIdUnion: - case ZigTypeIdFn: - case ZigTypeIdBoundFn: - case ZigTypeIdVector: - case ZigTypeIdFnFrame: - case ZigTypeIdAnyFrame: - break; - } - - ResolveStatus needed_status = (align_bytes == 0) ? - ResolveStatusZeroBitsKnown : ResolveStatusAlignmentKnown; - if ((err = type_resolve(ira->codegen, elem_type, needed_status))) - return err; - ZigType *slice_ptr_type = get_pointer_to_type_extra2(ira->codegen, elem_type, - lazy_slice_type->is_const, lazy_slice_type->is_volatile, - PtrLenUnknown, - align_bytes, - 0, 0, lazy_slice_type->is_allowzero, - VECTOR_INDEX_NONE, nullptr, sentinel_val); - val->special = ConstValSpecialStatic; - assert(val->type->id == ZigTypeIdMetaType); - val->data.x_type = get_slice_type(ira->codegen, slice_ptr_type); - - // We can't free the lazy value here, because multiple other ZigValues might be pointing to it. - return ErrorNone; - } - case LazyValueIdPtrType: { - LazyValuePtrType *lazy_ptr_type = reinterpret_cast(val->data.x_lazy); - IrAnalyze *ira = lazy_ptr_type->ira; - - ZigType *elem_type = ir_resolve_type(ira, lazy_ptr_type->elem_type); - if (type_is_invalid(elem_type)) - return ErrorSemanticAnalyzeFail; - - ZigValue *sentinel_val; - if (lazy_ptr_type->sentinel != nullptr) { - if (type_is_invalid(lazy_ptr_type->sentinel->value->type)) - return ErrorSemanticAnalyzeFail; - Stage1AirInst *sentinel = ir_implicit_cast(ira, lazy_ptr_type->sentinel, elem_type); - if (type_is_invalid(sentinel->value->type)) - return ErrorSemanticAnalyzeFail; - sentinel_val = ir_resolve_const(ira, sentinel, UndefBad); - if (sentinel_val == nullptr) - return ErrorSemanticAnalyzeFail; - } else { - sentinel_val = nullptr; - } - - uint32_t align_bytes = 0; - if (lazy_ptr_type->align_inst != nullptr) { - if (!ir_resolve_align(ira, lazy_ptr_type->align_inst, elem_type, &align_bytes)) - return ErrorSemanticAnalyzeFail; - } - - if (elem_type->id == ZigTypeIdUnreachable) { - ir_add_error_node(ira, lazy_ptr_type->elem_type->source_node, - buf_create_from_str("pointer to noreturn not allowed")); - return ErrorSemanticAnalyzeFail; - } else if (elem_type->id == ZigTypeIdOpaque && lazy_ptr_type->ptr_len == PtrLenUnknown) { - ir_add_error_node(ira, lazy_ptr_type->elem_type->source_node, - buf_create_from_str("unknown-length pointer to opaque")); - return ErrorSemanticAnalyzeFail; - } else if (lazy_ptr_type->ptr_len == PtrLenC) { - bool ok_type; - if ((err = type_allowed_in_extern(ira->codegen, elem_type, ExternPositionOther, &ok_type))) - return err; - if (!ok_type) { - ir_add_error_node(ira, lazy_ptr_type->elem_type->source_node, - buf_sprintf("C pointers cannot point to non-C-ABI-compatible type '%s'", - buf_ptr(&elem_type->name))); - return ErrorSemanticAnalyzeFail; - } else if (elem_type->id == ZigTypeIdOpaque) { - ir_add_error_node(ira, lazy_ptr_type->elem_type->source_node, - buf_sprintf("C pointers cannot point to opaque types")); - return ErrorSemanticAnalyzeFail; - } else if (lazy_ptr_type->is_allowzero) { - ir_add_error_node(ira, lazy_ptr_type->elem_type->source_node, - buf_sprintf("C pointers always allow address zero")); - return ErrorSemanticAnalyzeFail; - } - } - - if (align_bytes != 0) { - if ((err = type_resolve(ira->codegen, elem_type, ResolveStatusAlignmentKnown))) - return err; - if (!type_has_bits(ira->codegen, elem_type)) - align_bytes = 0; - } - bool allow_zero = lazy_ptr_type->is_allowzero || lazy_ptr_type->ptr_len == PtrLenC; - assert(val->type->id == ZigTypeIdMetaType); - val->data.x_type = get_pointer_to_type_extra2(ira->codegen, elem_type, - lazy_ptr_type->is_const, lazy_ptr_type->is_volatile, lazy_ptr_type->ptr_len, align_bytes, - lazy_ptr_type->bit_offset_in_host, lazy_ptr_type->host_int_bytes, - allow_zero, VECTOR_INDEX_NONE, nullptr, sentinel_val); - val->special = ConstValSpecialStatic; - - // We can't free the lazy value here, because multiple other ZigValues might be pointing to it. - return ErrorNone; - } - case LazyValueIdPtrTypeSimple: { - LazyValuePtrTypeSimple *lazy_ptr_type = reinterpret_cast(val->data.x_lazy); - IrAnalyze *ira = lazy_ptr_type->ira; - - ZigType *elem_type = ir_resolve_type(ira, lazy_ptr_type->elem_type); - if (type_is_invalid(elem_type)) - return ErrorSemanticAnalyzeFail; - - if (elem_type->id == ZigTypeIdUnreachable) { - ir_add_error_node(ira, lazy_ptr_type->elem_type->source_node, - buf_create_from_str("pointer to noreturn not allowed")); - return ErrorSemanticAnalyzeFail; - } - - assert(val->type->id == ZigTypeIdMetaType); - val->data.x_type = get_pointer_to_type_extra2(ira->codegen, elem_type, - false, false, PtrLenSingle, 0, - 0, 0, - false, VECTOR_INDEX_NONE, nullptr, nullptr); - val->special = ConstValSpecialStatic; - - // We can't free the lazy value here, because multiple other ZigValues might be pointing to it. - return ErrorNone; - } - case LazyValueIdPtrTypeSimpleConst: { - LazyValuePtrTypeSimple *lazy_ptr_type = reinterpret_cast(val->data.x_lazy); - IrAnalyze *ira = lazy_ptr_type->ira; - - ZigType *elem_type = ir_resolve_type(ira, lazy_ptr_type->elem_type); - if (type_is_invalid(elem_type)) - return ErrorSemanticAnalyzeFail; - - if (elem_type->id == ZigTypeIdUnreachable) { - ir_add_error_node(ira, lazy_ptr_type->elem_type->source_node, - buf_create_from_str("pointer to noreturn not allowed")); - return ErrorSemanticAnalyzeFail; - } - - assert(val->type->id == ZigTypeIdMetaType); - val->data.x_type = get_pointer_to_type_extra2(ira->codegen, elem_type, - true, false, PtrLenSingle, 0, - 0, 0, - false, VECTOR_INDEX_NONE, nullptr, nullptr); - val->special = ConstValSpecialStatic; - - // We can't free the lazy value here, because multiple other ZigValues might be pointing to it. - return ErrorNone; - } - case LazyValueIdArrayType: { - LazyValueArrayType *lazy_array_type = reinterpret_cast(val->data.x_lazy); - IrAnalyze *ira = lazy_array_type->ira; - - ZigType *elem_type = ir_resolve_type(ira, lazy_array_type->elem_type); - if (type_is_invalid(elem_type)) - return ErrorSemanticAnalyzeFail; - - switch (elem_type->id) { - case ZigTypeIdInvalid: // handled above - zig_unreachable(); - case ZigTypeIdUnreachable: - case ZigTypeIdUndefined: - case ZigTypeIdNull: - case ZigTypeIdOpaque: - ir_add_error_node(ira, lazy_array_type->elem_type->source_node, - buf_sprintf("array of type '%s' not allowed", - buf_ptr(&elem_type->name))); - return ErrorSemanticAnalyzeFail; - case ZigTypeIdMetaType: - case ZigTypeIdVoid: - case ZigTypeIdBool: - case ZigTypeIdInt: - case ZigTypeIdFloat: - case ZigTypeIdPointer: - case ZigTypeIdArray: - case ZigTypeIdStruct: - case ZigTypeIdComptimeFloat: - case ZigTypeIdComptimeInt: - case ZigTypeIdEnumLiteral: - case ZigTypeIdOptional: - case ZigTypeIdErrorUnion: - case ZigTypeIdErrorSet: - case ZigTypeIdEnum: - case ZigTypeIdUnion: - case ZigTypeIdFn: - case ZigTypeIdBoundFn: - case ZigTypeIdVector: - case ZigTypeIdFnFrame: - case ZigTypeIdAnyFrame: - break; - } - - // Avoid resolving the type if the total length is zero. - // Matches the logic in get_array_type and in the lazy alignment - // resolution routine. - if (lazy_array_type->length + (lazy_array_type->sentinel != nullptr) != 0) { - if ((err = type_resolve(ira->codegen, elem_type, ResolveStatusSizeKnown))) - return err; - } - - ZigValue *sentinel_val = nullptr; - if (lazy_array_type->sentinel != nullptr) { - if (type_is_invalid(lazy_array_type->sentinel->value->type)) - return ErrorSemanticAnalyzeFail; - Stage1AirInst *sentinel = ir_implicit_cast(ira, lazy_array_type->sentinel, elem_type); - if (type_is_invalid(sentinel->value->type)) - return ErrorSemanticAnalyzeFail; - sentinel_val = ir_resolve_const(ira, sentinel, UndefBad); - if (sentinel_val == nullptr) - return ErrorSemanticAnalyzeFail; - } - - assert(val->type->id == ZigTypeIdMetaType); - val->data.x_type = get_array_type(ira->codegen, elem_type, lazy_array_type->length, sentinel_val); - val->special = ConstValSpecialStatic; - - // We can't free the lazy value here, because multiple other ZigValues might be pointing to it. - return ErrorNone; - } - case LazyValueIdOptType: { - LazyValueOptType *lazy_opt_type = reinterpret_cast(val->data.x_lazy); - IrAnalyze *ira = lazy_opt_type->ira; - - ZigType *payload_type = ir_resolve_type(ira, lazy_opt_type->payload_type); - if (type_is_invalid(payload_type)) - return ErrorSemanticAnalyzeFail; - - if (payload_type->id == ZigTypeIdOpaque || payload_type->id == ZigTypeIdUnreachable) { - ir_add_error_node(ira, lazy_opt_type->payload_type->source_node, - buf_sprintf("type '%s' cannot be optional", buf_ptr(&payload_type->name))); - return ErrorSemanticAnalyzeFail; - } - - if ((err = type_resolve(ira->codegen, payload_type, ResolveStatusSizeKnown))) - return err; - - assert(val->type->id == ZigTypeIdMetaType); - val->data.x_type = get_optional_type(ira->codegen, payload_type); - val->special = ConstValSpecialStatic; - - // We can't free the lazy value here, because multiple other ZigValues might be pointing to it. - return ErrorNone; - } - case LazyValueIdFnType: { - LazyValueFnType *lazy_fn_type = reinterpret_cast(val->data.x_lazy); - IrAnalyze *ira = lazy_fn_type->ira; - ZigType *fn_type = ir_resolve_lazy_fn_type(ira, source_node, lazy_fn_type); - if (fn_type == nullptr) - return ErrorSemanticAnalyzeFail; - val->special = ConstValSpecialStatic; - assert(val->type->id == ZigTypeIdMetaType); - val->data.x_type = fn_type; - - // We can't free the lazy value here, because multiple other ZigValues might be pointing to it. - return ErrorNone; - } - case LazyValueIdErrUnionType: { - LazyValueErrUnionType *lazy_err_union_type = - reinterpret_cast(val->data.x_lazy); - IrAnalyze *ira = lazy_err_union_type->ira; - - ZigType *err_set_type = ir_resolve_type(ira, lazy_err_union_type->err_set_type); - if (type_is_invalid(err_set_type)) - return ErrorSemanticAnalyzeFail; - - ZigType *payload_type = ir_resolve_type(ira, lazy_err_union_type->payload_type); - if (type_is_invalid(payload_type)) - return ErrorSemanticAnalyzeFail; - - if (err_set_type->id != ZigTypeIdErrorSet) { - ir_add_error_node(ira, lazy_err_union_type->err_set_type->source_node, - buf_sprintf("expected error set type, found type '%s'", - buf_ptr(&err_set_type->name))); - return ErrorSemanticAnalyzeFail; - } - - if ((err = type_resolve(ira->codegen, payload_type, ResolveStatusSizeKnown))) - return ErrorSemanticAnalyzeFail; - - assert(val->type->id == ZigTypeIdMetaType); - val->data.x_type = get_error_union_type(ira->codegen, err_set_type, payload_type); - val->special = ConstValSpecialStatic; - - // We can't free the lazy value here, because multiple other ZigValues might be pointing to it. - return ErrorNone; - } - } - zig_unreachable(); -} - -static Error ir_resolve_lazy_recurse_array(AstNode *source_node, ZigValue *val, size_t len) { - Error err; - switch (val->data.x_array.special) { - case ConstArraySpecialUndef: - case ConstArraySpecialBuf: - return ErrorNone; - case ConstArraySpecialNone: - break; - } - ZigValue *elems = val->data.x_array.data.s_none.elements; - - for (size_t i = 0; i < len; i += 1) { - if ((err = ir_resolve_lazy_recurse(source_node, &elems[i]))) - return err; - } - - return ErrorNone; -} - -static Error ir_resolve_lazy_recurse(AstNode *source_node, ZigValue *val) { - Error err; - if ((err = ir_resolve_lazy_raw(source_node, val))) - return err; - assert(val->special != ConstValSpecialRuntime); - assert(val->special != ConstValSpecialLazy); - if (val->special != ConstValSpecialStatic) - return ErrorNone; - switch (val->type->id) { - case ZigTypeIdOpaque: - case ZigTypeIdEnum: - case ZigTypeIdMetaType: - case ZigTypeIdBool: - case ZigTypeIdVoid: - case ZigTypeIdComptimeFloat: - case ZigTypeIdInt: - case ZigTypeIdComptimeInt: - case ZigTypeIdEnumLiteral: - case ZigTypeIdErrorSet: - case ZigTypeIdUndefined: - case ZigTypeIdNull: - case ZigTypeIdPointer: - case ZigTypeIdFn: - case ZigTypeIdAnyFrame: - case ZigTypeIdBoundFn: - case ZigTypeIdInvalid: - case ZigTypeIdUnreachable: - case ZigTypeIdFloat: - return ErrorNone; - case ZigTypeIdFnFrame: - zig_panic("TODO: ir_resolve_lazy_recurse ZigTypeIdFnFrame"); - case ZigTypeIdUnion: { - ConstUnionValue *union_val = &val->data.x_union; - return ir_resolve_lazy_recurse(source_node, union_val->payload); - } - case ZigTypeIdVector: - return ir_resolve_lazy_recurse_array(source_node, val, val->type->data.vector.len); - case ZigTypeIdArray: - return ir_resolve_lazy_recurse_array(source_node, val, val->type->data.array.len); - case ZigTypeIdStruct: - for (size_t i = 0; i < val->type->data.structure.src_field_count; i += 1) { - ZigValue *field = val->data.x_struct.fields[i]; - if (val->type->data.structure.fields[i]->is_comptime) { - // comptime struct fields do not need to be resolved because - // they are not part of the value. - continue; - } - if ((err = ir_resolve_lazy_recurse(source_node, field))) - return err; - } - return ErrorNone; - case ZigTypeIdOptional: - if (get_src_ptr_type(val->type) != nullptr) - return ErrorNone; - if (val->data.x_optional == nullptr) - return ErrorNone; - - return ir_resolve_lazy_recurse(source_node, val->data.x_optional); - case ZigTypeIdErrorUnion: { - bool is_err = val->data.x_err_union.error_set->data.x_err_set != nullptr; - if (is_err) { - return ir_resolve_lazy_recurse(source_node, val->data.x_err_union.error_set); - } else { - return ir_resolve_lazy_recurse(source_node, val->data.x_err_union.payload); - } - } - } - zig_unreachable(); -} - -Error ir_resolve_lazy(CodeGen *codegen, AstNode *source_node, ZigValue *val) { - Error err; - if ((err = ir_resolve_lazy_raw(source_node, val))) { - return err; - } - if (type_is_invalid(val->type)) { - return ErrorSemanticAnalyzeFail; - } - return ErrorNone; -} - -void Stage1AirInst::src() { - Stage1AirInst *inst = this; - if (inst->source_node != nullptr) { - inst->source_node->src(); - } else { - fprintf(stderr, "(null source node)\n"); - } -} - -void Stage1AirInst::dump() { - Stage1AirInst *inst = this; - inst->src(); - if (inst->scope == nullptr) { - fprintf(stderr, "(null scope)\n"); - } else { - ir_print_inst_gen(inst->scope->codegen, stderr, inst, 0); - } -} - -void IrAnalyze::dump() { - ir_print_gen(this->codegen, stderr, this->new_irb.exec, 0); - if (this->new_irb.current_basic_block != nullptr) { - fprintf(stderr, "Current basic block:\n"); - ir_print_basic_block_gen(this->codegen, stderr, this->new_irb.current_basic_block, 1); - } -} diff --git a/src/stage1/ir.hpp b/src/stage1/ir.hpp deleted file mode 100644 index 6a998adf4022..000000000000 --- a/src/stage1/ir.hpp +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (c) 2016 Andrew Kelley - * - * This file is part of zig, which is MIT licensed. - * See http://opensource.org/licenses/MIT - */ - -#ifndef ZIG_IR_HPP -#define ZIG_IR_HPP - -#include "all_types.hpp" - -Stage1AirInst *ir_create_alloca(CodeGen *g, Scope *scope, AstNode *source_node, ZigFn *fn, - ZigType *var_type, const char *name_hint); - -Error ir_eval_const_value(CodeGen *codegen, Scope *scope, AstNode *node, - ZigValue *return_ptr, size_t *backward_branch_count, size_t *backward_branch_quota, - ZigFn *fn_entry, Buf *c_import_buf, AstNode *source_node, Buf *exec_name, - Stage1Air *parent_exec, AstNode *expected_type_source_node, UndefAllowed undef); - -Error ir_resolve_lazy(CodeGen *codegen, AstNode *source_node, ZigValue *val); - -ZigType *ir_analyze(CodeGen *codegen, Stage1Zir *stage1_zir, Stage1Air *stage1_air, - size_t *backward_branch_count, size_t *backward_branch_quota, - ZigType *expected_type, AstNode *expected_type_source_node, ZigValue *result_ptr, - ZigFn *fn); - -bool ir_inst_gen_has_side_effects(Stage1AirInst *inst); - -struct IrAnalyze; -ZigValue *const_ptr_pointee(IrAnalyze *ira, CodeGen *codegen, ZigValue *const_val, - AstNode *source_node); - -#endif diff --git a/src/stage1/ir_print.cpp b/src/stage1/ir_print.cpp deleted file mode 100644 index c86a0b975edb..000000000000 --- a/src/stage1/ir_print.cpp +++ /dev/null @@ -1,3543 +0,0 @@ -/* - * Copyright (c) 2016 Andrew Kelley - * - * This file is part of zig, which is MIT licensed. - * See http://opensource.org/licenses/MIT - */ - -#include "all_types.hpp" -#include "analyze.hpp" -#include "ir.hpp" -#include "astgen.hpp" -#include "ir_print.hpp" -#include "os.hpp" - -static uint32_t hash_inst_src_ptr(Stage1ZirInst* instruction) { - return (uint32_t)(uintptr_t)instruction; -} - -static uint32_t hash_inst_gen_ptr(Stage1AirInst* instruction) { - return (uint32_t)(uintptr_t)instruction; -} - -static bool inst_src_ptr_eql(Stage1ZirInst* a, Stage1ZirInst* b) { - return a == b; -} - -static bool inst_gen_ptr_eql(Stage1AirInst* a, Stage1AirInst* b) { - return a == b; -} - -using InstSetSrc = HashMap; -using InstSetGen = HashMap; -using InstListSrc = ZigList; -using InstListGen = ZigList; - -struct IrPrintSrc { - CodeGen *codegen; - FILE *f; - int indent; - int indent_size; -}; - -struct IrPrintGen { - CodeGen *codegen; - FILE *f; - int indent; - int indent_size; - - // When printing pass 2 instructions referenced var instructions are not - // present in the instruction list. Thus we track which instructions - // are printed (per executable) and after each pass 2 instruction those - // var instructions are rendered in a trailing fashion. - InstSetGen printed; - InstListGen pending; -}; - -static void ir_print_other_inst_src(IrPrintSrc *irp, Stage1ZirInst *inst); -static void ir_print_other_inst_gen(IrPrintGen *irp, Stage1AirInst *inst); - -static void ir_print_call_modifier(FILE *f, CallModifier modifier) { - switch (modifier) { - case CallModifierNone: - break; - case CallModifierNoSuspend: - fprintf(f, "nosuspend "); - break; - case CallModifierAsync: - fprintf(f, "async "); - break; - case CallModifierNeverTail: - fprintf(f, "notail "); - break; - case CallModifierNeverInline: - fprintf(f, "noinline "); - break; - case CallModifierAlwaysTail: - fprintf(f, "tail "); - break; - case CallModifierAlwaysInline: - fprintf(f, "inline "); - break; - case CallModifierCompileTime: - fprintf(f, "comptime "); - break; - case CallModifierBuiltin: - zig_unreachable(); - } -} - -const char* ir_inst_src_type_str(Stage1ZirInstId id) { - switch (id) { - case Stage1ZirInstIdInvalid: - return "SrcInvalid"; - case Stage1ZirInstIdShuffleVector: - return "SrcShuffle"; - case Stage1ZirInstIdSelect: - return "SrcSelect"; - case Stage1ZirInstIdSplat: - return "SrcSplat"; - case Stage1ZirInstIdDeclVar: - return "SrcDeclVar"; - case Stage1ZirInstIdBr: - return "SrcBr"; - case Stage1ZirInstIdCondBr: - return "SrcCondBr"; - case Stage1ZirInstIdSwitchBr: - return "SrcSwitchBr"; - case Stage1ZirInstIdSwitchVar: - return "SrcSwitchVar"; - case Stage1ZirInstIdSwitchElseVar: - return "SrcSwitchElseVar"; - case Stage1ZirInstIdSwitchTarget: - return "SrcSwitchTarget"; - case Stage1ZirInstIdPhi: - return "SrcPhi"; - case Stage1ZirInstIdUnOp: - return "SrcUnOp"; - case Stage1ZirInstIdBinOp: - return "SrcBinOp"; - case Stage1ZirInstIdMergeErrSets: - return "SrcMergeErrSets"; - case Stage1ZirInstIdLoadPtr: - return "SrcLoadPtr"; - case Stage1ZirInstIdStorePtr: - return "SrcStorePtr"; - case Stage1ZirInstIdFieldPtr: - return "SrcFieldPtr"; - case Stage1ZirInstIdElemPtr: - return "SrcElemPtr"; - case Stage1ZirInstIdVarPtr: - return "SrcVarPtr"; - case Stage1ZirInstIdCallExtra: - return "SrcCallExtra"; - case Stage1ZirInstIdAsyncCallExtra: - return "SrcAsyncCallExtra"; - case Stage1ZirInstIdCall: - return "SrcCall"; - case Stage1ZirInstIdCallArgs: - return "SrcCallArgs"; - case Stage1ZirInstIdConst: - return "SrcConst"; - case Stage1ZirInstIdReturn: - return "SrcReturn"; - case Stage1ZirInstIdContainerInitList: - return "SrcContainerInitList"; - case Stage1ZirInstIdContainerInitFields: - return "SrcContainerInitFields"; - case Stage1ZirInstIdUnreachable: - return "SrcUnreachable"; - case Stage1ZirInstIdTypeOf: - return "SrcTypeOf"; - case Stage1ZirInstIdSetCold: - return "SrcSetCold"; - case Stage1ZirInstIdSetRuntimeSafety: - return "SrcSetRuntimeSafety"; - case Stage1ZirInstIdSetFloatMode: - return "SrcSetFloatMode"; - case Stage1ZirInstIdArrayType: - return "SrcArrayType"; - case Stage1ZirInstIdAnyFrameType: - return "SrcAnyFrameType"; - case Stage1ZirInstIdSliceType: - return "SrcSliceType"; - case Stage1ZirInstIdAsm: - return "SrcAsm"; - case Stage1ZirInstIdSizeOf: - return "SrcSizeOf"; - case Stage1ZirInstIdTestNonNull: - return "SrcTestNonNull"; - case Stage1ZirInstIdOptionalUnwrapPtr: - return "SrcOptionalUnwrapPtr"; - case Stage1ZirInstIdClz: - return "SrcClz"; - case Stage1ZirInstIdCtz: - return "SrcCtz"; - case Stage1ZirInstIdPopCount: - return "SrcPopCount"; - case Stage1ZirInstIdBswap: - return "SrcBswap"; - case Stage1ZirInstIdBitReverse: - return "SrcBitReverse"; - case Stage1ZirInstIdImport: - return "SrcImport"; - case Stage1ZirInstIdCImport: - return "SrcCImport"; - case Stage1ZirInstIdCInclude: - return "SrcCInclude"; - case Stage1ZirInstIdCDefine: - return "SrcCDefine"; - case Stage1ZirInstIdCUndef: - return "SrcCUndef"; - case Stage1ZirInstIdRef: - return "SrcRef"; - case Stage1ZirInstIdCompileErr: - return "SrcCompileErr"; - case Stage1ZirInstIdCompileLog: - return "SrcCompileLog"; - case Stage1ZirInstIdErrName: - return "SrcErrName"; - case Stage1ZirInstIdEmbedFile: - return "SrcEmbedFile"; - case Stage1ZirInstIdCmpxchg: - return "SrcCmpxchg"; - case Stage1ZirInstIdFence: - return "SrcFence"; - case Stage1ZirInstIdReduce: - return "SrcReduce"; - case Stage1ZirInstIdTruncate: - return "SrcTruncate"; - case Stage1ZirInstIdIntCast: - return "SrcIntCast"; - case Stage1ZirInstIdFloatCast: - return "SrcFloatCast"; - case Stage1ZirInstIdIntToFloat: - return "SrcIntToFloat"; - case Stage1ZirInstIdFloatToInt: - return "SrcFloatToInt"; - case Stage1ZirInstIdBoolToInt: - return "SrcBoolToInt"; - case Stage1ZirInstIdVectorType: - return "SrcVectorType"; - case Stage1ZirInstIdBoolNot: - return "SrcBoolNot"; - case Stage1ZirInstIdMemset: - return "SrcMemset"; - case Stage1ZirInstIdMemcpy: - return "SrcMemcpy"; - case Stage1ZirInstIdSlice: - return "SrcSlice"; - case Stage1ZirInstIdBreakpoint: - return "SrcBreakpoint"; - case Stage1ZirInstIdReturnAddress: - return "SrcReturnAddress"; - case Stage1ZirInstIdFrameAddress: - return "SrcFrameAddress"; - case Stage1ZirInstIdFrameHandle: - return "SrcFrameHandle"; - case Stage1ZirInstIdFrameType: - return "SrcFrameType"; - case Stage1ZirInstIdFrameSize: - return "SrcFrameSize"; - case Stage1ZirInstIdAlignOf: - return "SrcAlignOf"; - case Stage1ZirInstIdOverflowOp: - return "SrcOverflowOp"; - case Stage1ZirInstIdTestErr: - return "SrcTestErr"; - case Stage1ZirInstIdMulAdd: - return "SrcMulAdd"; - case Stage1ZirInstIdFloatOp: - return "SrcFloatOp"; - case Stage1ZirInstIdUnwrapErrCode: - return "SrcUnwrapErrCode"; - case Stage1ZirInstIdUnwrapErrPayload: - return "SrcUnwrapErrPayload"; - case Stage1ZirInstIdFnProto: - return "SrcFnProto"; - case Stage1ZirInstIdTestComptime: - return "SrcTestComptime"; - case Stage1ZirInstIdPtrCast: - return "SrcPtrCast"; - case Stage1ZirInstIdBitCast: - return "SrcBitCast"; - case Stage1ZirInstIdIntToPtr: - return "SrcIntToPtr"; - case Stage1ZirInstIdPtrToInt: - return "SrcPtrToInt"; - case Stage1ZirInstIdIntToEnum: - return "SrcIntToEnum"; - case Stage1ZirInstIdEnumToInt: - return "SrcEnumToInt"; - case Stage1ZirInstIdIntToErr: - return "SrcIntToErr"; - case Stage1ZirInstIdErrToInt: - return "SrcErrToInt"; - case Stage1ZirInstIdCheckSwitchProngsUnderNo: - return "SrcCheckSwitchProngsUnderNo"; - case Stage1ZirInstIdCheckSwitchProngsUnderYes: - return "SrcCheckSwitchProngsUnderYes"; - case Stage1ZirInstIdCheckStatementIsVoid: - return "SrcCheckStatementIsVoid"; - case Stage1ZirInstIdTypeName: - return "SrcTypeName"; - case Stage1ZirInstIdDeclRef: - return "SrcDeclRef"; - case Stage1ZirInstIdPanic: - return "SrcPanic"; - case Stage1ZirInstIdTagName: - return "SrcTagName"; - case Stage1ZirInstIdFieldParentPtr: - return "SrcFieldParentPtr"; - case Stage1ZirInstIdOffsetOf: - return "SrcOffsetOf"; - case Stage1ZirInstIdBitOffsetOf: - return "SrcBitOffsetOf"; - case Stage1ZirInstIdTypeInfo: - return "SrcTypeInfo"; - case Stage1ZirInstIdType: - return "SrcType"; - case Stage1ZirInstIdHasField: - return "SrcHasField"; - case Stage1ZirInstIdSetEvalBranchQuota: - return "SrcSetEvalBranchQuota"; - case Stage1ZirInstIdPtrType: - return "SrcPtrType"; - case Stage1ZirInstIdPtrTypeSimple: - return "SrcPtrTypeSimple"; - case Stage1ZirInstIdPtrTypeSimpleConst: - return "SrcPtrTypeSimpleConst"; - case Stage1ZirInstIdAlignCast: - return "SrcAlignCast"; - case Stage1ZirInstIdImplicitCast: - return "SrcImplicitCast"; - case Stage1ZirInstIdResolveResult: - return "SrcResolveResult"; - case Stage1ZirInstIdResetResult: - return "SrcResetResult"; - case Stage1ZirInstIdSetAlignStack: - return "SrcSetAlignStack"; - case Stage1ZirInstIdArgTypeAllowVarFalse: - return "SrcArgTypeAllowVarFalse"; - case Stage1ZirInstIdArgTypeAllowVarTrue: - return "SrcArgTypeAllowVarTrue"; - case Stage1ZirInstIdExport: - return "SrcExport"; - case Stage1ZirInstIdExtern: - return "SrcExtern"; - case Stage1ZirInstIdErrorReturnTrace: - return "SrcErrorReturnTrace"; - case Stage1ZirInstIdErrorUnion: - return "SrcErrorUnion"; - case Stage1ZirInstIdAtomicRmw: - return "SrcAtomicRmw"; - case Stage1ZirInstIdAtomicLoad: - return "SrcAtomicLoad"; - case Stage1ZirInstIdAtomicStore: - return "SrcAtomicStore"; - case Stage1ZirInstIdSaveErrRetAddr: - return "SrcSaveErrRetAddr"; - case Stage1ZirInstIdAddImplicitReturnType: - return "SrcAddImplicitReturnType"; - case Stage1ZirInstIdErrSetCast: - return "SrcErrSetCast"; - case Stage1ZirInstIdCheckRuntimeScope: - return "SrcCheckRuntimeScope"; - case Stage1ZirInstIdHasDecl: - return "SrcHasDecl"; - case Stage1ZirInstIdUndeclaredIdent: - return "SrcUndeclaredIdent"; - case Stage1ZirInstIdAlloca: - return "SrcAlloca"; - case Stage1ZirInstIdEndExpr: - return "SrcEndExpr"; - case Stage1ZirInstIdUnionInitNamedField: - return "SrcUnionInitNamedField"; - case Stage1ZirInstIdSuspendBegin: - return "SrcSuspendBegin"; - case Stage1ZirInstIdSuspendFinish: - return "SrcSuspendFinish"; - case Stage1ZirInstIdAwait: - return "SrcAwaitSr"; - case Stage1ZirInstIdResume: - return "SrcResume"; - case Stage1ZirInstIdSpillBegin: - return "SrcSpillBegin"; - case Stage1ZirInstIdSpillEnd: - return "SrcSpillEnd"; - case Stage1ZirInstIdWasmMemorySize: - return "SrcWasmMemorySize"; - case Stage1ZirInstIdWasmMemoryGrow: - return "SrcWasmMemoryGrow"; - case Stage1ZirInstIdSrc: - return "SrcSrc"; - case Stage1ZirInstIdPrefetch: - return "SrcPrefetch"; - case Stage1ZirInstIdAddrSpaceCast: - return "SrcAddrSpaceCast"; - } - zig_unreachable(); -} - -const char* ir_inst_gen_type_str(Stage1AirInstId id) { - switch (id) { - case Stage1AirInstIdInvalid: - return "GenInvalid"; - case Stage1AirInstIdShuffleVector: - return "GenShuffle"; - case Stage1AirInstIdSelect: - return "GenSelect"; - case Stage1AirInstIdSplat: - return "GenSplat"; - case Stage1AirInstIdDeclVar: - return "GenDeclVar"; - case Stage1AirInstIdBr: - return "GenBr"; - case Stage1AirInstIdCondBr: - return "GenCondBr"; - case Stage1AirInstIdSwitchBr: - return "GenSwitchBr"; - case Stage1AirInstIdPhi: - return "GenPhi"; - case Stage1AirInstIdBinOp: - return "GenBinOp"; - case Stage1AirInstIdLoadPtr: - return "GenLoadPtr"; - case Stage1AirInstIdStorePtr: - return "GenStorePtr"; - case Stage1AirInstIdVectorStoreElem: - return "GenVectorStoreElem"; - case Stage1AirInstIdStructFieldPtr: - return "GenStructFieldPtr"; - case Stage1AirInstIdUnionFieldPtr: - return "GenUnionFieldPtr"; - case Stage1AirInstIdElemPtr: - return "GenElemPtr"; - case Stage1AirInstIdVarPtr: - return "GenVarPtr"; - case Stage1AirInstIdReturnPtr: - return "GenReturnPtr"; - case Stage1AirInstIdCall: - return "GenCall"; - case Stage1AirInstIdConst: - return "GenConst"; - case Stage1AirInstIdReturn: - return "GenReturn"; - case Stage1AirInstIdCast: - return "GenCast"; - case Stage1AirInstIdUnreachable: - return "GenUnreachable"; - case Stage1AirInstIdAsm: - return "GenAsm"; - case Stage1AirInstIdTestNonNull: - return "GenTestNonNull"; - case Stage1AirInstIdOptionalUnwrapPtr: - return "GenOptionalUnwrapPtr"; - case Stage1AirInstIdOptionalWrap: - return "GenOptionalWrap"; - case Stage1AirInstIdUnionTag: - return "GenUnionTag"; - case Stage1AirInstIdClz: - return "GenClz"; - case Stage1AirInstIdCtz: - return "GenCtz"; - case Stage1AirInstIdPopCount: - return "GenPopCount"; - case Stage1AirInstIdBswap: - return "GenBswap"; - case Stage1AirInstIdBitReverse: - return "GenBitReverse"; - case Stage1AirInstIdRef: - return "GenRef"; - case Stage1AirInstIdErrName: - return "GenErrName"; - case Stage1AirInstIdCmpxchg: - return "GenCmpxchg"; - case Stage1AirInstIdFence: - return "GenFence"; - case Stage1AirInstIdReduce: - return "GenReduce"; - case Stage1AirInstIdTruncate: - return "GenTruncate"; - case Stage1AirInstIdBoolNot: - return "GenBoolNot"; - case Stage1AirInstIdMemset: - return "GenMemset"; - case Stage1AirInstIdMemcpy: - return "GenMemcpy"; - case Stage1AirInstIdSlice: - return "GenSlice"; - case Stage1AirInstIdBreakpoint: - return "GenBreakpoint"; - case Stage1AirInstIdReturnAddress: - return "GenReturnAddress"; - case Stage1AirInstIdFrameAddress: - return "GenFrameAddress"; - case Stage1AirInstIdFrameHandle: - return "GenFrameHandle"; - case Stage1AirInstIdFrameSize: - return "GenFrameSize"; - case Stage1AirInstIdOverflowOp: - return "GenOverflowOp"; - case Stage1AirInstIdTestErr: - return "GenTestErr"; - case Stage1AirInstIdMulAdd: - return "GenMulAdd"; - case Stage1AirInstIdFloatOp: - return "GenFloatOp"; - case Stage1AirInstIdUnwrapErrCode: - return "GenUnwrapErrCode"; - case Stage1AirInstIdUnwrapErrPayload: - return "GenUnwrapErrPayload"; - case Stage1AirInstIdErrWrapCode: - return "GenErrWrapCode"; - case Stage1AirInstIdErrWrapPayload: - return "GenErrWrapPayload"; - case Stage1AirInstIdPtrCast: - return "GenPtrCast"; - case Stage1AirInstIdBitCast: - return "GenBitCast"; - case Stage1AirInstIdWidenOrShorten: - return "GenWidenOrShorten"; - case Stage1AirInstIdIntToPtr: - return "GenIntToPtr"; - case Stage1AirInstIdPtrToInt: - return "GenPtrToInt"; - case Stage1AirInstIdIntToEnum: - return "GenIntToEnum"; - case Stage1AirInstIdIntToErr: - return "GenIntToErr"; - case Stage1AirInstIdErrToInt: - return "GenErrToInt"; - case Stage1AirInstIdPanic: - return "GenPanic"; - case Stage1AirInstIdTagName: - return "GenTagName"; - case Stage1AirInstIdFieldParentPtr: - return "GenFieldParentPtr"; - case Stage1AirInstIdAlignCast: - return "GenAlignCast"; - case Stage1AirInstIdErrorReturnTrace: - return "GenErrorReturnTrace"; - case Stage1AirInstIdAtomicRmw: - return "GenAtomicRmw"; - case Stage1AirInstIdAtomicLoad: - return "GenAtomicLoad"; - case Stage1AirInstIdAtomicStore: - return "GenAtomicStore"; - case Stage1AirInstIdSaveErrRetAddr: - return "GenSaveErrRetAddr"; - case Stage1AirInstIdVectorToArray: - return "GenVectorToArray"; - case Stage1AirInstIdArrayToVector: - return "GenArrayToVector"; - case Stage1AirInstIdAssertZero: - return "GenAssertZero"; - case Stage1AirInstIdAssertNonNull: - return "GenAssertNonNull"; - case Stage1AirInstIdAlloca: - return "GenAlloca"; - case Stage1AirInstIdPtrOfArrayToSlice: - return "GenPtrOfArrayToSlice"; - case Stage1AirInstIdSuspendBegin: - return "GenSuspendBegin"; - case Stage1AirInstIdSuspendFinish: - return "GenSuspendFinish"; - case Stage1AirInstIdAwait: - return "GenAwait"; - case Stage1AirInstIdResume: - return "GenResume"; - case Stage1AirInstIdSpillBegin: - return "GenSpillBegin"; - case Stage1AirInstIdSpillEnd: - return "GenSpillEnd"; - case Stage1AirInstIdVectorExtractElem: - return "GenVectorExtractElem"; - case Stage1AirInstIdBinaryNot: - return "GenBinaryNot"; - case Stage1AirInstIdNegation: - return "GenNegation"; - case Stage1AirInstIdWasmMemorySize: - return "GenWasmMemorySize"; - case Stage1AirInstIdWasmMemoryGrow: - return "GenWasmMemoryGrow"; - case Stage1AirInstIdExtern: - return "GenExtern"; - case Stage1AirInstIdPrefetch: - return "GenPrefetch"; - } - zig_unreachable(); -} - -static void ir_print_indent_src(IrPrintSrc *irp) { - for (int i = 0; i < irp->indent; i += 1) { - fprintf(irp->f, " "); - } -} - -static void ir_print_indent_gen(IrPrintGen *irp) { - for (int i = 0; i < irp->indent; i += 1) { - fprintf(irp->f, " "); - } -} - -static void ir_print_prefix_src(IrPrintSrc *irp, Stage1ZirInst *instruction, bool trailing) { - ir_print_indent_src(irp); - const char mark = trailing ? ':' : '#'; - const char *type_name; - if (instruction->id == Stage1ZirInstIdConst) { - type_name = buf_ptr(&reinterpret_cast(instruction)->value->type->name); - } else { - type_name = "(unknown)"; - } - const char *ref_count = ir_inst_src_has_side_effects(instruction) ? - "-" : buf_ptr(buf_sprintf("%" PRIu32 "", instruction->ref_count)); - fprintf(irp->f, "%c%-3" PRIu32 "| %-22s| %-12s| %-2s| ", mark, instruction->debug_id, - ir_inst_src_type_str(instruction->id), type_name, ref_count); -} - -static void ir_print_prefix_gen(IrPrintGen *irp, Stage1AirInst *instruction, bool trailing) { - ir_print_indent_gen(irp); - const char mark = trailing ? ':' : '#'; - const char *type_name = instruction->value->type ? buf_ptr(&instruction->value->type->name) : "(unknown)"; - const char *ref_count = ir_inst_gen_has_side_effects(instruction) ? - "-" : buf_ptr(buf_sprintf("%" PRIu32 "", instruction->ref_count)); - fprintf(irp->f, "%c%-3" PRIu32 "| %-22s| %-12s| %-2s| ", mark, instruction->debug_id, - ir_inst_gen_type_str(instruction->id), type_name, ref_count); -} - -static void ir_print_var_src(IrPrintSrc *irp, Stage1ZirInst *inst) { - fprintf(irp->f, "#%" PRIu32 "", inst->debug_id); -} - -static void ir_print_var_gen(IrPrintGen *irp, Stage1AirInst *inst) { - fprintf(irp->f, "#%" PRIu32 "", inst->debug_id); - if (irp->printed.maybe_get(inst) == nullptr) { - irp->printed.put(inst, 0); - irp->pending.append(inst); - } -} - -static void ir_print_other_inst_src(IrPrintSrc *irp, Stage1ZirInst *inst) { - if (inst == nullptr) { - fprintf(irp->f, "(null)"); - return; - } - ir_print_var_src(irp, inst); -} - -static void ir_print_const_value(CodeGen *g, FILE *f, ZigValue *const_val) { - Buf buf = BUF_INIT; - buf_resize(&buf, 0); - render_const_value(g, &buf, const_val); - fprintf(f, "%s", buf_ptr(&buf)); -} - -static void ir_print_other_inst_gen(IrPrintGen *irp, Stage1AirInst *inst) { - if (inst == nullptr) { - fprintf(irp->f, "(null)"); - } else { - ir_print_var_gen(irp, inst); - } -} - -static void ir_print_other_block(IrPrintSrc *irp, Stage1ZirBasicBlock *bb) { - if (bb == nullptr) { - fprintf(irp->f, "(null block)"); - } else { - fprintf(irp->f, "$%s_%" PRIu32 "", bb->name_hint, bb->debug_id); - } -} - -static void ir_print_other_block_gen(IrPrintGen *irp, Stage1AirBasicBlock *bb) { - if (bb == nullptr) { - fprintf(irp->f, "(null block)"); - } else { - fprintf(irp->f, "$%s_%" PRIu32 "", bb->name_hint, bb->debug_id); - } -} - -static void ir_print_return_src(IrPrintSrc *irp, Stage1ZirInstReturn *inst) { - fprintf(irp->f, "return "); - ir_print_other_inst_src(irp, inst->operand); -} - -static void ir_print_return_gen(IrPrintGen *irp, Stage1AirInstReturn *inst) { - fprintf(irp->f, "return "); - ir_print_other_inst_gen(irp, inst->operand); -} - -static void ir_print_const(IrPrintSrc *irp, Stage1ZirInstConst *const_instruction) { - ir_print_const_value(irp->codegen, irp->f, const_instruction->value); -} - -static void ir_print_const(IrPrintGen *irp, Stage1AirInstConst *const_instruction) { - ir_print_const_value(irp->codegen, irp->f, const_instruction->base.value); -} - -static const char *ir_bin_op_id_str(IrBinOp op_id) { - switch (op_id) { - case IrBinOpInvalid: - zig_unreachable(); - case IrBinOpBoolOr: - return "BoolOr"; - case IrBinOpBoolAnd: - return "BoolAnd"; - case IrBinOpCmpEq: - return "=="; - case IrBinOpCmpNotEq: - return "!="; - case IrBinOpCmpLessThan: - return "<"; - case IrBinOpCmpGreaterThan: - return ">"; - case IrBinOpCmpLessOrEq: - return "<="; - case IrBinOpCmpGreaterOrEq: - return ">="; - case IrBinOpBinOr: - return "|"; - case IrBinOpBinXor: - return "^"; - case IrBinOpBinAnd: - return "&"; - case IrBinOpBitShiftLeftLossy: - return "<<"; - case IrBinOpBitShiftLeftExact: - return "@shlExact"; - case IrBinOpBitShiftRightLossy: - return ">>"; - case IrBinOpBitShiftRightExact: - return "@shrExact"; - case IrBinOpAdd: - return "+"; - case IrBinOpAddWrap: - return "+%"; - case IrBinOpSub: - return "-"; - case IrBinOpSubWrap: - return "-%"; - case IrBinOpMult: - return "*"; - case IrBinOpMultWrap: - return "*%"; - case IrBinOpDivUnspecified: - return "/"; - case IrBinOpDivTrunc: - return "@divTrunc"; - case IrBinOpDivFloor: - return "@divFloor"; - case IrBinOpDivExact: - return "@divExact"; - case IrBinOpRemUnspecified: - return "%"; - case IrBinOpRemRem: - return "@rem"; - case IrBinOpRemMod: - return "@mod"; - case IrBinOpArrayCat: - return "++"; - case IrBinOpArrayMult: - return "**"; - case IrBinOpMax: - return "@max"; - case IrBinOpMin: - return "@min"; - case IrBinOpAddSat: - return "@addWithSaturation"; - case IrBinOpSubSat: - return "@subWithSaturation"; - case IrBinOpMultSat: - return "@mulWithSaturation"; - case IrBinOpShlSat: - return "@shlWithSaturation"; - } - zig_unreachable(); -} - -static const char *ir_un_op_id_str(IrUnOp op_id) { - switch (op_id) { - case IrUnOpInvalid: - zig_unreachable(); - case IrUnOpBinNot: - return "~"; - case IrUnOpNegation: - return "-"; - case IrUnOpNegationWrap: - return "-%"; - case IrUnOpDereference: - return "*"; - case IrUnOpOptional: - return "?"; - } - zig_unreachable(); -} - -static void ir_print_un_op(IrPrintSrc *irp, Stage1ZirInstUnOp *inst) { - fprintf(irp->f, "%s ", ir_un_op_id_str(inst->op_id)); - ir_print_other_inst_src(irp, inst->value); -} - -static void ir_print_bin_op(IrPrintSrc *irp, Stage1ZirInstBinOp *bin_op_instruction) { - ir_print_other_inst_src(irp, bin_op_instruction->op1); - fprintf(irp->f, " %s ", ir_bin_op_id_str(bin_op_instruction->op_id)); - ir_print_other_inst_src(irp, bin_op_instruction->op2); - if (!bin_op_instruction->safety_check_on) { - fprintf(irp->f, " // no safety"); - } -} - -static void ir_print_bin_op(IrPrintGen *irp, Stage1AirInstBinOp *bin_op_instruction) { - ir_print_other_inst_gen(irp, bin_op_instruction->op1); - fprintf(irp->f, " %s ", ir_bin_op_id_str(bin_op_instruction->op_id)); - ir_print_other_inst_gen(irp, bin_op_instruction->op2); - if (!bin_op_instruction->safety_check_on) { - fprintf(irp->f, " // no safety"); - } -} - -static void ir_print_merge_err_sets(IrPrintSrc *irp, Stage1ZirInstMergeErrSets *instruction) { - ir_print_other_inst_src(irp, instruction->op1); - fprintf(irp->f, " || "); - ir_print_other_inst_src(irp, instruction->op2); - if (instruction->type_name != nullptr) { - fprintf(irp->f, " // name=%s", buf_ptr(instruction->type_name)); - } -} - -static void ir_print_decl_var_src(IrPrintSrc *irp, Stage1ZirInstDeclVar *decl_var_instruction) { - const char *var_or_const = decl_var_instruction->var->gen_is_const ? "const" : "var"; - const char *name = decl_var_instruction->var->name; - if (decl_var_instruction->var_type) { - fprintf(irp->f, "%s %s: ", var_or_const, name); - ir_print_other_inst_src(irp, decl_var_instruction->var_type); - fprintf(irp->f, " "); - } else { - fprintf(irp->f, "%s %s ", var_or_const, name); - } - if (decl_var_instruction->align_value) { - fprintf(irp->f, "align "); - ir_print_other_inst_src(irp, decl_var_instruction->align_value); - fprintf(irp->f, " "); - } - fprintf(irp->f, "= "); - ir_print_other_inst_src(irp, decl_var_instruction->ptr); - if (decl_var_instruction->var->is_comptime != nullptr) { - fprintf(irp->f, " // comptime = "); - ir_print_other_inst_src(irp, decl_var_instruction->var->is_comptime); - } -} - -static const char *cast_op_str(CastOp op) { - switch (op) { - case CastOpNoCast: return "NoCast"; - case CastOpNoop: return "NoOp"; - case CastOpIntToFloat: return "IntToFloat"; - case CastOpFloatToInt: return "FloatToInt"; - case CastOpBoolToInt: return "BoolToInt"; - case CastOpNumLitToConcrete: return "NumLitToConcrete"; - case CastOpErrSet: return "ErrSet"; - case CastOpBitCast: return "BitCast"; - } - zig_unreachable(); -} - -static void ir_print_cast(IrPrintGen *irp, Stage1AirInstCast *cast_instruction) { - fprintf(irp->f, "%s cast ", cast_op_str(cast_instruction->cast_op)); - ir_print_other_inst_gen(irp, cast_instruction->value); -} - -static void ir_print_result_loc_var(IrPrintSrc *irp, ResultLocVar *result_loc_var) { - fprintf(irp->f, "var("); - ir_print_other_inst_src(irp, result_loc_var->base.source_instruction); - fprintf(irp->f, ")"); -} - -static void ir_print_result_loc_instruction(IrPrintSrc *irp, ResultLocInstruction *result_loc_inst) { - fprintf(irp->f, "inst("); - ir_print_other_inst_src(irp, result_loc_inst->base.source_instruction); - fprintf(irp->f, ")"); -} - -static void ir_print_result_loc_peer(IrPrintSrc *irp, ResultLocPeer *result_loc_peer) { - fprintf(irp->f, "peer(next="); - ir_print_other_block(irp, result_loc_peer->next_bb); - fprintf(irp->f, ")"); -} - -static void ir_print_result_loc_bit_cast(IrPrintSrc *irp, ResultLocBitCast *result_loc_bit_cast) { - fprintf(irp->f, "bitcast(ty="); - ir_print_other_inst_src(irp, result_loc_bit_cast->base.source_instruction); - fprintf(irp->f, ")"); -} - -static void ir_print_result_loc_cast(IrPrintSrc *irp, ResultLocCast *result_loc_cast) { - fprintf(irp->f, "cast(ty="); - ir_print_other_inst_src(irp, result_loc_cast->base.source_instruction); - fprintf(irp->f, ")"); -} - -static void ir_print_result_loc(IrPrintSrc *irp, ResultLoc *result_loc) { - switch (result_loc->id) { - case ResultLocIdInvalid: - zig_unreachable(); - case ResultLocIdNone: - fprintf(irp->f, "none"); - return; - case ResultLocIdReturn: - fprintf(irp->f, "return"); - return; - case ResultLocIdVar: - return ir_print_result_loc_var(irp, (ResultLocVar *)result_loc); - case ResultLocIdInstruction: - return ir_print_result_loc_instruction(irp, (ResultLocInstruction *)result_loc); - case ResultLocIdPeer: - return ir_print_result_loc_peer(irp, (ResultLocPeer *)result_loc); - case ResultLocIdBitCast: - return ir_print_result_loc_bit_cast(irp, (ResultLocBitCast *)result_loc); - case ResultLocIdCast: - return ir_print_result_loc_cast(irp, (ResultLocCast *)result_loc); - case ResultLocIdPeerParent: - fprintf(irp->f, "peer_parent"); - return; - } - zig_unreachable(); -} - -static void ir_print_call_extra(IrPrintSrc *irp, Stage1ZirInstCallExtra *instruction) { - fprintf(irp->f, "opts="); - ir_print_other_inst_src(irp, instruction->options); - fprintf(irp->f, ", fn="); - ir_print_other_inst_src(irp, instruction->fn_ref); - fprintf(irp->f, ", args="); - ir_print_other_inst_src(irp, instruction->args); - fprintf(irp->f, ", result="); - ir_print_result_loc(irp, instruction->result_loc); -} - -static void ir_print_async_call_extra(IrPrintSrc *irp, Stage1ZirInstAsyncCallExtra *instruction) { - fprintf(irp->f, "modifier="); - ir_print_call_modifier(irp->f, instruction->modifier); - fprintf(irp->f, ", fn="); - ir_print_other_inst_src(irp, instruction->fn_ref); - if (instruction->ret_ptr != nullptr) { - fprintf(irp->f, ", ret_ptr="); - ir_print_other_inst_src(irp, instruction->ret_ptr); - } - fprintf(irp->f, ", new_stack="); - ir_print_other_inst_src(irp, instruction->new_stack); - fprintf(irp->f, ", args="); - ir_print_other_inst_src(irp, instruction->args); - fprintf(irp->f, ", result="); - ir_print_result_loc(irp, instruction->result_loc); -} - -static void ir_print_call_args(IrPrintSrc *irp, Stage1ZirInstCallArgs *instruction) { - fprintf(irp->f, "opts="); - ir_print_other_inst_src(irp, instruction->options); - fprintf(irp->f, ", fn="); - ir_print_other_inst_src(irp, instruction->fn_ref); - fprintf(irp->f, ", args=("); - for (size_t i = 0; i < instruction->args_len; i += 1) { - Stage1ZirInst *arg = instruction->args_ptr[i]; - if (i != 0) - fprintf(irp->f, ", "); - ir_print_other_inst_src(irp, arg); - } - fprintf(irp->f, "), result="); - ir_print_result_loc(irp, instruction->result_loc); -} - -static void ir_print_call_src(IrPrintSrc *irp, Stage1ZirInstCall *call_instruction) { - ir_print_call_modifier(irp->f, call_instruction->modifier); - if (call_instruction->fn_entry) { - fprintf(irp->f, "%s", buf_ptr(&call_instruction->fn_entry->symbol_name)); - } else { - assert(call_instruction->fn_ref); - ir_print_other_inst_src(irp, call_instruction->fn_ref); - } - fprintf(irp->f, "("); - for (size_t i = 0; i < call_instruction->arg_count; i += 1) { - Stage1ZirInst *arg = call_instruction->args[i]; - if (i != 0) - fprintf(irp->f, ", "); - ir_print_other_inst_src(irp, arg); - } - fprintf(irp->f, ")result="); - ir_print_result_loc(irp, call_instruction->result_loc); -} - -static void ir_print_call_gen(IrPrintGen *irp, Stage1AirInstCall *call_instruction) { - ir_print_call_modifier(irp->f, call_instruction->modifier); - if (call_instruction->fn_entry) { - fprintf(irp->f, "%s", buf_ptr(&call_instruction->fn_entry->symbol_name)); - } else { - assert(call_instruction->fn_ref); - ir_print_other_inst_gen(irp, call_instruction->fn_ref); - } - fprintf(irp->f, "("); - for (size_t i = 0; i < call_instruction->arg_count; i += 1) { - Stage1AirInst *arg = call_instruction->args[i]; - if (i != 0) - fprintf(irp->f, ", "); - ir_print_other_inst_gen(irp, arg); - } - fprintf(irp->f, ")result="); - ir_print_other_inst_gen(irp, call_instruction->result_loc); -} - -static void ir_print_cond_br(IrPrintSrc *irp, Stage1ZirInstCondBr *inst) { - fprintf(irp->f, "if ("); - ir_print_other_inst_src(irp, inst->condition); - fprintf(irp->f, ") "); - ir_print_other_block(irp, inst->then_block); - fprintf(irp->f, " else "); - ir_print_other_block(irp, inst->else_block); - if (inst->is_comptime != nullptr) { - fprintf(irp->f, " // comptime = "); - ir_print_other_inst_src(irp, inst->is_comptime); - } -} - -static void ir_print_cond_br(IrPrintGen *irp, Stage1AirInstCondBr *inst) { - fprintf(irp->f, "if ("); - ir_print_other_inst_gen(irp, inst->condition); - fprintf(irp->f, ") "); - ir_print_other_block_gen(irp, inst->then_block); - fprintf(irp->f, " else "); - ir_print_other_block_gen(irp, inst->else_block); -} - -static void ir_print_br(IrPrintSrc *irp, Stage1ZirInstBr *br_instruction) { - fprintf(irp->f, "goto "); - ir_print_other_block(irp, br_instruction->dest_block); - if (br_instruction->is_comptime != nullptr) { - fprintf(irp->f, " // comptime = "); - ir_print_other_inst_src(irp, br_instruction->is_comptime); - } -} - -static void ir_print_br(IrPrintGen *irp, Stage1AirInstBr *inst) { - fprintf(irp->f, "goto "); - ir_print_other_block_gen(irp, inst->dest_block); -} - -static void ir_print_phi(IrPrintSrc *irp, Stage1ZirInstPhi *phi_instruction) { - assert(phi_instruction->incoming_count != 0); - assert(phi_instruction->incoming_count != SIZE_MAX); - for (size_t i = 0; i < phi_instruction->incoming_count; i += 1) { - Stage1ZirBasicBlock *incoming_block = phi_instruction->incoming_blocks[i]; - Stage1ZirInst *incoming_value = phi_instruction->incoming_values[i]; - if (i != 0) - fprintf(irp->f, " "); - ir_print_other_block(irp, incoming_block); - fprintf(irp->f, ":"); - ir_print_other_inst_src(irp, incoming_value); - } -} - -static void ir_print_phi(IrPrintGen *irp, Stage1AirInstPhi *phi_instruction) { - assert(phi_instruction->incoming_count != 0); - assert(phi_instruction->incoming_count != SIZE_MAX); - for (size_t i = 0; i < phi_instruction->incoming_count; i += 1) { - Stage1AirBasicBlock *incoming_block = phi_instruction->incoming_blocks[i]; - Stage1AirInst *incoming_value = phi_instruction->incoming_values[i]; - if (i != 0) - fprintf(irp->f, " "); - ir_print_other_block_gen(irp, incoming_block); - fprintf(irp->f, ":"); - ir_print_other_inst_gen(irp, incoming_value); - } -} - -static void ir_print_container_init_list(IrPrintSrc *irp, Stage1ZirInstContainerInitList *instruction) { - fprintf(irp->f, "{"); - if (instruction->item_count > 50) { - fprintf(irp->f, "...(%" ZIG_PRI_usize " items)...", instruction->item_count); - } else { - for (size_t i = 0; i < instruction->item_count; i += 1) { - Stage1ZirInst *result_loc = instruction->elem_result_loc_list[i]; - if (i != 0) - fprintf(irp->f, ", "); - ir_print_other_inst_src(irp, result_loc); - } - } - fprintf(irp->f, "}result="); - ir_print_other_inst_src(irp, instruction->result_loc); -} - -static void ir_print_container_init_fields(IrPrintSrc *irp, Stage1ZirInstContainerInitFields *instruction) { - fprintf(irp->f, "{"); - for (size_t i = 0; i < instruction->field_count; i += 1) { - Stage1ZirInstContainerInitFieldsField *field = &instruction->fields[i]; - const char *comma = (i == 0) ? "" : ", "; - fprintf(irp->f, "%s.%s = ", comma, buf_ptr(field->name)); - ir_print_other_inst_src(irp, field->result_loc); - } - fprintf(irp->f, "}result="); - ir_print_other_inst_src(irp, instruction->result_loc); -} - -static void ir_print_unreachable(IrPrintSrc *irp, Stage1ZirInstUnreachable *instruction) { - fprintf(irp->f, "unreachable"); -} - -static void ir_print_unreachable(IrPrintGen *irp, Stage1AirInstUnreachable *instruction) { - fprintf(irp->f, "unreachable"); -} - -static void ir_print_elem_ptr(IrPrintSrc *irp, Stage1ZirInstElemPtr *instruction) { - fprintf(irp->f, "&"); - ir_print_other_inst_src(irp, instruction->array_ptr); - fprintf(irp->f, "["); - ir_print_other_inst_src(irp, instruction->elem_index); - fprintf(irp->f, "]"); - if (!instruction->safety_check_on) { - fprintf(irp->f, " // no safety"); - } -} - -static void ir_print_elem_ptr(IrPrintGen *irp, Stage1AirInstElemPtr *instruction) { - fprintf(irp->f, "&"); - ir_print_other_inst_gen(irp, instruction->array_ptr); - fprintf(irp->f, "["); - ir_print_other_inst_gen(irp, instruction->elem_index); - fprintf(irp->f, "]"); - if (!instruction->safety_check_on) { - fprintf(irp->f, " // no safety"); - } -} - -static void ir_print_var_ptr(IrPrintSrc *irp, Stage1ZirInstVarPtr *instruction) { - fprintf(irp->f, "&%s", instruction->var->name); -} - -static void ir_print_var_ptr(IrPrintGen *irp, Stage1AirInstVarPtr *instruction) { - fprintf(irp->f, "&%s", instruction->var->name); -} - -static void ir_print_return_ptr(IrPrintGen *irp, Stage1AirInstReturnPtr *instruction) { - fprintf(irp->f, "@ReturnPtr"); -} - -static void ir_print_load_ptr(IrPrintSrc *irp, Stage1ZirInstLoadPtr *instruction) { - ir_print_other_inst_src(irp, instruction->ptr); - fprintf(irp->f, ".*"); -} - -static void ir_print_load_ptr_gen(IrPrintGen *irp, Stage1AirInstLoadPtr *instruction) { - fprintf(irp->f, "loadptr("); - ir_print_other_inst_gen(irp, instruction->ptr); - fprintf(irp->f, ")result="); - ir_print_other_inst_gen(irp, instruction->result_loc); -} - -static void ir_print_store_ptr(IrPrintSrc *irp, Stage1ZirInstStorePtr *instruction) { - fprintf(irp->f, "*"); - ir_print_var_src(irp, instruction->ptr); - fprintf(irp->f, " = "); - ir_print_other_inst_src(irp, instruction->value); -} - -static void ir_print_store_ptr(IrPrintGen *irp, Stage1AirInstStorePtr *instruction) { - fprintf(irp->f, "*"); - ir_print_var_gen(irp, instruction->ptr); - fprintf(irp->f, " = "); - ir_print_other_inst_gen(irp, instruction->value); -} - -static void ir_print_vector_store_elem(IrPrintGen *irp, Stage1AirInstVectorStoreElem *instruction) { - fprintf(irp->f, "vector_ptr="); - ir_print_var_gen(irp, instruction->vector_ptr); - fprintf(irp->f, ",index="); - ir_print_var_gen(irp, instruction->index); - fprintf(irp->f, ",value="); - ir_print_other_inst_gen(irp, instruction->value); -} - -static void ir_print_typeof(IrPrintSrc *irp, Stage1ZirInstTypeOf *instruction) { - fprintf(irp->f, "@TypeOf("); - if (instruction->value_count == 1) { - ir_print_other_inst_src(irp, instruction->value.scalar); - } else { - for (size_t i = 0; i < instruction->value_count; i += 1) { - ir_print_other_inst_src(irp, instruction->value.list[i]); - } - } - fprintf(irp->f, ")"); -} - -static void ir_print_binary_not(IrPrintGen *irp, Stage1AirInstBinaryNot *instruction) { - fprintf(irp->f, "~"); - ir_print_other_inst_gen(irp, instruction->operand); -} - -static void ir_print_negation(IrPrintGen *irp, Stage1AirInstNegation *instruction) { - fprintf(irp->f, instruction->wrapping ? "-%%" : "-"); - ir_print_other_inst_gen(irp, instruction->operand); -} - -static void ir_print_field_ptr(IrPrintSrc *irp, Stage1ZirInstFieldPtr *instruction) { - if (instruction->field_name_buffer) { - fprintf(irp->f, "fieldptr "); - ir_print_other_inst_src(irp, instruction->container_ptr); - fprintf(irp->f, ".%s", buf_ptr(instruction->field_name_buffer)); - } else { - assert(instruction->field_name_expr); - fprintf(irp->f, "@field("); - ir_print_other_inst_src(irp, instruction->container_ptr); - fprintf(irp->f, ", "); - ir_print_other_inst_src(irp, instruction->field_name_expr); - fprintf(irp->f, ")"); - } -} - -static void ir_print_struct_field_ptr(IrPrintGen *irp, Stage1AirInstStructFieldPtr *instruction) { - fprintf(irp->f, "@StructFieldPtr(&"); - ir_print_other_inst_gen(irp, instruction->struct_ptr); - fprintf(irp->f, ".%s", buf_ptr(instruction->field->name)); - fprintf(irp->f, ")"); -} - -static void ir_print_union_field_ptr(IrPrintGen *irp, Stage1AirInstUnionFieldPtr *instruction) { - fprintf(irp->f, "@UnionFieldPtr(&"); - ir_print_other_inst_gen(irp, instruction->union_ptr); - fprintf(irp->f, ".%s", buf_ptr(instruction->field->enum_field->name)); - fprintf(irp->f, ")"); -} - -static void ir_print_set_cold(IrPrintSrc *irp, Stage1ZirInstSetCold *instruction) { - fprintf(irp->f, "@setCold("); - ir_print_other_inst_src(irp, instruction->is_cold); - fprintf(irp->f, ")"); -} - -static void ir_print_set_runtime_safety(IrPrintSrc *irp, Stage1ZirInstSetRuntimeSafety *instruction) { - fprintf(irp->f, "@setRuntimeSafety("); - ir_print_other_inst_src(irp, instruction->safety_on); - fprintf(irp->f, ")"); -} - -static void ir_print_set_float_mode(IrPrintSrc *irp, Stage1ZirInstSetFloatMode *instruction) { - fprintf(irp->f, "@setFloatMode("); - ir_print_other_inst_src(irp, instruction->scope_value); - fprintf(irp->f, ", "); - ir_print_other_inst_src(irp, instruction->mode_value); - fprintf(irp->f, ")"); -} - -static void ir_print_array_type(IrPrintSrc *irp, Stage1ZirInstArrayType *instruction) { - fprintf(irp->f, "["); - ir_print_other_inst_src(irp, instruction->size); - if (instruction->sentinel != nullptr) { - fprintf(irp->f, ":"); - ir_print_other_inst_src(irp, instruction->sentinel); - } - fprintf(irp->f, "]"); - ir_print_other_inst_src(irp, instruction->child_type); -} - -static void ir_print_slice_type(IrPrintSrc *irp, Stage1ZirInstSliceType *instruction) { - const char *const_kw = instruction->is_const ? "const " : ""; - fprintf(irp->f, "[]%s", const_kw); - ir_print_other_inst_src(irp, instruction->child_type); -} - -static void ir_print_any_frame_type(IrPrintSrc *irp, Stage1ZirInstAnyFrameType *instruction) { - if (instruction->payload_type == nullptr) { - fprintf(irp->f, "anyframe"); - } else { - fprintf(irp->f, "anyframe->"); - ir_print_other_inst_src(irp, instruction->payload_type); - } -} - -static void ir_print_asm_src(IrPrintSrc *irp, Stage1ZirInstAsm *instruction) { - assert(instruction->base.source_node->type == NodeTypeAsmExpr); - AstNodeAsmExpr *asm_expr = &instruction->base.source_node->data.asm_expr; - const char *volatile_kw = instruction->has_side_effects ? " volatile" : ""; - fprintf(irp->f, "asm%s (", volatile_kw); - ir_print_other_inst_src(irp, instruction->asm_template); - - for (size_t i = 0; i < asm_expr->output_list.length; i += 1) { - AsmOutput *asm_output = asm_expr->output_list.at(i); - if (i != 0) fprintf(irp->f, ", "); - - fprintf(irp->f, "[%s] \"%s\" (", - buf_ptr(asm_output->asm_symbolic_name), - buf_ptr(asm_output->constraint)); - if (asm_output->return_type) { - fprintf(irp->f, "-> "); - ir_print_other_inst_src(irp, instruction->output_types[i]); - } else { - fprintf(irp->f, "%s", buf_ptr(asm_output->variable_name)); - } - fprintf(irp->f, ")"); - } - - fprintf(irp->f, " : "); - for (size_t i = 0; i < asm_expr->input_list.length; i += 1) { - AsmInput *asm_input = asm_expr->input_list.at(i); - - if (i != 0) fprintf(irp->f, ", "); - fprintf(irp->f, "[%s] \"%s\" (", - buf_ptr(asm_input->asm_symbolic_name), - buf_ptr(asm_input->constraint)); - ir_print_other_inst_src(irp, instruction->input_list[i]); - fprintf(irp->f, ")"); - } - fprintf(irp->f, " : "); - for (size_t i = 0; i < asm_expr->clobber_list.length; i += 1) { - Buf *reg_name = asm_expr->clobber_list.at(i); - if (i != 0) fprintf(irp->f, ", "); - fprintf(irp->f, "\"%s\"", buf_ptr(reg_name)); - } - fprintf(irp->f, ")"); -} - -static void ir_print_asm_gen(IrPrintGen *irp, Stage1AirInstAsm *instruction) { - assert(instruction->base.source_node->type == NodeTypeAsmExpr); - AstNodeAsmExpr *asm_expr = &instruction->base.source_node->data.asm_expr; - const char *volatile_kw = instruction->has_side_effects ? " volatile" : ""; - fprintf(irp->f, "asm%s (\"%s\") : ", volatile_kw, buf_ptr(instruction->asm_template)); - - for (size_t i = 0; i < asm_expr->output_list.length; i += 1) { - AsmOutput *asm_output = asm_expr->output_list.at(i); - if (i != 0) fprintf(irp->f, ", "); - - fprintf(irp->f, "[%s] \"%s\" (", - buf_ptr(asm_output->asm_symbolic_name), - buf_ptr(asm_output->constraint)); - if (asm_output->return_type) { - fprintf(irp->f, "-> "); - ir_print_other_inst_gen(irp, instruction->output_types[i]); - } else { - fprintf(irp->f, "%s", buf_ptr(asm_output->variable_name)); - } - fprintf(irp->f, ")"); - } - - fprintf(irp->f, " : "); - for (size_t i = 0; i < asm_expr->input_list.length; i += 1) { - AsmInput *asm_input = asm_expr->input_list.at(i); - - if (i != 0) fprintf(irp->f, ", "); - fprintf(irp->f, "[%s] \"%s\" (", - buf_ptr(asm_input->asm_symbolic_name), - buf_ptr(asm_input->constraint)); - ir_print_other_inst_gen(irp, instruction->input_list[i]); - fprintf(irp->f, ")"); - } - fprintf(irp->f, " : "); - for (size_t i = 0; i < asm_expr->clobber_list.length; i += 1) { - Buf *reg_name = asm_expr->clobber_list.at(i); - if (i != 0) fprintf(irp->f, ", "); - fprintf(irp->f, "\"%s\"", buf_ptr(reg_name)); - } - fprintf(irp->f, ")"); -} - -static void ir_print_size_of(IrPrintSrc *irp, Stage1ZirInstSizeOf *instruction) { - if (instruction->bit_size) - fprintf(irp->f, "@bitSizeOf("); - else - fprintf(irp->f, "@sizeOf("); - ir_print_other_inst_src(irp, instruction->type_value); - fprintf(irp->f, ")"); -} - -static void ir_print_test_non_null(IrPrintSrc *irp, Stage1ZirInstTestNonNull *instruction) { - ir_print_other_inst_src(irp, instruction->value); - fprintf(irp->f, " != null"); -} - -static void ir_print_test_non_null(IrPrintGen *irp, Stage1AirInstTestNonNull *instruction) { - ir_print_other_inst_gen(irp, instruction->value); - fprintf(irp->f, " != null"); -} - -static void ir_print_optional_unwrap_ptr(IrPrintSrc *irp, Stage1ZirInstOptionalUnwrapPtr *instruction) { - fprintf(irp->f, "&"); - ir_print_other_inst_src(irp, instruction->base_ptr); - fprintf(irp->f, ".*.?"); - if (!instruction->safety_check_on) { - fprintf(irp->f, " // no safety"); - } -} - -static void ir_print_optional_unwrap_ptr(IrPrintGen *irp, Stage1AirInstOptionalUnwrapPtr *instruction) { - fprintf(irp->f, "&"); - ir_print_other_inst_gen(irp, instruction->base_ptr); - fprintf(irp->f, ".*.?"); - if (!instruction->safety_check_on) { - fprintf(irp->f, " // no safety"); - } -} - -static void ir_print_clz(IrPrintSrc *irp, Stage1ZirInstClz *instruction) { - fprintf(irp->f, "@clz("); - ir_print_other_inst_src(irp, instruction->type); - fprintf(irp->f, ","); - ir_print_other_inst_src(irp, instruction->op); - fprintf(irp->f, ")"); -} - -static void ir_print_clz(IrPrintGen *irp, Stage1AirInstClz *instruction) { - fprintf(irp->f, "@clz("); - ir_print_other_inst_gen(irp, instruction->op); - fprintf(irp->f, ")"); -} - -static void ir_print_ctz(IrPrintSrc *irp, Stage1ZirInstCtz *instruction) { - fprintf(irp->f, "@ctz("); - ir_print_other_inst_src(irp, instruction->type); - fprintf(irp->f, ","); - ir_print_other_inst_src(irp, instruction->op); - fprintf(irp->f, ")"); -} - -static void ir_print_ctz(IrPrintGen *irp, Stage1AirInstCtz *instruction) { - fprintf(irp->f, "@ctz("); - ir_print_other_inst_gen(irp, instruction->op); - fprintf(irp->f, ")"); -} - -static void ir_print_pop_count(IrPrintSrc *irp, Stage1ZirInstPopCount *instruction) { - fprintf(irp->f, "@popCount("); - ir_print_other_inst_src(irp, instruction->type); - fprintf(irp->f, ","); - ir_print_other_inst_src(irp, instruction->op); - fprintf(irp->f, ")"); -} - -static void ir_print_pop_count(IrPrintGen *irp, Stage1AirInstPopCount *instruction) { - fprintf(irp->f, "@popCount("); - ir_print_other_inst_gen(irp, instruction->op); - fprintf(irp->f, ")"); -} - -static void ir_print_bswap(IrPrintSrc *irp, Stage1ZirInstBswap *instruction) { - fprintf(irp->f, "@byteSwap("); - ir_print_other_inst_src(irp, instruction->type); - fprintf(irp->f, ","); - ir_print_other_inst_src(irp, instruction->op); - fprintf(irp->f, ")"); -} - -static void ir_print_bswap(IrPrintGen *irp, Stage1AirInstBswap *instruction) { - fprintf(irp->f, "@byteSwap("); - ir_print_other_inst_gen(irp, instruction->op); - fprintf(irp->f, ")"); -} - -static void ir_print_bit_reverse(IrPrintSrc *irp, Stage1ZirInstBitReverse *instruction) { - fprintf(irp->f, "@bitReverse("); - ir_print_other_inst_src(irp, instruction->type); - fprintf(irp->f, ","); - ir_print_other_inst_src(irp, instruction->op); - fprintf(irp->f, ")"); -} - -static void ir_print_bit_reverse(IrPrintGen *irp, Stage1AirInstBitReverse *instruction) { - fprintf(irp->f, "@bitReverse("); - ir_print_other_inst_gen(irp, instruction->op); - fprintf(irp->f, ")"); -} - -static void ir_print_switch_br(IrPrintSrc *irp, Stage1ZirInstSwitchBr *instruction) { - fprintf(irp->f, "switch ("); - ir_print_other_inst_src(irp, instruction->target_value); - fprintf(irp->f, ") "); - for (size_t i = 0; i < instruction->case_count; i += 1) { - Stage1ZirInstSwitchBrCase *this_case = &instruction->cases[i]; - ir_print_other_inst_src(irp, this_case->value); - fprintf(irp->f, " => "); - ir_print_other_block(irp, this_case->block); - fprintf(irp->f, ", "); - } - fprintf(irp->f, "else => "); - ir_print_other_block(irp, instruction->else_block); - if (instruction->is_comptime != nullptr) { - fprintf(irp->f, " // comptime = "); - ir_print_other_inst_src(irp, instruction->is_comptime); - } -} - -static void ir_print_switch_br(IrPrintGen *irp, Stage1AirInstSwitchBr *instruction) { - fprintf(irp->f, "switch ("); - ir_print_other_inst_gen(irp, instruction->target_value); - fprintf(irp->f, ") "); - for (size_t i = 0; i < instruction->case_count; i += 1) { - Stage1AirInstSwitchBrCase *this_case = &instruction->cases[i]; - ir_print_other_inst_gen(irp, this_case->value); - fprintf(irp->f, " => "); - ir_print_other_block_gen(irp, this_case->block); - fprintf(irp->f, ", "); - } - fprintf(irp->f, "else => "); - ir_print_other_block_gen(irp, instruction->else_block); -} - -static void ir_print_switch_var(IrPrintSrc *irp, Stage1ZirInstSwitchVar *instruction) { - fprintf(irp->f, "switchvar "); - ir_print_other_inst_src(irp, instruction->target_value_ptr); - for (size_t i = 0; i < instruction->prongs_len; i += 1) { - fprintf(irp->f, ", "); - ir_print_other_inst_src(irp, instruction->prongs_ptr[i]); - } -} - -static void ir_print_switch_else_var(IrPrintSrc *irp, Stage1ZirInstSwitchElseVar *instruction) { - fprintf(irp->f, "switchelsevar "); - ir_print_other_inst_src(irp, &instruction->switch_br->base); -} - -static void ir_print_switch_target(IrPrintSrc *irp, Stage1ZirInstSwitchTarget *instruction) { - fprintf(irp->f, "switchtarget "); - ir_print_other_inst_src(irp, instruction->target_value_ptr); -} - -static void ir_print_union_tag(IrPrintGen *irp, Stage1AirInstUnionTag *instruction) { - fprintf(irp->f, "uniontag "); - ir_print_other_inst_gen(irp, instruction->value); -} - -static void ir_print_import(IrPrintSrc *irp, Stage1ZirInstImport *instruction) { - fprintf(irp->f, "@import("); - ir_print_other_inst_src(irp, instruction->name); - fprintf(irp->f, ")"); -} - -static void ir_print_ref(IrPrintSrc *irp, Stage1ZirInstRef *instruction) { - fprintf(irp->f, "ref "); - ir_print_other_inst_src(irp, instruction->value); -} - -static void ir_print_ref_gen(IrPrintGen *irp, Stage1AirInstRef *instruction) { - fprintf(irp->f, "@ref("); - ir_print_other_inst_gen(irp, instruction->operand); - fprintf(irp->f, ")result="); - ir_print_other_inst_gen(irp, instruction->result_loc); -} - -static void ir_print_compile_err(IrPrintSrc *irp, Stage1ZirInstCompileErr *instruction) { - fprintf(irp->f, "@compileError("); - ir_print_other_inst_src(irp, instruction->msg); - fprintf(irp->f, ")"); -} - -static void ir_print_compile_log(IrPrintSrc *irp, Stage1ZirInstCompileLog *instruction) { - fprintf(irp->f, "@compileLog("); - for (size_t i = 0; i < instruction->msg_count; i += 1) { - if (i != 0) - fprintf(irp->f, ","); - Stage1ZirInst *msg = instruction->msg_list[i]; - ir_print_other_inst_src(irp, msg); - } - fprintf(irp->f, ")"); -} - -static void ir_print_err_name(IrPrintSrc *irp, Stage1ZirInstErrName *instruction) { - fprintf(irp->f, "@errorName("); - ir_print_other_inst_src(irp, instruction->value); - fprintf(irp->f, ")"); -} - -static void ir_print_err_name(IrPrintGen *irp, Stage1AirInstErrName *instruction) { - fprintf(irp->f, "@errorName("); - ir_print_other_inst_gen(irp, instruction->value); - fprintf(irp->f, ")"); -} - -static void ir_print_c_import(IrPrintSrc *irp, Stage1ZirInstCImport *instruction) { - fprintf(irp->f, "@cImport(...)"); -} - -static void ir_print_c_include(IrPrintSrc *irp, Stage1ZirInstCInclude *instruction) { - fprintf(irp->f, "@cInclude("); - ir_print_other_inst_src(irp, instruction->name); - fprintf(irp->f, ")"); -} - -static void ir_print_c_define(IrPrintSrc *irp, Stage1ZirInstCDefine *instruction) { - fprintf(irp->f, "@cDefine("); - ir_print_other_inst_src(irp, instruction->name); - fprintf(irp->f, ", "); - ir_print_other_inst_src(irp, instruction->value); - fprintf(irp->f, ")"); -} - -static void ir_print_c_undef(IrPrintSrc *irp, Stage1ZirInstCUndef *instruction) { - fprintf(irp->f, "@cUndef("); - ir_print_other_inst_src(irp, instruction->name); - fprintf(irp->f, ")"); -} - -static void ir_print_embed_file(IrPrintSrc *irp, Stage1ZirInstEmbedFile *instruction) { - fprintf(irp->f, "@embedFile("); - ir_print_other_inst_src(irp, instruction->name); - fprintf(irp->f, ")"); -} - -static void ir_print_cmpxchg_src(IrPrintSrc *irp, Stage1ZirInstCmpxchg *instruction) { - fprintf(irp->f, "@cmpxchg("); - ir_print_other_inst_src(irp, instruction->ptr); - fprintf(irp->f, ", "); - ir_print_other_inst_src(irp, instruction->cmp_value); - fprintf(irp->f, ", "); - ir_print_other_inst_src(irp, instruction->new_value); - fprintf(irp->f, ", "); - ir_print_other_inst_src(irp, instruction->success_order_value); - fprintf(irp->f, ", "); - ir_print_other_inst_src(irp, instruction->failure_order_value); - fprintf(irp->f, ")result="); - ir_print_result_loc(irp, instruction->result_loc); -} - -static void ir_print_cmpxchg_gen(IrPrintGen *irp, Stage1AirInstCmpxchg *instruction) { - fprintf(irp->f, "@cmpxchg("); - ir_print_other_inst_gen(irp, instruction->ptr); - fprintf(irp->f, ", "); - ir_print_other_inst_gen(irp, instruction->cmp_value); - fprintf(irp->f, ", "); - ir_print_other_inst_gen(irp, instruction->new_value); - fprintf(irp->f, ", TODO print atomic orders)result="); - ir_print_other_inst_gen(irp, instruction->result_loc); -} - -static void ir_print_fence(IrPrintSrc *irp, Stage1ZirInstFence *instruction) { - fprintf(irp->f, "@fence("); - ir_print_other_inst_src(irp, instruction->order); - fprintf(irp->f, ")"); -} - -static void ir_print_reduce(IrPrintSrc *irp, Stage1ZirInstReduce *instruction) { - fprintf(irp->f, "@reduce("); - ir_print_other_inst_src(irp, instruction->op); - fprintf(irp->f, ", "); - ir_print_other_inst_src(irp, instruction->value); - fprintf(irp->f, ")"); -} - -static const char *atomic_order_str(AtomicOrder order) { - switch (order) { - case AtomicOrderUnordered: return "Unordered"; - case AtomicOrderMonotonic: return "Monotonic"; - case AtomicOrderAcquire: return "Acquire"; - case AtomicOrderRelease: return "Release"; - case AtomicOrderAcqRel: return "AcqRel"; - case AtomicOrderSeqCst: return "SeqCst"; - } - zig_unreachable(); -} - -static void ir_print_fence(IrPrintGen *irp, Stage1AirInstFence *instruction) { - fprintf(irp->f, "fence %s", atomic_order_str(instruction->order)); -} - -static const char *reduce_op_str(ReduceOp op) { - switch (op) { - case ReduceOp_and: return "And"; - case ReduceOp_or: return "Or"; - case ReduceOp_xor: return "Xor"; - case ReduceOp_min: return "Min"; - case ReduceOp_max: return "Max"; - case ReduceOp_add: return "Add"; - case ReduceOp_mul: return "Mul"; - } - zig_unreachable(); -} - -static void ir_print_reduce(IrPrintGen *irp, Stage1AirInstReduce *instruction) { - fprintf(irp->f, "@reduce(.%s, ", reduce_op_str(instruction->op)); - ir_print_other_inst_gen(irp, instruction->value); - fprintf(irp->f, ")"); -} - -static void ir_print_truncate(IrPrintSrc *irp, Stage1ZirInstTruncate *instruction) { - fprintf(irp->f, "@truncate("); - ir_print_other_inst_src(irp, instruction->dest_type); - fprintf(irp->f, ", "); - ir_print_other_inst_src(irp, instruction->target); - fprintf(irp->f, ")"); -} - -static void ir_print_truncate(IrPrintGen *irp, Stage1AirInstTruncate *instruction) { - fprintf(irp->f, "@truncate("); - ir_print_other_inst_gen(irp, instruction->target); - fprintf(irp->f, ")"); -} - -static void ir_print_int_cast(IrPrintSrc *irp, Stage1ZirInstIntCast *instruction) { - fprintf(irp->f, "@intCast("); - ir_print_other_inst_src(irp, instruction->dest_type); - fprintf(irp->f, ", "); - ir_print_other_inst_src(irp, instruction->target); - fprintf(irp->f, ")"); -} - -static void ir_print_float_cast(IrPrintSrc *irp, Stage1ZirInstFloatCast *instruction) { - fprintf(irp->f, "@floatCast("); - ir_print_other_inst_src(irp, instruction->dest_type); - fprintf(irp->f, ", "); - ir_print_other_inst_src(irp, instruction->target); - fprintf(irp->f, ")"); -} - -static void ir_print_err_set_cast(IrPrintSrc *irp, Stage1ZirInstErrSetCast *instruction) { - fprintf(irp->f, "@errSetCast("); - ir_print_other_inst_src(irp, instruction->dest_type); - fprintf(irp->f, ", "); - ir_print_other_inst_src(irp, instruction->target); - fprintf(irp->f, ")"); -} - -static void ir_print_int_to_float(IrPrintSrc *irp, Stage1ZirInstIntToFloat *instruction) { - fprintf(irp->f, "@intToFloat("); - ir_print_other_inst_src(irp, instruction->dest_type); - fprintf(irp->f, ", "); - ir_print_other_inst_src(irp, instruction->target); - fprintf(irp->f, ")"); -} - -static void ir_print_float_to_int(IrPrintSrc *irp, Stage1ZirInstFloatToInt *instruction) { - fprintf(irp->f, "@floatToInt("); - ir_print_other_inst_src(irp, instruction->dest_type); - fprintf(irp->f, ", "); - ir_print_other_inst_src(irp, instruction->target); - fprintf(irp->f, ")"); -} - -static void ir_print_bool_to_int(IrPrintSrc *irp, Stage1ZirInstBoolToInt *instruction) { - fprintf(irp->f, "@boolToInt("); - ir_print_other_inst_src(irp, instruction->target); - fprintf(irp->f, ")"); -} - -static void ir_print_vector_type(IrPrintSrc *irp, Stage1ZirInstVectorType *instruction) { - fprintf(irp->f, "@Vector("); - ir_print_other_inst_src(irp, instruction->len); - fprintf(irp->f, ", "); - ir_print_other_inst_src(irp, instruction->elem_type); - fprintf(irp->f, ")"); -} - -static void ir_print_shuffle_vector(IrPrintSrc *irp, Stage1ZirInstShuffleVector *instruction) { - fprintf(irp->f, "@shuffle("); - ir_print_other_inst_src(irp, instruction->scalar_type); - fprintf(irp->f, ", "); - ir_print_other_inst_src(irp, instruction->a); - fprintf(irp->f, ", "); - ir_print_other_inst_src(irp, instruction->b); - fprintf(irp->f, ", "); - ir_print_other_inst_src(irp, instruction->mask); - fprintf(irp->f, ")"); -} - -static void ir_print_shuffle_vector(IrPrintGen *irp, Stage1AirInstShuffleVector *instruction) { - fprintf(irp->f, "@shuffle("); - ir_print_other_inst_gen(irp, instruction->a); - fprintf(irp->f, ", "); - ir_print_other_inst_gen(irp, instruction->b); - fprintf(irp->f, ", "); - ir_print_other_inst_gen(irp, instruction->mask); - fprintf(irp->f, ")"); -} - -static void ir_print_select(IrPrintSrc *irp, Stage1ZirInstSelect *instruction) { - fprintf(irp->f, "@select("); - ir_print_other_inst_src(irp, instruction->scalar_type); - fprintf(irp->f, ", "); - ir_print_other_inst_src(irp, instruction->pred); - fprintf(irp->f, ", "); - ir_print_other_inst_src(irp, instruction->a); - fprintf(irp->f, ", "); - ir_print_other_inst_src(irp, instruction->b); - fprintf(irp->f, ")"); -} - -static void ir_print_select(IrPrintGen *irp, Stage1AirInstSelect *instruction) { - fprintf(irp->f, "@select("); - ir_print_other_inst_gen(irp, instruction->pred); - fprintf(irp->f, ", "); - ir_print_other_inst_gen(irp, instruction->a); - fprintf(irp->f, ", "); - ir_print_other_inst_gen(irp, instruction->b); - fprintf(irp->f, ")"); -} - -static void ir_print_splat_src(IrPrintSrc *irp, Stage1ZirInstSplat *instruction) { - fprintf(irp->f, "@splat("); - ir_print_other_inst_src(irp, instruction->len); - fprintf(irp->f, ", "); - ir_print_other_inst_src(irp, instruction->scalar); - fprintf(irp->f, ")"); -} - -static void ir_print_splat_gen(IrPrintGen *irp, Stage1AirInstSplat *instruction) { - fprintf(irp->f, "@splat("); - ir_print_other_inst_gen(irp, instruction->scalar); - fprintf(irp->f, ")"); -} - -static void ir_print_bool_not(IrPrintSrc *irp, Stage1ZirInstBoolNot *instruction) { - fprintf(irp->f, "! "); - ir_print_other_inst_src(irp, instruction->value); -} - -static void ir_print_bool_not(IrPrintGen *irp, Stage1AirInstBoolNot *instruction) { - fprintf(irp->f, "! "); - ir_print_other_inst_gen(irp, instruction->value); -} - -static void ir_print_wasm_memory_size(IrPrintSrc *irp, Stage1ZirInstWasmMemorySize *instruction) { - fprintf(irp->f, "@wasmMemorySize("); - ir_print_other_inst_src(irp, instruction->index); - fprintf(irp->f, ")"); -} - -static void ir_print_wasm_memory_size(IrPrintGen *irp, Stage1AirInstWasmMemorySize *instruction) { - fprintf(irp->f, "@wasmMemorySize("); - ir_print_other_inst_gen(irp, instruction->index); - fprintf(irp->f, ")"); -} - -static void ir_print_wasm_memory_grow(IrPrintSrc *irp, Stage1ZirInstWasmMemoryGrow *instruction) { - fprintf(irp->f, "@wasmMemoryGrow("); - ir_print_other_inst_src(irp, instruction->index); - fprintf(irp->f, ", "); - ir_print_other_inst_src(irp, instruction->delta); - fprintf(irp->f, ")"); -} - -static void ir_print_wasm_memory_grow(IrPrintGen *irp, Stage1AirInstWasmMemoryGrow *instruction) { - fprintf(irp->f, "@wasmMemoryGrow("); - ir_print_other_inst_gen(irp, instruction->index); - fprintf(irp->f, ", "); - ir_print_other_inst_gen(irp, instruction->delta); - fprintf(irp->f, ")"); -} - -static void ir_print_builtin_src(IrPrintSrc *irp, Stage1ZirInstSrc *instruction) { - fprintf(irp->f, "@src()"); -} - -static void ir_print_memset(IrPrintSrc *irp, Stage1ZirInstMemset *instruction) { - fprintf(irp->f, "@memset("); - ir_print_other_inst_src(irp, instruction->dest_ptr); - fprintf(irp->f, ", "); - ir_print_other_inst_src(irp, instruction->byte); - fprintf(irp->f, ", "); - ir_print_other_inst_src(irp, instruction->count); - fprintf(irp->f, ")"); -} - -static void ir_print_memset(IrPrintGen *irp, Stage1AirInstMemset *instruction) { - fprintf(irp->f, "@memset("); - ir_print_other_inst_gen(irp, instruction->dest_ptr); - fprintf(irp->f, ", "); - ir_print_other_inst_gen(irp, instruction->byte); - fprintf(irp->f, ", "); - ir_print_other_inst_gen(irp, instruction->count); - fprintf(irp->f, ")"); -} - -static void ir_print_memcpy(IrPrintSrc *irp, Stage1ZirInstMemcpy *instruction) { - fprintf(irp->f, "@memcpy("); - ir_print_other_inst_src(irp, instruction->dest_ptr); - fprintf(irp->f, ", "); - ir_print_other_inst_src(irp, instruction->src_ptr); - fprintf(irp->f, ", "); - ir_print_other_inst_src(irp, instruction->count); - fprintf(irp->f, ")"); -} - -static void ir_print_memcpy(IrPrintGen *irp, Stage1AirInstMemcpy *instruction) { - fprintf(irp->f, "@memcpy("); - ir_print_other_inst_gen(irp, instruction->dest_ptr); - fprintf(irp->f, ", "); - ir_print_other_inst_gen(irp, instruction->src_ptr); - fprintf(irp->f, ", "); - ir_print_other_inst_gen(irp, instruction->count); - fprintf(irp->f, ")"); -} - -static void ir_print_slice_src(IrPrintSrc *irp, Stage1ZirInstSlice *instruction) { - ir_print_other_inst_src(irp, instruction->ptr); - fprintf(irp->f, "["); - ir_print_other_inst_src(irp, instruction->start); - fprintf(irp->f, ".."); - if (instruction->end) - ir_print_other_inst_src(irp, instruction->end); - fprintf(irp->f, "]result="); - ir_print_result_loc(irp, instruction->result_loc); -} - -static void ir_print_slice_gen(IrPrintGen *irp, Stage1AirInstSlice *instruction) { - ir_print_other_inst_gen(irp, instruction->ptr); - fprintf(irp->f, "["); - ir_print_other_inst_gen(irp, instruction->start); - fprintf(irp->f, ".."); - if (instruction->end) - ir_print_other_inst_gen(irp, instruction->end); - fprintf(irp->f, "]result="); - ir_print_other_inst_gen(irp, instruction->result_loc); -} - -static void ir_print_breakpoint(IrPrintSrc *irp, Stage1ZirInstBreakpoint *instruction) { - fprintf(irp->f, "@breakpoint()"); -} - -static void ir_print_breakpoint(IrPrintGen *irp, Stage1AirInstBreakpoint *instruction) { - fprintf(irp->f, "@breakpoint()"); -} - -static void ir_print_frame_address(IrPrintSrc *irp, Stage1ZirInstFrameAddress *instruction) { - fprintf(irp->f, "@frameAddress()"); -} - -static void ir_print_frame_address(IrPrintGen *irp, Stage1AirInstFrameAddress *instruction) { - fprintf(irp->f, "@frameAddress()"); -} - -static void ir_print_handle(IrPrintSrc *irp, Stage1ZirInstFrameHandle *instruction) { - fprintf(irp->f, "@frame()"); -} - -static void ir_print_handle(IrPrintGen *irp, Stage1AirInstFrameHandle *instruction) { - fprintf(irp->f, "@frame()"); -} - -static void ir_print_frame_type(IrPrintSrc *irp, Stage1ZirInstFrameType *instruction) { - fprintf(irp->f, "@Frame("); - ir_print_other_inst_src(irp, instruction->fn); - fprintf(irp->f, ")"); -} - -static void ir_print_frame_size_src(IrPrintSrc *irp, Stage1ZirInstFrameSize *instruction) { - fprintf(irp->f, "@frameSize("); - ir_print_other_inst_src(irp, instruction->fn); - fprintf(irp->f, ")"); -} - -static void ir_print_frame_size_gen(IrPrintGen *irp, Stage1AirInstFrameSize *instruction) { - fprintf(irp->f, "@frameSize("); - ir_print_other_inst_gen(irp, instruction->fn); - fprintf(irp->f, ")"); -} - -static void ir_print_return_address(IrPrintSrc *irp, Stage1ZirInstReturnAddress *instruction) { - fprintf(irp->f, "@returnAddress()"); -} - -static void ir_print_return_address(IrPrintGen *irp, Stage1AirInstReturnAddress *instruction) { - fprintf(irp->f, "@returnAddress()"); -} - -static void ir_print_align_of(IrPrintSrc *irp, Stage1ZirInstAlignOf *instruction) { - fprintf(irp->f, "@alignOf("); - ir_print_other_inst_src(irp, instruction->type_value); - fprintf(irp->f, ")"); -} - -static void ir_print_overflow_op(IrPrintSrc *irp, Stage1ZirInstOverflowOp *instruction) { - switch (instruction->op) { - case IrOverflowOpAdd: - fprintf(irp->f, "@addWithOverflow("); - break; - case IrOverflowOpSub: - fprintf(irp->f, "@subWithOverflow("); - break; - case IrOverflowOpMul: - fprintf(irp->f, "@mulWithOverflow("); - break; - case IrOverflowOpShl: - fprintf(irp->f, "@shlWithOverflow("); - break; - } - ir_print_other_inst_src(irp, instruction->type_value); - fprintf(irp->f, ", "); - ir_print_other_inst_src(irp, instruction->op1); - fprintf(irp->f, ", "); - ir_print_other_inst_src(irp, instruction->op2); - fprintf(irp->f, ", "); - ir_print_other_inst_src(irp, instruction->result_ptr); - fprintf(irp->f, ")"); -} - -static void ir_print_overflow_op(IrPrintGen *irp, Stage1AirInstOverflowOp *instruction) { - switch (instruction->op) { - case IrOverflowOpAdd: - fprintf(irp->f, "@addWithOverflow("); - break; - case IrOverflowOpSub: - fprintf(irp->f, "@subWithOverflow("); - break; - case IrOverflowOpMul: - fprintf(irp->f, "@mulWithOverflow("); - break; - case IrOverflowOpShl: - fprintf(irp->f, "@shlWithOverflow("); - break; - } - ir_print_other_inst_gen(irp, instruction->op1); - fprintf(irp->f, ", "); - ir_print_other_inst_gen(irp, instruction->op2); - fprintf(irp->f, ", "); - ir_print_other_inst_gen(irp, instruction->result_ptr); - fprintf(irp->f, ")"); -} - -static void ir_print_test_err_src(IrPrintSrc *irp, Stage1ZirInstTestErr *instruction) { - fprintf(irp->f, "@testError("); - ir_print_other_inst_src(irp, instruction->base_ptr); - fprintf(irp->f, ")"); -} - -static void ir_print_test_err_gen(IrPrintGen *irp, Stage1AirInstTestErr *instruction) { - fprintf(irp->f, "@testError("); - ir_print_other_inst_gen(irp, instruction->err_union); - fprintf(irp->f, ")"); -} - -static void ir_print_unwrap_err_code(IrPrintSrc *irp, Stage1ZirInstUnwrapErrCode *instruction) { - fprintf(irp->f, "UnwrapErrorCode("); - ir_print_other_inst_src(irp, instruction->err_union_ptr); - fprintf(irp->f, ")"); -} - -static void ir_print_unwrap_err_code(IrPrintGen *irp, Stage1AirInstUnwrapErrCode *instruction) { - fprintf(irp->f, "UnwrapErrorCode("); - ir_print_other_inst_gen(irp, instruction->err_union_ptr); - fprintf(irp->f, ")"); -} - -static void ir_print_unwrap_err_payload(IrPrintSrc *irp, Stage1ZirInstUnwrapErrPayload *instruction) { - fprintf(irp->f, "ErrorUnionFieldPayload("); - ir_print_other_inst_src(irp, instruction->value); - fprintf(irp->f, ")safety=%d,init=%d",instruction->safety_check_on, instruction->initializing); -} - -static void ir_print_unwrap_err_payload(IrPrintGen *irp, Stage1AirInstUnwrapErrPayload *instruction) { - fprintf(irp->f, "ErrorUnionFieldPayload("); - ir_print_other_inst_gen(irp, instruction->value); - fprintf(irp->f, ")safety=%d,init=%d",instruction->safety_check_on, instruction->initializing); -} - -static void ir_print_optional_wrap(IrPrintGen *irp, Stage1AirInstOptionalWrap *instruction) { - fprintf(irp->f, "@optionalWrap("); - ir_print_other_inst_gen(irp, instruction->operand); - fprintf(irp->f, ")result="); - ir_print_other_inst_gen(irp, instruction->result_loc); -} - -static void ir_print_err_wrap_code(IrPrintGen *irp, Stage1AirInstErrWrapCode *instruction) { - fprintf(irp->f, "@errWrapCode("); - ir_print_other_inst_gen(irp, instruction->operand); - fprintf(irp->f, ")result="); - ir_print_other_inst_gen(irp, instruction->result_loc); -} - -static void ir_print_err_wrap_payload(IrPrintGen *irp, Stage1AirInstErrWrapPayload *instruction) { - fprintf(irp->f, "@errWrapPayload("); - ir_print_other_inst_gen(irp, instruction->operand); - fprintf(irp->f, ")result="); - ir_print_other_inst_gen(irp, instruction->result_loc); -} - -static void ir_print_fn_proto(IrPrintSrc *irp, Stage1ZirInstFnProto *instruction) { - fprintf(irp->f, "fn("); - for (size_t i = 0; i < instruction->base.source_node->data.fn_proto.params.length; i += 1) { - if (i != 0) - fprintf(irp->f, ","); - if (instruction->is_var_args && i == instruction->base.source_node->data.fn_proto.params.length - 1) { - fprintf(irp->f, "..."); - } else { - ir_print_other_inst_src(irp, instruction->param_types[i]); - } - } - fprintf(irp->f, ")"); - if (instruction->align_value != nullptr) { - fprintf(irp->f, " align "); - ir_print_other_inst_src(irp, instruction->align_value); - fprintf(irp->f, " "); - } - fprintf(irp->f, "->"); - ir_print_other_inst_src(irp, instruction->return_type); -} - -static void ir_print_test_comptime(IrPrintSrc *irp, Stage1ZirInstTestComptime *instruction) { - fprintf(irp->f, "@testComptime("); - ir_print_other_inst_src(irp, instruction->value); - fprintf(irp->f, ")"); -} - -static void ir_print_ptr_cast_src(IrPrintSrc *irp, Stage1ZirInstPtrCast *instruction) { - fprintf(irp->f, "@ptrCast("); - if (instruction->dest_type) { - ir_print_other_inst_src(irp, instruction->dest_type); - } - fprintf(irp->f, ","); - ir_print_other_inst_src(irp, instruction->ptr); - fprintf(irp->f, ")"); -} - -static void ir_print_ptr_cast_gen(IrPrintGen *irp, Stage1AirInstPtrCast *instruction) { - fprintf(irp->f, "@ptrCast("); - ir_print_other_inst_gen(irp, instruction->ptr); - fprintf(irp->f, ")"); -} - -static void ir_print_implicit_cast(IrPrintSrc *irp, Stage1ZirInstImplicitCast *instruction) { - fprintf(irp->f, "@implicitCast("); - ir_print_other_inst_src(irp, instruction->operand); - fprintf(irp->f, ")result="); - ir_print_result_loc(irp, &instruction->result_loc_cast->base); -} - -static void ir_print_bit_cast_src(IrPrintSrc *irp, Stage1ZirInstBitCast *instruction) { - fprintf(irp->f, "@bitCast("); - ir_print_other_inst_src(irp, instruction->operand); - fprintf(irp->f, ")result="); - ir_print_result_loc(irp, &instruction->result_loc_bit_cast->base); -} - -static void ir_print_bit_cast_gen(IrPrintGen *irp, Stage1AirInstBitCast *instruction) { - fprintf(irp->f, "@bitCast("); - ir_print_other_inst_gen(irp, instruction->operand); - fprintf(irp->f, ")"); -} - -static void ir_print_widen_or_shorten(IrPrintGen *irp, Stage1AirInstWidenOrShorten *instruction) { - fprintf(irp->f, "WidenOrShorten("); - ir_print_other_inst_gen(irp, instruction->target); - fprintf(irp->f, ")"); -} - -static void ir_print_ptr_to_int(IrPrintSrc *irp, Stage1ZirInstPtrToInt *instruction) { - fprintf(irp->f, "@ptrToInt("); - ir_print_other_inst_src(irp, instruction->target); - fprintf(irp->f, ")"); -} - -static void ir_print_ptr_to_int(IrPrintGen *irp, Stage1AirInstPtrToInt *instruction) { - fprintf(irp->f, "@ptrToInt("); - ir_print_other_inst_gen(irp, instruction->target); - fprintf(irp->f, ")"); -} - -static void ir_print_int_to_ptr(IrPrintSrc *irp, Stage1ZirInstIntToPtr *instruction) { - fprintf(irp->f, "@intToPtr("); - ir_print_other_inst_src(irp, instruction->dest_type); - fprintf(irp->f, ","); - ir_print_other_inst_src(irp, instruction->target); - fprintf(irp->f, ")"); -} - -static void ir_print_int_to_ptr(IrPrintGen *irp, Stage1AirInstIntToPtr *instruction) { - fprintf(irp->f, "@intToPtr("); - ir_print_other_inst_gen(irp, instruction->target); - fprintf(irp->f, ")"); -} - -static void ir_print_int_to_enum(IrPrintSrc *irp, Stage1ZirInstIntToEnum *instruction) { - fprintf(irp->f, "@intToEnum("); - ir_print_other_inst_src(irp, instruction->dest_type); - fprintf(irp->f, ","); - ir_print_other_inst_src(irp, instruction->target); - fprintf(irp->f, ")"); -} - -static void ir_print_int_to_enum(IrPrintGen *irp, Stage1AirInstIntToEnum *instruction) { - fprintf(irp->f, "@intToEnum("); - ir_print_other_inst_gen(irp, instruction->target); - fprintf(irp->f, ")"); -} - -static void ir_print_enum_to_int(IrPrintSrc *irp, Stage1ZirInstEnumToInt *instruction) { - fprintf(irp->f, "@enumToInt("); - ir_print_other_inst_src(irp, instruction->target); - fprintf(irp->f, ")"); -} - -static void ir_print_check_runtime_scope(IrPrintSrc *irp, Stage1ZirInstCheckRuntimeScope *instruction) { - fprintf(irp->f, "@checkRuntimeScope("); - ir_print_other_inst_src(irp, instruction->scope_is_comptime); - fprintf(irp->f, ","); - ir_print_other_inst_src(irp, instruction->is_comptime); - fprintf(irp->f, ")"); -} - -static void ir_print_array_to_vector(IrPrintGen *irp, Stage1AirInstArrayToVector *instruction) { - fprintf(irp->f, "ArrayToVector("); - ir_print_other_inst_gen(irp, instruction->array); - fprintf(irp->f, ")"); -} - -static void ir_print_vector_to_array(IrPrintGen *irp, Stage1AirInstVectorToArray *instruction) { - fprintf(irp->f, "VectorToArray("); - ir_print_other_inst_gen(irp, instruction->vector); - fprintf(irp->f, ")result="); - ir_print_other_inst_gen(irp, instruction->result_loc); -} - -static void ir_print_ptr_of_array_to_slice(IrPrintGen *irp, Stage1AirInstPtrOfArrayToSlice *instruction) { - fprintf(irp->f, "PtrOfArrayToSlice("); - ir_print_other_inst_gen(irp, instruction->operand); - fprintf(irp->f, ")result="); - ir_print_other_inst_gen(irp, instruction->result_loc); -} - -static void ir_print_assert_zero(IrPrintGen *irp, Stage1AirInstAssertZero *instruction) { - fprintf(irp->f, "AssertZero("); - ir_print_other_inst_gen(irp, instruction->target); - fprintf(irp->f, ")"); -} - -static void ir_print_assert_non_null(IrPrintGen *irp, Stage1AirInstAssertNonNull *instruction) { - fprintf(irp->f, "AssertNonNull("); - ir_print_other_inst_gen(irp, instruction->target); - fprintf(irp->f, ")"); -} - -static void ir_print_alloca_src(IrPrintSrc *irp, Stage1ZirInstAlloca *instruction) { - fprintf(irp->f, "Alloca(align="); - ir_print_other_inst_src(irp, instruction->align); - fprintf(irp->f, ",name=%s)", instruction->name_hint); -} - -static void ir_print_alloca_gen(IrPrintGen *irp, Stage1AirInstAlloca *instruction) { - fprintf(irp->f, "Alloca(align=%" PRIu32 ",name=%s)", instruction->align, instruction->name_hint); -} - -static void ir_print_end_expr(IrPrintSrc *irp, Stage1ZirInstEndExpr *instruction) { - fprintf(irp->f, "EndExpr(result="); - ir_print_result_loc(irp, instruction->result_loc); - fprintf(irp->f, ",value="); - ir_print_other_inst_src(irp, instruction->value); - fprintf(irp->f, ")"); -} - -static void ir_print_int_to_err(IrPrintSrc *irp, Stage1ZirInstIntToErr *instruction) { - fprintf(irp->f, "inttoerr "); - ir_print_other_inst_src(irp, instruction->target); -} - -static void ir_print_int_to_err(IrPrintGen *irp, Stage1AirInstIntToErr *instruction) { - fprintf(irp->f, "inttoerr "); - ir_print_other_inst_gen(irp, instruction->target); -} - -static void ir_print_err_to_int(IrPrintSrc *irp, Stage1ZirInstErrToInt *instruction) { - fprintf(irp->f, "errtoint "); - ir_print_other_inst_src(irp, instruction->target); -} - -static void ir_print_err_to_int(IrPrintGen *irp, Stage1AirInstErrToInt *instruction) { - fprintf(irp->f, "errtoint "); - ir_print_other_inst_gen(irp, instruction->target); -} - -static void ir_print_check_switch_prongs(IrPrintSrc *irp, Stage1ZirInstCheckSwitchProngs *instruction, - bool have_underscore_prong) -{ - fprintf(irp->f, "@checkSwitchProngs("); - ir_print_other_inst_src(irp, instruction->target_value); - fprintf(irp->f, ","); - for (size_t i = 0; i < instruction->range_count; i += 1) { - if (i != 0) - fprintf(irp->f, ","); - ir_print_other_inst_src(irp, instruction->ranges[i].start); - fprintf(irp->f, "..."); - ir_print_other_inst_src(irp, instruction->ranges[i].end); - } - const char *have_else_str = instruction->else_prong != nullptr ? "yes" : "no"; - fprintf(irp->f, ")else:%s", have_else_str); - const char *have_under_str = have_underscore_prong ? "yes" : "no"; - fprintf(irp->f, " _:%s", have_under_str); -} - -static void ir_print_check_statement_is_void(IrPrintSrc *irp, Stage1ZirInstCheckStatementIsVoid *instruction) { - fprintf(irp->f, "@checkStatementIsVoid("); - ir_print_other_inst_src(irp, instruction->statement_value); - fprintf(irp->f, ")"); -} - -static void ir_print_type_name(IrPrintSrc *irp, Stage1ZirInstTypeName *instruction) { - fprintf(irp->f, "typename "); - ir_print_other_inst_src(irp, instruction->type_value); -} - -static void ir_print_tag_name(IrPrintSrc *irp, Stage1ZirInstTagName *instruction) { - fprintf(irp->f, "tagname "); - ir_print_other_inst_src(irp, instruction->target); -} - -static void ir_print_tag_name(IrPrintGen *irp, Stage1AirInstTagName *instruction) { - fprintf(irp->f, "tagname "); - ir_print_other_inst_gen(irp, instruction->target); -} - -static void ir_print_ptr_type(IrPrintSrc *irp, Stage1ZirInstPtrType *instruction) { - fprintf(irp->f, "&"); - if (instruction->align_value != nullptr) { - fprintf(irp->f, "align("); - ir_print_other_inst_src(irp, instruction->align_value); - fprintf(irp->f, ")"); - } - const char *const_str = instruction->is_const ? "const " : ""; - const char *volatile_str = instruction->is_volatile ? "volatile " : ""; - fprintf(irp->f, ":%" PRIu32 ":%" PRIu32 " %s%s", instruction->bit_offset_start, instruction->host_int_bytes, - const_str, volatile_str); - ir_print_other_inst_src(irp, instruction->child_type); -} - -static void ir_print_ptr_type_simple(IrPrintSrc *irp, Stage1ZirInstPtrTypeSimple *instruction, - bool is_const) -{ - fprintf(irp->f, "&"); - const char *const_str = is_const ? "const " : ""; - fprintf(irp->f, "*%s", const_str); - ir_print_other_inst_src(irp, instruction->child_type); -} - -static void ir_print_decl_ref(IrPrintSrc *irp, Stage1ZirInstDeclRef *instruction) { - const char *ptr_str = (instruction->lval != LValNone) ? "ptr " : ""; - fprintf(irp->f, "declref %s%s", ptr_str, buf_ptr(instruction->tld->name)); -} - -static void ir_print_panic(IrPrintSrc *irp, Stage1ZirInstPanic *instruction) { - fprintf(irp->f, "@panic("); - ir_print_other_inst_src(irp, instruction->msg); - fprintf(irp->f, ")"); -} - -static void ir_print_panic(IrPrintGen *irp, Stage1AirInstPanic *instruction) { - fprintf(irp->f, "@panic("); - ir_print_other_inst_gen(irp, instruction->msg); - fprintf(irp->f, ")"); -} - -static void ir_print_field_parent_ptr(IrPrintSrc *irp, Stage1ZirInstFieldParentPtr *instruction) { - fprintf(irp->f, "@fieldParentPtr("); - ir_print_other_inst_src(irp, instruction->type_value); - fprintf(irp->f, ","); - ir_print_other_inst_src(irp, instruction->field_name); - fprintf(irp->f, ","); - ir_print_other_inst_src(irp, instruction->field_ptr); - fprintf(irp->f, ")"); -} - -static void ir_print_field_parent_ptr(IrPrintGen *irp, Stage1AirInstFieldParentPtr *instruction) { - fprintf(irp->f, "@fieldParentPtr(%s,", buf_ptr(instruction->field->name)); - ir_print_other_inst_gen(irp, instruction->field_ptr); - fprintf(irp->f, ")"); -} - -static void ir_print_offset_of(IrPrintSrc *irp, Stage1ZirInstOffsetOf *instruction) { - fprintf(irp->f, "@offset_of("); - ir_print_other_inst_src(irp, instruction->type_value); - fprintf(irp->f, ","); - ir_print_other_inst_src(irp, instruction->field_name); - fprintf(irp->f, ")"); -} - -static void ir_print_bit_offset_of(IrPrintSrc *irp, Stage1ZirInstBitOffsetOf *instruction) { - fprintf(irp->f, "@bit_offset_of("); - ir_print_other_inst_src(irp, instruction->type_value); - fprintf(irp->f, ","); - ir_print_other_inst_src(irp, instruction->field_name); - fprintf(irp->f, ")"); -} - -static void ir_print_type_info(IrPrintSrc *irp, Stage1ZirInstTypeInfo *instruction) { - fprintf(irp->f, "@typeInfo("); - ir_print_other_inst_src(irp, instruction->type_value); - fprintf(irp->f, ")"); -} - -static void ir_print_type(IrPrintSrc *irp, Stage1ZirInstType *instruction) { - fprintf(irp->f, "@Type("); - ir_print_other_inst_src(irp, instruction->type_info); - fprintf(irp->f, ")"); -} - -static void ir_print_has_field(IrPrintSrc *irp, Stage1ZirInstHasField *instruction) { - fprintf(irp->f, "@hasField("); - ir_print_other_inst_src(irp, instruction->container_type); - fprintf(irp->f, ","); - ir_print_other_inst_src(irp, instruction->field_name); - fprintf(irp->f, ")"); -} - -static void ir_print_set_eval_branch_quota(IrPrintSrc *irp, Stage1ZirInstSetEvalBranchQuota *instruction) { - fprintf(irp->f, "@setEvalBranchQuota("); - ir_print_other_inst_src(irp, instruction->new_quota); - fprintf(irp->f, ")"); -} - -static void ir_print_align_cast(IrPrintSrc *irp, Stage1ZirInstAlignCast *instruction) { - fprintf(irp->f, "@alignCast("); - ir_print_other_inst_src(irp, instruction->align_bytes); - fprintf(irp->f, ","); - ir_print_other_inst_src(irp, instruction->target); - fprintf(irp->f, ")"); -} - -static void ir_print_addrspace_cast(IrPrintSrc *irp, Stage1ZirInstAddrSpaceCast *instruction) { - fprintf(irp->f, "@addrSpaceCast("); - ir_print_other_inst_src(irp, instruction->addrspace); - fprintf(irp->f, ","); - ir_print_other_inst_src(irp, instruction->ptr); - fprintf(irp->f, ")"); -} - -static void ir_print_align_cast(IrPrintGen *irp, Stage1AirInstAlignCast *instruction) { - fprintf(irp->f, "@alignCast("); - ir_print_other_inst_gen(irp, instruction->target); - fprintf(irp->f, ")"); -} - -static void ir_print_resolve_result(IrPrintSrc *irp, Stage1ZirInstResolveResult *instruction) { - fprintf(irp->f, "ResolveResult("); - ir_print_result_loc(irp, instruction->result_loc); - fprintf(irp->f, ")"); -} - -static void ir_print_reset_result(IrPrintSrc *irp, Stage1ZirInstResetResult *instruction) { - fprintf(irp->f, "ResetResult("); - ir_print_result_loc(irp, instruction->result_loc); - fprintf(irp->f, ")"); -} - -static void ir_print_set_align_stack(IrPrintSrc *irp, Stage1ZirInstSetAlignStack *instruction) { - fprintf(irp->f, "@setAlignStack("); - ir_print_other_inst_src(irp, instruction->align_bytes); - fprintf(irp->f, ")"); -} - -static void ir_print_arg_type(IrPrintSrc *irp, Stage1ZirInstArgType *instruction, bool allow_var) { - fprintf(irp->f, "@ArgType("); - ir_print_other_inst_src(irp, instruction->fn_type); - fprintf(irp->f, ","); - ir_print_other_inst_src(irp, instruction->arg_index); - fprintf(irp->f, ","); - if (allow_var) { - fprintf(irp->f, "allow_var=true"); - } else { - fprintf(irp->f, "allow_var=false"); - } - fprintf(irp->f, ")"); -} - -static void ir_print_export(IrPrintSrc *irp, Stage1ZirInstExport *instruction) { - fprintf(irp->f, "@export("); - ir_print_other_inst_src(irp, instruction->target); - fprintf(irp->f, ","); - ir_print_other_inst_src(irp, instruction->options); - fprintf(irp->f, ")"); -} - -static void ir_print_extern(IrPrintGen *irp, Stage1AirInstExtern *instruction) { - fprintf(irp->f, "@extern(...)"); -} - -static void ir_print_extern(IrPrintSrc *irp, Stage1ZirInstExtern *instruction) { - fprintf(irp->f, "@extern("); - ir_print_other_inst_src(irp, instruction->type); - fprintf(irp->f, ","); - ir_print_other_inst_src(irp, instruction->options); - fprintf(irp->f, ")"); -} - -static void ir_print_prefetch(IrPrintSrc *irp, Stage1ZirInstPrefetch *instruction) { - fprintf(irp->f, "@prefetch("); - ir_print_other_inst_src(irp, instruction->ptr); - fprintf(irp->f, ","); - ir_print_other_inst_src(irp, instruction->options); - fprintf(irp->f, ")"); -} - -static void ir_print_prefetch(IrPrintGen *irp, Stage1AirInstPrefetch *instruction) { - fprintf(irp->f, "@prefetch(...)"); -} - -static void ir_print_error_return_trace(IrPrintSrc *irp, Stage1ZirInstErrorReturnTrace *instruction) { - fprintf(irp->f, "@errorReturnTrace("); - switch (instruction->optional) { - case IrInstErrorReturnTraceNull: - fprintf(irp->f, "Null"); - break; - case IrInstErrorReturnTraceNonNull: - fprintf(irp->f, "NonNull"); - break; - } - fprintf(irp->f, ")"); -} - -static void ir_print_error_return_trace(IrPrintGen *irp, Stage1AirInstErrorReturnTrace *instruction) { - fprintf(irp->f, "@errorReturnTrace("); - switch (instruction->optional) { - case IrInstErrorReturnTraceNull: - fprintf(irp->f, "Null"); - break; - case IrInstErrorReturnTraceNonNull: - fprintf(irp->f, "NonNull"); - break; - } - fprintf(irp->f, ")"); -} - -static void ir_print_error_union(IrPrintSrc *irp, Stage1ZirInstErrorUnion *instruction) { - ir_print_other_inst_src(irp, instruction->err_set); - fprintf(irp->f, "!"); - ir_print_other_inst_src(irp, instruction->payload); -} - -static void ir_print_atomic_rmw(IrPrintSrc *irp, Stage1ZirInstAtomicRmw *instruction) { - fprintf(irp->f, "@atomicRmw("); - ir_print_other_inst_src(irp, instruction->operand_type); - fprintf(irp->f, ","); - ir_print_other_inst_src(irp, instruction->ptr); - fprintf(irp->f, ","); - ir_print_other_inst_src(irp, instruction->op); - fprintf(irp->f, ","); - ir_print_other_inst_src(irp, instruction->operand); - fprintf(irp->f, ","); - ir_print_other_inst_src(irp, instruction->ordering); - fprintf(irp->f, ")"); -} - -static void ir_print_atomic_rmw(IrPrintGen *irp, Stage1AirInstAtomicRmw *instruction) { - fprintf(irp->f, "@atomicRmw("); - ir_print_other_inst_gen(irp, instruction->ptr); - fprintf(irp->f, ",[TODO print op],"); - ir_print_other_inst_gen(irp, instruction->operand); - fprintf(irp->f, ",%s)", atomic_order_str(instruction->ordering)); -} - -static void ir_print_atomic_load(IrPrintSrc *irp, Stage1ZirInstAtomicLoad *instruction) { - fprintf(irp->f, "@atomicLoad("); - ir_print_other_inst_src(irp, instruction->operand_type); - fprintf(irp->f, ","); - ir_print_other_inst_src(irp, instruction->ptr); - fprintf(irp->f, ","); - ir_print_other_inst_src(irp, instruction->ordering); - fprintf(irp->f, ")"); -} - -static void ir_print_atomic_load(IrPrintGen *irp, Stage1AirInstAtomicLoad *instruction) { - fprintf(irp->f, "@atomicLoad("); - ir_print_other_inst_gen(irp, instruction->ptr); - fprintf(irp->f, ",%s)", atomic_order_str(instruction->ordering)); -} - -static void ir_print_atomic_store(IrPrintSrc *irp, Stage1ZirInstAtomicStore *instruction) { - fprintf(irp->f, "@atomicStore("); - ir_print_other_inst_src(irp, instruction->operand_type); - fprintf(irp->f, ","); - ir_print_other_inst_src(irp, instruction->ptr); - fprintf(irp->f, ","); - ir_print_other_inst_src(irp, instruction->value); - fprintf(irp->f, ","); - ir_print_other_inst_src(irp, instruction->ordering); - fprintf(irp->f, ")"); -} - -static void ir_print_atomic_store(IrPrintGen *irp, Stage1AirInstAtomicStore *instruction) { - fprintf(irp->f, "@atomicStore("); - ir_print_other_inst_gen(irp, instruction->ptr); - fprintf(irp->f, ","); - ir_print_other_inst_gen(irp, instruction->value); - fprintf(irp->f, ",%s)", atomic_order_str(instruction->ordering)); -} - - -static void ir_print_save_err_ret_addr(IrPrintSrc *irp, Stage1ZirInstSaveErrRetAddr *instruction) { - fprintf(irp->f, "@saveErrRetAddr()"); -} - -static void ir_print_save_err_ret_addr(IrPrintGen *irp, Stage1AirInstSaveErrRetAddr *instruction) { - fprintf(irp->f, "@saveErrRetAddr()"); -} - -static void ir_print_add_implicit_return_type(IrPrintSrc *irp, Stage1ZirInstAddImplicitReturnType *instruction) { - fprintf(irp->f, "@addImplicitReturnType("); - ir_print_other_inst_src(irp, instruction->value); - fprintf(irp->f, ")"); -} - -static void ir_print_float_op(IrPrintSrc *irp, Stage1ZirInstFloatOp *instruction) { - fprintf(irp->f, "@%s(", float_un_op_to_name(instruction->fn_id)); - ir_print_other_inst_src(irp, instruction->operand); - fprintf(irp->f, ")"); -} - -static void ir_print_float_op(IrPrintGen *irp, Stage1AirInstFloatOp *instruction) { - fprintf(irp->f, "@%s(", float_un_op_to_name(instruction->fn_id)); - ir_print_other_inst_gen(irp, instruction->operand); - fprintf(irp->f, ")"); -} - -static void ir_print_mul_add(IrPrintSrc *irp, Stage1ZirInstMulAdd *instruction) { - fprintf(irp->f, "@mulAdd("); - ir_print_other_inst_src(irp, instruction->type_value); - fprintf(irp->f, ","); - ir_print_other_inst_src(irp, instruction->op1); - fprintf(irp->f, ","); - ir_print_other_inst_src(irp, instruction->op2); - fprintf(irp->f, ","); - ir_print_other_inst_src(irp, instruction->op3); - fprintf(irp->f, ")"); -} - -static void ir_print_mul_add(IrPrintGen *irp, Stage1AirInstMulAdd *instruction) { - fprintf(irp->f, "@mulAdd("); - ir_print_other_inst_gen(irp, instruction->op1); - fprintf(irp->f, ","); - ir_print_other_inst_gen(irp, instruction->op2); - fprintf(irp->f, ","); - ir_print_other_inst_gen(irp, instruction->op3); - fprintf(irp->f, ")"); -} - -static void ir_print_decl_var_gen(IrPrintGen *irp, Stage1AirInstDeclVar *decl_var_instruction) { - ZigVar *var = decl_var_instruction->var; - const char *var_or_const = decl_var_instruction->var->gen_is_const ? "const" : "var"; - const char *name = decl_var_instruction->var->name; - fprintf(irp->f, "%s %s: %s align(%u) = ", var_or_const, name, buf_ptr(&var->var_type->name), - var->align_bytes); - - ir_print_other_inst_gen(irp, decl_var_instruction->var_ptr); -} - -static void ir_print_has_decl(IrPrintSrc *irp, Stage1ZirInstHasDecl *instruction) { - fprintf(irp->f, "@hasDecl("); - ir_print_other_inst_src(irp, instruction->container); - fprintf(irp->f, ","); - ir_print_other_inst_src(irp, instruction->name); - fprintf(irp->f, ")"); -} - -static void ir_print_undeclared_ident(IrPrintSrc *irp, Stage1ZirInstUndeclaredIdent *instruction) { - fprintf(irp->f, "@undeclaredIdent(%s)", buf_ptr(instruction->name)); -} - -static void ir_print_union_init_named_field(IrPrintSrc *irp, Stage1ZirInstUnionInitNamedField *instruction) { - fprintf(irp->f, "@unionInit("); - ir_print_other_inst_src(irp, instruction->union_type); - fprintf(irp->f, ", "); - ir_print_other_inst_src(irp, instruction->field_name); - fprintf(irp->f, ", "); - ir_print_other_inst_src(irp, instruction->field_result_loc); - fprintf(irp->f, ", "); - ir_print_other_inst_src(irp, instruction->result_loc); - fprintf(irp->f, ")"); -} - -static void ir_print_suspend_begin(IrPrintSrc *irp, Stage1ZirInstSuspendBegin *instruction) { - fprintf(irp->f, "@suspendBegin()"); -} - -static void ir_print_suspend_begin(IrPrintGen *irp, Stage1AirInstSuspendBegin *instruction) { - fprintf(irp->f, "@suspendBegin()"); -} - -static void ir_print_suspend_finish(IrPrintSrc *irp, Stage1ZirInstSuspendFinish *instruction) { - fprintf(irp->f, "@suspendFinish()"); -} - -static void ir_print_suspend_finish(IrPrintGen *irp, Stage1AirInstSuspendFinish *instruction) { - fprintf(irp->f, "@suspendFinish()"); -} - -static void ir_print_resume(IrPrintSrc *irp, Stage1ZirInstResume *instruction) { - fprintf(irp->f, "resume "); - ir_print_other_inst_src(irp, instruction->frame); -} - -static void ir_print_resume(IrPrintGen *irp, Stage1AirInstResume *instruction) { - fprintf(irp->f, "resume "); - ir_print_other_inst_gen(irp, instruction->frame); -} - -static void ir_print_await_src(IrPrintSrc *irp, Stage1ZirInstAwait *instruction) { - fprintf(irp->f, "@await("); - ir_print_other_inst_src(irp, instruction->frame); - fprintf(irp->f, ","); - ir_print_result_loc(irp, instruction->result_loc); - fprintf(irp->f, ")"); -} - -static void ir_print_await_gen(IrPrintGen *irp, Stage1AirInstAwait *instruction) { - fprintf(irp->f, "@await("); - ir_print_other_inst_gen(irp, instruction->frame); - fprintf(irp->f, ","); - ir_print_other_inst_gen(irp, instruction->result_loc); - fprintf(irp->f, ")"); -} - -static void ir_print_spill_begin(IrPrintSrc *irp, Stage1ZirInstSpillBegin *instruction) { - fprintf(irp->f, "@spillBegin("); - ir_print_other_inst_src(irp, instruction->operand); - fprintf(irp->f, ")"); -} - -static void ir_print_spill_begin(IrPrintGen *irp, Stage1AirInstSpillBegin *instruction) { - fprintf(irp->f, "@spillBegin("); - ir_print_other_inst_gen(irp, instruction->operand); - fprintf(irp->f, ")"); -} - -static void ir_print_spill_end(IrPrintSrc *irp, Stage1ZirInstSpillEnd *instruction) { - fprintf(irp->f, "@spillEnd("); - ir_print_other_inst_src(irp, &instruction->begin->base); - fprintf(irp->f, ")"); -} - -static void ir_print_spill_end(IrPrintGen *irp, Stage1AirInstSpillEnd *instruction) { - fprintf(irp->f, "@spillEnd("); - ir_print_other_inst_gen(irp, &instruction->begin->base); - fprintf(irp->f, ")"); -} - -static void ir_print_vector_extract_elem(IrPrintGen *irp, Stage1AirInstVectorExtractElem *instruction) { - fprintf(irp->f, "@vectorExtractElem("); - ir_print_other_inst_gen(irp, instruction->vector); - fprintf(irp->f, ","); - ir_print_other_inst_gen(irp, instruction->index); - fprintf(irp->f, ")"); -} - -static void ir_print_inst_src(IrPrintSrc *irp, Stage1ZirInst *instruction, bool trailing) { - ir_print_prefix_src(irp, instruction, trailing); - switch (instruction->id) { - case Stage1ZirInstIdInvalid: - zig_unreachable(); - case Stage1ZirInstIdReturn: - ir_print_return_src(irp, (Stage1ZirInstReturn *)instruction); - break; - case Stage1ZirInstIdConst: - ir_print_const(irp, (Stage1ZirInstConst *)instruction); - break; - case Stage1ZirInstIdBinOp: - ir_print_bin_op(irp, (Stage1ZirInstBinOp *)instruction); - break; - case Stage1ZirInstIdMergeErrSets: - ir_print_merge_err_sets(irp, (Stage1ZirInstMergeErrSets *)instruction); - break; - case Stage1ZirInstIdDeclVar: - ir_print_decl_var_src(irp, (Stage1ZirInstDeclVar *)instruction); - break; - case Stage1ZirInstIdCallExtra: - ir_print_call_extra(irp, (Stage1ZirInstCallExtra *)instruction); - break; - case Stage1ZirInstIdAsyncCallExtra: - ir_print_async_call_extra(irp, (Stage1ZirInstAsyncCallExtra *)instruction); - break; - case Stage1ZirInstIdCall: - ir_print_call_src(irp, (Stage1ZirInstCall *)instruction); - break; - case Stage1ZirInstIdCallArgs: - ir_print_call_args(irp, (Stage1ZirInstCallArgs *)instruction); - break; - case Stage1ZirInstIdUnOp: - ir_print_un_op(irp, (Stage1ZirInstUnOp *)instruction); - break; - case Stage1ZirInstIdCondBr: - ir_print_cond_br(irp, (Stage1ZirInstCondBr *)instruction); - break; - case Stage1ZirInstIdBr: - ir_print_br(irp, (Stage1ZirInstBr *)instruction); - break; - case Stage1ZirInstIdPhi: - ir_print_phi(irp, (Stage1ZirInstPhi *)instruction); - break; - case Stage1ZirInstIdContainerInitList: - ir_print_container_init_list(irp, (Stage1ZirInstContainerInitList *)instruction); - break; - case Stage1ZirInstIdContainerInitFields: - ir_print_container_init_fields(irp, (Stage1ZirInstContainerInitFields *)instruction); - break; - case Stage1ZirInstIdUnreachable: - ir_print_unreachable(irp, (Stage1ZirInstUnreachable *)instruction); - break; - case Stage1ZirInstIdElemPtr: - ir_print_elem_ptr(irp, (Stage1ZirInstElemPtr *)instruction); - break; - case Stage1ZirInstIdVarPtr: - ir_print_var_ptr(irp, (Stage1ZirInstVarPtr *)instruction); - break; - case Stage1ZirInstIdLoadPtr: - ir_print_load_ptr(irp, (Stage1ZirInstLoadPtr *)instruction); - break; - case Stage1ZirInstIdStorePtr: - ir_print_store_ptr(irp, (Stage1ZirInstStorePtr *)instruction); - break; - case Stage1ZirInstIdTypeOf: - ir_print_typeof(irp, (Stage1ZirInstTypeOf *)instruction); - break; - case Stage1ZirInstIdFieldPtr: - ir_print_field_ptr(irp, (Stage1ZirInstFieldPtr *)instruction); - break; - case Stage1ZirInstIdSetCold: - ir_print_set_cold(irp, (Stage1ZirInstSetCold *)instruction); - break; - case Stage1ZirInstIdSetRuntimeSafety: - ir_print_set_runtime_safety(irp, (Stage1ZirInstSetRuntimeSafety *)instruction); - break; - case Stage1ZirInstIdSetFloatMode: - ir_print_set_float_mode(irp, (Stage1ZirInstSetFloatMode *)instruction); - break; - case Stage1ZirInstIdArrayType: - ir_print_array_type(irp, (Stage1ZirInstArrayType *)instruction); - break; - case Stage1ZirInstIdSliceType: - ir_print_slice_type(irp, (Stage1ZirInstSliceType *)instruction); - break; - case Stage1ZirInstIdAnyFrameType: - ir_print_any_frame_type(irp, (Stage1ZirInstAnyFrameType *)instruction); - break; - case Stage1ZirInstIdAsm: - ir_print_asm_src(irp, (Stage1ZirInstAsm *)instruction); - break; - case Stage1ZirInstIdSizeOf: - ir_print_size_of(irp, (Stage1ZirInstSizeOf *)instruction); - break; - case Stage1ZirInstIdTestNonNull: - ir_print_test_non_null(irp, (Stage1ZirInstTestNonNull *)instruction); - break; - case Stage1ZirInstIdOptionalUnwrapPtr: - ir_print_optional_unwrap_ptr(irp, (Stage1ZirInstOptionalUnwrapPtr *)instruction); - break; - case Stage1ZirInstIdPopCount: - ir_print_pop_count(irp, (Stage1ZirInstPopCount *)instruction); - break; - case Stage1ZirInstIdCtz: - ir_print_ctz(irp, (Stage1ZirInstCtz *)instruction); - break; - case Stage1ZirInstIdBswap: - ir_print_bswap(irp, (Stage1ZirInstBswap *)instruction); - break; - case Stage1ZirInstIdBitReverse: - ir_print_bit_reverse(irp, (Stage1ZirInstBitReverse *)instruction); - break; - case Stage1ZirInstIdSwitchBr: - ir_print_switch_br(irp, (Stage1ZirInstSwitchBr *)instruction); - break; - case Stage1ZirInstIdSwitchVar: - ir_print_switch_var(irp, (Stage1ZirInstSwitchVar *)instruction); - break; - case Stage1ZirInstIdSwitchElseVar: - ir_print_switch_else_var(irp, (Stage1ZirInstSwitchElseVar *)instruction); - break; - case Stage1ZirInstIdSwitchTarget: - ir_print_switch_target(irp, (Stage1ZirInstSwitchTarget *)instruction); - break; - case Stage1ZirInstIdImport: - ir_print_import(irp, (Stage1ZirInstImport *)instruction); - break; - case Stage1ZirInstIdRef: - ir_print_ref(irp, (Stage1ZirInstRef *)instruction); - break; - case Stage1ZirInstIdCompileErr: - ir_print_compile_err(irp, (Stage1ZirInstCompileErr *)instruction); - break; - case Stage1ZirInstIdCompileLog: - ir_print_compile_log(irp, (Stage1ZirInstCompileLog *)instruction); - break; - case Stage1ZirInstIdErrName: - ir_print_err_name(irp, (Stage1ZirInstErrName *)instruction); - break; - case Stage1ZirInstIdCImport: - ir_print_c_import(irp, (Stage1ZirInstCImport *)instruction); - break; - case Stage1ZirInstIdCInclude: - ir_print_c_include(irp, (Stage1ZirInstCInclude *)instruction); - break; - case Stage1ZirInstIdCDefine: - ir_print_c_define(irp, (Stage1ZirInstCDefine *)instruction); - break; - case Stage1ZirInstIdCUndef: - ir_print_c_undef(irp, (Stage1ZirInstCUndef *)instruction); - break; - case Stage1ZirInstIdEmbedFile: - ir_print_embed_file(irp, (Stage1ZirInstEmbedFile *)instruction); - break; - case Stage1ZirInstIdCmpxchg: - ir_print_cmpxchg_src(irp, (Stage1ZirInstCmpxchg *)instruction); - break; - case Stage1ZirInstIdFence: - ir_print_fence(irp, (Stage1ZirInstFence *)instruction); - break; - case Stage1ZirInstIdReduce: - ir_print_reduce(irp, (Stage1ZirInstReduce *)instruction); - break; - case Stage1ZirInstIdTruncate: - ir_print_truncate(irp, (Stage1ZirInstTruncate *)instruction); - break; - case Stage1ZirInstIdIntCast: - ir_print_int_cast(irp, (Stage1ZirInstIntCast *)instruction); - break; - case Stage1ZirInstIdFloatCast: - ir_print_float_cast(irp, (Stage1ZirInstFloatCast *)instruction); - break; - case Stage1ZirInstIdErrSetCast: - ir_print_err_set_cast(irp, (Stage1ZirInstErrSetCast *)instruction); - break; - case Stage1ZirInstIdIntToFloat: - ir_print_int_to_float(irp, (Stage1ZirInstIntToFloat *)instruction); - break; - case Stage1ZirInstIdFloatToInt: - ir_print_float_to_int(irp, (Stage1ZirInstFloatToInt *)instruction); - break; - case Stage1ZirInstIdBoolToInt: - ir_print_bool_to_int(irp, (Stage1ZirInstBoolToInt *)instruction); - break; - case Stage1ZirInstIdVectorType: - ir_print_vector_type(irp, (Stage1ZirInstVectorType *)instruction); - break; - case Stage1ZirInstIdShuffleVector: - ir_print_shuffle_vector(irp, (Stage1ZirInstShuffleVector *)instruction); - break; - case Stage1ZirInstIdSelect: - ir_print_select(irp, (Stage1ZirInstSelect *)instruction); - break; - case Stage1ZirInstIdSplat: - ir_print_splat_src(irp, (Stage1ZirInstSplat *)instruction); - break; - case Stage1ZirInstIdBoolNot: - ir_print_bool_not(irp, (Stage1ZirInstBoolNot *)instruction); - break; - case Stage1ZirInstIdMemset: - ir_print_memset(irp, (Stage1ZirInstMemset *)instruction); - break; - case Stage1ZirInstIdMemcpy: - ir_print_memcpy(irp, (Stage1ZirInstMemcpy *)instruction); - break; - case Stage1ZirInstIdSlice: - ir_print_slice_src(irp, (Stage1ZirInstSlice *)instruction); - break; - case Stage1ZirInstIdBreakpoint: - ir_print_breakpoint(irp, (Stage1ZirInstBreakpoint *)instruction); - break; - case Stage1ZirInstIdReturnAddress: - ir_print_return_address(irp, (Stage1ZirInstReturnAddress *)instruction); - break; - case Stage1ZirInstIdFrameAddress: - ir_print_frame_address(irp, (Stage1ZirInstFrameAddress *)instruction); - break; - case Stage1ZirInstIdFrameHandle: - ir_print_handle(irp, (Stage1ZirInstFrameHandle *)instruction); - break; - case Stage1ZirInstIdFrameType: - ir_print_frame_type(irp, (Stage1ZirInstFrameType *)instruction); - break; - case Stage1ZirInstIdFrameSize: - ir_print_frame_size_src(irp, (Stage1ZirInstFrameSize *)instruction); - break; - case Stage1ZirInstIdAlignOf: - ir_print_align_of(irp, (Stage1ZirInstAlignOf *)instruction); - break; - case Stage1ZirInstIdOverflowOp: - ir_print_overflow_op(irp, (Stage1ZirInstOverflowOp *)instruction); - break; - case Stage1ZirInstIdTestErr: - ir_print_test_err_src(irp, (Stage1ZirInstTestErr *)instruction); - break; - case Stage1ZirInstIdUnwrapErrCode: - ir_print_unwrap_err_code(irp, (Stage1ZirInstUnwrapErrCode *)instruction); - break; - case Stage1ZirInstIdUnwrapErrPayload: - ir_print_unwrap_err_payload(irp, (Stage1ZirInstUnwrapErrPayload *)instruction); - break; - case Stage1ZirInstIdFnProto: - ir_print_fn_proto(irp, (Stage1ZirInstFnProto *)instruction); - break; - case Stage1ZirInstIdTestComptime: - ir_print_test_comptime(irp, (Stage1ZirInstTestComptime *)instruction); - break; - case Stage1ZirInstIdPtrCast: - ir_print_ptr_cast_src(irp, (Stage1ZirInstPtrCast *)instruction); - break; - case Stage1ZirInstIdBitCast: - ir_print_bit_cast_src(irp, (Stage1ZirInstBitCast *)instruction); - break; - case Stage1ZirInstIdPtrToInt: - ir_print_ptr_to_int(irp, (Stage1ZirInstPtrToInt *)instruction); - break; - case Stage1ZirInstIdIntToPtr: - ir_print_int_to_ptr(irp, (Stage1ZirInstIntToPtr *)instruction); - break; - case Stage1ZirInstIdIntToEnum: - ir_print_int_to_enum(irp, (Stage1ZirInstIntToEnum *)instruction); - break; - case Stage1ZirInstIdIntToErr: - ir_print_int_to_err(irp, (Stage1ZirInstIntToErr *)instruction); - break; - case Stage1ZirInstIdErrToInt: - ir_print_err_to_int(irp, (Stage1ZirInstErrToInt *)instruction); - break; - case Stage1ZirInstIdCheckSwitchProngsUnderNo: - ir_print_check_switch_prongs(irp, (Stage1ZirInstCheckSwitchProngs *)instruction, false); - break; - case Stage1ZirInstIdCheckSwitchProngsUnderYes: - ir_print_check_switch_prongs(irp, (Stage1ZirInstCheckSwitchProngs *)instruction, true); - break; - case Stage1ZirInstIdCheckStatementIsVoid: - ir_print_check_statement_is_void(irp, (Stage1ZirInstCheckStatementIsVoid *)instruction); - break; - case Stage1ZirInstIdTypeName: - ir_print_type_name(irp, (Stage1ZirInstTypeName *)instruction); - break; - case Stage1ZirInstIdTagName: - ir_print_tag_name(irp, (Stage1ZirInstTagName *)instruction); - break; - case Stage1ZirInstIdPtrType: - ir_print_ptr_type(irp, (Stage1ZirInstPtrType *)instruction); - break; - case Stage1ZirInstIdPtrTypeSimple: - ir_print_ptr_type_simple(irp, (Stage1ZirInstPtrTypeSimple *)instruction, false); - break; - case Stage1ZirInstIdPtrTypeSimpleConst: - ir_print_ptr_type_simple(irp, (Stage1ZirInstPtrTypeSimple *)instruction, true); - break; - case Stage1ZirInstIdDeclRef: - ir_print_decl_ref(irp, (Stage1ZirInstDeclRef *)instruction); - break; - case Stage1ZirInstIdPanic: - ir_print_panic(irp, (Stage1ZirInstPanic *)instruction); - break; - case Stage1ZirInstIdFieldParentPtr: - ir_print_field_parent_ptr(irp, (Stage1ZirInstFieldParentPtr *)instruction); - break; - case Stage1ZirInstIdOffsetOf: - ir_print_offset_of(irp, (Stage1ZirInstOffsetOf *)instruction); - break; - case Stage1ZirInstIdBitOffsetOf: - ir_print_bit_offset_of(irp, (Stage1ZirInstBitOffsetOf *)instruction); - break; - case Stage1ZirInstIdTypeInfo: - ir_print_type_info(irp, (Stage1ZirInstTypeInfo *)instruction); - break; - case Stage1ZirInstIdType: - ir_print_type(irp, (Stage1ZirInstType *)instruction); - break; - case Stage1ZirInstIdHasField: - ir_print_has_field(irp, (Stage1ZirInstHasField *)instruction); - break; - case Stage1ZirInstIdSetEvalBranchQuota: - ir_print_set_eval_branch_quota(irp, (Stage1ZirInstSetEvalBranchQuota *)instruction); - break; - case Stage1ZirInstIdAlignCast: - ir_print_align_cast(irp, (Stage1ZirInstAlignCast *)instruction); - break; - case Stage1ZirInstIdImplicitCast: - ir_print_implicit_cast(irp, (Stage1ZirInstImplicitCast *)instruction); - break; - case Stage1ZirInstIdResolveResult: - ir_print_resolve_result(irp, (Stage1ZirInstResolveResult *)instruction); - break; - case Stage1ZirInstIdResetResult: - ir_print_reset_result(irp, (Stage1ZirInstResetResult *)instruction); - break; - case Stage1ZirInstIdSetAlignStack: - ir_print_set_align_stack(irp, (Stage1ZirInstSetAlignStack *)instruction); - break; - case Stage1ZirInstIdArgTypeAllowVarFalse: - ir_print_arg_type(irp, (Stage1ZirInstArgType *)instruction, false); - break; - case Stage1ZirInstIdArgTypeAllowVarTrue: - ir_print_arg_type(irp, (Stage1ZirInstArgType *)instruction, true); - break; - case Stage1ZirInstIdExport: - ir_print_export(irp, (Stage1ZirInstExport *)instruction); - break; - case Stage1ZirInstIdExtern: - ir_print_extern(irp, (Stage1ZirInstExtern*)instruction); - break; - case Stage1ZirInstIdErrorReturnTrace: - ir_print_error_return_trace(irp, (Stage1ZirInstErrorReturnTrace *)instruction); - break; - case Stage1ZirInstIdErrorUnion: - ir_print_error_union(irp, (Stage1ZirInstErrorUnion *)instruction); - break; - case Stage1ZirInstIdAtomicRmw: - ir_print_atomic_rmw(irp, (Stage1ZirInstAtomicRmw *)instruction); - break; - case Stage1ZirInstIdSaveErrRetAddr: - ir_print_save_err_ret_addr(irp, (Stage1ZirInstSaveErrRetAddr *)instruction); - break; - case Stage1ZirInstIdAddImplicitReturnType: - ir_print_add_implicit_return_type(irp, (Stage1ZirInstAddImplicitReturnType *)instruction); - break; - case Stage1ZirInstIdFloatOp: - ir_print_float_op(irp, (Stage1ZirInstFloatOp *)instruction); - break; - case Stage1ZirInstIdMulAdd: - ir_print_mul_add(irp, (Stage1ZirInstMulAdd *)instruction); - break; - case Stage1ZirInstIdAtomicLoad: - ir_print_atomic_load(irp, (Stage1ZirInstAtomicLoad *)instruction); - break; - case Stage1ZirInstIdAtomicStore: - ir_print_atomic_store(irp, (Stage1ZirInstAtomicStore *)instruction); - break; - case Stage1ZirInstIdEnumToInt: - ir_print_enum_to_int(irp, (Stage1ZirInstEnumToInt *)instruction); - break; - case Stage1ZirInstIdCheckRuntimeScope: - ir_print_check_runtime_scope(irp, (Stage1ZirInstCheckRuntimeScope *)instruction); - break; - case Stage1ZirInstIdHasDecl: - ir_print_has_decl(irp, (Stage1ZirInstHasDecl *)instruction); - break; - case Stage1ZirInstIdUndeclaredIdent: - ir_print_undeclared_ident(irp, (Stage1ZirInstUndeclaredIdent *)instruction); - break; - case Stage1ZirInstIdAlloca: - ir_print_alloca_src(irp, (Stage1ZirInstAlloca *)instruction); - break; - case Stage1ZirInstIdEndExpr: - ir_print_end_expr(irp, (Stage1ZirInstEndExpr *)instruction); - break; - case Stage1ZirInstIdUnionInitNamedField: - ir_print_union_init_named_field(irp, (Stage1ZirInstUnionInitNamedField *)instruction); - break; - case Stage1ZirInstIdSuspendBegin: - ir_print_suspend_begin(irp, (Stage1ZirInstSuspendBegin *)instruction); - break; - case Stage1ZirInstIdSuspendFinish: - ir_print_suspend_finish(irp, (Stage1ZirInstSuspendFinish *)instruction); - break; - case Stage1ZirInstIdResume: - ir_print_resume(irp, (Stage1ZirInstResume *)instruction); - break; - case Stage1ZirInstIdAwait: - ir_print_await_src(irp, (Stage1ZirInstAwait *)instruction); - break; - case Stage1ZirInstIdSpillBegin: - ir_print_spill_begin(irp, (Stage1ZirInstSpillBegin *)instruction); - break; - case Stage1ZirInstIdSpillEnd: - ir_print_spill_end(irp, (Stage1ZirInstSpillEnd *)instruction); - break; - case Stage1ZirInstIdClz: - ir_print_clz(irp, (Stage1ZirInstClz *)instruction); - break; - case Stage1ZirInstIdWasmMemorySize: - ir_print_wasm_memory_size(irp, (Stage1ZirInstWasmMemorySize *)instruction); - break; - case Stage1ZirInstIdWasmMemoryGrow: - ir_print_wasm_memory_grow(irp, (Stage1ZirInstWasmMemoryGrow *)instruction); - break; - case Stage1ZirInstIdSrc: - ir_print_builtin_src(irp, (Stage1ZirInstSrc *)instruction); - break; - case Stage1ZirInstIdPrefetch: - ir_print_prefetch(irp, (Stage1ZirInstPrefetch *)instruction); - break; - case Stage1ZirInstIdAddrSpaceCast: - ir_print_addrspace_cast(irp, (Stage1ZirInstAddrSpaceCast *)instruction); - break; - } - fprintf(irp->f, "\n"); -} - -static void ir_print_inst_gen(IrPrintGen *irp, Stage1AirInst *instruction, bool trailing) { - ir_print_prefix_gen(irp, instruction, trailing); - switch (instruction->id) { - case Stage1AirInstIdInvalid: - zig_unreachable(); - case Stage1AirInstIdReturn: - ir_print_return_gen(irp, (Stage1AirInstReturn *)instruction); - break; - case Stage1AirInstIdConst: - ir_print_const(irp, (Stage1AirInstConst *)instruction); - break; - case Stage1AirInstIdBinOp: - ir_print_bin_op(irp, (Stage1AirInstBinOp *)instruction); - break; - case Stage1AirInstIdDeclVar: - ir_print_decl_var_gen(irp, (Stage1AirInstDeclVar *)instruction); - break; - case Stage1AirInstIdCast: - ir_print_cast(irp, (Stage1AirInstCast *)instruction); - break; - case Stage1AirInstIdCall: - ir_print_call_gen(irp, (Stage1AirInstCall *)instruction); - break; - case Stage1AirInstIdCondBr: - ir_print_cond_br(irp, (Stage1AirInstCondBr *)instruction); - break; - case Stage1AirInstIdBr: - ir_print_br(irp, (Stage1AirInstBr *)instruction); - break; - case Stage1AirInstIdPhi: - ir_print_phi(irp, (Stage1AirInstPhi *)instruction); - break; - case Stage1AirInstIdUnreachable: - ir_print_unreachable(irp, (Stage1AirInstUnreachable *)instruction); - break; - case Stage1AirInstIdElemPtr: - ir_print_elem_ptr(irp, (Stage1AirInstElemPtr *)instruction); - break; - case Stage1AirInstIdVarPtr: - ir_print_var_ptr(irp, (Stage1AirInstVarPtr *)instruction); - break; - case Stage1AirInstIdReturnPtr: - ir_print_return_ptr(irp, (Stage1AirInstReturnPtr *)instruction); - break; - case Stage1AirInstIdLoadPtr: - ir_print_load_ptr_gen(irp, (Stage1AirInstLoadPtr *)instruction); - break; - case Stage1AirInstIdStorePtr: - ir_print_store_ptr(irp, (Stage1AirInstStorePtr *)instruction); - break; - case Stage1AirInstIdStructFieldPtr: - ir_print_struct_field_ptr(irp, (Stage1AirInstStructFieldPtr *)instruction); - break; - case Stage1AirInstIdUnionFieldPtr: - ir_print_union_field_ptr(irp, (Stage1AirInstUnionFieldPtr *)instruction); - break; - case Stage1AirInstIdAsm: - ir_print_asm_gen(irp, (Stage1AirInstAsm *)instruction); - break; - case Stage1AirInstIdTestNonNull: - ir_print_test_non_null(irp, (Stage1AirInstTestNonNull *)instruction); - break; - case Stage1AirInstIdOptionalUnwrapPtr: - ir_print_optional_unwrap_ptr(irp, (Stage1AirInstOptionalUnwrapPtr *)instruction); - break; - case Stage1AirInstIdPopCount: - ir_print_pop_count(irp, (Stage1AirInstPopCount *)instruction); - break; - case Stage1AirInstIdClz: - ir_print_clz(irp, (Stage1AirInstClz *)instruction); - break; - case Stage1AirInstIdCtz: - ir_print_ctz(irp, (Stage1AirInstCtz *)instruction); - break; - case Stage1AirInstIdBswap: - ir_print_bswap(irp, (Stage1AirInstBswap *)instruction); - break; - case Stage1AirInstIdBitReverse: - ir_print_bit_reverse(irp, (Stage1AirInstBitReverse *)instruction); - break; - case Stage1AirInstIdSwitchBr: - ir_print_switch_br(irp, (Stage1AirInstSwitchBr *)instruction); - break; - case Stage1AirInstIdUnionTag: - ir_print_union_tag(irp, (Stage1AirInstUnionTag *)instruction); - break; - case Stage1AirInstIdRef: - ir_print_ref_gen(irp, (Stage1AirInstRef *)instruction); - break; - case Stage1AirInstIdErrName: - ir_print_err_name(irp, (Stage1AirInstErrName *)instruction); - break; - case Stage1AirInstIdCmpxchg: - ir_print_cmpxchg_gen(irp, (Stage1AirInstCmpxchg *)instruction); - break; - case Stage1AirInstIdFence: - ir_print_fence(irp, (Stage1AirInstFence *)instruction); - break; - case Stage1AirInstIdReduce: - ir_print_reduce(irp, (Stage1AirInstReduce *)instruction); - break; - case Stage1AirInstIdTruncate: - ir_print_truncate(irp, (Stage1AirInstTruncate *)instruction); - break; - case Stage1AirInstIdShuffleVector: - ir_print_shuffle_vector(irp, (Stage1AirInstShuffleVector *)instruction); - break; - case Stage1AirInstIdSelect: - ir_print_select(irp, (Stage1AirInstSelect *)instruction); - break; - case Stage1AirInstIdSplat: - ir_print_splat_gen(irp, (Stage1AirInstSplat *)instruction); - break; - case Stage1AirInstIdBoolNot: - ir_print_bool_not(irp, (Stage1AirInstBoolNot *)instruction); - break; - case Stage1AirInstIdMemset: - ir_print_memset(irp, (Stage1AirInstMemset *)instruction); - break; - case Stage1AirInstIdMemcpy: - ir_print_memcpy(irp, (Stage1AirInstMemcpy *)instruction); - break; - case Stage1AirInstIdSlice: - ir_print_slice_gen(irp, (Stage1AirInstSlice *)instruction); - break; - case Stage1AirInstIdBreakpoint: - ir_print_breakpoint(irp, (Stage1AirInstBreakpoint *)instruction); - break; - case Stage1AirInstIdReturnAddress: - ir_print_return_address(irp, (Stage1AirInstReturnAddress *)instruction); - break; - case Stage1AirInstIdFrameAddress: - ir_print_frame_address(irp, (Stage1AirInstFrameAddress *)instruction); - break; - case Stage1AirInstIdFrameHandle: - ir_print_handle(irp, (Stage1AirInstFrameHandle *)instruction); - break; - case Stage1AirInstIdFrameSize: - ir_print_frame_size_gen(irp, (Stage1AirInstFrameSize *)instruction); - break; - case Stage1AirInstIdOverflowOp: - ir_print_overflow_op(irp, (Stage1AirInstOverflowOp *)instruction); - break; - case Stage1AirInstIdTestErr: - ir_print_test_err_gen(irp, (Stage1AirInstTestErr *)instruction); - break; - case Stage1AirInstIdUnwrapErrCode: - ir_print_unwrap_err_code(irp, (Stage1AirInstUnwrapErrCode *)instruction); - break; - case Stage1AirInstIdUnwrapErrPayload: - ir_print_unwrap_err_payload(irp, (Stage1AirInstUnwrapErrPayload *)instruction); - break; - case Stage1AirInstIdOptionalWrap: - ir_print_optional_wrap(irp, (Stage1AirInstOptionalWrap *)instruction); - break; - case Stage1AirInstIdErrWrapCode: - ir_print_err_wrap_code(irp, (Stage1AirInstErrWrapCode *)instruction); - break; - case Stage1AirInstIdErrWrapPayload: - ir_print_err_wrap_payload(irp, (Stage1AirInstErrWrapPayload *)instruction); - break; - case Stage1AirInstIdPtrCast: - ir_print_ptr_cast_gen(irp, (Stage1AirInstPtrCast *)instruction); - break; - case Stage1AirInstIdBitCast: - ir_print_bit_cast_gen(irp, (Stage1AirInstBitCast *)instruction); - break; - case Stage1AirInstIdWidenOrShorten: - ir_print_widen_or_shorten(irp, (Stage1AirInstWidenOrShorten *)instruction); - break; - case Stage1AirInstIdPtrToInt: - ir_print_ptr_to_int(irp, (Stage1AirInstPtrToInt *)instruction); - break; - case Stage1AirInstIdIntToPtr: - ir_print_int_to_ptr(irp, (Stage1AirInstIntToPtr *)instruction); - break; - case Stage1AirInstIdIntToEnum: - ir_print_int_to_enum(irp, (Stage1AirInstIntToEnum *)instruction); - break; - case Stage1AirInstIdIntToErr: - ir_print_int_to_err(irp, (Stage1AirInstIntToErr *)instruction); - break; - case Stage1AirInstIdErrToInt: - ir_print_err_to_int(irp, (Stage1AirInstErrToInt *)instruction); - break; - case Stage1AirInstIdTagName: - ir_print_tag_name(irp, (Stage1AirInstTagName *)instruction); - break; - case Stage1AirInstIdPanic: - ir_print_panic(irp, (Stage1AirInstPanic *)instruction); - break; - case Stage1AirInstIdFieldParentPtr: - ir_print_field_parent_ptr(irp, (Stage1AirInstFieldParentPtr *)instruction); - break; - case Stage1AirInstIdAlignCast: - ir_print_align_cast(irp, (Stage1AirInstAlignCast *)instruction); - break; - case Stage1AirInstIdErrorReturnTrace: - ir_print_error_return_trace(irp, (Stage1AirInstErrorReturnTrace *)instruction); - break; - case Stage1AirInstIdAtomicRmw: - ir_print_atomic_rmw(irp, (Stage1AirInstAtomicRmw *)instruction); - break; - case Stage1AirInstIdSaveErrRetAddr: - ir_print_save_err_ret_addr(irp, (Stage1AirInstSaveErrRetAddr *)instruction); - break; - case Stage1AirInstIdFloatOp: - ir_print_float_op(irp, (Stage1AirInstFloatOp *)instruction); - break; - case Stage1AirInstIdMulAdd: - ir_print_mul_add(irp, (Stage1AirInstMulAdd *)instruction); - break; - case Stage1AirInstIdAtomicLoad: - ir_print_atomic_load(irp, (Stage1AirInstAtomicLoad *)instruction); - break; - case Stage1AirInstIdAtomicStore: - ir_print_atomic_store(irp, (Stage1AirInstAtomicStore *)instruction); - break; - case Stage1AirInstIdArrayToVector: - ir_print_array_to_vector(irp, (Stage1AirInstArrayToVector *)instruction); - break; - case Stage1AirInstIdVectorToArray: - ir_print_vector_to_array(irp, (Stage1AirInstVectorToArray *)instruction); - break; - case Stage1AirInstIdPtrOfArrayToSlice: - ir_print_ptr_of_array_to_slice(irp, (Stage1AirInstPtrOfArrayToSlice *)instruction); - break; - case Stage1AirInstIdAssertZero: - ir_print_assert_zero(irp, (Stage1AirInstAssertZero *)instruction); - break; - case Stage1AirInstIdAssertNonNull: - ir_print_assert_non_null(irp, (Stage1AirInstAssertNonNull *)instruction); - break; - case Stage1AirInstIdAlloca: - ir_print_alloca_gen(irp, (Stage1AirInstAlloca *)instruction); - break; - case Stage1AirInstIdSuspendBegin: - ir_print_suspend_begin(irp, (Stage1AirInstSuspendBegin *)instruction); - break; - case Stage1AirInstIdSuspendFinish: - ir_print_suspend_finish(irp, (Stage1AirInstSuspendFinish *)instruction); - break; - case Stage1AirInstIdResume: - ir_print_resume(irp, (Stage1AirInstResume *)instruction); - break; - case Stage1AirInstIdAwait: - ir_print_await_gen(irp, (Stage1AirInstAwait *)instruction); - break; - case Stage1AirInstIdSpillBegin: - ir_print_spill_begin(irp, (Stage1AirInstSpillBegin *)instruction); - break; - case Stage1AirInstIdSpillEnd: - ir_print_spill_end(irp, (Stage1AirInstSpillEnd *)instruction); - break; - case Stage1AirInstIdVectorExtractElem: - ir_print_vector_extract_elem(irp, (Stage1AirInstVectorExtractElem *)instruction); - break; - case Stage1AirInstIdVectorStoreElem: - ir_print_vector_store_elem(irp, (Stage1AirInstVectorStoreElem *)instruction); - break; - case Stage1AirInstIdBinaryNot: - ir_print_binary_not(irp, (Stage1AirInstBinaryNot *)instruction); - break; - case Stage1AirInstIdNegation: - ir_print_negation(irp, (Stage1AirInstNegation *)instruction); - break; - case Stage1AirInstIdWasmMemorySize: - ir_print_wasm_memory_size(irp, (Stage1AirInstWasmMemorySize *)instruction); - break; - case Stage1AirInstIdWasmMemoryGrow: - ir_print_wasm_memory_grow(irp, (Stage1AirInstWasmMemoryGrow *)instruction); - break; - case Stage1AirInstIdExtern: - ir_print_extern(irp, (Stage1AirInstExtern *)instruction); - break; - case Stage1AirInstIdPrefetch: - ir_print_prefetch(irp, (Stage1AirInstPrefetch *)instruction); - break; - - } - fprintf(irp->f, "\n"); -} - -static void irp_print_basic_block_src(IrPrintSrc *irp, Stage1ZirBasicBlock *current_block) { - fprintf(irp->f, "%s_%" PRIu32 ":\n", current_block->name_hint, current_block->debug_id); - for (size_t instr_i = 0; instr_i < current_block->instruction_list.length; instr_i += 1) { - Stage1ZirInst *instruction = current_block->instruction_list.at(instr_i); - ir_print_inst_src(irp, instruction, false); - } -} - -static void irp_print_basic_block_gen(IrPrintGen *irp, Stage1AirBasicBlock *current_block) { - fprintf(irp->f, "%s_%" PRIu32 ":\n", current_block->name_hint, current_block->debug_id); - for (size_t instr_i = 0; instr_i < current_block->instruction_list.length; instr_i += 1) { - Stage1AirInst *instruction = current_block->instruction_list.at(instr_i); - irp->printed.put(instruction, 0); - irp->pending.clear(); - ir_print_inst_gen(irp, instruction, false); - for (size_t j = 0; j < irp->pending.length; ++j) - ir_print_inst_gen(irp, irp->pending.at(j), true); - } -} - -void ir_print_basic_block_src(CodeGen *codegen, FILE *f, Stage1ZirBasicBlock *bb, int indent_size) { - IrPrintSrc ir_print = {}; - ir_print.codegen = codegen; - ir_print.f = f; - ir_print.indent = indent_size; - ir_print.indent_size = indent_size; - - irp_print_basic_block_src(&ir_print, bb); -} - -void ir_print_basic_block_gen(CodeGen *codegen, FILE *f, Stage1AirBasicBlock *bb, int indent_size) { - IrPrintGen ir_print = {}; - ir_print.codegen = codegen; - ir_print.f = f; - ir_print.indent = indent_size; - ir_print.indent_size = indent_size; - ir_print.printed = {}; - ir_print.printed.init(64); - ir_print.pending = {}; - - irp_print_basic_block_gen(&ir_print, bb); - - ir_print.pending.deinit(); - ir_print.printed.deinit(); -} - -void ir_print_src(CodeGen *codegen, FILE *f, Stage1Zir *executable, int indent_size) { - IrPrintSrc ir_print = {}; - IrPrintSrc *irp = &ir_print; - irp->codegen = codegen; - irp->f = f; - irp->indent = indent_size; - irp->indent_size = indent_size; - - for (size_t bb_i = 0; bb_i < executable->basic_block_list.length; bb_i += 1) { - irp_print_basic_block_src(irp, executable->basic_block_list.at(bb_i)); - } -} - -void ir_print_gen(CodeGen *codegen, FILE *f, Stage1Air *executable, int indent_size) { - IrPrintGen ir_print = {}; - IrPrintGen *irp = &ir_print; - irp->codegen = codegen; - irp->f = f; - irp->indent = indent_size; - irp->indent_size = indent_size; - irp->printed = {}; - irp->printed.init(64); - irp->pending = {}; - - for (size_t bb_i = 0; bb_i < executable->basic_block_list.length; bb_i += 1) { - irp_print_basic_block_gen(irp, executable->basic_block_list.at(bb_i)); - } - - irp->pending.deinit(); - irp->printed.deinit(); -} - -void ir_print_inst_src(CodeGen *codegen, FILE *f, Stage1ZirInst *instruction, int indent_size) { - IrPrintSrc ir_print = {}; - IrPrintSrc *irp = &ir_print; - irp->codegen = codegen; - irp->f = f; - irp->indent = indent_size; - irp->indent_size = indent_size; - - ir_print_inst_src(irp, instruction, false); -} - -void ir_print_inst_gen(CodeGen *codegen, FILE *f, Stage1AirInst *instruction, int indent_size) { - IrPrintGen ir_print = {}; - IrPrintGen *irp = &ir_print; - irp->codegen = codegen; - irp->f = f; - irp->indent = indent_size; - irp->indent_size = indent_size; - irp->printed = {}; - irp->printed.init(4); - irp->pending = {}; - - ir_print_inst_gen(irp, instruction, false); -} - -void Stage1ZirInst::dump() { - Stage1ZirInst *inst = this; - inst->src(); - if (inst->scope == nullptr) { - fprintf(stderr, "(null scope)\n"); - } else { - ir_print_inst_src(inst->scope->codegen, stderr, inst, 0); - fprintf(stderr, "-> "); - ir_print_inst_gen(inst->scope->codegen, stderr, inst->child, 0); - } -} diff --git a/src/stage1/ir_print.hpp b/src/stage1/ir_print.hpp deleted file mode 100644 index 1baddc5bd924..000000000000 --- a/src/stage1/ir_print.hpp +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright (c) 2016 Andrew Kelley - * - * This file is part of zig, which is MIT licensed. - * See http://opensource.org/licenses/MIT - */ - -#ifndef ZIG_IR_PRINT_HPP -#define ZIG_IR_PRINT_HPP - -#include "all_types.hpp" - -#include - -void ir_print_src(CodeGen *codegen, FILE *f, Stage1Zir *executable, int indent_size); -void ir_print_gen(CodeGen *codegen, FILE *f, Stage1Air *executable, int indent_size); -void ir_print_inst_src(CodeGen *codegen, FILE *f, Stage1ZirInst *inst, int indent_size); -void ir_print_inst_gen(CodeGen *codegen, FILE *f, Stage1AirInst *inst, int indent_size); -void ir_print_basic_block_src(CodeGen *codegen, FILE *f, Stage1ZirBasicBlock *bb, int indent_size); -void ir_print_basic_block_gen(CodeGen *codegen, FILE *f, Stage1AirBasicBlock *bb, int indent_size); - -const char* ir_inst_src_type_str(Stage1ZirInstId id); -const char* ir_inst_gen_type_str(Stage1AirInstId id); - -#endif diff --git a/src/stage1/list.hpp b/src/stage1/list.hpp deleted file mode 100644 index 803a2514371d..000000000000 --- a/src/stage1/list.hpp +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Copyright (c) 2015 Andrew Kelley - * - * This file is part of zig, which is MIT licensed. - * See http://opensource.org/licenses/MIT - */ - -#ifndef ZIG_LIST_HPP -#define ZIG_LIST_HPP - -#include "util.hpp" - -template -struct ZigList { - void deinit() { - heap::c_allocator.deallocate(items, capacity); - } - void append(const T& item) { - ensure_capacity(length + 1); - items[length++] = item; - } - void append_assuming_capacity(const T& item) { - items[length++] = item; - } - // remember that the pointer to this item is invalid after you - // modify the length of the list - const T & at(size_t index) const { - assert(index != SIZE_MAX); - assert(index < length); - return items[index]; - } - T & at(size_t index) { - assert(index != SIZE_MAX); - assert(index < length); - return items[index]; - } - T pop() { - assert(length >= 1); - return items[--length]; - } - - T *add_one() { - resize(length + 1); - return &last(); - } - - const T & last() const { - assert(length >= 1); - return items[length - 1]; - } - - T & last() { - assert(length >= 1); - return items[length - 1]; - } - - void resize(size_t new_length) { - assert(new_length != SIZE_MAX); - ensure_capacity(new_length); - length = new_length; - } - - void clear() { - length = 0; - } - - void ensure_capacity(size_t new_capacity) { - if (capacity >= new_capacity) - return; - - size_t better_capacity = capacity; - do { - better_capacity = better_capacity * 5 / 2 + 8; - } while (better_capacity < new_capacity); - - items = heap::c_allocator.reallocate_nonzero(items, capacity, better_capacity); - capacity = better_capacity; - } - - T swap_remove(size_t index) { - if (length - 1 == index) return pop(); - - assert(index != SIZE_MAX); - assert(index < length); - - T old_item = items[index]; - items[index] = pop(); - return old_item; - } - - T *items; - size_t length; - size_t capacity; -}; - -#endif diff --git a/src/stage1/mem.cpp b/src/stage1/mem.cpp deleted file mode 100644 index 5931c38e6e52..000000000000 --- a/src/stage1/mem.cpp +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright (c) 2020 Andrew Kelley - * - * This file is part of zig, which is MIT licensed. - * See http://opensource.org/licenses/MIT - */ - -#include "mem.hpp" -#include "heap.hpp" - -namespace mem { - -void init() { - heap::bootstrap_allocator_state.init("heap::bootstrap_allocator"); - heap::c_allocator_state.init("heap::c_allocator"); -} - -void deinit() { - heap::c_allocator_state.deinit(); - heap::bootstrap_allocator_state.deinit(); -} - -} // namespace mem diff --git a/src/stage1/mem.hpp b/src/stage1/mem.hpp deleted file mode 100644 index bf732412e4be..000000000000 --- a/src/stage1/mem.hpp +++ /dev/null @@ -1,139 +0,0 @@ -/* - * Copyright (c) 2020 Andrew Kelley - * - * This file is part of zig, which is MIT licensed. - * See http://opensource.org/licenses/MIT - */ - -#ifndef ZIG_MEM_HPP -#define ZIG_MEM_HPP - -#include -#include -#include - -#include "util_base.hpp" -#include "mem_type_info.hpp" - -// -// -- Memory Allocation General Notes -- -// -// `heap::c_allocator` is the preferred general allocator. -// -// `heap::bootstrap_allocator` is an implementation detail for use -// by allocators themselves when incidental heap may be required for -// profiling and statistics. It breaks the infinite recursion cycle. -// -// `mem::os` contains a raw wrapper for system malloc API used in -// preference to calling ::{malloc, free, calloc, realloc} directly. -// This isolates usage and helps with audits: -// -// mem::os::malloc -// mem::os::free -// mem::os::calloc -// mem::os::realloc -// -namespace mem { - -// initialize mem module before any use -void init(); - -// deinitialize mem module to free memory and print report -void deinit(); - -// isolate system/libc allocators -namespace os { - -ATTRIBUTE_RETURNS_NOALIAS -inline void *malloc(size_t size) { -#ifndef NDEBUG - // make behavior when size == 0 portable - if (size == 0) - return nullptr; -#endif - auto ptr = ::malloc(size); - if (ptr == nullptr) - zig_panic("allocation failed"); - return ptr; -} - -inline void free(void *ptr) { - ::free(ptr); -} - -ATTRIBUTE_RETURNS_NOALIAS -inline void *calloc(size_t count, size_t size) { -#ifndef NDEBUG - // make behavior when size == 0 portable - if (count == 0 || size == 0) - return nullptr; -#endif - auto ptr = ::calloc(count, size); - if (ptr == nullptr) - zig_panic("allocation failed"); - return ptr; -} - -inline void *realloc(void *old_ptr, size_t size) { -#ifndef NDEBUG - // make behavior when size == 0 portable - if (old_ptr == nullptr && size == 0) - return nullptr; -#endif - auto ptr = ::realloc(old_ptr, size); - if (ptr == nullptr) - zig_panic("allocation failed"); - return ptr; -} - -} // namespace os - -struct Allocator { - virtual void destruct(Allocator *allocator) = 0; - - template ATTRIBUTE_RETURNS_NOALIAS - T *allocate(size_t count) { - return reinterpret_cast(this->internal_allocate(TypeInfo::make(), count)); - } - - template ATTRIBUTE_RETURNS_NOALIAS - T *allocate_nonzero(size_t count) { - return reinterpret_cast(this->internal_allocate_nonzero(TypeInfo::make(), count)); - } - - template - T *reallocate(T *old_ptr, size_t old_count, size_t new_count) { - return reinterpret_cast(this->internal_reallocate(TypeInfo::make(), old_ptr, old_count, new_count)); - } - - template - T *reallocate_nonzero(T *old_ptr, size_t old_count, size_t new_count) { - return reinterpret_cast(this->internal_reallocate_nonzero(TypeInfo::make(), old_ptr, old_count, new_count)); - } - - template - void deallocate(T *ptr, size_t count) { - this->internal_deallocate(TypeInfo::make(), ptr, count); - } - - template - T *create() { - return reinterpret_cast(this->internal_allocate(TypeInfo::make(), 1)); - } - - template - void destroy(T *ptr) { - this->internal_deallocate(TypeInfo::make(), ptr, 1); - } - -protected: - ATTRIBUTE_RETURNS_NOALIAS virtual void *internal_allocate(const TypeInfo &info, size_t count) = 0; - ATTRIBUTE_RETURNS_NOALIAS virtual void *internal_allocate_nonzero(const TypeInfo &info, size_t count) = 0; - virtual void *internal_reallocate(const TypeInfo &info, void *old_ptr, size_t old_count, size_t new_count) = 0; - virtual void *internal_reallocate_nonzero(const TypeInfo &info, void *old_ptr, size_t old_count, size_t new_count) = 0; - virtual void internal_deallocate(const TypeInfo &info, void *ptr, size_t count) = 0; -}; - -} // namespace mem - -#endif diff --git a/src/stage1/mem_hash_map.hpp b/src/stage1/mem_hash_map.hpp deleted file mode 100644 index 6abbbf665003..000000000000 --- a/src/stage1/mem_hash_map.hpp +++ /dev/null @@ -1,244 +0,0 @@ -/* - * Copyright (c) 2015 Andrew Kelley - * - * This file is part of zig, which is MIT licensed. - * See http://opensource.org/licenses/MIT - */ - -#ifndef ZIG_MEM_HASH_MAP_HPP -#define ZIG_MEM_HASH_MAP_HPP - -#include "mem.hpp" - -namespace mem { - -template -class HashMap { -public: - void init(Allocator& allocator, int capacity) { - init_capacity(allocator, capacity); - } - void deinit(Allocator& allocator) { - allocator.deallocate(_entries, _capacity); - } - - struct Entry { - K key; - V value; - bool used; - int distance_from_start_index; - }; - - void clear() { - for (int i = 0; i < _capacity; i += 1) { - _entries[i].used = false; - } - _size = 0; - _max_distance_from_start_index = 0; - _modification_count += 1; - } - - int size() const { - return _size; - } - - void put(Allocator& allocator, const K &key, const V &value) { - _modification_count += 1; - internal_put(key, value); - - // if we get too full (60%), double the capacity - if (_size * 5 >= _capacity * 3) { - Entry *old_entries = _entries; - int old_capacity = _capacity; - init_capacity(allocator, _capacity * 2); - // dump all of the old elements into the new table - for (int i = 0; i < old_capacity; i += 1) { - Entry *old_entry = &old_entries[i]; - if (old_entry->used) - internal_put(old_entry->key, old_entry->value); - } - allocator.deallocate(old_entries, old_capacity); - } - } - - Entry *put_unique(Allocator& allocator, const K &key, const V &value) { - // TODO make this more efficient - Entry *entry = internal_get(key); - if (entry) - return entry; - put(allocator, key, value); - return nullptr; - } - - const V &get(const K &key) const { - Entry *entry = internal_get(key); - if (!entry) - zig_panic("key not found"); - return entry->value; - } - - Entry *maybe_get(const K &key) const { - return internal_get(key); - } - - void maybe_remove(const K &key) { - if (maybe_get(key)) { - remove(key); - } - } - - void remove(const K &key) { - _modification_count += 1; - int start_index = key_to_index(key); - for (int roll_over = 0; roll_over <= _max_distance_from_start_index; roll_over += 1) { - int index = (start_index + roll_over) % _capacity; - Entry *entry = &_entries[index]; - - if (!entry->used) - zig_panic("key not found"); - - if (!EqualFn(entry->key, key)) - continue; - - for (; roll_over < _capacity; roll_over += 1) { - int next_index = (start_index + roll_over + 1) % _capacity; - Entry *next_entry = &_entries[next_index]; - if (!next_entry->used || next_entry->distance_from_start_index == 0) { - entry->used = false; - _size -= 1; - return; - } - *entry = *next_entry; - entry->distance_from_start_index -= 1; - entry = next_entry; - } - zig_panic("shifting everything in the table"); - } - zig_panic("key not found"); - } - - class Iterator { - public: - Entry *next() { - if (_inital_modification_count != _table->_modification_count) - zig_panic("concurrent modification"); - if (_count >= _table->size()) - return NULL; - for (; _index < _table->_capacity; _index += 1) { - Entry *entry = &_table->_entries[_index]; - if (entry->used) { - _index += 1; - _count += 1; - return entry; - } - } - zig_panic("no next item"); - } - - private: - const HashMap * _table; - // how many items have we returned - int _count = 0; - // iterator through the entry array - int _index = 0; - // used to detect concurrent modification - uint32_t _inital_modification_count; - Iterator(const HashMap * table) : - _table(table), _inital_modification_count(table->_modification_count) { - } - friend HashMap; - }; - - // you must not modify the underlying HashMap while this iterator is still in use - Iterator entry_iterator() const { - return Iterator(this); - } - -private: - Entry *_entries; - int _capacity; - int _size; - int _max_distance_from_start_index; - // this is used to detect bugs where a hashtable is edited while an iterator is running. - uint32_t _modification_count; - - void init_capacity(Allocator& allocator, int capacity) { - _capacity = capacity; - _entries = allocator.allocate(_capacity); - _size = 0; - _max_distance_from_start_index = 0; - for (int i = 0; i < _capacity; i += 1) { - _entries[i].used = false; - } - } - - void internal_put(K key, V value) { - int start_index = key_to_index(key); - for (int roll_over = 0, distance_from_start_index = 0; - roll_over < _capacity; roll_over += 1, distance_from_start_index += 1) - { - int index = (start_index + roll_over) % _capacity; - Entry *entry = &_entries[index]; - - if (entry->used && !EqualFn(entry->key, key)) { - if (entry->distance_from_start_index < distance_from_start_index) { - // robin hood to the rescue - Entry tmp = *entry; - if (distance_from_start_index > _max_distance_from_start_index) - _max_distance_from_start_index = distance_from_start_index; - *entry = { - key, - value, - true, - distance_from_start_index, - }; - key = tmp.key; - value = tmp.value; - distance_from_start_index = tmp.distance_from_start_index; - } - continue; - } - - if (!entry->used) { - // adding an entry. otherwise overwriting old value with - // same key - _size += 1; - } - - if (distance_from_start_index > _max_distance_from_start_index) - _max_distance_from_start_index = distance_from_start_index; - *entry = { - key, - value, - true, - distance_from_start_index, - }; - return; - } - zig_panic("put into a full HashMap"); - } - - - Entry *internal_get(const K &key) const { - int start_index = key_to_index(key); - for (int roll_over = 0; roll_over <= _max_distance_from_start_index; roll_over += 1) { - int index = (start_index + roll_over) % _capacity; - Entry *entry = &_entries[index]; - - if (!entry->used) - return NULL; - - if (EqualFn(entry->key, key)) - return entry; - } - return NULL; - } - - int key_to_index(const K &key) const { - return (int)(HashFunction(key) % ((uint32_t)_capacity)); - } -}; - -} // namespace mem - -#endif diff --git a/src/stage1/mem_list.hpp b/src/stage1/mem_list.hpp deleted file mode 100644 index df82358ea954..000000000000 --- a/src/stage1/mem_list.hpp +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Copyright (c) 2015 Andrew Kelley - * - * This file is part of zig, which is MIT licensed. - * See http://opensource.org/licenses/MIT - */ - -#ifndef ZIG_MEM_LIST_HPP -#define ZIG_MEM_LIST_HPP - -#include "mem.hpp" - -namespace mem { - -template -struct List { - void deinit(Allocator *allocator) { - allocator->deallocate(items, capacity); - items = nullptr; - length = 0; - capacity = 0; - } - - void append(Allocator *allocator, const T& item) { - ensure_capacity(allocator, length + 1); - items[length++] = item; - } - - // remember that the pointer to this item is invalid after you - // modify the length of the list - const T & at(size_t index) const { - assert(index != SIZE_MAX); - assert(index < length); - return items[index]; - } - - T & at(size_t index) { - assert(index != SIZE_MAX); - assert(index < length); - return items[index]; - } - - T pop() { - assert(length >= 1); - return items[--length]; - } - - T *add_one() { - resize(length + 1); - return &last(); - } - - const T & last() const { - assert(length >= 1); - return items[length - 1]; - } - - T & last() { - assert(length >= 1); - return items[length - 1]; - } - - void resize(Allocator *allocator, size_t new_length) { - assert(new_length != SIZE_MAX); - ensure_capacity(allocator, new_length); - length = new_length; - } - - void clear() { - length = 0; - } - - void ensure_capacity(Allocator *allocator, size_t new_capacity) { - if (capacity >= new_capacity) - return; - - size_t better_capacity = capacity; - do { - better_capacity = better_capacity * 5 / 2 + 8; - } while (better_capacity < new_capacity); - - items = allocator->reallocate_nonzero(items, capacity, better_capacity); - capacity = better_capacity; - } - - T swap_remove(size_t index) { - if (length - 1 == index) return pop(); - - assert(index != SIZE_MAX); - assert(index < length); - - T old_item = items[index]; - items[index] = pop(); - return old_item; - } - - T *items{nullptr}; - size_t length{0}; - size_t capacity{0}; -}; - -} // namespace mem - -#endif diff --git a/src/stage1/mem_type_info.hpp b/src/stage1/mem_type_info.hpp deleted file mode 100644 index ae4b3414ae81..000000000000 --- a/src/stage1/mem_type_info.hpp +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright (c) 2020 Andrew Kelley - * - * This file is part of zig, which is MIT licensed. - * See http://opensource.org/licenses/MIT - */ - -#ifndef ZIG_MEM_TYPE_INFO_HPP -#define ZIG_MEM_TYPE_INFO_HPP - -namespace mem { - -struct TypeInfo { - size_t size; - size_t alignment; - - template - static constexpr TypeInfo make() { - return {sizeof(T), alignof(T)}; - } -}; - -} // namespace mem - -#endif diff --git a/src/stage1/os.cpp b/src/stage1/os.cpp deleted file mode 100644 index 776d2a291510..000000000000 --- a/src/stage1/os.cpp +++ /dev/null @@ -1,1282 +0,0 @@ -/* - * Copyright (c) 2015 Andrew Kelley - * - * This file is part of zig, which is MIT licensed. - * See http://opensource.org/licenses/MIT - */ - -#include "os.hpp" -#include "buffer.hpp" -#include "heap.hpp" -#include "util.hpp" -#include "error.hpp" -#include "util_base.hpp" -#include -#include - -#if defined(_WIN32) - -#if !defined(NOMINMAX) -#define NOMINMAX -#endif - -#if !defined(VC_EXTRALEAN) -#define VC_EXTRALEAN -#endif - -#if !defined(WIN32_LEAN_AND_MEAN) -#define WIN32_LEAN_AND_MEAN -#endif - -#if !defined(_WIN32_WINNT) -#define _WIN32_WINNT 0x600 -#endif - -#if !defined(NTDDI_VERSION) -#define NTDDI_VERSION 0x06000000 -#endif - -#include -#include -#include -#include -#include -#include - -// Workaround an upstream LLVM issue. -// See https://github.com/ziglang/zig/issues/7614#issuecomment-752939981 -#if defined(_MSC_VER) && defined(_WIN64) -typedef SSIZE_T ssize_t; -#endif -#else -#define ZIG_OS_POSIX - -#include -#include -#include -#include -#include -#include -#include -#include - -#endif - -#if defined(ZIG_OS_LINUX) || defined(ZIG_OS_FREEBSD) || defined(ZIG_OS_NETBSD) || defined(ZIG_OS_DRAGONFLY) || defined(ZIG_OS_OPENBSD) || defined(ZIG_OS_HAIKU) -#include -#endif - -#if defined(ZIG_OS_LINUX) -#include -#endif - -#if defined(ZIG_OS_FREEBSD) || defined(ZIG_OS_NETBSD) || defined(ZIG_OS_DRAGONFLY) || defined(ZIG_OS_OPENBSD) -#include -#endif - -#if defined(__MACH__) -#include -#include -#include -#endif - -#if defined(ZIG_OS_WINDOWS) -static void utf16le_ptr_to_utf8(Buf *out, WCHAR *utf16le); -static size_t utf8_to_utf16le(WCHAR *utf16_le, Slice utf8); -static uint64_t windows_perf_freq; -#elif defined(__MACH__) -static clock_serv_t macos_calendar_clock; -static clock_serv_t macos_monotonic_clock; -#endif - -#include -#include -#include - -#if !defined(environ) -extern char **environ; -#endif - -void os_path_dirname(Buf *full_path, Buf *out_dirname) { - return os_path_split(full_path, out_dirname, nullptr); -} - -bool os_is_sep(uint8_t c) { -#if defined(ZIG_OS_WINDOWS) - return c == '\\' || c == '/'; -#else - return c == '/'; -#endif -} - -void os_path_split(Buf *full_path, Buf *out_dirname, Buf *out_basename) { - size_t len = buf_len(full_path); - if (len != 0) { - size_t last_index = len - 1; - char last_char = buf_ptr(full_path)[last_index]; - if (os_is_sep(last_char)) { - if (last_index == 0) { - if (out_dirname) buf_init_from_mem(out_dirname, &last_char, 1); - if (out_basename) buf_init_from_str(out_basename, ""); - return; - } - last_index -= 1; - } - for (size_t i = last_index;;) { - uint8_t c = buf_ptr(full_path)[i]; - if (os_is_sep(c)) { - if (out_dirname) { - buf_init_from_mem(out_dirname, buf_ptr(full_path), (i == 0) ? 1 : i); - } - if (out_basename) { - buf_init_from_mem(out_basename, buf_ptr(full_path) + i + 1, buf_len(full_path) - (i + 1)); - } - return; - } - if (i == 0) break; - i -= 1; - } - } - if (out_dirname) buf_init_from_mem(out_dirname, ".", 1); - if (out_basename) buf_init_from_buf(out_basename, full_path); -} - -void os_path_extname(Buf *full_path, Buf *out_basename, Buf *out_extname) { - if (buf_len(full_path) == 0) { - if (out_basename) buf_init_from_str(out_basename, ""); - if (out_extname) buf_init_from_str(out_extname, ""); - return; - } - size_t i = buf_len(full_path) - 1; - while (true) { - if (buf_ptr(full_path)[i] == '.') { - if (out_basename) { - buf_resize(out_basename, 0); - buf_append_mem(out_basename, buf_ptr(full_path), i); - } - - if (out_extname) { - buf_resize(out_extname, 0); - buf_append_mem(out_extname, buf_ptr(full_path) + i, buf_len(full_path) - i); - } - return; - } - - if (i == 0) { - if (out_basename) buf_init_from_buf(out_basename, full_path); - if (out_extname) buf_init_from_str(out_extname, ""); - return; - } - i -= 1; - } -} - -void os_path_join(Buf *dirname, Buf *basename, Buf *out_full_path) { - if (buf_len(dirname) == 0) { - buf_init_from_buf(out_full_path, basename); - return; - } - - buf_init_from_buf(out_full_path, dirname); - uint8_t c = *(buf_ptr(out_full_path) + buf_len(out_full_path) - 1); - if (!os_is_sep(c)) - buf_append_char(out_full_path, ZIG_OS_SEP_CHAR); - buf_append_buf(out_full_path, basename); -} - - -#if defined(ZIG_OS_WINDOWS) -// Ported from std/os/path.zig -static bool isAbsoluteWindows(Slice path) { - if (path.ptr[0] == '/') - return true; - - if (path.ptr[0] == '\\') { - return true; - } - if (path.len < 3) { - return false; - } - if (path.ptr[1] == ':') { - if (path.ptr[2] == '/') - return true; - if (path.ptr[2] == '\\') - return true; - } - return false; -} - -enum WindowsPathKind { - WindowsPathKindNone, - WindowsPathKindDrive, - WindowsPathKindNetworkShare, -}; - -struct WindowsPath { - Slice disk_designator; - WindowsPathKind kind; - bool is_abs; -}; - - -// Ported from std/os/path.zig -static WindowsPath windowsParsePath(Slice path) { - if (path.len >= 2 && path.ptr[1] == ':') { - return WindowsPath{ - path.slice(0, 2), - WindowsPathKindDrive, - isAbsoluteWindows(path), - }; - } - if (path.len >= 1 && (path.ptr[0] == '/' || path.ptr[0] == '\\') && - (path.len == 1 || (path.ptr[1] != '/' && path.ptr[1] != '\\'))) - { - return WindowsPath{ - path.slice(0, 0), - WindowsPathKindNone, - true, - }; - } - WindowsPath relative_path = { - str(""), - WindowsPathKindNone, - false, - }; - if (path.len < strlen("//a/b")) { - return relative_path; - } - - { - if (memStartsWith(path, str("//"))) { - if (path.ptr[2] == '/') { - return relative_path; - } - - SplitIterator it = memSplit(path, str("/")); - { - Optional> opt_component = SplitIterator_next(&it); - if (!opt_component.is_some) return relative_path; - } - { - Optional> opt_component = SplitIterator_next(&it); - if (!opt_component.is_some) return relative_path; - } - return WindowsPath{ - path.slice(0, it.index), - WindowsPathKindNetworkShare, - isAbsoluteWindows(path), - }; - } - } - { - if (memStartsWith(path, str("\\\\"))) { - if (path.ptr[2] == '\\') { - return relative_path; - } - - SplitIterator it = memSplit(path, str("\\")); - { - Optional> opt_component = SplitIterator_next(&it); - if (!opt_component.is_some) return relative_path; - } - { - Optional> opt_component = SplitIterator_next(&it); - if (!opt_component.is_some) return relative_path; - } - return WindowsPath{ - path.slice(0, it.index), - WindowsPathKindNetworkShare, - isAbsoluteWindows(path), - }; - } - } - return relative_path; -} - -// Ported from std/os/path.zig -static uint8_t asciiUpper(uint8_t byte) { - if (byte >= 'a' && byte <= 'z') { - return 'A' + (byte - 'a'); - } - return byte; -} - -// Ported from std/os/path.zig -static bool asciiEqlIgnoreCase(Slice s1, Slice s2) { - if (s1.len != s2.len) - return false; - for (size_t i = 0; i < s1.len; i += 1) { - if (asciiUpper(s1.ptr[i]) != asciiUpper(s2.ptr[i])) - return false; - } - return true; -} - -// Ported from std/os/path.zig -static bool compareDiskDesignators(WindowsPathKind kind, Slice p1, Slice p2) { - switch (kind) { - case WindowsPathKindNone: - assert(p1.len == 0); - assert(p2.len == 0); - return true; - case WindowsPathKindDrive: - return asciiUpper(p1.ptr[0]) == asciiUpper(p2.ptr[0]); - case WindowsPathKindNetworkShare: - uint8_t sep1 = p1.ptr[0]; - uint8_t sep2 = p2.ptr[0]; - - SplitIterator it1 = memSplit(p1, {&sep1, 1}); - SplitIterator it2 = memSplit(p2, {&sep2, 1}); - - // TODO ASCII is wrong, we actually need full unicode support to compare paths. - return asciiEqlIgnoreCase(SplitIterator_next(&it1).value, SplitIterator_next(&it2).value) && - asciiEqlIgnoreCase(SplitIterator_next(&it1).value, SplitIterator_next(&it2).value); - } - zig_unreachable(); -} - -// Ported from std/os/path.zig -static Buf os_path_resolve_windows(Buf **paths_ptr, size_t paths_len) { - if (paths_len == 0) { - Buf cwd = BUF_INIT; - int err; - if ((err = os_get_cwd(&cwd))) { - zig_panic("get cwd failed"); - } - return cwd; - } - - // determine which disk designator we will result with, if any - char result_drive_buf[3] = {'_', ':', '\0'}; // 0 needed for strlen later - Slice result_disk_designator = str(""); - WindowsPathKind have_drive_kind = WindowsPathKindNone; - bool have_abs_path = false; - size_t first_index = 0; - size_t max_size = 0; - for (size_t i = 0; i < paths_len; i += 1) { - Slice p = buf_to_slice(paths_ptr[i]); - WindowsPath parsed = windowsParsePath(p); - if (parsed.is_abs) { - have_abs_path = true; - first_index = i; - max_size = result_disk_designator.len; - } - switch (parsed.kind) { - case WindowsPathKindDrive: - result_drive_buf[0] = asciiUpper(parsed.disk_designator.ptr[0]); - result_disk_designator = str(result_drive_buf); - have_drive_kind = WindowsPathKindDrive; - break; - case WindowsPathKindNetworkShare: - result_disk_designator = parsed.disk_designator; - have_drive_kind = WindowsPathKindNetworkShare; - break; - case WindowsPathKindNone: - break; - } - max_size += p.len + 1; - } - - // if we will result with a disk designator, loop again to determine - // which is the last time the disk designator is absolutely specified, if any - // and count up the max bytes for paths related to this disk designator - if (have_drive_kind != WindowsPathKindNone) { - have_abs_path = false; - first_index = 0; - max_size = result_disk_designator.len; - bool correct_disk_designator = false; - - for (size_t i = 0; i < paths_len; i += 1) { - Slice p = buf_to_slice(paths_ptr[i]); - WindowsPath parsed = windowsParsePath(p); - if (parsed.kind != WindowsPathKindNone) { - if (parsed.kind == have_drive_kind) { - correct_disk_designator = compareDiskDesignators(have_drive_kind, result_disk_designator, parsed.disk_designator); - } else { - continue; - } - } - if (!correct_disk_designator) { - continue; - } - if (parsed.is_abs) { - first_index = i; - max_size = result_disk_designator.len; - have_abs_path = true; - } - max_size += p.len + 1; - } - } - - // Allocate result and fill in the disk designator, calling getCwd if we have to. - Slice result; - size_t result_index = 0; - - if (have_abs_path) { - switch (have_drive_kind) { - case WindowsPathKindDrive: { - result = Slice::alloc(max_size); - - memCopy(result, result_disk_designator); - result_index += result_disk_designator.len; - break; - } - case WindowsPathKindNetworkShare: { - result = Slice::alloc(max_size); - SplitIterator it = memSplit(buf_to_slice(paths_ptr[first_index]), str("/\\")); - Slice server_name = SplitIterator_next(&it).value; - Slice other_name = SplitIterator_next(&it).value; - - result.ptr[result_index] = '\\'; - result_index += 1; - result.ptr[result_index] = '\\'; - result_index += 1; - memCopy(result.sliceFrom(result_index), server_name); - result_index += server_name.len; - result.ptr[result_index] = '\\'; - result_index += 1; - memCopy(result.sliceFrom(result_index), other_name); - result_index += other_name.len; - - result_disk_designator = result.slice(0, result_index); - break; - } - case WindowsPathKindNone: { - Buf cwd = BUF_INIT; - int err; - if ((err = os_get_cwd(&cwd))) { - zig_panic("get cwd failed"); - } - WindowsPath parsed_cwd = windowsParsePath(buf_to_slice(&cwd)); - result = Slice::alloc(max_size + parsed_cwd.disk_designator.len + 1); - memCopy(result, parsed_cwd.disk_designator); - result_index += parsed_cwd.disk_designator.len; - result_disk_designator = result.slice(0, parsed_cwd.disk_designator.len); - if (parsed_cwd.kind == WindowsPathKindDrive) { - result.ptr[0] = asciiUpper(result.ptr[0]); - } - have_drive_kind = parsed_cwd.kind; - break; - } - } - } else { - // TODO call get cwd for the result_disk_designator instead of the global one - Buf cwd = BUF_INIT; - int err; - if ((err = os_get_cwd(&cwd))) { - zig_panic("get cwd failed"); - } - result = Slice::alloc(max_size + buf_len(&cwd) + 1); - - memCopy(result, buf_to_slice(&cwd)); - result_index += buf_len(&cwd); - WindowsPath parsed_cwd = windowsParsePath(result.slice(0, result_index)); - result_disk_designator = parsed_cwd.disk_designator; - if (parsed_cwd.kind == WindowsPathKindDrive) { - result.ptr[0] = asciiUpper(result.ptr[0]); - // Remove the trailing slash if present, eg. if the cwd is a root - // directory. - if (buf_ends_with_mem(&cwd, "\\", 1)) { - result_index -= 1; - } - } - have_drive_kind = parsed_cwd.kind; - } - - // Now we know the disk designator to use, if any, and what kind it is. And our result - // is big enough to append all the paths to. - bool correct_disk_designator = true; - for (size_t i = first_index; i < paths_len; i += 1) { - Slice p = buf_to_slice(paths_ptr[i]); - WindowsPath parsed = windowsParsePath(p); - - if (parsed.kind != WindowsPathKindNone) { - if (parsed.kind == have_drive_kind) { - correct_disk_designator = compareDiskDesignators(have_drive_kind, result_disk_designator, parsed.disk_designator); - } else { - continue; - } - } - if (!correct_disk_designator) { - continue; - } - SplitIterator it = memSplit(p.sliceFrom(parsed.disk_designator.len), str("/\\")); - while (true) { - Optional> opt_component = SplitIterator_next(&it); - if (!opt_component.is_some) break; - Slice component = opt_component.value; - if (memEql(component, str("."))) { - continue; - } else if (memEql(component, str(".."))) { - while (true) { - if (result_index == 0 || result_index == result_disk_designator.len) - break; - result_index -= 1; - if (result.ptr[result_index] == '\\' || result.ptr[result_index] == '/') - break; - } - } else { - result.ptr[result_index] = '\\'; - result_index += 1; - memCopy(result.sliceFrom(result_index), component); - result_index += component.len; - } - } - } - - if (result_index == result_disk_designator.len) { - result.ptr[result_index] = '\\'; - result_index += 1; - } - - Buf return_value = BUF_INIT; - buf_init_from_mem(&return_value, (char *)result.ptr, result_index); - return return_value; -} -#endif - -#if defined(ZIG_OS_POSIX) -// Ported from std/os/path.zig -static Buf os_path_resolve_posix(Buf **paths_ptr, size_t paths_len) { - if (paths_len == 0) { - Buf cwd = BUF_INIT; - int err; - if ((err = os_get_cwd(&cwd))) { - zig_panic("get cwd failed"); - } - return cwd; - } - - size_t first_index = 0; - bool have_abs = false; - size_t max_size = 0; - for (size_t i = 0; i < paths_len; i += 1) { - Buf *p = paths_ptr[i]; - if (buf_ptr(p)[0] == '/') { - first_index = i; - have_abs = true; - max_size = 0; - } - max_size += buf_len(p) + 1; - } - - uint8_t *result_ptr; - size_t result_len; - size_t result_index = 0; - - if (have_abs) { - result_len = max_size; - result_ptr = heap::c_allocator.allocate_nonzero(result_len); - } else { - Buf cwd = BUF_INIT; - int err; - if ((err = os_get_cwd(&cwd))) { - zig_panic("get cwd failed"); - } - result_len = max_size + buf_len(&cwd) + 1; - result_ptr = heap::c_allocator.allocate_nonzero(result_len); - memcpy(result_ptr, buf_ptr(&cwd), buf_len(&cwd)); - result_index += buf_len(&cwd); - } - - for (size_t i = first_index; i < paths_len; i += 1) { - Buf *p = paths_ptr[i]; - SplitIterator it = memSplit(buf_to_slice(p), str("/")); - while (true) { - Optional> opt_component = SplitIterator_next(&it); - if (!opt_component.is_some) break; - Slice component = opt_component.value; - - if (memEql(component, str("."))) { - continue; - } else if (memEql(component, str(".."))) { - while (true) { - if (result_index == 0) - break; - result_index -= 1; - if (result_ptr[result_index] == '/') - break; - } - } else { - result_ptr[result_index] = '/'; - result_index += 1; - memcpy(result_ptr + result_index, component.ptr, component.len); - result_index += component.len; - } - } - } - - if (result_index == 0) { - result_ptr[0] = '/'; - result_index += 1; - } - - Buf return_value = BUF_INIT; - buf_init_from_mem(&return_value, (char *)result_ptr, result_index); - heap::c_allocator.deallocate(result_ptr, result_len); - return return_value; -} -#endif - -// Ported from std/os/path.zig -Buf os_path_resolve(Buf **paths_ptr, size_t paths_len) { -#if defined(ZIG_OS_WINDOWS) - return os_path_resolve_windows(paths_ptr, paths_len); -#elif defined(ZIG_OS_POSIX) - return os_path_resolve_posix(paths_ptr, paths_len); -#else -#error "missing os_path_resolve implementation" -#endif -} - -Error os_fetch_file(FILE *f, Buf *out_buf) { - static const ssize_t buf_size = 0x2000; - buf_resize(out_buf, buf_size); - ssize_t actual_buf_len = 0; - - for (;;) { - size_t amt_read = fread(buf_ptr(out_buf) + actual_buf_len, 1, buf_size, f); - actual_buf_len += amt_read; - - if (amt_read != buf_size) { - if (feof(f)) { - buf_resize(out_buf, actual_buf_len); - return ErrorNone; - } else { - return ErrorFileSystem; - } - } - - buf_resize(out_buf, actual_buf_len + buf_size); - } - zig_unreachable(); -} - -Error os_write_file(Buf *full_path, Buf *contents) { -#if defined(ZIG_OS_WINDOWS) - PathSpace path_space = slice_to_prefixed_file_w(buf_to_slice(full_path)); - FILE *f = _wfopen(&path_space.data.items[0], L"wb"); -#else - FILE *f = fopen(buf_ptr(full_path), "wb"); -#endif - if (!f) { - zig_panic("os_write_file failed for %s", buf_ptr(full_path)); - } - size_t amt_written = fwrite(buf_ptr(contents), 1, buf_len(contents), f); - if (amt_written != (size_t)buf_len(contents)) - zig_panic("write failed: %s", strerror(errno)); - if (fclose(f)) - zig_panic("close failed"); - return ErrorNone; -} - -static Error copy_open_files(FILE *src_f, FILE *dest_f) { - static const size_t buf_size = 2048; - char buf[buf_size]; - for (;;) { - size_t amt_read = fread(buf, 1, buf_size, src_f); - if (amt_read != buf_size) { - if (ferror(src_f)) { - return ErrorFileSystem; - } - } - size_t amt_written = fwrite(buf, 1, amt_read, dest_f); - if (amt_written != amt_read) { - return ErrorFileSystem; - } - if (feof(src_f)) { - return ErrorNone; - } - } -} - -Error os_copy_file(Buf *src_path, Buf *dest_path) { -#if defined(ZIG_OS_WINDOWS) - PathSpace src_path_space = slice_to_prefixed_file_w(buf_to_slice(src_path)); - FILE *src_f = _wfopen(&src_path_space.data.items[0], L"rb"); -#else - FILE *src_f = fopen(buf_ptr(src_path), "rb"); -#endif - if (!src_f) { - int err = errno; - if (err == ENOENT) { - return ErrorFileNotFound; - } else if (err == EACCES || err == EPERM) { - return ErrorAccess; - } else { - return ErrorFileSystem; - } - } -#if defined(ZIG_OS_WINDOWS) - PathSpace dest_path_space = slice_to_prefixed_file_w(buf_to_slice(dest_path)); - FILE *dest_f = _wfopen(&dest_path_space.data.items[0], L"wb"); -#else - FILE *dest_f = fopen(buf_ptr(dest_path), "wb"); -#endif - if (!dest_f) { - int err = errno; - if (err == ENOENT) { - fclose(src_f); - return ErrorFileNotFound; - } else if (err == EACCES || err == EPERM) { - fclose(src_f); - return ErrorAccess; - } else { - fclose(src_f); - return ErrorFileSystem; - } - } - Error err = copy_open_files(src_f, dest_f); - fclose(src_f); - fclose(dest_f); - return err; -} - -Error os_fetch_file_path(Buf *full_path, Buf *out_contents) { -#if defined(ZIG_OS_WINDOWS) - PathSpace path_space = slice_to_prefixed_file_w(buf_to_slice(full_path)); - FILE *f = _wfopen(&path_space.data.items[0], L"rb"); -#else - FILE *f = fopen(buf_ptr(full_path), "rb"); -#endif - if (!f) { - switch (errno) { - case EACCES: - return ErrorAccess; - case EINTR: - return ErrorInterrupted; - case EINVAL: - return ErrorInvalidFilename; - case ENFILE: - case ENOMEM: - return ErrorSystemResources; - case ENOENT: - return ErrorFileNotFound; - default: - return ErrorFileSystem; - } - } - Error result = os_fetch_file(f, out_contents); - fclose(f); - return result; -} - -Error os_get_cwd(Buf *out_cwd) { -#if defined(ZIG_OS_WINDOWS) - PathSpace path_space; - if (GetCurrentDirectoryW(PATH_MAX_WIDE, &path_space.data.items[0]) == 0) { - zig_panic("GetCurrentDirectory failed"); - } - utf16le_ptr_to_utf8(out_cwd, &path_space.data.items[0]); - return ErrorNone; -#elif defined(ZIG_OS_POSIX) - char buf[PATH_MAX]; - char *res = getcwd(buf, PATH_MAX); - if (res == nullptr) { - zig_panic("unable to get cwd: %s", strerror(errno)); - } - buf_init_from_str(out_cwd, res); - return ErrorNone; -#else -#error "missing os_get_cwd implementation" -#endif -} - -#if defined(ZIG_OS_WINDOWS) -#define is_wprefix(s, prefix) \ - (wcsncmp((s), (prefix), sizeof(prefix) / sizeof(WCHAR) - 1) == 0) -static bool is_stderr_cyg_pty(void) { - HANDLE stderr_handle = GetStdHandle(STD_ERROR_HANDLE); - if (stderr_handle == INVALID_HANDLE_VALUE) - return false; - - const int size = sizeof(FILE_NAME_INFO) + sizeof(WCHAR) * MAX_PATH; - FILE_NAME_INFO *nameinfo; - WCHAR *p = NULL; - - // Cygwin/msys's pty is a pipe. - if (GetFileType(stderr_handle) != FILE_TYPE_PIPE) { - return 0; - } - nameinfo = reinterpret_cast(heap::c_allocator.allocate(size)); - if (nameinfo == NULL) { - return 0; - } - // Check the name of the pipe: - // '\{cygwin,msys}-XXXXXXXXXXXXXXXX-ptyN-{from,to}-master' - if (GetFileInformationByHandleEx(stderr_handle, FileNameInfo, nameinfo, size)) { - nameinfo->FileName[nameinfo->FileNameLength / sizeof(WCHAR)] = L'\0'; - p = nameinfo->FileName; - if (is_wprefix(p, L"\\cygwin-")) { /* Cygwin */ - p += 8; - } else if (is_wprefix(p, L"\\msys-")) { /* MSYS and MSYS2 */ - p += 6; - } else { - p = NULL; - } - if (p != NULL) { - while (*p && isxdigit(*p)) /* Skip 16-digit hexadecimal. */ - ++p; - if (is_wprefix(p, L"-pty")) { - p += 4; - } else { - p = NULL; - } - } - if (p != NULL) { - while (*p && isdigit(*p)) /* Skip pty number. */ - ++p; - if (is_wprefix(p, L"-from-master")) { - //p += 12; - } else if (is_wprefix(p, L"-to-master")) { - //p += 10; - } else { - p = NULL; - } - } - } - heap::c_allocator.deallocate(reinterpret_cast(nameinfo), size); - return (p != NULL); -} -#endif - -bool os_stderr_supports_color(void) { - if (getenv("NO_COLOR") != NULL) return false; -#if defined(ZIG_OS_WINDOWS) - return _isatty(_fileno(stderr)) != 0 || is_stderr_cyg_pty(); -#elif defined(ZIG_OS_POSIX) - return isatty(STDERR_FILENO) != 0; -#else -#error "missing os_stderr_supports_color implementation" -#endif -} - -Error os_rename(Buf *src_path, Buf *dest_path) { - if (buf_eql_buf(src_path, dest_path)) { - return ErrorNone; - } -#if defined(ZIG_OS_WINDOWS) - PathSpace src_path_space = slice_to_prefixed_file_w(buf_to_slice(src_path)); - PathSpace dest_path_space = slice_to_prefixed_file_w(buf_to_slice(dest_path)); - if (!MoveFileExW(&src_path_space.data.items[0], &dest_path_space.data.items[0], MOVEFILE_REPLACE_EXISTING | MOVEFILE_WRITE_THROUGH)) { - return ErrorFileSystem; - } -#else - if (rename(buf_ptr(src_path), buf_ptr(dest_path)) == -1) { - return ErrorFileSystem; - } -#endif - return ErrorNone; -} - -OsTimeStamp os_timestamp_monotonic(void) { - OsTimeStamp result; -#if defined(ZIG_OS_WINDOWS) - uint64_t counts; - QueryPerformanceCounter((LARGE_INTEGER*)&counts); - result.sec = counts / windows_perf_freq; - result.nsec = (counts % windows_perf_freq) * 1000000000u / windows_perf_freq; -#elif defined(__MACH__) - mach_timespec_t mts; - - kern_return_t err = clock_get_time(macos_monotonic_clock, &mts); - assert(!err); - - result.sec = mts.tv_sec; - result.nsec = mts.tv_nsec; -#else - struct timespec tms; - clock_gettime(CLOCK_MONOTONIC, &tms); - - result.sec = tms.tv_sec; - result.nsec = tms.tv_nsec; -#endif - return result; -} - -Error os_make_path(Buf *path) { - Buf resolved_path = os_path_resolve(&path, 1); - - size_t end_index = buf_len(&resolved_path); - Error err; - while (true) { - if ((err = os_make_dir(buf_slice(&resolved_path, 0, end_index)))) { - if (err == ErrorPathAlreadyExists) { - if (end_index == buf_len(&resolved_path)) - return ErrorNone; - } else if (err == ErrorFileNotFound) { - // march end_index backward until next path component - while (true) { - end_index -= 1; - if (os_is_sep(buf_ptr(&resolved_path)[end_index])) - break; - } - continue; - } else { - return err; - } - } - if (end_index == buf_len(&resolved_path)) - return ErrorNone; - // march end_index forward until next path component - while (true) { - end_index += 1; - if (end_index == buf_len(&resolved_path) || os_is_sep(buf_ptr(&resolved_path)[end_index])) - break; - } - } - return ErrorNone; -} - -Error os_make_dir(Buf *path) { -#if defined(ZIG_OS_WINDOWS) - PathSpace path_space = slice_to_prefixed_file_w(buf_to_slice(path)); - - if (!CreateDirectoryW(&path_space.data.items[0], NULL)) { - if (GetLastError() == ERROR_ALREADY_EXISTS) - return ErrorPathAlreadyExists; - if (GetLastError() == ERROR_PATH_NOT_FOUND) - return ErrorFileNotFound; - if (GetLastError() == ERROR_ACCESS_DENIED) - return ErrorAccess; - return ErrorUnexpected; - } - return ErrorNone; -#else - if (mkdir(buf_ptr(path), 0755) == -1) { - if (errno == EEXIST) - return ErrorPathAlreadyExists; - if (errno == ENOENT) - return ErrorFileNotFound; - if (errno == EACCES) - return ErrorAccess; - return ErrorUnexpected; - } - return ErrorNone; -#endif -} - - -int os_init(void) { -#if defined(ZIG_OS_WINDOWS) - _setmode(fileno(stdout), _O_BINARY); - _setmode(fileno(stderr), _O_BINARY); - if (!QueryPerformanceFrequency((LARGE_INTEGER*)&windows_perf_freq)) { - return ErrorSystemResources; - } -#elif defined(__MACH__) - host_get_clock_service(mach_host_self(), SYSTEM_CLOCK, &macos_monotonic_clock); - host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, &macos_calendar_clock); -#endif - return 0; -} - -#define VT_RED "\x1b[31;1m" -#define VT_GREEN "\x1b[32;1m" -#define VT_CYAN "\x1b[36;1m" -#define VT_WHITE "\x1b[37;1m" -#define VT_BOLD "\x1b[0;1m" -#define VT_RESET "\x1b[0m" - -static void set_color_posix(TermColor color) { - switch (color) { - case TermColorRed: - fprintf(stderr, VT_RED); - break; - case TermColorGreen: - fprintf(stderr, VT_GREEN); - break; - case TermColorCyan: - fprintf(stderr, VT_CYAN); - break; - case TermColorWhite: - fprintf(stderr, VT_WHITE); - break; - case TermColorBold: - fprintf(stderr, VT_BOLD); - break; - case TermColorReset: - fprintf(stderr, VT_RESET); - break; - } -} - - -#if defined(ZIG_OS_WINDOWS) -bool got_orig_console_attrs = false; -WORD original_console_attributes = FOREGROUND_RED|FOREGROUND_GREEN|FOREGROUND_BLUE; -#endif - -void os_stderr_set_color(TermColor color) { -#if defined(ZIG_OS_WINDOWS) - if (is_stderr_cyg_pty()) { - set_color_posix(color); - return; - } - HANDLE stderr_handle = GetStdHandle(STD_ERROR_HANDLE); - if (stderr_handle == INVALID_HANDLE_VALUE) - zig_panic("unable to get stderr handle"); - fflush(stderr); - - if (!got_orig_console_attrs) { - got_orig_console_attrs = true; - CONSOLE_SCREEN_BUFFER_INFO info; - if (GetConsoleScreenBufferInfo(stderr_handle, &info)) { - original_console_attributes = info.wAttributes; - } - } - - switch (color) { - case TermColorRed: - SetConsoleTextAttribute(stderr_handle, FOREGROUND_RED|FOREGROUND_INTENSITY); - break; - case TermColorGreen: - SetConsoleTextAttribute(stderr_handle, FOREGROUND_GREEN|FOREGROUND_INTENSITY); - break; - case TermColorCyan: - SetConsoleTextAttribute(stderr_handle, FOREGROUND_GREEN|FOREGROUND_BLUE|FOREGROUND_INTENSITY); - break; - case TermColorWhite: - case TermColorBold: - SetConsoleTextAttribute(stderr_handle, - FOREGROUND_RED|FOREGROUND_GREEN|FOREGROUND_BLUE|FOREGROUND_INTENSITY); - break; - case TermColorReset: - SetConsoleTextAttribute(stderr_handle, original_console_attributes); - break; - } -#else - set_color_posix(color); -#endif -} - -#if defined(ZIG_OS_WINDOWS) -// Ported from std/unicode.zig -struct Utf16LeIterator { - uint8_t *bytes; - size_t i; -}; - -// Ported from std/unicode.zig -static Utf16LeIterator Utf16LeIterator_init(WCHAR *ptr) { - return {(uint8_t*)ptr, 0}; -} - -// Ported from std/unicode.zig -static Optional Utf16LeIterator_nextCodepoint(Utf16LeIterator *it) { - if (it->bytes[it->i] == 0 && it->bytes[it->i + 1] == 0) - return {}; - uint32_t c0 = ((uint32_t)it->bytes[it->i]) | (((uint32_t)it->bytes[it->i + 1]) << 8); - if ((c0 & ~((uint32_t)0x03ff)) == 0xd800) { - // surrogate pair - it->i += 2; - assert(it->bytes[it->i] != 0 || it->bytes[it->i + 1] != 0); - uint32_t c1 = ((uint32_t)it->bytes[it->i]) | (((uint32_t)it->bytes[it->i + 1]) << 8); - assert((c1 & ~((uint32_t)0x03ff)) == 0xdc00); - it->i += 2; - return Optional::some(0x10000 + (((c0 & 0x03ff) << 10) | (c1 & 0x03ff))); - } else { - assert((c0 & ~((uint32_t)0x03ff)) != 0xdc00); - it->i += 2; - return Optional::some(c0); - } -} - -// Ported from std/unicode.zig -static uint8_t utf8CodepointSequenceLength(uint32_t c) { - if (c < 0x80) return 1; - if (c < 0x800) return 2; - if (c < 0x10000) return 3; - if (c < 0x110000) return 4; - zig_unreachable(); -} - -// Ported from std.unicode.utf8ByteSequenceLength -static uint8_t utf8ByteSequenceLength(uint8_t first_byte) { - if (first_byte < 0b10000000) return 1; - if ((first_byte & 0b11100000) == 0b11000000) return 2; - if ((first_byte & 0b11110000) == 0b11100000) return 3; - if ((first_byte & 0b11111000) == 0b11110000) return 4; - zig_unreachable(); -} - -// Ported from std/unicode.zig -static size_t utf8Encode(uint32_t c, Slice out) { - size_t length = utf8CodepointSequenceLength(c); - assert(out.len >= length); - switch (length) { - // The pattern for each is the same - // - Increasing the initial shift by 6 each time - // - Each time after the first shorten the shifted - // value to a max of 0b111111 (63) - case 1: - out.ptr[0] = c; // Can just do 0 + codepoint for initial range - break; - case 2: - out.ptr[0] = 0b11000000 | (c >> 6); - out.ptr[1] = 0b10000000 | (c & 0b111111); - break; - case 3: - assert(!(0xd800 <= c && c <= 0xdfff)); - out.ptr[0] = 0b11100000 | (c >> 12); - out.ptr[1] = 0b10000000 | ((c >> 6) & 0b111111); - out.ptr[2] = 0b10000000 | (c & 0b111111); - break; - case 4: - out.ptr[0] = 0b11110000 | (c >> 18); - out.ptr[1] = 0b10000000 | ((c >> 12) & 0b111111); - out.ptr[2] = 0b10000000 | ((c >> 6) & 0b111111); - out.ptr[3] = 0b10000000 | (c & 0b111111); - break; - default: - zig_unreachable(); - } - return length; -} - -// Ported from std.unicode.utf8Decode2 -static uint32_t utf8Decode2(Slice bytes) { - assert(bytes.len == 2); - assert((bytes.at(0) & 0b11100000) == 0b11000000); - - uint32_t value = bytes.at(0) & 0b00011111; - assert((bytes.at(1) & 0b11000000) == 0b10000000); - value <<= 6; - value |= bytes.at(1) & 0b00111111; - - assert(value >= 0x80); - return value; -} - -// Ported from std.unicode.utf8Decode3 -static uint32_t utf8Decode3(Slice bytes) { - assert(bytes.len == 3); - assert((bytes.at(0) & 0b11110000) == 0b11100000); - - uint32_t value = bytes.at(0) & 0b00001111; - assert((bytes.at(1) & 0b11000000) == 0b10000000); - value <<= 6; - value |= bytes.at(1) & 0b00111111; - - assert((bytes.at(2) & 0b11000000) == 0b10000000); - value <<= 6; - value |= bytes.at(2) & 0b00111111; - - assert(value >= 0x80); - assert(value < 0xd800 || value > 0xdfff); - return value; -} - -// Ported from std.unicode.utf8Decode4 -static uint32_t utf8Decode4(Slice bytes) { - assert(bytes.len == 4); - assert((bytes.at(0) & 0b11111000) == 0b11110000); - - uint32_t value = bytes.at(0) & 0b00000111; - assert((bytes.at(1) & 0b11000000) == 0b10000000); - value <<= 6; - value |= bytes.at(1) & 0b00111111; - - assert((bytes.at(2) & 0b11000000) == 0b10000000); - value <<= 6; - value |= bytes.at(2) & 0b00111111; - - assert((bytes.at(3) & 0b11000000) == 0b10000000); - value <<= 6; - value |= bytes.at(3) & 0b00111111; - - assert(value >= 0x10000 && value <= 0x10FFFF); - return value; -} - -// Ported from std.unicode.utf8Decode -static uint32_t utf8Decode(Slice bytes) { - switch (bytes.len) { - case 1: - return bytes.at(0); - break; - case 2: - return utf8Decode2(bytes); - break; - case 3: - return utf8Decode3(bytes); - break; - case 4: - return utf8Decode4(bytes); - break; - default: - zig_unreachable(); - } -} -// Ported from std.unicode.utf16leToUtf8Alloc -static void utf16le_ptr_to_utf8(Buf *out, WCHAR *utf16le) { - // optimistically guess that it will all be ascii. - buf_resize(out, 0); - size_t out_index = 0; - Utf16LeIterator it = Utf16LeIterator_init(utf16le); - for (;;) { - Optional opt_codepoint = Utf16LeIterator_nextCodepoint(&it); - if (!opt_codepoint.is_some) break; - uint32_t codepoint = opt_codepoint.value; - - size_t utf8_len = utf8CodepointSequenceLength(codepoint); - buf_resize(out, buf_len(out) + utf8_len); - utf8Encode(codepoint, {(uint8_t*)buf_ptr(out)+out_index, buf_len(out)-out_index}); - out_index += utf8_len; - } -} - -// Ported from std.unicode.utf8ToUtf16Le -static size_t utf8_to_utf16le(WCHAR *utf16_le, Slice utf8) { - size_t dest_i = 0; - size_t src_i = 0; - while (src_i < utf8.len) { - uint8_t n = utf8ByteSequenceLength(utf8.at(src_i)); - size_t next_src_i = src_i + n; - uint32_t codepoint = utf8Decode(utf8.slice(src_i, next_src_i)); - if (codepoint < 0x10000) { - utf16_le[dest_i] = codepoint; - dest_i += 1; - } else { - WCHAR high = ((codepoint - 0x10000) >> 10) + 0xD800; - WCHAR low = (codepoint & 0x3FF) + 0xDC00; - utf16_le[dest_i] = high; - utf16_le[dest_i + 1] = low; - dest_i += 2; - } - src_i = next_src_i; - } - return dest_i; -} - -// Ported from std.os.windows.sliceToPrefixedFileW -PathSpace slice_to_prefixed_file_w(Slice path) { - PathSpace path_space; - for (size_t idx = 0; idx < path.len; idx++) { - assert(path.ptr[idx] != '*' && path.ptr[idx] != '?' && path.ptr[idx] != '"' && - path.ptr[idx] != '<' && path.ptr[idx] != '>' && path.ptr[idx] != '|'); - } - - size_t start_index; - if (memStartsWith(path, str("\\?")) || !isAbsoluteWindows(path)) { - start_index = 0; - } else { - static WCHAR prefix[4] = { u'\\', u'?', u'?', u'\\' }; - memCopy(path_space.data.slice(), Slice { prefix, 4 }); - start_index = 4; - } - - path_space.len = start_index + utf8_to_utf16le(path_space.data.slice().sliceFrom(start_index).ptr, path); - assert(path_space.len <= path_space.data.len); - - Slice path_slice = path_space.data.slice().slice(0, path_space.len); - for (size_t elem_idx = 0; elem_idx < path_slice.len; elem_idx += 1) { - if (path_slice.at(elem_idx) == '/') { - path_slice.at(elem_idx) = '\\'; - } - } - - path_space.data.items[path_space.len] = 0; - return path_space; -} -#endif diff --git a/src/stage1/os.hpp b/src/stage1/os.hpp deleted file mode 100644 index 6d086c890167..000000000000 --- a/src/stage1/os.hpp +++ /dev/null @@ -1,120 +0,0 @@ -/* - * Copyright (c) 2015 Andrew Kelley - * - * This file is part of zig, which is MIT licensed. - * See http://opensource.org/licenses/MIT - */ - -#ifndef ZIG_OS_HPP -#define ZIG_OS_HPP - -#include "list.hpp" -#include "buffer.hpp" -#include "error.hpp" -#include "zig_llvm.h" -#include "windows_sdk.h" - -#include -#include - -#if defined(__APPLE__) -#define ZIG_OS_DARWIN -#elif defined(_WIN32) -#define ZIG_OS_WINDOWS -#elif defined(__linux__) -#define ZIG_OS_LINUX -#elif defined(__FreeBSD__) -#define ZIG_OS_FREEBSD -#elif defined(__NetBSD__) -#define ZIG_OS_NETBSD -#elif defined(__DragonFly__) -#define ZIG_OS_DRAGONFLY -#elif defined(__OpenBSD__) -#define ZIG_OS_OPENBSD -#elif defined(__HAIKU__) -#define ZIG_OS_HAIKU -#elif defined(__sun) -#define ZIG_OS_SOLARIS -#else -#define ZIG_OS_UNKNOWN -#endif - -#if defined(__x86_64__) -#define ZIG_ARCH_X86_64 -#elif defined(__aarch64__) -#define ZIG_ARCH_ARM64 -#elif defined(__ARM_EABI__) -#define ZIG_ARCH_ARM -#else -#define ZIG_ARCH_UNKNOWN -#endif - -#if defined(ZIG_OS_WINDOWS) -#define ZIG_PRI_usize "Iu" -#define ZIG_PRI_i64 "I64d" -#define ZIG_PRI_u64 "I64u" -#define ZIG_PRI_llu "I64u" -#define ZIG_PRI_x64 "I64x" -#define OS_SEP "\\" -#define ZIG_OS_SEP_CHAR '\\' -#else -#define ZIG_PRI_usize "zu" -#define ZIG_PRI_i64 PRId64 -#define ZIG_PRI_u64 PRIu64 -#define ZIG_PRI_llu "llu" -#define ZIG_PRI_x64 PRIx64 -#define OS_SEP "/" -#define ZIG_OS_SEP_CHAR '/' -#endif - -enum TermColor { - TermColorRed, - TermColorGreen, - TermColorCyan, - TermColorWhite, - TermColorBold, - TermColorReset, -}; - -struct OsTimeStamp { - int64_t sec; - int64_t nsec; -}; - -int os_init(void); - -void os_path_dirname(Buf *full_path, Buf *out_dirname); -void os_path_split(Buf *full_path, Buf *out_dirname, Buf *out_basename); -void os_path_extname(Buf *full_path, Buf *out_basename, Buf *out_extname); -void os_path_join(Buf *dirname, Buf *basename, Buf *out_full_path); -Buf os_path_resolve(Buf **paths_ptr, size_t paths_len); -bool os_path_is_absolute(Buf *path); - -Error ATTRIBUTE_MUST_USE os_make_path(Buf *path); -Error ATTRIBUTE_MUST_USE os_make_dir(Buf *path); - -Error ATTRIBUTE_MUST_USE os_write_file(Buf *full_path, Buf *contents); -Error ATTRIBUTE_MUST_USE os_copy_file(Buf *src_path, Buf *dest_path); - -Error ATTRIBUTE_MUST_USE os_fetch_file(FILE *file, Buf *out_contents); -Error ATTRIBUTE_MUST_USE os_fetch_file_path(Buf *full_path, Buf *out_contents); - -Error ATTRIBUTE_MUST_USE os_get_cwd(Buf *out_cwd); - -bool os_stderr_supports_color(void); -void os_stderr_set_color(TermColor color); - -Error os_rename(Buf *src_path, Buf *dest_path); -OsTimeStamp os_timestamp_monotonic(void); - -bool os_is_sep(uint8_t c); - -const size_t PATH_MAX_WIDE = 32767; - -struct PathSpace { - Array data; - size_t len; -}; - -PathSpace slice_to_prefixed_file_w(Slice path); -#endif diff --git a/src/stage1/parse_f128.c b/src/stage1/parse_f128.c deleted file mode 100644 index 493375e4d1db..000000000000 --- a/src/stage1/parse_f128.c +++ /dev/null @@ -1,1085 +0,0 @@ -// Code ported from musl libc 8f12c4e110acb3bbbdc8abfb3a552c3ced718039 -// and then modified to use softfloat and to assume f128 for everything - -#include "parse_f128.h" -#include "softfloat.h" -#include "zigendian.h" -#include -#include -#include -#include -#include -#include - -#define shcnt(f) ((f)->shcnt + ((f)->rpos - (f)->buf)) -#define shlim(f, lim) __shlim((f), (lim)) -#define shgetc(f) (((f)->rpos != (f)->shend) ? *(f)->rpos++ : __shgetc(f)) -#define shunget(f) ((f)->shlim>=0 ? (void)(f)->rpos-- : (void)0) - -#define sh_fromstring(f, s) \ - ((f)->buf = (f)->rpos = (void *)(s), (f)->rend = (void*)-1) - -#define LD_B1B_DIG 4 -#define LD_B1B_MAX 10384593, 717069655, 257060992, 658440191 -#define KMAX 2048 - -#define MASK (KMAX-1) - -#define CONCAT2(x,y) x ## y -#define CONCAT(x,y) CONCAT2(x,y) - -#define F_PERM 1 -#define F_NORD 4 -#define F_NOWR 8 -#define F_EOF 16 -#define F_ERR 32 -#define F_SVB 64 -#define F_APP 128 - -#define EOF (-1) - -#define LDBL_MANT_DIG 113 -#define LDBL_MIN_EXP (-16381) -#define LDBL_MAX_EXP 16384 - -#define LDBL_DIG 33 -#define LDBL_MIN_10_EXP (-4931) -#define LDBL_MAX_10_EXP 4932 - -#define DECIMAL_DIG 36 - -#if defined(ZIG_BYTE_ORDER) && ZIG_BYTE_ORDER == ZIG_LITTLE_ENDIAN -union ldshape { - float128_t f; - struct { - uint64_t lo; - uint32_t mid; - uint16_t top; - uint16_t se; - } i; - struct { - uint64_t lo; - uint64_t hi; - } i2; -}; -#elif defined(ZIG_BYTE_ORDER) && ZIG_BYTE_ORDER == ZIG_BIG_ENDIAN -union ldshape { - float128_t f; - struct { - uint16_t se; - uint16_t top; - uint32_t mid; - uint64_t lo; - } i; - struct { - uint64_t hi; - uint64_t lo; - } i2; -}; -#else -#error Unsupported endian -#endif - -struct MuslFILE { - unsigned flags; - unsigned char *rpos, *rend; - int (*close)(struct MuslFILE *); - unsigned char *wend, *wpos; - unsigned char *mustbezero_1; - unsigned char *wbase; - size_t (*read)(struct MuslFILE *, unsigned char *, size_t); - size_t (*write)(struct MuslFILE *, const unsigned char *, size_t); - off_t (*seek)(struct MuslFILE *, off_t, int); - unsigned char *buf; - size_t buf_size; - struct MuslFILE *prev, *next; - int fd; - int pipe_pid; - long lockcount; - int mode; - volatile int lock; - int lbf; - void *cookie; - off_t off; - char *getln_buf; - void *mustbezero_2; - unsigned char *shend; - off_t shlim, shcnt; - struct MuslFILE *prev_locked, *next_locked; - struct __locale_struct *locale; -}; - -static void __shlim(struct MuslFILE *f, off_t lim) -{ - f->shlim = lim; - f->shcnt = f->buf - f->rpos; - /* If lim is nonzero, rend must be a valid pointer. */ - if (lim && f->rend - f->rpos > lim) - f->shend = f->rpos + lim; - else - f->shend = f->rend; -} - -static int __toread(struct MuslFILE *f) -{ - f->mode |= f->mode-1; - if (f->wpos != f->wbase) f->write(f, 0, 0); - f->wpos = f->wbase = f->wend = 0; - if (f->flags & F_NORD) { - f->flags |= F_ERR; - return EOF; - } - f->rpos = f->rend = f->buf + f->buf_size; - return (f->flags & F_EOF) ? EOF : 0; -} - -static int __uflow(struct MuslFILE *f) -{ - unsigned char c; - if (!__toread(f) && f->read(f, &c, 1)==1) return c; - return EOF; -} - -static int __shgetc(struct MuslFILE *f) -{ - int c; - off_t cnt = shcnt(f); - if ((f->shlim && cnt >= f->shlim) || (c=__uflow(f)) < 0) { - f->shcnt = f->buf - f->rpos + cnt; - f->shend = f->rpos; - f->shlim = -1; - return EOF; - } - cnt++; - if (f->shlim && f->rend - f->rpos > f->shlim - cnt) - f->shend = f->rpos + (f->shlim - cnt); - else - f->shend = f->rend; - f->shcnt = f->buf - f->rpos + cnt; - if (f->rpos[-1] != c) f->rpos[-1] = c; - return c; -} - -static long long scanexp(struct MuslFILE *f, int pok) -{ - int c; - int x; - long long y; - int neg = 0; - - c = shgetc(f); - if (c=='+' || c=='-') { - neg = (c=='-'); - c = shgetc(f); - if (c-'0'>=10U && pok) shunget(f); - } - if (c-'0'>=10U && c!='_') { - shunget(f); - return LLONG_MIN; - } - for (x=0; ; c = shgetc(f)) { - if (c=='_') { - continue; - } else if (c-'0'<10U && x>16) | 1ULL<<48; - yhi = (uy.i2.hi & -1ULL>>16) | 1ULL<<48; - xlo = ux.i2.lo; - ylo = uy.i2.lo; - for (; ex > ey; ex--) { - hi = xhi - yhi; - lo = xlo - ylo; - if (xlo < ylo) - hi -= 1; - if (hi >> 63 == 0) { - if ((hi|lo) == 0) { - //return 0*x; - float128_t result; - f128M_mul(&zero, &x, &result); - return result; - } - xhi = 2*hi + (lo>>63); - xlo = 2*lo; - } else { - xhi = 2*xhi + (xlo>>63); - xlo = 2*xlo; - } - } - hi = xhi - yhi; - lo = xlo - ylo; - if (xlo < ylo) - hi -= 1; - if (hi >> 63 == 0) { - if ((hi|lo) == 0) { - //return 0*x; - float128_t result; - f128M_mul(&zero, &x, &result); - return result; - } - xhi = hi; - xlo = lo; - } - for (; xhi >> 48 == 0; xhi = 2*xhi + (xlo>>63), xlo = 2*xlo, ex--); - ux.i2.hi = xhi; - ux.i2.lo = xlo; - - /* scale result */ - if (ex <= 0) { - ux.i.se = (ex+120)|sx; - //ux.f *= 0x1p-120f; - mul_eq_f128_float(&ux.f, 0x1p-120f); - } else - ux.i.se = ex|sx; - return ux.f; -} - -static float128_t int_mul_f128_cast_u32(int sign, uint32_t x0) { - float128_t x0_f128; - ui32_to_f128M(x0, &x0_f128); - float128_t sign_f128; - i32_to_f128M(sign, &sign_f128); - float128_t result; - f128M_mul(&sign_f128, &x0_f128, &result); - return result; -} - -static float128_t triple_divide(int sign, uint32_t x0, int p10s) { - float128_t part1 = int_mul_f128_cast_u32(sign, x0); - float128_t p10s_f128; - i32_to_f128M(p10s, &p10s_f128); - float128_t result; - f128M_div(&part1, &p10s_f128, &result); - return result; -} - -static float128_t triple_multiply(int sign, uint32_t x0, int p10s) { - float128_t part1 = int_mul_f128_cast_u32(sign, x0); - float128_t p10s_f128; - i32_to_f128M(p10s, &p10s_f128); - float128_t result; - f128M_mul(&part1, &p10s_f128, &result); - return result; -} - -static void mul_eq_f128_int(float128_t *y, int sign) { - float128_t sign_f128; - i32_to_f128M(sign, &sign_f128); - float128_t new_value; - f128M_mul(y, &sign_f128, &new_value); - *y = new_value; -} - -static float128_t make_f128(uint64_t hi, uint64_t lo) { - union ldshape ux; - ux.i2.hi = hi; - ux.i2.lo = lo; - return ux.f; -} - -static void mul_eq_f128_f128(float128_t *a, float128_t b) { - float128_t new_value; - f128M_mul(a, &b, &new_value); - *a = new_value; -} - -static void add_eq_f128_dbl(float128_t *a, double b) { - float64_t b_f64; - memcpy(&b_f64, &b, sizeof(double)); - - float128_t b_f128; - f64_to_f128M(b_f64, &b_f128); - - float128_t new_value; - f128M_add(a, &b_f128, &new_value); - *a = new_value; -} - -static float128_t scalbnf128(float128_t x, int n) -{ - union ldshape u; - - if (n > 16383) { - //x *= 0x1p16383q; - mul_eq_f128_f128(&x, make_f128(0x7ffe000000000000, 0x0000000000000000)); - n -= 16383; - if (n > 16383) { - //x *= 0x1p16383q; - mul_eq_f128_f128(&x, make_f128(0x7ffe000000000000, 0x0000000000000000)); - n -= 16383; - if (n > 16383) - n = 16383; - } - } else if (n < -16382) { - //x *= 0x1p-16382q * 0x1p113q; - { - float128_t mul_result; - float128_t a = make_f128(0x0001000000000000, 0x0000000000000000); - float128_t b = make_f128(0x4070000000000000, 0x0000000000000000); - f128M_mul(&a, &b, &mul_result); - mul_eq_f128_f128(&x, mul_result); - } - n += 16382 - 113; - if (n < -16382) { - //x *= 0x1p-16382q * 0x1p113q; - { - float128_t mul_result; - float128_t a = make_f128(0x0001000000000000, 0x0000000000000000); - float128_t b = make_f128(0x4070000000000000, 0x0000000000000000); - f128M_mul(&a, &b, &mul_result); - mul_eq_f128_f128(&x, mul_result); - } - n += 16382 - 113; - if (n < -16382) - n = -16382; - } - } - //u.f = 1.0; - ui32_to_f128M(1, &u.f); - u.i.se = 0x3fff + n; - mul_eq_f128_f128(&x, u.f); - return x; -} - -static float128_t fabsf128(float128_t x) -{ - union ldshape u = {x}; - - u.i.se &= 0x7fff; - return u.f; -} - -static float128_t decfloat(struct MuslFILE *f, int c, int bits, int emin, int sign, int pok) -{ - uint32_t x[KMAX]; - static const uint32_t th[] = { LD_B1B_MAX }; - int i, j, k, a, z; - long long lrp=0, dc=0; - long long e10=0; - int lnz = 0; - int gotdig = 0, gotrad = 0; - int rp; - int e2; - int emax = -emin-bits+3; - int denormal = 0; - float128_t y; - float128_t zero; - ui32_to_f128M(0, &zero); - float128_t frac=zero; - float128_t bias=zero; - static const int p10s[] = { 10, 100, 1000, 10000, - 100000, 1000000, 10000000, 100000000 }; - - j=0; - k=0; - - /* Don't let leading zeros/underscores consume buffer space */ - for (; ; c = shgetc(f)) { - if (c=='_') { - continue; - } else if (c=='0') { - gotdig=1; - } else { - break; - } - } - - if (c=='.') { - gotrad = 1; - for (c = shgetc(f); ; c = shgetc(f)) { - if (c == '_') { - continue; - } else if (c=='0') { - gotdig=1; - lrp--; - } else { - break; - } - } - } - - x[0] = 0; - for (; c-'0'<10U || c=='.' || c=='_'; c = shgetc(f)) { - if (c == '_') { - continue; - } else if (c == '.') { - if (gotrad) break; - gotrad = 1; - lrp = dc; - } else if (k < KMAX-3) { - dc++; - if (c!='0') lnz = dc; - if (j) x[k] = x[k]*10 + c-'0'; - else x[k] = c-'0'; - if (++j==9) { - k++; - j=0; - } - gotdig=1; - } else { - dc++; - if (c!='0') { - lnz = (KMAX-4)*9; - x[KMAX-4] |= 1; - } - } - } - if (!gotrad) lrp=dc; - - if (gotdig && (c|32)=='e') { - e10 = scanexp(f, pok); - if (e10 == LLONG_MIN) { - if (pok) { - shunget(f); - } else { - shlim(f, 0); - return zero; - } - e10 = 0; - } - lrp += e10; - } else if (c>=0) { - shunget(f); - } - if (!gotdig) { - errno = EINVAL; - shlim(f, 0); - return zero; - } - - /* Handle zero specially to avoid nasty special cases later */ - if (!x[0]) { - //return sign * 0.0; - return dbl_to_f128(sign * 0.0); - } - - /* Optimize small integers (w/no exponent) and over/under-flow */ - if (lrp==dc && dc<10 && (bits>30 || x[0]>>bits==0)) { - //return sign * (float128_t)x[0]; - float128_t sign_f128; - i32_to_f128M(sign, &sign_f128); - float128_t x0_f128; - ui32_to_f128M(x[0], &x0_f128); - float128_t result; - f128M_mul(&sign_f128, &x0_f128, &result); - return result; - } - if (lrp > -emin/2) { - errno = ERANGE; - //return sign * LDBL_MAX * LDBL_MAX; - return zero; - } - if (lrp < emin-2*LDBL_MANT_DIG) { - errno = ERANGE; - //return sign * LDBL_MIN * LDBL_MIN; - return zero; - } - - /* Align incomplete final B1B digit */ - if (j) { - for (; j<9; j++) x[k]*=10; - k++; - j=0; - } - - a = 0; - z = k; - e2 = 0; - rp = lrp; - - /* Optimize small to mid-size integers (even in exp. notation) */ - if (lnz<9 && lnz<=rp && rp < 18) { - if (rp == 9) { - //return sign * (float128_t)(x[0]); - return int_mul_f128_cast_u32(sign, x[0]); - } - if (rp < 9) { - //return sign * (float128_t)(x[0]) / p10s[8-rp]; - return triple_divide(sign, x[0], p10s[8-rp]); - } - int bitlim = bits-3*(int)(rp-9); - if (bitlim>30 || x[0]>>bitlim==0) - //return sign * (float128_t)(x[0]) * p10s[rp-10]; - return triple_multiply(sign, x[0], p10s[rp-10]); - } - - /* Drop trailing zeros */ - for (; !x[z-1]; z--); - - /* Align radix point to B1B digit boundary */ - if (rp % 9) { - int rpm9 = rp>=0 ? rp%9 : rp%9+9; - int p10 = p10s[8-rpm9]; - uint32_t carry = 0; - for (k=a; k!=z; k++) { - uint32_t tmp = x[k] % p10; - x[k] = x[k]/p10 + carry; - carry = 1000000000/p10 * tmp; - if (k==a && !x[k]) { - a = (a+1 & MASK); - rp -= 9; - } - } - if (carry) x[z++] = carry; - rp += 9-rpm9; - } - - /* Upscale until desired number of bits are left of radix point */ - while (rp < 9*LD_B1B_DIG || (rp == 9*LD_B1B_DIG && x[a] 1000000000) { - carry = tmp / 1000000000; - x[k] = tmp % 1000000000; - } else { - carry = 0; - x[k] = tmp; - } - if (k==(z-1 & MASK) && k!=a && !x[k]) z = k; - if (k==a) break; - } - if (carry) { - rp += 9; - a = (a-1 & MASK); - if (a == z) { - z = (z-1 & MASK); - x[z-1 & MASK] |= x[z]; - } - x[a] = carry; - } - } - - /* Downscale until exactly number of bits are left of radix point */ - for (;;) { - uint32_t carry = 0; - int sh = 1; - for (i=0; i th[i]) break; - } - if (i==LD_B1B_DIG && rp==9*LD_B1B_DIG) break; - /* FIXME: find a way to compute optimal sh */ - if (rp > 9+9*LD_B1B_DIG) sh = 9; - e2 += sh; - for (k=a; k!=z; k=(k+1 & MASK)) { - uint32_t tmp = x[k] & (1<>sh) + carry; - carry = (1000000000>>sh) * tmp; - if (k==a && !x[k]) { - a = (a+1 & MASK); - i--; - rp -= 9; - } - } - if (carry) { - if ((z+1 & MASK) != a) { - x[z] = carry; - z = (z+1 & MASK); - } else x[z-1 & MASK] |= 1; - } - } - - /* Assemble desired bits into floating point variable */ - for (y=zero,i=0; i LDBL_MANT_DIG+e2-emin) { - bits = LDBL_MANT_DIG+e2-emin; - if (bits<0) bits=0; - denormal = 1; - } - - /* Calculate bias term to force rounding, move out lower bits */ - if (bits < LDBL_MANT_DIG) { - bias = copysignf128(dbl_to_f128(scalbn(1, 2*LDBL_MANT_DIG-bits-1)), y); - frac = fmodf128(y, dbl_to_f128(scalbn(1, LDBL_MANT_DIG-bits))); - //y -= frac; - { - float128_t new_value; - f128M_sub(&y, &frac, &new_value); - y = new_value; - } - //y += bias; - { - float128_t new_value; - f128M_add(&y, &frac, &new_value); - y = new_value; - } - } - - /* Process tail of decimal input so it can affect rounding */ - if ((a+i & MASK) != z) { - uint32_t t = x[a+i & MASK]; - if (t < 500000000 && (t || (a+i+1 & MASK) != z)) { - //frac += 0.25*sign; - add_eq_f128_dbl(&frac, 0.25*sign); - } else if (t > 500000000) { - //frac += 0.75*sign; - add_eq_f128_dbl(&frac, 0.75*sign); - } else if (t == 500000000) { - if ((a+i+1 & MASK) == z) { - //frac += 0.5*sign; - add_eq_f128_dbl(&frac, 0.5*sign); - } else { - //frac += 0.75*sign; - add_eq_f128_dbl(&frac, 0.75*sign); - } - } - //if (LDBL_MANT_DIG-bits >= 2 && !fmodf128(frac, 1)) - if (LDBL_MANT_DIG-bits >= 2) { - float128_t one; - ui32_to_f128M(1, &one); - float128_t mod_result = fmodf128(frac, one); - if (f128M_eq(&mod_result, &zero)) { - //frac++; - add_eq_f128_dbl(&frac, 1.0); - } - } - } - - //y += frac; - { - float128_t new_value; - f128M_add(&y, &frac, &new_value); - y = new_value; - } - //y -= bias; - { - float128_t new_value; - f128M_sub(&y, &bias, &new_value); - y = new_value; - } - - if ((e2+LDBL_MANT_DIG & INT_MAX) > emax-5) { - //if (fabsf128(y) >= 0x1p113) - float128_t abs_y = fabsf128(y); - float128_t mant_f128 = make_f128(0x4070000000000000, 0x0000000000000000); - if (!f128M_lt(&abs_y, &mant_f128)) { - if (denormal && bits==LDBL_MANT_DIG+e2-emin) - denormal = 0; - //y *= 0.5; - { - float128_t point_5 = dbl_to_f128(0.5); - float128_t new_value; - f128M_mul(&y, &point_5, &new_value); - y = new_value; - } - - e2++; - } - if (e2+LDBL_MANT_DIG>emax || (denormal && !f128M_eq(&frac, &zero))) - errno = ERANGE; - } - - return scalbnf128(y, e2); -} - -static float128_t hexfloat(struct MuslFILE *f, int bits, int emin, int sign, int pok) -{ - float128_t zero; - ui32_to_f128M(0, &zero); - float128_t one; - ui32_to_f128M(1, &one); - float128_t sixteen; - ui32_to_f128M(16, &sixteen); - float128_t point_5 = dbl_to_f128(0.5); - - uint32_t x = 0; - float128_t y = zero; - float128_t scale = one; - float128_t bias = zero; - int gottail = 0, gotrad = 0, gotdig = 0; - long long rp = 0; - long long dc = 0; - long long e2 = 0; - int d; - int c; - - c = shgetc(f); - - /* Skip leading zeros/underscores */ - for (; c=='0' || c=='_'; c = shgetc(f)) gotdig = 1; - - if (c=='.') { - gotrad = 1; - c = shgetc(f); - /* Count zeros after the radix point before significand */ - for (rp=0; ; c = shgetc(f)) { - if (c == '_') { - continue; - } else if (c == '0') { - gotdig = 1; - rp--; - } else { - break; - } - } - } - - for (; c-'0'<10U || (c|32)-'a'<6U || c=='.' || c=='_'; c = shgetc(f)) { - if (c=='_') { - continue; - } else if (c=='.') { - if (gotrad) break; - rp = dc; - gotrad = 1; - } else { - gotdig = 1; - if (c > '9') d = (c|32)+10-'a'; - else d = c-'0'; - if (dc<8) { - x = x*16 + d; - } else if (dc < LDBL_MANT_DIG/4+1) { - //y += d*(scale/=16); - { - float128_t divided; - f128M_div(&scale, &sixteen, ÷d); - scale = divided; - float128_t d_f128; - i32_to_f128M(d, &d_f128); - float128_t add_op; - f128M_mul(&d_f128, &scale, &add_op); - float128_t new_y; - f128M_add(&y, &add_op, &new_y); - y = new_y; - } - } else if (d && !gottail) { - //y += 0.5*scale; - { - float128_t add_op; - f128M_mul(&point_5, &scale, &add_op); - float128_t new_y; - f128M_add(&y, &add_op, &new_y); - y = new_y; - } - gottail = 1; - } - dc++; - } - } - if (!gotdig) { - shunget(f); - if (pok) { - shunget(f); - if (gotrad) shunget(f); - } else { - shlim(f, 0); - } - //return sign * 0.0; - return dbl_to_f128(sign * 0.0); - } - if (!gotrad) rp = dc; - while (dc<8) x *= 16, dc++; - if ((c|32)=='p') { - e2 = scanexp(f, pok); - if (e2 == LLONG_MIN) { - if (pok) { - shunget(f); - } else { - shlim(f, 0); - return zero; - } - e2 = 0; - } - } else { - shunget(f); - } - e2 += 4*rp - 32; - - if (!x) { - //return sign * 0.0; - return dbl_to_f128(sign * 0.0); - } - if (e2 > -emin) { - errno = ERANGE; - //return sign * LDBL_MAX * LDBL_MAX; - return zero; - } - if (e2 < emin-2*LDBL_MANT_DIG) { - errno = ERANGE; - //return sign * LDBL_MIN * LDBL_MIN; - return zero; - } - - while (x < 0x80000000) { - //if (y>=0.5) - if (!f128M_lt(&y, &point_5)) { - x += x + 1; - //y += y - 1; - { - float128_t minus_one; - f128M_sub(&y, &one, &minus_one); - float128_t new_y; - f128M_add(&y, &minus_one, &new_y); - y = new_y; - } - } else { - x += x; - //y += y; - { - float128_t new_y; - f128M_add(&y, &y, &new_y); - y = new_y; - } - } - e2--; - } - - if (bits > 32+e2-emin) { - bits = 32+e2-emin; - if (bits<0) bits=0; - } - - if (bits < LDBL_MANT_DIG) { - float128_t sign_f128; - i32_to_f128M(sign, &sign_f128); - bias = copysignf128(dbl_to_f128(scalbn(1, 32+LDBL_MANT_DIG-bits-1)), sign_f128); - } - - //if (bits<32 && y && !(x&1)) x++, y=0; - if (bits<32 && !f128M_eq(&y, &zero) && !(x&1)) x++, y=zero; - - //y = bias + sign*(float128_t)x + sign*y; - { - float128_t x_f128; - ui32_to_f128M(x, &x_f128); - float128_t sign_f128; - i32_to_f128M(sign, &sign_f128); - float128_t sign_mul_x; - f128M_mul(&sign_f128, &x_f128, &sign_mul_x); - float128_t sign_mul_y; - f128M_mul(&sign_f128, &y, &sign_mul_y); - float128_t bias_op; - f128M_add(&bias, &sign_mul_x, &bias_op); - float128_t new_y; - f128M_add(&bias_op, &sign_mul_y, &new_y); - y = new_y; - } - //y -= bias; - { - float128_t new_y; - f128M_sub(&y, &bias, &new_y); - y = new_y; - } - - if (f128M_eq(&y, &zero)) errno = ERANGE; - - return scalbnf128(y, e2); -} - -static int isspace(int c) -{ - return c == ' ' || (unsigned)c-'\t' < 5; -} - -static inline float128_t makeInf128(void) { - union ldshape ux; - ux.i2.hi = 0x7fff000000000000UL; - ux.i2.lo = 0x0UL; - return ux.f; -} - -static inline float128_t makeNaN128(void) { - uint64_t rand = 0UL; - union ldshape ux; - ux.i2.hi = 0x7fff000000000000UL | (rand & 0xffffffffffffUL); - ux.i2.lo = 0x0UL; - return ux.f; -} - -float128_t __floatscan(struct MuslFILE *f, int prec, int pok) -{ - int sign = 1; - size_t i; - int bits = LDBL_MANT_DIG; - int emin = LDBL_MIN_EXP-bits; - int c; - - while (isspace((c=shgetc(f)))); - - if (c=='+' || c=='-') { - sign -= 2*(c=='-'); - c = shgetc(f); - } - - for (i=0; i<8 && (c|32)=="infinity"[i]; i++) - if (i<7) c = shgetc(f); - if (i==3 || i==8 || (i>3 && pok)) { - if (i!=8) { - shunget(f); - if (pok) for (; i>3; i--) shunget(f); - } - //return sign * INFINITY; - float128_t sign_f128; - i32_to_f128M(sign, &sign_f128); - float128_t infinity_f128 = makeInf128(); - float128_t result; - f128M_mul(&sign_f128, &infinity_f128, &result); - return result; - } - if (!i) for (i=0; i<3 && (c|32)=="nan"[i]; i++) - if (i<2) c = shgetc(f); - if (i==3) { - if (shgetc(f) != '(') { - shunget(f); - return makeNaN128(); - } - for (i=1; ; i++) { - c = shgetc(f); - if (c-'0'<10U || c-'A'<26U || c-'a'<26U || c=='_') - continue; - if (c==')') return makeNaN128(); - shunget(f); - if (!pok) { - errno = EINVAL; - shlim(f, 0); - float128_t zero; - ui32_to_f128M(0, &zero); - return zero; - } - while (i--) shunget(f); - return makeNaN128(); - } - return makeNaN128(); - } - - if (i) { - shunget(f); - errno = EINVAL; - shlim(f, 0); - float128_t zero; - ui32_to_f128M(0, &zero); - return zero; - } - - if (c=='0') { - c = shgetc(f); - if ((c|32) == 'x') - return hexfloat(f, bits, emin, sign, pok); - shunget(f); - c = '0'; - } - - return decfloat(f, c, bits, emin, sign, pok); -} - -float128_t parse_f128(const char *s, char **p) { - struct MuslFILE f; - sh_fromstring(&f, s); - shlim(&f, 0); - float128_t y = __floatscan(&f, 2, 1); - off_t cnt = shcnt(&f); - if (p) *p = cnt ? (char *)s + cnt : (char *)s; - return y; -} diff --git a/src/stage1/parse_f128.h b/src/stage1/parse_f128.h deleted file mode 100644 index 82cdf6c9a0bf..000000000000 --- a/src/stage1/parse_f128.h +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright (c) 2015 Andrew Kelley - * - * This file is part of zig, which is MIT licensed. - * See http://opensource.org/licenses/MIT - */ - -#ifndef ZIG_PARSE_F128_H -#define ZIG_PARSE_F128_H - -#include "softfloat_types.h" - -#ifdef __cplusplus -#define ZIG_EXTERN_C extern "C" -#else -#define ZIG_EXTERN_C -#endif - -ZIG_EXTERN_C float128_t parse_f128(const char *s, char **p); - -#endif diff --git a/src/stage1/parser.cpp b/src/stage1/parser.cpp deleted file mode 100644 index eaa15c47b0c3..000000000000 --- a/src/stage1/parser.cpp +++ /dev/null @@ -1,3603 +0,0 @@ -/* - * Copyright (c) 2015 Andrew Kelley - * - * This file is part of zig, which is MIT licensed. - * See http://opensource.org/licenses/MIT - */ - -#include "parser.hpp" -#include "errmsg.hpp" -#include "analyze.hpp" - -#include -#include -#include -#include - -struct ParseContext { - Buf *buf; - // Shortcut to `owner->data.structure.root_struct->token_ids`. - TokenId *token_ids; - // Shortcut to `owner->data.structure.root_struct->token_locs`. - TokenLoc *token_locs; - ZigType *owner; - TokenIndex current_token; - ErrColor err_color; - // Shortcut to `owner->data.structure.root_struct->token_count`. - uint32_t token_count; -}; - -struct PtrPayload { - TokenIndex asterisk; - TokenIndex payload; -}; - -struct PtrIndexPayload { - TokenIndex asterisk; - TokenIndex payload; - TokenIndex index; -}; - -static AstNode *ast_parse_root(ParseContext *pc); -static AstNodeContainerDecl ast_parse_container_members(ParseContext *pc); -static AstNode *ast_parse_test_decl(ParseContext *pc); -static AstNode *ast_parse_top_level_comptime(ParseContext *pc); -static AstNode *ast_parse_top_level_decl(ParseContext *pc, VisibMod visib_mod, - TokenIndex doc_comments); -static AstNode *ast_parse_fn_proto(ParseContext *pc); -static AstNode *ast_parse_var_decl(ParseContext *pc); -static AstNode *ast_parse_container_field(ParseContext *pc); -static AstNode *ast_parse_statement(ParseContext *pc); -static AstNode *ast_parse_if_statement(ParseContext *pc); -static AstNode *ast_parse_labeled_statement(ParseContext *pc); -static AstNode *ast_parse_loop_statement(ParseContext *pc); -static AstNode *ast_parse_for_statement(ParseContext *pc); -static AstNode *ast_parse_while_statement(ParseContext *pc); -static AstNode *ast_parse_block_expr_statement(ParseContext *pc); -static AstNode *ast_parse_block_expr(ParseContext *pc); -static AstNode *ast_parse_assign_expr(ParseContext *pc); -static AstNode *ast_parse_expr(ParseContext *pc); -static AstNode *ast_parse_bool_or_expr(ParseContext *pc); -static AstNode *ast_parse_bool_and_expr(ParseContext *pc); -static AstNode *ast_parse_compare_expr(ParseContext *pc); -static AstNode *ast_parse_bitwise_expr(ParseContext *pc); -static AstNode *ast_parse_bit_shift_expr(ParseContext *pc); -static AstNode *ast_parse_addition_expr(ParseContext *pc); -static AstNode *ast_parse_multiply_expr(ParseContext *pc); -static AstNode *ast_parse_prefix_expr(ParseContext *pc); -static AstNode *ast_parse_primary_expr(ParseContext *pc); -static AstNode *ast_parse_if_expr(ParseContext *pc); -static AstNode *ast_parse_block(ParseContext *pc); -static AstNode *ast_parse_loop_expr(ParseContext *pc); -static AstNode *ast_parse_for_expr(ParseContext *pc); -static AstNode *ast_parse_while_expr(ParseContext *pc); -static AstNode *ast_parse_curly_suffix_expr(ParseContext *pc); -static AstNode *ast_parse_init_list(ParseContext *pc); -static AstNode *ast_parse_type_expr(ParseContext *pc); -static AstNode *ast_parse_error_union_expr(ParseContext *pc); -static AstNode *ast_parse_suffix_expr(ParseContext *pc); -static AstNode *ast_parse_primary_type_expr(ParseContext *pc); -static AstNode *ast_parse_container_decl(ParseContext *pc); -static AstNode *ast_parse_error_set_decl(ParseContext *pc); -static AstNode *ast_parse_grouped_expr(ParseContext *pc); -static AstNode *ast_parse_if_type_expr(ParseContext *pc); -static AstNode *ast_parse_labeled_type_expr(ParseContext *pc); -static AstNode *ast_parse_loop_type_expr(ParseContext *pc); -static AstNode *ast_parse_for_type_expr(ParseContext *pc); -static AstNode *ast_parse_while_type_expr(ParseContext *pc); -static AstNode *ast_parse_switch_expr(ParseContext *pc); -static AstNode *ast_parse_asm_expr(ParseContext *pc); -static AstNode *ast_parse_anon_lit(ParseContext *pc); -static AstNode *ast_parse_asm_output(ParseContext *pc); -static AsmOutput *ast_parse_asm_output_item(ParseContext *pc); -static AstNode *ast_parse_asm_input(ParseContext *pc); -static AsmInput *ast_parse_asm_input_item(ParseContext *pc); -static AstNode *ast_parse_asm_clobbers(ParseContext *pc); -static TokenIndex ast_parse_break_label(ParseContext *pc); -static TokenIndex ast_parse_block_label(ParseContext *pc); -static AstNode *ast_parse_field_init(ParseContext *pc); -static AstNode *ast_parse_while_continue_expr(ParseContext *pc); -static AstNode *ast_parse_link_section(ParseContext *pc); -static AstNode *ast_parse_callconv(ParseContext *pc); -static AstNode *ast_parse_param_decl(ParseContext *pc); -static AstNode *ast_parse_param_type(ParseContext *pc); -static AstNode *ast_parse_if_prefix(ParseContext *pc); -static AstNode *ast_parse_while_prefix(ParseContext *pc); -static AstNode *ast_parse_for_prefix(ParseContext *pc); -static TokenIndex ast_parse_payload(ParseContext *pc); -static Optional ast_parse_ptr_payload(ParseContext *pc); -static Optional ast_parse_ptr_index_payload(ParseContext *pc); -static AstNode *ast_parse_switch_prong(ParseContext *pc); -static AstNode *ast_parse_switch_case(ParseContext *pc); -static AstNode *ast_parse_switch_item(ParseContext *pc); -static AstNode *ast_parse_assign_op(ParseContext *pc); -static AstNode *ast_parse_compare_op(ParseContext *pc); -static AstNode *ast_parse_bitwise_op(ParseContext *pc); -static AstNode *ast_parse_bit_shift_op(ParseContext *pc); -static AstNode *ast_parse_addition_op(ParseContext *pc); -static AstNode *ast_parse_multiply_op(ParseContext *pc); -static AstNode *ast_parse_prefix_op(ParseContext *pc); -static AstNode *ast_parse_prefix_type_op(ParseContext *pc); -static AstNode *ast_parse_suffix_op(ParseContext *pc); -static AstNode *ast_parse_fn_call_arguments(ParseContext *pc); -static AstNode *ast_parse_array_type_start(ParseContext *pc); -static AstNode *ast_parse_ptr_type_start(ParseContext *pc); -static AstNode *ast_parse_container_decl_auto(ParseContext *pc); -static AstNode *ast_parse_container_decl_type(ParseContext *pc); -static AstNode *ast_parse_byte_align(ParseContext *pc); - -ATTRIBUTE_NORETURN -static void ast_error_offset(RootStruct *root_struct, ErrColor err_color, - TokenIndex token, size_t bad_index, Buf *msg) -{ - assert(token < root_struct->token_count); - uint32_t byte_offset = root_struct->token_locs[token].offset; - ErrorMsg *err = err_msg_create_with_offset(root_struct->path, - byte_offset + bad_index, buf_ptr(root_struct->source_code), msg); - - print_err_msg(err, err_color); - exit(EXIT_FAILURE); -} - -ATTRIBUTE_PRINTF(3, 4) -ATTRIBUTE_NORETURN -static void ast_error(ParseContext *pc, TokenIndex token, const char *format, ...) { - va_list ap; - va_start(ap, format); - Buf *msg = buf_vprintf(format, ap); - va_end(ap); - - RootStruct *root_struct = pc->owner->data.structure.root_struct; - ast_error_offset(root_struct, pc->err_color, token, 0, msg); -} - -ATTRIBUTE_NORETURN -static void ast_invalid_token_error(ParseContext *pc, TokenIndex token) { - ast_error(pc, token, "invalid token: '%s'", token_name(pc->token_ids[token])); -} - -static AstNode *ast_create_node_no_line_info(ParseContext *pc, NodeType type) { - AstNode *node = heap::c_allocator.create(); - node->type = type; - node->owner = pc->owner; - return node; -} - -static AstNode *ast_create_node(ParseContext *pc, NodeType type, TokenIndex first_token) { - assert(first_token); - AstNode *node = ast_create_node_no_line_info(pc, type); - node->main_token = first_token; - return node; -} - -static AstNode *ast_create_node_copy_line_info(ParseContext *pc, NodeType type, AstNode *from) { - assert(from); - AstNode *node = ast_create_node_no_line_info(pc, type); - node->main_token = from->main_token; - return node; -} - -static TokenIndex peek_token(ParseContext *pc) { - return pc->current_token; -} - -static TokenIndex eat_token(ParseContext *pc) { - TokenIndex res = peek_token(pc); - pc->current_token += 1; - return res; -} - -static TokenIndex eat_token_if(ParseContext *pc, TokenId id) { - TokenIndex res = peek_token(pc); - if (pc->token_ids[res] == id) { - return eat_token(pc); - } - - return 0; -} - -static TokenIndex expect_token(ParseContext *pc, TokenId id) { - TokenIndex res = eat_token(pc); - TokenId actual_id = pc->token_ids[res]; - if (actual_id != id) - ast_error(pc, res, "expected token '%s', found '%s'", token_name(id), token_name(actual_id)); - - return res; -} - -static void put_back_token(ParseContext *pc) { - pc->current_token -= 1; -} - -static Buf *token_buf(ParseContext *pc, TokenIndex token) { - Error err; - - if (token == 0) - return nullptr; - - RootStruct *root_struct = pc->owner->data.structure.root_struct; - if (root_struct->token_ids[token] == TokenIdIdentifier) { - return token_identifier_buf(root_struct, token); - } else if (root_struct->token_ids[token] == TokenIdStringLiteral) { - assert(root_struct->token_ids[token] == TokenIdStringLiteral); - const char *source = buf_ptr(root_struct->source_code); - size_t byte_offset = root_struct->token_locs[token].offset; - size_t bad_index; - Buf *str = buf_alloc(); - if ((err = source_string_literal_buf(source + byte_offset, str, &bad_index))) { - ast_error_offset(root_struct, pc->err_color, token, bad_index, - buf_create_from_str("invalid string literal character")); - } - return str; - } else { - zig_unreachable(); - } -} - -static AstNode *token_identifier(ParseContext *pc, TokenIndex token) { - assert(pc->token_ids[token] == TokenIdIdentifier); - return ast_create_node(pc, NodeTypeIdentifier, token); -} - -// (Rule SEP)* Rule? -template -static ZigList ast_parse_list(ParseContext *pc, TokenId sep, T *(*parser)(ParseContext*)) { - ZigList res = {}; - while (true) { - T *curr = parser(pc); - if (curr == nullptr) - break; - - res.append(curr); - if (eat_token_if(pc, sep) == 0) - break; - } - - return res; -} - -static AstNode *ast_expect(ParseContext *pc, AstNode *(*parser)(ParseContext*)) { - AstNode *res = parser(pc); - if (res == nullptr) - ast_invalid_token_error(pc, peek_token(pc)); - return res; -} - -enum BinOpChain { - BinOpChainOnce, - BinOpChainInf, -}; - -// Op* Child -static AstNode *ast_parse_prefix_op_expr( - ParseContext *pc, - AstNode *(*op_parser)(ParseContext *), - AstNode *(*child_parser)(ParseContext *) -) { - AstNode *res = nullptr; - AstNode **right = &res; - while (true) { - AstNode *prefix = op_parser(pc); - if (prefix == nullptr) - break; - - *right = prefix; - switch (prefix->type) { - case NodeTypePrefixOpExpr: - right = &prefix->data.prefix_op_expr.primary_expr; - break; - case NodeTypeReturnExpr: - right = &prefix->data.return_expr.expr; - break; - case NodeTypeAwaitExpr: - right = &prefix->data.await_expr.expr; - break; - case NodeTypeAnyFrameType: - right = &prefix->data.anyframe_type.payload_type; - break; - case NodeTypeArrayType: - right = &prefix->data.array_type.child_type; - break; - case NodeTypeInferredArrayType: - right = &prefix->data.inferred_array_type.child_type; - break; - case NodeTypePointerType: { - // We might get two pointers from *_ptr_type_start - AstNode *child = prefix->data.pointer_type.op_expr; - if (child == nullptr) - child = prefix; - right = &child->data.pointer_type.op_expr; - break; - } - default: - zig_unreachable(); - } - } - - // If we have already consumed a token, and determined that - // this node is a prefix op, then we expect that the node has - // a child. - if (res != nullptr) { - *right = ast_expect(pc, child_parser); - } else { - // Otherwise, if we didn't consume a token, then we can return - // null, if the child expr did. - *right = child_parser(pc); - if (*right == nullptr) - return nullptr; - } - - return res; -} - -// Child (Op Child)(*/?) -static AstNode *ast_parse_bin_op_expr( - ParseContext *pc, - BinOpChain chain, - AstNode *(*op_parse)(ParseContext*), - AstNode *(*child_parse)(ParseContext*) -) { - AstNode *res = child_parse(pc); - if (res == nullptr) - return nullptr; - - do { - AstNode *op = op_parse(pc); - if (op == nullptr) - break; - - AstNode *left = res; - AstNode *right = ast_expect(pc, child_parse); - res = op; - switch (op->type) { - case NodeTypeBinOpExpr: - op->data.bin_op_expr.op1 = left; - op->data.bin_op_expr.op2 = right; - break; - case NodeTypeCatchExpr: - op->data.unwrap_err_expr.op1 = left; - op->data.unwrap_err_expr.op2 = right; - break; - default: - zig_unreachable(); - } - } while (chain == BinOpChainInf); - - return res; -} - -// IfPrefix Body (KEYWORD_else Payload? Body)? -static AstNode *ast_parse_if_expr_helper(ParseContext *pc, AstNode *(*body_parser)(ParseContext*)) { - AstNode *res = ast_parse_if_prefix(pc); - if (res == nullptr) - return nullptr; - - AstNode *body = ast_expect(pc, body_parser); - TokenIndex err_payload = 0; - AstNode *else_body = nullptr; - if (eat_token_if(pc, TokenIdKeywordElse) != 0) { - err_payload = ast_parse_payload(pc); - else_body = ast_expect(pc, body_parser); - } - - assert(res->type == NodeTypeIfOptional); - if (err_payload != 0) { - AstNodeTestExpr old = res->data.test_expr; - res->type = NodeTypeIfErrorExpr; - res->data.if_err_expr.target_node = old.target_node; - res->data.if_err_expr.var_is_ptr = old.var_is_ptr; - res->data.if_err_expr.var_symbol = old.var_symbol; - res->data.if_err_expr.then_node = body; - res->data.if_err_expr.err_symbol = token_buf(pc, err_payload); - res->data.if_err_expr.else_node = else_body; - return res; - } - - if (res->data.test_expr.var_symbol != nullptr) { - res->data.test_expr.then_node = body; - res->data.test_expr.else_node = else_body; - return res; - } - - AstNodeTestExpr old = res->data.test_expr; - res->type = NodeTypeIfBoolExpr; - res->data.if_bool_expr.condition = old.target_node; - res->data.if_bool_expr.then_block = body; - res->data.if_bool_expr.else_node = else_body; - return res; -} - -// KEYWORD_inline? (ForLoop / WhileLoop) -static AstNode *ast_parse_loop_expr_helper( - ParseContext *pc, - AstNode *(*for_parser)(ParseContext *), - AstNode *(*while_parser)(ParseContext *) -) { - TokenIndex inline_token = eat_token_if(pc, TokenIdKeywordInline); - AstNode *for_expr = for_parser(pc); - if (for_expr != nullptr) { - assert(for_expr->type == NodeTypeForExpr); - for_expr->data.for_expr.is_inline = inline_token != 0; - return for_expr; - } - - AstNode *while_expr = while_parser(pc); - if (while_expr != nullptr) { - assert(while_expr->type == NodeTypeWhileExpr); - while_expr->data.while_expr.is_inline = inline_token != 0; - return while_expr; - } - - if (inline_token != 0) - ast_invalid_token_error(pc, peek_token(pc)); - return nullptr; -} - -// ForPrefix Body (KEYWORD_else Body)? -static AstNode *ast_parse_for_expr_helper(ParseContext *pc, AstNode *(*body_parser)(ParseContext*)) { - AstNode *res = ast_parse_for_prefix(pc); - if (res == nullptr) - return nullptr; - - AstNode *body = ast_expect(pc, body_parser); - AstNode *else_body = nullptr; - if (eat_token_if(pc, TokenIdKeywordElse) != 0) - else_body = ast_expect(pc, body_parser); - - assert(res->type == NodeTypeForExpr); - res->data.for_expr.body = body; - res->data.for_expr.else_node = else_body; - return res; -} - -// WhilePrefix Body (KEYWORD_else Payload? Body)? -static AstNode *ast_parse_while_expr_helper(ParseContext *pc, AstNode *(*body_parser)(ParseContext*)) { - AstNode *res = ast_parse_while_prefix(pc); - if (res == nullptr) - return nullptr; - - AstNode *body = ast_expect(pc, body_parser); - TokenIndex err_payload = 0; - AstNode *else_body = nullptr; - if (eat_token_if(pc, TokenIdKeywordElse) != 0) { - err_payload = ast_parse_payload(pc); - else_body = ast_expect(pc, body_parser); - } - - assert(res->type == NodeTypeWhileExpr); - res->data.while_expr.body = body; - res->data.while_expr.err_symbol = token_buf(pc, err_payload); - res->data.while_expr.else_node = else_body; - return res; -} - -template -AstNode *ast_parse_bin_op_simple(ParseContext *pc) { - TokenIndex op_token = eat_token_if(pc, id); - if (op_token == 0) - return nullptr; - - AstNode *res = ast_create_node(pc, NodeTypeBinOpExpr, op_token); - res->data.bin_op_expr.bin_op = op; - return res; -} - -AstNode *ast_parse(Buf *buf, ZigType *owner, ErrColor err_color) { - RootStruct *root_struct = owner->data.structure.root_struct; - - ParseContext pc = {}; - pc.err_color = err_color; - pc.owner = owner; - pc.buf = buf; - pc.token_ids = root_struct->token_ids; - pc.token_locs = root_struct->token_locs; - pc.token_count = root_struct->token_count; - pc.current_token = 1; // Skip over the first (invalid) token. - return ast_parse_root(&pc); -} - -// Root <- skip ContainerMembers eof -static AstNode *ast_parse_root(ParseContext *pc) { - TokenIndex first = peek_token(pc); - AstNodeContainerDecl members = ast_parse_container_members(pc); - if (pc->current_token != pc->token_count - 1) - ast_invalid_token_error(pc, peek_token(pc)); - - AstNode *node = ast_create_node(pc, NodeTypeContainerDecl, first); - node->data.container_decl.fields = members.fields; - node->data.container_decl.decls = members.decls; - node->data.container_decl.layout = ContainerLayoutAuto; - node->data.container_decl.kind = ContainerKindStruct; - node->data.container_decl.is_root = true; - node->data.container_decl.doc_comments = members.doc_comments; - - return node; -} - -static TokenIndex ast_parse_multi_tok(ParseContext *pc, TokenId token_id) { - TokenIndex first_token = eat_token_if(pc, token_id); - TokenIndex token = first_token; - while (token != 0) { - token = eat_token_if(pc, token_id); - } - return first_token; -} - -static TokenIndex ast_parse_doc_comments(ParseContext *pc) { - return ast_parse_multi_tok(pc, TokenIdDocComment); -} - -static TokenIndex ast_parse_container_doc_comments(ParseContext *pc) { - return ast_parse_multi_tok(pc, TokenIdContainerDocComment); -} - -enum ContainerFieldState { - // no fields have been seen - ContainerFieldStateNone, - // currently parsing fields - ContainerFieldStateSeen, - // saw fields and then a declaration after them - ContainerFieldStateEnd, -}; - -// ContainerMembers -// <- TestDecl ContainerMembers -// / TopLevelComptime ContainerMembers -// / KEYWORD_pub? TopLevelDecl ContainerMembers -// / ContainerField COMMA ContainerMembers -// / ContainerField -// / -static AstNodeContainerDecl ast_parse_container_members(ParseContext *pc) { - AstNodeContainerDecl res = {}; - ContainerFieldState field_state = ContainerFieldStateNone; - TokenIndex first_token = 0; - res.doc_comments = ast_parse_container_doc_comments(pc); - for (;;) { - TokenIndex peeked_token = peek_token(pc); - - AstNode *test_decl = ast_parse_test_decl(pc); - if (test_decl != nullptr) { - if (field_state == ContainerFieldStateSeen) { - field_state = ContainerFieldStateEnd; - first_token = peeked_token; - } - res.decls.append(test_decl); - continue; - } - - AstNode *top_level_comptime = ast_parse_top_level_comptime(pc); - if (top_level_comptime != nullptr) { - if (field_state == ContainerFieldStateSeen) { - field_state = ContainerFieldStateEnd; - first_token = peeked_token; - } - res.decls.append(top_level_comptime); - continue; - } - - TokenIndex first_doc_token = ast_parse_doc_comments(pc); - - peeked_token = peek_token(pc); - - TokenIndex visib_token = eat_token_if(pc, TokenIdKeywordPub); - VisibMod visib_mod = (visib_token != 0) ? VisibModPub : VisibModPrivate; - - AstNode *top_level_decl = ast_parse_top_level_decl(pc, visib_mod, first_doc_token); - if (top_level_decl != nullptr) { - if (field_state == ContainerFieldStateSeen) { - field_state = ContainerFieldStateEnd; - first_token = peeked_token; - } - res.decls.append(top_level_decl); - continue; - } - - if (visib_token != 0) { - ast_error(pc, peek_token(pc), "expected function or variable declaration after pub"); - } - - TokenIndex comptime_token = eat_token_if(pc, TokenIdKeywordCompTime); - - AstNode *container_field = ast_parse_container_field(pc); - if (container_field != nullptr) { - switch (field_state) { - case ContainerFieldStateNone: - field_state = ContainerFieldStateSeen; - break; - case ContainerFieldStateSeen: - break; - case ContainerFieldStateEnd: - ast_error(pc, first_token, "declarations are not allowed between container fields"); - } - - assert(container_field->type == NodeTypeStructField); - container_field->data.struct_field.doc_comments = first_doc_token; - container_field->data.struct_field.comptime_token = comptime_token; - res.fields.append(container_field); - if (eat_token_if(pc, TokenIdComma) != 0) { - continue; - } else { - break; - } - } - - break; - } - return res; -} - -// TestDecl <- KEYWORD_test STRINGLITERALSINGLE? Block -static AstNode *ast_parse_test_decl(ParseContext *pc) { - TokenIndex test = eat_token_if(pc, TokenIdKeywordTest); - if (test == 0) - return nullptr; - - TokenIndex name = eat_token_if(pc, TokenIdStringLiteral); - AstNode *block = ast_expect(pc, ast_parse_block); - AstNode *res = ast_create_node(pc, NodeTypeTestDecl, test); - res->data.test_decl.name = name ? token_buf(pc, name) : nullptr; - res->data.test_decl.body = block; - return res; -} - -// TopLevelComptime <- KEYWORD_comptime BlockExpr -static AstNode *ast_parse_top_level_comptime(ParseContext *pc) { - TokenIndex comptime = eat_token_if(pc, TokenIdKeywordCompTime); - if (comptime == 0) - return nullptr; - - // 1 token lookahead because it could be a comptime struct field - TokenIndex lbrace = peek_token(pc); - if (pc->token_ids[lbrace] != TokenIdLBrace) { - put_back_token(pc); - return nullptr; - } - - AstNode *block = ast_expect(pc, ast_parse_block_expr); - AstNode *res = ast_create_node(pc, NodeTypeCompTime, comptime); - res->data.comptime_expr.expr = block; - return res; -} - -// TopLevelDecl -// <- (KEYWORD_export / KEYWORD_extern STRINGLITERALSINGLE? / (KEYWORD_inline / KEYWORD_noinline))? FnProto (SEMICOLON / Block) -// / (KEYWORD_export / KEYWORD_extern STRINGLITERALSINGLE?)? KEYWORD_threadlocal? VarDecl -// / KEYWORD_use Expr SEMICOLON -static AstNode *ast_parse_top_level_decl(ParseContext *pc, VisibMod visib_mod, - TokenIndex doc_comments) -{ - TokenIndex first = eat_token_if(pc, TokenIdKeywordExport); - if (first == 0) - first = eat_token_if(pc, TokenIdKeywordExtern); - if (first == 0) - first = eat_token_if(pc, TokenIdKeywordInline); - if (first == 0) - first = eat_token_if(pc, TokenIdKeywordNoInline); - if (first != 0) { - TokenIndex lib_name = 0; - if (pc->token_ids[first] == TokenIdKeywordExtern) - lib_name = eat_token_if(pc, TokenIdStringLiteral); - - if (pc->token_ids[first] != TokenIdKeywordNoInline && pc->token_ids[first] != TokenIdKeywordInline) { - TokenIndex thread_local_kw = eat_token_if(pc, TokenIdKeywordThreadLocal); - AstNode *var_decl = ast_parse_var_decl(pc); - if (var_decl != nullptr) { - assert(var_decl->type == NodeTypeVariableDeclaration); - if (pc->token_ids[first] == TokenIdKeywordExtern && var_decl->data.variable_declaration.expr != nullptr) { - ast_error(pc, first, "extern variables have no initializers"); - } - var_decl->main_token = first; - var_decl->data.variable_declaration.threadlocal_tok = thread_local_kw; - var_decl->data.variable_declaration.visib_mod = visib_mod; - var_decl->data.variable_declaration.doc_comments = doc_comments; - var_decl->data.variable_declaration.is_extern = pc->token_ids[first] == TokenIdKeywordExtern; - var_decl->data.variable_declaration.is_export = pc->token_ids[first] == TokenIdKeywordExport; - var_decl->data.variable_declaration.lib_name = token_buf(pc, lib_name); - return var_decl; - } - - if (thread_local_kw != 0) - put_back_token(pc); - } - - AstNode *fn_proto = ast_parse_fn_proto(pc); - if (fn_proto != nullptr) { - AstNode *body = ast_parse_block(pc); - if (body == nullptr) - expect_token(pc, TokenIdSemicolon); - - assert(fn_proto->type == NodeTypeFnProto); - fn_proto->main_token = first; - fn_proto->data.fn_proto.visib_mod = visib_mod; - fn_proto->data.fn_proto.doc_comments = doc_comments; - if (!fn_proto->data.fn_proto.is_extern) - fn_proto->data.fn_proto.is_extern = pc->token_ids[first] == TokenIdKeywordExtern; - fn_proto->data.fn_proto.is_export = pc->token_ids[first] == TokenIdKeywordExport; - switch (pc->token_ids[first]) { - case TokenIdKeywordInline: - fn_proto->data.fn_proto.fn_inline = FnInlineAlways; - break; - case TokenIdKeywordNoInline: - fn_proto->data.fn_proto.fn_inline = FnInlineNever; - break; - default: - fn_proto->data.fn_proto.fn_inline = FnInlineAuto; - break; - } - fn_proto->data.fn_proto.lib_name = token_buf(pc, lib_name); - - AstNode *res = fn_proto; - if (body != nullptr) { - if (fn_proto->data.fn_proto.is_extern) { - ast_error(pc, first, "extern functions have no body"); - } - res = ast_create_node_copy_line_info(pc, NodeTypeFnDef, fn_proto); - res->data.fn_def.fn_proto = fn_proto; - res->data.fn_def.body = body; - fn_proto->data.fn_proto.fn_def_node = res; - } - - return res; - } - - ast_invalid_token_error(pc, peek_token(pc)); - } - - TokenIndex thread_local_kw = eat_token_if(pc, TokenIdKeywordThreadLocal); - AstNode *var_decl = ast_parse_var_decl(pc); - if (var_decl != nullptr) { - assert(var_decl->type == NodeTypeVariableDeclaration); - var_decl->data.variable_declaration.visib_mod = visib_mod; - var_decl->data.variable_declaration.doc_comments = doc_comments; - var_decl->data.variable_declaration.threadlocal_tok = thread_local_kw; - return var_decl; - } - - if (thread_local_kw != 0) - put_back_token(pc); - - AstNode *fn_proto = ast_parse_fn_proto(pc); - if (fn_proto != nullptr) { - AstNode *body = ast_parse_block(pc); - if (body == nullptr) - expect_token(pc, TokenIdSemicolon); - - assert(fn_proto->type == NodeTypeFnProto); - fn_proto->data.fn_proto.visib_mod = visib_mod; - fn_proto->data.fn_proto.doc_comments = doc_comments; - AstNode *res = fn_proto; - if (body != nullptr) { - res = ast_create_node_copy_line_info(pc, NodeTypeFnDef, fn_proto); - res->data.fn_def.fn_proto = fn_proto; - res->data.fn_def.body = body; - fn_proto->data.fn_proto.fn_def_node = res; - } - - return res; - } - - TokenIndex usingnamespace = eat_token_if(pc, TokenIdKeywordUsingNamespace); - if (usingnamespace != 0) { - AstNode *expr = ast_expect(pc, ast_parse_expr); - expect_token(pc, TokenIdSemicolon); - - AstNode *res = ast_create_node(pc, NodeTypeUsingNamespace, usingnamespace); - res->data.using_namespace.visib_mod = visib_mod; - res->data.using_namespace.expr = expr; - return res; - } - - return nullptr; -} - -// FnProto <- KEYWORD_fn IDENTIFIER? LPAREN ParamDeclList RPAREN ByteAlign? LinkSection? EXCLAMATIONMARK? (KEYWORD_anytype / TypeExpr) -static AstNode *ast_parse_fn_proto(ParseContext *pc) { - TokenIndex first = eat_token_if(pc, TokenIdKeywordFn); - if (first == 0) { - return nullptr; - } - - TokenIndex identifier = eat_token_if(pc, TokenIdIdentifier); - expect_token(pc, TokenIdLParen); - ZigList params = ast_parse_list(pc, TokenIdComma, ast_parse_param_decl); - expect_token(pc, TokenIdRParen); - - AstNode *align_expr = ast_parse_byte_align(pc); - AstNode *section_expr = ast_parse_link_section(pc); - AstNode *callconv_expr = ast_parse_callconv(pc); - TokenIndex exmark = 0; - AstNode *return_type = nullptr; - - exmark = eat_token_if(pc, TokenIdBang); - return_type = ast_parse_type_expr(pc); - if (return_type == nullptr) { - TokenIndex next = peek_token(pc); - ast_error( - pc, - next, - "expected return type (use 'void' to return nothing), found: '%s'", - token_name(pc->token_ids[next]) - ); - } - - AstNode *res = ast_create_node(pc, NodeTypeFnProto, first); - res->data.fn_proto = {}; - res->data.fn_proto.name = token_buf(pc, identifier); - res->data.fn_proto.params = params; - res->data.fn_proto.align_expr = align_expr; - res->data.fn_proto.section_expr = section_expr; - res->data.fn_proto.callconv_expr = callconv_expr; - res->data.fn_proto.auto_err_set = exmark != 0; - res->data.fn_proto.return_type = return_type; - - for (size_t i = 0; i < params.length; i++) { - AstNode *param_decl = params.at(i); - assert(param_decl->type == NodeTypeParamDecl); - if (param_decl->data.param_decl.is_var_args) - res->data.fn_proto.is_var_args = true; - if (i != params.length - 1 && res->data.fn_proto.is_var_args) - ast_error(pc, first, "Function prototype have varargs as a none last parameter."); - } - return res; -} - -// VarDecl <- (KEYWORD_const / KEYWORD_var) IDENTIFIER (COLON TypeExpr)? ByteAlign? LinkSection? (EQUAL Expr)? SEMICOLON -static AstNode *ast_parse_var_decl(ParseContext *pc) { - TokenIndex mut_kw = eat_token_if(pc, TokenIdKeywordConst); - if (mut_kw == 0) - mut_kw = eat_token_if(pc, TokenIdKeywordVar); - if (mut_kw == 0) - return nullptr; - - TokenIndex identifier = expect_token(pc, TokenIdIdentifier); - AstNode *type_expr = nullptr; - if (eat_token_if(pc, TokenIdColon) != 0) - type_expr = ast_expect(pc, ast_parse_type_expr); - - AstNode *align_expr = ast_parse_byte_align(pc); - AstNode *section_expr = ast_parse_link_section(pc); - AstNode *expr = nullptr; - if (eat_token_if(pc, TokenIdEq) != 0) - expr = ast_expect(pc, ast_parse_expr); - - expect_token(pc, TokenIdSemicolon); - - AstNode *res = ast_create_node(pc, NodeTypeVariableDeclaration, mut_kw); - res->data.variable_declaration.is_const = pc->token_ids[mut_kw] == TokenIdKeywordConst; - res->data.variable_declaration.symbol = token_buf(pc, identifier); - res->data.variable_declaration.type = type_expr; - res->data.variable_declaration.align_expr = align_expr; - res->data.variable_declaration.section_expr = section_expr; - res->data.variable_declaration.expr = expr; - return res; -} - -// ContainerField <- KEYWORD_comptime? IDENTIFIER (COLON TypeExpr ByteAlign?)? (EQUAL Expr)? -static AstNode *ast_parse_container_field(ParseContext *pc) { - TokenIndex identifier = eat_token_if(pc, TokenIdIdentifier); - if (identifier == 0) - return nullptr; - - AstNode *type_expr = nullptr; - if (eat_token_if(pc, TokenIdColon) != 0) { - TokenIndex anytype_tok = eat_token_if(pc, TokenIdKeywordAnyType); - if (anytype_tok != 0) { - type_expr = ast_create_node(pc, NodeTypeAnyTypeField, anytype_tok); - } else { - type_expr = ast_expect(pc, ast_parse_type_expr); - } - } - AstNode *align_expr = ast_parse_byte_align(pc); - AstNode *expr = nullptr; - if (eat_token_if(pc, TokenIdEq) != 0) - expr = ast_expect(pc, ast_parse_expr); - - AstNode *res = ast_create_node(pc, NodeTypeStructField, identifier); - res->data.struct_field.name = token_buf(pc, identifier); - res->data.struct_field.type = type_expr; - res->data.struct_field.value = expr; - res->data.struct_field.align_expr = align_expr; - return res; -} - -// Statement -// <- KEYWORD_comptime? VarDecl -// / KEYWORD_comptime BlockExprStatement -// / KEYWORD_nosuspend BlockExprStatement -// / KEYWORD_suspend (SEMICOLON / BlockExprStatement) -// / KEYWORD_defer BlockExprStatement -// / KEYWORD_errdefer Payload? BlockExprStatement -// / IfStatement -// / LabeledStatement -// / SwitchExpr -// / AssignExpr SEMICOLON -static AstNode *ast_parse_statement(ParseContext *pc) { - TokenIndex comptime = eat_token_if(pc, TokenIdKeywordCompTime); - AstNode *var_decl = ast_parse_var_decl(pc); - if (var_decl != nullptr) { - assert(var_decl->type == NodeTypeVariableDeclaration); - var_decl->data.variable_declaration.is_comptime = comptime != 0; - return var_decl; - } - - if (comptime != 0) { - AstNode *statement = ast_expect(pc, ast_parse_block_expr_statement); - AstNode *res = ast_create_node(pc, NodeTypeCompTime, comptime); - res->data.comptime_expr.expr = statement; - return res; - } - - TokenIndex nosuspend = eat_token_if(pc, TokenIdKeywordNoSuspend); - if (nosuspend != 0) { - AstNode *statement = ast_expect(pc, ast_parse_block_expr_statement); - AstNode *res = ast_create_node(pc, NodeTypeNoSuspend, nosuspend); - res->data.nosuspend_expr.expr = statement; - return res; - } - - TokenIndex suspend = eat_token_if(pc, TokenIdKeywordSuspend); - if (suspend != 0) { - AstNode *statement = ast_expect(pc, ast_parse_block_expr_statement); - AstNode *res = ast_create_node(pc, NodeTypeSuspend, suspend); - res->data.suspend.block = statement; - return res; - } - - TokenIndex defer = eat_token_if(pc, TokenIdKeywordDefer); - if (defer == 0) - defer = eat_token_if(pc, TokenIdKeywordErrdefer); - if (defer != 0) { - TokenIndex payload = (pc->token_ids[defer] == TokenIdKeywordErrdefer) ? - ast_parse_payload(pc) : 0; - AstNode *statement = ast_expect(pc, ast_parse_block_expr_statement); - AstNode *res = ast_create_node(pc, NodeTypeDefer, defer); - - res->data.defer.kind = ReturnKindUnconditional; - res->data.defer.expr = statement; - if (pc->token_ids[defer] == TokenIdKeywordErrdefer) { - res->data.defer.kind = ReturnKindError; - if (payload != 0) - res->data.defer.err_payload = token_identifier(pc, payload); - } - return res; - } - - AstNode *if_statement = ast_parse_if_statement(pc); - if (if_statement != nullptr) - return if_statement; - - AstNode *labeled_statement = ast_parse_labeled_statement(pc); - if (labeled_statement != nullptr) - return labeled_statement; - - AstNode *switch_expr = ast_parse_switch_expr(pc); - if (switch_expr != nullptr) - return switch_expr; - - AstNode *assign = ast_parse_assign_expr(pc); - if (assign != nullptr) { - expect_token(pc, TokenIdSemicolon); - return assign; - } - - return nullptr; -} - -// IfStatement -// <- IfPrefix BlockExpr ( KEYWORD_else Payload? Statement )? -// / IfPrefix AssignExpr ( SEMICOLON / KEYWORD_else Payload? Statement ) -static AstNode *ast_parse_if_statement(ParseContext *pc) { - AstNode *res = ast_parse_if_prefix(pc); - if (res == nullptr) - return nullptr; - - AstNode *body = ast_parse_block_expr(pc); - bool requires_semi = false; - if (body == nullptr) { - requires_semi = true; - body = ast_parse_assign_expr(pc); - } - - if (body == nullptr) { - TokenIndex tok = eat_token(pc); - ast_error(pc, tok, "expected if body, found '%s'", token_name(pc->token_ids[tok])); - } - - TokenIndex err_payload = 0; - AstNode *else_body = nullptr; - if (eat_token_if(pc, TokenIdKeywordElse) != 0) { - err_payload = ast_parse_payload(pc); - else_body = ast_expect(pc, ast_parse_statement); - } - - if (requires_semi && else_body == nullptr) - expect_token(pc, TokenIdSemicolon); - - assert(res->type == NodeTypeIfOptional); - if (err_payload != 0) { - AstNodeTestExpr old = res->data.test_expr; - res->type = NodeTypeIfErrorExpr; - res->data.if_err_expr.target_node = old.target_node; - res->data.if_err_expr.var_is_ptr = old.var_is_ptr; - res->data.if_err_expr.var_symbol = old.var_symbol; - res->data.if_err_expr.then_node = body; - res->data.if_err_expr.err_symbol = token_buf(pc, err_payload); - res->data.if_err_expr.else_node = else_body; - return res; - } - - if (res->data.test_expr.var_symbol != nullptr) { - res->data.test_expr.then_node = body; - res->data.test_expr.else_node = else_body; - return res; - } - - AstNodeTestExpr old = res->data.test_expr; - res->type = NodeTypeIfBoolExpr; - res->data.if_bool_expr.condition = old.target_node; - res->data.if_bool_expr.then_block = body; - res->data.if_bool_expr.else_node = else_body; - return res; -} - -// LabeledStatement <- BlockLabel? (Block / LoopStatement) -static AstNode *ast_parse_labeled_statement(ParseContext *pc) { - TokenIndex label = ast_parse_block_label(pc); - AstNode *block = ast_parse_block(pc); - if (block != nullptr) { - assert(block->type == NodeTypeBlock); - block->data.block.name = token_buf(pc, label); - return block; - } - - AstNode *loop = ast_parse_loop_statement(pc); - if (loop != nullptr) { - switch (loop->type) { - case NodeTypeForExpr: - loop->data.for_expr.name = token_buf(pc, label); - break; - case NodeTypeWhileExpr: - loop->data.while_expr.name = token_buf(pc, label); - break; - default: - zig_unreachable(); - } - return loop; - } - - if (label != 0) - ast_invalid_token_error(pc, peek_token(pc)); - return nullptr; -} - -// LoopStatement <- KEYWORD_inline? (ForStatement / WhileStatement) -static AstNode *ast_parse_loop_statement(ParseContext *pc) { - TokenIndex inline_token = eat_token_if(pc, TokenIdKeywordInline); - AstNode *for_statement = ast_parse_for_statement(pc); - if (for_statement != nullptr) { - assert(for_statement->type == NodeTypeForExpr); - for_statement->data.for_expr.is_inline = inline_token != 0; - return for_statement; - } - - AstNode *while_statement = ast_parse_while_statement(pc); - if (while_statement != nullptr) { - assert(while_statement->type == NodeTypeWhileExpr); - while_statement->data.while_expr.is_inline = inline_token != 0; - return while_statement; - } - - if (inline_token != 0) - ast_invalid_token_error(pc, peek_token(pc)); - return nullptr; -} - -// ForStatement -// <- ForPrefix BlockExpr ( KEYWORD_else Statement )? -// / ForPrefix AssignExpr ( SEMICOLON / KEYWORD_else Statement ) -static AstNode *ast_parse_for_statement(ParseContext *pc) { - AstNode *res = ast_parse_for_prefix(pc); - if (res == nullptr) - return nullptr; - - AstNode *body = ast_parse_block_expr(pc); - bool requires_semi = false; - if (body == nullptr) { - requires_semi = true; - body = ast_parse_assign_expr(pc); - } - - if (body == nullptr) { - TokenIndex tok = eat_token(pc); - ast_error(pc, tok, "expected loop body, found '%s'", token_name(pc->token_ids[tok])); - } - - AstNode *else_body = nullptr; - if (eat_token_if(pc, TokenIdKeywordElse) != 0) { - else_body = ast_expect(pc, ast_parse_statement); - } - - if (requires_semi && else_body == nullptr) - expect_token(pc, TokenIdSemicolon); - - assert(res->type == NodeTypeForExpr); - res->data.for_expr.body = body; - res->data.for_expr.else_node = else_body; - return res; -} - -// WhileStatement -// <- WhilePrefix BlockExpr ( KEYWORD_else Payload? Statement )? -// / WhilePrefix AssignExpr ( SEMICOLON / KEYWORD_else Payload? Statement ) -static AstNode *ast_parse_while_statement(ParseContext *pc) { - AstNode *res = ast_parse_while_prefix(pc); - if (res == nullptr) - return nullptr; - - AstNode *body = ast_parse_block_expr(pc); - bool requires_semi = false; - if (body == nullptr) { - requires_semi = true; - body = ast_parse_assign_expr(pc); - } - - if (body == nullptr) { - TokenIndex tok = eat_token(pc); - ast_error(pc, tok, "expected loop body, found '%s'", token_name(pc->token_ids[tok])); - } - - TokenIndex err_payload = 0; - AstNode *else_body = nullptr; - if (eat_token_if(pc, TokenIdKeywordElse) != 0) { - err_payload = ast_parse_payload(pc); - else_body = ast_expect(pc, ast_parse_statement); - } - - if (requires_semi && else_body == nullptr) - expect_token(pc, TokenIdSemicolon); - - assert(res->type == NodeTypeWhileExpr); - res->data.while_expr.body = body; - res->data.while_expr.err_symbol = token_buf(pc, err_payload); - res->data.while_expr.else_node = else_body; - return res; -} - - -// BlockExprStatement -// <- BlockExpr -// / AssignExpr SEMICOLON -static AstNode *ast_parse_block_expr_statement(ParseContext *pc) { - AstNode *block = ast_parse_block_expr(pc); - if (block != nullptr) - return block; - - AstNode *assign_expr = ast_parse_assign_expr(pc); - if (assign_expr != nullptr) { - expect_token(pc, TokenIdSemicolon); - return assign_expr; - } - - return nullptr; -} - -// BlockExpr <- BlockLabel? Block -static AstNode *ast_parse_block_expr(ParseContext *pc) { - TokenIndex label = ast_parse_block_label(pc); - if (label != 0) { - AstNode *res = ast_expect(pc, ast_parse_block); - assert(res->type == NodeTypeBlock); - res->data.block.name = token_buf(pc, label); - return res; - } - - return ast_parse_block(pc); -} - -// AssignExpr <- Expr (AssignOp Expr)? -static AstNode *ast_parse_assign_expr(ParseContext *pc) { - return ast_parse_bin_op_expr(pc, BinOpChainOnce, ast_parse_assign_op, ast_parse_expr); -} - -// Expr <- KEYWORD_try* BoolOrExpr -static AstNode *ast_parse_expr(ParseContext *pc) { - return ast_parse_prefix_op_expr( - pc, - [](ParseContext *context) { - TokenIndex try_token = eat_token_if(context, TokenIdKeywordTry); - if (try_token != 0) { - AstNode *res = ast_create_node(context, NodeTypeReturnExpr, try_token); - res->data.return_expr.kind = ReturnKindError; - return res; - } - - return (AstNode*)nullptr; - }, - ast_parse_bool_or_expr - ); -} - -// BoolOrExpr <- BoolAndExpr (KEYWORD_or BoolAndExpr)* -static AstNode *ast_parse_bool_or_expr(ParseContext *pc) { - return ast_parse_bin_op_expr( - pc, - BinOpChainInf, - ast_parse_bin_op_simple, - ast_parse_bool_and_expr - ); -} - -// BoolAndExpr <- CompareExpr (KEYWORD_and CompareExpr)* -static AstNode *ast_parse_bool_and_expr(ParseContext *pc) { - return ast_parse_bin_op_expr( - pc, - BinOpChainInf, - ast_parse_bin_op_simple, - ast_parse_compare_expr - ); -} - -// CompareExpr <- BitwiseExpr (CompareOp BitwiseExpr)? -static AstNode *ast_parse_compare_expr(ParseContext *pc) { - return ast_parse_bin_op_expr(pc, BinOpChainOnce, ast_parse_compare_op, ast_parse_bitwise_expr); -} - -// BitwiseExpr <- BitShiftExpr (BitwiseOp BitShiftExpr)* -static AstNode *ast_parse_bitwise_expr(ParseContext *pc) { - return ast_parse_bin_op_expr(pc, BinOpChainInf, ast_parse_bitwise_op, ast_parse_bit_shift_expr); -} - -// BitShiftExpr <- AdditionExpr (BitShiftOp AdditionExpr)* -static AstNode *ast_parse_bit_shift_expr(ParseContext *pc) { - return ast_parse_bin_op_expr(pc, BinOpChainInf, ast_parse_bit_shift_op, ast_parse_addition_expr); -} - -// AdditionExpr <- MultiplyExpr (AdditionOp MultiplyExpr)* -static AstNode *ast_parse_addition_expr(ParseContext *pc) { - return ast_parse_bin_op_expr(pc, BinOpChainInf, ast_parse_addition_op, ast_parse_multiply_expr); -} - -// MultiplyExpr <- PrefixExpr (MultiplyOp PrefixExpr)* -static AstNode *ast_parse_multiply_expr(ParseContext *pc) { - return ast_parse_bin_op_expr(pc, BinOpChainInf, ast_parse_multiply_op, ast_parse_prefix_expr); -} - -// PrefixExpr <- PrefixOp* PrimaryExpr -static AstNode *ast_parse_prefix_expr(ParseContext *pc) { - return ast_parse_prefix_op_expr( - pc, - ast_parse_prefix_op, - ast_parse_primary_expr - ); -} - -// PrimaryExpr -// <- AsmExpr -// / IfExpr -// / KEYWORD_break BreakLabel? Expr? -// / KEYWORD_comptime Expr -// / KEYWORD_nosuspend Expr -// / KEYWORD_continue BreakLabel? -// / KEYWORD_resume Expr -// / KEYWORD_return Expr? -// / BlockLabel? LoopExpr -// / Block -// / CurlySuffixExpr -static AstNode *ast_parse_primary_expr(ParseContext *pc) { - AstNode *asm_expr = ast_parse_asm_expr(pc); - if (asm_expr != nullptr) - return asm_expr; - - AstNode *if_expr = ast_parse_if_expr(pc); - if (if_expr != nullptr) - return if_expr; - - TokenIndex break_token = eat_token_if(pc, TokenIdKeywordBreak); - if (break_token != 0) { - TokenIndex label = ast_parse_break_label(pc); - AstNode *expr = ast_parse_expr(pc); - - AstNode *res = ast_create_node(pc, NodeTypeBreak, break_token); - res->data.break_expr.name = token_buf(pc, label); - res->data.break_expr.expr = expr; - return res; - } - - TokenIndex comptime = eat_token_if(pc, TokenIdKeywordCompTime); - if (comptime != 0) { - AstNode *expr = ast_expect(pc, ast_parse_expr); - AstNode *res = ast_create_node(pc, NodeTypeCompTime, comptime); - res->data.comptime_expr.expr = expr; - return res; - } - - TokenIndex nosuspend = eat_token_if(pc, TokenIdKeywordNoSuspend); - if (nosuspend != 0) { - AstNode *expr = ast_expect(pc, ast_parse_expr); - AstNode *res = ast_create_node(pc, NodeTypeNoSuspend, nosuspend); - res->data.nosuspend_expr.expr = expr; - return res; - } - - TokenIndex continue_token = eat_token_if(pc, TokenIdKeywordContinue); - if (continue_token != 0) { - TokenIndex label = ast_parse_break_label(pc); - AstNode *res = ast_create_node(pc, NodeTypeContinue, continue_token); - res->data.continue_expr.name = token_buf(pc, label); - return res; - } - - TokenIndex resume = eat_token_if(pc, TokenIdKeywordResume); - if (resume != 0) { - AstNode *expr = ast_expect(pc, ast_parse_expr); - AstNode *res = ast_create_node(pc, NodeTypeResume, resume); - res->data.resume_expr.expr = expr; - return res; - } - - TokenIndex return_token = eat_token_if(pc, TokenIdKeywordReturn); - if (return_token != 0) { - AstNode *expr = ast_parse_expr(pc); - AstNode *res = ast_create_node(pc, NodeTypeReturnExpr, return_token); - res->data.return_expr.expr = expr; - return res; - } - - TokenIndex label = ast_parse_block_label(pc); - AstNode *loop = ast_parse_loop_expr(pc); - if (loop != nullptr) { - switch (loop->type) { - case NodeTypeForExpr: - loop->data.for_expr.name = token_buf(pc, label); - break; - case NodeTypeWhileExpr: - loop->data.while_expr.name = token_buf(pc, label); - break; - default: - zig_unreachable(); - } - return loop; - } else if (label != 0) { - // Restore the tokens that we eaten by ast_parse_block_label. - put_back_token(pc); - put_back_token(pc); - } - - AstNode *block = ast_parse_block(pc); - if (block != nullptr) - return block; - - AstNode *curly_suffix = ast_parse_curly_suffix_expr(pc); - if (curly_suffix != nullptr) - return curly_suffix; - - return nullptr; -} - -// IfExpr <- IfPrefix Expr (KEYWORD_else Payload? Expr)? -static AstNode *ast_parse_if_expr(ParseContext *pc) { - return ast_parse_if_expr_helper(pc, ast_parse_expr); -} - -// Block <- LBRACE Statement* RBRACE -static AstNode *ast_parse_block(ParseContext *pc) { - TokenIndex lbrace = eat_token_if(pc, TokenIdLBrace); - if (lbrace == 0) - return nullptr; - - ZigList statements = {}; - AstNode *statement; - while ((statement = ast_parse_statement(pc)) != nullptr) - statements.append(statement); - - expect_token(pc, TokenIdRBrace); - - AstNode *res = ast_create_node(pc, NodeTypeBlock, lbrace); - res->data.block.statements = statements; - return res; -} - -// LoopExpr <- KEYWORD_inline? (ForExpr / WhileExpr) -static AstNode *ast_parse_loop_expr(ParseContext *pc) { - return ast_parse_loop_expr_helper( - pc, - ast_parse_for_expr, - ast_parse_while_expr - ); -} - -// ForExpr <- ForPrefix Expr (KEYWORD_else Expr)? -static AstNode *ast_parse_for_expr(ParseContext *pc) { - return ast_parse_for_expr_helper(pc, ast_parse_expr); -} - -// WhileExpr <- WhilePrefix Expr (KEYWORD_else Payload? Expr)? -static AstNode *ast_parse_while_expr(ParseContext *pc) { - return ast_parse_while_expr_helper(pc, ast_parse_expr); -} - -// CurlySuffixExpr <- TypeExpr InitList? -static AstNode *ast_parse_curly_suffix_expr(ParseContext *pc) { - AstNode *type_expr = ast_parse_type_expr(pc); - if (type_expr == nullptr) - return nullptr; - - AstNode *res = ast_parse_init_list(pc); - if (res == nullptr) - return type_expr; - - assert(res->type == NodeTypeContainerInitExpr); - res->data.container_init_expr.type = type_expr; - return res; -} - -// InitList -// <- LBRACE FieldInit (COMMA FieldInit)* COMMA? RBRACE -// / LBRACE Expr (COMMA Expr)* COMMA? RBRACE -// / LBRACE RBRACE -static AstNode *ast_parse_init_list(ParseContext *pc) { - TokenIndex lbrace = eat_token_if(pc, TokenIdLBrace); - if (lbrace == 0) - return nullptr; - - AstNode *first = ast_parse_field_init(pc); - if (first != nullptr) { - AstNode *res = ast_create_node(pc, NodeTypeContainerInitExpr, lbrace); - res->data.container_init_expr.kind = ContainerInitKindStruct; - res->data.container_init_expr.entries.append(first); - - while (eat_token_if(pc, TokenIdComma) != 0) { - AstNode *field_init = ast_parse_field_init(pc); - if (field_init == nullptr) - break; - res->data.container_init_expr.entries.append(field_init); - } - - expect_token(pc, TokenIdRBrace); - return res; - } - - AstNode *res = ast_create_node(pc, NodeTypeContainerInitExpr, lbrace); - res->data.container_init_expr.kind = ContainerInitKindArray; - - first = ast_parse_expr(pc); - if (first != nullptr) { - res->data.container_init_expr.entries.append(first); - - while (eat_token_if(pc, TokenIdComma) != 0) { - AstNode *expr = ast_parse_expr(pc); - if (expr == nullptr) - break; - res->data.container_init_expr.entries.append(expr); - } - - expect_token(pc, TokenIdRBrace); - return res; - } - - expect_token(pc, TokenIdRBrace); - return res; -} - -// TypeExpr <- PrefixTypeOp* ErrorUnionExpr -static AstNode *ast_parse_type_expr(ParseContext *pc) { - return ast_parse_prefix_op_expr( - pc, - ast_parse_prefix_type_op, - ast_parse_error_union_expr - ); -} - -// ErrorUnionExpr <- SuffixExpr (EXCLAMATIONMARK TypeExpr)? -static AstNode *ast_parse_error_union_expr(ParseContext *pc) { - AstNode *res = ast_parse_suffix_expr(pc); - if (res == nullptr) - return nullptr; - - AstNode *op = ast_parse_bin_op_simple(pc); - if (op == nullptr) - return res; - - AstNode *right = ast_expect(pc, ast_parse_type_expr); - assert(op->type == NodeTypeBinOpExpr); - op->data.bin_op_expr.op1 = res; - op->data.bin_op_expr.op2 = right; - return op; -} - -// SuffixExpr -// <- KEYWORD_async PrimaryTypeExpr SuffixOp* FnCallArguments -// / PrimaryTypeExpr (SuffixOp / FnCallArguments)* -static AstNode *ast_parse_suffix_expr(ParseContext *pc) { - TokenIndex async_token = eat_token_if(pc, TokenIdKeywordAsync); - if (async_token) { - AstNode *child = ast_expect(pc, ast_parse_primary_type_expr); - while (true) { - AstNode *suffix = ast_parse_suffix_op(pc); - if (suffix == nullptr) - break; - - switch (suffix->type) { - case NodeTypeSliceExpr: - suffix->data.slice_expr.array_ref_expr = child; - break; - case NodeTypeArrayAccessExpr: - suffix->data.array_access_expr.array_ref_expr = child; - break; - case NodeTypeFieldAccessExpr: - suffix->data.field_access_expr.struct_expr = child; - break; - case NodeTypeUnwrapOptional: - suffix->data.unwrap_optional.expr = child; - break; - case NodeTypePtrDeref: - suffix->data.ptr_deref_expr.target = child; - break; - default: - zig_unreachable(); - } - child = suffix; - } - - // TODO: Both *_async_prefix and *_fn_call_arguments returns an - // AstNode *. All we really want here is the arguments of - // the call we parse. We therefor "leak" the node for now. - // Wait till we get async rework to fix this. - AstNode *args = ast_parse_fn_call_arguments(pc); - if (args == nullptr) - ast_invalid_token_error(pc, peek_token(pc)); - - assert(args->type == NodeTypeFnCallExpr); - - AstNode *res = ast_create_node(pc, NodeTypeFnCallExpr, async_token); - res->data.fn_call_expr.modifier = CallModifierAsync; - res->data.fn_call_expr.seen = false; - res->data.fn_call_expr.fn_ref_expr = child; - res->data.fn_call_expr.params = args->data.fn_call_expr.params; - return res; - } - - AstNode *res = ast_parse_primary_type_expr(pc); - if (res == nullptr) - return nullptr; - - while (true) { - AstNode *suffix = ast_parse_suffix_op(pc); - if (suffix != nullptr) { - switch (suffix->type) { - case NodeTypeSliceExpr: - suffix->data.slice_expr.array_ref_expr = res; - break; - case NodeTypeArrayAccessExpr: - suffix->data.array_access_expr.array_ref_expr = res; - break; - case NodeTypeFieldAccessExpr: - suffix->data.field_access_expr.struct_expr = res; - break; - case NodeTypeUnwrapOptional: - suffix->data.unwrap_optional.expr = res; - break; - case NodeTypePtrDeref: - suffix->data.ptr_deref_expr.target = res; - break; - default: - zig_unreachable(); - } - res = suffix; - continue; - } - - AstNode * call = ast_parse_fn_call_arguments(pc); - if (call != nullptr) { - assert(call->type == NodeTypeFnCallExpr); - call->data.fn_call_expr.fn_ref_expr = res; - res = call; - continue; - } - - break; - } - - return res; - -} - -// PrimaryTypeExpr -// <- BUILTINIDENTIFIER FnCallArguments -// / CHAR_LITERAL -// / ContainerDecl -// / DOT IDENTIFIER -// / ErrorSetDecl -// / FLOAT -// / FnProto -// / GroupedExpr -// / LabeledTypeExpr -// / IDENTIFIER -// / IfTypeExpr -// / INTEGER -// / KEYWORD_comptime TypeExpr -// / KEYWORD_error DOT IDENTIFIER -// / KEYWORD_promise -// / KEYWORD_unreachable -// / STRINGLITERAL -// / SwitchExpr -static AstNode *ast_parse_primary_type_expr(ParseContext *pc) { - TokenIndex builtin_tok = eat_token_if(pc, TokenIdBuiltin); - if (builtin_tok != 0) { - AstNode *res = ast_expect(pc, ast_parse_fn_call_arguments); - AstNode *name_sym = ast_create_node(pc, NodeTypeIdentifier, builtin_tok); - - assert(res->type == NodeTypeFnCallExpr); - res->main_token = builtin_tok; - res->data.fn_call_expr.fn_ref_expr = name_sym; - res->data.fn_call_expr.modifier = CallModifierBuiltin; - return res; - } - - TokenIndex char_lit = eat_token_if(pc, TokenIdCharLiteral); - if (char_lit != 0) { - return ast_create_node(pc, NodeTypeCharLiteral, char_lit); - } - - AstNode *container_decl = ast_parse_container_decl(pc); - if (container_decl != nullptr) - return container_decl; - - AstNode *anon_lit = ast_parse_anon_lit(pc); - if (anon_lit != nullptr) - return anon_lit; - - AstNode *error_set_decl = ast_parse_error_set_decl(pc); - if (error_set_decl != nullptr) - return error_set_decl; - - TokenIndex float_lit = eat_token_if(pc, TokenIdFloatLiteral); - if (float_lit != 0) { - return ast_create_node(pc, NodeTypeFloatLiteral, float_lit); - } - - AstNode *fn_proto = ast_parse_fn_proto(pc); - if (fn_proto != nullptr) - return fn_proto; - - AstNode *grouped_expr = ast_parse_grouped_expr(pc); - if (grouped_expr != nullptr) - return grouped_expr; - - AstNode *labeled_type_expr = ast_parse_labeled_type_expr(pc); - if (labeled_type_expr != nullptr) - return labeled_type_expr; - - TokenIndex identifier = eat_token_if(pc, TokenIdIdentifier); - if (identifier != 0) - return token_identifier(pc, identifier); - - AstNode *if_type_expr = ast_parse_if_type_expr(pc); - if (if_type_expr != nullptr) - return if_type_expr; - - TokenIndex int_lit = eat_token_if(pc, TokenIdIntLiteral); - if (int_lit != 0) { - return ast_create_node(pc, NodeTypeIntLiteral, int_lit); - } - - TokenIndex comptime = eat_token_if(pc, TokenIdKeywordCompTime); - if (comptime != 0) { - AstNode *expr = ast_expect(pc, ast_parse_type_expr); - AstNode *res = ast_create_node(pc, NodeTypeCompTime, comptime); - res->data.comptime_expr.expr = expr; - return res; - } - - TokenIndex error = eat_token_if(pc, TokenIdKeywordError); - if (error != 0) { - TokenIndex dot = expect_token(pc, TokenIdDot); - TokenIndex name = expect_token(pc, TokenIdIdentifier); - AstNode *left = ast_create_node(pc, NodeTypeErrorType, error); - AstNode *res = ast_create_node(pc, NodeTypeFieldAccessExpr, dot); - res->data.field_access_expr.struct_expr = left; - res->data.field_access_expr.field_name = token_buf(pc, name); - return res; - } - - TokenIndex anyframe = eat_token_if(pc, TokenIdKeywordAnyFrame); - if (anyframe != 0) - return ast_create_node(pc, NodeTypeAnyFrameType, anyframe); - - TokenIndex unreachable = eat_token_if(pc, TokenIdKeywordUnreachable); - if (unreachable != 0) - return ast_create_node(pc, NodeTypeUnreachable, unreachable); - - - TokenIndex string_lit = eat_token_if(pc, TokenIdStringLiteral); - if (string_lit != 0) { - return ast_create_node(pc, NodeTypeStringLiteral, string_lit); - } - - TokenIndex multiline_str_lit = ast_parse_multi_tok(pc, TokenIdMultilineStringLiteralLine); - if (multiline_str_lit != 0) { - return ast_create_node(pc, NodeTypeStringLiteral, multiline_str_lit); - } - - AstNode *switch_expr = ast_parse_switch_expr(pc); - if (switch_expr != nullptr) - return switch_expr; - - return nullptr; -} - -// ContainerDecl <- (KEYWORD_extern / KEYWORD_packed)? ContainerDeclAuto -static AstNode *ast_parse_container_decl(ParseContext *pc) { - TokenIndex layout_token = eat_token_if(pc, TokenIdKeywordExtern); - if (layout_token == 0) - layout_token = eat_token_if(pc, TokenIdKeywordPacked); - - AstNode *res = ast_parse_container_decl_auto(pc); - if (res == nullptr) { - if (layout_token != 0) - put_back_token(pc); - return nullptr; - } - - assert(res->type == NodeTypeContainerDecl); - if (layout_token != 0) { - res->main_token = layout_token; - res->data.container_decl.layout = pc->token_ids[layout_token] == TokenIdKeywordExtern - ? ContainerLayoutExtern - : ContainerLayoutPacked; - } - return res; -} - -// ErrorSetDecl <- KEYWORD_error LBRACE IdentifierList RBRACE -static AstNode *ast_parse_error_set_decl(ParseContext *pc) { - TokenIndex first = eat_token_if(pc, TokenIdKeywordError); - if (first == 0) - return nullptr; - if (eat_token_if(pc, TokenIdLBrace) == 0) { - put_back_token(pc); - return nullptr; - } - - ZigList decls = ast_parse_list(pc, TokenIdComma, [](ParseContext *context) { - TokenIndex doc_token = ast_parse_doc_comments(context); - TokenIndex ident = eat_token_if(context, TokenIdIdentifier); - if (ident == 0) - return (AstNode*)nullptr; - - AstNode *symbol_node = token_identifier(context, ident); - if (doc_token == 0) - return symbol_node; - - AstNode *field_node = ast_create_node(context, NodeTypeErrorSetField, doc_token); - field_node->data.err_set_field.field_name = symbol_node; - field_node->data.err_set_field.doc_comments = doc_token; - return field_node; - }); - expect_token(pc, TokenIdRBrace); - - AstNode *res = ast_create_node(pc, NodeTypeErrorSetDecl, first); - res->data.err_set_decl.decls = decls; - return res; -} - -// GroupedExpr <- LPAREN Expr RPAREN -static AstNode *ast_parse_grouped_expr(ParseContext *pc) { - TokenIndex lparen = eat_token_if(pc, TokenIdLParen); - if (lparen == 0) - return nullptr; - - AstNode *expr = ast_expect(pc, ast_parse_expr); - expect_token(pc, TokenIdRParen); - - AstNode *res = ast_create_node(pc, NodeTypeGroupedExpr, lparen); - res->data.grouped_expr = expr; - return res; -} - -// IfTypeExpr <- IfPrefix TypeExpr (KEYWORD_else Payload? TypeExpr)? -static AstNode *ast_parse_if_type_expr(ParseContext *pc) { - return ast_parse_if_expr_helper(pc, ast_parse_type_expr); -} - -// LabeledTypeExpr -// <- BlockLabel Block -// / BlockLabel? LoopTypeExpr -static AstNode *ast_parse_labeled_type_expr(ParseContext *pc) { - TokenIndex label = ast_parse_block_label(pc); - if (label != 0) { - AstNode *block = ast_parse_block(pc); - if (block != nullptr) { - assert(block->type == NodeTypeBlock); - block->data.block.name = token_buf(pc, label); - return block; - } - } - - AstNode *loop = ast_parse_loop_type_expr(pc); - if (loop != nullptr) { - switch (loop->type) { - case NodeTypeForExpr: - loop->data.for_expr.name = token_buf(pc, label); - break; - case NodeTypeWhileExpr: - loop->data.while_expr.name = token_buf(pc, label); - break; - default: - zig_unreachable(); - } - return loop; - } - - if (label != 0) { - put_back_token(pc); - put_back_token(pc); - } - return nullptr; -} - -// LoopTypeExpr <- KEYWORD_inline? (ForTypeExpr / WhileTypeExpr) -static AstNode *ast_parse_loop_type_expr(ParseContext *pc) { - return ast_parse_loop_expr_helper( - pc, - ast_parse_for_type_expr, - ast_parse_while_type_expr - ); -} - -// ForTypeExpr <- ForPrefix TypeExpr (KEYWORD_else TypeExpr)? -static AstNode *ast_parse_for_type_expr(ParseContext *pc) { - return ast_parse_for_expr_helper(pc, ast_parse_type_expr); -} - -// WhileTypeExpr <- WhilePrefix TypeExpr (KEYWORD_else Payload? TypeExpr)? -static AstNode *ast_parse_while_type_expr(ParseContext *pc) { - return ast_parse_while_expr_helper(pc, ast_parse_type_expr); -} - -// SwitchExpr <- KEYWORD_switch LPAREN Expr RPAREN LBRACE SwitchProngList RBRACE -static AstNode *ast_parse_switch_expr(ParseContext *pc) { - TokenIndex switch_token = eat_token_if(pc, TokenIdKeywordSwitch); - if (switch_token == 0) - return nullptr; - - expect_token(pc, TokenIdLParen); - AstNode *expr = ast_expect(pc, ast_parse_expr); - expect_token(pc, TokenIdRParen); - expect_token(pc, TokenIdLBrace); - ZigList prongs = ast_parse_list(pc, TokenIdComma, ast_parse_switch_prong); - expect_token(pc, TokenIdRBrace); - - AstNode *res = ast_create_node(pc, NodeTypeSwitchExpr, switch_token); - res->data.switch_expr.expr = expr; - res->data.switch_expr.prongs = prongs; - return res; -} - -// AsmExpr <- KEYWORD_asm KEYWORD_volatile? LPAREN STRINGLITERAL AsmOutput? RPAREN -static AstNode *ast_parse_asm_expr(ParseContext *pc) { - TokenIndex asm_token = eat_token_if(pc, TokenIdKeywordAsm); - if (asm_token == 0) - return nullptr; - - TokenIndex volatile_token = eat_token_if(pc, TokenIdKeywordVolatile); - expect_token(pc, TokenIdLParen); - AstNode *asm_template = ast_expect(pc, ast_parse_expr); - AstNode *res = ast_parse_asm_output(pc); - if (res == nullptr) - res = ast_create_node_no_line_info(pc, NodeTypeAsmExpr); - expect_token(pc, TokenIdRParen); - - res->main_token = asm_token; - res->data.asm_expr.volatile_token = volatile_token; - res->data.asm_expr.asm_template = asm_template; - return res; -} - -static AstNode *ast_parse_anon_lit(ParseContext *pc) { - TokenIndex period = eat_token_if(pc, TokenIdDot); - if (period == 0) - return nullptr; - - // anon enum literal - TokenIndex identifier = eat_token_if(pc, TokenIdIdentifier); - if (identifier != 0) { - return ast_create_node(pc, NodeTypeEnumLiteral, period); - } - - // anon container literal - AstNode *res = ast_parse_init_list(pc); - if (res != nullptr) - return res; - put_back_token(pc); - return nullptr; -} - -// AsmOutput <- COLON AsmOutputList AsmInput? -static AstNode *ast_parse_asm_output(ParseContext *pc) { - if (eat_token_if(pc, TokenIdColon) == 0) - return nullptr; - - ZigList output_list = ast_parse_list(pc, TokenIdComma, ast_parse_asm_output_item); - AstNode *res = ast_parse_asm_input(pc); - if (res == nullptr) - res = ast_create_node_no_line_info(pc, NodeTypeAsmExpr); - - res->data.asm_expr.output_list = output_list; - return res; -} - -// AsmOutputItem <- LBRACKET IDENTIFIER RBRACKET STRINGLITERAL LPAREN (MINUSRARROW TypeExpr / IDENTIFIER) RPAREN -static AsmOutput *ast_parse_asm_output_item(ParseContext *pc) { - if (eat_token_if(pc, TokenIdLBracket) == 0) - return nullptr; - - TokenIndex sym_name = expect_token(pc, TokenIdIdentifier); - expect_token(pc, TokenIdRBracket); - - TokenIndex str = ast_parse_multi_tok(pc, TokenIdMultilineStringLiteralLine); - if (str == 0) - str = expect_token(pc, TokenIdStringLiteral); - expect_token(pc, TokenIdLParen); - - TokenIndex var_name = eat_token_if(pc, TokenIdIdentifier); - AstNode *return_type = nullptr; - if (var_name == 0) { - expect_token(pc, TokenIdArrow); - return_type = ast_expect(pc, ast_parse_type_expr); - } - - expect_token(pc, TokenIdRParen); - - AsmOutput *res = heap::c_allocator.create(); - res->asm_symbolic_name = token_buf(pc, sym_name); - res->constraint = token_buf(pc, str); - res->variable_name = token_buf(pc, var_name); - res->return_type = return_type; - return res; -} - -// AsmInput <- COLON AsmInputList AsmClobbers? -static AstNode *ast_parse_asm_input(ParseContext *pc) { - if (eat_token_if(pc, TokenIdColon) == 0) - return nullptr; - - ZigList input_list = ast_parse_list(pc, TokenIdComma, ast_parse_asm_input_item); - AstNode *res = ast_parse_asm_clobbers(pc); - if (res == nullptr) - res = ast_create_node_no_line_info(pc, NodeTypeAsmExpr); - - res->data.asm_expr.input_list = input_list; - return res; -} - -// AsmInputItem <- LBRACKET IDENTIFIER RBRACKET STRINGLITERAL LPAREN Expr RPAREN -static AsmInput *ast_parse_asm_input_item(ParseContext *pc) { - if (eat_token_if(pc, TokenIdLBracket) == 0) - return nullptr; - - TokenIndex sym_name = expect_token(pc, TokenIdIdentifier); - expect_token(pc, TokenIdRBracket); - - TokenIndex constraint = expect_token(pc, TokenIdStringLiteral); - expect_token(pc, TokenIdLParen); - AstNode *expr = ast_expect(pc, ast_parse_expr); - expect_token(pc, TokenIdRParen); - - AsmInput *res = heap::c_allocator.create(); - res->asm_symbolic_name = token_buf(pc, sym_name); - res->constraint = token_buf(pc, constraint); - res->expr = expr; - return res; -} - -// AsmClobbers <- COLON StringList -static AstNode *ast_parse_asm_clobbers(ParseContext *pc) { - if (eat_token_if(pc, TokenIdColon) == 0) - return nullptr; - - ZigList clobber_list = ast_parse_list(pc, TokenIdComma, [](ParseContext *context) { - TokenIndex str = eat_token_if(context, TokenIdStringLiteral); - if (str == 0) - str = ast_parse_multi_tok(context, TokenIdMultilineStringLiteralLine); - if (str != 0) - return token_buf(context, str); - return (Buf*)nullptr; - }); - - AstNode *res = ast_create_node_no_line_info(pc, NodeTypeAsmExpr); - res->data.asm_expr.clobber_list = clobber_list; - return res; -} - -// BreakLabel <- COLON IDENTIFIER -static TokenIndex ast_parse_break_label(ParseContext *pc) { - if (eat_token_if(pc, TokenIdColon) == 0) - return 0; - - return expect_token(pc, TokenIdIdentifier); -} - -// BlockLabel <- IDENTIFIER COLON -static TokenIndex ast_parse_block_label(ParseContext *pc) { - TokenIndex ident = eat_token_if(pc, TokenIdIdentifier); - if (ident == 0) - return 0; - - // We do 2 token lookahead here, as we don't want to error when - // parsing identifiers. - if (eat_token_if(pc, TokenIdColon) == 0) { - put_back_token(pc); - return 0; - } - - return ident; -} - -// FieldInit <- DOT IDENTIFIER EQUAL Expr -static AstNode *ast_parse_field_init(ParseContext *pc) { - TokenIndex first = eat_token_if(pc, TokenIdDot); - if (first == 0) - return nullptr; - - TokenIndex name = eat_token_if(pc, TokenIdIdentifier); - if (name == 0) { - // Because of anon literals ".{" is also valid. - put_back_token(pc); - return nullptr; - } - if (eat_token_if(pc, TokenIdEq) == 0) { - // Because ".Name" can also be interpreted as an enum literal, we should put back - // those two tokens again so that the parser can try to parse them as the enum - // literal later. - put_back_token(pc); - put_back_token(pc); - return nullptr; - } - AstNode *expr = ast_expect(pc, ast_parse_expr); - - AstNode *res = ast_create_node(pc, NodeTypeStructValueField, first); - res->data.struct_val_field.name = token_buf(pc, name); - res->data.struct_val_field.expr = expr; - return res; -} - -// WhileContinueExpr <- COLON LPAREN AssignExpr RPAREN -static AstNode *ast_parse_while_continue_expr(ParseContext *pc) { - TokenIndex first = eat_token_if(pc, TokenIdColon); - if (first == 0) - return nullptr; - - expect_token(pc, TokenIdLParen); - AstNode *expr = ast_expect(pc, ast_parse_assign_expr); - expect_token(pc, TokenIdRParen); - return expr; -} - -// LinkSection <- KEYWORD_linksection LPAREN Expr RPAREN -static AstNode *ast_parse_link_section(ParseContext *pc) { - TokenIndex first = eat_token_if(pc, TokenIdKeywordLinkSection); - if (first == 0) - return nullptr; - - expect_token(pc, TokenIdLParen); - AstNode *res = ast_expect(pc, ast_parse_expr); - expect_token(pc, TokenIdRParen); - return res; -} - -// CallConv <- KEYWORD_callconv LPAREN Expr RPAREN -static AstNode *ast_parse_callconv(ParseContext *pc) { - TokenIndex first = eat_token_if(pc, TokenIdKeywordCallconv); - if (first == 0) - return nullptr; - - expect_token(pc, TokenIdLParen); - AstNode *res = ast_expect(pc, ast_parse_expr); - expect_token(pc, TokenIdRParen); - return res; -} - -// ParamDecl <- (KEYWORD_noalias / KEYWORD_comptime)? (IDENTIFIER COLON)? ParamType -static AstNode *ast_parse_param_decl(ParseContext *pc) { - TokenIndex first_doc_comment = ast_parse_doc_comments(pc); - - TokenIndex first = eat_token_if(pc, TokenIdKeywordNoAlias); - if (first == 0) - first = eat_token_if(pc, TokenIdKeywordCompTime); - - TokenIndex name = eat_token_if(pc, TokenIdIdentifier); - if (name != 0) { - if (eat_token_if(pc, TokenIdColon) != 0) { - if (first == 0) - first = name; - } else { - // We put back the ident, so it can be parsed as a ParamType - // later. - put_back_token(pc); - name = 0; - } - } - - AstNode *res; - if (first == 0) { - first = peek_token(pc); - res = ast_parse_param_type(pc); - } else { - res = ast_expect(pc, ast_parse_param_type); - } - - if (res == nullptr) - return nullptr; - - assert(res->type == NodeTypeParamDecl); - res->main_token = first; - res->data.param_decl.name = token_buf(pc, name); - res->data.param_decl.doc_comments = first_doc_comment; - res->data.param_decl.is_noalias = pc->token_ids[first] == TokenIdKeywordNoAlias; - res->data.param_decl.is_comptime = pc->token_ids[first] == TokenIdKeywordCompTime; - return res; -} - -// ParamType -// <- KEYWORD_anytype -// / DOT3 -// / TypeExpr -static AstNode *ast_parse_param_type(ParseContext *pc) { - TokenIndex anytype_token = eat_token_if(pc, TokenIdKeywordAnyType); - if (anytype_token != 0) { - AstNode *res = ast_create_node(pc, NodeTypeParamDecl, anytype_token); - res->data.param_decl.anytype_token = anytype_token; - return res; - } - - TokenIndex dots = eat_token_if(pc, TokenIdEllipsis3); - if (dots != 0) { - AstNode *res = ast_create_node(pc, NodeTypeParamDecl, dots); - res->data.param_decl.is_var_args = true; - return res; - } - - AstNode *type_expr = ast_parse_type_expr(pc); - if (type_expr != nullptr) { - AstNode *res = ast_create_node_copy_line_info(pc, NodeTypeParamDecl, type_expr); - res->data.param_decl.type = type_expr; - return res; - } - - return nullptr; -} - -// IfPrefix <- KEYWORD_if LPAREN Expr RPAREN PtrPayload? -static AstNode *ast_parse_if_prefix(ParseContext *pc) { - TokenIndex first = eat_token_if(pc, TokenIdKeywordIf); - if (first == 0) - return nullptr; - - expect_token(pc, TokenIdLParen); - AstNode *condition = ast_expect(pc, ast_parse_expr); - expect_token(pc, TokenIdRParen); - Optional opt_payload = ast_parse_ptr_payload(pc); - - PtrPayload payload; - AstNode *res = ast_create_node(pc, NodeTypeIfOptional, first); - res->data.test_expr.target_node = condition; - if (opt_payload.unwrap(&payload)) { - res->data.test_expr.var_symbol = token_buf(pc, payload.payload); - res->data.test_expr.var_is_ptr = payload.asterisk != 0; - } - return res; -} - -// WhilePrefix <- KEYWORD_while LPAREN Expr RPAREN PtrPayload? WhileContinueExpr? -static AstNode *ast_parse_while_prefix(ParseContext *pc) { - TokenIndex while_token = eat_token_if(pc, TokenIdKeywordWhile); - if (while_token == 0) - return nullptr; - - expect_token(pc, TokenIdLParen); - AstNode *condition = ast_expect(pc, ast_parse_expr); - expect_token(pc, TokenIdRParen); - Optional opt_payload = ast_parse_ptr_payload(pc); - AstNode *continue_expr = ast_parse_while_continue_expr(pc); - - PtrPayload payload; - AstNode *res = ast_create_node(pc, NodeTypeWhileExpr, while_token); - res->data.while_expr.condition = condition; - res->data.while_expr.continue_expr = continue_expr; - if (opt_payload.unwrap(&payload)) { - res->data.while_expr.var_symbol = token_buf(pc, payload.payload); - res->data.while_expr.var_is_ptr = payload.asterisk != 0; - } - - return res; -} - -// ForPrefix <- KEYWORD_for LPAREN Expr RPAREN PtrIndexPayload -static AstNode *ast_parse_for_prefix(ParseContext *pc) { - TokenIndex for_token = eat_token_if(pc, TokenIdKeywordFor); - if (for_token == 0) - return nullptr; - - expect_token(pc, TokenIdLParen); - AstNode *array_expr = ast_expect(pc, ast_parse_expr); - expect_token(pc, TokenIdRParen); - PtrIndexPayload payload; - if (!ast_parse_ptr_index_payload(pc).unwrap(&payload)) - ast_invalid_token_error(pc, peek_token(pc)); - - AstNode *res = ast_create_node(pc, NodeTypeForExpr, for_token); - res->data.for_expr.array_expr = array_expr; - res->data.for_expr.elem_node = token_identifier(pc, payload.payload); - res->data.for_expr.elem_is_ptr = payload.asterisk != 0; - if (payload.index != 0) - res->data.for_expr.index_node = token_identifier(pc, payload.index); - - return res; -} - -// Payload <- PIPE IDENTIFIER PIPE -static TokenIndex ast_parse_payload(ParseContext *pc) { - if (eat_token_if(pc, TokenIdBinOr) == 0) - return 0; - - TokenIndex res = expect_token(pc, TokenIdIdentifier); - expect_token(pc, TokenIdBinOr); - return res; -} - -// PtrPayload <- PIPE ASTERISK? IDENTIFIER PIPE -static Optional ast_parse_ptr_payload(ParseContext *pc) { - if (eat_token_if(pc, TokenIdBinOr) == 0) - return Optional::none(); - - TokenIndex asterisk = eat_token_if(pc, TokenIdStar); - TokenIndex payload = expect_token(pc, TokenIdIdentifier); - expect_token(pc, TokenIdBinOr); - - PtrPayload res; - res.asterisk = asterisk; - res.payload = payload; - return Optional::some(res); -} - -// PtrIndexPayload <- PIPE ASTERISK? IDENTIFIER (COMMA IDENTIFIER)? PIPE -static Optional ast_parse_ptr_index_payload(ParseContext *pc) { - if (eat_token_if(pc, TokenIdBinOr) == 0) - return Optional::none(); - - TokenIndex asterisk = eat_token_if(pc, TokenIdStar); - TokenIndex payload = expect_token(pc, TokenIdIdentifier); - TokenIndex index = 0; - if (eat_token_if(pc, TokenIdComma) != 0) - index = expect_token(pc, TokenIdIdentifier); - expect_token(pc, TokenIdBinOr); - - PtrIndexPayload res; - res.asterisk = asterisk; - res.payload = payload; - res.index = index; - return Optional::some(res); -} - -// SwitchProng <- KEYWORD_inline? SwitchCase EQUALRARROW PtrIndexPayload? AssignExpr -static AstNode *ast_parse_switch_prong(ParseContext *pc) { - AstNode *res = ast_parse_switch_case(pc); - if (res == nullptr) - return nullptr; - - expect_token(pc, TokenIdFatArrow); - Optional opt_payload = ast_parse_ptr_index_payload(pc); - AstNode *expr = ast_expect(pc, ast_parse_assign_expr); - - PtrIndexPayload payload; - assert(res->type == NodeTypeSwitchProng); - res->data.switch_prong.expr = expr; - if (opt_payload.unwrap(&payload)) { - res->data.switch_prong.var_symbol = token_identifier(pc, payload.payload); - res->data.switch_prong.var_is_ptr = payload.asterisk != 0; - } - - return res; -} - -// SwitchCase -// <- SwitchItem (COMMA SwitchItem)* COMMA? -// / KEYWORD_else -static AstNode *ast_parse_switch_case(ParseContext *pc) { - bool is_inline = eat_token_if(pc, TokenIdKeywordInline) != 0; - AstNode *first = ast_parse_switch_item(pc); - if (first != nullptr) { - AstNode *res = ast_create_node_copy_line_info(pc, NodeTypeSwitchProng, first); - res->data.switch_prong.is_inline = is_inline; - res->data.switch_prong.items.append(first); - res->data.switch_prong.any_items_are_range = first->type == NodeTypeSwitchRange; - - while (eat_token_if(pc, TokenIdComma) != 0) { - AstNode *item = ast_parse_switch_item(pc); - if (item == nullptr) - break; - - res->data.switch_prong.items.append(item); - res->data.switch_prong.any_items_are_range |= item->type == NodeTypeSwitchRange; - } - - return res; - } - - TokenIndex else_token = eat_token_if(pc, TokenIdKeywordElse); - if (else_token != 0) { - AstNode *res = ast_create_node(pc, NodeTypeSwitchProng, else_token); - res->data.switch_prong.is_inline = is_inline; - return res; - } - - if (is_inline) pc->current_token -= 1; - return nullptr; -} - -// SwitchItem <- Expr (DOT3 Expr)? -static AstNode *ast_parse_switch_item(ParseContext *pc) { - AstNode *expr = ast_parse_expr(pc); - if (expr == nullptr) - return nullptr; - - TokenIndex dots = eat_token_if(pc, TokenIdEllipsis3); - if (dots != 0) { - AstNode *expr2 = ast_expect(pc, ast_parse_expr); - AstNode *res = ast_create_node(pc, NodeTypeSwitchRange, dots); - res->data.switch_range.start = expr; - res->data.switch_range.end = expr2; - return res; - } - - return expr; -} - -// AssignOp -// <- ASTERISKEQUAL -// / SLASHEQUAL -// / PERCENTEQUAL -// / PLUSEQUAL -// / MINUSEQUAL -// / LARROW2EQUAL -// / LARROW2PIPEEQUAL -// / RARROW2EQUAL -// / AMPERSANDEQUAL -// / CARETEQUAL -// / PIPEEQUAL -// / ASTERISKPERCENTEQUAL -// / PLUSPERCENTEQUAL -// / MINUSPERCENTEQUAL -// / ASTERISKPIPEEQUAL -// / PLUSPIPEEQUAL -// / MINUSPIPEEQUAL -// / EQUAL -static AstNode *ast_parse_assign_op(ParseContext *pc) { - // In C, we have `T arr[N] = {[i] = T{}};` but it doesn't - // seem to work in C++... - BinOpType table[TokenIdCount] = {}; - table[TokenIdBitAndEq] = BinOpTypeAssignBitAnd; - table[TokenIdBitOrEq] = BinOpTypeAssignBitOr; - table[TokenIdBitShiftLeftEq] = BinOpTypeAssignBitShiftLeft; - table[TokenIdBitShiftLeftPipeEq] = BinOpTypeAssignBitShiftLeftSat; - table[TokenIdBitShiftRightEq] = BinOpTypeAssignBitShiftRight; - table[TokenIdBitXorEq] = BinOpTypeAssignBitXor; - table[TokenIdDivEq] = BinOpTypeAssignDiv; - table[TokenIdEq] = BinOpTypeAssign; - table[TokenIdMinusEq] = BinOpTypeAssignMinus; - table[TokenIdMinusPercentEq] = BinOpTypeAssignMinusWrap; - table[TokenIdMinusPipeEq] = BinOpTypeAssignMinusSat; - table[TokenIdModEq] = BinOpTypeAssignMod; - table[TokenIdPlusEq] = BinOpTypeAssignPlus; - table[TokenIdPlusPercentEq] = BinOpTypeAssignPlusWrap; - table[TokenIdPlusPipeEq] = BinOpTypeAssignPlusSat; - table[TokenIdTimesEq] = BinOpTypeAssignTimes; - table[TokenIdTimesPercentEq] = BinOpTypeAssignTimesWrap; - table[TokenIdTimesPipeEq] = BinOpTypeAssignTimesSat; - - BinOpType op = table[pc->token_ids[pc->current_token]]; - if (op != BinOpTypeInvalid) { - TokenIndex op_token = eat_token(pc); - AstNode *res = ast_create_node(pc, NodeTypeBinOpExpr, op_token); - res->data.bin_op_expr.bin_op = op; - return res; - } - - return nullptr; - -} - -// CompareOp -// <- EQUALEQUAL -// / EXCLAMATIONMARKEQUAL -// / LARROW -// / RARROW -// / LARROWEQUAL -// / RARROWEQUAL -static AstNode *ast_parse_compare_op(ParseContext *pc) { - BinOpType table[TokenIdCount] = {}; - table[TokenIdCmpEq] = BinOpTypeCmpEq; - table[TokenIdCmpNotEq] = BinOpTypeCmpNotEq; - table[TokenIdCmpLessThan] = BinOpTypeCmpLessThan; - table[TokenIdCmpGreaterThan] = BinOpTypeCmpGreaterThan; - table[TokenIdCmpLessOrEq] = BinOpTypeCmpLessOrEq; - table[TokenIdCmpGreaterOrEq] = BinOpTypeCmpGreaterOrEq; - - BinOpType op = table[pc->token_ids[pc->current_token]]; - if (op != BinOpTypeInvalid) { - TokenIndex op_token = eat_token(pc); - AstNode *res = ast_create_node(pc, NodeTypeBinOpExpr, op_token); - res->data.bin_op_expr.bin_op = op; - return res; - } - - return nullptr; -} - -// BitwiseOp -// <- AMPERSAND -// / CARET -// / PIPE -// / KEYWORD_orelse -// / KEYWORD_catch Payload? -static AstNode *ast_parse_bitwise_op(ParseContext *pc) { - BinOpType table[TokenIdCount] = {}; - table[TokenIdAmpersand] = BinOpTypeBinAnd; - table[TokenIdBinXor] = BinOpTypeBinXor; - table[TokenIdBinOr] = BinOpTypeBinOr; - table[TokenIdKeywordOrElse] = BinOpTypeUnwrapOptional; - - BinOpType op = table[pc->token_ids[pc->current_token]]; - if (op != BinOpTypeInvalid) { - TokenIndex op_token = eat_token(pc); - AstNode *res = ast_create_node(pc, NodeTypeBinOpExpr, op_token); - res->data.bin_op_expr.bin_op = op; - return res; - } - - TokenIndex catch_token = eat_token_if(pc, TokenIdKeywordCatch); - if (catch_token != 0) { - TokenIndex payload = ast_parse_payload(pc); - AstNode *res = ast_create_node(pc, NodeTypeCatchExpr, catch_token); - if (payload != 0) - res->data.unwrap_err_expr.symbol = token_identifier(pc, payload); - - return res; - } - - return nullptr; -} - -// BitShiftOp -// <- LARROW2 -// / LARROW2PIPE -// / RARROW2 -static AstNode *ast_parse_bit_shift_op(ParseContext *pc) { - BinOpType table[TokenIdCount] = {}; - table[TokenIdBitShiftLeft] = BinOpTypeBitShiftLeft; - table[TokenIdBitShiftLeftPipe] = BinOpTypeBitShiftLeftSat; - table[TokenIdBitShiftRight] = BinOpTypeBitShiftRight; - - BinOpType op = table[pc->token_ids[pc->current_token]]; - if (op != BinOpTypeInvalid) { - TokenIndex op_token = eat_token(pc); - AstNode *res = ast_create_node(pc, NodeTypeBinOpExpr, op_token); - res->data.bin_op_expr.bin_op = op; - return res; - } - - return nullptr; -} - -// AdditionOp -// <- PLUS -// / MINUS -// / PLUS2 -// / PLUSPERCENT -// / MINUSPERCENT -// / PLUSPIPE -// / MINUSPIPE -static AstNode *ast_parse_addition_op(ParseContext *pc) { - BinOpType table[TokenIdCount] = {}; - table[TokenIdPlus] = BinOpTypeAdd; - table[TokenIdDash] = BinOpTypeSub; - table[TokenIdPlusPlus] = BinOpTypeArrayCat; - table[TokenIdPlusPercent] = BinOpTypeAddWrap; - table[TokenIdMinusPercent] = BinOpTypeSubWrap; - table[TokenIdPlusPipe] = BinOpTypeAddSat; - table[TokenIdMinusPipe] = BinOpTypeSubSat; - - BinOpType op = table[pc->token_ids[pc->current_token]]; - if (op != BinOpTypeInvalid) { - TokenIndex op_token = eat_token(pc); - AstNode *res = ast_create_node(pc, NodeTypeBinOpExpr, op_token); - res->data.bin_op_expr.bin_op = op; - return res; - } - - return nullptr; -} - -// MultiplyOp -// <- PIPE2 -// / ASTERISK -// / SLASH -// / PERCENT -// / ASTERISK2 -// / ASTERISKPERCENT -// / ASTERISKPIPE -static AstNode *ast_parse_multiply_op(ParseContext *pc) { - BinOpType table[TokenIdCount] = {}; - table[TokenIdBarBar] = BinOpTypeMergeErrorSets; - table[TokenIdStar] = BinOpTypeMult; - table[TokenIdSlash] = BinOpTypeDiv; - table[TokenIdPercent] = BinOpTypeMod; - table[TokenIdStarStar] = BinOpTypeArrayMult; - table[TokenIdTimesPercent] = BinOpTypeMultWrap; - table[TokenIdTimesPipe] = BinOpTypeMultSat; - - BinOpType op = table[pc->token_ids[pc->current_token]]; - if (op != BinOpTypeInvalid) { - TokenIndex op_token = eat_token(pc); - AstNode *res = ast_create_node(pc, NodeTypeBinOpExpr, op_token); - res->data.bin_op_expr.bin_op = op; - return res; - } - - return nullptr; -} - -// PrefixOp -// <- EXCLAMATIONMARK -// / MINUS -// / TILDE -// / MINUSPERCENT -// / AMPERSAND -// / KEYWORD_try -// / KEYWORD_await -static AstNode *ast_parse_prefix_op(ParseContext *pc) { - PrefixOp table[TokenIdCount] = {}; - table[TokenIdBang] = PrefixOpBoolNot; - table[TokenIdDash] = PrefixOpNegation; - table[TokenIdTilde] = PrefixOpBinNot; - table[TokenIdMinusPercent] = PrefixOpNegationWrap; - table[TokenIdAmpersand] = PrefixOpAddrOf; - - PrefixOp op = table[pc->token_ids[pc->current_token]]; - if (op != PrefixOpInvalid) { - TokenIndex op_token = eat_token(pc); - AstNode *res = ast_create_node(pc, NodeTypePrefixOpExpr, op_token); - res->data.prefix_op_expr.prefix_op = op; - return res; - } - - TokenIndex try_token = eat_token_if(pc, TokenIdKeywordTry); - if (try_token != 0) { - AstNode *res = ast_create_node(pc, NodeTypeReturnExpr, try_token); - res->data.return_expr.kind = ReturnKindError; - return res; - } - - TokenIndex await = eat_token_if(pc, TokenIdKeywordAwait); - if (await != 0) { - AstNode *res = ast_create_node(pc, NodeTypeAwaitExpr, await); - return res; - } - - return nullptr; -} - -// PrefixTypeOp -// <- QUESTIONMARK -// / KEYWORD_anyframe MINUSRARROW -// / ArrayTypeStart (ByteAlign / KEYWORD_const / KEYWORD_volatile)* -// / PtrTypeStart (KEYWORD_align LPAREN Expr (COLON INTEGER COLON INTEGER)? RPAREN / KEYWORD_const / KEYWORD_volatile)* -static AstNode *ast_parse_prefix_type_op(ParseContext *pc) { - TokenIndex questionmark = eat_token_if(pc, TokenIdQuestion); - if (questionmark != 0) { - AstNode *res = ast_create_node(pc, NodeTypePrefixOpExpr, questionmark); - res->data.prefix_op_expr.prefix_op = PrefixOpOptional; - return res; - } - - TokenIndex anyframe = eat_token_if(pc, TokenIdKeywordAnyFrame); - if (anyframe != 0) { - if (eat_token_if(pc, TokenIdArrow) != 0) { - AstNode *res = ast_create_node(pc, NodeTypeAnyFrameType, anyframe); - return res; - } - - put_back_token(pc); - } - - TokenIndex arr_init_lbracket = eat_token_if(pc, TokenIdLBracket); - if (arr_init_lbracket != 0) { - TokenIndex underscore = eat_token_if(pc, TokenIdIdentifier); - if (underscore == 0) { - put_back_token(pc); - } else if (!buf_eql_str(token_buf(pc, underscore), "_")) { - put_back_token(pc); - put_back_token(pc); - } else { - AstNode *sentinel = nullptr; - TokenIndex colon = eat_token_if(pc, TokenIdColon); - if (colon != 0) { - sentinel = ast_expect(pc, ast_parse_expr); - } - expect_token(pc, TokenIdRBracket); - AstNode *node = ast_create_node(pc, NodeTypeInferredArrayType, arr_init_lbracket); - node->data.inferred_array_type.sentinel = sentinel; - return node; - } - } - - - AstNode *ptr = ast_parse_ptr_type_start(pc); - if (ptr != nullptr) { - assert(ptr->type == NodeTypePointerType); - // We might get two pointers from *_ptr_type_start - AstNode *child = ptr->data.pointer_type.op_expr; - if (child == nullptr) - child = ptr; - while (true) { - TokenIndex allowzero_token = eat_token_if(pc, TokenIdKeywordAllowZero); - if (allowzero_token != 0) { - child->data.pointer_type.allow_zero_token = allowzero_token; - continue; - } - - if (eat_token_if(pc, TokenIdKeywordAlign) != 0) { - expect_token(pc, TokenIdLParen); - AstNode *align_expr = ast_expect(pc, ast_parse_expr); - child->data.pointer_type.align_expr = align_expr; - if (eat_token_if(pc, TokenIdColon) != 0) { - TokenIndex bit_offset_start = expect_token(pc, TokenIdIntLiteral); - expect_token(pc, TokenIdColon); - TokenIndex host_int_bytes = expect_token(pc, TokenIdIntLiteral); - child->data.pointer_type.bit_offset_start = bit_offset_start; - child->data.pointer_type.host_int_bytes = host_int_bytes; - } - expect_token(pc, TokenIdRParen); - continue; - } - - if (eat_token_if(pc, TokenIdKeywordConst) != 0) { - child->data.pointer_type.is_const = true; - continue; - } - - if (eat_token_if(pc, TokenIdKeywordVolatile) != 0) { - child->data.pointer_type.is_volatile = true; - continue; - } - - break; - } - - return ptr; - } - - AstNode *array = ast_parse_array_type_start(pc); - if (array != nullptr) { - assert(array->type == NodeTypeArrayType); - while (true) { - TokenIndex allowzero_token = eat_token_if(pc, TokenIdKeywordAllowZero); - if (allowzero_token != 0) { - array->data.array_type.allow_zero_token = allowzero_token; - continue; - } - - AstNode *align_expr = ast_parse_byte_align(pc); - if (align_expr != nullptr) { - array->data.array_type.align_expr = align_expr; - continue; - } - - if (eat_token_if(pc, TokenIdKeywordConst) != 0) { - array->data.array_type.is_const = true; - continue; - } - - if (eat_token_if(pc, TokenIdKeywordVolatile) != 0) { - array->data.array_type.is_volatile = true; - continue; - } - break; - } - - return array; - } - - - return nullptr; -} - -// SuffixOp -// <- LBRACKET Expr (DOT2 (Expr (COLON Expr)?)?)? RBRACKET -// / DOT IDENTIFIER -// / DOTASTERISK -// / DOTQUESTIONMARK -static AstNode *ast_parse_suffix_op(ParseContext *pc) { - TokenIndex lbracket = eat_token_if(pc, TokenIdLBracket); - if (lbracket != 0) { - AstNode *start = ast_expect(pc, ast_parse_expr); - AstNode *end = nullptr; - if (eat_token_if(pc, TokenIdEllipsis2) != 0) { - AstNode *sentinel = nullptr; - end = ast_parse_expr(pc); - if (eat_token_if(pc, TokenIdColon) != 0) { - sentinel = ast_parse_expr(pc); - } - expect_token(pc, TokenIdRBracket); - - AstNode *res = ast_create_node(pc, NodeTypeSliceExpr, lbracket); - res->data.slice_expr.start = start; - res->data.slice_expr.end = end; - res->data.slice_expr.sentinel = sentinel; - return res; - } - - expect_token(pc, TokenIdRBracket); - - AstNode *res = ast_create_node(pc, NodeTypeArrayAccessExpr, lbracket); - res->data.array_access_expr.subscript = start; - return res; - } - - TokenIndex dot_asterisk = eat_token_if(pc, TokenIdDotStar); - if (dot_asterisk != 0) - return ast_create_node(pc, NodeTypePtrDeref, dot_asterisk); - - TokenIndex dot = eat_token_if(pc, TokenIdDot); - if (dot != 0) { - if (eat_token_if(pc, TokenIdQuestion) != 0) - return ast_create_node(pc, NodeTypeUnwrapOptional, dot); - - TokenIndex ident = expect_token(pc, TokenIdIdentifier); - AstNode *res = ast_create_node(pc, NodeTypeFieldAccessExpr, dot); - res->data.field_access_expr.field_name = token_buf(pc, ident); - return res; - } - - return nullptr; -} - -// FnCallArguments <- LPAREN ExprList RPAREN -static AstNode *ast_parse_fn_call_arguments(ParseContext *pc) { - TokenIndex paren = eat_token_if(pc, TokenIdLParen); - if (paren == 0) - return nullptr; - - ZigList params = ast_parse_list(pc, TokenIdComma, ast_parse_expr); - expect_token(pc, TokenIdRParen); - - AstNode *res = ast_create_node(pc, NodeTypeFnCallExpr, paren); - res->data.fn_call_expr.params = params; - res->data.fn_call_expr.seen = false; - return res; -} - -// ArrayTypeStart <- LBRACKET Expr? RBRACKET -static AstNode *ast_parse_array_type_start(ParseContext *pc) { - TokenIndex lbracket = eat_token_if(pc, TokenIdLBracket); - if (lbracket == 0) - return nullptr; - - AstNode *size = ast_parse_expr(pc); - AstNode *sentinel = nullptr; - TokenIndex colon = eat_token_if(pc, TokenIdColon); - if (colon != 0) { - sentinel = ast_expect(pc, ast_parse_expr); - } - expect_token(pc, TokenIdRBracket); - AstNode *res = ast_create_node(pc, NodeTypeArrayType, lbracket); - res->data.array_type.size = size; - res->data.array_type.sentinel = sentinel; - return res; -} - -// PtrTypeStart -// <- ASTERISK -// / ASTERISK2 -// / PTRUNKNOWN -// / PTRC -static AstNode *ast_parse_ptr_type_start(ParseContext *pc) { - AstNode *sentinel = nullptr; - - TokenIndex asterisk = eat_token_if(pc, TokenIdStar); - if (asterisk != 0) { - TokenIndex colon = eat_token_if(pc, TokenIdColon); - if (colon != 0) { - sentinel = ast_expect(pc, ast_parse_expr); - } - AstNode *res = ast_create_node(pc, NodeTypePointerType, asterisk); - res->data.pointer_type.star_token = asterisk; - res->data.pointer_type.sentinel = sentinel; - return res; - } - - TokenIndex asterisk2 = eat_token_if(pc, TokenIdStarStar); - if (asterisk2 != 0) { - TokenIndex colon = eat_token_if(pc, TokenIdColon); - if (colon != 0) { - sentinel = ast_expect(pc, ast_parse_expr); - } - AstNode *res = ast_create_node(pc, NodeTypePointerType, asterisk2); - AstNode *res2 = ast_create_node(pc, NodeTypePointerType, asterisk2); - res->data.pointer_type.star_token = asterisk2; - res2->data.pointer_type.star_token = asterisk2; - res2->data.pointer_type.sentinel = sentinel; - res->data.pointer_type.op_expr = res2; - return res; - } - - TokenIndex lbracket = eat_token_if(pc, TokenIdLBracket); - if (lbracket != 0) { - TokenIndex star = eat_token_if(pc, TokenIdStar); - if (star == 0) { - put_back_token(pc); - } else { - TokenIndex c_tok = eat_token_if(pc, TokenIdIdentifier); - if (c_tok != 0) { - if (!buf_eql_str(token_buf(pc, c_tok), "c")) { - put_back_token(pc); // c symbol - } else { - expect_token(pc, TokenIdRBracket); - AstNode *res = ast_create_node(pc, NodeTypePointerType, lbracket); - res->data.pointer_type.star_token = c_tok; - return res; - } - } - - TokenIndex colon = eat_token_if(pc, TokenIdColon); - if (colon != 0) { - sentinel = ast_expect(pc, ast_parse_expr); - } - expect_token(pc, TokenIdRBracket); - AstNode *res = ast_create_node(pc, NodeTypePointerType, lbracket); - res->data.pointer_type.star_token = lbracket; - res->data.pointer_type.sentinel = sentinel; - return res; - } - } - - return nullptr; -} - -// ContainerDeclAuto <- ContainerDeclType LBRACE ContainerMembers RBRACE -static AstNode *ast_parse_container_decl_auto(ParseContext *pc) { - AstNode *res = ast_parse_container_decl_type(pc); - if (res == nullptr) - return nullptr; - - expect_token(pc, TokenIdLBrace); - AstNodeContainerDecl members = ast_parse_container_members(pc); - expect_token(pc, TokenIdRBrace); - - res->data.container_decl.fields = members.fields; - res->data.container_decl.decls = members.decls; - res->data.container_decl.doc_comments = members.doc_comments; - return res; -} - -// ContainerDeclType -// <- KEYWORD_struct (LPAREN Expr RPAREN)? -// / KEYWORD_enum (LPAREN Expr RPAREN)? -// / KEYWORD_union (LPAREN (KEYWORD_enum (LPAREN Expr RPAREN)? / Expr) RPAREN)? -// / KEYWORD_opaque -static AstNode *ast_parse_container_decl_type(ParseContext *pc) { - TokenIndex first = eat_token_if(pc, TokenIdKeywordStruct); - if (first != 0) { - bool explicit_backing_int = false; - if (eat_token_if(pc, TokenIdLParen) != 0) { - explicit_backing_int = true; - ast_expect(pc, ast_parse_expr); - expect_token(pc, TokenIdRParen); - } - AstNode *res = ast_create_node(pc, NodeTypeContainerDecl, first); - res->data.container_decl.init_arg_expr = nullptr; - res->data.container_decl.kind = ContainerKindStruct; - // We want this to be an error in semantic analysis not parsing to make sharing - // the test suite between stage1 and self hosted easier. - res->data.container_decl.unsupported_explicit_backing_int = explicit_backing_int; - return res; - } - - first = eat_token_if(pc, TokenIdKeywordOpaque); - if (first != 0) { - AstNode *res = ast_create_node(pc, NodeTypeContainerDecl, first); - res->data.container_decl.init_arg_expr = nullptr; - res->data.container_decl.kind = ContainerKindOpaque; - return res; - } - - first = eat_token_if(pc, TokenIdKeywordEnum); - if (first != 0) { - AstNode *init_arg_expr = nullptr; - if (eat_token_if(pc, TokenIdLParen) != 0) { - init_arg_expr = ast_expect(pc, ast_parse_expr); - expect_token(pc, TokenIdRParen); - } - AstNode *res = ast_create_node(pc, NodeTypeContainerDecl, first); - res->data.container_decl.init_arg_expr = init_arg_expr; - res->data.container_decl.kind = ContainerKindEnum; - return res; - } - - first = eat_token_if(pc, TokenIdKeywordUnion); - if (first != 0) { - AstNode *init_arg_expr = nullptr; - bool auto_enum = false; - if (eat_token_if(pc, TokenIdLParen) != 0) { - if (eat_token_if(pc, TokenIdKeywordEnum) != 0) { - auto_enum = true; - if (eat_token_if(pc, TokenIdLParen) != 0) { - init_arg_expr = ast_expect(pc, ast_parse_expr); - expect_token(pc, TokenIdRParen); - } - } else { - init_arg_expr = ast_expect(pc, ast_parse_expr); - } - - expect_token(pc, TokenIdRParen); - } - - AstNode *res = ast_create_node(pc, NodeTypeContainerDecl, first); - res->data.container_decl.init_arg_expr = init_arg_expr; - res->data.container_decl.auto_enum = auto_enum; - res->data.container_decl.kind = ContainerKindUnion; - return res; - } - - return nullptr; -} - -// ByteAlign <- KEYWORD_align LPAREN Expr RPAREN -static AstNode *ast_parse_byte_align(ParseContext *pc) { - if (eat_token_if(pc, TokenIdKeywordAlign) == 0) - return nullptr; - - expect_token(pc, TokenIdLParen); - AstNode *res = ast_expect(pc, ast_parse_expr); - expect_token(pc, TokenIdRParen); - return res; -} - -static void visit_field(AstNode **node, void (*visit)(AstNode **, void *context), void *context) { - if (*node) { - visit(node, context); - } -} - -static void visit_node_list(ZigList *list, void (*visit)(AstNode **, void *context), void *context) { - if (list) { - for (size_t i = 0; i < list->length; i += 1) { - visit(&list->at(i), context); - } - } -} - -void ast_visit_node_children(AstNode *node, void (*visit)(AstNode **, void *context), void *context) { - switch (node->type) { - case NodeTypeFnProto: - visit_field(&node->data.fn_proto.return_type, visit, context); - visit_node_list(&node->data.fn_proto.params, visit, context); - visit_field(&node->data.fn_proto.align_expr, visit, context); - visit_field(&node->data.fn_proto.section_expr, visit, context); - break; - case NodeTypeFnDef: - visit_field(&node->data.fn_def.fn_proto, visit, context); - visit_field(&node->data.fn_def.body, visit, context); - break; - case NodeTypeParamDecl: - visit_field(&node->data.param_decl.type, visit, context); - break; - case NodeTypeBlock: - visit_node_list(&node->data.block.statements, visit, context); - break; - case NodeTypeGroupedExpr: - visit_field(&node->data.grouped_expr, visit, context); - break; - case NodeTypeReturnExpr: - visit_field(&node->data.return_expr.expr, visit, context); - break; - case NodeTypeDefer: - visit_field(&node->data.defer.expr, visit, context); - visit_field(&node->data.defer.err_payload, visit, context); - break; - case NodeTypeVariableDeclaration: - visit_field(&node->data.variable_declaration.type, visit, context); - visit_field(&node->data.variable_declaration.expr, visit, context); - visit_field(&node->data.variable_declaration.align_expr, visit, context); - visit_field(&node->data.variable_declaration.section_expr, visit, context); - break; - case NodeTypeTestDecl: - visit_field(&node->data.test_decl.body, visit, context); - break; - case NodeTypeBinOpExpr: - visit_field(&node->data.bin_op_expr.op1, visit, context); - visit_field(&node->data.bin_op_expr.op2, visit, context); - break; - case NodeTypeCatchExpr: - visit_field(&node->data.unwrap_err_expr.op1, visit, context); - visit_field(&node->data.unwrap_err_expr.symbol, visit, context); - visit_field(&node->data.unwrap_err_expr.op2, visit, context); - break; - case NodeTypeIntLiteral: - // none - break; - case NodeTypeFloatLiteral: - // none - break; - case NodeTypeStringLiteral: - // none - break; - case NodeTypeCharLiteral: - // none - break; - case NodeTypeIdentifier: - // none - break; - case NodeTypePrefixOpExpr: - visit_field(&node->data.prefix_op_expr.primary_expr, visit, context); - break; - case NodeTypeFnCallExpr: - visit_field(&node->data.fn_call_expr.fn_ref_expr, visit, context); - visit_node_list(&node->data.fn_call_expr.params, visit, context); - break; - case NodeTypeArrayAccessExpr: - visit_field(&node->data.array_access_expr.array_ref_expr, visit, context); - visit_field(&node->data.array_access_expr.subscript, visit, context); - break; - case NodeTypeSliceExpr: - visit_field(&node->data.slice_expr.array_ref_expr, visit, context); - visit_field(&node->data.slice_expr.start, visit, context); - visit_field(&node->data.slice_expr.end, visit, context); - visit_field(&node->data.slice_expr.sentinel, visit, context); - break; - case NodeTypeFieldAccessExpr: - visit_field(&node->data.field_access_expr.struct_expr, visit, context); - break; - case NodeTypePtrDeref: - visit_field(&node->data.ptr_deref_expr.target, visit, context); - break; - case NodeTypeUnwrapOptional: - visit_field(&node->data.unwrap_optional.expr, visit, context); - break; - case NodeTypeUsingNamespace: - visit_field(&node->data.using_namespace.expr, visit, context); - break; - case NodeTypeIfBoolExpr: - visit_field(&node->data.if_bool_expr.condition, visit, context); - visit_field(&node->data.if_bool_expr.then_block, visit, context); - visit_field(&node->data.if_bool_expr.else_node, visit, context); - break; - case NodeTypeIfErrorExpr: - visit_field(&node->data.if_err_expr.target_node, visit, context); - visit_field(&node->data.if_err_expr.then_node, visit, context); - visit_field(&node->data.if_err_expr.else_node, visit, context); - break; - case NodeTypeIfOptional: - visit_field(&node->data.test_expr.target_node, visit, context); - visit_field(&node->data.test_expr.then_node, visit, context); - visit_field(&node->data.test_expr.else_node, visit, context); - break; - case NodeTypeWhileExpr: - visit_field(&node->data.while_expr.condition, visit, context); - visit_field(&node->data.while_expr.body, visit, context); - break; - case NodeTypeForExpr: - visit_field(&node->data.for_expr.elem_node, visit, context); - visit_field(&node->data.for_expr.array_expr, visit, context); - visit_field(&node->data.for_expr.index_node, visit, context); - visit_field(&node->data.for_expr.body, visit, context); - break; - case NodeTypeSwitchExpr: - visit_field(&node->data.switch_expr.expr, visit, context); - visit_node_list(&node->data.switch_expr.prongs, visit, context); - break; - case NodeTypeSwitchProng: - visit_node_list(&node->data.switch_prong.items, visit, context); - visit_field(&node->data.switch_prong.var_symbol, visit, context); - visit_field(&node->data.switch_prong.expr, visit, context); - break; - case NodeTypeSwitchRange: - visit_field(&node->data.switch_range.start, visit, context); - visit_field(&node->data.switch_range.end, visit, context); - break; - case NodeTypeCompTime: - visit_field(&node->data.comptime_expr.expr, visit, context); - break; - case NodeTypeNoSuspend: - visit_field(&node->data.comptime_expr.expr, visit, context); - break; - case NodeTypeBreak: - // none - break; - case NodeTypeContinue: - // none - break; - case NodeTypeUnreachable: - // none - break; - case NodeTypeAsmExpr: - for (size_t i = 0; i < node->data.asm_expr.input_list.length; i += 1) { - AsmInput *asm_input = node->data.asm_expr.input_list.at(i); - visit_field(&asm_input->expr, visit, context); - } - for (size_t i = 0; i < node->data.asm_expr.output_list.length; i += 1) { - AsmOutput *asm_output = node->data.asm_expr.output_list.at(i); - visit_field(&asm_output->return_type, visit, context); - } - break; - case NodeTypeContainerDecl: - visit_node_list(&node->data.container_decl.fields, visit, context); - visit_node_list(&node->data.container_decl.decls, visit, context); - visit_field(&node->data.container_decl.init_arg_expr, visit, context); - break; - case NodeTypeStructField: - visit_field(&node->data.struct_field.type, visit, context); - visit_field(&node->data.struct_field.value, visit, context); - break; - case NodeTypeContainerInitExpr: - visit_field(&node->data.container_init_expr.type, visit, context); - visit_node_list(&node->data.container_init_expr.entries, visit, context); - break; - case NodeTypeStructValueField: - visit_field(&node->data.struct_val_field.expr, visit, context); - break; - case NodeTypeArrayType: - visit_field(&node->data.array_type.size, visit, context); - visit_field(&node->data.array_type.sentinel, visit, context); - visit_field(&node->data.array_type.child_type, visit, context); - visit_field(&node->data.array_type.align_expr, visit, context); - break; - case NodeTypeInferredArrayType: - visit_field(&node->data.array_type.sentinel, visit, context); - visit_field(&node->data.array_type.child_type, visit, context); - break; - case NodeTypeAnyFrameType: - visit_field(&node->data.anyframe_type.payload_type, visit, context); - break; - case NodeTypeErrorType: - // none - break; - case NodeTypePointerType: - visit_field(&node->data.pointer_type.sentinel, visit, context); - visit_field(&node->data.pointer_type.align_expr, visit, context); - visit_field(&node->data.pointer_type.op_expr, visit, context); - break; - case NodeTypeErrorSetDecl: - visit_node_list(&node->data.err_set_decl.decls, visit, context); - break; - case NodeTypeErrorSetField: - visit_field(&node->data.err_set_field.field_name, visit, context); - break; - case NodeTypeResume: - visit_field(&node->data.resume_expr.expr, visit, context); - break; - case NodeTypeAwaitExpr: - visit_field(&node->data.await_expr.expr, visit, context); - break; - case NodeTypeSuspend: - visit_field(&node->data.suspend.block, visit, context); - break; - case NodeTypeEnumLiteral: - case NodeTypeAnyTypeField: - break; - } -} - -Error source_string_literal_buf(const char *source, Buf *out, size_t *bad_index) { - size_t byte_offset = 0; - - assert(source[byte_offset] == '"'); - byte_offset += 1; - - buf_resize(out, 0); - - uint32_t codepoint; - - enum { - StateStart, - StateBackslash, - StateUnicodeLBrace, - StateUnicodeDigit, - } state = StateStart; - for (;;byte_offset += 1) { - switch (state) { - case StateStart: switch (source[byte_offset]) { - case '\\': - state = StateBackslash; - continue; - case '\n': - *bad_index = byte_offset; - return ErrorInvalidCharacter; - case '"': - return ErrorNone; - default: - buf_append_char(out, source[byte_offset]); - continue; - } - case StateBackslash: switch (source[byte_offset]) { - case 'n': - buf_append_char(out, '\n'); - state = StateStart; - continue; - case 'r': - buf_append_char(out, '\r'); - state = StateStart; - continue; - case '\\': - buf_append_char(out, '\\'); - state = StateStart; - continue; - case 't': - buf_append_char(out, '\t'); - state = StateStart; - continue; - case '\'': - buf_append_char(out, '\''); - state = StateStart; - continue; - case '"': - buf_append_char(out, '"'); - state = StateStart; - continue; - case 'x': { - byte_offset += 1; - uint8_t digit1; - if (source[byte_offset] >= '0' && source[byte_offset] <= '9') { - digit1 = source[byte_offset] - '0'; - } else if (source[byte_offset] >= 'a' && source[byte_offset] <= 'z') { - digit1 = source[byte_offset] - 'a' + 10; - } else if (source[byte_offset] >= 'A' && source[byte_offset] <= 'Z') { - digit1 = source[byte_offset] - 'A' + 10; - } else { - *bad_index = byte_offset; - return ErrorInvalidCharacter; - } - - byte_offset += 1; - uint8_t digit0; - if (source[byte_offset] >= '0' && source[byte_offset] <= '9') { - digit0 = source[byte_offset] - '0'; - } else if (source[byte_offset] >= 'a' && source[byte_offset] <= 'z') { - digit0 = source[byte_offset] - 'a' + 10; - } else if (source[byte_offset] >= 'A' && source[byte_offset] <= 'Z') { - digit0 = source[byte_offset] - 'A' + 10; - } else { - *bad_index = byte_offset; - return ErrorInvalidCharacter; - } - - buf_append_char(out, digit1 * 16 + digit0); - state = StateStart; - continue; - } - case 'u': - state = StateUnicodeLBrace; - continue; - default: - *bad_index = byte_offset; - return ErrorInvalidCharacter; - } - case StateUnicodeLBrace: switch (source[byte_offset]) { - case '{': - state = StateUnicodeDigit; - codepoint = 0; - continue; - default: - *bad_index = byte_offset; - return ErrorInvalidCharacter; - } - case StateUnicodeDigit: { - uint8_t digit; - if (source[byte_offset] >= '0' && source[byte_offset] <= '9') { - digit = source[byte_offset] - '0'; - } else if (source[byte_offset] >= 'a' && source[byte_offset] <= 'z') { - digit = source[byte_offset] - 'a' + 10; - } else if (source[byte_offset] >= 'A' && source[byte_offset] <= 'Z') { - digit = source[byte_offset] - 'A' + 10; - } else if (source[byte_offset] == '}') { - if (codepoint < 0x80) { - buf_append_char(out, codepoint); - } else if (codepoint < 0x800) { - buf_append_char(out, 0xc0 | (codepoint >> 6)); - buf_append_char(out, 0x80 | (codepoint & 0x3f)); - } else if (codepoint < 0x10000) { - buf_append_char(out, 0xe0 | (codepoint >> 12)); - buf_append_char(out, 0x80 | ((codepoint >> 6) & 0x3f)); - buf_append_char(out, 0x80 | (codepoint & 0x3f)); - } else if (codepoint < 0x110000) { - buf_append_char(out, 0xf0 | (codepoint >> 18)); - buf_append_char(out, 0x80 | ((codepoint >> 12) & 0x3f)); - buf_append_char(out, 0x80 | ((codepoint >> 6) & 0x3f)); - buf_append_char(out, 0x80 | (codepoint & 0x3f)); - } else { - *bad_index = byte_offset; - return ErrorUnicodePointTooLarge; - } - state = StateStart; - continue; - } else { - *bad_index = byte_offset; - return ErrorInvalidCharacter; - } - codepoint = codepoint * 16 + digit; - continue; - } - } - } - zig_unreachable(); -} - -static uint32_t utf8_code_point(const uint8_t *bytes) { - if (bytes[0] <= 0x7f) { - return bytes[0]; - } else if (bytes[0] >= 0xc0 && bytes[0] <= 0xdf) { - uint32_t result = bytes[0] & 0x1f; - result <<= 6; - result |= bytes[1] & 0x3f; - return result; - } else if (bytes[0] >= 0xe0 && bytes[0] <= 0xef) { - uint32_t result = bytes[0] & 0xf; - - result <<= 6; - result |= bytes[1] & 0x3f; - - result <<= 6; - result |= bytes[2] & 0x3f; - - return result; - } else if (bytes[0] >= 0xf0 && bytes[0] <= 0xf7) { - uint32_t result = bytes[0] & 0x7; - - result <<= 6; - result |= bytes[1] & 0x3f; - - result <<= 6; - result |= bytes[2] & 0x3f; - - result <<= 6; - result |= bytes[3] & 0x3f; - - return result; - } else { - zig_unreachable(); - } -} - -Error source_char_literal(const char *source, uint32_t *result, size_t *bad_index) { - if (source[0] != '\\') { - *result = utf8_code_point((const uint8_t *)source); - return ErrorNone; - } - - uint32_t byte_offset = 1; - uint32_t codepoint; - - enum State { - StateBackslash, - StateUnicodeLBrace, - StateUnicodeDigit, - } state = StateBackslash; - - for (;;byte_offset += 1) { - switch (state) { - case StateBackslash: switch (source[byte_offset]) { - case 'n': - *result = '\n'; - return ErrorNone; - case 'r': - *result = '\r'; - return ErrorNone; - case '\\': - *result = '\\'; - return ErrorNone; - case 't': - *result = '\t'; - return ErrorNone; - case '\'': - *result = '\''; - return ErrorNone; - case '"': - *result = '"'; - return ErrorNone; - case 'x': { - byte_offset += 1; - uint8_t digit1; - if (source[byte_offset] >= '0' && source[byte_offset] <= '9') { - digit1 = source[byte_offset] - '0'; - } else if (source[byte_offset] >= 'a' && source[byte_offset] <= 'z') { - digit1 = source[byte_offset] - 'a' + 10; - } else if (source[byte_offset] >= 'A' && source[byte_offset] <= 'Z') { - digit1 = source[byte_offset] - 'A' + 10; - } else { - *bad_index = byte_offset; - return ErrorInvalidCharacter; - } - - byte_offset += 1; - uint8_t digit0; - if (source[byte_offset] >= '0' && source[byte_offset] <= '9') { - digit0 = source[byte_offset] - '0'; - } else if (source[byte_offset] >= 'a' && source[byte_offset] <= 'z') { - digit0 = source[byte_offset] - 'a' + 10; - } else if (source[byte_offset] >= 'A' && source[byte_offset] <= 'Z') { - digit0 = source[byte_offset] - 'A' + 10; - } else { - *bad_index = byte_offset; - return ErrorInvalidCharacter; - } - - *result = digit1 * 16 + digit0; - return ErrorNone; - } - case 'u': - state = StateUnicodeLBrace; - continue; - default: - *bad_index = byte_offset; - return ErrorInvalidCharacter; - } - case StateUnicodeLBrace: switch (source[byte_offset]) { - case '{': - state = StateUnicodeDigit; - codepoint = 0; - continue; - default: - *bad_index = byte_offset; - return ErrorInvalidCharacter; - } - case StateUnicodeDigit: { - uint8_t digit; - if (source[byte_offset] >= '0' && source[byte_offset] <= '9') { - digit = source[byte_offset] - '0'; - } else if (source[byte_offset] >= 'a' && source[byte_offset] <= 'z') { - digit = source[byte_offset] - 'a' + 10; - } else if (source[byte_offset] >= 'A' && source[byte_offset] <= 'Z') { - digit = source[byte_offset] - 'A' + 10; - } else if (source[byte_offset] == '}') { - if (codepoint < 0x110000) { - *result = codepoint; - return ErrorNone; - } else { - *bad_index = byte_offset; - return ErrorUnicodePointTooLarge; - } - } else { - *bad_index = byte_offset; - return ErrorInvalidCharacter; - } - codepoint = codepoint * 16 + digit; - continue; - } - } - } -} - -static Buf *token_identifier_buf2(RootStruct *root_struct, TokenIndex token, bool *is_at_syntax) { - Error err; - const char *source = buf_ptr(root_struct->source_code); - size_t byte_offset = root_struct->token_locs[token].offset; - if (root_struct->token_ids[token] == TokenIdBuiltin) { - byte_offset += 1; - } else { - assert(root_struct->token_ids[token] == TokenIdIdentifier); - } - assert(source[byte_offset] != '.'); // wrong token index - - if (source[byte_offset] == '@') { - *is_at_syntax = true; - size_t bad_index; - Buf *str = buf_alloc(); - if ((err = source_string_literal_buf(source + byte_offset + 1, str, &bad_index))) { - ast_error_offset(root_struct, ErrColorAuto, token, bad_index + 1, - buf_create_from_str("invalid string literal character")); - } - return str; - } else { - *is_at_syntax = false; - size_t start = byte_offset; - for (;; byte_offset += 1) { - if (source[byte_offset] == 0) break; - if ((source[byte_offset] >= 'a' && source[byte_offset] <= 'z') || - (source[byte_offset] >= 'A' && source[byte_offset] <= 'Z') || - (source[byte_offset] >= '0' && source[byte_offset] <= '9') || - source[byte_offset] == '_') - { - continue; - } - break; - } - return buf_create_from_mem(source + start, byte_offset - start); - } -} - -Buf *token_identifier_buf(RootStruct *root_struct, TokenIndex token) { - bool trash; - return token_identifier_buf2(root_struct, token, &trash); -} - -Buf *node_identifier_buf(AstNode *node) { - bool trash; - return node_identifier_buf2(node, &trash); -} - -Buf *node_identifier_buf2(AstNode *node, bool *is_at_syntax) { - assert(node->type == NodeTypeIdentifier); - // Currently, stage1 runs astgen for every comptime function call, - // resulting the allocation here wasting memory. As a workaround until - // the code is adjusted to make astgen run only once per source node, - // we memoize the result into the AST here. - if (node->data.identifier.name == nullptr) { - RootStruct *root_struct = node->owner->data.structure.root_struct; - node->data.identifier.name = token_identifier_buf2(root_struct, node->main_token, - &node->data.identifier.is_at_syntax); - } - *is_at_syntax = node->data.identifier.is_at_syntax; - return node->data.identifier.name; -} - -void token_number_literal_bigint(RootStruct *root_struct, BigInt *result, TokenIndex token) { - const char *source = buf_ptr(root_struct->source_code); - uint32_t byte_offset = root_struct->token_locs[token].offset; - - bigint_init_unsigned(result, 0); - BigInt radix_bi; - - if (source[byte_offset] == '0') { - byte_offset += 1; - switch (source[byte_offset]) { - case 'b': - byte_offset += 1; - bigint_init_unsigned(&radix_bi, 2); - break; - case 'o': - byte_offset += 1; - bigint_init_unsigned(&radix_bi, 8); - break; - case 'x': - byte_offset += 1; - bigint_init_unsigned(&radix_bi, 16); - break; - default: - bigint_init_unsigned(&radix_bi, 10); - break; - } - } else { - bigint_init_unsigned(&radix_bi, 10); - } - - BigInt digit_value_bi = {}; - BigInt multiplied = {}; - - for (;source[byte_offset] != 0; byte_offset += 1) { - uint8_t digit; - if (source[byte_offset] >= '0' && source[byte_offset] <= '9') { - digit = source[byte_offset] - '0'; - } else if (source[byte_offset] >= 'a' && source[byte_offset] <= 'z') { - digit = source[byte_offset] - 'a' + 10; - } else if (source[byte_offset] >= 'A' && source[byte_offset] <= 'Z') { - digit = source[byte_offset] - 'A' + 10; - } else if (source[byte_offset] == '_') { - continue; - } else { - break; - } - bigint_deinit(&digit_value_bi); - bigint_init_unsigned(&digit_value_bi, digit); - - bigint_deinit(&multiplied); - bigint_mul(&multiplied, result, &radix_bi); - - bigint_add(result, &multiplied, &digit_value_bi); - } - - bigint_deinit(&digit_value_bi); - bigint_deinit(&multiplied); - bigint_deinit(&radix_bi); -} - diff --git a/src/stage1/parser.hpp b/src/stage1/parser.hpp deleted file mode 100644 index 065f951e91f6..000000000000 --- a/src/stage1/parser.hpp +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright (c) 2015 Andrew Kelley - * - * This file is part of zig, which is MIT licensed. - * See http://opensource.org/licenses/MIT - */ - -#ifndef ZIG_PARSER_HPP -#define ZIG_PARSER_HPP - -#include "all_types.hpp" -#include "tokenizer.hpp" -#include "errmsg.hpp" - -AstNode * ast_parse(Buf *buf, ZigType *owner, ErrColor err_color); - -void ast_visit_node_children(AstNode *node, void (*visit)(AstNode **, void *context), void *context); - -Buf *node_identifier_buf(AstNode *node); -Buf *node_identifier_buf2(AstNode *node, bool *is_at_syntax); - -Buf *token_identifier_buf(RootStruct *root_struct, TokenIndex token); - -void token_number_literal_bigint(RootStruct *root_struct, BigInt *result, TokenIndex token); - -Error source_string_literal_buf(const char *source, Buf *out, size_t *bad_index); -Error source_char_literal(const char *source, uint32_t *out, size_t *bad_index); - -#endif diff --git a/src/stage1/range_set.cpp b/src/stage1/range_set.cpp deleted file mode 100644 index 9e621d2f1305..000000000000 --- a/src/stage1/range_set.cpp +++ /dev/null @@ -1,74 +0,0 @@ -#include "range_set.hpp" - -AstNode *rangeset_add_range(RangeSet *rs, BigInt *first, BigInt *last, AstNode *source_node) { - for (size_t i = 0; i < rs->src_range_list.length; i += 1) { - RangeWithSrc *range_with_src = &rs->src_range_list.at(i); - Range *range = &range_with_src->range; - if ((bigint_cmp(first, &range->first) == CmpLT && bigint_cmp(last, &range->first) == CmpLT) || - (bigint_cmp(first, &range->last) == CmpGT && bigint_cmp(last, &range->last) == CmpGT)) - { - // first...last is completely before/after `range` - } - else - { - return range_with_src->source_node; - } - } - rs->src_range_list.append({{*first, *last}, source_node}); - - return nullptr; - -} - -static int compare_rangeset(const void *a, const void *b) { - const Range *r1 = &static_cast(a)->range; - const Range *r2 = &static_cast(b)->range; - // Assume no two ranges overlap - switch (bigint_cmp(&r1->first, &r2->first)) { - case CmpLT: return -1; - case CmpGT: return 1; - case CmpEQ: return 0; - } - zig_unreachable(); -} - -void rangeset_sort(RangeSet *rs) { - if (rs->src_range_list.length > 1) { - qsort(rs->src_range_list.items, rs->src_range_list.length, - sizeof(RangeWithSrc), compare_rangeset); - } -} - -bool rangeset_spans(RangeSet *rs, BigInt *first, BigInt *last) { - if (rs->src_range_list.length == 0) - return false; - - rangeset_sort(rs); - - const Range *first_range = &rs->src_range_list.at(0).range; - if (bigint_cmp(&first_range->first, first) != CmpEQ) - return false; - - const Range *last_range = &rs->src_range_list.last().range; - if (bigint_cmp(&last_range->last, last) != CmpEQ) - return false; - - BigInt one; - bigint_init_unsigned(&one, 1); - - // Make sure there are no holes in the first...last range - for (size_t i = 1; i < rs->src_range_list.length; i++) { - const Range *range = &rs->src_range_list.at(i).range; - const Range *prev_range = &rs->src_range_list.at(i - 1).range; - - assert(bigint_cmp(&prev_range->last, &range->first) == CmpLT); - - BigInt last_plus_one; - bigint_add(&last_plus_one, &prev_range->last, &one); - - if (bigint_cmp(&last_plus_one, &range->first) != CmpEQ) - return false; - } - - return true; -} diff --git a/src/stage1/range_set.hpp b/src/stage1/range_set.hpp deleted file mode 100644 index 9164a8b5c0a5..000000000000 --- a/src/stage1/range_set.hpp +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (c) 2017 Andrew Kelley - * - * This file is part of zig, which is MIT licensed. - * See http://opensource.org/licenses/MIT - */ - -#ifndef ZIG_RANGE_SET_HPP -#define ZIG_RANGE_SET_HPP - -#include "all_types.hpp" - -struct Range { - BigInt first; - BigInt last; -}; - -struct RangeWithSrc { - Range range; - AstNode *source_node; -}; - -struct RangeSet { - ZigList src_range_list; -}; - -AstNode *rangeset_add_range(RangeSet *rs, BigInt *first, BigInt *last, AstNode *source_node); -bool rangeset_spans(RangeSet *rs, BigInt *first, BigInt *last); - -#endif diff --git a/src/stage1/softfloat.hpp b/src/stage1/softfloat.hpp deleted file mode 100644 index b9d886d311d5..000000000000 --- a/src/stage1/softfloat.hpp +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright (c) 2017 Andrew Kelley - * - * This file is part of zig, which is MIT licensed. - * See http://opensource.org/licenses/MIT - */ - -#ifndef ZIG_SOFTFLOAT_HPP -#define ZIG_SOFTFLOAT_HPP - -extern "C" { -#include "softfloat.h" -} - -#include "zigendian.h" - -static inline float16_t zig_double_to_f16(double x) { - float64_t y; - static_assert(sizeof(x) == sizeof(y), ""); - memcpy(&y, &x, sizeof(x)); - return f64_to_f16(y); -} - -static inline void zig_double_to_extF80M(double x, extFloat80_t *result) { - float64_t y; - static_assert(sizeof(x) == sizeof(y), ""); - memcpy(&y, &x, sizeof(x)); - f64_to_extF80M(y, result); -} - -static inline void zig_double_to_f128M(double x, float128_t *result) { - float64_t y; - static_assert(sizeof(x) == sizeof(y), ""); - memcpy(&y, &x, sizeof(x)); - f64_to_f128M(y, result); -} - - -// Return value is safe to coerce to float even when |x| is NaN or Infinity. -static inline double zig_f16_to_double(float16_t x) { - float64_t y = f16_to_f64(x); - double z; - static_assert(sizeof(y) == sizeof(z), ""); - memcpy(&z, &y, sizeof(y)); - return z; -} - -static inline bool zig_f16_isNaN(float16_t a) { - union { uint16_t ui; float16_t f; } uA; - uA.f = a; - return 0x7C00 < (uA.ui & 0x7FFF); -} - -static inline bool zig_f128_isNaN(float128_t *aPtr) { - uint64_t hi, lo; - - #if defined(ZIG_BYTE_ORDER) && ZIG_BYTE_ORDER == ZIG_LITTLE_ENDIAN - hi = aPtr->v[1]; - lo = aPtr->v[0]; - #elif defined(ZIG_BYTE_ORDER) && ZIG_BYTE_ORDER == ZIG_BIG_ENDIAN - hi = aPtr->v[0]; - lo = aPtr->v[1]; - #else - #error Unsupported endian - #endif - - uint64_t absA64 = hi & UINT64_C(0x7FFFFFFFFFFFFFFF); - return - (UINT64_C(0x7FFF000000000000) < absA64) - || ((absA64 == UINT64_C(0x7FFF000000000000)) && lo); -} - -static inline bool zig_extF80_isNaN(extFloat80_t *aPtr) { - return (aPtr->signExp & 0x7FFF) == 0x7FFF && aPtr->signif & UINT64_C(0x7FFFFFFFFFFFFFFF); -} - -#endif diff --git a/src/stage1/softfloat_ext.cpp b/src/stage1/softfloat_ext.cpp deleted file mode 100644 index bb4c134d9ec7..000000000000 --- a/src/stage1/softfloat_ext.cpp +++ /dev/null @@ -1,71 +0,0 @@ -#include "softfloat_ext.hpp" -#include "zigendian.h" - -extern "C" { - #include "softfloat.h" -} - -void f128M_abs(const float128_t *aPtr, float128_t *zPtr) { - // Clear the sign bit. -#if ZIG_BYTE_ORDER == ZIG_LITTLE_ENDIAN - zPtr->v[1] = aPtr->v[1] & ~(UINT64_C(1) << 63); - zPtr->v[0] = aPtr->v[0]; -#elif ZIG_BYTE_ORDER == ZIG_BIG_ENDIAN - zPtr->v[0] = aPtr->v[0] & ~(UINT64_C(1) << 63); - zPtr->v[1] = aPtr->v[1]; -#else -#error Unsupported endian -#endif -} - -void f128M_trunc(const float128_t *aPtr, float128_t *zPtr) { - float128_t zero_float; - ui32_to_f128M(0, &zero_float); - if (f128M_lt(aPtr, &zero_float)) { - f128M_roundToInt(aPtr, softfloat_round_max, false, zPtr); - } else { - f128M_roundToInt(aPtr, softfloat_round_min, false, zPtr); - } -} - -void f128M_neg(const float128_t *aPtr, float128_t *zPtr) { - // Toggle the sign bit. -#if ZIG_BYTE_ORDER == ZIG_LITTLE_ENDIAN - zPtr->v[1] = aPtr->v[1] ^ (UINT64_C(1) << 63); - zPtr->v[0] = aPtr->v[0]; -#elif ZIG_BYTE_ORDER == ZIG_BIG_ENDIAN - zPtr->v[0] = aPtr->v[0] ^ (UINT64_C(1) << 63); - zPtr->v[1] = aPtr->v[1]; -#else -#error Unsupported endian -#endif -} - -void extF80M_abs(const extFloat80_t *aPtr, extFloat80_t *zPtr) { - // Clear the sign bit. - zPtr->signExp = aPtr->signExp & UINT16_C(0x7FFF); - zPtr->signif = aPtr->signif; -} - -void extF80M_trunc(const extFloat80_t *aPtr, extFloat80_t *zPtr) { - extFloat80_t zero_float; - ui32_to_extF80M(0, &zero_float); - if (extF80M_lt(aPtr, &zero_float)) { - extF80M_roundToInt(aPtr, softfloat_round_max, false, zPtr); - } else { - extF80M_roundToInt(aPtr, softfloat_round_min, false, zPtr); - } -} - -void extF80M_neg(const extFloat80_t *aPtr, extFloat80_t *zPtr) { - // Toggle the sign bit. - zPtr->signExp = aPtr->signExp ^ UINT16_C(0x8000); - zPtr->signif = aPtr->signif; -} - -float16_t f16_neg(const float16_t a) { - union { uint16_t ui; float16_t f; } uA; - // Toggle the sign bit. - uA.ui = a.v ^ (UINT16_C(1) << 15); - return uA.f; -} diff --git a/src/stage1/softfloat_ext.hpp b/src/stage1/softfloat_ext.hpp deleted file mode 100644 index 4e6fd753c892..000000000000 --- a/src/stage1/softfloat_ext.hpp +++ /dev/null @@ -1,16 +0,0 @@ -#ifndef ZIG_SOFTFLOAT_EXT_HPP -#define ZIG_SOFTFLOAT_EXT_HPP - -#include "softfloat_types.h" - -void f128M_abs(const float128_t *aPtr, float128_t *zPtr); -void f128M_trunc(const float128_t *aPtr, float128_t *zPtr); -void f128M_neg(const float128_t *aPtr, float128_t *zPtr); - -void extF80M_abs(const extFloat80_t *aPtr, extFloat80_t *zPtr); -void extF80M_trunc(const extFloat80_t *aPtr, extFloat80_t *zPtr); -void extF80M_neg(const extFloat80_t *aPtr, extFloat80_t *zPtr); - -float16_t f16_neg(const float16_t a); - -#endif \ No newline at end of file diff --git a/src/stage1/stage1.cpp b/src/stage1/stage1.cpp deleted file mode 100644 index 860d4ba4b143..000000000000 --- a/src/stage1/stage1.cpp +++ /dev/null @@ -1,131 +0,0 @@ -/* - * Copyright (c) 2020 Andrew Kelley - * - * This file is part of zig, which is MIT licensed. - * See http://opensource.org/licenses/MIT - */ - -#include "stage1.h" -#include "os.hpp" -#include "all_types.hpp" -#include "codegen.hpp" - -void zig_stage1_os_init(void) { - os_init(); - mem::init(); - init_all_targets(); -} - -struct ZigStage1 *zig_stage1_create(BuildMode optimize_mode, - const char *main_pkg_path_ptr, size_t main_pkg_path_len, - const char *root_src_path_ptr, size_t root_src_path_len, - const char *zig_lib_dir_ptr, size_t zig_lib_dir_len, - const ZigTarget *target, bool is_test_build) -{ - Buf *main_pkg_path = (main_pkg_path_len == 0) ? - nullptr : buf_create_from_mem(main_pkg_path_ptr, main_pkg_path_len); - Buf *root_src_path = buf_create_from_mem(root_src_path_ptr, root_src_path_len); - Buf *zig_lib_dir = buf_create_from_mem(zig_lib_dir_ptr, zig_lib_dir_len); - CodeGen *g = codegen_create(main_pkg_path, root_src_path, target, optimize_mode, - zig_lib_dir, is_test_build); - return &g->stage1; -} - -void zig_stage1_destroy(struct ZigStage1 *stage1) { - CodeGen *codegen = reinterpret_cast(stage1); - codegen_destroy(codegen); -} - -static void add_package(CodeGen *g, ZigStage1Pkg *stage1_pkg, ZigPackage *pkg) { - for (size_t i = 0; i < stage1_pkg->children_len; i += 1) { - ZigStage1Pkg *child_cli_pkg = stage1_pkg->children_ptr[i]; - - Buf *dirname = buf_alloc(); - Buf *basename = buf_alloc(); - os_path_split(buf_create_from_mem(child_cli_pkg->path_ptr, child_cli_pkg->path_len), dirname, basename); - - ZigPackage *child_pkg = codegen_create_package(g, buf_ptr(dirname), buf_ptr(basename), - buf_ptr(buf_sprintf("%s.%.*s", buf_ptr(&pkg->pkg_path), - (int)child_cli_pkg->name_len, child_cli_pkg->name_ptr))); - auto entry = pkg->package_table.put_unique( - buf_create_from_mem(child_cli_pkg->name_ptr, child_cli_pkg->name_len), - child_pkg); - if (entry) { - ZigPackage *existing_pkg = entry->value; - Buf *full_path = buf_alloc(); - os_path_join(&existing_pkg->root_src_dir, &existing_pkg->root_src_path, full_path); - fprintf(stderr, "Unable to add package '%.*s'->'%.*s': already exists as '%s'\n", - (int)child_cli_pkg->name_len, child_cli_pkg->name_ptr, - (int)child_cli_pkg->path_len, child_cli_pkg->path_ptr, - buf_ptr(full_path)); - exit(EXIT_FAILURE); - } - - add_package(g, child_cli_pkg, child_pkg); - } -} - -void zig_stage1_build_object(struct ZigStage1 *stage1) { - CodeGen *g = reinterpret_cast(stage1); - - g->root_out_name = buf_create_from_mem(stage1->root_name_ptr, stage1->root_name_len); - buf_init_from_mem(&g->o_file_output_path, stage1->emit_o_ptr, stage1->emit_o_len); - buf_init_from_mem(&g->h_file_output_path, stage1->emit_h_ptr, stage1->emit_h_len); - buf_init_from_mem(&g->asm_file_output_path, stage1->emit_asm_ptr, stage1->emit_asm_len); - buf_init_from_mem(&g->llvm_ir_file_output_path, stage1->emit_llvm_ir_ptr, stage1->emit_llvm_ir_len); - buf_init_from_mem(&g->bitcode_file_output_path, stage1->emit_bitcode_ptr, stage1->emit_bitcode_len); - - if (stage1->builtin_zig_path_len != 0) { - g->builtin_zig_path = buf_create_from_mem(stage1->builtin_zig_path_ptr, stage1->builtin_zig_path_len); - } - if (stage1->test_filter_len != 0) { - g->test_filter = buf_create_from_mem(stage1->test_filter_ptr, stage1->test_filter_len); - } - if (stage1->test_name_prefix_len != 0) { - g->test_name_prefix = buf_create_from_mem(stage1->test_name_prefix_ptr, stage1->test_name_prefix_len); - } - - g->link_mode_dynamic = stage1->link_mode_dynamic; - g->dll_export_fns = stage1->dll_export_fns; - g->have_pic = stage1->pic; - g->have_pie = stage1->pie; - g->have_lto = stage1->lto; - g->unwind_tables = stage1->unwind_tables; - g->have_stack_probing = stage1->enable_stack_probing; - g->red_zone = stage1->red_zone; - g->omit_frame_pointer = stage1->omit_frame_pointer; - g->is_single_threaded = stage1->is_single_threaded; - g->valgrind_enabled = stage1->valgrind_enabled; - g->tsan_enabled = stage1->tsan_enabled; - g->link_libc = stage1->link_libc; - g->link_libcpp = stage1->link_libcpp; - g->function_sections = stage1->function_sections; - g->include_compiler_rt = stage1->include_compiler_rt; - - g->subsystem = stage1->subsystem; - - g->enable_time_report = stage1->enable_time_report; - g->enable_stack_report = stage1->enable_stack_report; - g->test_is_evented = stage1->test_is_evented; - - g->verbose_ir = stage1->verbose_ir; - g->verbose_llvm_ir = stage1->verbose_llvm_ir; - g->verbose_cimport = stage1->verbose_cimport; - g->verbose_llvm_cpu_features = stage1->verbose_llvm_cpu_features; - - g->err_color = stage1->err_color; - g->code_model = stage1->code_model; - - { - g->strip_debug_symbols = stage1->strip; - if (!target_has_debug_info(g->zig_target)) { - g->strip_debug_symbols = true; - } - } - - g->main_progress_node = stage1->main_progress_node; - - add_package(g, stage1->main_pkg, g->main_pkg); - - codegen_build_object(g); -} diff --git a/src/stage1/stage1.h b/src/stage1/stage1.h deleted file mode 100644 index c8af8b9688b3..000000000000 --- a/src/stage1/stage1.h +++ /dev/null @@ -1,230 +0,0 @@ -/* - * Copyright (c) 2020 Andrew Kelley - * - * This file is part of zig, which is MIT licensed. - * See http://opensource.org/licenses/MIT - */ - -// This file deals with exposing stage1 C++ code to stage2 Zig code. - -#ifndef ZIG_STAGE1_H -#define ZIG_STAGE1_H - -#include "zig_llvm.h" - -#include - -#ifdef __cplusplus -#define ZIG_EXTERN_C extern "C" -#else -#define ZIG_EXTERN_C -#endif - -// ABI warning -enum ErrColor { - ErrColorAuto, - ErrColorOff, - ErrColorOn, -}; - -// ABI warning -enum CodeModel { - CodeModelDefault, - CodeModelTiny, - CodeModelSmall, - CodeModelKernel, - CodeModelMedium, - CodeModelLarge, -}; - -// ABI warning -enum TargetSubsystem { - TargetSubsystemConsole, - TargetSubsystemWindows, - TargetSubsystemPosix, - TargetSubsystemNative, - TargetSubsystemEfiApplication, - TargetSubsystemEfiBootServiceDriver, - TargetSubsystemEfiRom, - TargetSubsystemEfiRuntimeDriver, - - // This means Zig should infer the subsystem. - // It's last so that the indexes of other items can line up - // with the enum in builtin.zig. - TargetSubsystemAuto -}; - - -// ABI warning -// Synchronize with std.Target.Os.Tag and target.cpp::os_list -enum Os { - OsFreestanding, - OsAnanas, - OsCloudABI, - OsDragonFly, - OsFreeBSD, - OsFuchsia, - OsIOS, - OsKFreeBSD, - OsLinux, - OsLv2, // PS3 - OsMacOSX, - OsNetBSD, - OsOpenBSD, - OsSolaris, - OsWindows, - OsZOS, - OsHaiku, - OsMinix, - OsRTEMS, - OsNaCl, // Native Client - OsAIX, - OsCUDA, // NVIDIA CUDA - OsNVCL, // NVIDIA OpenCL - OsAMDHSA, // AMD HSA Runtime - OsPS4, - OsPS5, - OsELFIAMCU, - OsTvOS, // Apple tvOS - OsWatchOS, // Apple watchOS - OsDriverKit, // Apple DriverKit - OsMesa3D, - OsContiki, - OsAMDPAL, - OsHermitCore, - OsHurd, - OsWASI, - OsEmscripten, - OsShaderModel, // DirectX ShaderModel - OsUefi, - OsOpenCL, - OsGLSL450, - OsVulkan, - OsPlan9, - OsOther, -}; - -// ABI warning -struct ZigTarget { - enum ZigLLVM_ArchType arch; - enum Os os; - enum ZigLLVM_EnvironmentType abi; - - bool is_native_os; - bool is_native_cpu; - - const char *llvm_cpu_name; - const char *llvm_cpu_features; - const char *llvm_target_abi; -}; - -// ABI warning -struct Stage2Progress; -// ABI warning -struct Stage2ProgressNode; - -enum BuildMode { - BuildModeDebug, - BuildModeSafeRelease, - BuildModeFastRelease, - BuildModeSmallRelease, -}; - - -struct ZigStage1Pkg { - const char *name_ptr; - size_t name_len; - - const char *path_ptr; - size_t path_len; - - struct ZigStage1Pkg **children_ptr; - size_t children_len; - - struct ZigStage1Pkg *parent; -}; - -// This struct is used by both main.cpp and stage1.zig. -struct ZigStage1 { - const char *root_name_ptr; - size_t root_name_len; - - const char *emit_o_ptr; - size_t emit_o_len; - - const char *emit_h_ptr; - size_t emit_h_len; - - const char *emit_asm_ptr; - size_t emit_asm_len; - - const char *emit_llvm_ir_ptr; - size_t emit_llvm_ir_len; - - const char *emit_bitcode_ptr; - size_t emit_bitcode_len; - - const char *builtin_zig_path_ptr; - size_t builtin_zig_path_len; - - const char *test_filter_ptr; - size_t test_filter_len; - - const char *test_name_prefix_ptr; - size_t test_name_prefix_len; - - void *userdata; - struct ZigStage1Pkg *main_pkg; - struct Stage2ProgressNode *main_progress_node; - - enum CodeModel code_model; - enum TargetSubsystem subsystem; - enum ErrColor err_color; - - bool pic; - bool pie; - bool lto; - bool unwind_tables; - bool link_libc; - bool link_libcpp; - bool strip; - bool is_single_threaded; - bool dll_export_fns; - bool link_mode_dynamic; - bool valgrind_enabled; - bool tsan_enabled; - bool function_sections; - bool include_compiler_rt; - bool enable_stack_probing; - bool red_zone; - bool omit_frame_pointer; - bool enable_time_report; - bool enable_stack_report; - bool test_is_evented; - bool verbose_ir; - bool verbose_llvm_ir; - bool verbose_cimport; - bool verbose_llvm_cpu_features; - - // Set by stage1 - bool have_c_main; - bool have_winmain; - bool have_wwinmain; - bool have_winmain_crt_startup; - bool have_wwinmain_crt_startup; - bool have_dllmain_crt_startup; -}; - -ZIG_EXTERN_C void zig_stage1_os_init(void); - -ZIG_EXTERN_C struct ZigStage1 *zig_stage1_create(enum BuildMode optimize_mode, - const char *main_pkg_path_ptr, size_t main_pkg_path_len, - const char *root_src_path_ptr, size_t root_src_path_len, - const char *zig_lib_dir_ptr, size_t zig_lib_dir_len, - const struct ZigTarget *target, bool is_test_build); - -ZIG_EXTERN_C void zig_stage1_build_object(struct ZigStage1 *); - -ZIG_EXTERN_C void zig_stage1_destroy(struct ZigStage1 *); - -#endif diff --git a/src/stage1/stage2.h b/src/stage1/stage2.h deleted file mode 100644 index 58b3a7687f05..000000000000 --- a/src/stage1/stage2.h +++ /dev/null @@ -1,188 +0,0 @@ -/* - * Copyright (c) 2019 Andrew Kelley - * - * This file is part of zig, which is MIT licensed. - * See http://opensource.org/licenses/MIT - */ - -// This file deals with exposing stage2 Zig code to stage1 C++ code. - -#ifndef ZIG_STAGE2_H -#define ZIG_STAGE2_H - -#include -#include -#include - -#include "stage1.h" - -#ifdef __cplusplus -#define ZIG_EXTERN_C extern "C" -#else -#define ZIG_EXTERN_C -#endif - -#if defined(_MSC_VER) -#define ZIG_ATTRIBUTE_NORETURN __declspec(noreturn) -#else -#define ZIG_ATTRIBUTE_NORETURN __attribute__((noreturn)) -#endif - -// ABI warning: the types and declarations in this file must match both those in -// stage2.cpp and src/stage1.zig. - -// ABI warning -enum Error { - ErrorNone, - ErrorNoMem, - ErrorInvalidFormat, - ErrorSemanticAnalyzeFail, - ErrorAccess, - ErrorInterrupted, - ErrorSystemResources, - ErrorFileNotFound, - ErrorFileSystem, - ErrorFileTooBig, - ErrorDivByZero, - ErrorOverflow, - ErrorPathAlreadyExists, - ErrorUnexpected, - ErrorExactDivRemainder, - ErrorNegativeDenominator, - ErrorShiftedOutOneBits, - ErrorCCompileErrors, - ErrorEndOfFile, - ErrorIsDir, - ErrorNotDir, - ErrorUnsupportedOperatingSystem, - ErrorSharingViolation, - ErrorPipeBusy, - ErrorPrimitiveTypeNotFound, - ErrorCacheUnavailable, - ErrorPathTooLong, - ErrorCCompilerCannotFindFile, - ErrorNoCCompilerInstalled, - ErrorReadingDepFile, - ErrorInvalidDepFile, - ErrorMissingArchitecture, - ErrorMissingOperatingSystem, - ErrorUnknownArchitecture, - ErrorUnknownOperatingSystem, - ErrorUnknownABI, - ErrorInvalidFilename, - ErrorDiskQuota, - ErrorDiskSpace, - ErrorUnexpectedWriteFailure, - ErrorUnexpectedSeekFailure, - ErrorUnexpectedFileTruncationFailure, - ErrorUnimplemented, - ErrorOperationAborted, - ErrorBrokenPipe, - ErrorNoSpaceLeft, - ErrorNotLazy, - ErrorIsAsync, - ErrorImportOutsidePkgPath, - ErrorUnknownCpu, - ErrorUnknownCpuFeature, - ErrorInvalidCpuFeatures, - ErrorInvalidLlvmCpuFeaturesFormat, - ErrorUnknownApplicationBinaryInterface, - ErrorASTUnitFailure, - ErrorBadPathName, - ErrorSymLinkLoop, - ErrorProcessFdQuotaExceeded, - ErrorSystemFdQuotaExceeded, - ErrorNoDevice, - ErrorDeviceBusy, - ErrorUnableToSpawnCCompiler, - ErrorCCompilerExitCode, - ErrorCCompilerCrashed, - ErrorCCompilerCannotFindHeaders, - ErrorLibCRuntimeNotFound, - ErrorLibCStdLibHeaderNotFound, - ErrorLibCKernel32LibNotFound, - ErrorUnsupportedArchitecture, - ErrorWindowsSdkNotFound, - ErrorUnknownDynamicLinkerPath, - ErrorTargetHasNoDynamicLinker, - ErrorInvalidAbiVersion, - ErrorInvalidOperatingSystemVersion, - ErrorUnknownClangOption, - ErrorNestedResponseFile, - ErrorZigIsTheCCompiler, - ErrorFileBusy, - ErrorLocked, - ErrorInvalidCharacter, - ErrorUnicodePointTooLarge, -}; - -// ABI warning -struct Stage2ErrorMsg { - const char *filename_ptr; // can be null - size_t filename_len; - const char *msg_ptr; - size_t msg_len; - const char *source; // valid until the ASTUnit is freed. can be null - unsigned line; // 0 based - unsigned column; // 0 based - unsigned offset; // byte offset into source -}; - -// ABI warning -ZIG_EXTERN_C ZIG_ATTRIBUTE_NORETURN void stage2_panic(const char *ptr, size_t len); - -// ABI warning -ZIG_EXTERN_C struct Stage2Progress *stage2_progress_create(void); -// ABI warning -ZIG_EXTERN_C void stage2_progress_disable_tty(struct Stage2Progress *progress); -// ABI warning -ZIG_EXTERN_C void stage2_progress_destroy(struct Stage2Progress *progress); -// ABI warning -ZIG_EXTERN_C struct Stage2ProgressNode *stage2_progress_start_root(struct Stage2Progress *progress, - const char *name_ptr, size_t name_len, size_t estimated_total_items); -// ABI warning -ZIG_EXTERN_C struct Stage2ProgressNode *stage2_progress_start(struct Stage2ProgressNode *node, - const char *name_ptr, size_t name_len, size_t estimated_total_items); -// ABI warning -ZIG_EXTERN_C void stage2_progress_end(struct Stage2ProgressNode *node); -// ABI warning -ZIG_EXTERN_C void stage2_progress_complete_one(struct Stage2ProgressNode *node); -// ABI warning -ZIG_EXTERN_C void stage2_progress_update_node(struct Stage2ProgressNode *node, - size_t completed_count, size_t estimated_total_items); - -// ABI warning -struct Stage2SemVer { - uint32_t major; - uint32_t minor; - uint32_t patch; -}; - -// ABI warning -ZIG_EXTERN_C const char *stage2_version_string(void); - -// ABI warning -ZIG_EXTERN_C Stage2SemVer stage2_version(void); - -// ABI warning -ZIG_EXTERN_C enum Error stage2_target_parse(struct ZigTarget *target, const char *zig_triple, const char *mcpu, - const char *dynamic_linker); - -// ABI warning -ZIG_EXTERN_C const char *stage2_fetch_file(struct ZigStage1 *stage1, const char *path_ptr, size_t path_len, - size_t *result_len); - -// ABI warning -ZIG_EXTERN_C Error stage2_cimport(struct ZigStage1 *stage1, const char *c_src_ptr, size_t c_src_len, - const char **out_zig_path_ptr, size_t *out_zig_path_len, - struct Stage2ErrorMsg **out_errors_ptr, size_t *out_errors_len); - -// ABI warning -ZIG_EXTERN_C const char *stage2_add_link_lib(struct ZigStage1 *stage1, - const char *lib_name_ptr, size_t lib_name_len, - const char *symbol_name_ptr, size_t symbol_name_len); - -// ABI warning -ZIG_EXTERN_C enum Error stage2_append_symbol(struct ZigStage1 *stage1, const char *name_ptr, size_t name_len); - -#endif diff --git a/src/stage1/target.cpp b/src/stage1/target.cpp deleted file mode 100644 index dfd91bed8aba..000000000000 --- a/src/stage1/target.cpp +++ /dev/null @@ -1,1165 +0,0 @@ -/* - * Copyright (c) 2016 Andrew Kelley - * - * This file is part of zig, which is MIT licensed. - * See http://opensource.org/licenses/MIT - */ - -#include "buffer.hpp" -#include "error.hpp" -#include "target.hpp" -#include "util.hpp" -#include "os.hpp" - -#include - -static const ZigLLVM_ArchType arch_list[] = { - ZigLLVM_arm, // ARM (little endian): arm, armv.*, xscale - ZigLLVM_armeb, // ARM (big endian): armeb - ZigLLVM_aarch64, // AArch64 (little endian): aarch64 - ZigLLVM_aarch64_be, // AArch64 (big endian): aarch64_be - ZigLLVM_aarch64_32, // AArch64 (little endian) ILP32: aarch64_32 - ZigLLVM_arc, // ARC: Synopsys ARC - ZigLLVM_avr, // AVR: Atmel AVR microcontroller - ZigLLVM_bpfel, // eBPF or extended BPF or 64-bit BPF (little endian) - ZigLLVM_bpfeb, // eBPF or extended BPF or 64-bit BPF (big endian) - ZigLLVM_csky, // CSKY: csky - ZigLLVM_dxil, // DXIL 32-bit DirectX bytecode - ZigLLVM_hexagon, // Hexagon: hexagon - ZigLLVM_loongarch32, // LoongArch (32-bit): loongarch32 - ZigLLVM_loongarch64, // LoongArch (64-bit): loongarch64 - ZigLLVM_m68k, // M68k: Motorola 680x0 family - ZigLLVM_mips, // MIPS: mips, mipsallegrex, mipsr6 - ZigLLVM_mipsel, // MIPSEL: mipsel, mipsallegrexe, mipsr6el - ZigLLVM_mips64, // MIPS64: mips64, mips64r6, mipsn32, mipsn32r6 - ZigLLVM_mips64el, // MIPS64EL: mips64el, mips64r6el, mipsn32el, mipsn32r6el - ZigLLVM_msp430, // MSP430: msp430 - ZigLLVM_ppc, // PPC: powerpc - ZigLLVM_ppcle, // PPCLE: powerpc (little endian) - ZigLLVM_ppc64, // PPC64: powerpc64, ppu - ZigLLVM_ppc64le, // PPC64LE: powerpc64le - ZigLLVM_r600, // R600: AMD GPUs HD2XXX - HD6XXX - ZigLLVM_amdgcn, // AMDGCN: AMD GCN GPUs - ZigLLVM_riscv32, // RISC-V (32-bit): riscv32 - ZigLLVM_riscv64, // RISC-V (64-bit): riscv64 - ZigLLVM_sparc, // Sparc: sparc - ZigLLVM_sparcv9, // Sparcv9: Sparcv9 - ZigLLVM_sparcel, // Sparc: (endianness = little). NB: 'Sparcle' is a CPU variant - ZigLLVM_systemz, // SystemZ: s390x - ZigLLVM_tce, // TCE (http://tce.cs.tut.fi/): tce - ZigLLVM_tcele, // TCE little endian (http://tce.cs.tut.fi/): tcele - ZigLLVM_thumb, // Thumb (little endian): thumb, thumbv.* - ZigLLVM_thumbeb, // Thumb (big endian): thumbeb - ZigLLVM_x86, // X86: i[3-9]86 - ZigLLVM_x86_64, // X86-64: amd64, x86_64 - ZigLLVM_xcore, // XCore: xcore - ZigLLVM_nvptx, // NVPTX: 32-bit - ZigLLVM_nvptx64, // NVPTX: 64-bit - ZigLLVM_le32, // le32: generic little-endian 32-bit CPU (PNaCl) - ZigLLVM_le64, // le64: generic little-endian 64-bit CPU (PNaCl) - ZigLLVM_amdil, // AMDIL - ZigLLVM_amdil64, // AMDIL with 64-bit pointers - ZigLLVM_hsail, // AMD HSAIL - ZigLLVM_hsail64, // AMD HSAIL with 64-bit pointers - ZigLLVM_spir, // SPIR: standard portable IR for OpenCL 32-bit version - ZigLLVM_spir64, // SPIR: standard portable IR for OpenCL 64-bit version - ZigLLVM_spirv32, // SPIR-V with 32-bit pointers - ZigLLVM_spirv64, // SPIR-V with 64-bit pointers - ZigLLVM_kalimba, // Kalimba: generic kalimba - ZigLLVM_shave, // SHAVE: Movidius vector VLIW processors - ZigLLVM_lanai, // Lanai: Lanai 32-bit - ZigLLVM_wasm32, // WebAssembly with 32-bit pointers - ZigLLVM_wasm64, // WebAssembly with 64-bit pointers - ZigLLVM_renderscript32, // 32-bit RenderScript - ZigLLVM_renderscript64, // 64-bit RenderScript - ZigLLVM_ve, // NEC SX-Aurora Vector Engine -}; - -static const ZigLLVM_VendorType vendor_list[] = { - ZigLLVM_Apple, - ZigLLVM_PC, - ZigLLVM_SCEI, - ZigLLVM_Freescale, - ZigLLVM_IBM, - ZigLLVM_ImaginationTechnologies, - ZigLLVM_MipsTechnologies, - ZigLLVM_NVIDIA, - ZigLLVM_CSR, - ZigLLVM_Myriad, - ZigLLVM_AMD, - ZigLLVM_Mesa, - ZigLLVM_SUSE, -}; - -static const Os os_list[] = { - OsFreestanding, - OsAnanas, - OsCloudABI, - OsDragonFly, - OsFreeBSD, - OsFuchsia, - OsIOS, - OsKFreeBSD, - OsLinux, - OsLv2, // PS3 - OsMacOSX, - OsNetBSD, - OsOpenBSD, - OsSolaris, - OsWindows, - OsZOS, - OsHaiku, - OsMinix, - OsRTEMS, - OsNaCl, // Native Client - OsAIX, - OsCUDA, // NVIDIA CUDA - OsNVCL, // NVIDIA OpenCL - OsAMDHSA, // AMD HSA Runtime - OsPS4, - OsPS5, - OsELFIAMCU, - OsTvOS, // Apple tvOS - OsWatchOS, // Apple watchOS - OsDriverKit, // Apple DriverKit - OsMesa3D, - OsContiki, - OsAMDPAL, - OsHermitCore, - OsHurd, - OsWASI, - OsEmscripten, - OsShaderModel, // DirectX ShaderModel - OsUefi, - OsOpenCL, - OsGLSL450, - OsVulkan, - OsPlan9, - OsOther, -}; - -// Coordinate with zig_llvm.h -static const ZigLLVM_EnvironmentType abi_list[] = { - ZigLLVM_UnknownEnvironment, - - ZigLLVM_GNU, - ZigLLVM_GNUABIN32, - ZigLLVM_GNUABI64, - ZigLLVM_GNUEABI, - ZigLLVM_GNUEABIHF, - ZigLLVM_GNUX32, - ZigLLVM_GNUILP32, - ZigLLVM_CODE16, - ZigLLVM_EABI, - ZigLLVM_EABIHF, - ZigLLVM_Android, - ZigLLVM_Musl, - ZigLLVM_MuslEABI, - ZigLLVM_MuslEABIHF, - ZigLLVM_MuslX32, - - ZigLLVM_MSVC, - ZigLLVM_Itanium, - ZigLLVM_Cygnus, - ZigLLVM_CoreCLR, - ZigLLVM_Simulator, // Simulator variants of other systems, e.g., Apple's iOS - ZigLLVM_MacABI, // Mac Catalyst variant of Apple's iOS deployment target. - - ZigLLVM_Pixel, - ZigLLVM_Vertex, - ZigLLVM_Geometry, - ZigLLVM_Hull, - ZigLLVM_Domain, - ZigLLVM_Compute, - ZigLLVM_Library, - ZigLLVM_RayGeneration, - ZigLLVM_Intersection, - ZigLLVM_AnyHit, - ZigLLVM_ClosestHit, - ZigLLVM_Miss, - ZigLLVM_Callable, - ZigLLVM_Mesh, - ZigLLVM_Amplification, -}; - -static const ZigLLVM_ObjectFormatType oformat_list[] = { - ZigLLVM_UnknownObjectFormat, - ZigLLVM_COFF, - ZigLLVM_DXContainer, - ZigLLVM_ELF, - ZigLLVM_GOFF, - ZigLLVM_MachO, - ZigLLVM_SPIRV, - ZigLLVM_Wasm, - ZigLLVM_XCOFF, -}; - -size_t target_oformat_count(void) { - return array_length(oformat_list); -} - -ZigLLVM_ObjectFormatType target_oformat_enum(size_t index) { - assert(index < array_length(oformat_list)); - return oformat_list[index]; -} - -const char *target_oformat_name(ZigLLVM_ObjectFormatType oformat) { - switch (oformat) { - case ZigLLVM_UnknownObjectFormat: return "unknown"; - case ZigLLVM_COFF: return "coff"; - case ZigLLVM_DXContainer: return "dxcontainer"; - case ZigLLVM_ELF: return "elf"; - case ZigLLVM_GOFF: return "goff"; - case ZigLLVM_MachO: return "macho"; - case ZigLLVM_SPIRV: return "spirv"; - case ZigLLVM_Wasm: return "wasm"; - case ZigLLVM_XCOFF: return "xcoff"; - } - zig_unreachable(); -} - -size_t target_arch_count(void) { - return array_length(arch_list); -} - -ZigLLVM_ArchType target_arch_enum(size_t index) { - assert(index < array_length(arch_list)); - return arch_list[index]; -} - -size_t target_vendor_count(void) { - return array_length(vendor_list); -} - -ZigLLVM_VendorType target_vendor_enum(size_t index) { - assert(index < array_length(vendor_list)); - return vendor_list[index]; -} - -size_t target_os_count(void) { - return array_length(os_list); -} -Os target_os_enum(size_t index) { - assert(index < array_length(os_list)); - return os_list[index]; -} - -ZigLLVM_OSType get_llvm_os_type(Os os_type) { - switch (os_type) { - case OsFreestanding: - case OsOpenCL: - case OsGLSL450: - case OsVulkan: - case OsPlan9: - case OsOther: - return ZigLLVM_UnknownOS; - case OsAnanas: - return ZigLLVM_Ananas; - case OsCloudABI: - return ZigLLVM_CloudABI; - case OsDragonFly: - return ZigLLVM_DragonFly; - case OsFreeBSD: - return ZigLLVM_FreeBSD; - case OsFuchsia: - return ZigLLVM_Fuchsia; - case OsIOS: - return ZigLLVM_IOS; - case OsKFreeBSD: - return ZigLLVM_KFreeBSD; - case OsLinux: - return ZigLLVM_Linux; - case OsLv2: - return ZigLLVM_Lv2; - case OsMacOSX: - return ZigLLVM_MacOSX; - case OsNetBSD: - return ZigLLVM_NetBSD; - case OsOpenBSD: - return ZigLLVM_OpenBSD; - case OsSolaris: - return ZigLLVM_Solaris; - case OsWindows: - case OsUefi: - return ZigLLVM_Win32; - case OsZOS: - return ZigLLVM_ZOS; - case OsHaiku: - return ZigLLVM_Haiku; - case OsMinix: - return ZigLLVM_Minix; - case OsRTEMS: - return ZigLLVM_RTEMS; - case OsNaCl: - return ZigLLVM_NaCl; - case OsAIX: - return ZigLLVM_AIX; - case OsCUDA: - return ZigLLVM_CUDA; - case OsNVCL: - return ZigLLVM_NVCL; - case OsAMDHSA: - return ZigLLVM_AMDHSA; - case OsPS4: - return ZigLLVM_PS4; - case OsPS5: - return ZigLLVM_PS5; - case OsELFIAMCU: - return ZigLLVM_ELFIAMCU; - case OsTvOS: - return ZigLLVM_TvOS; - case OsWatchOS: - return ZigLLVM_WatchOS; - case OsDriverKit: - return ZigLLVM_DriverKit; - case OsMesa3D: - return ZigLLVM_Mesa3D; - case OsContiki: - return ZigLLVM_Contiki; - case OsAMDPAL: - return ZigLLVM_AMDPAL; - case OsHermitCore: - return ZigLLVM_HermitCore; - case OsHurd: - return ZigLLVM_Hurd; - case OsWASI: - return ZigLLVM_WASI; - case OsEmscripten: - return ZigLLVM_Emscripten; - case OsShaderModel: - return ZigLLVM_ShaderModel; - } - zig_unreachable(); -} - -const char *target_os_name(Os os_type) { - switch (os_type) { - case OsFreestanding: - return "freestanding"; - case OsPlan9: - return "plan9"; - case OsUefi: - return "uefi"; - case OsOther: - return "other"; - case OsAnanas: - case OsCloudABI: - case OsDragonFly: - case OsFreeBSD: - case OsFuchsia: - case OsIOS: - case OsKFreeBSD: - case OsLinux: - case OsLv2: // PS3 - case OsMacOSX: - case OsNetBSD: - case OsOpenBSD: - case OsSolaris: - case OsWindows: - case OsZOS: - case OsHaiku: - case OsMinix: - case OsRTEMS: - case OsNaCl: // Native Client - case OsAIX: - case OsCUDA: // NVIDIA CUDA - case OsNVCL: // NVIDIA OpenCL - case OsAMDHSA: // AMD HSA Runtime - case OsPS4: - case OsPS5: - case OsELFIAMCU: - case OsTvOS: // Apple tvOS - case OsWatchOS: // Apple watchOS - case OsDriverKit: - case OsMesa3D: - case OsContiki: - case OsAMDPAL: - case OsHermitCore: - case OsHurd: - case OsWASI: - case OsEmscripten: - case OsShaderModel: - case OsOpenCL: - case OsGLSL450: - case OsVulkan: - return ZigLLVMGetOSTypeName(get_llvm_os_type(os_type)); - } - zig_unreachable(); -} - -size_t target_abi_count(void) { - return array_length(abi_list); -} -ZigLLVM_EnvironmentType target_abi_enum(size_t index) { - assert(index < array_length(abi_list)); - return abi_list[index]; -} -const char *target_abi_name(ZigLLVM_EnvironmentType abi) { - if (abi == ZigLLVM_UnknownEnvironment) - return "none"; - return ZigLLVMGetEnvironmentTypeName(abi); -} - -Error target_parse_arch(ZigLLVM_ArchType *out_arch, const char *arch_ptr, size_t arch_len) { - *out_arch = ZigLLVM_UnknownArch; - for (size_t arch_i = 0; arch_i < array_length(arch_list); arch_i += 1) { - ZigLLVM_ArchType arch = arch_list[arch_i]; - if (mem_eql_str(arch_ptr, arch_len, target_arch_name(arch))) { - *out_arch = arch; - return ErrorNone; - } - } - return ErrorUnknownArchitecture; -} - -Error target_parse_os(Os *out_os, const char *os_ptr, size_t os_len) { - if (mem_eql_str(os_ptr, os_len, "native")) { -#if defined(ZIG_OS_DARWIN) - *out_os = OsMacOSX; - return ErrorNone; -#elif defined(ZIG_OS_WINDOWS) - *out_os = OsWindows; - return ErrorNone; -#elif defined(ZIG_OS_LINUX) - *out_os = OsLinux; - return ErrorNone; -#elif defined(ZIG_OS_FREEBSD) - *out_os = OsFreeBSD; - return ErrorNone; -#elif defined(ZIG_OS_NETBSD) - *out_os = OsNetBSD; - return ErrorNone; -#elif defined(ZIG_OS_DRAGONFLY) - *out_os = OsDragonFly; - return ErrorNone; -#elif defined(ZIG_OS_OPENBSD) - *out_os = OsOpenBSD; - return ErrorNone; -#elif defined(ZIG_OS_HAIKU) - *out_os = OsHaiku; - return ErrorNone; -#elif defined(ZIG_OS_SOLARIS) - *out_os = OsSolaris; - return ErrorNone; -#else - zig_panic("stage1 is unable to detect native target for this OS"); -#endif - } - - for (size_t i = 0; i < array_length(os_list); i += 1) { - Os os = os_list[i]; - const char *os_name = target_os_name(os); - if (mem_eql_str(os_ptr, os_len, os_name)) { - *out_os = os; - return ErrorNone; - } - } - return ErrorUnknownOperatingSystem; -} - -Error target_parse_abi(ZigLLVM_EnvironmentType *out_abi, const char *abi_ptr, size_t abi_len) { - for (size_t i = 0; i < array_length(abi_list); i += 1) { - ZigLLVM_EnvironmentType abi = abi_list[i]; - const char *abi_name = target_abi_name(abi); - if (mem_eql_str(abi_ptr, abi_len, abi_name)) { - *out_abi = abi; - return ErrorNone; - } - } - return ErrorUnknownABI; -} - -const char *target_arch_name(ZigLLVM_ArchType arch) { - return ZigLLVMGetArchTypeName(arch); -} - -void init_all_targets(void) { - LLVMInitializeAllTargets(); - LLVMInitializeAllTargetInfos(); - LLVMInitializeAllTargetMCs(); - LLVMInitializeAllAsmPrinters(); - LLVMInitializeAllAsmParsers(); -} - -void target_triple_zig(Buf *triple, const ZigTarget *target) { - buf_resize(triple, 0); - buf_appendf(triple, "%s-%s-%s", - target_arch_name(target->arch), - target_os_name(target->os), - target_abi_name(target->abi)); -} - -void target_triple_llvm(Buf *triple, const ZigTarget *target) { - buf_resize(triple, 0); - buf_appendf(triple, "%s-%s-%s-%s", - ZigLLVMGetArchTypeName(target->arch), - ZigLLVMGetVendorTypeName(ZigLLVM_UnknownVendor), - ZigLLVMGetOSTypeName(get_llvm_os_type(target->os)), - ZigLLVMGetEnvironmentTypeName(target->abi)); -} - -bool target_os_is_darwin(Os os) { - switch (os) { - case OsMacOSX: - case OsIOS: - case OsWatchOS: - case OsTvOS: - return true; - default: - return false; - } -} - -ZigLLVM_ObjectFormatType target_object_format(const ZigTarget *target) { - if (target->os == OsUefi || target->os == OsWindows) { - return ZigLLVM_COFF; - } else if (target_os_is_darwin(target->os)) { - return ZigLLVM_MachO; - } - if (target->arch == ZigLLVM_wasm32 || - target->arch == ZigLLVM_wasm64) - { - return ZigLLVM_Wasm; - } - return ZigLLVM_ELF; -} - -// See lib/Support/Triple.cpp in LLVM for the source of this data. -// getArchPointerBitWidth -uint32_t target_arch_pointer_bit_width(ZigLLVM_ArchType arch) { - switch (arch) { - case ZigLLVM_UnknownArch: - return 0; - - case ZigLLVM_avr: - case ZigLLVM_msp430: - return 16; - - case ZigLLVM_arc: - case ZigLLVM_arm: - case ZigLLVM_armeb: - case ZigLLVM_hexagon: - case ZigLLVM_m68k: - case ZigLLVM_le32: - case ZigLLVM_mips: - case ZigLLVM_mipsel: - case ZigLLVM_nvptx: - case ZigLLVM_ppc: - case ZigLLVM_ppcle: - case ZigLLVM_r600: - case ZigLLVM_riscv32: - case ZigLLVM_sparc: - case ZigLLVM_sparcel: - case ZigLLVM_tce: - case ZigLLVM_tcele: - case ZigLLVM_thumb: - case ZigLLVM_thumbeb: - case ZigLLVM_x86: - case ZigLLVM_xcore: - case ZigLLVM_amdil: - case ZigLLVM_hsail: - case ZigLLVM_spir: - case ZigLLVM_kalimba: - case ZigLLVM_lanai: - case ZigLLVM_shave: - case ZigLLVM_wasm32: - case ZigLLVM_renderscript32: - case ZigLLVM_aarch64_32: - case ZigLLVM_csky: - case ZigLLVM_spirv32: - case ZigLLVM_loongarch32: - case ZigLLVM_dxil: - return 32; - - case ZigLLVM_aarch64: - case ZigLLVM_aarch64_be: - case ZigLLVM_amdgcn: - case ZigLLVM_bpfel: - case ZigLLVM_bpfeb: - case ZigLLVM_le64: - case ZigLLVM_mips64: - case ZigLLVM_mips64el: - case ZigLLVM_nvptx64: - case ZigLLVM_ppc64: - case ZigLLVM_ppc64le: - case ZigLLVM_riscv64: - case ZigLLVM_sparcv9: - case ZigLLVM_systemz: - case ZigLLVM_x86_64: - case ZigLLVM_amdil64: - case ZigLLVM_hsail64: - case ZigLLVM_spir64: - case ZigLLVM_wasm64: - case ZigLLVM_renderscript64: - case ZigLLVM_ve: - case ZigLLVM_spirv64: - case ZigLLVM_loongarch64: - return 64; - } - zig_unreachable(); -} - -uint32_t target_arch_largest_atomic_bits(ZigLLVM_ArchType arch) { - switch (arch) { - case ZigLLVM_UnknownArch: - zig_unreachable(); - - case ZigLLVM_avr: - case ZigLLVM_msp430: - return 16; - - case ZigLLVM_arc: - case ZigLLVM_arm: - case ZigLLVM_armeb: - case ZigLLVM_hexagon: - case ZigLLVM_m68k: - case ZigLLVM_le32: - case ZigLLVM_mips: - case ZigLLVM_mipsel: - case ZigLLVM_nvptx: - case ZigLLVM_ppc: - case ZigLLVM_ppcle: - case ZigLLVM_r600: - case ZigLLVM_riscv32: - case ZigLLVM_sparc: - case ZigLLVM_sparcel: - case ZigLLVM_tce: - case ZigLLVM_tcele: - case ZigLLVM_thumb: - case ZigLLVM_thumbeb: - case ZigLLVM_x86: - case ZigLLVM_xcore: - case ZigLLVM_amdil: - case ZigLLVM_hsail: - case ZigLLVM_spir: - case ZigLLVM_kalimba: - case ZigLLVM_lanai: - case ZigLLVM_shave: - case ZigLLVM_wasm32: - case ZigLLVM_renderscript32: - case ZigLLVM_csky: - case ZigLLVM_spirv32: - case ZigLLVM_loongarch32: - case ZigLLVM_dxil: - return 32; - - case ZigLLVM_aarch64: - case ZigLLVM_aarch64_be: - case ZigLLVM_aarch64_32: - case ZigLLVM_amdgcn: - case ZigLLVM_bpfel: - case ZigLLVM_bpfeb: - case ZigLLVM_le64: - case ZigLLVM_mips64: - case ZigLLVM_mips64el: - case ZigLLVM_nvptx64: - case ZigLLVM_ppc64: - case ZigLLVM_ppc64le: - case ZigLLVM_riscv64: - case ZigLLVM_sparcv9: - case ZigLLVM_systemz: - case ZigLLVM_amdil64: - case ZigLLVM_hsail64: - case ZigLLVM_spir64: - case ZigLLVM_wasm64: - case ZigLLVM_renderscript64: - case ZigLLVM_ve: - case ZigLLVM_spirv64: - case ZigLLVM_loongarch64: - return 64; - - case ZigLLVM_x86_64: - return 128; - } - zig_unreachable(); -} - -uint32_t target_c_type_size_in_bits(const ZigTarget *target, CIntType id) { - switch (target->os) { - case OsFreestanding: - case OsOther: - switch (target->arch) { - case ZigLLVM_msp430: - switch (id) { - case CIntTypeShort: - case CIntTypeUShort: - return 16; - case CIntTypeInt: - case CIntTypeUInt: - return 16; - case CIntTypeLong: - case CIntTypeULong: - return 32; - case CIntTypeLongLong: - case CIntTypeULongLong: - return 64; - case CIntTypeCount: - zig_unreachable(); - } - zig_unreachable(); - default: - switch (id) { - case CIntTypeShort: - case CIntTypeUShort: - return 16; - case CIntTypeInt: - case CIntTypeUInt: - return 32; - case CIntTypeLong: - case CIntTypeULong: - return target_arch_pointer_bit_width(target->arch); - case CIntTypeLongLong: - case CIntTypeULongLong: - return 64; - case CIntTypeCount: - zig_unreachable(); - } - } - zig_unreachable(); - case OsLinux: - case OsMacOSX: - case OsFreeBSD: - case OsNetBSD: - case OsDragonFly: - case OsOpenBSD: - case OsWASI: - case OsHaiku: - case OsSolaris: - case OsEmscripten: - case OsPlan9: - case OsCUDA: - case OsNVCL: - switch (id) { - case CIntTypeShort: - case CIntTypeUShort: - return 16; - case CIntTypeInt: - case CIntTypeUInt: - return 32; - case CIntTypeLong: - case CIntTypeULong: - return target_arch_pointer_bit_width(target->arch); - case CIntTypeLongLong: - case CIntTypeULongLong: - return 64; - case CIntTypeCount: - zig_unreachable(); - } - zig_unreachable(); - case OsUefi: - case OsWindows: - switch (id) { - case CIntTypeShort: - case CIntTypeUShort: - return 16; - case CIntTypeInt: - case CIntTypeUInt: - case CIntTypeLong: - case CIntTypeULong: - return 32; - case CIntTypeLongLong: - case CIntTypeULongLong: - return 64; - case CIntTypeCount: - zig_unreachable(); - } - zig_unreachable(); - case OsIOS: - switch (id) { - case CIntTypeShort: - case CIntTypeUShort: - return 16; - case CIntTypeInt: - case CIntTypeUInt: - return 32; - case CIntTypeLong: - case CIntTypeULong: - case CIntTypeLongLong: - case CIntTypeULongLong: - return 64; - case CIntTypeCount: - zig_unreachable(); - } - zig_unreachable(); - case OsAnanas: - case OsCloudABI: - case OsKFreeBSD: - case OsLv2: - case OsZOS: - case OsMinix: - case OsRTEMS: - case OsNaCl: - case OsAIX: - case OsAMDHSA: - case OsPS4: - case OsPS5: - case OsELFIAMCU: - case OsTvOS: - case OsWatchOS: - case OsMesa3D: - case OsFuchsia: - case OsContiki: - case OsAMDPAL: - case OsHermitCore: - case OsHurd: - case OsOpenCL: - case OsGLSL450: - case OsVulkan: - case OsDriverKit: - case OsShaderModel: - zig_panic("TODO c type size in bits for this target"); - } - zig_unreachable(); -} - -bool target_allows_addr_zero(const ZigTarget *target) { - return target->os == OsFreestanding || target->os == OsUefi; -} - -const char *target_o_file_ext(const ZigTarget *target) { - if (target->abi == ZigLLVM_MSVC || - target->os == OsWindows || target->os == OsUefi) - { - return ".obj"; - } else { - return ".o"; - } -} - -const char *target_asm_file_ext(const ZigTarget *target) { - return ".s"; -} - -const char *target_llvm_ir_file_ext(const ZigTarget *target) { - return ".ll"; -} - -bool target_is_android(const ZigTarget *target) { - return target->abi == ZigLLVM_Android; -} - -const char *arch_stack_pointer_register_name(ZigLLVM_ArchType arch) { - switch (arch) { - case ZigLLVM_UnknownArch: - zig_unreachable(); - case ZigLLVM_x86: - return "esp"; - case ZigLLVM_x86_64: - return "rsp"; - case ZigLLVM_arm: - case ZigLLVM_armeb: - case ZigLLVM_thumb: - case ZigLLVM_thumbeb: - case ZigLLVM_aarch64: - case ZigLLVM_aarch64_be: - case ZigLLVM_aarch64_32: - case ZigLLVM_riscv32: - case ZigLLVM_riscv64: - case ZigLLVM_m68k: - case ZigLLVM_mips: - case ZigLLVM_mipsel: - case ZigLLVM_ppc: - case ZigLLVM_ppcle: - case ZigLLVM_ppc64: - case ZigLLVM_ppc64le: - return "sp"; - - case ZigLLVM_wasm32: - case ZigLLVM_wasm64: - case ZigLLVM_spirv32: - case ZigLLVM_spirv64: - return nullptr; // known to be not available - - case ZigLLVM_amdgcn: - case ZigLLVM_amdil: - case ZigLLVM_amdil64: - case ZigLLVM_arc: - case ZigLLVM_avr: - case ZigLLVM_bpfeb: - case ZigLLVM_bpfel: - case ZigLLVM_csky: - case ZigLLVM_hexagon: - case ZigLLVM_lanai: - case ZigLLVM_hsail: - case ZigLLVM_hsail64: - case ZigLLVM_kalimba: - case ZigLLVM_le32: - case ZigLLVM_le64: - case ZigLLVM_mips64: - case ZigLLVM_mips64el: - case ZigLLVM_msp430: - case ZigLLVM_nvptx: - case ZigLLVM_nvptx64: - case ZigLLVM_r600: - case ZigLLVM_renderscript32: - case ZigLLVM_renderscript64: - case ZigLLVM_shave: - case ZigLLVM_sparc: - case ZigLLVM_sparcel: - case ZigLLVM_sparcv9: - case ZigLLVM_spir: - case ZigLLVM_spir64: - case ZigLLVM_systemz: - case ZigLLVM_tce: - case ZigLLVM_tcele: - case ZigLLVM_xcore: - case ZigLLVM_ve: - case ZigLLVM_dxil: - case ZigLLVM_loongarch32: - case ZigLLVM_loongarch64: - zig_panic("TODO populate this table with stack pointer register name for this CPU architecture"); - } - zig_unreachable(); -} - -bool target_is_arm(const ZigTarget *target) { - switch (target->arch) { - case ZigLLVM_UnknownArch: - zig_unreachable(); - case ZigLLVM_aarch64: - case ZigLLVM_aarch64_be: - case ZigLLVM_aarch64_32: - case ZigLLVM_arm: - case ZigLLVM_armeb: - case ZigLLVM_thumb: - case ZigLLVM_thumbeb: - return true; - - case ZigLLVM_x86: - case ZigLLVM_x86_64: - case ZigLLVM_amdgcn: - case ZigLLVM_amdil: - case ZigLLVM_amdil64: - case ZigLLVM_arc: - case ZigLLVM_avr: - case ZigLLVM_bpfeb: - case ZigLLVM_bpfel: - case ZigLLVM_csky: - case ZigLLVM_hexagon: - case ZigLLVM_m68k: - case ZigLLVM_lanai: - case ZigLLVM_hsail: - case ZigLLVM_hsail64: - case ZigLLVM_kalimba: - case ZigLLVM_le32: - case ZigLLVM_le64: - case ZigLLVM_mips: - case ZigLLVM_mips64: - case ZigLLVM_mips64el: - case ZigLLVM_mipsel: - case ZigLLVM_msp430: - case ZigLLVM_nvptx: - case ZigLLVM_nvptx64: - case ZigLLVM_r600: - case ZigLLVM_renderscript32: - case ZigLLVM_renderscript64: - case ZigLLVM_riscv32: - case ZigLLVM_riscv64: - case ZigLLVM_shave: - case ZigLLVM_sparc: - case ZigLLVM_sparcel: - case ZigLLVM_sparcv9: - case ZigLLVM_spir: - case ZigLLVM_spir64: - case ZigLLVM_systemz: - case ZigLLVM_tce: - case ZigLLVM_tcele: - case ZigLLVM_wasm32: - case ZigLLVM_wasm64: - case ZigLLVM_xcore: - case ZigLLVM_ppc: - case ZigLLVM_ppcle: - case ZigLLVM_ppc64: - case ZigLLVM_ppc64le: - case ZigLLVM_ve: - case ZigLLVM_spirv32: - case ZigLLVM_spirv64: - case ZigLLVM_dxil: - case ZigLLVM_loongarch32: - case ZigLLVM_loongarch64: - return false; - } - zig_unreachable(); -} - -// Valgrind supports more, but Zig does not support them yet. -bool target_has_valgrind_support(const ZigTarget *target) { - switch (target->arch) { - case ZigLLVM_UnknownArch: - zig_unreachable(); - case ZigLLVM_x86_64: - return (target->os == OsLinux || target->os == OsSolaris || - (target->os == OsWindows && target->abi != ZigLLVM_MSVC)); - default: - return false; - } - zig_unreachable(); -} - -bool target_is_wasm(const ZigTarget *target) { - return target->arch == ZigLLVM_wasm32 || target->arch == ZigLLVM_wasm64; -} - -bool target_is_bpf(const ZigTarget *target) { - return target->arch == ZigLLVM_bpfel || target->arch == ZigLLVM_bpfeb; -} - -ZigLLVM_EnvironmentType target_default_abi(ZigLLVM_ArchType arch, Os os) { - if (arch == ZigLLVM_wasm32 || arch == ZigLLVM_wasm64) { - return ZigLLVM_Musl; - } - switch (os) { - case OsFreestanding: - case OsAnanas: - case OsCloudABI: - case OsLv2: - case OsSolaris: - case OsZOS: - case OsMinix: - case OsRTEMS: - case OsNaCl: - case OsAIX: - case OsCUDA: - case OsNVCL: - case OsAMDHSA: - case OsPS4: - case OsPS5: - case OsELFIAMCU: - case OsMesa3D: - case OsContiki: - case OsAMDPAL: - case OsHermitCore: - case OsOther: - return ZigLLVM_EABI; - case OsOpenBSD: - case OsFreeBSD: - case OsFuchsia: - case OsKFreeBSD: - case OsNetBSD: - case OsDragonFly: - case OsHurd: - case OsHaiku: - return ZigLLVM_GNU; - case OsUefi: - case OsWindows: - return ZigLLVM_MSVC; - case OsLinux: - case OsWASI: - case OsEmscripten: - return ZigLLVM_Musl; - case OsOpenCL: - case OsGLSL450: - case OsVulkan: - case OsPlan9: - case OsMacOSX: - case OsIOS: - case OsTvOS: - case OsWatchOS: - case OsDriverKit: - case OsShaderModel: - return ZigLLVM_UnknownEnvironment; - } - zig_unreachable(); -} - -bool target_has_debug_info(const ZigTarget *target) { - return true; -} - -bool target_long_double_is_f128(const ZigTarget *target) { - if (target->abi == ZigLLVM_MSVC) { - return false; - } - switch (target->arch) { - case ZigLLVM_aarch64: - // According to Apple's official guide: - // > The long double type is a double precision IEEE754 binary floating-point type, - // > which makes it identical to the double type. This behavior contrasts to the - // > standard specification, in which a long double is a quad-precision, IEEE754 - // > binary, floating-point type. - // https://developer.apple.com/documentation/xcode/writing-arm64-code-for-apple-platforms - return !target_os_is_darwin(target->os); - - case ZigLLVM_riscv64: - case ZigLLVM_aarch64_be: - case ZigLLVM_aarch64_32: - case ZigLLVM_systemz: - case ZigLLVM_mips64: - case ZigLLVM_mips64el: - case ZigLLVM_sparc: - case ZigLLVM_sparcv9: - case ZigLLVM_sparcel: - case ZigLLVM_ppc: - case ZigLLVM_ppcle: - case ZigLLVM_ppc64: - case ZigLLVM_ppc64le: - return true; - - default: - return false; - } -} - -bool target_has_f80(const ZigTarget *target) { - switch (target->arch) { - case ZigLLVM_x86: - case ZigLLVM_x86_64: - return true; - - default: - return false; - } -} - -bool target_is_riscv(const ZigTarget *target) { - return target->arch == ZigLLVM_riscv32 || target->arch == ZigLLVM_riscv64; -} - -bool target_is_sparc(const ZigTarget *target) { - return target->arch == ZigLLVM_sparc || target->arch == ZigLLVM_sparcv9; -} - -bool target_is_mips(const ZigTarget *target) { - return target->arch == ZigLLVM_mips || target->arch == ZigLLVM_mipsel || - target->arch == ZigLLVM_mips64 || target->arch == ZigLLVM_mips64el; -} - -bool target_is_ppc(const ZigTarget *target) { - return target->arch == ZigLLVM_ppc || target->arch == ZigLLVM_ppcle || - target->arch == ZigLLVM_ppc64 || target->arch == ZigLLVM_ppc64le; -} - -// Returns the minimum alignment for every function pointer on the given -// architecture. -unsigned target_fn_ptr_align(const ZigTarget *target) { - // TODO This is a pessimization but is always correct. - return 1; -} - -// Returns the minimum alignment for every function on the given architecture. -unsigned target_fn_align(const ZigTarget *target) { - switch (target->arch) { - case ZigLLVM_riscv32: - case ZigLLVM_riscv64: - // TODO If the C extension is not present the value is 4. - return 2; - case ZigLLVM_ppc: - case ZigLLVM_ppcle: - case ZigLLVM_ppc64: - case ZigLLVM_ppc64le: - case ZigLLVM_aarch64: - case ZigLLVM_aarch64_be: - case ZigLLVM_aarch64_32: - case ZigLLVM_sparc: - case ZigLLVM_sparcel: - case ZigLLVM_sparcv9: - case ZigLLVM_mips: - case ZigLLVM_mipsel: - case ZigLLVM_mips64: - case ZigLLVM_mips64el: - return 4; - - default: - return 1; - } -} diff --git a/src/stage1/target.hpp b/src/stage1/target.hpp deleted file mode 100644 index 2e2603354989..000000000000 --- a/src/stage1/target.hpp +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright (c) 2016 Andrew Kelley - * - * This file is part of zig, which is MIT licensed. - * See http://opensource.org/licenses/MIT - */ - -#ifndef ZIG_TARGET_HPP -#define ZIG_TARGET_HPP - -#include "stage2.h" - -struct Buf; - -enum CIntType { - CIntTypeShort, - CIntTypeUShort, - CIntTypeInt, - CIntTypeUInt, - CIntTypeLong, - CIntTypeULong, - CIntTypeLongLong, - CIntTypeULongLong, - - CIntTypeCount, -}; - -Error target_parse_arch(ZigLLVM_ArchType *arch, const char *arch_ptr, size_t arch_len); -Error target_parse_os(Os *os, const char *os_ptr, size_t os_len); -Error target_parse_abi(ZigLLVM_EnvironmentType *abi, const char *abi_ptr, size_t abi_len); - -size_t target_arch_count(void); -ZigLLVM_ArchType target_arch_enum(size_t index); -const char *target_arch_name(ZigLLVM_ArchType arch); - -const char *arch_stack_pointer_register_name(ZigLLVM_ArchType arch); - -size_t target_vendor_count(void); -ZigLLVM_VendorType target_vendor_enum(size_t index); - -size_t target_os_count(void); -Os target_os_enum(size_t index); -const char *target_os_name(Os os_type); - -size_t target_abi_count(void); -ZigLLVM_EnvironmentType target_abi_enum(size_t index); -const char *target_abi_name(ZigLLVM_EnvironmentType abi); -ZigLLVM_EnvironmentType target_default_abi(ZigLLVM_ArchType arch, Os os); - - -size_t target_oformat_count(void); -ZigLLVM_ObjectFormatType target_oformat_enum(size_t index); -const char *target_oformat_name(ZigLLVM_ObjectFormatType oformat); -ZigLLVM_ObjectFormatType target_object_format(const ZigTarget *target); - -void target_triple_llvm(Buf *triple, const ZigTarget *target); -void target_triple_zig(Buf *triple, const ZigTarget *target); - -void init_all_targets(void); - -void resolve_target_object_format(ZigTarget *target); - -uint32_t target_c_type_size_in_bits(const ZigTarget *target, CIntType id); - -const char *target_o_file_ext(const ZigTarget *target); -const char *target_asm_file_ext(const ZigTarget *target); -const char *target_llvm_ir_file_ext(const ZigTarget *target); - -ZigLLVM_OSType get_llvm_os_type(Os os_type); - -bool target_is_arm(const ZigTarget *target); -bool target_is_mips(const ZigTarget *target); -bool target_is_ppc(const ZigTarget *target); -bool target_allows_addr_zero(const ZigTarget *target); -bool target_has_valgrind_support(const ZigTarget *target); -bool target_os_is_darwin(Os os); -bool target_is_wasm(const ZigTarget *target); -bool target_is_bpf(const ZigTarget *target); -bool target_is_riscv(const ZigTarget *target); -bool target_is_sparc(const ZigTarget *target); -bool target_is_android(const ZigTarget *target); -bool target_has_debug_info(const ZigTarget *target); -bool target_long_double_is_f128(const ZigTarget *target); -bool target_has_f80(const ZigTarget *target); - -uint32_t target_arch_pointer_bit_width(ZigLLVM_ArchType arch); -uint32_t target_arch_largest_atomic_bits(ZigLLVM_ArchType arch); - -unsigned target_fn_ptr_align(const ZigTarget *target); -unsigned target_fn_align(const ZigTarget *target); - -#endif diff --git a/src/stage1/tokenizer.cpp b/src/stage1/tokenizer.cpp deleted file mode 100644 index 820c73be5c09..000000000000 --- a/src/stage1/tokenizer.cpp +++ /dev/null @@ -1,1626 +0,0 @@ -/* - * Copyright (c) 2015 Andrew Kelley - * - * This file is part of zig, which is MIT licensed. - * See http://opensource.org/licenses/MIT - */ - -#include "tokenizer.hpp" -#include "util.hpp" - -#include -#include -#include -#include -#include -#include - -#define WHITESPACE \ - ' ': \ - case '\r': \ - case '\n' - -#define DIGIT_NON_ZERO \ - '1': \ - case '2': \ - case '3': \ - case '4': \ - case '5': \ - case '6': \ - case '7': \ - case '8': \ - case '9' - -#define DIGIT \ - '0': \ - case DIGIT_NON_ZERO - -#define HEXDIGIT \ - 'a': \ - case 'b': \ - case 'c': \ - case 'd': \ - case 'e': \ - case 'f': \ - case 'A': \ - case 'B': \ - case 'C': \ - case 'D': \ - case 'E': \ - case 'F': \ - case DIGIT - -#define ALPHA_EXCEPT_HEX_P_O_X \ - 'g': \ - case 'h': \ - case 'i': \ - case 'j': \ - case 'k': \ - case 'l': \ - case 'm': \ - case 'n': \ - case 'q': \ - case 'r': \ - case 's': \ - case 't': \ - case 'u': \ - case 'v': \ - case 'w': \ - case 'y': \ - case 'z': \ - case 'G': \ - case 'H': \ - case 'I': \ - case 'J': \ - case 'K': \ - case 'L': \ - case 'M': \ - case 'N': \ - case 'O': \ - case 'Q': \ - case 'R': \ - case 'S': \ - case 'T': \ - case 'U': \ - case 'V': \ - case 'W': \ - case 'X': \ - case 'Y': \ - case 'Z' - -#define ALPHA_EXCEPT_E_B_O_X \ - ALPHA_EXCEPT_HEX_P_O_X: \ - case 'a': \ - case 'c': \ - case 'd': \ - case 'f': \ - case 'A': \ - case 'B': \ - case 'C': \ - case 'D': \ - case 'F': \ - case 'p': \ - case 'P' - -#define ALPHA_EXCEPT_HEX_AND_P \ - ALPHA_EXCEPT_HEX_P_O_X: \ - case 'o': \ - case 'x' - -#define ALPHA_EXCEPT_E \ - ALPHA_EXCEPT_HEX_AND_P: \ - case 'a': \ - case 'b': \ - case 'c': \ - case 'd': \ - case 'f': \ - case 'A': \ - case 'B': \ - case 'C': \ - case 'D': \ - case 'F': \ - case 'p': \ - case 'P' - -#define ALPHA \ - ALPHA_EXCEPT_E: \ - case 'e': \ - case 'E' - -#define IDENTIFIER_CHAR \ - ALPHA: \ - case DIGIT: \ - case '_' - -#define SYMBOL_START \ - ALPHA: \ - case '_' - -struct ZigKeyword { - const char *text; - TokenId token_id; -}; - -static const struct ZigKeyword zig_keywords[] = { - {"align", TokenIdKeywordAlign}, - {"allowzero", TokenIdKeywordAllowZero}, - {"and", TokenIdKeywordAnd}, - {"anyframe", TokenIdKeywordAnyFrame}, - {"anytype", TokenIdKeywordAnyType}, - {"asm", TokenIdKeywordAsm}, - {"async", TokenIdKeywordAsync}, - {"await", TokenIdKeywordAwait}, - {"break", TokenIdKeywordBreak}, - {"callconv", TokenIdKeywordCallconv}, - {"catch", TokenIdKeywordCatch}, - {"comptime", TokenIdKeywordCompTime}, - {"const", TokenIdKeywordConst}, - {"continue", TokenIdKeywordContinue}, - {"defer", TokenIdKeywordDefer}, - {"else", TokenIdKeywordElse}, - {"enum", TokenIdKeywordEnum}, - {"errdefer", TokenIdKeywordErrdefer}, - {"error", TokenIdKeywordError}, - {"export", TokenIdKeywordExport}, - {"extern", TokenIdKeywordExtern}, - {"fn", TokenIdKeywordFn}, - {"for", TokenIdKeywordFor}, - {"if", TokenIdKeywordIf}, - {"inline", TokenIdKeywordInline}, - {"noalias", TokenIdKeywordNoAlias}, - {"noinline", TokenIdKeywordNoInline}, - {"nosuspend", TokenIdKeywordNoSuspend}, - {"opaque", TokenIdKeywordOpaque}, - {"or", TokenIdKeywordOr}, - {"orelse", TokenIdKeywordOrElse}, - {"packed", TokenIdKeywordPacked}, - {"pub", TokenIdKeywordPub}, - {"resume", TokenIdKeywordResume}, - {"return", TokenIdKeywordReturn}, - {"linksection", TokenIdKeywordLinkSection}, - {"struct", TokenIdKeywordStruct}, - {"suspend", TokenIdKeywordSuspend}, - {"switch", TokenIdKeywordSwitch}, - {"test", TokenIdKeywordTest}, - {"threadlocal", TokenIdKeywordThreadLocal}, - {"try", TokenIdKeywordTry}, - {"union", TokenIdKeywordUnion}, - {"unreachable", TokenIdKeywordUnreachable}, - {"usingnamespace", TokenIdKeywordUsingNamespace}, - {"var", TokenIdKeywordVar}, - {"volatile", TokenIdKeywordVolatile}, - {"while", TokenIdKeywordWhile}, -}; - -// Returns TokenIdIdentifier if it is not a keyword. -static TokenId zig_keyword_token(const char *name_ptr, size_t name_len) { - for (size_t i = 0; i < array_length(zig_keywords); i += 1) { - if (mem_eql_str(name_ptr, name_len, zig_keywords[i].text)) { - return zig_keywords[i].token_id; - } - } - return TokenIdIdentifier; -} - -enum TokenizeState { - TokenizeState_start, - TokenizeState_identifier, - TokenizeState_builtin, - TokenizeState_string_literal, - TokenizeState_string_literal_backslash, - TokenizeState_multiline_string_literal_line, - TokenizeState_char_literal, - TokenizeState_char_literal_backslash, - TokenizeState_char_literal_hex_escape, - TokenizeState_char_literal_unicode_escape_saw_u, - TokenizeState_char_literal_unicode_escape, - TokenizeState_char_literal_unicode, - TokenizeState_char_literal_end, - TokenizeState_backslash, - TokenizeState_equal, - TokenizeState_bang, - TokenizeState_pipe, - TokenizeState_minus, - TokenizeState_minus_percent, - TokenizeState_minus_pipe, - TokenizeState_asterisk, - TokenizeState_asterisk_percent, - TokenizeState_asterisk_pipe, - TokenizeState_slash, - TokenizeState_line_comment_start, - TokenizeState_line_comment, - TokenizeState_doc_comment_start, - TokenizeState_doc_comment, - TokenizeState_container_doc_comment, - TokenizeState_zero, - TokenizeState_int_literal_dec, - TokenizeState_int_literal_dec_no_underscore, - TokenizeState_int_literal_bin, - TokenizeState_int_literal_bin_no_underscore, - TokenizeState_int_literal_oct, - TokenizeState_int_literal_oct_no_underscore, - TokenizeState_int_literal_hex, - TokenizeState_int_literal_hex_no_underscore, - TokenizeState_num_dot_dec, - TokenizeState_num_dot_hex, - TokenizeState_float_fraction_dec, - TokenizeState_float_fraction_dec_no_underscore, - TokenizeState_float_fraction_hex, - TokenizeState_float_fraction_hex_no_underscore, - TokenizeState_float_exponent_unsigned, - TokenizeState_float_exponent_num, - TokenizeState_float_exponent_num_no_underscore, - TokenizeState_ampersand, - TokenizeState_caret, - TokenizeState_percent, - TokenizeState_plus, - TokenizeState_plus_percent, - TokenizeState_plus_pipe, - TokenizeState_angle_bracket_left, - TokenizeState_angle_bracket_angle_bracket_left, - TokenizeState_angle_bracket_angle_bracket_left_pipe, - TokenizeState_angle_bracket_right, - TokenizeState_angle_bracket_angle_bracket_right, - TokenizeState_period, - TokenizeState_period_2, - TokenizeState_period_asterisk, - TokenizeState_saw_at_sign, - TokenizeState_error, -}; - - -struct Tokenize { - Tokenization *out; - size_t pos; - TokenizeState state; - uint32_t line; - uint32_t column; -}; - -ATTRIBUTE_PRINTF(2, 3) -static void tokenize_error(Tokenize *t, const char *format, ...) { - t->state = TokenizeState_error; - - t->out->err_byte_offset = t->pos; - - va_list ap; - va_start(ap, format); - t->out->err = buf_vprintf(format, ap); - va_end(ap); -} - -static void begin_token(Tokenize *t, TokenId id) { - t->out->ids.append(id); - TokenLoc tok_loc; - tok_loc.offset = (uint32_t) t->pos; - tok_loc.line = t->line; - tok_loc.column = t->column; - t->out->locs.append(tok_loc); -} - -static void cancel_token(Tokenize *t) { - t->out->ids.pop(); - t->out->locs.pop(); -} - -static const char* get_escape_shorthand(uint8_t c) { - switch (c) { - case '\0': - return "\\0"; - case '\a': - return "\\a"; - case '\b': - return "\\b"; - case '\t': - return "\\t"; - case '\n': - return "\\n"; - case '\v': - return "\\v"; - case '\f': - return "\\f"; - case '\r': - return "\\r"; - default: - return nullptr; - } -} - -static void invalid_eof(Tokenize *t) { - return tokenize_error(t, "unexpected End-Of-File"); -} - -static void invalid_char_error(Tokenize *t, uint8_t c) { - if (c == 0) { - return invalid_eof(t); - } - - if (c == '\r') { - tokenize_error(t, "invalid carriage return, only '\\n' line endings are supported"); - return; - } - - const char *sh = get_escape_shorthand(c); - if (sh) { - tokenize_error(t, "invalid character: '%s'", sh); - return; - } - - if (isprint(c)) { - tokenize_error(t, "invalid character: '%c'", c); - return; - } - - tokenize_error(t, "invalid character: '\\x%02x'", c); -} - -void tokenize(const char *source, Tokenization *out) { - Tokenize t = {0}; - t.out = out; - - size_t remaining_code_units; - size_t seen_escape_digits; - - // Skip the UTF-8 BOM if present. - if (source[0] == (char)0xef && - source[1] == (char)0xbb && - source[2] == (char)0xbf) - { - t.pos += 3; - } - - // Invalid token takes up index 0 so that index 0 can mean "none". - begin_token(&t, TokenIdCount); - - for (;;) { - uint8_t c = source[t.pos]; - switch (t.state) { - case TokenizeState_error: - goto eof; - case TokenizeState_start: - switch (c) { - case 0: - goto eof; - case WHITESPACE: - break; - case '"': - begin_token(&t, TokenIdStringLiteral); - t.state = TokenizeState_string_literal; - break; - case '\'': - begin_token(&t, TokenIdCharLiteral); - t.state = TokenizeState_char_literal; - break; - case ALPHA: - case '_': - t.state = TokenizeState_identifier; - begin_token(&t, TokenIdIdentifier); - break; - case '@': - begin_token(&t, TokenIdBuiltin); - t.state = TokenizeState_saw_at_sign; - break; - case '=': - begin_token(&t, TokenIdEq); - t.state = TokenizeState_equal; - break; - case '!': - begin_token(&t, TokenIdBang); - t.state = TokenizeState_bang; - break; - case '|': - begin_token(&t, TokenIdBinOr); - t.state = TokenizeState_pipe; - break; - case '(': - begin_token(&t, TokenIdLParen); - break; - case ')': - begin_token(&t, TokenIdRParen); - break; - case '[': - begin_token(&t, TokenIdLBracket); - break; - case ']': - begin_token(&t, TokenIdRBracket); - break; - case ';': - begin_token(&t, TokenIdSemicolon); - break; - case ',': - begin_token(&t, TokenIdComma); - break; - case '?': - begin_token(&t, TokenIdQuestion); - break; - case ':': - begin_token(&t, TokenIdColon); - break; - case '%': - begin_token(&t, TokenIdPercent); - t.state = TokenizeState_percent; - break; - case '*': - begin_token(&t, TokenIdStar); - t.state = TokenizeState_asterisk; - break; - case '+': - begin_token(&t, TokenIdPlus); - t.state = TokenizeState_plus; - break; - case '<': - begin_token(&t, TokenIdCmpLessThan); - t.state = TokenizeState_angle_bracket_left; - break; - case '>': - begin_token(&t, TokenIdCmpGreaterThan); - t.state = TokenizeState_angle_bracket_right; - break; - case '^': - begin_token(&t, TokenIdBinXor); - t.state = TokenizeState_caret; - break; - case '\\': - begin_token(&t, TokenIdMultilineStringLiteralLine); - t.state = TokenizeState_backslash; - break; - case '{': - begin_token(&t, TokenIdLBrace); - break; - case '}': - begin_token(&t, TokenIdRBrace); - break; - case '~': - begin_token(&t, TokenIdTilde); - break; - case '.': - begin_token(&t, TokenIdDot); - t.state = TokenizeState_period; - break; - case '-': - begin_token(&t, TokenIdDash); - t.state = TokenizeState_minus; - break; - case '/': - begin_token(&t, TokenIdSlash); - t.state = TokenizeState_slash; - break; - case '&': - begin_token(&t, TokenIdAmpersand); - t.state = TokenizeState_ampersand; - break; - case '0': - t.state = TokenizeState_zero; - begin_token(&t, TokenIdIntLiteral); - break; - case DIGIT_NON_ZERO: - t.state = TokenizeState_int_literal_dec; - begin_token(&t, TokenIdIntLiteral); - break; - default: - invalid_char_error(&t, c); - } - break; - case TokenizeState_saw_at_sign: - switch (c) { - case 0: - invalid_eof(&t); - goto eof; - case '"': - t.out->ids.last() = TokenIdIdentifier; - t.state = TokenizeState_string_literal; - break; - case IDENTIFIER_CHAR: - t.state = TokenizeState_builtin; - break; - default: - invalid_char_error(&t, c); - } - break; - case TokenizeState_ampersand: - switch (c) { - case 0: - goto eof; - case '&': - tokenize_error(&t, "`&&` is invalid. Note that `and` is boolean AND"); - break; - case '=': - t.out->ids.last() = TokenIdBitAndEq; - t.state = TokenizeState_start; - break; - default: - t.state = TokenizeState_start; - continue; - } - break; - case TokenizeState_asterisk: - switch (c) { - case 0: - goto eof; - case '=': - t.out->ids.last() = TokenIdTimesEq; - t.state = TokenizeState_start; - break; - case '*': - t.out->ids.last() = TokenIdStarStar; - t.state = TokenizeState_start; - break; - case '%': - t.state = TokenizeState_asterisk_percent; - break; - case '|': - t.state = TokenizeState_asterisk_pipe; - break; - default: - t.state = TokenizeState_start; - continue; - } - break; - case TokenizeState_asterisk_percent: - switch (c) { - case 0: - t.out->ids.last() = TokenIdTimesPercent; - goto eof; - case '=': - t.out->ids.last() = TokenIdTimesPercentEq; - t.state = TokenizeState_start; - break; - default: - t.out->ids.last() = TokenIdTimesPercent; - t.state = TokenizeState_start; - continue; - } - break; - case TokenizeState_asterisk_pipe: - switch (c) { - case 0: - t.out->ids.last() = TokenIdTimesPipe; - goto eof; - case '=': - t.out->ids.last() = TokenIdTimesPipeEq; - t.state = TokenizeState_start; - break; - default: - t.out->ids.last() = TokenIdTimesPipe; - t.state = TokenizeState_start; - continue; - } - break; - case TokenizeState_percent: - switch (c) { - case 0: - goto eof; - case '=': - t.out->ids.last() = TokenIdModEq; - t.state = TokenizeState_start; - break; - default: - t.state = TokenizeState_start; - continue; - } - break; - case TokenizeState_plus: - switch (c) { - case 0: - goto eof; - case '=': - t.out->ids.last() = TokenIdPlusEq; - t.state = TokenizeState_start; - break; - case '+': - t.out->ids.last() = TokenIdPlusPlus; - t.state = TokenizeState_start; - break; - case '%': - t.state = TokenizeState_plus_percent; - break; - case '|': - t.state = TokenizeState_plus_pipe; - break; - default: - t.state = TokenizeState_start; - continue; - } - break; - case TokenizeState_plus_percent: - switch (c) { - case 0: - t.out->ids.last() = TokenIdPlusPercent; - goto eof; - case '=': - t.out->ids.last() = TokenIdPlusPercentEq; - t.state = TokenizeState_start; - break; - default: - t.out->ids.last() = TokenIdPlusPercent; - t.state = TokenizeState_start; - continue; - } - break; - case TokenizeState_plus_pipe: - switch (c) { - case 0: - t.out->ids.last() = TokenIdPlusPipe; - goto eof; - case '=': - t.out->ids.last() = TokenIdPlusPipeEq; - t.state = TokenizeState_start; - break; - default: - t.out->ids.last() = TokenIdPlusPipe; - t.state = TokenizeState_start; - continue; - } - break; - case TokenizeState_caret: - switch (c) { - case 0: - goto eof; - case '=': - t.out->ids.last() = TokenIdBitXorEq; - t.state = TokenizeState_start; - break; - default: - t.state = TokenizeState_start; - continue; - } - break; - case TokenizeState_identifier: - switch (c) { - case 0: { - uint32_t start_pos = t.out->locs.last().offset; - t.out->ids.last() = zig_keyword_token( - source + start_pos, t.pos - start_pos); - goto eof; - } - case IDENTIFIER_CHAR: - break; - default: { - uint32_t start_pos = t.out->locs.last().offset; - t.out->ids.last() = zig_keyword_token( - source + start_pos, t.pos - start_pos); - - t.state = TokenizeState_start; - continue; - } - } - break; - case TokenizeState_builtin: - switch (c) { - case 0: - goto eof; - case IDENTIFIER_CHAR: - break; - default: - t.state = TokenizeState_start; - continue; - } - break; - case TokenizeState_backslash: - switch (c) { - case '\\': - t.state = TokenizeState_multiline_string_literal_line; - break; - default: - invalid_char_error(&t, c); - break; - } - break; - case TokenizeState_string_literal: - switch (c) { - case 0: - invalid_eof(&t); - goto eof; - case '\\': - t.state = TokenizeState_string_literal_backslash; - break; - case '"': - t.state = TokenizeState_start; - break; - case '\n': - case '\r': - tokenize_error(&t, "newline not allowed in string literal"); - break; - default: - break; - } - break; - case TokenizeState_string_literal_backslash: - switch (c) { - case 0: - invalid_eof(&t); - goto eof; - case '\n': - case '\r': - tokenize_error(&t, "newline not allowed in string literal"); - break; - default: - t.state = TokenizeState_string_literal; - break; - } - break; - case TokenizeState_char_literal: - if (c == 0) { - invalid_eof(&t); - goto eof; - } else if (c == '\\') { - t.state = TokenizeState_char_literal_backslash; - } else if (c == '\'') { - tokenize_error(&t, "expected character"); - } else if ((c >= 0x80 && c <= 0xbf) || c >= 0xf8) { - // 10xxxxxx - // 11111xxx - invalid_char_error(&t, c); - } else if (c >= 0xc0 && c <= 0xdf) { - // 110xxxxx - remaining_code_units = 1; - t.state = TokenizeState_char_literal_unicode; - } else if (c >= 0xe0 && c <= 0xef) { - // 1110xxxx - remaining_code_units = 2; - t.state = TokenizeState_char_literal_unicode; - } else if (c >= 0xf0 && c <= 0xf7) { - // 11110xxx - remaining_code_units = 3; - t.state = TokenizeState_char_literal_unicode; - } else { - t.state = TokenizeState_char_literal_end; - } - break; - case TokenizeState_char_literal_backslash: - switch (c) { - case 0: - invalid_eof(&t); - goto eof; - case '\n': - case '\r': - tokenize_error(&t, "newline not allowed in character literal"); - break; - case 'x': - t.state = TokenizeState_char_literal_hex_escape; - seen_escape_digits = 0; - break; - case 'u': - t.state = TokenizeState_char_literal_unicode_escape_saw_u; - break; - case 'U': - invalid_char_error(&t, c); - break; - default: - t.state = TokenizeState_char_literal_end; - break; - } - break; - case TokenizeState_char_literal_hex_escape: - switch (c) { - case ALPHA: - case DIGIT: - seen_escape_digits += 1; - if (seen_escape_digits == 2) { - t.state = TokenizeState_char_literal_end; - } - break; - default: - tokenize_error(&t, "expected hex digit"); - break; - } - break; - case TokenizeState_char_literal_unicode_escape_saw_u: - switch (c) { - case '{': - t.state = TokenizeState_char_literal_unicode_escape; - seen_escape_digits = 0; - break; - default: - tokenize_error(&t, "expected '{' to begin unicode escape sequence"); - break; - } - break; - case TokenizeState_char_literal_unicode_escape: - switch (c) { - case ALPHA: - case DIGIT: - seen_escape_digits += 1; - break; - case '}': - if (seen_escape_digits == 0) { - tokenize_error(&t, "empty unicode escape sequence"); - break; - } - t.state = TokenizeState_char_literal_end; - break; - default: - tokenize_error(&t, "expected hex digit"); - break; - } - break; - case TokenizeState_char_literal_end: - switch (c) { - case '\'': - t.state = TokenizeState_start; - break; - default: - invalid_char_error(&t, c); - break; - } - break; - case TokenizeState_char_literal_unicode: - if (c >= 0x80 && c <= 0xbf) { - remaining_code_units -= 1; - if (remaining_code_units == 0) { - t.state = TokenizeState_char_literal_end; - } - } else { - invalid_char_error(&t, c); - } - break; - case TokenizeState_multiline_string_literal_line: - switch (c) { - case 0: - goto eof; - case '\n': - t.state = TokenizeState_start; - break; - default: - break; - } - break; - case TokenizeState_bang: - switch (c) { - case 0: - goto eof; - case '=': - t.out->ids.last() = TokenIdCmpNotEq; - t.state = TokenizeState_start; - break; - default: - t.state = TokenizeState_start; - continue; - } - break; - case TokenizeState_pipe: - switch (c) { - case 0: - goto eof; - case '=': - t.out->ids.last() = TokenIdBitOrEq; - t.state = TokenizeState_start; - break; - case '|': - t.out->ids.last() = TokenIdBarBar; - t.state = TokenizeState_start; - break; - default: - t.state = TokenizeState_start; - continue; - } - break; - case TokenizeState_equal: - switch (c) { - case 0: - goto eof; - case '=': - t.out->ids.last() = TokenIdCmpEq; - t.state = TokenizeState_start; - break; - case '>': - t.out->ids.last() = TokenIdFatArrow; - t.state = TokenizeState_start; - break; - default: - t.state = TokenizeState_start; - continue; - } - break; - case TokenizeState_minus: - switch (c) { - case 0: - goto eof; - case '>': - t.out->ids.last() = TokenIdArrow; - t.state = TokenizeState_start; - break; - case '=': - t.out->ids.last() = TokenIdMinusEq; - t.state = TokenizeState_start; - break; - case '%': - t.state = TokenizeState_minus_percent; - break; - case '|': - t.state = TokenizeState_minus_pipe; - break; - default: - t.state = TokenizeState_start; - continue; - } - break; - case TokenizeState_minus_percent: - switch (c) { - case 0: - t.out->ids.last() = TokenIdMinusPercent; - goto eof; - case '=': - t.out->ids.last() = TokenIdMinusPercentEq; - t.state = TokenizeState_start; - break; - default: - t.out->ids.last() = TokenIdMinusPercent; - t.state = TokenizeState_start; - continue; - } - break; - case TokenizeState_minus_pipe: - switch (c) { - case 0: - t.out->ids.last() = TokenIdMinusPipe; - goto eof; - case '=': - t.out->ids.last() = TokenIdMinusPipeEq; - t.state = TokenizeState_start; - break; - default: - t.out->ids.last() = TokenIdMinusPipe; - t.state = TokenizeState_start; - continue; - } - break; - case TokenizeState_angle_bracket_left: - switch (c) { - case 0: - goto eof; - case '=': - t.out->ids.last() = TokenIdCmpLessOrEq; - t.state = TokenizeState_start; - break; - case '<': - t.state = TokenizeState_angle_bracket_angle_bracket_left; - break; - default: - t.state = TokenizeState_start; - continue; - } - break; - case TokenizeState_angle_bracket_angle_bracket_left: - switch (c) { - case 0: - t.out->ids.last() = TokenIdBitShiftLeft; - goto eof; - case '=': - t.out->ids.last() = TokenIdBitShiftLeftEq; - t.state = TokenizeState_start; - break; - case '|': - t.state = TokenizeState_angle_bracket_angle_bracket_left_pipe; - break; - default: - t.out->ids.last() = TokenIdBitShiftLeft; - t.state = TokenizeState_start; - continue; - } - break; - case TokenizeState_angle_bracket_angle_bracket_left_pipe: - switch (c) { - case 0: - t.out->ids.last() = TokenIdBitShiftLeftPipe; - goto eof; - case '=': - t.out->ids.last() = TokenIdBitShiftLeftPipeEq; - t.state = TokenizeState_start; - break; - default: - t.out->ids.last() = TokenIdBitShiftLeftPipe; - t.state = TokenizeState_start; - continue; - } - break; - case TokenizeState_angle_bracket_right: - switch (c) { - case 0: - goto eof; - case '=': - t.out->ids.last() = TokenIdCmpGreaterOrEq; - t.state = TokenizeState_start; - break; - case '>': - t.state = TokenizeState_angle_bracket_angle_bracket_right; - break; - default: - t.state = TokenizeState_start; - continue; - } - break; - case TokenizeState_angle_bracket_angle_bracket_right: - switch (c) { - case 0: - t.out->ids.last() = TokenIdBitShiftRight; - goto eof; - case '=': - t.out->ids.last() = TokenIdBitShiftRightEq; - t.state = TokenizeState_start; - break; - default: - t.out->ids.last() = TokenIdBitShiftRight; - t.state = TokenizeState_start; - continue; - } - break; - case TokenizeState_period: - switch (c) { - case 0: - goto eof; - case '.': - t.state = TokenizeState_period_2; - break; - case '*': - t.state = TokenizeState_period_asterisk; - break; - default: - t.state = TokenizeState_start; - continue; - } - break; - case TokenizeState_period_2: - switch (c) { - case 0: - t.out->ids.last() = TokenIdEllipsis2; - goto eof; - case '.': - t.out->ids.last() = TokenIdEllipsis3; - t.state = TokenizeState_start; - break; - default: - t.out->ids.last() = TokenIdEllipsis2; - t.state = TokenizeState_start; - continue; - } - break; - case TokenizeState_period_asterisk: - switch (c) { - case 0: - t.out->ids.last() = TokenIdDotStar; - goto eof; - case '*': - tokenize_error(&t, "`.*` cannot be followed by `*`. Are you missing a space?"); - break; - default: - t.out->ids.last() = TokenIdDotStar; - t.state = TokenizeState_start; - continue; - } - break; - case TokenizeState_slash: - switch (c) { - case 0: - goto eof; - case '/': - t.state = TokenizeState_line_comment_start; - break; - case '=': - t.out->ids.last() = TokenIdDivEq; - t.state = TokenizeState_start; - break; - default: - t.state = TokenizeState_start; - continue; - } - break; - case TokenizeState_line_comment_start: - switch (c) { - case 0: - goto eof; - case '/': - t.state = TokenizeState_doc_comment_start; - break; - case '!': - t.out->ids.last() = TokenIdContainerDocComment; - t.state = TokenizeState_container_doc_comment; - break; - case '\n': - cancel_token(&t); - t.state = TokenizeState_start; - break; - default: - cancel_token(&t); - t.state = TokenizeState_line_comment; - break; - } - break; - case TokenizeState_doc_comment_start: - switch (c) { - case 0: - t.out->ids.last() = TokenIdDocComment; - goto eof; - case '/': - cancel_token(&t); - t.state = TokenizeState_line_comment; - break; - case '\n': - t.out->ids.last() = TokenIdDocComment; - t.state = TokenizeState_start; - break; - default: - t.out->ids.last() = TokenIdDocComment; - t.state = TokenizeState_doc_comment; - break; - } - break; - case TokenizeState_line_comment: - switch (c) { - case 0: - goto eof; - case '\n': - t.state = TokenizeState_start; - break; - default: - break; - } - break; - case TokenizeState_doc_comment: - case TokenizeState_container_doc_comment: - switch (c) { - case 0: - goto eof; - case '\n': - t.state = TokenizeState_start; - break; - default: - // do nothing - break; - } - break; - case TokenizeState_zero: - switch (c) { - case 0: - goto eof; - case 'b': - t.state = TokenizeState_int_literal_bin_no_underscore; - break; - case 'o': - t.state = TokenizeState_int_literal_oct_no_underscore; - break; - case 'x': - t.state = TokenizeState_int_literal_hex_no_underscore; - break; - case DIGIT: - case '_': - case '.': - case 'e': - case 'E': - // Reinterpret as a decimal number. - t.state = TokenizeState_int_literal_dec; - continue; - case ALPHA_EXCEPT_E_B_O_X: - invalid_char_error(&t, c); - break; - default: - t.state = TokenizeState_start; - continue; - } - break; - case TokenizeState_int_literal_bin_no_underscore: - switch (c) { - case '0': - case '1': - t.state = TokenizeState_int_literal_bin; - break; - default: - invalid_char_error(&t, c); - } - break; - case TokenizeState_int_literal_bin: - switch (c) { - case 0: - goto eof; - case '_': - t.state = TokenizeState_int_literal_bin_no_underscore; - break; - case '0': - case '1': - break; - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - case ALPHA: - invalid_char_error(&t, c); - break; - default: - t.state = TokenizeState_start; - continue; - } - break; - case TokenizeState_int_literal_oct_no_underscore: - switch (c) { - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - t.state = TokenizeState_int_literal_oct; - break; - default: - invalid_char_error(&t, c); - break; - } - break; - case TokenizeState_int_literal_oct: - switch (c) { - case 0: - goto eof; - case '_': - t.state = TokenizeState_int_literal_oct_no_underscore; - break; - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - break; - case ALPHA: - case '8': - case '9': - invalid_char_error(&t, c); - break; - default: - t.state = TokenizeState_start; - continue; - } - break; - case TokenizeState_int_literal_dec_no_underscore: - switch (c) { - case DIGIT: - t.state = TokenizeState_int_literal_dec; - break; - default: - invalid_char_error(&t, c); - break; - } - break; - case TokenizeState_int_literal_dec: - switch (c) { - case 0: - goto eof; - case '_': - t.state = TokenizeState_int_literal_dec_no_underscore; - break; - case '.': - t.state = TokenizeState_num_dot_dec; - t.out->ids.last() = TokenIdFloatLiteral; - break; - case 'e': - case 'E': - t.state = TokenizeState_float_exponent_unsigned; - t.out->ids.last() = TokenIdFloatLiteral; - break; - case DIGIT: - break; - case ALPHA_EXCEPT_E: - invalid_char_error(&t, c); - break; - default: - t.state = TokenizeState_start; - continue; - } - break; - case TokenizeState_int_literal_hex_no_underscore: - switch (c) { - case HEXDIGIT: - t.state = TokenizeState_int_literal_hex; - break; - default: - invalid_char_error(&t, c); - } - break; - case TokenizeState_int_literal_hex: - switch (c) { - case 0: - goto eof; - case '_': - t.state = TokenizeState_int_literal_hex_no_underscore; - break; - case '.': - t.state = TokenizeState_num_dot_hex; - t.out->ids.last() = TokenIdFloatLiteral; - break; - case 'p': - case 'P': - t.state = TokenizeState_float_exponent_unsigned; - t.out->ids.last() = TokenIdFloatLiteral; - break; - case HEXDIGIT: - break; - case ALPHA_EXCEPT_HEX_AND_P: - invalid_char_error(&t, c); - break; - default: - t.state = TokenizeState_start; - continue; - } - break; - case TokenizeState_num_dot_dec: - switch (c) { - case 0: - goto eof; - case '.': - t.out->ids.last() = TokenIdIntLiteral; - t.pos -= 1; - t.column -= 1; - t.state = TokenizeState_start; - continue; - case DIGIT: - t.state = TokenizeState_float_fraction_dec; - break; - default: - invalid_char_error(&t, c); - break; - } - break; - case TokenizeState_num_dot_hex: - switch (c) { - case 0: - goto eof; - case '.': - t.out->ids.last() = TokenIdIntLiteral; - t.pos -= 1; - t.column -= 1; - t.state = TokenizeState_start; - continue; - case HEXDIGIT: - t.out->ids.last() = TokenIdFloatLiteral; - t.state = TokenizeState_float_fraction_hex; - break; - default: - invalid_char_error(&t, c); - break; - } - break; - case TokenizeState_float_fraction_dec_no_underscore: - switch (c) { - case DIGIT: - t.state = TokenizeState_float_fraction_dec; - break; - default: - invalid_char_error(&t, c); - } - break; - case TokenizeState_float_fraction_dec: - switch (c) { - case 0: - goto eof; - case '_': - t.state = TokenizeState_float_fraction_dec_no_underscore; - break; - case 'e': - case 'E': - t.state = TokenizeState_float_exponent_unsigned; - break; - case DIGIT: - break; - case ALPHA_EXCEPT_E: - invalid_char_error(&t, c); - break; - default: - t.state = TokenizeState_start; - continue; - } - break; - case TokenizeState_float_fraction_hex_no_underscore: - switch (c) { - case HEXDIGIT: - t.state = TokenizeState_float_fraction_hex; - break; - default: - invalid_char_error(&t, c); - } - break; - case TokenizeState_float_fraction_hex: - switch (c) { - case 0: - goto eof; - case '_': - t.state = TokenizeState_float_fraction_hex_no_underscore; - break; - case 'p': - case 'P': - t.state = TokenizeState_float_exponent_unsigned; - break; - case HEXDIGIT: - break; - case ALPHA_EXCEPT_HEX_AND_P: - invalid_char_error(&t, c); - break; - default: - t.state = TokenizeState_start; - continue; - } - break; - case TokenizeState_float_exponent_unsigned: - switch (c) { - case '+': - case '-': - t.state = TokenizeState_float_exponent_num_no_underscore; - break; - default: - // Reinterpret as a normal exponent number. - t.state = TokenizeState_float_exponent_num_no_underscore; - continue; - } - break; - case TokenizeState_float_exponent_num_no_underscore: - switch (c) { - case DIGIT: - t.state = TokenizeState_float_exponent_num; - break; - default: - invalid_char_error(&t, c); - } - break; - case TokenizeState_float_exponent_num: - switch (c) { - case 0: - goto eof; - case '_': - t.state = TokenizeState_float_exponent_num_no_underscore; - break; - case DIGIT: - break; - case ALPHA: - invalid_char_error(&t, c); - break; - default: - t.state = TokenizeState_start; - continue; - } - break; - } - t.pos += 1; - if (c == '\n') { - t.line += 1; - t.column = 0; - } else { - t.column += 1; - } - } -eof:; - - begin_token(&t, TokenIdEof); -} - -const char * token_name(TokenId id) { - switch (id) { - case TokenIdAmpersand: return "&"; - case TokenIdArrow: return "->"; - case TokenIdBang: return "!"; - case TokenIdBarBar: return "||"; - case TokenIdBinOr: return "|"; - case TokenIdBinXor: return "^"; - case TokenIdBitAndEq: return "&="; - case TokenIdBitOrEq: return "|="; - case TokenIdBitShiftLeft: return "<<"; - case TokenIdBitShiftLeftEq: return "<<="; - case TokenIdBitShiftLeftPipe: return "<<|"; - case TokenIdBitShiftLeftPipeEq: return "<<|="; - case TokenIdBitShiftRight: return ">>"; - case TokenIdBitShiftRightEq: return ">>="; - case TokenIdBitXorEq: return "^="; - case TokenIdCharLiteral: return "CharLiteral"; - case TokenIdCmpEq: return "=="; - case TokenIdCmpGreaterOrEq: return ">="; - case TokenIdCmpGreaterThan: return ">"; - case TokenIdCmpLessOrEq: return "<="; - case TokenIdCmpLessThan: return "<"; - case TokenIdCmpNotEq: return "!="; - case TokenIdColon: return ":"; - case TokenIdComma: return ","; - case TokenIdDash: return "-"; - case TokenIdDivEq: return "/="; - case TokenIdDocComment: return "DocComment"; - case TokenIdContainerDocComment: return "ContainerDocComment"; - case TokenIdDot: return "."; - case TokenIdDotStar: return ".*"; - case TokenIdEllipsis2: return ".."; - case TokenIdEllipsis3: return "..."; - case TokenIdEof: return "EOF"; - case TokenIdEq: return "="; - case TokenIdFatArrow: return "=>"; - case TokenIdFloatLiteral: return "FloatLiteral"; - case TokenIdIntLiteral: return "IntLiteral"; - case TokenIdKeywordAsync: return "async"; - case TokenIdKeywordAllowZero: return "allowzero"; - case TokenIdKeywordAwait: return "await"; - case TokenIdKeywordResume: return "resume"; - case TokenIdKeywordSuspend: return "suspend"; - case TokenIdKeywordAlign: return "align"; - case TokenIdKeywordAnd: return "and"; - case TokenIdKeywordAnyFrame: return "anyframe"; - case TokenIdKeywordAnyType: return "anytype"; - case TokenIdKeywordAsm: return "asm"; - case TokenIdKeywordBreak: return "break"; - case TokenIdKeywordCatch: return "catch"; - case TokenIdKeywordCallconv: return "callconv"; - case TokenIdKeywordCompTime: return "comptime"; - case TokenIdKeywordConst: return "const"; - case TokenIdKeywordContinue: return "continue"; - case TokenIdKeywordDefer: return "defer"; - case TokenIdKeywordElse: return "else"; - case TokenIdKeywordEnum: return "enum"; - case TokenIdKeywordErrdefer: return "errdefer"; - case TokenIdKeywordError: return "error"; - case TokenIdKeywordExport: return "export"; - case TokenIdKeywordExtern: return "extern"; - case TokenIdKeywordFn: return "fn"; - case TokenIdKeywordFor: return "for"; - case TokenIdKeywordIf: return "if"; - case TokenIdKeywordInline: return "inline"; - case TokenIdKeywordNoAlias: return "noalias"; - case TokenIdKeywordNoInline: return "noinline"; - case TokenIdKeywordNoSuspend: return "nosuspend"; - case TokenIdKeywordOpaque: return "opaque"; - case TokenIdKeywordOr: return "or"; - case TokenIdKeywordOrElse: return "orelse"; - case TokenIdKeywordPacked: return "packed"; - case TokenIdKeywordPub: return "pub"; - case TokenIdKeywordReturn: return "return"; - case TokenIdKeywordLinkSection: return "linksection"; - case TokenIdKeywordStruct: return "struct"; - case TokenIdKeywordSwitch: return "switch"; - case TokenIdKeywordTest: return "test"; - case TokenIdKeywordThreadLocal: return "threadlocal"; - case TokenIdKeywordTry: return "try"; - case TokenIdKeywordUnion: return "union"; - case TokenIdKeywordUnreachable: return "unreachable"; - case TokenIdKeywordUsingNamespace: return "usingnamespace"; - case TokenIdKeywordVar: return "var"; - case TokenIdKeywordVolatile: return "volatile"; - case TokenIdKeywordWhile: return "while"; - case TokenIdLBrace: return "{"; - case TokenIdLBracket: return "["; - case TokenIdLParen: return "("; - case TokenIdQuestion: return "?"; - case TokenIdMinusEq: return "-="; - case TokenIdMinusPercent: return "-%"; - case TokenIdMinusPercentEq: return "-%="; - case TokenIdMinusPipe: return "-|"; - case TokenIdMinusPipeEq: return "-|="; - case TokenIdModEq: return "%="; - case TokenIdPercent: return "%"; - case TokenIdPlus: return "+"; - case TokenIdPlusEq: return "+="; - case TokenIdPlusPercent: return "+%"; - case TokenIdPlusPercentEq: return "+%="; - case TokenIdPlusPipe: return "+|"; - case TokenIdPlusPipeEq: return "+|="; - case TokenIdPlusPlus: return "++"; - case TokenIdRBrace: return "}"; - case TokenIdRBracket: return "]"; - case TokenIdRParen: return ")"; - case TokenIdSemicolon: return ";"; - case TokenIdSlash: return "/"; - case TokenIdStar: return "*"; - case TokenIdStarStar: return "**"; - case TokenIdStringLiteral: return "StringLiteral"; - case TokenIdMultilineStringLiteralLine: return "MultilineStringLiteralLine"; - case TokenIdIdentifier: return "Identifier"; - case TokenIdTilde: return "~"; - case TokenIdTimesEq: return "*="; - case TokenIdTimesPercent: return "*%"; - case TokenIdTimesPercentEq: return "*%="; - case TokenIdTimesPipe: return "*|"; - case TokenIdTimesPipeEq: return "*|="; - case TokenIdBuiltin: return "Builtin"; - case TokenIdCount: - zig_unreachable(); - } - return "(invalid token)"; -} diff --git a/src/stage1/tokenizer.hpp b/src/stage1/tokenizer.hpp deleted file mode 100644 index e2cb96e866f0..000000000000 --- a/src/stage1/tokenizer.hpp +++ /dev/null @@ -1,161 +0,0 @@ -/* - * Copyright (c) 2015 Andrew Kelley - * - * This file is part of zig, which is MIT licensed. - * See http://opensource.org/licenses/MIT - */ - -#ifndef ZIG_TOKENIZER_HPP -#define ZIG_TOKENIZER_HPP - -#include "buffer.hpp" -#include "bigint.hpp" -#include "bigfloat.hpp" - -enum TokenId : uint8_t { - TokenIdAmpersand, - TokenIdArrow, - TokenIdBang, - TokenIdBarBar, - TokenIdBinOr, - TokenIdBinXor, - TokenIdBitAndEq, - TokenIdBitOrEq, - TokenIdBitShiftLeft, - TokenIdBitShiftLeftEq, - TokenIdBitShiftLeftPipe, - TokenIdBitShiftLeftPipeEq, - TokenIdBitShiftRight, - TokenIdBitShiftRightEq, - TokenIdBitXorEq, - TokenIdBuiltin, - TokenIdCharLiteral, - TokenIdCmpEq, - TokenIdCmpGreaterOrEq, - TokenIdCmpGreaterThan, - TokenIdCmpLessOrEq, - TokenIdCmpLessThan, - TokenIdCmpNotEq, - TokenIdColon, - TokenIdComma, - TokenIdDash, - TokenIdDivEq, - TokenIdDocComment, - TokenIdContainerDocComment, - TokenIdDot, - TokenIdDotStar, - TokenIdEllipsis2, - TokenIdEllipsis3, - TokenIdEof, - TokenIdEq, - TokenIdFatArrow, - TokenIdFloatLiteral, - TokenIdIntLiteral, - TokenIdKeywordAlign, - TokenIdKeywordAllowZero, - TokenIdKeywordAnd, - TokenIdKeywordAnyFrame, - TokenIdKeywordAnyType, - TokenIdKeywordAsm, - TokenIdKeywordAsync, - TokenIdKeywordAwait, - TokenIdKeywordBreak, - TokenIdKeywordCatch, - TokenIdKeywordCallconv, - TokenIdKeywordCompTime, - TokenIdKeywordConst, - TokenIdKeywordContinue, - TokenIdKeywordDefer, - TokenIdKeywordElse, - TokenIdKeywordEnum, - TokenIdKeywordErrdefer, - TokenIdKeywordError, - TokenIdKeywordExport, - TokenIdKeywordExtern, - TokenIdKeywordFn, - TokenIdKeywordFor, - TokenIdKeywordIf, - TokenIdKeywordInline, - TokenIdKeywordNoInline, - TokenIdKeywordLinkSection, - TokenIdKeywordNoAlias, - TokenIdKeywordNoSuspend, - TokenIdKeywordOpaque, - TokenIdKeywordOr, - TokenIdKeywordOrElse, - TokenIdKeywordPacked, - TokenIdKeywordPub, - TokenIdKeywordResume, - TokenIdKeywordReturn, - TokenIdKeywordStruct, - TokenIdKeywordSuspend, - TokenIdKeywordSwitch, - TokenIdKeywordTest, - TokenIdKeywordThreadLocal, - TokenIdKeywordTry, - TokenIdKeywordUnion, - TokenIdKeywordUnreachable, - TokenIdKeywordUsingNamespace, - TokenIdKeywordVar, - TokenIdKeywordVolatile, - TokenIdKeywordWhile, - TokenIdLBrace, - TokenIdLBracket, - TokenIdLParen, - TokenIdQuestion, - TokenIdMinusEq, - TokenIdMinusPercent, - TokenIdMinusPercentEq, - TokenIdMinusPipe, - TokenIdMinusPipeEq, - TokenIdModEq, - TokenIdPercent, - TokenIdPlus, - TokenIdPlusEq, - TokenIdPlusPercent, - TokenIdPlusPercentEq, - TokenIdPlusPipe, - TokenIdPlusPipeEq, - TokenIdPlusPlus, - TokenIdRBrace, - TokenIdRBracket, - TokenIdRParen, - TokenIdSemicolon, - TokenIdSlash, - TokenIdStar, - TokenIdStarStar, - TokenIdStringLiteral, - TokenIdMultilineStringLiteralLine, - TokenIdIdentifier, - TokenIdTilde, - TokenIdTimesEq, - TokenIdTimesPercent, - TokenIdTimesPercentEq, - TokenIdTimesPipe, - TokenIdTimesPipeEq, - - TokenIdCount, -}; - -typedef uint32_t TokenIndex; - -struct TokenLoc { - uint32_t offset; - uint32_t line; - uint32_t column; -}; - -struct Tokenization { - ZigList ids; - ZigList locs; - - // if an error occurred - Buf *err; - uint32_t err_byte_offset; -}; - -void tokenize(const char *source, Tokenization *out_tokenization); - -const char * token_name(TokenId id); - -#endif diff --git a/src/stage1/util.cpp b/src/stage1/util.cpp deleted file mode 100644 index e1e167adf918..000000000000 --- a/src/stage1/util.cpp +++ /dev/null @@ -1,115 +0,0 @@ -/* - * Copyright (c) 2015 Andrew Kelley - * - * This file is part of zig, which is MIT licensed. - * See http://opensource.org/licenses/MIT - */ - -#include "util.hpp" -#include "stage2.h" - -#include -#include - -void zig_panic(const char *format, ...) { - va_list ap; - va_start(ap, format); - vfprintf(stderr, format, ap); - fflush(stderr); - va_end(ap); - stage2_panic("", 0); - abort(); -} - -// Ported from std/mem.zig. -bool SplitIterator_isSplitByte(SplitIterator *self, uint8_t byte) { - for (size_t i = 0; i < self->split_bytes.len; i += 1) { - if (byte == self->split_bytes.ptr[i]) { - return true; - } - } - return false; -} - -// Ported from std/mem.zig. -Optional> SplitIterator_next(SplitIterator *self) { - // move to beginning of token - while (self->index < self->buffer.len && - SplitIterator_isSplitByte(self, self->buffer.ptr[self->index])) - { - self->index += 1; - } - size_t start = self->index; - if (start == self->buffer.len) { - return {}; - } - - // move to end of token - while (self->index < self->buffer.len && - !SplitIterator_isSplitByte(self, self->buffer.ptr[self->index])) - { - self->index += 1; - } - size_t end = self->index; - - return Optional>::some(self->buffer.slice(start, end)); -} - -// Ported from std/mem.zig. -// This one won't collapse multiple separators into one, so you could use it, for example, -// to parse Comma Separated Value format. -Optional> SplitIterator_next_separate(SplitIterator *self) { - // move to beginning of token - if (self->index < self->buffer.len && - SplitIterator_isSplitByte(self, self->buffer.ptr[self->index])) - { - self->index += 1; - } - size_t start = self->index; - if (start == self->buffer.len) { - return {}; - } - - // move to end of token - while (self->index < self->buffer.len && - !SplitIterator_isSplitByte(self, self->buffer.ptr[self->index])) - { - self->index += 1; - } - size_t end = self->index; - - return Optional>::some(self->buffer.slice(start, end)); -} - -// Ported from std/mem.zig -Slice SplitIterator_rest(SplitIterator *self) { - // move to beginning of token - size_t index = self->index; - while (index < self->buffer.len && SplitIterator_isSplitByte(self, self->buffer.ptr[index])) { - index += 1; - } - return self->buffer.sliceFrom(index); -} - -// Ported from std/mem.zig -SplitIterator memSplit(Slice buffer, Slice split_bytes) { - return SplitIterator{0, buffer, split_bytes}; -} - -void zig_pretty_print_bytes(FILE *f, double n) { - if (n > 1024.0 * 1024.0 * 1024.0) { - fprintf(f, "%.03f GiB", n / 1024.0 / 1024.0 / 1024.0); - return; - } - if (n > 1024.0 * 1024.0) { - fprintf(f, "%.03f MiB", n / 1024.0 / 1024.0); - return; - } - if (n > 1024.0) { - fprintf(f, "%.03f KiB", n / 1024.0); - return; - } - fprintf(f, "%.03f bytes", n ); - return; -} - diff --git a/src/stage1/util.hpp b/src/stage1/util.hpp deleted file mode 100644 index 35fa49acce5f..000000000000 --- a/src/stage1/util.hpp +++ /dev/null @@ -1,247 +0,0 @@ -/* - * Copyright (c) 2015 Andrew Kelley - * - * This file is part of zig, which is MIT licensed. - * See http://opensource.org/licenses/MIT - */ - -#ifndef ZIG_UTIL_HPP -#define ZIG_UTIL_HPP - -#include -#include -#include -#include - -#if defined(_MSC_VER) -#include -#endif - -#define ZIG_Q(x) #x -#define ZIG_QUOTE(x) ZIG_Q(x) - -#include "util_base.hpp" -#include "heap.hpp" -#include "mem.hpp" - -#if defined(_MSC_VER) -static inline int clzll(unsigned long long mask) { - unsigned long lz; -#if defined(_WIN64) - if (_BitScanReverse64(&lz, mask)) - return static_cast(63 - lz); - zig_unreachable(); -#else - if (_BitScanReverse(&lz, mask >> 32)) - lz += 32; - else - _BitScanReverse(&lz, mask & 0xffffffff); - return 63 - lz; -#endif -} -static inline int ctzll(unsigned long long mask) { - unsigned long result; -#if defined(_WIN64) - if (_BitScanForward64(&result, mask)) - return result; - zig_unreachable(); -#else - if (_BitScanForward(&result, mask & 0xffffffff)) - return result; - if (_BitScanForward(&result, mask >> 32)) - return 32 + result; - zig_unreachable(); -#endif -} -#else -#define clzll(x) __builtin_clzll(x) -#define ctzll(x) __builtin_ctzll(x) -#endif - -template -constexpr size_t array_length(const T (&)[n]) { - return n; -} - -template -static inline T max(T a, T b) { - return (a >= b) ? a : b; -} - -template -static inline T min(T a, T b) { - return (a <= b) ? a : b; -} - -template -static inline T clamp(T min_value, T value, T max_value) { - return max(min(value, max_value), min_value); -} - -static inline bool mem_eql_mem(const char *a_ptr, size_t a_len, const char *b_ptr, size_t b_len) { - if (a_len != b_len) - return false; - return memcmp(a_ptr, b_ptr, a_len) == 0; -} -static inline bool mem_eql_mem_ignore_case(const char *a_ptr, size_t a_len, const char *b_ptr, size_t b_len) { - if (a_len != b_len) - return false; - for (size_t i = 0; i < a_len; i += 1) { - if (tolower(a_ptr[i]) != tolower(b_ptr[i])) - return false; - } - return true; -} - -static inline bool mem_eql_str(const char *mem, size_t mem_len, const char *str) { - return mem_eql_mem(mem, mem_len, str, strlen(str)); -} - -static inline bool str_eql_str(const char *a, const char* b) { - return mem_eql_mem(a, strlen(a), b, strlen(b)); -} - -static inline bool str_eql_str_ignore_case(const char *a, const char* b) { - return mem_eql_mem_ignore_case(a, strlen(a), b, strlen(b)); -} - -static inline bool is_power_of_2(uint64_t x) { - return x != 0 && ((x & (~x + 1)) == x); -} - -static inline bool mem_ends_with_mem(const char *mem, size_t mem_len, const char *end, size_t end_len) { - if (mem_len < end_len) return false; - return memcmp(mem + mem_len - end_len, end, end_len) == 0; -} - -static inline bool mem_ends_with_str(const char *mem, size_t mem_len, const char *str) { - return mem_ends_with_mem(mem, mem_len, str, strlen(str)); -} - -static inline uint64_t round_to_next_power_of_2(uint64_t x) { - --x; - x |= x >> 1; - x |= x >> 2; - x |= x >> 4; - x |= x >> 8; - x |= x >> 16; - x |= x >> 32; - return x + 1; -} - -static inline uint8_t log2_u64(uint64_t x) { - return (63 - clzll(x)); -} - -void zig_pretty_print_bytes(FILE *f, double n); - -template -struct Optional { - T value; - bool is_some; - - static inline Optional some(T x) { - return {x, true}; - } - - static inline Optional none() { - return {{}, false}; - } - - inline bool unwrap(T *res) { - *res = value; - return is_some; - } -}; - -template -struct Slice { - T *ptr; - size_t len; - - inline T &at(size_t i) { - assert(i < len); - return ptr[i]; - } - - inline Slice slice(size_t start, size_t end) { - assert(end <= len); - assert(end >= start); - return { - ptr + start, - end - start, - }; - } - - inline Slice sliceFrom(size_t start) { - assert(start <= len); - return { - ptr + start, - len - start, - }; - } - - static inline Slice alloc(size_t n) { - return {heap::c_allocator.allocate_nonzero(n), n}; - } -}; - -template -struct Array { - static const size_t len = n; - T items[n]; - - inline Slice slice() { - return { - &items[0], - len, - }; - } -}; - -static inline Slice str(const char *literal) { - return {(uint8_t*)(literal), strlen(literal)}; -} - -// Ported from std/mem.zig -template -static inline bool memEql(Slice a, Slice b) { - if (a.len != b.len) - return false; - for (size_t i = 0; i < a.len; i += 1) { - if (a.ptr[i] != b.ptr[i]) - return false; - } - return true; -} - -// Ported from std/mem.zig -template -static inline bool memStartsWith(Slice haystack, Slice needle) { - if (needle.len > haystack.len) - return false; - return memEql(haystack.slice(0, needle.len), needle); -} - -// Ported from std/mem.zig -template -static inline void memCopy(Slice dest, Slice src) { - assert(dest.len >= src.len); - memcpy(dest.ptr, src.ptr, src.len * sizeof(T)); -} - -// Ported from std/mem.zig. -// Coordinate struct fields with memSplit function -struct SplitIterator { - size_t index; - Slice buffer; - Slice split_bytes; -}; - -bool SplitIterator_isSplitByte(SplitIterator *self, uint8_t byte); -Optional< Slice > SplitIterator_next(SplitIterator *self); -Optional< Slice > SplitIterator_next_separate(SplitIterator *self); -Slice SplitIterator_rest(SplitIterator *self); -SplitIterator memSplit(Slice buffer, Slice split_bytes); - -#endif diff --git a/src/stage1/util_base.hpp b/src/stage1/util_base.hpp deleted file mode 100644 index da1d3bf234de..000000000000 --- a/src/stage1/util_base.hpp +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright (c) 2015 Andrew Kelley - * - * This file is part of zig, which is MIT licensed. - * See http://opensource.org/licenses/MIT - */ - -#ifndef ZIG_UTIL_BASE_HPP -#define ZIG_UTIL_BASE_HPP - -#include - -#if defined(_MSC_VER) - -#define ATTRIBUTE_COLD __declspec(noinline) -#define ATTRIBUTE_PRINTF(a, b) -#define ATTRIBUTE_RETURNS_NOALIAS __declspec(restrict) -#define ATTRIBUTE_NORETURN __declspec(noreturn) -#define ATTRIBUTE_MUST_USE - -#define BREAKPOINT __debugbreak() - -#else - -#define ATTRIBUTE_COLD __attribute__((cold)) -#define ATTRIBUTE_PRINTF(a, b) __attribute__((format(printf, a, b))) -#define ATTRIBUTE_RETURNS_NOALIAS __attribute__((__malloc__)) -#define ATTRIBUTE_NORETURN __attribute__((noreturn)) -#define ATTRIBUTE_MUST_USE __attribute__((warn_unused_result)) - -#if defined(__MINGW32__) || defined(__MINGW64__) -#define BREAKPOINT __debugbreak() -#elif defined(__i386__) || defined(__x86_64__) -#define BREAKPOINT __asm__ volatile("int $0x03"); -#elif defined(__clang__) -#define BREAKPOINT __builtin_debugtrap() -#elif defined(__GNUC__) -#define BREAKPOINT __builtin_trap() -#else -#include -#define BREAKPOINT raise(SIGTRAP) -#endif - -#endif - -ATTRIBUTE_COLD -ATTRIBUTE_NORETURN -ATTRIBUTE_PRINTF(1, 2) -void zig_panic(const char *format, ...); - -static inline void zig_assert(bool ok, const char *file, int line, const char *func) { - if (!ok) { - zig_panic("Assertion failed at %s:%d in %s. This is a bug in the Zig compiler.", file, line, func); - } -} - -#ifdef _WIN32 -#define __func__ __FUNCTION__ -#endif - -#define zig_unreachable() zig_panic("Unreachable at %s:%d in %s. This is a bug in the Zig compiler.", __FILE__, __LINE__, __func__) - -// Assertions in stage1 are always on, and they call zig @panic. -#undef assert -#define assert(ok) zig_assert(ok, __FILE__, __LINE__, __func__) - -#if defined(_MSC_VER) -#define ZIG_FALLTHROUGH -#elif defined(__clang__) -#define ZIG_FALLTHROUGH [[clang::fallthrough]] -#elif defined(__GNUC__) && __GNUC__ >= 7 -#define ZIG_FALLTHROUGH __attribute__((fallthrough)) -#else -#define ZIG_FALLTHROUGH -#endif - -#endif diff --git a/src/stage1/zig0.cpp b/src/stage1/zig0.cpp deleted file mode 100644 index 96d33a093c81..000000000000 --- a/src/stage1/zig0.cpp +++ /dev/null @@ -1,578 +0,0 @@ -/* - * Copyright (c) 2015 Andrew Kelley - * - * This file is part of zig, which is MIT licensed. - * See http://opensource.org/licenses/MIT - */ - -// This file is the entry point for zig0, which is *only* used to build -// stage2, the self-hosted compiler, into an object file, which is then -// linked by the same build system (cmake) that linked this binary. - -#include "stage1.h" -#include "heap.hpp" -#include "stage2.h" -#include "target.hpp" -#include "error.hpp" -#include "util.hpp" -#include "buffer.hpp" -#include "os.hpp" - -#ifndef ZIG_VERSION_STRING -#include "config.h" -#endif - -#include -#include - -static int print_error_usage(const char *arg0) { - fprintf(stderr, "See `%s --help` for detailed usage information\n", arg0); - return EXIT_FAILURE; -} - -static int print_full_usage(const char *arg0, FILE *file, int return_code) { - fprintf(file, - "Usage: %s [options] builds an object file\n" - "\n" - "Options:\n" - " --color [auto|off|on] enable or disable colored error messages\n" - " --name [name] override output name\n" - " -femit-bin=[path] Output machine code\n" - " -fcompiler-rt Always include compiler-rt symbols in output\n" - " --pkg-begin [name] [path] make pkg available to import and push current pkg\n" - " --pkg-end pop current pkg\n" - " -ODebug build with optimizations off and safety on\n" - " -OReleaseFast build with optimizations on and safety off\n" - " -OReleaseSafe build with optimizations on and safety on\n" - " -OReleaseSmall build with size optimizations on and safety off\n" - " -fsingle-threaded source may assume it is only used single-threaded\n" - " -dynamic create a shared library (.so; .dll; .dylib)\n" - " --strip exclude debug symbols\n" - " -target [name] -- see the targets command\n" - " -mcpu [cpu] specify target CPU and feature set\n" - " --verbose-ir enable compiler debug output for Zig IR\n" - " --verbose-llvm-ir enable compiler debug output for LLVM IR\n" - " --verbose-cimport enable compiler debug output for C imports\n" - " --verbose-llvm-cpu-features enable compiler debug output for LLVM CPU features\n" - "\n" - , arg0); - return return_code; -} - -static Os get_zig_os_type(ZigLLVM_OSType os_type) { - switch (os_type) { - case ZigLLVM_UnknownOS: - return OsFreestanding; - case ZigLLVM_Ananas: - return OsAnanas; - case ZigLLVM_CloudABI: - return OsCloudABI; - case ZigLLVM_DragonFly: - return OsDragonFly; - case ZigLLVM_FreeBSD: - return OsFreeBSD; - case ZigLLVM_Fuchsia: - return OsFuchsia; - case ZigLLVM_IOS: - return OsIOS; - case ZigLLVM_KFreeBSD: - return OsKFreeBSD; - case ZigLLVM_Linux: - return OsLinux; - case ZigLLVM_Lv2: - return OsLv2; - case ZigLLVM_Darwin: - case ZigLLVM_MacOSX: - return OsMacOSX; - case ZigLLVM_NetBSD: - return OsNetBSD; - case ZigLLVM_OpenBSD: - return OsOpenBSD; - case ZigLLVM_Solaris: - return OsSolaris; - case ZigLLVM_Win32: - return OsWindows; - case ZigLLVM_ZOS: - return OsZOS; - case ZigLLVM_Haiku: - return OsHaiku; - case ZigLLVM_Minix: - return OsMinix; - case ZigLLVM_RTEMS: - return OsRTEMS; - case ZigLLVM_NaCl: - return OsNaCl; - case ZigLLVM_AIX: - return OsAIX; - case ZigLLVM_CUDA: - return OsCUDA; - case ZigLLVM_NVCL: - return OsNVCL; - case ZigLLVM_AMDHSA: - return OsAMDHSA; - case ZigLLVM_PS4: - return OsPS4; - case ZigLLVM_PS5: - return OsPS5; - case ZigLLVM_ELFIAMCU: - return OsELFIAMCU; - case ZigLLVM_TvOS: - return OsTvOS; - case ZigLLVM_WatchOS: - return OsWatchOS; - case ZigLLVM_Mesa3D: - return OsMesa3D; - case ZigLLVM_Contiki: - return OsContiki; - case ZigLLVM_AMDPAL: - return OsAMDPAL; - case ZigLLVM_HermitCore: - return OsHermitCore; - case ZigLLVM_Hurd: - return OsHurd; - case ZigLLVM_WASI: - return OsWASI; - case ZigLLVM_Emscripten: - return OsEmscripten; - case ZigLLVM_DriverKit: - return OsDriverKit; - case ZigLLVM_ShaderModel: - return OsShaderModel; - } - zig_unreachable(); -} - -static void get_native_target(ZigTarget *target) { - // first zero initialize - *target = {}; - - ZigLLVM_OSType os_type; - ZigLLVM_ObjectFormatType oformat; // ignored; based on arch/os - ZigLLVM_VendorType trash; - ZigLLVMGetNativeTarget( - &target->arch, - &trash, - &os_type, - &target->abi, - &oformat); - target->os = get_zig_os_type(os_type); - target->is_native_os = true; - target->is_native_cpu = true; - if (target->abi == ZigLLVM_UnknownEnvironment) { - target->abi = target_default_abi(target->arch, target->os); - } -} - -static const char* get_baseline_llvm_cpu_name(ZigLLVM_ArchType arch) { - return ""; -} - -static const char* get_baseline_llvm_cpu_features(ZigLLVM_ArchType arch) { - switch (arch) { - case ZigLLVM_riscv64: return "+a,+c,+d,+m"; - default: return ""; - } -} - -static Error target_parse_triple(struct ZigTarget *target, const char *zig_triple, const char *mcpu, - const char *dynamic_linker) -{ - Error err; - - if (zig_triple != nullptr && strcmp(zig_triple, "native") == 0) { - zig_triple = nullptr; - } - - if (zig_triple == nullptr) { - get_native_target(target); - - if (mcpu == nullptr || strcmp(mcpu, "native") == 0) { - target->llvm_cpu_name = ZigLLVMGetHostCPUName(); - target->llvm_cpu_features = ZigLLVMGetNativeFeatures(); - } else if (strcmp(mcpu, "baseline") == 0) { - target->is_native_os = false; - target->is_native_cpu = false; - target->llvm_cpu_name = get_baseline_llvm_cpu_name(target->arch); - target->llvm_cpu_features = get_baseline_llvm_cpu_features(target->arch); - } else { - const char *msg = "stage0 can't handle CPU/features in the target"; - stage2_panic(msg, strlen(msg)); - } - } else { - // first initialize all to zero - *target = {}; - - SplitIterator it = memSplit(str(zig_triple), str("-")); - - Optional> opt_archsub = SplitIterator_next(&it); - Optional> opt_os = SplitIterator_next(&it); - Optional> opt_abi = SplitIterator_next(&it); - - if (!opt_archsub.is_some) - return ErrorMissingArchitecture; - - if ((err = target_parse_arch(&target->arch, (char*)opt_archsub.value.ptr, opt_archsub.value.len))) { - return err; - } - - if (!opt_os.is_some) - return ErrorMissingOperatingSystem; - - if ((err = target_parse_os(&target->os, (char*)opt_os.value.ptr, opt_os.value.len))) { - return err; - } - - if (opt_abi.is_some) { - if ((err = target_parse_abi(&target->abi, (char*)opt_abi.value.ptr, opt_abi.value.len))) { - return err; - } - } else { - target->abi = target_default_abi(target->arch, target->os); - } - - if (mcpu != nullptr && strcmp(mcpu, "baseline") != 0) { - const char *msg = "stage0 can't handle CPU/features in the target"; - stage2_panic(msg, strlen(msg)); - } - - target->llvm_cpu_name = get_baseline_llvm_cpu_name(target->arch); - target->llvm_cpu_features = get_baseline_llvm_cpu_features(target->arch); - } - - return ErrorNone; -} - - -static bool str_starts_with(const char *s1, const char *s2) { - size_t s2_len = strlen(s2); - if (strlen(s1) < s2_len) { - return false; - } - return memcmp(s1, s2, s2_len) == 0; -} - -int main_exit(Stage2ProgressNode *root_progress_node, int exit_code) { - if (root_progress_node != nullptr) { - stage2_progress_end(root_progress_node); - } - return exit_code; -} - -int main(int argc, char **argv) { - zig_stage1_os_init(); - - char *arg0 = argv[0]; - Error err; - - const char *in_file = nullptr; - const char *emit_bin_path = nullptr; - bool strip = false; - const char *out_name = nullptr; - bool verbose_ir = false; - bool verbose_llvm_ir = false; - bool verbose_cimport = false; - bool verbose_llvm_cpu_features = false; - ErrColor color = ErrColorAuto; - const char *dynamic_linker = nullptr; - bool link_libc = false; - bool link_libcpp = false; - const char *target_string = nullptr; - ZigStage1Pkg *cur_pkg = heap::c_allocator.create(); - BuildMode optimize_mode = BuildModeDebug; - TargetSubsystem subsystem = TargetSubsystemAuto; - const char *override_lib_dir = nullptr; - const char *mcpu = nullptr; - bool single_threaded = false; - bool is_test_build = false; - bool include_compiler_rt = false; - - for (int i = 1; i < argc; i += 1) { - char *arg = argv[i]; - - if (arg[0] == '-') { - if (strcmp(arg, "--") == 0) { - fprintf(stderr, "Unexpected end-of-parameter mark: %s\n", arg); - } else if (strcmp(arg, "--test") == 0) { - is_test_build = true; - } else if (strcmp(arg, "-ODebug") == 0) { - optimize_mode = BuildModeDebug; - } else if (strcmp(arg, "-OReleaseFast") == 0) { - optimize_mode = BuildModeFastRelease; - } else if (strcmp(arg, "-OReleaseSafe") == 0) { - optimize_mode = BuildModeSafeRelease; - } else if (strcmp(arg, "-OReleaseSmall") == 0) { - optimize_mode = BuildModeSmallRelease; - } else if (strcmp(arg, "-fsingle-threaded") == 0) { - single_threaded = true; - } else if (strcmp(arg, "--help") == 0) { - return print_full_usage(arg0, stdout, EXIT_SUCCESS); - } else if (strcmp(arg, "--strip") == 0) { - strip = true; - } else if (strcmp(arg, "--verbose-ir") == 0) { - verbose_ir = true; - } else if (strcmp(arg, "--verbose-llvm-ir") == 0) { - verbose_llvm_ir = true; - } else if (strcmp(arg, "--verbose-cimport") == 0) { - verbose_cimport = true; - } else if (strcmp(arg, "--verbose-llvm-cpu-features") == 0) { - verbose_llvm_cpu_features = true; - } else if (arg[1] == 'l' && arg[2] != 0) { - // alias for --library - const char *l = &arg[2]; - if (strcmp(l, "c") == 0) { - link_libc = true; - } else if (strcmp(l, "c++") == 0 || strcmp(l, "stdc++") == 0) { - link_libcpp = true; - } - } else if (strcmp(arg, "--pkg-begin") == 0) { - if (i + 2 >= argc) { - fprintf(stderr, "Expected 2 arguments after --pkg-begin\n"); - return print_error_usage(arg0); - } - ZigStage1Pkg *new_cur_pkg = heap::c_allocator.create(); - i += 1; - new_cur_pkg->name_ptr = argv[i]; - new_cur_pkg->name_len = strlen(argv[i]); - i += 1; - new_cur_pkg->path_ptr = argv[i]; - new_cur_pkg->path_len = strlen(argv[i]); - new_cur_pkg->parent = cur_pkg; - cur_pkg->children_ptr = heap::c_allocator.reallocate(cur_pkg->children_ptr, - cur_pkg->children_len, cur_pkg->children_len + 1); - cur_pkg->children_ptr[cur_pkg->children_len] = new_cur_pkg; - cur_pkg->children_len += 1; - - cur_pkg = new_cur_pkg; - } else if (strcmp(arg, "--pkg-end") == 0) { - if (cur_pkg->parent == nullptr) { - fprintf(stderr, "Encountered --pkg-end with no matching --pkg-begin\n"); - return EXIT_FAILURE; - } - cur_pkg = cur_pkg->parent; - } else if (str_starts_with(arg, "-mcpu=")) { - mcpu = arg + strlen("-mcpu="); - } else if (str_starts_with(arg, "-femit-bin=")) { - emit_bin_path = arg + strlen("-femit-bin="); - } else if (strcmp(arg, "-fcompiler-rt") == 0) { - include_compiler_rt = true; - } else if (i + 1 >= argc) { - fprintf(stderr, "Expected another argument after %s\n", arg); - return print_error_usage(arg0); - } else { - i += 1; - if (strcmp(arg, "--color") == 0) { - if (strcmp(argv[i], "auto") == 0) { - color = ErrColorAuto; - } else if (strcmp(argv[i], "on") == 0) { - color = ErrColorOn; - } else if (strcmp(argv[i], "off") == 0) { - color = ErrColorOff; - } else { - fprintf(stderr, "--color options are 'auto', 'on', or 'off'\n"); - return print_error_usage(arg0); - } - } else if (strcmp(arg, "--name") == 0) { - out_name = argv[i]; - } else if (strcmp(arg, "--dynamic-linker") == 0) { - dynamic_linker = argv[i]; - } else if (strcmp(arg, "--zig-lib-dir") == 0) { - override_lib_dir = argv[i]; - } else if (strcmp(arg, "--library") == 0 || strcmp(arg, "-l") == 0) { - if (strcmp(argv[i], "c") == 0) { - link_libc = true; - } else if (strcmp(argv[i], "c++") == 0 || strcmp(argv[i], "stdc++") == 0) { - link_libcpp = true; - } - } else if (strcmp(arg, "-target") == 0) { - target_string = argv[i]; - } else if (strcmp(arg, "--subsystem") == 0) { - if (strcmp(argv[i], "console") == 0) { - subsystem = TargetSubsystemConsole; - } else if (strcmp(argv[i], "windows") == 0) { - subsystem = TargetSubsystemWindows; - } else if (strcmp(argv[i], "posix") == 0) { - subsystem = TargetSubsystemPosix; - } else if (strcmp(argv[i], "native") == 0) { - subsystem = TargetSubsystemNative; - } else if (strcmp(argv[i], "efi_application") == 0) { - subsystem = TargetSubsystemEfiApplication; - } else if (strcmp(argv[i], "efi_boot_service_driver") == 0) { - subsystem = TargetSubsystemEfiBootServiceDriver; - } else if (strcmp(argv[i], "efi_rom") == 0) { - subsystem = TargetSubsystemEfiRom; - } else if (strcmp(argv[i], "efi_runtime_driver") == 0) { - subsystem = TargetSubsystemEfiRuntimeDriver; - } else { - fprintf(stderr, "invalid: --subsystem %s\n" - "Options are:\n" - " console\n" - " windows\n" - " posix\n" - " native\n" - " efi_application\n" - " efi_boot_service_driver\n" - " efi_rom\n" - " efi_runtime_driver\n" - , argv[i]); - return EXIT_FAILURE; - } - } else if (strcmp(arg, "-mcpu") == 0) { - mcpu = argv[i]; - } else { - fprintf(stderr, "Invalid argument: %s\n", arg); - return print_error_usage(arg0); - } - } - } else if (!in_file) { - in_file = arg; - } else { - fprintf(stderr, "Unexpected extra parameter: %s\n", arg); - return print_error_usage(arg0); - } - } - - if (cur_pkg->parent != nullptr) { - fprintf(stderr, "Unmatched --pkg-begin\n"); - return EXIT_FAILURE; - } - - Stage2Progress *progress = stage2_progress_create(); - Stage2ProgressNode *root_progress_node = stage2_progress_start_root(progress, "", 0, 0); - if (color == ErrColorOff) stage2_progress_disable_tty(progress); - - ZigTarget target; - if ((err = target_parse_triple(&target, target_string, mcpu, dynamic_linker))) { - fprintf(stderr, "invalid target: %s\n", err_str(err)); - return print_error_usage(arg0); - } - - if (in_file == nullptr) { - fprintf(stderr, "missing zig file\n"); - return print_error_usage(arg0); - } - - if (out_name == nullptr) { - fprintf(stderr, "missing --name\n"); - return print_error_usage(arg0); - } - - if (override_lib_dir == nullptr) { - fprintf(stderr, "missing --zig-lib-dir\n"); - return print_error_usage(arg0); - } - - if (emit_bin_path == nullptr) { - fprintf(stderr, "missing -femit-bin=\n"); - return print_error_usage(arg0); - } - - ZigStage1 *stage1 = zig_stage1_create(optimize_mode, - nullptr, 0, - in_file, strlen(in_file), - override_lib_dir, strlen(override_lib_dir), - &target, is_test_build); - - stage1->main_progress_node = root_progress_node; - stage1->root_name_ptr = out_name; - stage1->root_name_len = strlen(out_name); - stage1->strip = strip; - stage1->verbose_ir = verbose_ir; - stage1->verbose_llvm_ir = verbose_llvm_ir; - stage1->verbose_cimport = verbose_cimport; - stage1->verbose_llvm_cpu_features = verbose_llvm_cpu_features; - stage1->emit_o_ptr = emit_bin_path; - stage1->emit_o_len = strlen(emit_bin_path); - stage1->main_pkg = cur_pkg; - stage1->err_color = color; - stage1->link_libc = link_libc; - stage1->link_libcpp = link_libcpp; - stage1->subsystem = subsystem; - stage1->pic = true; - stage1->is_single_threaded = single_threaded; - stage1->include_compiler_rt = include_compiler_rt; - - zig_stage1_build_object(stage1); - - zig_stage1_destroy(stage1); - - return main_exit(root_progress_node, EXIT_SUCCESS); -} - -void stage2_panic(const char *ptr, size_t len) { - fwrite(ptr, 1, len, stderr); - fprintf(stderr, "\n"); - fflush(stderr); - abort(); -} - -struct Stage2Progress { - int trash; -}; - -struct Stage2ProgressNode { - int trash; -}; - -Stage2Progress *stage2_progress_create(void) { - return nullptr; -} - -void stage2_progress_destroy(Stage2Progress *progress) {} - -Stage2ProgressNode *stage2_progress_start_root(Stage2Progress *progress, - const char *name_ptr, size_t name_len, size_t estimated_total_items) -{ - return nullptr; -} -Stage2ProgressNode *stage2_progress_start(Stage2ProgressNode *node, - const char *name_ptr, size_t name_len, size_t estimated_total_items) -{ - return nullptr; -} -void stage2_progress_end(Stage2ProgressNode *node) {} -void stage2_progress_complete_one(Stage2ProgressNode *node) {} -void stage2_progress_disable_tty(Stage2Progress *progress) {} -void stage2_progress_update_node(Stage2ProgressNode *node, size_t completed_count, size_t estimated_total_items){} - -const char *stage2_fetch_file(struct ZigStage1 *stage1, const char *path_ptr, size_t path_len, - size_t *result_len) -{ - Error err; - Buf contents_buf = BUF_INIT; - Buf path_buf = BUF_INIT; - - buf_init_from_mem(&path_buf, path_ptr, path_len); - if ((err = os_fetch_file_path(&path_buf, &contents_buf))) { - return nullptr; - } - *result_len = buf_len(&contents_buf); - return buf_ptr(&contents_buf); -} - -Error stage2_cimport(struct ZigStage1 *stage1, const char *c_src_ptr, size_t c_src_len, - const char **out_zig_path_ptr, size_t *out_zig_path_len, - struct Stage2ErrorMsg **out_errors_ptr, size_t *out_errors_len) -{ - const char *msg = "stage0 called stage2_cimport"; - stage2_panic(msg, strlen(msg)); -} - -const char *stage2_add_link_lib(struct ZigStage1 *stage1, - const char *lib_name_ptr, size_t lib_name_len, - const char *symbol_name_ptr, size_t symbol_name_len) -{ - return nullptr; -} - -const char *stage2_version_string(void) { - return ZIG_VERSION_STRING; -} - -struct Stage2SemVer stage2_version(void) { - return {ZIG_VERSION_MAJOR, ZIG_VERSION_MINOR, ZIG_VERSION_PATCH}; -} - -Error stage2_append_symbol(struct ZigStage1 *stage1, const char *name_ptr, size_t name_len) -{ - return ErrorNone; -} diff --git a/src/stage1/zigendian.h b/src/stage1/zigendian.h deleted file mode 100644 index 0a4f6a6ad2c3..000000000000 --- a/src/stage1/zigendian.h +++ /dev/null @@ -1,34 +0,0 @@ -#ifndef ZIG_ENDIAN_H -#define ZIG_ENDIAN_H - -// Every OSes seem to define endianness macros in different files. -#if defined(__APPLE__) - #include - #define ZIG_BIG_ENDIAN BIG_ENDIAN - #define ZIG_LITTLE_ENDIAN LITTLE_ENDIAN - #define ZIG_BYTE_ORDER BYTE_ORDER -#elif defined(__DragonFly__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) - #include - #define ZIG_BIG_ENDIAN _BIG_ENDIAN - #define ZIG_LITTLE_ENDIAN _LITTLE_ENDIAN - #define ZIG_BYTE_ORDER _BYTE_ORDER -#elif defined(_WIN32) || defined(_WIN64) - // Assume that Windows installations are always little endian. - #define ZIG_LITTLE_ENDIAN 1 - #define ZIG_BYTE_ORDER ZIG_LITTLE_ENDIAN -#else // Linux - #include - #define ZIG_BIG_ENDIAN __BIG_ENDIAN - #define ZIG_LITTLE_ENDIAN __LITTLE_ENDIAN - #define ZIG_BYTE_ORDER __BYTE_ORDER -#endif - -#if defined(ZIG_BYTE_ORDER) && ZIG_BYTE_ORDER == ZIG_LITTLE_ENDIAN - const bool native_is_big_endian = false; -#elif defined(ZIG_BYTE_ORDER) && ZIG_BYTE_ORDER == ZIG_BIG_ENDIAN - const bool native_is_big_endian = true; -#else - #error Unsupported endian -#endif - -#endif // ZIG_ENDIAN_H diff --git a/src/test.zig b/src/test.zig index ab70198e410d..56abe248b3c1 100644 --- a/src/test.zig +++ b/src/test.zig @@ -20,15 +20,11 @@ const enable_wasmtime: bool = build_options.enable_wasmtime; const enable_darling: bool = build_options.enable_darling; const enable_rosetta: bool = build_options.enable_rosetta; const glibc_runtimes_dir: ?[]const u8 = build_options.glibc_runtimes_dir; -const skip_stage1 = builtin.zig_backend != .stage1 or build_options.skip_stage1; +const skip_stage1 = true; const hr = "=" ** 80; test { - if (build_options.have_stage1) { - @import("stage1.zig").os_init(); - } - const use_gpa = build_options.force_gpa or !builtin.link_libc; const gpa = gpa: { if (use_gpa) { @@ -1548,7 +1544,6 @@ pub const TestContext = struct { .dynamic_linker = target_info.dynamic_linker.get(), .link_libc = case.link_libc, .use_llvm = use_llvm, - .use_stage1 = null, // We already handled stage1 tests .self_exe_path = zig_exe_path, // TODO instead of turning off color, pass in a std.Progress.Node .color = .off, diff --git a/src/translate_c.zig b/src/translate_c.zig index 7a4bd843a58f..d4b2e0c709fc 100644 --- a/src/translate_c.zig +++ b/src/translate_c.zig @@ -327,16 +327,6 @@ pub const Context = struct { pattern_list: PatternList, - /// This is used to emit different code depending on whether - /// the output zig source code is intended to be compiled with stage1 or stage2. - /// Ideally we will have stage1 and stage2 support the exact same Zig language, - /// but for now they diverge because I would rather focus on finishing and shipping - /// stage2 than implementing the features in stage1. - /// The list of differences are currently: - /// * function pointers in stage1 are e.g. `fn()void` - /// but in stage2 they are `*const fn()void`. - zig_is_stage1: bool, - fn getMangle(c: *Context) u32 { c.mangle_count += 1; return c.mangle_count; @@ -365,7 +355,6 @@ pub fn translate( args_end: [*]?[*]const u8, errors: *[]ClangErrMsg, resources_path: [*:0]const u8, - zig_is_stage1: bool, ) !std.zig.Ast { // TODO stage2 bug var tmp = errors; @@ -395,7 +384,6 @@ pub fn translate( .global_scope = try arena.create(Scope.Root), .clang_context = ast_unit.getASTContext(), .pattern_list = try PatternList.init(gpa), - .zig_is_stage1 = zig_is_stage1, }; context.global_scope.* = Scope.Root.init(&context); defer { @@ -435,7 +423,7 @@ pub fn translate( } } - return ast.render(gpa, zig_is_stage1, context.global_scope.nodes.items); + return ast.render(gpa, context.global_scope.nodes.items); } /// Determines whether macro is of the form: `#define FOO FOO` (Possibly with trailing tokens) @@ -4747,9 +4735,6 @@ fn transType(c: *Context, scope: *Scope, ty: *const clang.Type, source_loc: clan .Pointer => { const child_qt = ty.getPointeeType(); const is_fn_proto = qualTypeChildIsFnProto(child_qt); - if (c.zig_is_stage1 and is_fn_proto) { - return Tag.optional_type.create(c.arena, try transQualType(c, scope, child_qt, source_loc)); - } const is_const = is_fn_proto or child_qt.isConstQualified(); const is_volatile = child_qt.isVolatileQualified(); const elem_type = try transQualType(c, scope, child_qt, source_loc); @@ -6681,16 +6666,10 @@ fn getFnProto(c: *Context, ref: Node) ?*ast.Payload.Func { return null; if (getContainerTypeOf(c, init)) |ty_node| { if (ty_node.castTag(.optional_type)) |prefix| { - if (c.zig_is_stage1) { - if (prefix.data.castTag(.func)) |fn_proto| { + if (prefix.data.castTag(.single_pointer)) |sp| { + if (sp.data.elem_type.castTag(.func)) |fn_proto| { return fn_proto; } - } else { - if (prefix.data.castTag(.single_pointer)) |sp| { - if (sp.data.elem_type.castTag(.func)) |fn_proto| { - return fn_proto; - } - } } } } diff --git a/src/translate_c/ast.zig b/src/translate_c/ast.zig index bc0f002c2116..1ed2eb568c63 100644 --- a/src/translate_c/ast.zig +++ b/src/translate_c/ast.zig @@ -732,11 +732,10 @@ pub const Payload = struct { /// Converts the nodes into a Zig Ast. /// Caller must free the source slice. -pub fn render(gpa: Allocator, zig_is_stage1: bool, nodes: []const Node) !std.zig.Ast { +pub fn render(gpa: Allocator, nodes: []const Node) !std.zig.Ast { var ctx = Context{ .gpa = gpa, .buf = std.ArrayList(u8).init(gpa), - .zig_is_stage1 = zig_is_stage1, }; defer ctx.buf.deinit(); defer ctx.nodes.deinit(gpa); @@ -805,11 +804,6 @@ const Context = struct { extra_data: std.ArrayListUnmanaged(std.zig.Ast.Node.Index) = .{}, tokens: std.zig.Ast.TokenList = .{}, - /// This is used to emit different code depending on whether - /// the output zig source code is intended to be compiled with stage1 or stage2. - /// Refer to the Context in translate_c.zig. - zig_is_stage1: bool, - fn addTokenFmt(c: *Context, tag: TokenTag, comptime format: []const u8, args: anytype) Allocator.Error!TokenIndex { const start_index = c.buf.items.len; try c.buf.writer().print(format ++ " ", args); @@ -932,7 +926,7 @@ fn renderNode(c: *Context, node: Node) Allocator.Error!NodeIndex { .call => { const payload = node.castTag(.call).?.data; // Cosmetic: avoids an unnecesary address_of on most function calls. - const lhs = if (!c.zig_is_stage1 and payload.lhs.tag() == .fn_identifier) + const lhs = if (payload.lhs.tag() == .fn_identifier) try c.addNode(.{ .tag = .identifier, .main_token = try c.addIdentifier(payload.lhs.castTag(.fn_identifier).?.data), @@ -1097,28 +1091,20 @@ fn renderNode(c: *Context, node: Node) Allocator.Error!NodeIndex { // value (implicit in stage1, explicit in stage2), except in // the context of an address_of, which is handled there. const payload = node.castTag(.fn_identifier).?.data; - if (c.zig_is_stage1) { - return try c.addNode(.{ - .tag = .identifier, - .main_token = try c.addIdentifier(payload), - .data = undefined, - }); - } else { - const tok = try c.addToken(.ampersand, "&"); - const arg = try c.addNode(.{ - .tag = .identifier, - .main_token = try c.addIdentifier(payload), - .data = undefined, - }); - return c.addNode(.{ - .tag = .address_of, - .main_token = tok, - .data = .{ - .lhs = arg, - .rhs = undefined, - }, - }); - } + const tok = try c.addToken(.ampersand, "&"); + const arg = try c.addNode(.{ + .tag = .identifier, + .main_token = try c.addIdentifier(payload), + .data = undefined, + }); + return c.addNode(.{ + .tag = .address_of, + .main_token = tok, + .data = .{ + .lhs = arg, + .rhs = undefined, + }, + }); }, .float_literal => { const payload = node.castTag(.float_literal).?.data; @@ -1448,12 +1434,6 @@ fn renderNode(c: *Context, node: Node) Allocator.Error!NodeIndex { .optional_type => return renderPrefixOp(c, node, .optional_type, .question_mark, "?"), .address_of => { const payload = node.castTag(.address_of).?.data; - if (c.zig_is_stage1 and payload.tag() == .fn_identifier) - return try c.addNode(.{ - .tag = .identifier, - .main_token = try c.addIdentifier(payload.castTag(.fn_identifier).?.data), - .data = undefined, - }); const ampersand = try c.addToken(.ampersand, "&"); const base = if (payload.tag() == .fn_identifier) diff --git a/stage1/FuncGen.h b/stage1/FuncGen.h new file mode 100644 index 000000000000..41717c3d4992 --- /dev/null +++ b/stage1/FuncGen.h @@ -0,0 +1,174 @@ +#ifndef FUNC_GEN_H +#define FUNC_GEN_H + +#include "panic.h" +#include "wasm.h" + +#include +#include +#include +#include +#include + +struct Block { + uint32_t type; + uint32_t label; + uint32_t stack_i; +}; + +struct FuncGen { + int8_t *type; + uint32_t *stack; + struct Block *block; + uint32_t type_i; + uint32_t stack_i; + uint32_t block_i; + uint32_t type_len; + uint32_t stack_len; + uint32_t block_len; +}; + +static void FuncGen_init(struct FuncGen *self) { + memset(self, 0, sizeof(struct FuncGen)); +} + +static void FuncGen_reset(struct FuncGen *self) { + self->type_i = 0; + self->stack_i = 0; + self->block_i = 0; +} + +static void FuncGen_free(struct FuncGen *self) { + free(self->block); + free(self->stack); + free(self->type); +} + +static void FuncGen_outdent(struct FuncGen *self, FILE *out) { + for (uint32_t i = 0; i < self->block_i; i += 1) fputs(" ", out); +} + +static void FuncGen_indent(struct FuncGen *self, FILE *out) { + FuncGen_outdent(self, out); + fputs(" ", out); +} + +static void FuncGen_cont(struct FuncGen *self, FILE *out) { + FuncGen_indent(self, out); + fputs(" ", out); +} + +static uint32_t FuncGen_localAlloc(struct FuncGen *self, int8_t type) { + if (self->type_i == self->type_len) { + self->type_len += 10; + self->type_len *= 2; + self->type = realloc(self->type, sizeof(int8_t) * self->type_len); + if (self->type == NULL) panic("out of memory"); + } + uint32_t local_i = self->type_i; + self->type[local_i] = type; + self->type_i += 1; + return local_i; +} + +static uint32_t FuncGen_localDeclare(struct FuncGen *self, FILE *out, enum WasmValType val_type) { + uint32_t local_i = FuncGen_localAlloc(self, (int8_t)val_type); + fprintf(out, "%s l%" PRIu32, WasmValType_toC(val_type), local_i); + return local_i; +} + +static enum WasmValType FuncGen_localType(const struct FuncGen *self, uint32_t local_idx) { + return self->type[local_idx]; +} + +static void FuncGen_stackPush(struct FuncGen *self, FILE *out, enum WasmValType val_type) { + if (self->stack_i == self->stack_len) { + self->stack_len += 10; + self->stack_len *= 2; + self->stack = realloc(self->stack, sizeof(uint32_t) * self->stack_len); + if (self->stack == NULL) panic("out of memory"); + } + FuncGen_indent(self, out); + fputs("const ", out); + self->stack[self->stack_i] = FuncGen_localDeclare(self, out, val_type); + self->stack_i += 1; + fputs(" = ", out); +} + +static uint32_t FuncGen_stackAt(const struct FuncGen *self, uint32_t stack_idx) { + return self->stack[self->stack_i - 1 - stack_idx]; +} + +static uint32_t FuncGen_stackPop(struct FuncGen *self) { + self->stack_i -= 1; + return self->stack[self->stack_i]; +} + +static void FuncGen_label(struct FuncGen *self, FILE *out, uint32_t label) { + FuncGen_indent(self, out); + fprintf(out, "goto l%" PRIu32 ";\n", label); + FuncGen_outdent(self, out); + fprintf(out, "l%" PRIu32 ":;\n", label); +} + +static void FuncGen_blockBegin(struct FuncGen *self, FILE *out, enum WasmOpcode kind, int64_t type) { + if (self->block_i == self->block_len) { + self->block_len += 10; + self->block_len *= 2; + self->block = realloc(self->block, sizeof(struct Block) * self->block_len); + if (self->block == NULL) panic("out of memory"); + } + uint32_t label = FuncGen_localAlloc(self, type < 0 ? ~(int8_t)kind : (int8_t)kind); + + if (kind == WasmOpcode_if) { + FuncGen_indent(self, out); + fprintf(out, "if (l%" PRIu32 ") {\n", FuncGen_stackPop(self)); + } else if (EXTRA_BRACES) { + FuncGen_indent(self, out); + fputs("{\n", out); + } + + self->block[self->block_i].type = type < 0 ? ~type : type; + self->block[self->block_i].label = label; + self->block[self->block_i].stack_i = self->stack_i; + self->block_i += 1; + if (kind == WasmOpcode_loop) FuncGen_label(self, out, label); +} + +static enum WasmOpcode FuncGen_blockKind(const struct FuncGen *self, uint32_t label_idx) { + int8_t kind = self->type[self->block[self->block_i - 1 - label_idx].label]; + return (enum WasmOpcode)(kind < 0 ? ~kind : kind); +} + +static int64_t FuncGen_blockType(const struct FuncGen *self, uint32_t label_idx) { + struct Block *block = &self->block[self->block_i - 1 - label_idx]; + return self->type[block->label] < 0 ? ~(int64_t)block->type : (int64_t)block->type; +} + +static uint32_t FuncGen_blockLabel(const struct FuncGen *self, uint32_t label_idx) { + return self->block[self->block_i - 1 - label_idx].label; +} + +static void FuncGen_blockEnd(struct FuncGen *self, FILE *out) { + enum WasmOpcode kind = FuncGen_blockKind(self, 0); + uint32_t label = FuncGen_blockLabel(self, 0); + if (kind != WasmOpcode_loop) FuncGen_label(self, out, label); + self->block_i -= 1; + + if (EXTRA_BRACES || kind == WasmOpcode_if) { + FuncGen_indent(self, out); + fputs("}\n", out); + } + + if (self->stack_i != self->block[self->block_i].stack_i) { + FuncGen_indent(self, out); + fprintf(out, "// stack mismatch %u != %u\n", self->stack_i, self->block[self->block_i].stack_i); + } + self->stack_i = self->block[self->block_i].stack_i; +} + +static bool FuncGen_done(const struct FuncGen *self) { + return self->block_i == 0; +} + +#endif /* FUNC_GEN_H */ diff --git a/stage1/InputStream.h b/stage1/InputStream.h new file mode 100644 index 000000000000..36de3d6c7b81 --- /dev/null +++ b/stage1/InputStream.h @@ -0,0 +1,241 @@ +#ifndef INPUT_STREAM_H +#define INPUT_STREAM_H + +#include "panic.h" +#include "wasm.h" + +#include + +#include +#include +#include +#include +#include +#include + +struct InputStream { + FILE *stream; + ZSTD_DStream *ds; + ZSTD_outBuffer out; + ZSTD_inBuffer in; + size_t pos; +}; + +static void InputStream_open(struct InputStream *self, const char *path) { + self->stream = fopen(path, "rb"); + if (self->stream == NULL) panic("unable to open input file"); + self->ds = ZSTD_createDStream(); + if (self->ds == NULL) panic("unable to create zstd context"); + size_t in_size = ZSTD_initDStream(self->ds); + if (ZSTD_isError(in_size)) panic(ZSTD_getErrorName(in_size)); + self->out.size = ZSTD_DStreamOutSize(); + self->out.dst = malloc(self->out.size + ZSTD_DStreamInSize()); + if (self->out.dst == NULL) panic("unable to allocate input buffers"); + self->out.pos = 0; + self->in.src = (const char *)self->out.dst + self->out.size; + self->in.size = fread((void *)self->in.src, 1, in_size, self->stream); + self->in.pos = 0; + self->pos = 0; +} + +static void InputStream_close(struct InputStream *self) { + free(self->out.dst); + ZSTD_freeDStream(self->ds); + fclose(self->stream); +} + +static bool InputStream_atEnd(struct InputStream *self) { + while (self->pos >= self->out.pos) { + self->out.pos = 0; + self->pos = 0; + size_t in_size = ZSTD_decompressStream(self->ds, &self->out, &self->in); + if (ZSTD_isError(in_size)) panic(ZSTD_getErrorName(in_size)); + if (self->in.pos >= self->in.size) { + size_t max_in_size = ZSTD_DStreamInSize(); + if (in_size > max_in_size) in_size = max_in_size; + self->in.size = fread((void *)self->in.src, 1, in_size, self->stream); + self->in.pos = 0; + if (self->in.pos >= self->in.size) return true; + } + } + return false; +} + +static uint8_t InputStream_readByte(struct InputStream *self) { + if (InputStream_atEnd(self)) panic("unexpected end of input stream"); + uint8_t value = ((uint8_t *)self->out.dst)[self->pos]; + self->pos += 1; + return value; +} + +static uint32_t InputStream_readLittle_u32(struct InputStream *self) { + uint32_t value = 0; + value |= (uint32_t)InputStream_readByte(self) << 0; + value |= (uint32_t)InputStream_readByte(self) << 8; + value |= (uint32_t)InputStream_readByte(self) << 16; + value |= (uint32_t)InputStream_readByte(self) << 24; + return value; +} + +static uint64_t InputStream_readLittle_u64(struct InputStream *self) { + uint64_t value = 0; + value |= (uint64_t)InputStream_readByte(self) << 0; + value |= (uint64_t)InputStream_readByte(self) << 8; + value |= (uint64_t)InputStream_readByte(self) << 16; + value |= (uint64_t)InputStream_readByte(self) << 24; + value |= (uint64_t)InputStream_readByte(self) << 32; + value |= (uint64_t)InputStream_readByte(self) << 40; + value |= (uint64_t)InputStream_readByte(self) << 48; + value |= (uint64_t)InputStream_readByte(self) << 56; + return value; +} + +static float InputStream_readLittle_f32(struct InputStream *self) { + uint32_t value = InputStream_readLittle_u32(self); + float result; + memcpy(&result, &value, sizeof(result)); + return result; +} + +static double InputStream_readLittle_f64(struct InputStream *self) { + uint64_t value = InputStream_readLittle_u64(self); + double result; + memcpy(&result, &value, sizeof(result)); + return result; +} + +static uint32_t InputStream_readLeb128_u32(struct InputStream *self) { + uint32_t value = 0; + uint8_t shift = 0; + uint8_t byte; + do { + byte = InputStream_readByte(self); + assert(shift < 32); + value |= (uint32_t)(byte & 0x7F) << shift; + shift += 7; + } while (byte & 0x80); + return value; +} + +static int32_t InputStream_readLeb128_i32(struct InputStream *self) { + uint32_t value = 0; + uint8_t shift = 0; + uint8_t byte; + do { + byte = InputStream_readByte(self); + assert(shift < 64); + value |= (uint32_t)(byte & 0x7F) << shift; + shift += 7; + } while (byte & 0x80); + if (shift < 32) { + uint32_t mask = -((uint32_t)1 << shift); + if (byte & 0x40) value |= mask; else value &= ~mask; + } + return (int32_t)value; +} + +static int64_t InputStream_readLeb128_u64(struct InputStream *self) { + uint64_t value = 0; + uint8_t shift = 0; + uint8_t byte; + do { + byte = InputStream_readByte(self); + assert(shift < 64); + value |= (uint64_t)(byte & 0x7F) << shift; + shift += 7; + } while (byte & 0x80); + return value; +} + +static int64_t InputStream_readLeb128_i64(struct InputStream *self) { + uint64_t value = 0; + uint8_t shift = 0; + uint8_t byte; + do { + byte = InputStream_readByte(self); + assert(shift < 64); + value |= (uint64_t)(byte & 0x7F) << shift; + shift += 7; + } while (byte & 0x80); + if (shift < 64) { + uint64_t mask = -((uint64_t)1 << shift); + if (byte & 0x40) value |= mask; else value &= ~mask; + } + return (int64_t)value; +} + +static char *InputStream_readName(struct InputStream *self) { + uint32_t len = InputStream_readLeb128_u32(self); + char *name = malloc(len + 1); + if (name == NULL) panic("out of memory"); + for (uint32_t i = 0; i < len; ) { + if (InputStream_atEnd(self)) panic("unexpected end of input stream"); + size_t remaining = self->out.pos - self->pos; + if (remaining > len - i) remaining = len - i; + memcpy(&name[i], &((char *)self->out.dst)[self->pos], remaining); + i += remaining; + self->pos += remaining; + } + name[len] = '\0'; + return name; +} + +static void InputStream_skipBytes(struct InputStream *self, size_t len) { + for (size_t i = 0; i < len; ) { + if (InputStream_atEnd(self)) panic("unexpected end of input stream"); + size_t remaining = self->out.pos - self->pos; + if (remaining > len - i) remaining = len - i; + i += remaining; + self->pos += remaining; + } +} + +static uint32_t InputStream_skipToSection(struct InputStream *self, uint8_t expected_id) { + while (true) { + uint8_t id = InputStream_readByte(self); + uint32_t size = InputStream_readLeb128_u32(self); + if (id == expected_id) return size; + InputStream_skipBytes(self, size); + } +} + +struct ResultType { + uint32_t len; + int8_t types[1]; +}; +static struct ResultType *InputStream_readResultType(struct InputStream *self) { + uint32_t len = InputStream_readLeb128_u32(self); + struct ResultType *result_type = malloc(offsetof(struct ResultType, types) + sizeof(int8_t) * len); + if (result_type == NULL) panic("out of memory"); + result_type->len = len; + for (uint32_t i = 0; i < len; i += 1) { + int64_t val_type = InputStream_readLeb128_i64(self); + switch (val_type) { + case WasmValType_i32: case WasmValType_i64: + case WasmValType_f32: case WasmValType_f64: + break; + + default: panic("unsupported valtype"); + } + result_type->types[i] = val_type; + } + return result_type; +} + +struct Limits { + uint32_t min; + uint32_t max; +}; +static struct Limits InputStream_readLimits(struct InputStream *self) { + struct Limits limits; + uint8_t kind = InputStream_readByte(self); + limits.min = InputStream_readLeb128_u32(self); + switch (kind) { + case 0x00: limits.max = UINT32_MAX; break; + case 0x01: limits.max = InputStream_readLeb128_u32(self); break; + default: panic("unsupported limit kind"); + } + return limits; +} + +#endif /* INPUT_STREAM_H */ diff --git a/src/stage1/config.h.in b/stage1/config.h.in similarity index 94% rename from src/stage1/config.h.in rename to stage1/config.h.in index 22311373f69a..2d4fff6df297 100644 --- a/src/stage1/config.h.in +++ b/stage1/config.h.in @@ -12,7 +12,7 @@ #define ZIG_VERSION_MAJOR @ZIG_VERSION_MAJOR@ #define ZIG_VERSION_MINOR @ZIG_VERSION_MINOR@ #define ZIG_VERSION_PATCH @ZIG_VERSION_PATCH@ -#define ZIG_VERSION_STRING "@RESOLVED_ZIG_VERSION@" +#define ZIG_VERSION_STRING "@ZIG_VERSION@" // Used by build.zig for communicating build information to self hosted build. #define ZIG_CMAKE_BINARY_DIR "@CMAKE_BINARY_DIR@" diff --git a/src/config.zig.in b/stage1/config.zig.in similarity index 81% rename from src/config.zig.in rename to stage1/config.zig.in index 2a0d45c010f8..68d09f159b99 100644 --- a/src/config.zig.in +++ b/stage1/config.zig.in @@ -4,10 +4,11 @@ pub const llvm_has_csky = false; pub const llvm_has_arc = false; pub const version: [:0]const u8 = "@RESOLVED_ZIG_VERSION@"; pub const semver = @import("std").SemanticVersion.parse(version) catch unreachable; -pub const enable_logging: bool = @ZIG_ENABLE_LOGGING_BOOL@; +pub const enable_logging: bool = false; pub const enable_link_snapshots: bool = false; pub const enable_tracy = false; pub const value_tracing = false; -pub const have_stage1 = true; +pub const have_stage1 = false; pub const skip_non_native = false; pub const only_c = false; +pub const force_gpa = false; diff --git a/stage1/panic.h b/stage1/panic.h new file mode 100644 index 000000000000..7a8fc5f45071 --- /dev/null +++ b/stage1/panic.h @@ -0,0 +1,12 @@ +#ifndef PANIC_H +#define PANIC_H + +#include +#include + +static void panic(const char *reason) { + fprintf(stderr, "%s\n", reason); + abort(); +} + +#endif /* PANIC_H */ diff --git a/stage1/wasi.c b/stage1/wasi.c new file mode 100644 index 000000000000..911ce6e52053 --- /dev/null +++ b/stage1/wasi.c @@ -0,0 +1,974 @@ +#include +#include +#include +#include +#include +#include + +#include "panic.h" + +#define LOG_TRACE 0 + +enum wasi_errno { + wasi_errno_success = 0, + wasi_errno_2big = 1, + wasi_errno_acces = 2, + wasi_errno_addrinuse = 3, + wasi_errno_addrnotavail = 4, + wasi_errno_afnosupport = 5, + wasi_errno_again = 6, + wasi_errno_already = 7, + wasi_errno_badf = 8, + wasi_errno_badmsg = 9, + wasi_errno_busy = 10, + wasi_errno_canceled = 11, + wasi_errno_child = 12, + wasi_errno_connaborted = 13, + wasi_errno_connrefused = 14, + wasi_errno_connreset = 15, + wasi_errno_deadlk = 16, + wasi_errno_destaddrreq = 17, + wasi_errno_dom = 18, + wasi_errno_dquot = 19, + wasi_errno_exist = 20, + wasi_errno_fault = 21, + wasi_errno_fbig = 22, + wasi_errno_hostunreach = 23, + wasi_errno_idrm = 24, + wasi_errno_ilseq = 25, + wasi_errno_inprogress = 26, + wasi_errno_intr = 27, + wasi_errno_inval = 28, + wasi_errno_io = 29, + wasi_errno_isconn = 30, + wasi_errno_isdir = 31, + wasi_errno_loop = 32, + wasi_errno_mfile = 33, + wasi_errno_mlink = 34, + wasi_errno_msgsize = 35, + wasi_errno_multihop = 36, + wasi_errno_nametoolong = 37, + wasi_errno_netdown = 38, + wasi_errno_netreset = 39, + wasi_errno_netunreach = 40, + wasi_errno_nfile = 41, + wasi_errno_nobufs = 42, + wasi_errno_nodev = 43, + wasi_errno_noent = 44, + wasi_errno_noexec = 45, + wasi_errno_nolck = 46, + wasi_errno_nolink = 47, + wasi_errno_nomem = 48, + wasi_errno_nomsg = 49, + wasi_errno_noprotoopt = 50, + wasi_errno_nospc = 51, + wasi_errno_nosys = 52, + wasi_errno_notconn = 53, + wasi_errno_notdir = 54, + wasi_errno_notempty = 55, + wasi_errno_notrecoverable = 56, + wasi_errno_notsock = 57, + wasi_errno_opnotsupp = 58, + wasi_errno_notty = 59, + wasi_errno_nxio = 60, + wasi_errno_overflow = 61, + wasi_errno_ownerdead = 62, + wasi_errno_perm = 63, + wasi_errno_pipe = 64, + wasi_errno_proto = 65, + wasi_errno_protonosupport = 66, + wasi_errno_prototype = 67, + wasi_errno_range = 68, + wasi_errno_rofs = 69, + wasi_errno_spipe = 70, + wasi_errno_srch = 71, + wasi_errno_stale = 72, + wasi_errno_timedout = 73, + wasi_errno_txtbsy = 74, + wasi_errno_xdev = 75, + wasi_errno_notcapable = 76, +}; + +enum wasi_oflags { + wasi_oflags_creat = 1 << 0, + wasi_oflags_directory = 1 << 1, + wasi_oflags_excl = 1 << 2, + wasi_oflags_trunc = 1 << 3, +}; + +enum wasi_rights { + wasi_rights_fd_datasync = 1ull << 0, + wasi_rights_fd_read = 1ull << 1, + wasi_rights_fd_seek = 1ull << 2, + wasi_rights_fd_fdstat_set_flags = 1ull << 3, + wasi_rights_fd_sync = 1ull << 4, + wasi_rights_fd_tell = 1ull << 5, + wasi_rights_fd_write = 1ull << 6, + wasi_rights_fd_advise = 1ull << 7, + wasi_rights_fd_allocate = 1ull << 8, + wasi_rights_path_create_directory = 1ull << 9, + wasi_rights_path_create_file = 1ull << 10, + wasi_rights_path_link_source = 1ull << 11, + wasi_rights_path_link_target = 1ull << 12, + wasi_rights_path_open = 1ull << 13, + wasi_rights_fd_readdir = 1ull << 14, + wasi_rights_path_readlink = 1ull << 15, + wasi_rights_path_rename_source = 1ull << 16, + wasi_rights_path_rename_target = 1ull << 17, + wasi_rights_path_filestat_get = 1ull << 18, + wasi_rights_path_filestat_set_size = 1ull << 19, + wasi_rights_path_filestat_set_times = 1ull << 20, + wasi_rights_fd_filestat_get = 1ull << 21, + wasi_rights_fd_filestat_set_size = 1ull << 22, + wasi_rights_fd_filestat_set_times = 1ull << 23, + wasi_rights_path_symlink = 1ull << 24, + wasi_rights_path_remove_directory = 1ull << 25, + wasi_rights_path_unlink_file = 1ull << 26, + wasi_rights_poll_fd_readwrite = 1ull << 27, + wasi_rights_sock_shutdown = 1ull << 28, + wasi_rights_sock_accept = 1ull << 29, +}; + +enum wasi_clockid { + wasi_clockid_realtime = 0, + wasi_clockid_monotonic = 1, + wasi_clockid_process_cputime_id = 2, + wasi_clockid_thread_cputime_id = 3, +}; + +enum wasi_filetype { + wasi_filetype_unknown = 0, + wasi_filetype_block_device = 1, + wasi_filetype_character_device = 2, + wasi_filetype_directory = 3, + wasi_filetype_regular_file = 4, + wasi_filetype_socket_dgram = 5, + wasi_filetype_socket_stream = 6, + wasi_filetype_symbolic_link = 7, +}; + +enum wasi_fdflags { + wasi_fdflags_append = 1 << 0, + wasi_fdflags_dsync = 1 << 1, + wasi_fdflags_nonblock = 1 << 2, + wasi_fdflags_rsync = 1 << 3, + wasi_fdflags_sync = 1 << 4, +}; + +struct wasi_filestat { + uint64_t dev; + uint64_t ino; + uint64_t filetype; + uint64_t nlink; + uint64_t size; + uint64_t atim; + uint64_t mtim; + uint64_t ctim; +}; + +struct wasi_fdstat { + uint16_t fs_filetype; + uint16_t fs_flags; + uint32_t padding; + uint64_t fs_rights_inheriting; +}; + +struct wasi_ciovec { + uint32_t ptr; + uint32_t len; +}; + +extern uint8_t **const wasm_memory; +extern void wasm__start(void); + +static int global_argc; +static char **global_argv; + +static uint32_t de_len; +struct DirEntry { + enum wasi_filetype filetype; + time_t atim; + time_t mtim; + time_t ctim; + char *guest_path; + char *host_path; +} *des; + +static uint32_t fd_len; +static struct FileDescriptor { + uint32_t de; + FILE *stream; +} *fds; + +static void *dupe(const void *data, size_t len) { + void *copy = malloc(len); + if (copy == NULL) panic("out of memory"); + memcpy(copy, data, len); + return copy; +} + +int main(int argc, char **argv) { + if (argc < 2) { + fprintf(stderr, "usage: %s \n", argv[0]); + return 1; + } + + global_argc = argc; + global_argv = argv; + + time_t now = time(NULL); + srand((unsigned)now); + + de_len = 4; + des = calloc(de_len, sizeof(struct DirEntry)); + if (des == NULL) panic("out of memory"); + + des[0].filetype = wasi_filetype_character_device; + + des[1].filetype = wasi_filetype_directory; + des[1].guest_path = dupe(".", sizeof(".")); + des[1].host_path = dupe(".", sizeof(".")); + + des[2].filetype = wasi_filetype_directory; + des[2].guest_path = dupe("/cache", sizeof("/cache")); + des[2].atim = now; + des[2].mtim = now; + des[2].ctim = now; + + des[3].filetype = wasi_filetype_directory; + des[3].guest_path = dupe("/lib", sizeof("/lib")); + des[3].host_path = dupe(argv[1], strlen(argv[1]) + 1); + + fd_len = 6; + fds = calloc(sizeof(struct FileDescriptor), fd_len); + if (fds == NULL) panic("out of memory"); + fds[0].stream = stdin; + fds[1].stream = stdout; + fds[2].stream = stderr; + fds[3].de = 1; + fds[4].de = 2; + fds[5].de = 3; + + wasm__start(); +} + +static bool isLetter(char c) { + return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z'); +} +static bool isPathSep(char c) { + return c == '/' || c == '\\'; +} +static bool isAbsPath(const char *path, uint32_t path_len) { + if (path_len >= 1 && isPathSep(path[0])) return true; + if (path_len >= 3 && isLetter(path[0]) && path[1] == ':' && isPathSep(path[2])) return true; + return false; +} +static bool isSamePath(const char *a, const char *b, uint32_t len) { + for (uint32_t i = 0; i < len; i += 1) { + if (isPathSep(a[i]) && isPathSep(b[i])) continue; + if (a[i] != b[i]) return false; + } + return true; +} + +static enum wasi_errno DirEntry_create(uint32_t dir_fd, const char *path, uint32_t path_len, enum wasi_filetype filetype, time_t tim, uint32_t *res_de) { + if (isAbsPath(path, path_len)) { + if (dir_fd >= fd_len || fds[dir_fd].de >= de_len) return wasi_errno_badf; + if (des[fds[dir_fd].de].filetype != wasi_filetype_directory) return wasi_errno_notdir; + } + + struct DirEntry *new_des = realloc(des, (de_len + 1) * sizeof(struct DirEntry)); + if (new_des == NULL) return wasi_errno_nomem; + des = new_des; + + struct DirEntry *de = &des[de_len]; + de->filetype = filetype; + de->atim = tim; + de->mtim = tim; + de->ctim = tim; + if (isAbsPath(path, path_len)) { + de->guest_path = malloc(path_len + 1); + if (de->guest_path == NULL) return wasi_errno_nomem; + memcpy(&de->guest_path[0], path, path_len); + de->guest_path[path_len] = '\0'; + + de->host_path = malloc(path_len + 1); + if (de->host_path == NULL) return wasi_errno_nomem; + memcpy(&de->host_path[0], path, path_len); + de->host_path[path_len] = '\0'; + } else { + const struct DirEntry *dir_de = &des[fds[dir_fd].de]; + if (dir_de->guest_path != NULL) { + size_t dir_guest_path_len = strlen(dir_de->guest_path); + de->guest_path = malloc(dir_guest_path_len + 1 + path_len + 1); + if (de->guest_path == NULL) return wasi_errno_nomem; + memcpy(&de->guest_path[0], dir_de->guest_path, dir_guest_path_len); + de->guest_path[dir_guest_path_len] = '/'; + memcpy(&de->guest_path[dir_guest_path_len + 1], path, path_len); + de->guest_path[dir_guest_path_len + 1 + path_len] = '\0'; + } else de->guest_path = NULL; + + if (dir_de->host_path != NULL) { + size_t dir_host_path_len = strlen(dir_de->host_path); + de->host_path = malloc(dir_host_path_len + 1 + path_len + 1); + if (de->host_path == NULL) { free(de->guest_path); return wasi_errno_nomem; } + memcpy(&de->host_path[0], dir_de->host_path, dir_host_path_len); + de->host_path[dir_host_path_len] = '/'; + memcpy(&de->host_path[dir_host_path_len + 1], path, path_len); + de->host_path[dir_host_path_len + 1 + path_len] = '\0'; + } else de->host_path = NULL; + } + + if (res_de != NULL) *res_de = de_len; + de_len += 1; + return wasi_errno_success; +} + +static enum wasi_errno DirEntry_lookup(uint32_t dir_fd, uint32_t flags, const char *path, uint32_t path_len, uint32_t *res_de) { + (void)flags; + if (isAbsPath(path, path_len)) { + for (uint32_t de = 0; de < de_len; de += 1) { + if (des[de].guest_path == NULL) continue; + if (!isSamePath(&des[de].guest_path[0], path, path_len)) continue; + if (des[de].guest_path[path_len] != '\0') continue; + if (res_de != NULL) *res_de = de; + return wasi_errno_success; + } + } else { + if (dir_fd >= fd_len || fds[dir_fd].de >= de_len) return wasi_errno_badf; + const struct DirEntry *dir_de = &des[fds[dir_fd].de]; + if (dir_de->filetype != wasi_filetype_directory) return wasi_errno_notdir; + + size_t dir_guest_path_len = strlen(dir_de->guest_path); + for (uint32_t de = 0; de < de_len; de += 1) { + if (des[de].guest_path == NULL) continue; + if (!isSamePath(&des[de].guest_path[0], dir_de->guest_path, dir_guest_path_len)) continue; + if (!isPathSep(des[de].guest_path[dir_guest_path_len])) continue; + if (!isSamePath(&des[de].guest_path[dir_guest_path_len + 1], path, path_len)) continue; + if (des[de].guest_path[dir_guest_path_len + 1 + path_len] != '\0') continue; + if (res_de != NULL) *res_de = de; + return wasi_errno_success; + } + } + return wasi_errno_noent; +} + +static void DirEntry_filestat(uint32_t de, struct wasi_filestat *res_filestat) { + res_filestat->dev = 0; + res_filestat->ino = de; + res_filestat->filetype = des[de].filetype; + res_filestat->nlink = 1; + res_filestat->size = 0; + res_filestat->atim = des[de].atim * UINT64_C(1000000000); + res_filestat->mtim = des[de].mtim * UINT64_C(1000000000); + res_filestat->ctim = des[de].ctim * UINT64_C(1000000000); +} + +static void DirEntry_unlink(uint32_t de) { + free(des[de].guest_path); + des[de].guest_path = NULL; + free(des[de].host_path); + des[de].host_path = NULL; +} + +uint32_t wasi_snapshot_preview1_args_sizes_get(uint32_t argv_size, uint32_t argv_buf_size) { + uint8_t *const m = *wasm_memory; + uint32_t *argv_size_ptr = (uint32_t *)&m[argv_size]; + uint32_t *argv_buf_size_ptr = (uint32_t *)&m[argv_buf_size]; +#if LOG_TRACE + fprintf(stderr, "wasi_snapshot_preview1_args_sizes_get()\n"); +#endif + + int c_argc = global_argc; + char **c_argv = global_argv; + uint32_t size = 0; + for (int i = 0; i < c_argc; i += 1) { + if (i == 1) continue; + size += strlen(c_argv[i]) + 1; + } + *argv_size_ptr = c_argc - 1; + *argv_buf_size_ptr = size; + return wasi_errno_success; +} + +uint32_t wasi_snapshot_preview1_args_get(uint32_t argv, uint32_t argv_buf) { + uint8_t *const m = *wasm_memory; + uint32_t *argv_ptr = (uint32_t *)&m[argv]; + char *argv_buf_ptr = (char *)&m[argv_buf]; +#if LOG_TRACE + fprintf(stderr, "wasi_snapshot_preview1_args_get()\n"); +#endif + + int c_argc = global_argc; + char **c_argv = global_argv; + uint32_t dst_i = 0; + uint32_t argv_buf_i = 0; + for (int src_i = 0; src_i < c_argc; src_i += 1) { + if (src_i == 1) continue; + argv_ptr[dst_i] = argv_buf + argv_buf_i; + dst_i += 1; + strcpy(&argv_buf_ptr[argv_buf_i], c_argv[src_i]); + argv_buf_i += strlen(c_argv[src_i]) + 1; + } + return wasi_errno_success; +} + +uint32_t wasi_snapshot_preview1_fd_prestat_get(uint32_t fd, uint32_t res_prestat) { + uint8_t *const m = *wasm_memory; + uint32_t *res_prestat_ptr = (uint32_t *)&m[res_prestat]; +#if LOG_TRACE + fprintf(stderr, "wasi_snapshot_preview1_fd_prestat_get(%u)\n", fd); +#endif + + if (fd >= fd_len || fds[fd].de >= de_len) return wasi_errno_badf; + + res_prestat_ptr[0] = 0; + res_prestat_ptr[1] = strlen(des[fds[fd].de].guest_path); + return wasi_errno_success; +} + +uint32_t wasi_snapshot_preview1_fd_prestat_dir_name(uint32_t fd, uint32_t path, uint32_t path_len) { + uint8_t *const m = *wasm_memory; + char *path_ptr = (char *)&m[path]; +#if LOG_TRACE + fprintf(stderr, "wasi_snapshot_preview1_fd_prestat_dir_name(%u, \"%.*s\")\n", fd, (int)path_len, path_ptr); +#endif + + if (fd >= fd_len || fds[fd].de >= de_len) return wasi_errno_badf; + strncpy(path_ptr, des[fds[fd].de].guest_path, path_len); + return wasi_errno_success; +} + +void wasi_snapshot_preview1_proc_exit(uint32_t rval) { +#if LOG_TRACE + fprintf(stderr, "wasi_snapshot_preview1_proc_exit(%u)\n", rval); +#endif + + exit(rval); +} + +uint32_t wasi_snapshot_preview1_fd_close(uint32_t fd) { +#if LOG_TRACE + fprintf(stderr, "wasi_snapshot_preview1_fd_close(%u)\n", fd); +#endif + + if (fd >= fd_len || fds[fd].de >= de_len) return wasi_errno_badf; + if (fds[fd].stream != NULL) fclose(fds[fd].stream); + + fds[fd].de = ~0; + fds[fd].stream = NULL; + return wasi_errno_success; +} + +uint32_t wasi_snapshot_preview1_path_create_directory(uint32_t fd, uint32_t path, uint32_t path_len) { + uint8_t *const m = *wasm_memory; + const char *path_ptr = (const char *)&m[path]; +#if LOG_TRACE + fprintf(stderr, "wasi_snapshot_preview1_path_create_directory(%u, \"%.*s\")\n", fd, (int)path_len, path_ptr); +#endif + + enum wasi_errno lookup_errno = DirEntry_lookup(fd, 0, path_ptr, path_len, NULL); + switch (lookup_errno) { + case wasi_errno_success: return wasi_errno_exist; + case wasi_errno_noent: break; + default: return lookup_errno; + } + return DirEntry_create(fd, path_ptr, path_len, wasi_filetype_directory, time(NULL), NULL); +} + +uint32_t wasi_snapshot_preview1_fd_read(uint32_t fd, uint32_t iovs, uint32_t iovs_len, uint32_t res_size) { + uint8_t *const m = *wasm_memory; + struct wasi_ciovec *iovs_ptr = (struct wasi_ciovec *)&m[iovs]; + uint32_t *res_size_ptr = (uint32_t *)&m[res_size]; +#if LOG_TRACE + fprintf(stderr, "wasi_snapshot_preview1_fd_read(%u, 0x%X, %u)\n", fd, iovs, iovs_len); +#endif + + if (fd >= fd_len || fds[fd].de >= de_len) return wasi_errno_badf; + switch (des[fds[fd].de].filetype) { + case wasi_filetype_character_device: break; + case wasi_filetype_regular_file: break; + case wasi_filetype_directory: return wasi_errno_inval; + default: panic("unimplemented"); + } + + size_t size = 0; + for (uint32_t i = 0; i < iovs_len; i += 1) { + size_t read_size = 0; + if (fds[fd].stream != NULL) + read_size = fread(&m[iovs_ptr[i].ptr], 1, iovs_ptr[i].len, fds[fd].stream); + else + panic("unimplemented"); + size += read_size; + if (read_size < iovs_ptr[i].len) break; + } + + if (size > 0) des[fds[fd].de].atim = time(NULL); + *res_size_ptr = size; + return wasi_errno_success; +} + +uint32_t wasi_snapshot_preview1_fd_filestat_get(uint32_t fd, uint32_t res_filestat) { + uint8_t *const m = *wasm_memory; + struct wasi_filestat *res_filestat_ptr = (struct wasi_filestat *)&m[res_filestat]; +#if LOG_TRACE + fprintf(stderr, "wasi_snapshot_preview1_fd_filestat_get(%u)\n", fd); +#endif + + if (fd >= fd_len || fds[fd].de >= de_len) return wasi_errno_badf; + DirEntry_filestat(fds[fd].de, res_filestat_ptr); + if (des[fds[fd].de].filetype != wasi_filetype_regular_file) return wasi_errno_success; + if (fds[fd].stream == NULL) return wasi_errno_success; + fpos_t pos; + if (fgetpos(fds[fd].stream, &pos) < 0) return wasi_errno_io; + if (fseek(fds[fd].stream, 0, SEEK_END) < 0) return wasi_errno_io; + long size = ftell(fds[fd].stream); + if (size < 0) return wasi_errno_io; + res_filestat_ptr->size = size; + if (fsetpos(fds[fd].stream, &pos) < 0) return wasi_errno_io; + return wasi_errno_success; +} + +uint32_t wasi_snapshot_preview1_path_rename(uint32_t fd, uint32_t old_path, uint32_t old_path_len, uint32_t new_fd, uint32_t new_path, uint32_t new_path_len) { + uint8_t *const m = *wasm_memory; + const char *old_path_ptr = (const char *)&m[old_path]; + const char *new_path_ptr = (const char *)&m[new_path]; +#if LOG_TRACE + fprintf(stderr, "wasi_snapshot_preview1_path_rename(%u, \"%.*s\", %u, \"%.*s\")\n", fd, (int)old_path_len, old_path_ptr, new_fd, (int)new_path_len, new_path_ptr); +#endif + + uint32_t old_de; + enum wasi_errno old_lookup_errno = DirEntry_lookup(fd, 0, old_path_ptr, old_path_len, &old_de); + if (old_lookup_errno != wasi_errno_success) return old_lookup_errno; + DirEntry_unlink(old_de); + + uint32_t de; + enum wasi_errno new_lookup_errno = DirEntry_lookup(new_fd, 0, new_path_ptr, new_path_len, &de); + switch (new_lookup_errno) { + case wasi_errno_success: DirEntry_unlink(de); break; + case wasi_errno_noent: break; + default: return new_lookup_errno; + } + + uint32_t new_de; + enum wasi_errno create_errno = + DirEntry_create(new_fd, new_path_ptr, new_path_len, des[old_de].filetype, 0, &new_de); + if (create_errno != wasi_errno_success) return create_errno; + des[new_de].atim = des[old_de].atim; + des[new_de].mtim = des[old_de].mtim; + des[new_de].ctim = time(NULL); + return wasi_errno_success; +} + +uint32_t wasi_snapshot_preview1_fd_filestat_set_size(uint32_t fd, uint64_t size) { +#if LOG_TRACE + fprintf(stderr, "wasi_snapshot_preview1_fd_filestat_set_size(%u, %llu)\n", fd, (unsigned long long)size); +#endif + + if (fd >= fd_len || fds[fd].de >= de_len) return wasi_errno_badf; + if (des[fds[fd].de].filetype != wasi_filetype_regular_file) return wasi_errno_inval; + + if (fds[fd].stream == NULL) return wasi_errno_success; + fpos_t pos; + if (fgetpos(fds[fd].stream, &pos) < 0) return wasi_errno_io; + if (fseek(fds[fd].stream, 0, SEEK_END) < 0) return wasi_errno_io; + long old_size = ftell(fds[fd].stream); + if (old_size < 0) return wasi_errno_io; + if (size != (unsigned long)old_size) { + if (size > 0 && fseek(fds[fd].stream, size - 1, SEEK_SET) < 0) return wasi_errno_io; + if (size < (unsigned long)old_size) { + // Note that this destroys the contents on resize might have to save truncated + // file in memory if this becomes an issue. + FILE *trunc = fopen(des[fds[fd].de].host_path, "wb"); + if (trunc == NULL) return wasi_errno_io; + fclose(trunc); + } + if (size > 0) fputc(0, fds[fd].stream); + } + if (fsetpos(fds[fd].stream, &pos) < 0) return wasi_errno_io; + return wasi_errno_success; +} + +uint32_t wasi_snapshot_preview1_fd_pwrite(uint32_t fd, uint32_t iovs, uint32_t iovs_len, uint64_t offset, uint32_t res_size) { + uint8_t *const m = *wasm_memory; + struct wasi_ciovec *iovs_ptr = (struct wasi_ciovec *)&m[iovs]; + uint32_t *res_size_ptr = (uint32_t *)&m[res_size]; +#if LOG_TRACE + fprintf(stderr, "wasi_snapshot_preview1_fd_pwrite(%u, 0x%X, %u)\n", fd, iovs, iovs_len); +#endif + + if (fd >= fd_len || fds[fd].de >= de_len) return wasi_errno_badf; + switch (des[fds[fd].de].filetype) { + case wasi_filetype_character_device: break; + case wasi_filetype_regular_file: break; + case wasi_filetype_directory: return wasi_errno_inval; + default: panic("unimplemented"); + } + + fpos_t pos; + if (fgetpos(fds[fd].stream, &pos) < 0) return wasi_errno_io; + if (fseek(fds[fd].stream, offset, SEEK_SET) < 0) return wasi_errno_io; + + size_t size = 0; + for (uint32_t i = 0; i < iovs_len; i += 1) { + size_t written_size = 0; + if (fds[fd].stream != NULL) + written_size = fwrite(&m[iovs_ptr[i].ptr], 1, iovs_ptr[i].len, fds[fd].stream); + else + written_size = iovs_ptr[i].len; + size += written_size; + if (written_size < iovs_ptr[i].len) break; + } + + if (fsetpos(fds[fd].stream, &pos) < 0) return wasi_errno_io; + + if (size > 0) { + time_t now = time(NULL); + des[fds[fd].de].atim = now; + des[fds[fd].de].mtim = now; + } + *res_size_ptr = size; + return wasi_errno_success; +} + +uint32_t wasi_snapshot_preview1_random_get(uint32_t buf, uint32_t buf_len) { + uint8_t *const m = *wasm_memory; + uint8_t *buf_ptr = (uint8_t *)&m[buf]; +#if LOG_TRACE + fprintf(stderr, "wasi_snapshot_preview1_random_get(%u)\n", buf_len); +#endif + + for (uint32_t i = 0; i < buf_len; i += 1) buf_ptr[i] = (uint8_t)rand(); + return wasi_errno_success; +} + +uint32_t wasi_snapshot_preview1_fd_filestat_set_times(uint32_t fd, uint64_t atim, uint64_t mtim, uint32_t fst_flags) { + (void)fd; + (void)atim; + (void)mtim; + (void)fst_flags; +#if LOG_TRACE + fprintf(stderr, "wasi_snapshot_preview1_fd_filestat_set_times(%u, %llu, %llu, 0x%X)\n", fd, (unsigned long long)atim, (unsigned long long)mtim, fst_flags); +#endif + + panic("unimplemented"); + return wasi_errno_success; +} + +uint32_t wasi_snapshot_preview1_environ_sizes_get(uint32_t environ_size, uint32_t environ_buf_size) { + (void)environ_size; + (void)environ_buf_size; +#if LOG_TRACE + fprintf(stderr, "wasi_snapshot_preview1_environ_sizes_get()\n"); +#endif + + panic("unimplemented"); + return wasi_errno_success; +} + +uint32_t wasi_snapshot_preview1_environ_get(uint32_t environ, uint32_t environ_buf) { + (void)environ; + (void)environ_buf; +#if LOG_TRACE + fprintf(stderr, "wasi_snapshot_preview1_environ_get()\n"); +#endif + + panic("unimplemented"); + return wasi_errno_success; +} + +uint32_t wasi_snapshot_preview1_path_filestat_get(uint32_t fd, uint32_t flags, uint32_t path, uint32_t path_len, uint32_t res_filestat) { + uint8_t *const m = *wasm_memory; + const char *path_ptr = (const char *)&m[path]; + struct wasi_filestat *res_filestat_ptr = (struct wasi_filestat *)&m[res_filestat]; +#if LOG_TRACE + fprintf(stderr, "wasi_snapshot_preview1_path_filestat_get(%u, 0x%X, \"%.*s\")\n", fd, flags, (int)path_len, path_ptr); +#endif + + uint32_t de; + enum wasi_errno lookup_errno = DirEntry_lookup(fd, flags, path_ptr, path_len, &de); + if (lookup_errno != wasi_errno_success) return lookup_errno; + DirEntry_filestat(de, res_filestat_ptr); + if (des[de].filetype == wasi_filetype_regular_file && des[de].host_path != NULL) { + FILE *stream = fopen(des[de].host_path, "rb"); + if (stream != NULL) { + if (fseek(stream, 0, SEEK_END) >= 0) { + long size = ftell(stream); + if (size >= 0) res_filestat_ptr->size = size; + } + fclose(stream); + } + } + return wasi_errno_success; +} + +uint32_t wasi_snapshot_preview1_fd_fdstat_get(uint32_t fd, uint32_t res_fdstat) { + (void)fd; + (void)res_fdstat; +#if LOG_TRACE + fprintf(stderr, "wasi_snapshot_preview1_fd_fdstat_get(%u)\n", fd); +#endif + + panic("unimplemented"); + return wasi_errno_success; +} + +uint32_t wasi_snapshot_preview1_fd_readdir(uint32_t fd, uint32_t buf, uint32_t buf_len, uint64_t cookie, uint32_t res_size) { + (void)fd; + (void)buf; + (void)buf_len; + (void)cookie; + (void)res_size; +#if LOG_TRACE + fprintf(stderr, "wasi_snapshot_preview1_fd_readdir(%u, 0x%X, %u, %llu)\n", fd, buf, buf_len, (unsigned long long)cookie); +#endif + + panic("unimplemented"); + return wasi_errno_success; +} + +uint32_t wasi_snapshot_preview1_fd_write(uint32_t fd, uint32_t iovs, uint32_t iovs_len, uint32_t res_size) { + uint8_t *const m = *wasm_memory; + struct wasi_ciovec *iovs_ptr = (struct wasi_ciovec *)&m[iovs]; + uint32_t *res_size_ptr = (uint32_t *)&m[res_size]; +#if LOG_TRACE + fprintf(stderr, "wasi_snapshot_preview1_fd_write(%u, 0x%X, %u)\n", fd, iovs, iovs_len); +#endif + + if (fd >= fd_len || fds[fd].de >= de_len) return wasi_errno_badf; + switch (des[fds[fd].de].filetype) { + case wasi_filetype_character_device: break; + case wasi_filetype_regular_file: break; + case wasi_filetype_directory: return wasi_errno_inval; + default: panic("unimplemented"); + } + + size_t size = 0; + for (uint32_t i = 0; i < iovs_len; i += 1) { + size_t written_size = 0; + if (fds[fd].stream != NULL) + written_size = fwrite(&m[iovs_ptr[i].ptr], 1, iovs_ptr[i].len, fds[fd].stream); + else + written_size = iovs_ptr[i].len; + size += written_size; + if (written_size < iovs_ptr[i].len) break; + } + + if (size > 0) { + time_t now = time(NULL); + des[fds[fd].de].atim = now; + des[fds[fd].de].mtim = now; + } + *res_size_ptr = size; + return wasi_errno_success; +} + +uint32_t wasi_snapshot_preview1_path_open(uint32_t fd, uint32_t dirflags, uint32_t path, uint32_t path_len, uint32_t oflags, uint64_t fs_rights_base, uint64_t fs_rights_inheriting, uint32_t fdflags, uint32_t res_fd) { + uint8_t *const m = *wasm_memory; + const char *path_ptr = (const char *)&m[path]; + (void)fs_rights_inheriting; + uint32_t *res_fd_ptr = (uint32_t *)&m[res_fd]; +#if LOG_TRACE + fprintf(stderr, "wasi_snapshot_preview1_path_open(%u, 0x%X, \"%.*s\", 0x%X, 0x%llX, 0x%llX, 0x%X)\n", fd, dirflags, (int)path_len, path_ptr, oflags, (unsigned long long)fs_rights_base, (unsigned long long)fs_rights_inheriting, fdflags); +#endif + + bool creat = (oflags & wasi_oflags_creat) != 0; + bool directory = (oflags & wasi_oflags_directory) != 0; + bool excl = (oflags & wasi_oflags_excl) != 0; + bool trunc = (oflags & wasi_oflags_trunc) != 0; + bool append = (fdflags & wasi_fdflags_append) != 0; + + uint32_t de; + enum wasi_errno lookup_errno = DirEntry_lookup(fd, dirflags, path_ptr, path_len, &de); + if (lookup_errno == wasi_errno_success) { + if (directory && des[de].filetype != wasi_filetype_directory) return wasi_errno_notdir; + + struct FileDescriptor *new_fds = realloc(fds, (fd_len + 1) * sizeof(struct FileDescriptor)); + if (new_fds == NULL) return wasi_errno_nomem; + fds = new_fds; + + fds[fd_len].de = de; + switch (des[de].filetype) { + case wasi_filetype_directory: fds[fd_len].stream = NULL; break; + default: panic("unimplemented"); + } + +#if LOG_TRACE + fprintf(stderr, "fd = %u\n", fd_len); +#endif + *res_fd_ptr = fd_len; + fd_len += 1; + } + if (lookup_errno != wasi_errno_noent) return lookup_errno; + + struct FileDescriptor *new_fds = realloc(fds, (fd_len + 1) * sizeof(struct FileDescriptor)); + if (new_fds == NULL) return wasi_errno_nomem; + fds = new_fds; + + enum wasi_filetype filetype = directory ? wasi_filetype_directory : wasi_filetype_regular_file; + enum wasi_errno create_errno = DirEntry_create(fd, path_ptr, path_len, filetype, 0, &de); + if (create_errno != wasi_errno_success) return create_errno; + FILE *stream; + if (!directory) { + if (des[de].host_path == NULL) { + if (!creat) { DirEntry_unlink(de); de_len -= 1; return wasi_errno_noent; } + time_t now = time(NULL); + des[de].atim = now; + des[de].mtim = now; + des[de].ctim = now; + stream = NULL; + } else { + if (oflags != (append ? wasi_oflags_creat : wasi_oflags_creat | wasi_oflags_trunc)) { + char mode[] = "rb+"; + if ((fs_rights_base & wasi_rights_fd_write) == 0) mode[2] = '\0'; + stream = fopen(des[de].host_path, mode); + if (stream != NULL) { + if (append || excl || trunc) fclose(stream); + if (excl) { + DirEntry_unlink(de); + de_len -= 1; + return wasi_errno_exist; + } + } else if (!creat) { DirEntry_unlink(de); de_len -= 1; return wasi_errno_noent; } + } + if (append || trunc || stream == NULL) { + char mode[] = "wb+"; + if ((fs_rights_base & wasi_rights_fd_read) == 0) mode[2] = '\0'; + if (trunc || !append) { + stream = fopen(des[de].host_path, mode); + if (append && stream != NULL) fclose(stream); + } + if (append) { + mode[0] = 'a'; + stream = fopen(des[de].host_path, mode); + } + } + if (stream == NULL) { DirEntry_unlink(de); de_len -= 1; return wasi_errno_isdir; } + } + } else stream = NULL; + +#if LOG_TRACE + fprintf(stderr, "fd = %u\n", fd_len); +#endif + fds[fd_len].de = de; + fds[fd_len].stream = stream; + *res_fd_ptr = fd_len; + fd_len += 1; + return wasi_errno_success; +} + +uint32_t wasi_snapshot_preview1_clock_time_get(uint32_t id, uint64_t precision, uint32_t res_timestamp) { + uint8_t *const m = *wasm_memory; + (void)precision; + uint64_t *res_timestamp_ptr = (uint64_t *)&m[res_timestamp]; +#if LOG_TRACE + fprintf(stderr, "wasi_snapshot_preview1_clock_time_get(%u, %llu)\n", id, (unsigned long long)precision); +#endif + + switch (id) { + case wasi_clockid_realtime: + *res_timestamp_ptr = time(NULL) * UINT64_C(1000000000); + break; + case wasi_clockid_monotonic: + case wasi_clockid_process_cputime_id: + case wasi_clockid_thread_cputime_id: + *res_timestamp_ptr = clock() * (UINT64_C(1000000000) / CLOCKS_PER_SEC); + break; + default: return wasi_errno_inval; + } + return wasi_errno_success; +} + +uint32_t wasi_snapshot_preview1_path_remove_directory(uint32_t fd, uint32_t path, uint32_t path_len) { + uint8_t *const m = *wasm_memory; + const char *path_ptr = (const char *)&m[path]; +#if LOG_TRACE + fprintf(stderr, "wasi_snapshot_preview1_path_remove_directory(%u, \"%.*s\")\n", fd, (int)path_len, path_ptr); +#endif + + uint32_t de; + enum wasi_errno lookup_errno = DirEntry_lookup(fd, 0, path_ptr, path_len, &de); + if (lookup_errno != wasi_errno_success) return lookup_errno; + if (des[de].filetype != wasi_filetype_directory) return wasi_errno_notdir; + DirEntry_unlink(de); + return wasi_errno_success; +} + +uint32_t wasi_snapshot_preview1_path_unlink_file(uint32_t fd, uint32_t path, uint32_t path_len) { + uint8_t *const m = *wasm_memory; + const char *path_ptr = (const char *)&m[path]; +#if LOG_TRACE + fprintf(stderr, "wasi_snapshot_preview1_path_unlink_file(%u, \"%.*s\")\n", fd, (int)path_len, path_ptr); +#endif + + uint32_t de; + enum wasi_errno lookup_errno = DirEntry_lookup(fd, 0, path_ptr, path_len, &de); + if (lookup_errno != wasi_errno_success) return lookup_errno; + if (des[de].filetype == wasi_filetype_directory) return wasi_errno_isdir; + if (des[de].filetype != wasi_filetype_regular_file) panic("unimplemented"); + DirEntry_unlink(de); + return wasi_errno_success; +} + +uint32_t wasi_snapshot_preview1_fd_pread(uint32_t fd, uint32_t iovs, uint32_t iovs_len, uint64_t offset, uint32_t res_size) { + uint8_t *const m = *wasm_memory; + struct wasi_ciovec *iovs_ptr = (struct wasi_ciovec *)&m[iovs]; + uint32_t *res_size_ptr = (uint32_t *)&m[res_size]; +#if LOG_TRACE + fprintf(stderr, "wasi_snapshot_preview1_fd_pread(%u, 0x%X, %u)\n", fd, iovs, iovs_len); +#endif + + if (fd >= fd_len || fds[fd].de >= de_len) return wasi_errno_badf; + switch (des[fds[fd].de].filetype) { + case wasi_filetype_character_device: break; + case wasi_filetype_regular_file: break; + case wasi_filetype_directory: return wasi_errno_inval; + default: panic("unimplemented"); + } + + fpos_t pos; + if (fgetpos(fds[fd].stream, &pos) < 0) return wasi_errno_io; + if (fseek(fds[fd].stream, offset, SEEK_SET) < 0) return wasi_errno_io; + + size_t size = 0; + for (uint32_t i = 0; i < iovs_len; i += 1) { + size_t read_size = 0; + if (fds[fd].stream != NULL) + read_size = fread(&m[iovs_ptr[i].ptr], 1, iovs_ptr[i].len, fds[fd].stream); + else + panic("unimplemented"); + size += read_size; + if (read_size < iovs_ptr[i].len) break; + } + + if (fsetpos(fds[fd].stream, &pos) < 0) return wasi_errno_io; + + if (size > 0) des[fds[fd].de].atim = time(NULL); + *res_size_ptr = size; + return wasi_errno_success; +} + +uint32_t wasi_snapshot_preview1_poll_oneoff(uint32_t in, uint32_t out, uint32_t nsubscriptions, uint32_t res_nevents) { + (void)in; + (void)out; + (void)nsubscriptions; + (void)res_nevents; +#if LOG_TRACE + fprintf(stderr, "wasi_snapshot_preview1_poll_oneoff(%u)\n", nsubscriptions); +#endif + + panic("unimplemented"); + return wasi_errno_success; +} + + +void wasi_snapshot_preview1_debug(uint32_t string, uint64_t x) { + uint8_t *const m = *wasm_memory; + const char *string_ptr = (const char *)&m[string]; +#if LOG_TRACE + fprintf(stderr, "wasi_snapshot_preview1_debug(\"%s\", %llu, 0x%llX)\n", string_ptr, (unsigned long long)x, (unsigned long long)x); +#endif + + (void)string_ptr; + (void)x; +} diff --git a/stage1/wasm.h b/stage1/wasm.h new file mode 100644 index 000000000000..276d340bbbd2 --- /dev/null +++ b/stage1/wasm.h @@ -0,0 +1,280 @@ +#ifndef WASM_H +#define WASM_H + +#include "panic.h" + +enum WasmSectionId { + WasmSectionId_type = 1, + WasmSectionId_import = 2, + WasmSectionId_func = 3, + WasmSectionId_table = 4, + WasmSectionId_mem = 5, + WasmSectionId_global = 6, + WasmSectionId_export = 7, + WasmSectionId_start = 8, + WasmSectionId_elem = 9, + WasmSectionId_code = 10, + WasmSectionId_data = 11, + WasmSectionId_datacount = 12, +}; + +enum WasmValType { + WasmValType_i32 = -0x01, + WasmValType_i64 = -0x02, + WasmValType_f32 = -0x03, + WasmValType_f64 = -0x04, + WasmValType_v128 = -0x05, + WasmValType_funcref = -0x10, + WasmValType_externref = -0x11, + WasmValType_empty = -0x40, +}; +static const char *WasmValType_toC(enum WasmValType val_type) { + switch (val_type) { + case WasmValType_i32: return "uint32_t"; + case WasmValType_i64: return "uint64_t"; + case WasmValType_f32: return "float"; + case WasmValType_f64: return "double"; + case WasmValType_v128: panic("vector types are unsupported"); + case WasmValType_funcref: return "void (*)(void)"; + case WasmValType_externref: return "void *"; + default: panic("unsupported value type"); + } + return NULL; +} + +enum WasmMut { + WasmMut_const = 0x00, + WasmMut_var = 0x01, +}; +static const char *WasmMut_toC(enum WasmMut val_type) { + switch (val_type) { + case WasmMut_const: return "const "; + case WasmMut_var: return ""; + default: panic("unsupported mut"); + } +} + +enum WasmOpcode { + WasmOpcode_unreachable = 0x00, + WasmOpcode_nop = 0x01, + WasmOpcode_block = 0x02, + WasmOpcode_loop = 0x03, + WasmOpcode_if = 0x04, + WasmOpcode_else = 0x05, + WasmOpcode_end = 0x0B, + WasmOpcode_br = 0x0C, + WasmOpcode_br_if = 0x0D, + WasmOpcode_br_table = 0x0E, + WasmOpcode_return = 0x0F, + WasmOpcode_call = 0x10, + WasmOpcode_call_indirect = 0x11, + + WasmOpcode_drop = 0x1A, + WasmOpcode_select = 0x1B, + WasmOpcode_select_t = 0x1C, + + WasmOpcode_local_get = 0x20, + WasmOpcode_local_set = 0x21, + WasmOpcode_local_tee = 0x22, + WasmOpcode_global_get = 0x23, + WasmOpcode_global_set = 0x24, + + WasmOpcode_table_get = 0x25, + WasmOpcode_table_set = 0x26, + + WasmOpcode_i32_load = 0x28, + WasmOpcode_i64_load = 0x29, + WasmOpcode_f32_load = 0x2A, + WasmOpcode_f64_load = 0x2B, + WasmOpcode_i32_load8_s = 0x2C, + WasmOpcode_i32_load8_u = 0x2D, + WasmOpcode_i32_load16_s = 0x2E, + WasmOpcode_i32_load16_u = 0x2F, + WasmOpcode_i64_load8_s = 0x30, + WasmOpcode_i64_load8_u = 0x31, + WasmOpcode_i64_load16_s = 0x32, + WasmOpcode_i64_load16_u = 0x33, + WasmOpcode_i64_load32_s = 0x34, + WasmOpcode_i64_load32_u = 0x35, + WasmOpcode_i32_store = 0x36, + WasmOpcode_i64_store = 0x37, + WasmOpcode_f32_store = 0x38, + WasmOpcode_f64_store = 0x39, + WasmOpcode_i32_store8 = 0x3A, + WasmOpcode_i32_store16 = 0x3B, + WasmOpcode_i64_store8 = 0x3C, + WasmOpcode_i64_store16 = 0x3D, + WasmOpcode_i64_store32 = 0x3E, + WasmOpcode_memory_size = 0x3F, + WasmOpcode_memory_grow = 0x40, + + WasmOpcode_i32_const = 0x41, + WasmOpcode_i64_const = 0x42, + WasmOpcode_f32_const = 0x43, + WasmOpcode_f64_const = 0x44, + + WasmOpcode_i32_eqz = 0x45, + WasmOpcode_i32_eq = 0x46, + WasmOpcode_i32_ne = 0x47, + WasmOpcode_i32_lt_s = 0x48, + WasmOpcode_i32_lt_u = 0x49, + WasmOpcode_i32_gt_s = 0x4A, + WasmOpcode_i32_gt_u = 0x4B, + WasmOpcode_i32_le_s = 0x4C, + WasmOpcode_i32_le_u = 0x4D, + WasmOpcode_i32_ge_s = 0x4E, + WasmOpcode_i32_ge_u = 0x4F, + + WasmOpcode_i64_eqz = 0x50, + WasmOpcode_i64_eq = 0x51, + WasmOpcode_i64_ne = 0x52, + WasmOpcode_i64_lt_s = 0x53, + WasmOpcode_i64_lt_u = 0x54, + WasmOpcode_i64_gt_s = 0x55, + WasmOpcode_i64_gt_u = 0x56, + WasmOpcode_i64_le_s = 0x57, + WasmOpcode_i64_le_u = 0x58, + WasmOpcode_i64_ge_s = 0x59, + WasmOpcode_i64_ge_u = 0x5A, + + WasmOpcode_f32_eq = 0x5B, + WasmOpcode_f32_ne = 0x5C, + WasmOpcode_f32_lt = 0x5D, + WasmOpcode_f32_gt = 0x5E, + WasmOpcode_f32_le = 0x5F, + WasmOpcode_f32_ge = 0x60, + + WasmOpcode_f64_eq = 0x61, + WasmOpcode_f64_ne = 0x62, + WasmOpcode_f64_lt = 0x63, + WasmOpcode_f64_gt = 0x64, + WasmOpcode_f64_le = 0x65, + WasmOpcode_f64_ge = 0x66, + + WasmOpcode_i32_clz = 0x67, + WasmOpcode_i32_ctz = 0x68, + WasmOpcode_i32_popcnt = 0x69, + WasmOpcode_i32_add = 0x6A, + WasmOpcode_i32_sub = 0x6B, + WasmOpcode_i32_mul = 0x6C, + WasmOpcode_i32_div_s = 0x6D, + WasmOpcode_i32_div_u = 0x6E, + WasmOpcode_i32_rem_s = 0x6F, + WasmOpcode_i32_rem_u = 0x70, + WasmOpcode_i32_and = 0x71, + WasmOpcode_i32_or = 0x72, + WasmOpcode_i32_xor = 0x73, + WasmOpcode_i32_shl = 0x74, + WasmOpcode_i32_shr_s = 0x75, + WasmOpcode_i32_shr_u = 0x76, + WasmOpcode_i32_rotl = 0x77, + WasmOpcode_i32_rotr = 0x78, + + WasmOpcode_i64_clz = 0x79, + WasmOpcode_i64_ctz = 0x7A, + WasmOpcode_i64_popcnt = 0x7B, + WasmOpcode_i64_add = 0x7C, + WasmOpcode_i64_sub = 0x7D, + WasmOpcode_i64_mul = 0x7E, + WasmOpcode_i64_div_s = 0x7F, + WasmOpcode_i64_div_u = 0x80, + WasmOpcode_i64_rem_s = 0x81, + WasmOpcode_i64_rem_u = 0x82, + WasmOpcode_i64_and = 0x83, + WasmOpcode_i64_or = 0x84, + WasmOpcode_i64_xor = 0x85, + WasmOpcode_i64_shl = 0x86, + WasmOpcode_i64_shr_s = 0x87, + WasmOpcode_i64_shr_u = 0x88, + WasmOpcode_i64_rotl = 0x89, + WasmOpcode_i64_rotr = 0x8A, + + WasmOpcode_f32_abs = 0x8B, + WasmOpcode_f32_neg = 0x8C, + WasmOpcode_f32_ceil = 0x8D, + WasmOpcode_f32_floor = 0x8E, + WasmOpcode_f32_trunc = 0x8F, + WasmOpcode_f32_nearest = 0x90, + WasmOpcode_f32_sqrt = 0x91, + WasmOpcode_f32_add = 0x92, + WasmOpcode_f32_sub = 0x93, + WasmOpcode_f32_mul = 0x94, + WasmOpcode_f32_div = 0x95, + WasmOpcode_f32_min = 0x96, + WasmOpcode_f32_max = 0x97, + WasmOpcode_f32_copysign = 0x98, + + WasmOpcode_f64_abs = 0x99, + WasmOpcode_f64_neg = 0x9A, + WasmOpcode_f64_ceil = 0x9B, + WasmOpcode_f64_floor = 0x9C, + WasmOpcode_f64_trunc = 0x9D, + WasmOpcode_f64_nearest = 0x9E, + WasmOpcode_f64_sqrt = 0x9F, + WasmOpcode_f64_add = 0xA0, + WasmOpcode_f64_sub = 0xA1, + WasmOpcode_f64_mul = 0xA2, + WasmOpcode_f64_div = 0xA3, + WasmOpcode_f64_min = 0xA4, + WasmOpcode_f64_max = 0xA5, + WasmOpcode_f64_copysign = 0xA6, + + WasmOpcode_i32_wrap_i64 = 0xA7, + WasmOpcode_i32_trunc_f32_s = 0xA8, + WasmOpcode_i32_trunc_f32_u = 0xA9, + WasmOpcode_i32_trunc_f64_s = 0xAA, + WasmOpcode_i32_trunc_f64_u = 0xAB, + WasmOpcode_i64_extend_i32_s = 0xAC, + WasmOpcode_i64_extend_i32_u = 0xAD, + WasmOpcode_i64_trunc_f32_s = 0xAE, + WasmOpcode_i64_trunc_f32_u = 0xAF, + WasmOpcode_i64_trunc_f64_s = 0xB0, + WasmOpcode_i64_trunc_f64_u = 0xB1, + WasmOpcode_f32_convert_i32_s = 0xB2, + WasmOpcode_f32_convert_i32_u = 0xB3, + WasmOpcode_f32_convert_i64_s = 0xB4, + WasmOpcode_f32_convert_i64_u = 0xB5, + WasmOpcode_f32_demote_f64 = 0xB6, + WasmOpcode_f64_convert_i32_s = 0xB7, + WasmOpcode_f64_convert_i32_u = 0xB8, + WasmOpcode_f64_convert_i64_s = 0xB9, + WasmOpcode_f64_convert_i64_u = 0xBA, + WasmOpcode_f64_promote_f32 = 0xBB, + WasmOpcode_i32_reinterpret_f32 = 0xBC, + WasmOpcode_i64_reinterpret_f64 = 0xBD, + WasmOpcode_f32_reinterpret_i32 = 0xBE, + WasmOpcode_f64_reinterpret_i64 = 0xBF, + + WasmOpcode_i32_extend8_s = 0xC0, + WasmOpcode_i32_extend16_s = 0xC1, + WasmOpcode_i64_extend8_s = 0xC2, + WasmOpcode_i64_extend16_s = 0xC3, + WasmOpcode_i64_extend32_s = 0xC4, + + WasmOpcode_prefixed = 0xFC, +}; + +enum WasmPrefixedOpcode { + WasmPrefixedOpcode_i32_trunc_sat_f32_s = 0, + WasmPrefixedOpcode_i32_trunc_sat_f32_u = 1, + WasmPrefixedOpcode_i32_trunc_sat_f64_s = 2, + WasmPrefixedOpcode_i32_trunc_sat_f64_u = 3, + WasmPrefixedOpcode_i64_trunc_sat_f32_s = 4, + WasmPrefixedOpcode_i64_trunc_sat_f32_u = 5, + WasmPrefixedOpcode_i64_trunc_sat_f64_s = 6, + WasmPrefixedOpcode_i64_trunc_sat_f64_u = 7, + + WasmPrefixedOpcode_memory_init = 8, + WasmPrefixedOpcode_data_drop = 9, + WasmPrefixedOpcode_memory_copy = 10, + WasmPrefixedOpcode_memory_fill = 11, + + WasmPrefixedOpcode_table_init = 12, + WasmPrefixedOpcode_elem_drop = 13, + WasmPrefixedOpcode_table_copy = 14, + WasmPrefixedOpcode_table_grow = 15, + WasmPrefixedOpcode_table_size = 16, + WasmPrefixedOpcode_table_fill = 17, +}; + +#endif /* WASM_H */ diff --git a/stage1/wasm2c.c b/stage1/wasm2c.c new file mode 100644 index 000000000000..3beba3b04427 --- /dev/null +++ b/stage1/wasm2c.c @@ -0,0 +1,2496 @@ +#define EXTRA_BRACES 0 + +#include "FuncGen.h" +#include "InputStream.h" +#include "panic.h" +#include "wasm.h" + +#include +#include +#include +#include +#include +#include + +struct FuncType { + const struct ResultType *param; + const struct ResultType *result; +}; +static const struct FuncType *FuncType_blockType(const struct FuncType *types, int64_t block_type) { + if (block_type >= 0) return &types[block_type]; + + static const struct ResultType none = { 0, { 0 }}; + static const struct ResultType i32 = { 1, { WasmValType_i32 } }; + static const struct ResultType i64 = { 1, { WasmValType_i64 } }; + static const struct ResultType f32 = { 1, { WasmValType_f32 } }; + static const struct ResultType f64 = { 1, { WasmValType_f64 } }; + + static const struct FuncType none_i32 = { &none, &i32 }; + static const struct FuncType none_i64 = { &none, &i64 }; + static const struct FuncType none_f32 = { &none, &f32 }; + static const struct FuncType none_f64 = { &none, &f64 }; + static const struct FuncType none_none = { &none, &none }; + + switch (block_type) { + case WasmValType_i32: return &none_i32; + case WasmValType_i64: return &none_i64; + case WasmValType_f32: return &none_f32; + case WasmValType_f64: return &none_f64; + case WasmValType_empty: return &none_none; + default: panic("unsupported block type"); + } + return NULL; +} + +static uint32_t evalExpr(struct InputStream *in) { + uint32_t value; + while (true) { + switch (InputStream_readByte(in)) { + case WasmOpcode_end: return value; + + case WasmOpcode_i32_const: + value = (uint32_t)InputStream_readLeb128_i32(in); + break; + + default: panic("unsupported expr opcode"); + } + } +} + +static void renderExpr(FILE *out, struct InputStream *in) { + while (true) { + switch (InputStream_readByte(in)) { + case WasmOpcode_end: return; + + case WasmOpcode_i32_const: { + uint32_t value = (uint32_t)InputStream_readLeb128_i32(in); + fprintf(out, "UINT32_C(0x%" PRIX32 ")", value); + break; + } + + default: panic("unsupported expr opcode"); + } + } +} + +int main(int argc, char **argv) { + if (argc != 3) { + fprintf(stderr, "usage: %s in.wasm.zst out.c\n", argv[0]); + return 1; + } + + const char *mod = "wasm"; + bool is_big_endian = false; // TODO + + struct InputStream in; + InputStream_open(&in, argv[1]); + + if (InputStream_readByte(&in) != '\0' || + InputStream_readByte(&in) != 'a' || + InputStream_readByte(&in) != 's' || + InputStream_readByte(&in) != 'm') panic("input is not a zstd-compressed wasm file"); + if (InputStream_readLittle_u32(&in) != 1) panic("unsupported wasm version"); + + FILE *out = fopen(argv[2], "wb"); + if (out == NULL) panic("unable to open output file"); + fputs("#include \n" + "#include \n" + "#include \n" + "#include \n" + "\n", out); + if (is_big_endian) + fputs("static uint16_t i16_byteswap(uint16_t src) {\n" + " return (uint16_t)(uint8_t)(src >> 0) << 8 |\n" + " (uint16_t)(uint8_t)(src >> 8) << 0;\n" + "}\n" + "static uint32_t i32_byteswap(uint32_t src) {\n" + " return (uint32_t)i16_byteswap(src >> 0) << 16 |\n" + " (uint32_t)i16_byteswap(src >> 16) << 0;\n" + "}\n" + "static uint64_t i64_byteswap(uint64_t src) {\n" + " return (uint64_t)i32_byteswap(src >> 0) << 32 |\n" + " (uint64_t)i32_byteswap(src >> 32) << 0;\n" + "}\n" + "\n", out); + fputs("static uint16_t load16_align0(const uint8_t *ptr) {\n" + " uint16_t val;\n" + " memcpy(&val, ptr, sizeof(val));\n", out); + if (is_big_endian) fputs(" val = i16_byteswap(val);", out); + fputs(" return val;\n" + "}\n" + "static uint16_t load16_align1(const uint16_t *ptr) {\n" + " uint16_t val;\n" + " memcpy(&val, ptr, sizeof(val));\n", out); + if (is_big_endian) fputs(" val = i16_byteswap(val);", out); + fputs(" return val;\n" + "}\n" + "static uint32_t load32_align0(const uint8_t *ptr) {\n" + " uint32_t val;\n" + " memcpy(&val, ptr, sizeof(val));\n", out); + if (is_big_endian) fputs(" val = i32_byteswap(val);", out); + fputs(" return val;\n" + "}\n" + "static uint32_t load32_align1(const uint16_t *ptr) {\n" + " uint32_t val;\n" + " memcpy(&val, ptr, sizeof(val));\n", out); + if (is_big_endian) fputs(" val = i32_byteswap(val);", out); + fputs(" return val;\n" + "}\n" + "static uint32_t load32_align2(const uint32_t *ptr) {\n" + " uint32_t val;\n" + " memcpy(&val, ptr, sizeof(val));\n", out); + if (is_big_endian) fputs(" val = i32_byteswap(val);", out); + fputs(" return val;\n" + "}\n" + "static uint64_t load64_align0(const uint8_t *ptr) {\n" + " uint64_t val;\n" + " memcpy(&val, ptr, sizeof(val));\n", out); + if (is_big_endian) fputs(" val = i64_byteswap(val);", out); + fputs(" return val;\n" + "}\n" + "static uint64_t load64_align1(const uint16_t *ptr) {\n" + " uint64_t val;\n" + " memcpy(&val, ptr, sizeof(val));\n", out); + if (is_big_endian) fputs(" val = i64_byteswap(val);", out); + fputs(" return val;\n" + "}\n" + "static uint64_t load64_align2(const uint32_t *ptr) {\n" + " uint64_t val;\n" + " memcpy(&val, ptr, sizeof(val));\n", out); + if (is_big_endian) fputs(" val = i64_byteswap(val);", out); + fputs(" return val;\n" + "}\n" + "static uint64_t load64_align3(const uint64_t *ptr) {\n" + " uint64_t val;\n" + " memcpy(&val, ptr, sizeof(val));\n", out); + if (is_big_endian) fputs(" val = i64_byteswap(val);", out); + fputs(" return val;\n" + "}\n" + "\n" + "static void store16_align0(uint8_t *ptr, uint16_t val) {\n", out); + if (is_big_endian) fputs(" val = i16_byteswap(val);", out); + fputs(" memcpy(ptr, &val, sizeof(val));\n" + "}\n" + "static void store16_align1(uint16_t *ptr, uint16_t val) {\n", out); + if (is_big_endian) fputs(" val = i16_byteswap(val);", out); + fputs(" memcpy(ptr, &val, sizeof(val));\n" + "}\n" + "static void store32_align0(uint8_t *ptr, uint32_t val) {\n", out); + if (is_big_endian) fputs(" val = i32_byteswap(val);", out); + fputs(" memcpy(ptr, &val, sizeof(val));\n" + "}\n" + "static void store32_align1(uint16_t *ptr, uint32_t val) {\n", out); + if (is_big_endian) fputs(" val = i32_byteswap(val);", out); + fputs(" memcpy(ptr, &val, sizeof(val));\n" + "}\n" + "static void store32_align2(uint32_t *ptr, uint32_t val) {\n", out); + if (is_big_endian) fputs(" val = i32_byteswap(val);", out); + fputs(" memcpy(ptr, &val, sizeof(val));\n" + "}\n" + "static void store64_align0(uint8_t *ptr, uint64_t val) {\n", out); + if (is_big_endian) fputs(" val = i64_byteswap(val);", out); + fputs(" memcpy(ptr, &val, sizeof(val));\n" + "}\n" + "static void store64_align1(uint16_t *ptr, uint64_t val) {\n", out); + if (is_big_endian) fputs(" val = i64_byteswap(val);", out); + fputs(" memcpy(ptr, &val, sizeof(val));\n" + "}\n" + "static void store64_align2(uint32_t *ptr, uint64_t val) {\n", out); + if (is_big_endian) fputs(" val = i64_byteswap(val);", out); + fputs(" memcpy(ptr, &val, sizeof(val));\n" + "}\n" + "static void store64_align3(uint64_t *ptr, uint64_t val) {\n", out); + if (is_big_endian) fputs(" val = i64_byteswap(val);", out); + fputs(" memcpy(ptr, &val, sizeof(val));\n" + "}\n" + "\n" + "static uint32_t i32_reinterpret_f32(const float src) {\n" + " uint32_t dst;\n" + " memcpy(&dst, &src, sizeof(dst));\n" + " return dst;\n" + "}\n" + "static uint64_t i64_reinterpret_f64(const double src) {\n" + " uint64_t dst;\n" + " memcpy(&dst, &src, sizeof(dst));\n" + " return dst;\n" + "}\n" + "static float f32_reinterpret_i32(const uint32_t src) {\n" + " float dst;\n" + " memcpy(&dst, &src, sizeof(dst));\n" + " return dst;\n" + "}\n" + "static double f64_reinterpret_i64(const uint64_t src) {\n" + " double dst;\n" + " memcpy(&dst, &src, sizeof(dst));\n" + " return dst;\n" + "}\n" + "\n" + "static uint32_t memory_grow(uint8_t **m, uint32_t *p, uint32_t *c, uint32_t n) {\n" + " uint8_t *new_m = *m;\n" + " uint32_t r = *p;\n" + " uint32_t new_p = r + n;\n" + " if (new_p > UINT32_C(0x10000)) return UINT32_C(0xFFFFFFF);\n" + " uint32_t new_c = *c;\n" + " if (new_c < new_p) {\n" + " do new_c += new_c / 2 + 8; while (new_c < new_p);\n" + " if (new_c > UINT32_C(0x10000)) new_c = UINT32_C(0x10000);\n" + " new_m = realloc(new_m, new_c << 16);\n" + " if (new_m == NULL) return UINT32_C(0xFFFFFFF);\n" + " *m = new_m;\n" + " *c = new_c;\n" + " }\n" + " *p = new_p;\n" + " memset(&new_m[r << 16], 0, n << 16);\n" + " return r;\n" + "}\n" + "\n" + "static int inited;\n" + "static void init_elem(void);\n" + "static void init_data(void);\n" + "static void init(void) {\n" + " if (inited != 0) return;\n" + " init_elem();\n" + " init_data();\n" + " inited = 1;\n" + "}\n" + "\n", out); + + struct FuncType *types; + uint32_t max_param_len = 0; + (void)InputStream_skipToSection(&in, WasmSectionId_type); + { + uint32_t len = InputStream_readLeb128_u32(&in); + types = malloc(sizeof(struct FuncType) * len); + if (types == NULL) panic("out of memory"); + for (uint32_t i = 0; i < len; i += 1) { + if (InputStream_readByte(&in) != 0x60) panic("expected functype"); + types[i].param = InputStream_readResultType(&in); + if (types[i].param->len > max_param_len) max_param_len = types[i].param->len; + types[i].result = InputStream_readResultType(&in); + } + } + + struct Import { + const char *mod; + const char *name; + uint32_t type_idx; + } *imports; + (void)InputStream_skipToSection(&in, WasmSectionId_import); + uint32_t imports_len = InputStream_readLeb128_u32(&in); + { + imports = malloc(sizeof(struct Import) * imports_len); + if (imports == NULL) panic("out of memory"); + for (uint32_t i = 0; i < imports_len; i += 1) { + imports[i].mod = InputStream_readName(&in); + imports[i].name = InputStream_readName(&in); + switch (InputStream_readByte(&in)) { + case 0x00: { // func + imports[i].type_idx = InputStream_readLeb128_u32(&in); + const struct FuncType *func_type = &types[imports[i].type_idx]; + switch (func_type->result->len) { + case 0: fputs("void", out); break; + case 1: fputs(WasmValType_toC(func_type->result->types[0]), out); break; + default: panic("multiple function returns not supported"); + } + fprintf(out, " %s_%s(", imports[i].mod, imports[i].name); + if (func_type->param->len == 0) fputs("void", out); + for (uint32_t param_i = 0; param_i < func_type->param->len; param_i += 1) { + if (param_i > 0) fputs(", ", out); + fputs(WasmValType_toC(func_type->param->types[param_i]), out); + } + fputs(");\n", out); + break; + } + + case 0x01: // table + case 0x02: // mem + case 0x03: // global + default: + panic("unsupported import type"); + } + } + fputc('\n', out); + } + + struct Func { + uint32_t type_idx; + } *funcs; + (void)InputStream_skipToSection(&in, WasmSectionId_func); + { + uint32_t len = InputStream_readLeb128_u32(&in); + funcs = malloc(sizeof(struct Func) * len); + if (funcs == NULL) panic("out of memory"); + for (uint32_t i = 0; i < len; i += 1) { + funcs[i].type_idx = InputStream_readLeb128_u32(&in); + const struct FuncType *func_type = &types[funcs[i].type_idx]; + fputs("static ", out); + switch (func_type->result->len) { + case 0: fputs("void", out); break; + case 1: fputs(WasmValType_toC(func_type->result->types[0]), out); break; + default: panic("multiple function returns not supported"); + } + fprintf(out, " f%" PRIu32 "(", i); + if (func_type->param->len == 0) fputs("void", out); + for (uint32_t param_i = 0; param_i < func_type->param->len; param_i += 1) { + if (param_i > 0) fputs(", ", out); + fprintf(out, "%s", WasmValType_toC(func_type->param->types[param_i])); + } + fputs(");\n", out); + } + fputc('\n', out); + } + + struct Table { + int8_t type; + struct Limits limits; + } *tables; + (void)InputStream_skipToSection(&in, WasmSectionId_table); + { + uint32_t len = InputStream_readLeb128_u32(&in); + tables = malloc(sizeof(struct Table) * len); + if (tables == NULL) panic("out of memory"); + for (uint32_t i = 0; i < len; i += 1) { + int64_t ref_type = InputStream_readLeb128_i64(&in); + switch (ref_type) { + case WasmValType_funcref: + break; + + default: panic("unsupported reftype"); + } + tables[i].type = ref_type; + tables[i].limits = InputStream_readLimits(&in); + if (tables[i].limits.min != tables[i].limits.max) panic("growable table not supported"); + fprintf(out, "static void (*t%" PRIu32 "[UINT32_C(%" PRIu32 ")])(void);\n", + i, tables[i].limits.min); + } + fputc('\n', out); + } + + struct Mem { + struct Limits limits; + } *mems; + (void)InputStream_skipToSection(&in, WasmSectionId_mem); + uint32_t mems_len = InputStream_readLeb128_u32(&in); + { + mems = malloc(sizeof(struct Mem) * mems_len); + if (mems == NULL) panic("out of memory"); + for (uint32_t i = 0; i < mems_len; i += 1) { + mems[i].limits = InputStream_readLimits(&in); + fprintf(out, "static uint8_t *m%" PRIu32 ";\n" + "static uint32_t p%" PRIu32 ";\n" + "static uint32_t c%" PRIu32 ";\n", i, i, i); + } + fputc('\n', out); + } + + struct Global { + bool mut; + int8_t val_type; + } *globals; + (void)InputStream_skipToSection(&in, WasmSectionId_global); + { + uint32_t len = InputStream_readLeb128_u32(&in); + globals = malloc(sizeof(struct Global) * len); + if (globals == NULL) panic("out of memory"); + for (uint32_t i = 0; i < len; i += 1) { + int64_t val_type = InputStream_readLeb128_i64(&in); + enum WasmMut mut = InputStream_readByte(&in); + fprintf(out, "%s%s g%" PRIu32 " = ", WasmMut_toC(mut), WasmValType_toC(val_type), i); + renderExpr(out, &in); + fputs(";\n", out); + globals[i].mut = mut; + globals[i].val_type = val_type; + } + fputc('\n', out); + } + + (void)InputStream_skipToSection(&in, WasmSectionId_export); + { + uint32_t len = InputStream_readLeb128_u32(&in); + for (uint32_t i = 0; i < len; i += 1) { + char *name = InputStream_readName(&in); + uint8_t kind = InputStream_readByte(&in); + uint32_t idx = InputStream_readLeb128_u32(&in); + switch (kind) { + case 0x00: { + if (idx < imports_len) panic("can't export an import"); + const struct FuncType *func_type = &types[funcs[idx - imports_len].type_idx]; + switch (func_type->result->len) { + case 0: fputs("void", out); break; + case 1: fputs(WasmValType_toC(func_type->result->types[0]), out); break; + default: panic("multiple function returns not supported"); + } + fprintf(out, " %s_%s(", mod, name); + if (func_type->param->len == 0) fputs("void", out); + for (uint32_t param_i = 0; param_i < func_type->param->len; param_i += 1) { + if (param_i > 0) fputs(", ", out); + fprintf(out, "%s l%" PRIu32, WasmValType_toC(func_type->param->types[param_i]), param_i); + } + fprintf(out, + ") {\n" + " init();\n" + " %sf%" PRIu32 "(", + func_type->result->len > 0 ? "return " : "", idx - imports_len); + for (uint32_t param_i = 0; param_i < func_type->param->len; param_i += 1) { + if (param_i > 0) fputs(", ", out); + fprintf(out, "l%" PRIu32, param_i); + } + fputs(");\n}\n", out); + break; + } + + case 0x02: + fprintf(out, "uint8_t **const %s_%s = &m%" PRIu32 ";\n", mod, name, idx); + break; + + default: panic("unsupported export kind"); + } + free(name); + } + fputc('\n', out); + } + + (void)InputStream_skipToSection(&in, WasmSectionId_elem); + { + uint32_t table_i = 0; + uint32_t len = InputStream_readLeb128_u32(&in); + fputs("static void init_elem(void) {\n", out); + for (uint32_t segment_i = 0; segment_i < len; segment_i += 1) { + uint32_t table_idx = 0; + uint32_t elem_type = InputStream_readLeb128_u32(&in); + if (elem_type != 0x00) panic("unsupported elem type"); + uint32_t offset = evalExpr(&in); + uint32_t segment_len = InputStream_readLeb128_u32(&in); + for (uint32_t i = 0; i < segment_len; i += 1) { + uint32_t func_id = InputStream_readLeb128_u32(&in); + fprintf(out, " t%" PRIu32 "[UINT32_C(%" PRIu32 ")] = (void (*)(void))&", + table_idx, offset + i); + if (func_id < imports_len) + fprintf(out, "%s_%s", imports[func_id].mod, imports[func_id].name); + else + fprintf(out, "f%" PRIu32, func_id - imports_len); + fputs(";\n", out); + } + } + fputs("}\n\n", out); + } + + (void)InputStream_skipToSection(&in, WasmSectionId_code); + { + struct FuncGen fg; + FuncGen_init(&fg); + bool *param_used = malloc(sizeof(bool) * max_param_len); + uint32_t *param_stash = malloc(sizeof(uint32_t) * max_param_len); + + uint32_t len = InputStream_readLeb128_u32(&in); + for (uint32_t func_i = 0; func_i < len; func_i += 1) { + FuncGen_reset(&fg); + + uint32_t code_len = InputStream_readLeb128_u32(&in); + const struct FuncType *func_type = &types[funcs[func_i].type_idx]; + fputs("static ", out); + switch (func_type->result->len) { + case 0: fputs("void", out); break; + case 1: fputs(WasmValType_toC(func_type->result->types[0]), out); break; + default: panic("multiple function returns not supported"); + } + fprintf(out, " f%" PRIu32 "(", func_i); + if (func_type->param->len == 0) fputs("void", out); + for (uint32_t param_i = 0; param_i < func_type->param->len; param_i += 1) { + param_used[param_i] = false; + int8_t param_type = func_type->param->types[param_i]; + if (param_i > 0) fputs(", ", out); + FuncGen_localDeclare(&fg, out, param_type); + } + fputs(") {\n", out); + + for (uint32_t local_sets_remaining = InputStream_readLeb128_u32(&in); + local_sets_remaining > 0; local_sets_remaining -= 1) { + uint32_t local_set_len = InputStream_readLeb128_u32(&in); + int64_t val_type = InputStream_readLeb128_i64(&in); + for (; local_set_len > 0; local_set_len -= 1) { + FuncGen_indent(&fg, out); + FuncGen_localDeclare(&fg, out, val_type); + fputs(" = 0;\n", out); + } + } + + uint32_t unreachable_depth = 0; + for (uint32_t result_i = func_type->result->len; result_i > 0; ) { + result_i -= 1; + FuncGen_indent(&fg, out); + (void)FuncGen_localDeclare(&fg, out, + func_type->result->types[result_i]); + fputs(";\n", out); + } + FuncGen_blockBegin(&fg, out, WasmOpcode_block, funcs[func_i].type_idx); + while (!FuncGen_done(&fg)) { + //static const char *mnemonics[] = { + // [WasmOpcode_unreachable] = "unreachable", + // [WasmOpcode_nop] = "nop", + // [WasmOpcode_block] = "block", + // [WasmOpcode_loop] = "loop", + // [WasmOpcode_if] = "if", + // [WasmOpcode_else] = "else", + // [WasmOpcode_end] = "end", + // [WasmOpcode_br] = "br", + // [WasmOpcode_br_if] = "br_if", + // [WasmOpcode_br_table] = "br_table", + // [WasmOpcode_return] = "return", + // [WasmOpcode_call] = "call", + // [WasmOpcode_call_indirect] = "call_indirect", + // + // [WasmOpcode_drop] = "drop", + // [WasmOpcode_select] = "select", + // [WasmOpcode_select_t] = "select t", + // + // [WasmOpcode_local_get] = "local.get", + // [WasmOpcode_local_set] = "local.set", + // [WasmOpcode_local_tee] = "local.tee", + // [WasmOpcode_global_get] = "global.get", + // [WasmOpcode_global_set] = "global.set", + // [WasmOpcode_table_get] = "table.get", + // [WasmOpcode_table_set] = "table.set", + // + // [WasmOpcode_i32_load] = "i32.load", + // [WasmOpcode_i64_load] = "i64.load", + // [WasmOpcode_f32_load] = "f32.load", + // [WasmOpcode_f64_load] = "f64.load", + // [WasmOpcode_i32_load8_s] = "i32.load8_s", + // [WasmOpcode_i32_load8_u] = "i32.load8_u", + // [WasmOpcode_i32_load16_s] = "i32.load16_s", + // [WasmOpcode_i32_load16_u] = "i32.load16_u", + // [WasmOpcode_i64_load8_s] = "i64.load8_s", + // [WasmOpcode_i64_load8_u] = "i64.load8_u", + // [WasmOpcode_i64_load16_s] = "i64.load16_s", + // [WasmOpcode_i64_load16_u] = "i64.load16_u", + // [WasmOpcode_i64_load32_s] = "i64.load32_s", + // [WasmOpcode_i64_load32_u] = "i64.load32_u", + // [WasmOpcode_i32_store] = "i32.store", + // [WasmOpcode_i64_store] = "i64.store", + // [WasmOpcode_f32_store] = "f32.store", + // [WasmOpcode_f64_store] = "f64.store", + // [WasmOpcode_i32_store8] = "i32.store8", + // [WasmOpcode_i32_store16] = "i32.store16", + // [WasmOpcode_i64_store8] = "i64.store8", + // [WasmOpcode_i64_store16] = "i64.store16", + // [WasmOpcode_i64_store32] = "i64.store32", + // [WasmOpcode_memory_size] = "memory.size", + // [WasmOpcode_memory_grow] = "memory.grow", + // + // [WasmOpcode_i32_const] = "i32.const", + // [WasmOpcode_i64_const] = "i64.const", + // [WasmOpcode_f32_const] = "f32.const", + // [WasmOpcode_f64_const] = "f64.const", + // + // [WasmOpcode_i32_eqz] = "i32.eqz", + // [WasmOpcode_i32_eq] = "i32.eq", + // [WasmOpcode_i32_ne] = "i32.ne", + // [WasmOpcode_i32_lt_s] = "i32.lt_s", + // [WasmOpcode_i32_lt_u] = "i32.lt_u", + // [WasmOpcode_i32_gt_s] = "i32.gt_s", + // [WasmOpcode_i32_gt_u] = "i32.gt_u", + // [WasmOpcode_i32_le_s] = "i32.le_s", + // [WasmOpcode_i32_le_u] = "i32.le_u", + // [WasmOpcode_i32_ge_s] = "i32.ge_s", + // [WasmOpcode_i32_ge_u] = "i32.ge_u", + // + // [WasmOpcode_i64_eqz] = "i64.eqz", + // [WasmOpcode_i64_eq] = "i64.eq", + // [WasmOpcode_i64_ne] = "i64.ne", + // [WasmOpcode_i64_lt_s] = "i64.lt_s", + // [WasmOpcode_i64_lt_u] = "i64.lt_u", + // [WasmOpcode_i64_gt_s] = "i64.gt_s", + // [WasmOpcode_i64_gt_u] = "i64.gt_u", + // [WasmOpcode_i64_le_s] = "i64.le_s", + // [WasmOpcode_i64_le_u] = "i64.le_u", + // [WasmOpcode_i64_ge_s] = "i64.ge_s", + // [WasmOpcode_i64_ge_u] = "i64.ge_u", + // + // [WasmOpcode_f32_eq] = "f32.eq", + // [WasmOpcode_f32_ne] = "f32.ne", + // [WasmOpcode_f32_lt] = "f32.lt", + // [WasmOpcode_f32_gt] = "f32.gt", + // [WasmOpcode_f32_le] = "f32.le", + // [WasmOpcode_f32_ge] = "f32.ge", + // + // [WasmOpcode_f64_eq] = "f64.eq", + // [WasmOpcode_f64_ne] = "f64.ne", + // [WasmOpcode_f64_lt] = "f64.lt", + // [WasmOpcode_f64_gt] = "f64.gt", + // [WasmOpcode_f64_le] = "f64.le", + // [WasmOpcode_f64_ge] = "f64.ge", + // + // [WasmOpcode_i32_clz] = "i32.clz", + // [WasmOpcode_i32_ctz] = "i32.ctz", + // [WasmOpcode_i32_popcnt] = "i32.popcnt", + // [WasmOpcode_i32_add] = "i32.add", + // [WasmOpcode_i32_sub] = "i32.sub", + // [WasmOpcode_i32_mul] = "i32.mul", + // [WasmOpcode_i32_div_s] = "i32.div_s", + // [WasmOpcode_i32_div_u] = "i32.div_u", + // [WasmOpcode_i32_rem_s] = "i32.rem_s", + // [WasmOpcode_i32_rem_u] = "i32.rem_u", + // [WasmOpcode_i32_and] = "i32.and", + // [WasmOpcode_i32_or] = "i32.or", + // [WasmOpcode_i32_xor] = "i32.xor", + // [WasmOpcode_i32_shl] = "i32.shl", + // [WasmOpcode_i32_shr_s] = "i32.shr_s", + // [WasmOpcode_i32_shr_u] = "i32.shr_u", + // [WasmOpcode_i32_rotl] = "i32.rotl", + // [WasmOpcode_i32_rotr] = "i32.rotr", + // + // [WasmOpcode_i64_clz] = "i64.clz", + // [WasmOpcode_i64_ctz] = "i64.ctz", + // [WasmOpcode_i64_popcnt] = "i64.popcnt", + // [WasmOpcode_i64_add] = "i64.add", + // [WasmOpcode_i64_sub] = "i64.sub", + // [WasmOpcode_i64_mul] = "i64.mul", + // [WasmOpcode_i64_div_s] = "i64.div_s", + // [WasmOpcode_i64_div_u] = "i64.div_u", + // [WasmOpcode_i64_rem_s] = "i64.rem_s", + // [WasmOpcode_i64_rem_u] = "i64.rem_u", + // [WasmOpcode_i64_and] = "i64.and", + // [WasmOpcode_i64_or] = "i64.or", + // [WasmOpcode_i64_xor] = "i64.xor", + // [WasmOpcode_i64_shl] = "i64.shl", + // [WasmOpcode_i64_shr_s] = "i64.shr_s", + // [WasmOpcode_i64_shr_u] = "i64.shr_u", + // [WasmOpcode_i64_rotl] = "i64.rotl", + // [WasmOpcode_i64_rotr] = "i64.rotr", + // + // [WasmOpcode_f32_abs] = "f32.abs", + // [WasmOpcode_f32_neg] = "f32.neg", + // [WasmOpcode_f32_ceil] = "f32.ceil", + // [WasmOpcode_f32_floor] = "f32.floor", + // [WasmOpcode_f32_trunc] = "f32.trunc", + // [WasmOpcode_f32_nearest] = "f32.nearest", + // [WasmOpcode_f32_sqrt] = "f32.sqrt", + // [WasmOpcode_f32_add] = "f32.add", + // [WasmOpcode_f32_sub] = "f32.sub", + // [WasmOpcode_f32_mul] = "f32.mul", + // [WasmOpcode_f32_div] = "f32.div", + // [WasmOpcode_f32_min] = "f32.min", + // [WasmOpcode_f32_max] = "f32.max", + // [WasmOpcode_f32_copysign] = "f32.copysign", + // + // [WasmOpcode_f64_abs] = "f64.abs", + // [WasmOpcode_f64_neg] = "f64.neg", + // [WasmOpcode_f64_ceil] = "f64.ceil", + // [WasmOpcode_f64_floor] = "f64.floor", + // [WasmOpcode_f64_trunc] = "f64.trunc", + // [WasmOpcode_f64_nearest] = "f64.nearest", + // [WasmOpcode_f64_sqrt] = "f64.sqrt", + // [WasmOpcode_f64_add] = "f64.add", + // [WasmOpcode_f64_sub] = "f64.sub", + // [WasmOpcode_f64_mul] = "f64.mul", + // [WasmOpcode_f64_div] = "f64.div", + // [WasmOpcode_f64_min] = "f64.min", + // [WasmOpcode_f64_max] = "f64.max", + // [WasmOpcode_f64_copysign] = "f64.copysign", + // + // [WasmOpcode_i32_wrap_i64] = "i32.wrap_i64", + // [WasmOpcode_i32_trunc_f32_s] = "i32.trunc_f32_s", + // [WasmOpcode_i32_trunc_f32_u] = "i32.trunc_f32_u", + // [WasmOpcode_i32_trunc_f64_s] = "i32.trunc_f64_s", + // [WasmOpcode_i32_trunc_f64_u] = "i32.trunc_f64_u", + // [WasmOpcode_i64_extend_i32_s] = "i64.extend_i32_s", + // [WasmOpcode_i64_extend_i32_u] = "i64.extend_i32_u", + // [WasmOpcode_i64_trunc_f32_s] = "i64.trunc_f32_s", + // [WasmOpcode_i64_trunc_f32_u] = "i64.trunc_f32_u", + // [WasmOpcode_i64_trunc_f64_s] = "i64.trunc_f64_s", + // [WasmOpcode_i64_trunc_f64_u] = "i64.trunc_f64_u", + // [WasmOpcode_f32_convert_i32_s] = "f32.convert_i32_s", + // [WasmOpcode_f32_convert_i32_u] = "f32.convert_i32_u", + // [WasmOpcode_f32_convert_i64_s] = "f32.convert_i64_s", + // [WasmOpcode_f32_convert_i64_u] = "f32.convert_i64_u", + // [WasmOpcode_f32_demote_f64] = "f32.demote_f64", + // [WasmOpcode_f64_convert_i32_s] = "f64.convert_i32_s", + // [WasmOpcode_f64_convert_i32_u] = "f64.convert_i32_u", + // [WasmOpcode_f64_convert_i64_s] = "f64.convert_i64_s", + // [WasmOpcode_f64_convert_i64_u] = "f64.convert_i64_u", + // [WasmOpcode_f64_promote_f32] = "f64.promote_f32", + // [WasmOpcode_i32_reinterpret_f32] = "i32.reinterpret_f32", + // [WasmOpcode_i64_reinterpret_f64] = "i64.reinterpret_f64", + // [WasmOpcode_f32_reinterpret_i32] = "f32.reinterpret_i32", + // [WasmOpcode_f64_reinterpret_i64] = "f64.reinterpret_i64", + // + // [WasmOpcode_i32_extend8_s] = "i32.extend8_s", + // [WasmOpcode_i32_extend16_s] = "i32.extend16_s", + // [WasmOpcode_i64_extend8_s] = "i64.extend8_s", + // [WasmOpcode_i64_extend16_s] = "i64.extend16_s", + // [WasmOpcode_i64_extend32_s] = "i64.extend32_s", + // + // [WasmOpcode_prefixed] = "prefixed", + //}; + uint8_t opcode = InputStream_readByte(&in); + //FuncGen_indent(&fg, out); + //fprintf(out, "// %2u: ", fg.stack_i); + //if (mnemonics[opcode]) + // fprintf(out, "%s\n", mnemonics[opcode]); + //else + // fprintf(out, "%02hhX\n", opcode); + //fflush(out); // DEBUG + switch (opcode) { + case WasmOpcode_unreachable: + if (unreachable_depth == 0) { + FuncGen_indent(&fg, out); + fprintf(out, "abort();\n"); + unreachable_depth += 1; + } + break; + case WasmOpcode_nop: + break; + case WasmOpcode_block: + case WasmOpcode_loop: + case WasmOpcode_if: { + int64_t block_type = InputStream_readLeb128_i64(&in); + if (unreachable_depth == 0) { + const struct FuncType *func_type = FuncType_blockType(types, block_type); + for (uint32_t param_i = func_type->param->len; param_i > 0; ) { + param_i -= 1; + FuncGen_indent(&fg, out); + param_stash[param_i] = + FuncGen_localDeclare(&fg, out, func_type->param->types[param_i]); + fprintf(out, " = l%" PRIu32 ";\n", FuncGen_stackPop(&fg)); + } + for (uint32_t result_i = func_type->result->len; result_i > 0; ) { + result_i -= 1; + FuncGen_indent(&fg, out); + (void)FuncGen_localDeclare(&fg, out, + func_type->result->types[result_i]); + fputs(";\n", out); + } + FuncGen_blockBegin(&fg, out, opcode, block_type); + for (uint32_t param_i = 0; param_i < func_type->param->len; param_i += 1) { + FuncGen_stackPush(&fg, out, func_type->param->types[param_i]); + fprintf(out, " = l%" PRIu32 ";\n", param_stash[param_i]); + } + } else unreachable_depth += 1; + break; + } + case WasmOpcode_else: + case WasmOpcode_end: + if (unreachable_depth <= 1) { + const struct ResultType *result_type = + FuncType_blockType(types, FuncGen_blockType(&fg, 0))->result; + uint32_t label = FuncGen_blockLabel(&fg, 0); + if (unreachable_depth == 0) { + const struct ResultType *result_type = + FuncType_blockType(types, FuncGen_blockType(&fg, 0))->result; + for (uint32_t result_i = result_type->len; result_i > 0; ) { + result_i -= 1; + FuncGen_indent(&fg, out); + fprintf(out, "l%" PRIu32 " = l%" PRIu32 ";\n", + label - result_type->len + result_i, FuncGen_stackPop(&fg)); + } + } else unreachable_depth -= 1; + switch (opcode) { + case WasmOpcode_else: + FuncGen_outdent(&fg, out); + fputs("} else {\n", out); + break; + case WasmOpcode_end: + FuncGen_blockEnd(&fg, out); + for (uint32_t result_i = 0; result_i < result_type->len; + result_i += 1) { + FuncGen_stackPush(&fg, out, result_type->types[result_i]); + fprintf(out, "l%" PRIu32 ";\n", + label - result_type->len + result_i); + } + break; + } + } else if (opcode == WasmOpcode_end) unreachable_depth -= 1; + break; + case WasmOpcode_br: + case WasmOpcode_br_if: { + uint32_t label_idx = InputStream_readLeb128_u32(&in); + if (unreachable_depth == 0) { + enum WasmOpcode kind = FuncGen_blockKind(&fg, label_idx); + const struct FuncType *func_type = + FuncType_blockType(types, FuncGen_blockType(&fg, label_idx)); + uint32_t label = FuncGen_blockLabel(&fg, label_idx); + + if (opcode == WasmOpcode_br_if) { + FuncGen_indent(&fg, out); + fprintf(out, "if (l%" PRIu32 ") {\n", FuncGen_stackPop(&fg)); + } else if (EXTRA_BRACES) { + FuncGen_indent(&fg, out); + fputs("{\n", out); + } + + const struct ResultType *label_type; + uint32_t lhs; + switch (kind) { + case WasmOpcode_loop: + label_type = func_type->param; + lhs = label - func_type->result->len - func_type->param->len; + break; + default: + label_type = func_type->result; + lhs = label - func_type->result->len; + break; + } + for (uint32_t stack_i = 0; stack_i < label_type->len; stack_i += 1) { + uint32_t rhs; + switch (opcode) { + case WasmOpcode_br: + rhs = FuncGen_stackPop(&fg); + break; + case WasmOpcode_br_if: + rhs = FuncGen_stackAt(&fg, stack_i); + break; + default: panic("unexpected opcode"); + } + FuncGen_cont(&fg, out); + fprintf(out, "l%" PRIu32 " = l%" PRIu32 ";\n", lhs, rhs); + lhs += 1; + } + FuncGen_cont(&fg, out); + fprintf(out, "goto l%" PRIu32 ";\n", label); + if (EXTRA_BRACES || opcode == WasmOpcode_br_if) { + FuncGen_indent(&fg, out); + fputs("}\n", out); + } + if (opcode == WasmOpcode_br) unreachable_depth += 1; + } + break; + } + case WasmOpcode_br_table: { + if (unreachable_depth == 0) { + FuncGen_indent(&fg, out); + fprintf(out, "switch (l%" PRIu32 ") {\n", FuncGen_stackPop(&fg)); + } + uint32_t label_len = InputStream_readLeb128_u32(&in); + for (uint32_t i = 0; i < label_len; i += 1) { + uint32_t label = InputStream_readLeb128_u32(&in); + if (unreachable_depth == 0) { + FuncGen_indent(&fg, out); + fprintf(out, "case %u: goto l%" PRIu32 ";\n", + i, FuncGen_blockLabel(&fg, label)); + } + } + uint32_t label = InputStream_readLeb128_u32(&in); + if (unreachable_depth == 0) { + FuncGen_indent(&fg, out); + fprintf(out, "default: goto l%" PRIu32 ";\n", + FuncGen_blockLabel(&fg, label)); + FuncGen_indent(&fg, out); + fputs("}\n", out); + unreachable_depth += 1; + } + break; + } + case WasmOpcode_return: + if (unreachable_depth == 0) { + FuncGen_indent(&fg, out); + fputs("return", out); + switch (func_type->result->len) { + case 0: break; + case 1: fprintf(out, " l%" PRIu32, FuncGen_stackPop(&fg)); break; + default: panic("multiple function returns not supported"); + } + fputs(";\n", out); + unreachable_depth += 1; + } + break; + case WasmOpcode_call: + case WasmOpcode_call_indirect: { + uint32_t func_id; + uint32_t type_idx; + uint32_t table_idx; + switch (opcode) { + case WasmOpcode_call: + func_id = InputStream_readLeb128_u32(&in); + if (func_id < imports_len) + type_idx = imports[func_id].type_idx; + else + type_idx = funcs[func_id - imports_len].type_idx; + break; + case WasmOpcode_call_indirect: + type_idx = InputStream_readLeb128_u32(&in); + table_idx = InputStream_readLeb128_u32(&in); + func_id = FuncGen_stackPop(&fg); + break; + } + if (unreachable_depth == 0) { + const struct FuncType *callee_func_type = &types[type_idx]; + for (uint32_t param_i = callee_func_type->param->len; param_i > 0; ) { + param_i -= 1; + param_stash[param_i] = FuncGen_stackPop(&fg); + } + switch (callee_func_type->result->len) { + case 0: FuncGen_indent(&fg, out); break; + case 1: FuncGen_stackPush(&fg, out, callee_func_type->result->types[0]); break; + default: panic("multiple function returns not supported"); + } + switch (opcode) { + case WasmOpcode_call: + if (func_id < imports_len) + fprintf(out, "%s_%s", imports[func_id].mod, imports[func_id].name); + else + fprintf(out, "f%" PRIu32, func_id - imports_len); + break; + case WasmOpcode_call_indirect: + fputs("(*(", out); + switch (callee_func_type->result->len) { + case 0: fputs("void", out); break; + case 1: fputs(WasmValType_toC(callee_func_type->result->types[0]), out); break; + default: panic("multiple function returns not supported"); + } + fputs(" (*)(", out); + if (callee_func_type->param->len == 0) fputs("void", out); + for (uint32_t param_i = 0; param_i < callee_func_type->param->len; param_i += 1) { + if (param_i > 0) fputs(", ", out); + fputs(WasmValType_toC(callee_func_type->param->types[param_i]), out); + } + fprintf(out, "))t%" PRIu32 "[l%" PRIu32 "])", table_idx, func_id); + break; + } + fputc('(', out); + for (uint32_t param_i = 0; param_i < callee_func_type->param->len; + param_i += 1) { + if (param_i > 0) fputs(", ", out); + fprintf(out, "l%" PRIu32, param_stash[param_i]); + } + fputs(");\n", out); + } + break; + } + + case WasmOpcode_drop: + if (unreachable_depth == 0) { + FuncGen_indent(&fg, out); + fprintf(out, "(void)l%" PRIu32 ";\n", FuncGen_stackPop(&fg)); + } + break; + case WasmOpcode_select: + if (unreachable_depth == 0) { + uint32_t cond = FuncGen_stackPop(&fg); + uint32_t rhs = FuncGen_stackPop(&fg); + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, FuncGen_localType(&fg, lhs)); + fprintf(out, "l%" PRIu32 " ? l%" PRIu32 " : l%" PRIu32 ";\n", + cond, lhs, rhs); + } + break; + + case WasmOpcode_local_get: { + uint32_t local_idx = InputStream_readLeb128_u32(&in); + if (unreachable_depth == 0) { + if (local_idx < func_type->param->len) param_used[local_idx] = true; + FuncGen_stackPush(&fg, out, FuncGen_localType(&fg, local_idx)); + fprintf(out, "l%" PRIu32 ";\n", local_idx); + } + break; + } + case WasmOpcode_local_set: { + uint32_t local_idx = InputStream_readLeb128_u32(&in); + if (unreachable_depth == 0) { + if (local_idx < func_type->param->len) param_used[local_idx] = true; + FuncGen_indent(&fg, out); + fprintf(out, "l%" PRIu32 " = l%" PRIu32 ";\n", + local_idx, FuncGen_stackPop(&fg)); + } + break; + } + case WasmOpcode_local_tee: { + uint32_t local_idx = InputStream_readLeb128_u32(&in); + if (unreachable_depth == 0) { + if (local_idx < func_type->param->len) param_used[local_idx] = true; + FuncGen_indent(&fg, out); + fprintf(out, "l%" PRIu32 " = l%" PRIu32 ";\n", + local_idx, FuncGen_stackAt(&fg, 0)); + } + break; + } + + case WasmOpcode_global_get: { + uint32_t global_idx = InputStream_readLeb128_u32(&in); + if (unreachable_depth == 0) { + FuncGen_stackPush(&fg, out, globals[global_idx].val_type); + fprintf(out, "g%" PRIu32 ";\n", global_idx); + } + break; + } + case WasmOpcode_global_set: { + uint32_t global_idx = InputStream_readLeb128_u32(&in); + if (unreachable_depth == 0) { + FuncGen_indent(&fg, out); + fprintf(out, "g%" PRIu32 " = l%" PRIu32 ";\n", + global_idx, FuncGen_stackPop(&fg)); + } + break; + } + + case WasmOpcode_table_get: + case WasmOpcode_table_set: + (void)InputStream_readLeb128_u32(&in); + if (unreachable_depth == 0) panic("unimplemented opcode"); + break; + + case WasmOpcode_i32_load: { + uint32_t align = InputStream_readLeb128_u32(&in); + uint32_t offset = InputStream_readLeb128_u32(&in); + if (unreachable_depth == 0) { + uint32_t base = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i32); + fprintf(out, "load32_align%" PRIu32 "((const uint%" PRIu32 "_t *)&m%" PRIu32 + "[l%" PRIu32 " + UINT32_C(%" PRIu32 ")]);\n", + align, 8 << align, 0, base, offset); + } + break; + } + case WasmOpcode_i64_load: { + uint32_t align = InputStream_readLeb128_u32(&in); + uint32_t offset = InputStream_readLeb128_u32(&in); + if (unreachable_depth == 0) { + uint32_t base = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i64); + fprintf(out, "load64_align%" PRIu32 "((const uint%" PRIu32 "_t *)&m%" PRIu32 + "[l%" PRIu32 " + UINT32_C(%" PRIu32 ")]);\n", + align, 8 << align, 0, base, offset); + } + break; + } + case WasmOpcode_f32_load: { + uint32_t align = InputStream_readLeb128_u32(&in); + uint32_t offset = InputStream_readLeb128_u32(&in); + if (unreachable_depth == 0) { + uint32_t base = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_f32); + fprintf(out, "f32_reinterpret_i32(load32_align%" PRIu32 "((const uint%" PRIu32 + "_t *)&m%" PRIu32 "[l%" PRIu32 " + UINT32_C(%" PRIu32 ")]));\n", + align, 8 << align, 0, base, offset); + } + break; + } + case WasmOpcode_f64_load: { + uint32_t align = InputStream_readLeb128_u32(&in); + uint32_t offset = InputStream_readLeb128_u32(&in); + if (unreachable_depth == 0) { + uint32_t base = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_f64); + fprintf(out, "f64_reinterpret_i64(load64_align%" PRIu32 "((const uint%" PRIu32 + "_t *)&m%" PRIu32 "[l%" PRIu32 " + UINT32_C(%" PRIu32 ")]));\n", + align, 8 << align, 0, base, offset); + } + break; + } + case WasmOpcode_i32_load8_s: { + (void)InputStream_readLeb128_u32(&in); + uint32_t offset = InputStream_readLeb128_u32(&in); + if (unreachable_depth == 0) { + uint32_t base = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i32); + fprintf(out, "(int8_t)m%" PRIu32 "[l%" PRIu32 " + UINT32_C(%" PRIu32 ")];\n", + 0, base, offset); + } + break; + } + case WasmOpcode_i32_load8_u: { + (void)InputStream_readLeb128_u32(&in); + uint32_t offset = InputStream_readLeb128_u32(&in); + if (unreachable_depth == 0) { + uint32_t base = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i32); + fprintf(out, "m%" PRIu32 "[l%" PRIu32 " + UINT32_C(%" PRIu32 ")];\n", + 0, base, offset); + } + break; + } + case WasmOpcode_i32_load16_s: { + uint32_t align = InputStream_readLeb128_u32(&in); + uint32_t offset = InputStream_readLeb128_u32(&in); + if (unreachable_depth == 0) { + uint32_t base = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i32); + fprintf(out, "(int16_t)load16_align%" PRIu32 "((const uint%" PRIu32 "_t *)&m%" + PRIu32 "[l%" PRIu32 " + UINT32_C(%" PRIu32 ")]);\n", + align, 8 << align, 0, base, offset); + } + break; + } + case WasmOpcode_i32_load16_u: { + uint32_t align = InputStream_readLeb128_u32(&in); + uint32_t offset = InputStream_readLeb128_u32(&in); + if (unreachable_depth == 0) { + uint32_t base = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i32); + fprintf(out, "load16_align%" PRIu32 "((const uint%" PRIu32 "_t *)&m%" + PRIu32 "[l%" PRIu32 " + UINT32_C(%" PRIu32 ")]);\n", + align, 8 << align, 0, base, offset); + } + break; + } + case WasmOpcode_i64_load8_s: { + (void)InputStream_readLeb128_u32(&in); + uint32_t offset = InputStream_readLeb128_u32(&in); + if (unreachable_depth == 0) { + uint32_t base = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i64); + fprintf(out, "(int8_t)m%" PRIu32 "[l%" PRIu32 " + UINT32_C(%" PRIu32 ")];\n", + 0, base, offset); + } + break; + } + case WasmOpcode_i64_load8_u: { + (void)InputStream_readLeb128_u32(&in); + uint32_t offset = InputStream_readLeb128_u32(&in); + if (unreachable_depth == 0) { + uint32_t base = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i64); + fprintf(out, "m%" PRIu32 "[l%" PRIu32 " + UINT32_C(%" PRIu32 ")];\n", + 0, base, offset); + } + break; + } + case WasmOpcode_i64_load16_s: { + uint32_t align = InputStream_readLeb128_u32(&in); + uint32_t offset = InputStream_readLeb128_u32(&in); + if (unreachable_depth == 0) { + uint32_t base = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i64); + fprintf(out, "(int16_t)load16_align%" PRIu32 "((const uint%" PRIu32 "_t *)&m%" + PRIu32 "[l%" PRIu32 " + UINT32_C(%" PRIu32 ")]);\n", + align, 8 << align, 0, base, offset); + } + break; + } + case WasmOpcode_i64_load16_u: { + uint32_t align = InputStream_readLeb128_u32(&in); + uint32_t offset = InputStream_readLeb128_u32(&in); + if (unreachable_depth == 0) { + uint32_t base = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i64); + fprintf(out, "load16_align%" PRIu32 "((const uint%" PRIu32 "_t *)&m%" + PRIu32 "[l%" PRIu32 " + UINT32_C(%" PRIu32 ")]);\n", + align, 8 << align, 0, base, offset); + } + break; + } + case WasmOpcode_i64_load32_s: { + uint32_t align = InputStream_readLeb128_u32(&in); + uint32_t offset = InputStream_readLeb128_u32(&in); + if (unreachable_depth == 0) { + uint32_t base = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i64); + fprintf(out, "(int32_t)load32_align%" PRIu32 "((const uint%" PRIu32 "_t *)&m%" + PRIu32 "[l%" PRIu32 " + UINT32_C(%" PRIu32 ")]);\n", + align, 8 << align, 0, base, offset); + } + break; + } + case WasmOpcode_i64_load32_u: { + uint32_t align = InputStream_readLeb128_u32(&in); + uint32_t offset = InputStream_readLeb128_u32(&in); + if (unreachable_depth == 0) { + uint32_t base = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i64); + fprintf(out, "load32_align%" PRIu32 "((const uint%" PRIu32 "_t *)&m%" + PRIu32 "[l%" PRIu32 " + UINT32_C(%" PRIu32 ")]);\n", + align, 8 << align, 0, base, offset); + } + break; + } + + case WasmOpcode_i32_store: { + uint32_t align = InputStream_readLeb128_u32(&in); + uint32_t offset = InputStream_readLeb128_u32(&in); + if (unreachable_depth == 0) { + uint32_t value = FuncGen_stackPop(&fg); + uint32_t base = FuncGen_stackPop(&fg); + FuncGen_indent(&fg, out); + fprintf(out, "store32_align%" PRIu32 "((uint%" PRIu32 "_t *)&m%" + PRIu32 "[l%" PRIu32 " + UINT32_C(%" PRIu32 ")], l%" PRIu32 ");\n", + align, 8 << align, 0, base, offset, value); + } + break; + } + case WasmOpcode_i64_store: { + uint32_t align = InputStream_readLeb128_u32(&in); + uint32_t offset = InputStream_readLeb128_u32(&in); + if (unreachable_depth == 0) { + uint32_t value = FuncGen_stackPop(&fg); + uint32_t base = FuncGen_stackPop(&fg); + FuncGen_indent(&fg, out); + fprintf(out, "store64_align%" PRIu32 "((uint%" PRIu32 "_t *)&m%" + PRIu32 "[l%" PRIu32 " + UINT32_C(%" PRIu32 ")], l%" PRIu32 ");\n", + align, 8 << align, 0, base, offset, value); + } + break; + } + case WasmOpcode_f32_store: { + uint32_t align = InputStream_readLeb128_u32(&in); + uint32_t offset = InputStream_readLeb128_u32(&in); + if (unreachable_depth == 0) { + uint32_t value = FuncGen_stackPop(&fg); + uint32_t base = FuncGen_stackPop(&fg); + FuncGen_indent(&fg, out); + fprintf(out, "store32_align%" PRIu32 "((uint%" PRIu32 "_t *)&m%" + PRIu32 "[l%" PRIu32 " + UINT32_C(%" PRIu32 ")], " + "i32_reinterpret_f32(l%" PRIu32 "));\n", + align, 8 << align, 0, base, offset, value); + } + break; + } + case WasmOpcode_f64_store: { + uint32_t align = InputStream_readLeb128_u32(&in); + uint32_t offset = InputStream_readLeb128_u32(&in); + if (unreachable_depth == 0) { + uint32_t value = FuncGen_stackPop(&fg); + uint32_t base = FuncGen_stackPop(&fg); + FuncGen_indent(&fg, out); + fprintf(out, "store64_align%" PRIu32 "((uint%" PRIu32 "_t *)&m%" + PRIu32 "[l%" PRIu32 " + UINT32_C(%" PRIu32 ")], " + "i64_reinterpret_f64(l%" PRIu32 "));\n", + align, 8 << align, 0, base, offset, value); + } + break; + } + case WasmOpcode_i32_store8: { + (void)InputStream_readLeb128_u32(&in); + uint32_t offset = InputStream_readLeb128_u32(&in); + if (unreachable_depth == 0) { + uint32_t value = FuncGen_stackPop(&fg); + uint32_t base = FuncGen_stackPop(&fg); + FuncGen_indent(&fg, out); + fprintf(out, "m%" PRIu32 "[l%" PRIu32 " + UINT32_C(%" PRIu32 + ")] = (uint8_t)l%" PRIu32 ";\n", 0, base, offset, value); + } + break; + } + case WasmOpcode_i32_store16: { + uint32_t align = InputStream_readLeb128_u32(&in); + uint32_t offset = InputStream_readLeb128_u32(&in); + if (unreachable_depth == 0) { + uint32_t value = FuncGen_stackPop(&fg); + uint32_t base = FuncGen_stackPop(&fg); + FuncGen_indent(&fg, out); + fprintf(out, "store16_align%" PRIu32 "((uint%" PRIu32 "_t *)&m%" + PRIu32 "[l%" PRIu32 " + UINT32_C(%" PRIu32 ")], " + "(uint16_t)l%" PRIu32 ");\n", + align, 8 << align, 0, base, offset, value); + } + break; + } + case WasmOpcode_i64_store8: { + (void)InputStream_readLeb128_u32(&in); + uint32_t offset = InputStream_readLeb128_u32(&in); + if (unreachable_depth == 0) { + uint32_t value = FuncGen_stackPop(&fg); + uint32_t base = FuncGen_stackPop(&fg); + FuncGen_indent(&fg, out); + fprintf(out, "m%" PRIu32 "[l%" PRIu32 " + UINT32_C(%" PRIu32 + ")] = (uint8_t)l%" PRIu32 ";\n", 0, base, offset, value); + } + break; + } + case WasmOpcode_i64_store16: { + uint32_t align = InputStream_readLeb128_u32(&in); + uint32_t offset = InputStream_readLeb128_u32(&in); + if (unreachable_depth == 0) { + uint32_t value = FuncGen_stackPop(&fg); + uint32_t base = FuncGen_stackPop(&fg); + FuncGen_indent(&fg, out); + fprintf(out, "store16_align%" PRIu32 "((uint%" PRIu32 "_t *)&m%" + PRIu32 "[l%" PRIu32 " + UINT32_C(%" PRIu32 ")], " + "(uint16_t)l%" PRIu32 ");\n", + align, 8 << align, 0, base, offset, value); + } + break; + } + case WasmOpcode_i64_store32: { + uint32_t align = InputStream_readLeb128_u32(&in); + uint32_t offset = InputStream_readLeb128_u32(&in); + if (unreachable_depth == 0) { + uint32_t value = FuncGen_stackPop(&fg); + uint32_t base = FuncGen_stackPop(&fg); + FuncGen_indent(&fg, out); + fprintf(out, "store32_align%" PRIu32 "((uint%" PRIu32 "_t *)&m%" + PRIu32 "[l%" PRIu32 " + UINT32_C(%" PRIu32 ")], " + "(uint32_t)l%" PRIu32 ");\n", + align, 8 << align, 0, base, offset, value); + } + break; + } + + case WasmOpcode_memory_size: { + uint32_t mem_idx = InputStream_readLeb128_u32(&in); + if (unreachable_depth == 0) { + FuncGen_stackPush(&fg, out, WasmValType_i32); + fprintf(out, "p%" PRIu32 ";\n", mem_idx); + } + break; + } + case WasmOpcode_memory_grow: { + uint32_t mem_idx = InputStream_readLeb128_u32(&in); + if (unreachable_depth == 0) { + uint32_t pages = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i32); + fprintf(out, "memory_grow(&m%" PRIu32 ", &p%" PRIu32 ", &c%" PRIu32 + ", l%" PRIu32 ");\n", mem_idx, mem_idx, mem_idx, pages); + } + break; + } + + case WasmOpcode_i32_const: { + uint32_t value = (uint32_t)InputStream_readLeb128_i32(&in); + if (unreachable_depth == 0) { + FuncGen_stackPush(&fg, out, WasmValType_i32); + fprintf(out, "UINT32_C(0x%" PRIX32 ");\n", value); + } + break; + } + case WasmOpcode_i64_const: { + uint64_t value = (uint64_t)InputStream_readLeb128_i64(&in); + if (unreachable_depth == 0) { + FuncGen_stackPush(&fg, out, WasmValType_i64); + fprintf(out, "UINT64_C(0x%" PRIX64 ");\n", value); + } + break; + } + case WasmOpcode_f32_const: { + uint32_t value = InputStream_readLittle_u32(&in); + if (unreachable_depth == 0) { + FuncGen_stackPush(&fg, out, WasmValType_f32); + fprintf(out, "f32_reinterpret_i32(UINT32_C(0x%" PRIX32 "));\n", value); + } + break; + } + case WasmOpcode_f64_const: { + uint64_t value = InputStream_readLittle_u64(&in); + if (unreachable_depth == 0) { + FuncGen_stackPush(&fg, out, WasmValType_f64); + fprintf(out, "f64_reinterpret_i64(UINT64_C(0x%" PRIX64 "));\n", value); + } + break; + } + + case WasmOpcode_i32_eqz: + if (unreachable_depth == 0) { + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i32); + fprintf(out, "!l%" PRIu32 ";\n", lhs); + } + break; + case WasmOpcode_i32_eq: + if (unreachable_depth == 0) { + uint32_t rhs = FuncGen_stackPop(&fg); + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i32); + fprintf(out, "l%" PRIu32 " == l%" PRIu32 ";\n", lhs, rhs); + } + break; + case WasmOpcode_i32_ne: + if (unreachable_depth == 0) { + uint32_t rhs = FuncGen_stackPop(&fg); + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i32); + fprintf(out, "l%" PRIu32 " != l%" PRIu32 ";\n", lhs, rhs); + } + break; + case WasmOpcode_i32_lt_s: + if (unreachable_depth == 0) { + uint32_t rhs = FuncGen_stackPop(&fg); + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i32); + fprintf(out, "(int32_t)l%" PRIu32 " < (int32_t)l%" PRIu32 ";\n", lhs, rhs); + } + break; + case WasmOpcode_i32_lt_u: + if (unreachable_depth == 0) { + uint32_t rhs = FuncGen_stackPop(&fg); + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i32); + fprintf(out, "l%" PRIu32 " < l%" PRIu32 ";\n", lhs, rhs); + } + break; + case WasmOpcode_i32_gt_s: + if (unreachable_depth == 0) { + uint32_t rhs = FuncGen_stackPop(&fg); + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i32); + fprintf(out, "(int32_t)l%" PRIu32 " > (int32_t)l%" PRIu32 ";\n", lhs, rhs); + } + break; + case WasmOpcode_i32_gt_u: + if (unreachable_depth == 0) { + uint32_t rhs = FuncGen_stackPop(&fg); + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i32); + fprintf(out, "l%" PRIu32 " > l%" PRIu32 ";\n", lhs, rhs); + } + break; + case WasmOpcode_i32_le_s: + if (unreachable_depth == 0) { + uint32_t rhs = FuncGen_stackPop(&fg); + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i32); + fprintf(out, "(int32_t)l%" PRIu32 " <= (int32_t)l%" PRIu32 ";\n", lhs, rhs); + } + break; + case WasmOpcode_i32_le_u: + if (unreachable_depth == 0) { + uint32_t rhs = FuncGen_stackPop(&fg); + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i32); + fprintf(out, "l%" PRIu32 " <= l%" PRIu32 ";\n", lhs, rhs); + } + break; + case WasmOpcode_i32_ge_s: + if (unreachable_depth == 0) { + uint32_t rhs = FuncGen_stackPop(&fg); + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i32); + fprintf(out, "(int32_t)l%" PRIu32 " >= (int32_t)l%" PRIu32 ";\n", lhs, rhs); + } + break; + case WasmOpcode_i32_ge_u: + if (unreachable_depth == 0) { + uint32_t rhs = FuncGen_stackPop(&fg); + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i32); + fprintf(out, "l%" PRIu32 " >= l%" PRIu32 ";\n", lhs, rhs); + } + break; + + case WasmOpcode_i64_eqz: + if (unreachable_depth == 0) { + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i32); + fprintf(out, "!l%" PRIu32 ";\n", lhs); + } + break; + case WasmOpcode_i64_eq: + if (unreachable_depth == 0) { + uint32_t rhs = FuncGen_stackPop(&fg); + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i32); + fprintf(out, "l%" PRIu32 " == l%" PRIu32 ";\n", lhs, rhs); + } + break; + case WasmOpcode_i64_ne: + if (unreachable_depth == 0) { + uint32_t rhs = FuncGen_stackPop(&fg); + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i32); + fprintf(out, "l%" PRIu32 " != l%" PRIu32 ";\n", lhs, rhs); + } + break; + case WasmOpcode_i64_lt_s: + if (unreachable_depth == 0) { + uint32_t rhs = FuncGen_stackPop(&fg); + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i32); + fprintf(out, "(int64_t)l%" PRIu32 " < (int64_t)l%" PRIu32 ";\n", lhs, rhs); + } + break; + case WasmOpcode_i64_lt_u: + if (unreachable_depth == 0) { + uint32_t rhs = FuncGen_stackPop(&fg); + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i32); + fprintf(out, "l%" PRIu32 " < l%" PRIu32 ";\n", lhs, rhs); + } + break; + case WasmOpcode_i64_gt_s: + if (unreachable_depth == 0) { + uint32_t rhs = FuncGen_stackPop(&fg); + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i32); + fprintf(out, "(int64_t)l%" PRIu32 " > (int64_t)l%" PRIu32 ";\n", lhs, rhs); + } + break; + case WasmOpcode_i64_gt_u: + if (unreachable_depth == 0) { + uint32_t rhs = FuncGen_stackPop(&fg); + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i32); + fprintf(out, "l%" PRIu32 " > l%" PRIu32 ";\n", lhs, rhs); + } + break; + case WasmOpcode_i64_le_s: + if (unreachable_depth == 0) { + uint32_t rhs = FuncGen_stackPop(&fg); + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i32); + fprintf(out, "(int64_t)l%" PRIu32 " <= (int64_t)l%" PRIu32 ";\n", lhs, rhs); + } + break; + case WasmOpcode_i64_le_u: + if (unreachable_depth == 0) { + uint32_t rhs = FuncGen_stackPop(&fg); + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i32); + fprintf(out, "l%" PRIu32 " <= l%" PRIu32 ";\n", lhs, rhs); + } + break; + case WasmOpcode_i64_ge_s: + if (unreachable_depth == 0) { + uint32_t rhs = FuncGen_stackPop(&fg); + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i32); + fprintf(out, "(int64_t)l%" PRIu32 " >= (int64_t)l%" PRIu32 ";\n", lhs, rhs); + } + break; + case WasmOpcode_i64_ge_u: + if (unreachable_depth == 0) { + uint32_t rhs = FuncGen_stackPop(&fg); + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i32); + fprintf(out, "l%" PRIu32 " >= l%" PRIu32 ";\n", lhs, rhs); + } + break; + + case WasmOpcode_f32_eq: + if (unreachable_depth == 0) { + uint32_t rhs = FuncGen_stackPop(&fg); + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i32); + fprintf(out, "l%" PRIu32 " == l%" PRIu32 ";\n", lhs, rhs); + } + break; + case WasmOpcode_f32_ne: + if (unreachable_depth == 0) { + uint32_t rhs = FuncGen_stackPop(&fg); + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i32); + fprintf(out, "l%" PRIu32 " != l%" PRIu32 ";\n", lhs, rhs); + } + break; + case WasmOpcode_f32_lt: + if (unreachable_depth == 0) { + uint32_t rhs = FuncGen_stackPop(&fg); + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i32); + fprintf(out, "l%" PRIu32 " < l%" PRIu32 ";\n", lhs, rhs); + } + break; + case WasmOpcode_f32_gt: + if (unreachable_depth == 0) { + uint32_t rhs = FuncGen_stackPop(&fg); + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i32); + fprintf(out, "l%" PRIu32 " > l%" PRIu32 ";\n", lhs, rhs); + } + break; + case WasmOpcode_f32_le: + if (unreachable_depth == 0) { + uint32_t rhs = FuncGen_stackPop(&fg); + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i32); + fprintf(out, "l%" PRIu32 " <= l%" PRIu32 ";\n", lhs, rhs); + } + break; + case WasmOpcode_f32_ge: + if (unreachable_depth == 0) { + uint32_t rhs = FuncGen_stackPop(&fg); + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i32); + fprintf(out, "l%" PRIu32 " >= l%" PRIu32 ";\n", lhs, rhs); + } + break; + + case WasmOpcode_f64_eq: + if (unreachable_depth == 0) { + uint32_t rhs = FuncGen_stackPop(&fg); + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i32); + fprintf(out, "l%" PRIu32 " == l%" PRIu32 ";\n", lhs, rhs); + } + break; + case WasmOpcode_f64_ne: + if (unreachable_depth == 0) { + uint32_t rhs = FuncGen_stackPop(&fg); + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i32); + fprintf(out, "l%" PRIu32 " != l%" PRIu32 ";\n", lhs, rhs); + } + break; + case WasmOpcode_f64_lt: + if (unreachable_depth == 0) { + uint32_t rhs = FuncGen_stackPop(&fg); + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i32); + fprintf(out, "l%" PRIu32 " < l%" PRIu32 ";\n", lhs, rhs); + } + break; + case WasmOpcode_f64_gt: + if (unreachable_depth == 0) { + uint32_t rhs = FuncGen_stackPop(&fg); + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i32); + fprintf(out, "l%" PRIu32 " > l%" PRIu32 ";\n", lhs, rhs); + } + break; + case WasmOpcode_f64_le: + if (unreachable_depth == 0) { + uint32_t rhs = FuncGen_stackPop(&fg); + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i32); + fprintf(out, "l%" PRIu32 " <= l%" PRIu32 ";\n", lhs, rhs); + } + break; + case WasmOpcode_f64_ge: + if (unreachable_depth == 0) { + uint32_t rhs = FuncGen_stackPop(&fg); + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i32); + fprintf(out, "l%" PRIu32 " >= l%" PRIu32 ";\n", lhs, rhs); + } + break; + + case WasmOpcode_i32_clz: + if (unreachable_depth == 0) { + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i32); + fprintf(out, "l%" PRIu32 " != 0 ? __builtin_clz(l%" PRIu32 ") : 32;\n", + lhs, lhs); + } + break; + case WasmOpcode_i32_ctz: + if (unreachable_depth == 0) { + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i32); + fprintf(out, "l%" PRIu32 " != 0 ? __builtin_ctz(l%" PRIu32 ") : 32;\n", + lhs, lhs); + } + break; + case WasmOpcode_i32_popcnt: + if (unreachable_depth == 0) { + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i32); + fprintf(out, "__builtin_popcount(l%" PRIu32 ");\n", lhs); + } + break; + case WasmOpcode_i32_add: + if (unreachable_depth == 0) { + uint32_t rhs = FuncGen_stackPop(&fg); + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i32); + fprintf(out, "l%" PRIu32 " + l%" PRIu32 ";\n", lhs, rhs); + } + break; + case WasmOpcode_i32_sub: + if (unreachable_depth == 0) { + uint32_t rhs = FuncGen_stackPop(&fg); + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i32); + fprintf(out, "l%" PRIu32 " - l%" PRIu32 ";\n", lhs, rhs); + } + break; + case WasmOpcode_i32_mul: + if (unreachable_depth == 0) { + uint32_t rhs = FuncGen_stackPop(&fg); + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i32); + fprintf(out, "l%" PRIu32 " * l%" PRIu32 ";\n", lhs, rhs); + } + break; + case WasmOpcode_i32_div_s: + if (unreachable_depth == 0) { + uint32_t rhs = FuncGen_stackPop(&fg); + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i32); + fprintf(out, "(int32_t)l%" PRIu32 " / (int32_t)l%" PRIu32 ";\n", lhs, rhs); + } + break; + case WasmOpcode_i32_div_u: + if (unreachable_depth == 0) { + uint32_t rhs = FuncGen_stackPop(&fg); + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i32); + fprintf(out, "l%" PRIu32 " / l%" PRIu32 ";\n", lhs, rhs); + } + break; + case WasmOpcode_i32_rem_s: + if (unreachable_depth == 0) { + uint32_t rhs = FuncGen_stackPop(&fg); + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i32); + fprintf(out, "(int32_t)l%" PRIu32 " %% (int32_t)l%" PRIu32 ";\n", lhs, rhs); + } + break; + case WasmOpcode_i32_rem_u: + if (unreachable_depth == 0) { + uint32_t rhs = FuncGen_stackPop(&fg); + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i32); + fprintf(out, "l%" PRIu32 " %% l%" PRIu32 ";\n", lhs, rhs); + } + break; + case WasmOpcode_i32_and: + if (unreachable_depth == 0) { + uint32_t rhs = FuncGen_stackPop(&fg); + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i32); + fprintf(out, "l%" PRIu32 " & l%" PRIu32 ";\n", lhs, rhs); + } + break; + case WasmOpcode_i32_or: + if (unreachable_depth == 0) { + uint32_t rhs = FuncGen_stackPop(&fg); + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i32); + fprintf(out, "l%" PRIu32 " | l%" PRIu32 ";\n", lhs, rhs); + } + break; + case WasmOpcode_i32_xor: + if (unreachable_depth == 0) { + uint32_t rhs = FuncGen_stackPop(&fg); + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i32); + fprintf(out, "l%" PRIu32 " ^ l%" PRIu32 ";\n", lhs, rhs); + } + break; + case WasmOpcode_i32_shl: + if (unreachable_depth == 0) { + uint32_t rhs = FuncGen_stackPop(&fg); + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i32); + fprintf(out, "l%" PRIu32 " << (l%" PRIu32 " & 0x1F);\n", lhs, rhs); + } + break; + case WasmOpcode_i32_shr_s: + if (unreachable_depth == 0) { + uint32_t rhs = FuncGen_stackPop(&fg); + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i32); + fprintf(out, "(int32_t)l%" PRIu32 " >> (l%" PRIu32 " & 0x1F);\n", lhs, rhs); + } + break; + case WasmOpcode_i32_shr_u: + if (unreachable_depth == 0) { + uint32_t rhs = FuncGen_stackPop(&fg); + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i32); + fprintf(out, "l%" PRIu32 " >> (l%" PRIu32 " & 0x1F);\n", lhs, rhs); + } + break; + case WasmOpcode_i32_rotl: + if (unreachable_depth == 0) { + uint32_t rhs = FuncGen_stackPop(&fg); + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i32); + fprintf(out, "l%" PRIu32 " << (l%" PRIu32 " & 0x1F) | " + "l%" PRIu32 " >> (-l%" PRIu32" & 0x1F);\n", lhs, rhs, lhs, rhs); + } + break; + case WasmOpcode_i32_rotr: + if (unreachable_depth == 0) { + uint32_t rhs = FuncGen_stackPop(&fg); + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i32); + fprintf(out, "l%" PRIu32 " >> (l%" PRIu32 " & 0x1F) | " + "l%" PRIu32 " << (-l%" PRIu32" & 0x1F);\n", lhs, rhs, lhs, rhs); + } + break; + + case WasmOpcode_i64_clz: + if (unreachable_depth == 0) { + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i64); + fprintf(out, "l%" PRIu32 " != 0 ? __builtin_clzll(l%" PRIu32 ") : 64;\n", + lhs, lhs); + } + break; + case WasmOpcode_i64_ctz: + if (unreachable_depth == 0) { + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i64); + fprintf(out, "l%" PRIu32 " != 0 ? __builtin_ctzll(l%" PRIu32 ") : 64;\n", + lhs, lhs); + } + break; + case WasmOpcode_i64_popcnt: + if (unreachable_depth == 0) { + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i64); + fprintf(out, "__builtin_popcountll(l%" PRIu32 ");\n", lhs); + } + break; + case WasmOpcode_i64_add: + if (unreachable_depth == 0) { + uint32_t rhs = FuncGen_stackPop(&fg); + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i64); + fprintf(out, "l%" PRIu32 " + l%" PRIu32 ";\n", lhs, rhs); + } + break; + case WasmOpcode_i64_sub: + if (unreachable_depth == 0) { + uint32_t rhs = FuncGen_stackPop(&fg); + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i64); + fprintf(out, "l%" PRIu32 " - l%" PRIu32 ";\n", lhs, rhs); + } + break; + case WasmOpcode_i64_mul: + if (unreachable_depth == 0) { + uint32_t rhs = FuncGen_stackPop(&fg); + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i64); + fprintf(out, "l%" PRIu32 " * l%" PRIu32 ";\n", lhs, rhs); + } + break; + case WasmOpcode_i64_div_s: + if (unreachable_depth == 0) { + uint32_t rhs = FuncGen_stackPop(&fg); + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i64); + fprintf(out, "(int64_t)l%" PRIu32 " / (int64_t)l%" PRIu32 ";\n", lhs, rhs); + } + break; + case WasmOpcode_i64_div_u: + if (unreachable_depth == 0) { + uint32_t rhs = FuncGen_stackPop(&fg); + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i64); + fprintf(out, "l%" PRIu32 " / l%" PRIu32 ";\n", lhs, rhs); + } + break; + case WasmOpcode_i64_rem_s: + if (unreachable_depth == 0) { + uint32_t rhs = FuncGen_stackPop(&fg); + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i64); + fprintf(out, "(int64_t)l%" PRIu32 " %% (int64_t)l%" PRIu32 ";\n", lhs, rhs); + } + break; + case WasmOpcode_i64_rem_u: + if (unreachable_depth == 0) { + uint32_t rhs = FuncGen_stackPop(&fg); + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i64); + fprintf(out, "l%" PRIu32 " %% l%" PRIu32 ";\n", lhs, rhs); + } + break; + case WasmOpcode_i64_and: + if (unreachable_depth == 0) { + uint32_t rhs = FuncGen_stackPop(&fg); + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i64); + fprintf(out, "l%" PRIu32 " & l%" PRIu32 ";\n", lhs, rhs); + } + break; + case WasmOpcode_i64_or: + if (unreachable_depth == 0) { + uint32_t rhs = FuncGen_stackPop(&fg); + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i64); + fprintf(out, "l%" PRIu32 " | l%" PRIu32 ";\n", lhs, rhs); + } + break; + case WasmOpcode_i64_xor: + if (unreachable_depth == 0) { + uint32_t rhs = FuncGen_stackPop(&fg); + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i64); + fprintf(out, "l%" PRIu32 " ^ l%" PRIu32 ";\n", lhs, rhs); + } + break; + case WasmOpcode_i64_shl: + if (unreachable_depth == 0) { + uint32_t rhs = FuncGen_stackPop(&fg); + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i64); + fprintf(out, "l%" PRIu32 " << (l%" PRIu32 " & 0x3F);\n", lhs, rhs); + } + break; + case WasmOpcode_i64_shr_s: + if (unreachable_depth == 0) { + uint32_t rhs = FuncGen_stackPop(&fg); + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i64); + fprintf(out, "(int64_t)l%" PRIu32 " >> (l%" PRIu32 " & 0x3F);\n", lhs, rhs); + } + break; + case WasmOpcode_i64_shr_u: + if (unreachable_depth == 0) { + uint32_t rhs = FuncGen_stackPop(&fg); + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i64); + fprintf(out, "l%" PRIu32 " >> (l%" PRIu32 " & 0x3F);\n", lhs, rhs); + } + break; + case WasmOpcode_i64_rotl: + if (unreachable_depth == 0) { + uint32_t rhs = FuncGen_stackPop(&fg); + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i64); + fprintf(out, "l%" PRIu32 " << (l%" PRIu32 " & 0x3F) | " + "l%" PRIu32 " >> (-l%" PRIu32" & 0x3F);\n", lhs, rhs, lhs, rhs); + } + break; + case WasmOpcode_i64_rotr: + if (unreachable_depth == 0) { + uint32_t rhs = FuncGen_stackPop(&fg); + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i64); + fprintf(out, "l%" PRIu32 " >> (l%" PRIu32 " & 0x3F) | " + "l%" PRIu32 " << (-l%" PRIu32" & 0x3F);\n", lhs, rhs, lhs, rhs); + } + break; + + case WasmOpcode_f32_abs: + if (unreachable_depth == 0) { + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_f32); + fprintf(out, "fabsf(l%" PRIu32 ");\n", lhs); + } + break; + case WasmOpcode_f32_neg: + if (unreachable_depth == 0) { + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_f32); + fprintf(out, "-l%" PRIu32 ";\n", lhs); + } + break; + case WasmOpcode_f32_ceil: + if (unreachable_depth == 0) { + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_f32); + fprintf(out, "ceilf(l%" PRIu32 ");\n", lhs); + } + break; + case WasmOpcode_f32_floor: + if (unreachable_depth == 0) { + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_f32); + fprintf(out, "floorf(l%" PRIu32 ");\n", lhs); + } + break; + case WasmOpcode_f32_trunc: + if (unreachable_depth == 0) { + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_f32); + fprintf(out, "truncf(l%" PRIu32 ");\n", lhs); + } + break; + case WasmOpcode_f32_nearest: + if (unreachable_depth == 0) { + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_f32); + fprintf(out, "roundf(l%" PRIu32 ");\n", lhs); + } + break; + case WasmOpcode_f32_sqrt: + if (unreachable_depth == 0) { + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_f32); + fprintf(out, "sqrtf(l%" PRIu32 ");\n", lhs); + } + break; + case WasmOpcode_f32_add: + if (unreachable_depth == 0) { + uint32_t rhs = FuncGen_stackPop(&fg); + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_f32); + fprintf(out, "l%" PRIu32 " + l%" PRIu32 ";\n", lhs, rhs); + } + break; + case WasmOpcode_f32_sub: + if (unreachable_depth == 0) { + uint32_t rhs = FuncGen_stackPop(&fg); + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_f32); + fprintf(out, "l%" PRIu32 " - l%" PRIu32 ";\n", lhs, rhs); + } + break; + case WasmOpcode_f32_mul: + if (unreachable_depth == 0) { + uint32_t rhs = FuncGen_stackPop(&fg); + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_f32); + fprintf(out, "l%" PRIu32 " * l%" PRIu32 ";\n", lhs, rhs); + } + break; + case WasmOpcode_f32_div: + if (unreachable_depth == 0) { + uint32_t rhs = FuncGen_stackPop(&fg); + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_f32); + fprintf(out, "l%" PRIu32 " / l%" PRIu32 ";\n", lhs, rhs); + } + break; + case WasmOpcode_f32_min: + if (unreachable_depth == 0) { + uint32_t rhs = FuncGen_stackPop(&fg); + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_f32); + fprintf(out, "fminf(l%" PRIu32 ", l%" PRIu32 ");\n", lhs, rhs); + } + break; + case WasmOpcode_f32_max: + if (unreachable_depth == 0) { + uint32_t rhs = FuncGen_stackPop(&fg); + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_f32); + fprintf(out, "fmaxf(l%" PRIu32 ", l%" PRIu32 ");\n", lhs, rhs); + } + break; + case WasmOpcode_f32_copysign: + if (unreachable_depth == 0) { + uint32_t rhs = FuncGen_stackPop(&fg); + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_f32); + fprintf(out, "copysignf(l%" PRIu32 ", l%" PRIu32 ");\n", lhs, rhs); + } + break; + + case WasmOpcode_f64_abs: + if (unreachable_depth == 0) { + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_f64); + fprintf(out, "fabs(l%" PRIu32 ");\n", lhs); + } + break; + case WasmOpcode_f64_neg: + if (unreachable_depth == 0) { + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_f64); + fprintf(out, "-l%" PRIu32 ";\n", lhs); + } + break; + case WasmOpcode_f64_ceil: + if (unreachable_depth == 0) { + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_f64); + fprintf(out, "ceil(l%" PRIu32 ");\n", lhs); + } + break; + case WasmOpcode_f64_floor: + if (unreachable_depth == 0) { + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_f64); + fprintf(out, "floor(l%" PRIu32 ");\n", lhs); + } + break; + case WasmOpcode_f64_trunc: + if (unreachable_depth == 0) { + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_f64); + fprintf(out, "trunc(l%" PRIu32 ");\n", lhs); + } + break; + case WasmOpcode_f64_nearest: + if (unreachable_depth == 0) { + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_f64); + fprintf(out, "round(l%" PRIu32 ");\n", lhs); + } + break; + case WasmOpcode_f64_sqrt: + if (unreachable_depth == 0) { + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_f64); + fprintf(out, "sqrt(l%" PRIu32 ");\n", lhs); + } + break; + case WasmOpcode_f64_add: + if (unreachable_depth == 0) { + uint32_t rhs = FuncGen_stackPop(&fg); + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_f64); + fprintf(out, "l%" PRIu32 " + l%" PRIu32 ";\n", lhs, rhs); + } + break; + case WasmOpcode_f64_sub: + if (unreachable_depth == 0) { + uint32_t rhs = FuncGen_stackPop(&fg); + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_f64); + fprintf(out, "l%" PRIu32 " - l%" PRIu32 ";\n", lhs, rhs); + } + break; + case WasmOpcode_f64_mul: + if (unreachable_depth == 0) { + uint32_t rhs = FuncGen_stackPop(&fg); + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_f64); + fprintf(out, "l%" PRIu32 " * l%" PRIu32 ";\n", lhs, rhs); + } + break; + case WasmOpcode_f64_div: + if (unreachable_depth == 0) { + uint32_t rhs = FuncGen_stackPop(&fg); + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_f64); + fprintf(out, "l%" PRIu32 " / l%" PRIu32 ";\n", lhs, rhs); + } + break; + case WasmOpcode_f64_min: + if (unreachable_depth == 0) { + uint32_t rhs = FuncGen_stackPop(&fg); + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_f64); + fprintf(out, "fmin(l%" PRIu32 ", l%" PRIu32 ");\n", lhs, rhs); + } + break; + case WasmOpcode_f64_max: + if (unreachable_depth == 0) { + uint32_t rhs = FuncGen_stackPop(&fg); + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_f64); + fprintf(out, "fmax(l%" PRIu32 ", l%" PRIu32 ");\n", lhs, rhs); + } + break; + case WasmOpcode_f64_copysign: + if (unreachable_depth == 0) { + uint32_t rhs = FuncGen_stackPop(&fg); + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_f64); + fprintf(out, "copysign(l%" PRIu32 ", l%" PRIu32 ");\n", lhs, rhs); + } + break; + + case WasmOpcode_i32_wrap_i64: + if (unreachable_depth == 0) { + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i32); + fprintf(out, "(uint32_t)l%" PRIu32 ";\n", lhs); + } + break; + case WasmOpcode_i32_trunc_f32_s: + if (unreachable_depth == 0) { + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i32); + fprintf(out, "(int32_t)l%" PRIu32 ";\n", lhs); + } + break; + case WasmOpcode_i32_trunc_f32_u: + if (unreachable_depth == 0) { + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i32); + fprintf(out, "(uint32_t)l%" PRIu32 ";\n", lhs); + } + break; + case WasmOpcode_i32_trunc_f64_s: + if (unreachable_depth == 0) { + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i32); + fprintf(out, "(int32_t)l%" PRIu32 ";\n", lhs); + } + break; + case WasmOpcode_i32_trunc_f64_u: + if (unreachable_depth == 0) { + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i32); + fprintf(out, "(uint32_t)l%" PRIu32 ";\n", lhs); + } + break; + case WasmOpcode_i64_extend_i32_s: + if (unreachable_depth == 0) { + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i64); + fprintf(out, "(int32_t)l%" PRIu32 ";\n", lhs); + } + break; + case WasmOpcode_i64_extend_i32_u: + if (unreachable_depth == 0) { + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i64); + fprintf(out, "(uint32_t)l%" PRIu32 ";\n", lhs); + } + break; + case WasmOpcode_i64_trunc_f32_s: + if (unreachable_depth == 0) { + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i64); + fprintf(out, "(int64_t)l%" PRIu32 ";\n", lhs); + } + break; + case WasmOpcode_i64_trunc_f32_u: + if (unreachable_depth == 0) { + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i64); + fprintf(out, "(uint64_t)l%" PRIu32 ";\n", lhs); + } + break; + case WasmOpcode_i64_trunc_f64_s: + if (unreachable_depth == 0) { + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i64); + fprintf(out, "(int64_t)l%" PRIu32 ";\n", lhs); + } + break; + case WasmOpcode_i64_trunc_f64_u: + if (unreachable_depth == 0) { + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i64); + fprintf(out, "(uint64_t)l%" PRIu32 ";\n", lhs); + } + break; + case WasmOpcode_f32_convert_i32_s: + if (unreachable_depth == 0) { + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_f32); + fprintf(out, "(int32_t)l%" PRIu32 ";\n", lhs); + } + break; + case WasmOpcode_f32_convert_i32_u: + if (unreachable_depth == 0) { + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_f32); + fprintf(out, "(uint32_t)l%" PRIu32 ";\n", lhs); + } + break; + case WasmOpcode_f32_convert_i64_s: + if (unreachable_depth == 0) { + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_f32); + fprintf(out, "(int64_t)l%" PRIu32 ";\n", lhs); + } + break; + case WasmOpcode_f32_convert_i64_u: + if (unreachable_depth == 0) { + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_f32); + fprintf(out, "(uint64_t)l%" PRIu32 ";\n", lhs); + } + break; + case WasmOpcode_f32_demote_f64: + if (unreachable_depth == 0) { + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_f32); + fprintf(out, "(float)l%" PRIu32 ";\n", lhs); + } + break; + case WasmOpcode_f64_convert_i32_s: + if (unreachable_depth == 0) { + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_f64); + fprintf(out, "(int32_t)l%" PRIu32 ";\n", lhs); + } + break; + case WasmOpcode_f64_convert_i32_u: + if (unreachable_depth == 0) { + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_f64); + fprintf(out, "(uint32_t)l%" PRIu32 ";\n", lhs); + } + break; + case WasmOpcode_f64_convert_i64_s: + if (unreachable_depth == 0) { + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_f64); + fprintf(out, "(int64_t)l%" PRIu32 ";\n", lhs); + } + break; + case WasmOpcode_f64_convert_i64_u: + if (unreachable_depth == 0) { + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_f64); + fprintf(out, "(uint64_t)l%" PRIu32 ";\n", lhs); + } + break; + case WasmOpcode_f64_promote_f32: + if (unreachable_depth == 0) { + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_f64); + fprintf(out, "(double)l%" PRIu32 ";\n", lhs); + } + break; + case WasmOpcode_i32_reinterpret_f32: + if (unreachable_depth == 0) { + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i32); + fprintf(out, "i32_reinterpret_f32(l%" PRIu32 ");\n", lhs); + } + break; + case WasmOpcode_i64_reinterpret_f64: + if (unreachable_depth == 0) { + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i64); + fprintf(out, "i64_reinterpret_f64(l%" PRIu32 ");\n", lhs); + } + break; + case WasmOpcode_f32_reinterpret_i32: + if (unreachable_depth == 0) { + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_f32); + fprintf(out, "f32_reinterpret_i32(l%" PRIu32 ");\n", lhs); + } + break; + case WasmOpcode_f64_reinterpret_i64: + if (unreachable_depth == 0) { + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_f64); + fprintf(out, "f64_reinterpret_i64(l%" PRIu32 ");\n", lhs); + } + break; + + case WasmOpcode_i32_extend8_s: + if (unreachable_depth == 0) { + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i32); + fprintf(out, "(int8_t)l%" PRIu32 ";\n", lhs); + } + break; + case WasmOpcode_i32_extend16_s: + if (unreachable_depth == 0) { + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i32); + fprintf(out, "(int16_t)l%" PRIu32 ";\n", lhs); + } + break; + case WasmOpcode_i64_extend8_s: + if (unreachable_depth == 0) { + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i64); + fprintf(out, "(int8_t)l%" PRIu32 ";\n", lhs); + } + break; + case WasmOpcode_i64_extend16_s: + if (unreachable_depth == 0) { + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i64); + fprintf(out, "(int16_t)l%" PRIu32 ";\n", lhs); + } + break; + case WasmOpcode_i64_extend32_s: + if (unreachable_depth == 0) { + uint32_t lhs = FuncGen_stackPop(&fg); + FuncGen_stackPush(&fg, out, WasmValType_i64); + fprintf(out, "(int32_t)l%" PRIu32 ";\n", lhs); + } + break; + + case WasmOpcode_prefixed: + switch (InputStream_readLeb128_u32(&in)) { + case WasmPrefixedOpcode_i32_trunc_sat_f32_s: + case WasmPrefixedOpcode_i32_trunc_sat_f32_u: + case WasmPrefixedOpcode_i32_trunc_sat_f64_s: + case WasmPrefixedOpcode_i32_trunc_sat_f64_u: + case WasmPrefixedOpcode_i64_trunc_sat_f32_s: + case WasmPrefixedOpcode_i64_trunc_sat_f32_u: + case WasmPrefixedOpcode_i64_trunc_sat_f64_s: + case WasmPrefixedOpcode_i64_trunc_sat_f64_u: + if (unreachable_depth == 0) panic("unimplemented opcode"); + + case WasmPrefixedOpcode_memory_init: + (void)InputStream_readLeb128_u32(&in); + (void)InputStream_readByte(&in); + if (unreachable_depth == 0) panic("unimplemented opcode"); + + case WasmPrefixedOpcode_data_drop: + (void)InputStream_readLeb128_u32(&in); + if (unreachable_depth == 0) panic("unimplemented opcode"); + + case WasmPrefixedOpcode_memory_copy: { + uint32_t dst_mem_idx = InputStream_readLeb128_u32(&in); + uint32_t src_mem_idx = InputStream_readLeb128_u32(&in); + if (unreachable_depth == 0) { + uint32_t n = FuncGen_stackPop(&fg); + uint32_t src = FuncGen_stackPop(&fg); + uint32_t dst = FuncGen_stackPop(&fg); + FuncGen_indent(&fg, out); + fprintf(out, "memmove(&m%" PRIu32 "[l%" PRIu32 "], " + "&m%" PRIu32 "[l%" PRIu32 "], l%" PRIu32 ");\n", + dst_mem_idx, dst, src_mem_idx, src, n); + } + break; + } + + case WasmPrefixedOpcode_memory_fill: { + uint32_t mem_idx = InputStream_readLeb128_u32(&in); + if (unreachable_depth == 0) { + uint32_t n = FuncGen_stackPop(&fg); + uint32_t c = FuncGen_stackPop(&fg); + uint32_t s = FuncGen_stackPop(&fg); + FuncGen_indent(&fg, out); + fprintf(out, "memset(&m%" PRIu32 "[l%" PRIu32 "], " + "l%" PRIu32 ", l%" PRIu32 ");\n", mem_idx, s, c, n); + } + break; + } + + case WasmPrefixedOpcode_table_init: + (void)InputStream_readLeb128_u32(&in); + (void)InputStream_readLeb128_u32(&in); + if (unreachable_depth == 0) panic("unimplemented opcode"); + + case WasmPrefixedOpcode_elem_drop: + (void)InputStream_readLeb128_u32(&in); + if (unreachable_depth == 0) panic("unimplemented opcode"); + + case WasmPrefixedOpcode_table_copy: + (void)InputStream_readLeb128_u32(&in); + (void)InputStream_readLeb128_u32(&in); + if (unreachable_depth == 0) panic("unimplemented opcode"); + + case WasmPrefixedOpcode_table_grow: + (void)InputStream_readLeb128_u32(&in); + if (unreachable_depth == 0) panic("unimplemented opcode"); + + case WasmPrefixedOpcode_table_size: + (void)InputStream_readLeb128_u32(&in); + if (unreachable_depth == 0) panic("unimplemented opcode"); + + case WasmPrefixedOpcode_table_fill: + (void)InputStream_readLeb128_u32(&in); + if (unreachable_depth == 0) panic("unimplemented opcode"); + } + break; + } + } + for (uint32_t param_i = 0; param_i < func_type->param->len; param_i += 1) { + if (param_used[param_i]) continue; + FuncGen_indent(&fg, out); + fprintf(out, "(void)l%" PRIu32 ";\n", param_i); + } + switch (func_type->result->len) { + case 0: break; + case 1: + FuncGen_indent(&fg, out); + fprintf(out, "return l%" PRIu32 ";\n", FuncGen_stackPop(&fg)); + break; + default: panic("multiple function returns not supported"); + } + fputs("}\n\n", out); + } + } + + (void)InputStream_skipToSection(&in, WasmSectionId_data); + { + uint32_t len = InputStream_readLeb128_u32(&in); + fputs("static void init_data(void) {\n", out); + for (uint32_t i = 0; i < mems_len; i += 1) + fprintf(out, " p%" PRIu32 " = UINT32_C(%" PRIu32 ");\n" + " c%" PRIu32 " = p%" PRIu32 ";\n" + " m%" PRIu32 " = calloc(c%" PRIu32 ", UINT32_C(1) << 16);\n", + i, mems[i].limits.min, i, i, i, i); + for (uint32_t segment_i = 0; segment_i < len; segment_i += 1) { + uint32_t mem_idx; + switch (InputStream_readLeb128_u32(&in)) { + case 0: + mem_idx = 0; + break; + + case 2: + mem_idx = InputStream_readLeb128_u32(&in); + break; + + default: panic("unsupported data kind"); + } + uint32_t offset = evalExpr(&in); + uint32_t segment_len = InputStream_readLeb128_u32(&in); + fputc('\n', out); + fprintf(out, " static const uint8_t s%" PRIu32 "[UINT32_C(%" PRIu32 ")] = {", + segment_i, segment_len); + for (uint32_t i = 0; i < segment_len; i += 1) { + if (i % 32 == 0) fputs("\n ", out); + fprintf(out, " 0x%02hhX,", InputStream_readByte(&in)); + } + fprintf(out, "\n" + " };\n" + " memcpy(&m%" PRIu32 "[UINT32_C(0x%" PRIX32 ")], s%" PRIu32 ", UINT32_C(%" PRIu32 "));\n", + mem_idx, offset, segment_i, segment_len); + } + fputs("}\n", out); + } + + InputStream_close(&in); + fclose(out); +} diff --git a/stage1/zig1.wasm.zst b/stage1/zig1.wasm.zst new file mode 100644 index 000000000000..624745f3acd8 Binary files /dev/null and b/stage1/zig1.wasm.zst differ diff --git a/stage1/zstd/LICENSE b/stage1/zstd/LICENSE new file mode 100644 index 000000000000..a793a8028925 --- /dev/null +++ b/stage1/zstd/LICENSE @@ -0,0 +1,30 @@ +BSD License + +For Zstandard software + +Copyright (c) 2016-present, Facebook, Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + * Neither the name Facebook nor the names of its contributors may be used to + endorse or promote products derived from this software without specific + prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/stage1/zstd/lib/common/bitstream.h b/stage1/zstd/lib/common/bitstream.h new file mode 100644 index 000000000000..84b6062ff350 --- /dev/null +++ b/stage1/zstd/lib/common/bitstream.h @@ -0,0 +1,478 @@ +/* ****************************************************************** + * bitstream + * Part of FSE library + * Copyright (c) Yann Collet, Facebook, Inc. + * + * You can contact the author at : + * - Source repository : https://github.com/Cyan4973/FiniteStateEntropy + * + * This source code is licensed under both the BSD-style license (found in the + * LICENSE file in the root directory of this source tree) and the GPLv2 (found + * in the COPYING file in the root directory of this source tree). + * You may select, at your option, one of the above-listed licenses. +****************************************************************** */ +#ifndef BITSTREAM_H_MODULE +#define BITSTREAM_H_MODULE + +#if defined (__cplusplus) +extern "C" { +#endif +/* +* This API consists of small unitary functions, which must be inlined for best performance. +* Since link-time-optimization is not available for all compilers, +* these functions are defined into a .h to be included. +*/ + +/*-**************************************** +* Dependencies +******************************************/ +#include "mem.h" /* unaligned access routines */ +#include "compiler.h" /* UNLIKELY() */ +#include "debug.h" /* assert(), DEBUGLOG(), RAWLOG() */ +#include "error_private.h" /* error codes and messages */ + + +/*========================================= +* Target specific +=========================================*/ +#ifndef ZSTD_NO_INTRINSICS +# if defined(__BMI__) && defined(__GNUC__) +# include /* support for bextr (experimental) */ +# elif defined(__ICCARM__) +# include +# endif +#endif + +#define STREAM_ACCUMULATOR_MIN_32 25 +#define STREAM_ACCUMULATOR_MIN_64 57 +#define STREAM_ACCUMULATOR_MIN ((U32)(MEM_32bits() ? STREAM_ACCUMULATOR_MIN_32 : STREAM_ACCUMULATOR_MIN_64)) + + +/*-****************************************** +* bitStream encoding API (write forward) +********************************************/ +/* bitStream can mix input from multiple sources. + * A critical property of these streams is that they encode and decode in **reverse** direction. + * So the first bit sequence you add will be the last to be read, like a LIFO stack. + */ +typedef struct { + size_t bitContainer; + unsigned bitPos; + char* startPtr; + char* ptr; + char* endPtr; +} BIT_CStream_t; + +MEM_STATIC size_t BIT_initCStream(BIT_CStream_t* bitC, void* dstBuffer, size_t dstCapacity); +MEM_STATIC void BIT_addBits(BIT_CStream_t* bitC, size_t value, unsigned nbBits); +MEM_STATIC void BIT_flushBits(BIT_CStream_t* bitC); +MEM_STATIC size_t BIT_closeCStream(BIT_CStream_t* bitC); + +/* Start with initCStream, providing the size of buffer to write into. +* bitStream will never write outside of this buffer. +* `dstCapacity` must be >= sizeof(bitD->bitContainer), otherwise @return will be an error code. +* +* bits are first added to a local register. +* Local register is size_t, hence 64-bits on 64-bits systems, or 32-bits on 32-bits systems. +* Writing data into memory is an explicit operation, performed by the flushBits function. +* Hence keep track how many bits are potentially stored into local register to avoid register overflow. +* After a flushBits, a maximum of 7 bits might still be stored into local register. +* +* Avoid storing elements of more than 24 bits if you want compatibility with 32-bits bitstream readers. +* +* Last operation is to close the bitStream. +* The function returns the final size of CStream in bytes. +* If data couldn't fit into `dstBuffer`, it will return a 0 ( == not storable) +*/ + + +/*-******************************************** +* bitStream decoding API (read backward) +**********************************************/ +typedef struct { + size_t bitContainer; + unsigned bitsConsumed; + const char* ptr; + const char* start; + const char* limitPtr; +} BIT_DStream_t; + +typedef enum { BIT_DStream_unfinished = 0, + BIT_DStream_endOfBuffer = 1, + BIT_DStream_completed = 2, + BIT_DStream_overflow = 3 } BIT_DStream_status; /* result of BIT_reloadDStream() */ + /* 1,2,4,8 would be better for bitmap combinations, but slows down performance a bit ... :( */ + +MEM_STATIC size_t BIT_initDStream(BIT_DStream_t* bitD, const void* srcBuffer, size_t srcSize); +MEM_STATIC size_t BIT_readBits(BIT_DStream_t* bitD, unsigned nbBits); +MEM_STATIC BIT_DStream_status BIT_reloadDStream(BIT_DStream_t* bitD); +MEM_STATIC unsigned BIT_endOfDStream(const BIT_DStream_t* bitD); + + +/* Start by invoking BIT_initDStream(). +* A chunk of the bitStream is then stored into a local register. +* Local register size is 64-bits on 64-bits systems, 32-bits on 32-bits systems (size_t). +* You can then retrieve bitFields stored into the local register, **in reverse order**. +* Local register is explicitly reloaded from memory by the BIT_reloadDStream() method. +* A reload guarantee a minimum of ((8*sizeof(bitD->bitContainer))-7) bits when its result is BIT_DStream_unfinished. +* Otherwise, it can be less than that, so proceed accordingly. +* Checking if DStream has reached its end can be performed with BIT_endOfDStream(). +*/ + + +/*-**************************************** +* unsafe API +******************************************/ +MEM_STATIC void BIT_addBitsFast(BIT_CStream_t* bitC, size_t value, unsigned nbBits); +/* faster, but works only if value is "clean", meaning all high bits above nbBits are 0 */ + +MEM_STATIC void BIT_flushBitsFast(BIT_CStream_t* bitC); +/* unsafe version; does not check buffer overflow */ + +MEM_STATIC size_t BIT_readBitsFast(BIT_DStream_t* bitD, unsigned nbBits); +/* faster, but works only if nbBits >= 1 */ + + + +/*-************************************************************** +* Internal functions +****************************************************************/ +MEM_STATIC unsigned BIT_highbit32 (U32 val) +{ + assert(val != 0); + { +# if defined(_MSC_VER) /* Visual */ +# if STATIC_BMI2 == 1 + return _lzcnt_u32(val) ^ 31; +# else + if (val != 0) { + unsigned long r; + _BitScanReverse(&r, val); + return (unsigned)r; + } else { + /* Should not reach this code path */ + __assume(0); + } +# endif +# elif defined(__GNUC__) && (__GNUC__ >= 3) /* Use GCC Intrinsic */ + return __builtin_clz (val) ^ 31; +# elif defined(__ICCARM__) /* IAR Intrinsic */ + return 31 - __CLZ(val); +# else /* Software version */ + static const unsigned DeBruijnClz[32] = { 0, 9, 1, 10, 13, 21, 2, 29, + 11, 14, 16, 18, 22, 25, 3, 30, + 8, 12, 20, 28, 15, 17, 24, 7, + 19, 27, 23, 6, 26, 5, 4, 31 }; + U32 v = val; + v |= v >> 1; + v |= v >> 2; + v |= v >> 4; + v |= v >> 8; + v |= v >> 16; + return DeBruijnClz[ (U32) (v * 0x07C4ACDDU) >> 27]; +# endif + } +} + +/*===== Local Constants =====*/ +static const unsigned BIT_mask[] = { + 0, 1, 3, 7, 0xF, 0x1F, + 0x3F, 0x7F, 0xFF, 0x1FF, 0x3FF, 0x7FF, + 0xFFF, 0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF, 0x1FFFF, + 0x3FFFF, 0x7FFFF, 0xFFFFF, 0x1FFFFF, 0x3FFFFF, 0x7FFFFF, + 0xFFFFFF, 0x1FFFFFF, 0x3FFFFFF, 0x7FFFFFF, 0xFFFFFFF, 0x1FFFFFFF, + 0x3FFFFFFF, 0x7FFFFFFF}; /* up to 31 bits */ +#define BIT_MASK_SIZE (sizeof(BIT_mask) / sizeof(BIT_mask[0])) + +/*-************************************************************** +* bitStream encoding +****************************************************************/ +/*! BIT_initCStream() : + * `dstCapacity` must be > sizeof(size_t) + * @return : 0 if success, + * otherwise an error code (can be tested using ERR_isError()) */ +MEM_STATIC size_t BIT_initCStream(BIT_CStream_t* bitC, + void* startPtr, size_t dstCapacity) +{ + bitC->bitContainer = 0; + bitC->bitPos = 0; + bitC->startPtr = (char*)startPtr; + bitC->ptr = bitC->startPtr; + bitC->endPtr = bitC->startPtr + dstCapacity - sizeof(bitC->bitContainer); + if (dstCapacity <= sizeof(bitC->bitContainer)) return ERROR(dstSize_tooSmall); + return 0; +} + +/*! BIT_addBits() : + * can add up to 31 bits into `bitC`. + * Note : does not check for register overflow ! */ +MEM_STATIC void BIT_addBits(BIT_CStream_t* bitC, + size_t value, unsigned nbBits) +{ + DEBUG_STATIC_ASSERT(BIT_MASK_SIZE == 32); + assert(nbBits < BIT_MASK_SIZE); + assert(nbBits + bitC->bitPos < sizeof(bitC->bitContainer) * 8); + bitC->bitContainer |= (value & BIT_mask[nbBits]) << bitC->bitPos; + bitC->bitPos += nbBits; +} + +/*! BIT_addBitsFast() : + * works only if `value` is _clean_, + * meaning all high bits above nbBits are 0 */ +MEM_STATIC void BIT_addBitsFast(BIT_CStream_t* bitC, + size_t value, unsigned nbBits) +{ + assert((value>>nbBits) == 0); + assert(nbBits + bitC->bitPos < sizeof(bitC->bitContainer) * 8); + bitC->bitContainer |= value << bitC->bitPos; + bitC->bitPos += nbBits; +} + +/*! BIT_flushBitsFast() : + * assumption : bitContainer has not overflowed + * unsafe version; does not check buffer overflow */ +MEM_STATIC void BIT_flushBitsFast(BIT_CStream_t* bitC) +{ + size_t const nbBytes = bitC->bitPos >> 3; + assert(bitC->bitPos < sizeof(bitC->bitContainer) * 8); + assert(bitC->ptr <= bitC->endPtr); + MEM_writeLEST(bitC->ptr, bitC->bitContainer); + bitC->ptr += nbBytes; + bitC->bitPos &= 7; + bitC->bitContainer >>= nbBytes*8; +} + +/*! BIT_flushBits() : + * assumption : bitContainer has not overflowed + * safe version; check for buffer overflow, and prevents it. + * note : does not signal buffer overflow. + * overflow will be revealed later on using BIT_closeCStream() */ +MEM_STATIC void BIT_flushBits(BIT_CStream_t* bitC) +{ + size_t const nbBytes = bitC->bitPos >> 3; + assert(bitC->bitPos < sizeof(bitC->bitContainer) * 8); + assert(bitC->ptr <= bitC->endPtr); + MEM_writeLEST(bitC->ptr, bitC->bitContainer); + bitC->ptr += nbBytes; + if (bitC->ptr > bitC->endPtr) bitC->ptr = bitC->endPtr; + bitC->bitPos &= 7; + bitC->bitContainer >>= nbBytes*8; +} + +/*! BIT_closeCStream() : + * @return : size of CStream, in bytes, + * or 0 if it could not fit into dstBuffer */ +MEM_STATIC size_t BIT_closeCStream(BIT_CStream_t* bitC) +{ + BIT_addBitsFast(bitC, 1, 1); /* endMark */ + BIT_flushBits(bitC); + if (bitC->ptr >= bitC->endPtr) return 0; /* overflow detected */ + return (bitC->ptr - bitC->startPtr) + (bitC->bitPos > 0); +} + + +/*-******************************************************** +* bitStream decoding +**********************************************************/ +/*! BIT_initDStream() : + * Initialize a BIT_DStream_t. + * `bitD` : a pointer to an already allocated BIT_DStream_t structure. + * `srcSize` must be the *exact* size of the bitStream, in bytes. + * @return : size of stream (== srcSize), or an errorCode if a problem is detected + */ +MEM_STATIC size_t BIT_initDStream(BIT_DStream_t* bitD, const void* srcBuffer, size_t srcSize) +{ + if (srcSize < 1) { ZSTD_memset(bitD, 0, sizeof(*bitD)); return ERROR(srcSize_wrong); } + + bitD->start = (const char*)srcBuffer; + bitD->limitPtr = bitD->start + sizeof(bitD->bitContainer); + + if (srcSize >= sizeof(bitD->bitContainer)) { /* normal case */ + bitD->ptr = (const char*)srcBuffer + srcSize - sizeof(bitD->bitContainer); + bitD->bitContainer = MEM_readLEST(bitD->ptr); + { BYTE const lastByte = ((const BYTE*)srcBuffer)[srcSize-1]; + bitD->bitsConsumed = lastByte ? 8 - BIT_highbit32(lastByte) : 0; /* ensures bitsConsumed is always set */ + if (lastByte == 0) return ERROR(GENERIC); /* endMark not present */ } + } else { + bitD->ptr = bitD->start; + bitD->bitContainer = *(const BYTE*)(bitD->start); + switch(srcSize) + { + case 7: bitD->bitContainer += (size_t)(((const BYTE*)(srcBuffer))[6]) << (sizeof(bitD->bitContainer)*8 - 16); + ZSTD_FALLTHROUGH; + + case 6: bitD->bitContainer += (size_t)(((const BYTE*)(srcBuffer))[5]) << (sizeof(bitD->bitContainer)*8 - 24); + ZSTD_FALLTHROUGH; + + case 5: bitD->bitContainer += (size_t)(((const BYTE*)(srcBuffer))[4]) << (sizeof(bitD->bitContainer)*8 - 32); + ZSTD_FALLTHROUGH; + + case 4: bitD->bitContainer += (size_t)(((const BYTE*)(srcBuffer))[3]) << 24; + ZSTD_FALLTHROUGH; + + case 3: bitD->bitContainer += (size_t)(((const BYTE*)(srcBuffer))[2]) << 16; + ZSTD_FALLTHROUGH; + + case 2: bitD->bitContainer += (size_t)(((const BYTE*)(srcBuffer))[1]) << 8; + ZSTD_FALLTHROUGH; + + default: break; + } + { BYTE const lastByte = ((const BYTE*)srcBuffer)[srcSize-1]; + bitD->bitsConsumed = lastByte ? 8 - BIT_highbit32(lastByte) : 0; + if (lastByte == 0) return ERROR(corruption_detected); /* endMark not present */ + } + bitD->bitsConsumed += (U32)(sizeof(bitD->bitContainer) - srcSize)*8; + } + + return srcSize; +} + +MEM_STATIC FORCE_INLINE_ATTR size_t BIT_getUpperBits(size_t bitContainer, U32 const start) +{ + return bitContainer >> start; +} + +MEM_STATIC FORCE_INLINE_ATTR size_t BIT_getMiddleBits(size_t bitContainer, U32 const start, U32 const nbBits) +{ + U32 const regMask = sizeof(bitContainer)*8 - 1; + /* if start > regMask, bitstream is corrupted, and result is undefined */ + assert(nbBits < BIT_MASK_SIZE); + /* x86 transform & ((1 << nbBits) - 1) to bzhi instruction, it is better + * than accessing memory. When bmi2 instruction is not present, we consider + * such cpus old (pre-Haswell, 2013) and their performance is not of that + * importance. + */ +#if defined(__x86_64__) || defined(_M_X86) + return (bitContainer >> (start & regMask)) & ((((U64)1) << nbBits) - 1); +#else + return (bitContainer >> (start & regMask)) & BIT_mask[nbBits]; +#endif +} + +MEM_STATIC FORCE_INLINE_ATTR size_t BIT_getLowerBits(size_t bitContainer, U32 const nbBits) +{ +#if defined(STATIC_BMI2) && STATIC_BMI2 == 1 + return _bzhi_u64(bitContainer, nbBits); +#else + assert(nbBits < BIT_MASK_SIZE); + return bitContainer & BIT_mask[nbBits]; +#endif +} + +/*! BIT_lookBits() : + * Provides next n bits from local register. + * local register is not modified. + * On 32-bits, maxNbBits==24. + * On 64-bits, maxNbBits==56. + * @return : value extracted */ +MEM_STATIC FORCE_INLINE_ATTR size_t BIT_lookBits(const BIT_DStream_t* bitD, U32 nbBits) +{ + /* arbitrate between double-shift and shift+mask */ +#if 1 + /* if bitD->bitsConsumed + nbBits > sizeof(bitD->bitContainer)*8, + * bitstream is likely corrupted, and result is undefined */ + return BIT_getMiddleBits(bitD->bitContainer, (sizeof(bitD->bitContainer)*8) - bitD->bitsConsumed - nbBits, nbBits); +#else + /* this code path is slower on my os-x laptop */ + U32 const regMask = sizeof(bitD->bitContainer)*8 - 1; + return ((bitD->bitContainer << (bitD->bitsConsumed & regMask)) >> 1) >> ((regMask-nbBits) & regMask); +#endif +} + +/*! BIT_lookBitsFast() : + * unsafe version; only works if nbBits >= 1 */ +MEM_STATIC size_t BIT_lookBitsFast(const BIT_DStream_t* bitD, U32 nbBits) +{ + U32 const regMask = sizeof(bitD->bitContainer)*8 - 1; + assert(nbBits >= 1); + return (bitD->bitContainer << (bitD->bitsConsumed & regMask)) >> (((regMask+1)-nbBits) & regMask); +} + +MEM_STATIC FORCE_INLINE_ATTR void BIT_skipBits(BIT_DStream_t* bitD, U32 nbBits) +{ + bitD->bitsConsumed += nbBits; +} + +/*! BIT_readBits() : + * Read (consume) next n bits from local register and update. + * Pay attention to not read more than nbBits contained into local register. + * @return : extracted value. */ +MEM_STATIC FORCE_INLINE_ATTR size_t BIT_readBits(BIT_DStream_t* bitD, unsigned nbBits) +{ + size_t const value = BIT_lookBits(bitD, nbBits); + BIT_skipBits(bitD, nbBits); + return value; +} + +/*! BIT_readBitsFast() : + * unsafe version; only works only if nbBits >= 1 */ +MEM_STATIC size_t BIT_readBitsFast(BIT_DStream_t* bitD, unsigned nbBits) +{ + size_t const value = BIT_lookBitsFast(bitD, nbBits); + assert(nbBits >= 1); + BIT_skipBits(bitD, nbBits); + return value; +} + +/*! BIT_reloadDStreamFast() : + * Similar to BIT_reloadDStream(), but with two differences: + * 1. bitsConsumed <= sizeof(bitD->bitContainer)*8 must hold! + * 2. Returns BIT_DStream_overflow when bitD->ptr < bitD->limitPtr, at this + * point you must use BIT_reloadDStream() to reload. + */ +MEM_STATIC BIT_DStream_status BIT_reloadDStreamFast(BIT_DStream_t* bitD) +{ + if (UNLIKELY(bitD->ptr < bitD->limitPtr)) + return BIT_DStream_overflow; + assert(bitD->bitsConsumed <= sizeof(bitD->bitContainer)*8); + bitD->ptr -= bitD->bitsConsumed >> 3; + bitD->bitsConsumed &= 7; + bitD->bitContainer = MEM_readLEST(bitD->ptr); + return BIT_DStream_unfinished; +} + +/*! BIT_reloadDStream() : + * Refill `bitD` from buffer previously set in BIT_initDStream() . + * This function is safe, it guarantees it will not read beyond src buffer. + * @return : status of `BIT_DStream_t` internal register. + * when status == BIT_DStream_unfinished, internal register is filled with at least 25 or 57 bits */ +MEM_STATIC BIT_DStream_status BIT_reloadDStream(BIT_DStream_t* bitD) +{ + if (bitD->bitsConsumed > (sizeof(bitD->bitContainer)*8)) /* overflow detected, like end of stream */ + return BIT_DStream_overflow; + + if (bitD->ptr >= bitD->limitPtr) { + return BIT_reloadDStreamFast(bitD); + } + if (bitD->ptr == bitD->start) { + if (bitD->bitsConsumed < sizeof(bitD->bitContainer)*8) return BIT_DStream_endOfBuffer; + return BIT_DStream_completed; + } + /* start < ptr < limitPtr */ + { U32 nbBytes = bitD->bitsConsumed >> 3; + BIT_DStream_status result = BIT_DStream_unfinished; + if (bitD->ptr - nbBytes < bitD->start) { + nbBytes = (U32)(bitD->ptr - bitD->start); /* ptr > start */ + result = BIT_DStream_endOfBuffer; + } + bitD->ptr -= nbBytes; + bitD->bitsConsumed -= nbBytes*8; + bitD->bitContainer = MEM_readLEST(bitD->ptr); /* reminder : srcSize > sizeof(bitD->bitContainer), otherwise bitD->ptr == bitD->start */ + return result; + } +} + +/*! BIT_endOfDStream() : + * @return : 1 if DStream has _exactly_ reached its end (all bits consumed). + */ +MEM_STATIC unsigned BIT_endOfDStream(const BIT_DStream_t* DStream) +{ + return ((DStream->ptr == DStream->start) && (DStream->bitsConsumed == sizeof(DStream->bitContainer)*8)); +} + +#if defined (__cplusplus) +} +#endif + +#endif /* BITSTREAM_H_MODULE */ diff --git a/stage1/zstd/lib/common/compiler.h b/stage1/zstd/lib/common/compiler.h new file mode 100644 index 000000000000..516930c01ec9 --- /dev/null +++ b/stage1/zstd/lib/common/compiler.h @@ -0,0 +1,335 @@ +/* + * Copyright (c) Yann Collet, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under both the BSD-style license (found in the + * LICENSE file in the root directory of this source tree) and the GPLv2 (found + * in the COPYING file in the root directory of this source tree). + * You may select, at your option, one of the above-listed licenses. + */ + +#ifndef ZSTD_COMPILER_H +#define ZSTD_COMPILER_H + +#include "portability_macros.h" + +/*-******************************************************* +* Compiler specifics +*********************************************************/ +/* force inlining */ + +#if !defined(ZSTD_NO_INLINE) +#if (defined(__GNUC__) && !defined(__STRICT_ANSI__)) || defined(__cplusplus) || defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L /* C99 */ +# define INLINE_KEYWORD inline +#else +# define INLINE_KEYWORD +#endif + +#if defined(__GNUC__) || defined(__ICCARM__) +# define FORCE_INLINE_ATTR __attribute__((always_inline)) +#elif defined(_MSC_VER) +# define FORCE_INLINE_ATTR __forceinline +#else +# define FORCE_INLINE_ATTR +#endif + +#else + +#define INLINE_KEYWORD +#define FORCE_INLINE_ATTR + +#endif + +/** + On MSVC qsort requires that functions passed into it use the __cdecl calling conversion(CC). + This explicitly marks such functions as __cdecl so that the code will still compile + if a CC other than __cdecl has been made the default. +*/ +#if defined(_MSC_VER) +# define WIN_CDECL __cdecl +#else +# define WIN_CDECL +#endif + +/** + * FORCE_INLINE_TEMPLATE is used to define C "templates", which take constant + * parameters. They must be inlined for the compiler to eliminate the constant + * branches. + */ +#define FORCE_INLINE_TEMPLATE static INLINE_KEYWORD FORCE_INLINE_ATTR +/** + * HINT_INLINE is used to help the compiler generate better code. It is *not* + * used for "templates", so it can be tweaked based on the compilers + * performance. + * + * gcc-4.8 and gcc-4.9 have been shown to benefit from leaving off the + * always_inline attribute. + * + * clang up to 5.0.0 (trunk) benefit tremendously from the always_inline + * attribute. + */ +#if !defined(__clang__) && defined(__GNUC__) && __GNUC__ >= 4 && __GNUC_MINOR__ >= 8 && __GNUC__ < 5 +# define HINT_INLINE static INLINE_KEYWORD +#else +# define HINT_INLINE static INLINE_KEYWORD FORCE_INLINE_ATTR +#endif + +/* UNUSED_ATTR tells the compiler it is okay if the function is unused. */ +#if defined(__GNUC__) +# define UNUSED_ATTR __attribute__((unused)) +#else +# define UNUSED_ATTR +#endif + +/* force no inlining */ +#ifdef _MSC_VER +# define FORCE_NOINLINE static __declspec(noinline) +#else +# if defined(__GNUC__) || defined(__ICCARM__) +# define FORCE_NOINLINE static __attribute__((__noinline__)) +# else +# define FORCE_NOINLINE static +# endif +#endif + + +/* target attribute */ +#if defined(__GNUC__) || defined(__ICCARM__) +# define TARGET_ATTRIBUTE(target) __attribute__((__target__(target))) +#else +# define TARGET_ATTRIBUTE(target) +#endif + +/* Target attribute for BMI2 dynamic dispatch. + * Enable lzcnt, bmi, and bmi2. + * We test for bmi1 & bmi2. lzcnt is included in bmi1. + */ +#define BMI2_TARGET_ATTRIBUTE TARGET_ATTRIBUTE("lzcnt,bmi,bmi2") + +/* prefetch + * can be disabled, by declaring NO_PREFETCH build macro */ +#if defined(NO_PREFETCH) +# define PREFETCH_L1(ptr) (void)(ptr) /* disabled */ +# define PREFETCH_L2(ptr) (void)(ptr) /* disabled */ +#else +# if defined(_MSC_VER) && (defined(_M_X64) || defined(_M_I86)) /* _mm_prefetch() is not defined outside of x86/x64 */ +# include /* https://msdn.microsoft.com/fr-fr/library/84szxsww(v=vs.90).aspx */ +# define PREFETCH_L1(ptr) _mm_prefetch((const char*)(ptr), _MM_HINT_T0) +# define PREFETCH_L2(ptr) _mm_prefetch((const char*)(ptr), _MM_HINT_T1) +# elif defined(__GNUC__) && ( (__GNUC__ >= 4) || ( (__GNUC__ == 3) && (__GNUC_MINOR__ >= 1) ) ) +# define PREFETCH_L1(ptr) __builtin_prefetch((ptr), 0 /* rw==read */, 3 /* locality */) +# define PREFETCH_L2(ptr) __builtin_prefetch((ptr), 0 /* rw==read */, 2 /* locality */) +# elif defined(__aarch64__) +# define PREFETCH_L1(ptr) __asm__ __volatile__("prfm pldl1keep, %0" ::"Q"(*(ptr))) +# define PREFETCH_L2(ptr) __asm__ __volatile__("prfm pldl2keep, %0" ::"Q"(*(ptr))) +# else +# define PREFETCH_L1(ptr) (void)(ptr) /* disabled */ +# define PREFETCH_L2(ptr) (void)(ptr) /* disabled */ +# endif +#endif /* NO_PREFETCH */ + +#define CACHELINE_SIZE 64 + +#define PREFETCH_AREA(p, s) { \ + const char* const _ptr = (const char*)(p); \ + size_t const _size = (size_t)(s); \ + size_t _pos; \ + for (_pos=0; _pos<_size; _pos+=CACHELINE_SIZE) { \ + PREFETCH_L2(_ptr + _pos); \ + } \ +} + +/* vectorization + * older GCC (pre gcc-4.3 picked as the cutoff) uses a different syntax, + * and some compilers, like Intel ICC and MCST LCC, do not support it at all. */ +#if !defined(__INTEL_COMPILER) && !defined(__clang__) && defined(__GNUC__) && !defined(__LCC__) +# if (__GNUC__ == 4 && __GNUC_MINOR__ > 3) || (__GNUC__ >= 5) +# define DONT_VECTORIZE __attribute__((optimize("no-tree-vectorize"))) +# else +# define DONT_VECTORIZE _Pragma("GCC optimize(\"no-tree-vectorize\")") +# endif +#else +# define DONT_VECTORIZE +#endif + +/* Tell the compiler that a branch is likely or unlikely. + * Only use these macros if it causes the compiler to generate better code. + * If you can remove a LIKELY/UNLIKELY annotation without speed changes in gcc + * and clang, please do. + */ +#if defined(__GNUC__) +#define LIKELY(x) (__builtin_expect((x), 1)) +#define UNLIKELY(x) (__builtin_expect((x), 0)) +#else +#define LIKELY(x) (x) +#define UNLIKELY(x) (x) +#endif + +/* disable warnings */ +#ifdef _MSC_VER /* Visual Studio */ +# include /* For Visual 2005 */ +# pragma warning(disable : 4100) /* disable: C4100: unreferenced formal parameter */ +# pragma warning(disable : 4127) /* disable: C4127: conditional expression is constant */ +# pragma warning(disable : 4204) /* disable: C4204: non-constant aggregate initializer */ +# pragma warning(disable : 4214) /* disable: C4214: non-int bitfields */ +# pragma warning(disable : 4324) /* disable: C4324: padded structure */ +#endif + +/*Like DYNAMIC_BMI2 but for compile time determination of BMI2 support*/ +#ifndef STATIC_BMI2 +# if defined(_MSC_VER) && (defined(_M_X64) || defined(_M_I86)) +# ifdef __AVX2__ //MSVC does not have a BMI2 specific flag, but every CPU that supports AVX2 also supports BMI2 +# define STATIC_BMI2 1 +# endif +# endif +#endif + +#ifndef STATIC_BMI2 + #define STATIC_BMI2 0 +#endif + +/* compile time determination of SIMD support */ +#if !defined(ZSTD_NO_INTRINSICS) +# if defined(__SSE2__) || defined(_M_AMD64) || (defined (_M_IX86) && defined(_M_IX86_FP) && (_M_IX86_FP >= 2)) +# define ZSTD_ARCH_X86_SSE2 +# endif +# if defined(__ARM_NEON) || defined(_M_ARM64) +# define ZSTD_ARCH_ARM_NEON +# endif +# +# if defined(ZSTD_ARCH_X86_SSE2) +# include +# elif defined(ZSTD_ARCH_ARM_NEON) +# include +# endif +#endif + +/* C-language Attributes are added in C23. */ +#if defined(__STDC_VERSION__) && (__STDC_VERSION__ > 201710L) && defined(__has_c_attribute) +# define ZSTD_HAS_C_ATTRIBUTE(x) __has_c_attribute(x) +#else +# define ZSTD_HAS_C_ATTRIBUTE(x) 0 +#endif + +/* Only use C++ attributes in C++. Some compilers report support for C++ + * attributes when compiling with C. + */ +#if defined(__cplusplus) && defined(__has_cpp_attribute) +# define ZSTD_HAS_CPP_ATTRIBUTE(x) __has_cpp_attribute(x) +#else +# define ZSTD_HAS_CPP_ATTRIBUTE(x) 0 +#endif + +/* Define ZSTD_FALLTHROUGH macro for annotating switch case with the 'fallthrough' attribute. + * - C23: https://en.cppreference.com/w/c/language/attributes/fallthrough + * - CPP17: https://en.cppreference.com/w/cpp/language/attributes/fallthrough + * - Else: __attribute__((__fallthrough__)) + */ +#ifndef ZSTD_FALLTHROUGH +# if ZSTD_HAS_C_ATTRIBUTE(fallthrough) +# define ZSTD_FALLTHROUGH [[fallthrough]] +# elif ZSTD_HAS_CPP_ATTRIBUTE(fallthrough) +# define ZSTD_FALLTHROUGH [[fallthrough]] +# elif __has_attribute(__fallthrough__) +/* Leading semicolon is to satisfy gcc-11 with -pedantic. Without the semicolon + * gcc complains about: a label can only be part of a statement and a declaration is not a statement. + */ +# define ZSTD_FALLTHROUGH ; __attribute__((__fallthrough__)) +# else +# define ZSTD_FALLTHROUGH +# endif +#endif + +/*-************************************************************** +* Alignment check +*****************************************************************/ + +/* this test was initially positioned in mem.h, + * but this file is removed (or replaced) for linux kernel + * so it's now hosted in compiler.h, + * which remains valid for both user & kernel spaces. + */ + +#ifndef ZSTD_ALIGNOF +# if defined(__GNUC__) || defined(_MSC_VER) +/* covers gcc, clang & MSVC */ +/* note : this section must come first, before C11, + * due to a limitation in the kernel source generator */ +# define ZSTD_ALIGNOF(T) __alignof(T) + +# elif defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L) +/* C11 support */ +# include +# define ZSTD_ALIGNOF(T) alignof(T) + +# else +/* No known support for alignof() - imperfect backup */ +# define ZSTD_ALIGNOF(T) (sizeof(void*) < sizeof(T) ? sizeof(void*) : sizeof(T)) + +# endif +#endif /* ZSTD_ALIGNOF */ + +/*-************************************************************** +* Sanitizer +*****************************************************************/ + +#if ZSTD_MEMORY_SANITIZER +/* Not all platforms that support msan provide sanitizers/msan_interface.h. + * We therefore declare the functions we need ourselves, rather than trying to + * include the header file... */ +#include /* size_t */ +#define ZSTD_DEPS_NEED_STDINT +#include "zstd_deps.h" /* intptr_t */ + +/* Make memory region fully initialized (without changing its contents). */ +void __msan_unpoison(const volatile void *a, size_t size); + +/* Make memory region fully uninitialized (without changing its contents). + This is a legacy interface that does not update origin information. Use + __msan_allocated_memory() instead. */ +void __msan_poison(const volatile void *a, size_t size); + +/* Returns the offset of the first (at least partially) poisoned byte in the + memory range, or -1 if the whole range is good. */ +intptr_t __msan_test_shadow(const volatile void *x, size_t size); +#endif + +#if ZSTD_ADDRESS_SANITIZER +/* Not all platforms that support asan provide sanitizers/asan_interface.h. + * We therefore declare the functions we need ourselves, rather than trying to + * include the header file... */ +#include /* size_t */ + +/** + * Marks a memory region ([addr, addr+size)) as unaddressable. + * + * This memory must be previously allocated by your program. Instrumented + * code is forbidden from accessing addresses in this region until it is + * unpoisoned. This function is not guaranteed to poison the entire region - + * it could poison only a subregion of [addr, addr+size) due to ASan + * alignment restrictions. + * + * \note This function is not thread-safe because no two threads can poison or + * unpoison memory in the same memory region simultaneously. + * + * \param addr Start of memory region. + * \param size Size of memory region. */ +void __asan_poison_memory_region(void const volatile *addr, size_t size); + +/** + * Marks a memory region ([addr, addr+size)) as addressable. + * + * This memory must be previously allocated by your program. Accessing + * addresses in this region is allowed until this region is poisoned again. + * This function could unpoison a super-region of [addr, addr+size) due + * to ASan alignment restrictions. + * + * \note This function is not thread-safe because no two threads can + * poison or unpoison memory in the same memory region simultaneously. + * + * \param addr Start of memory region. + * \param size Size of memory region. */ +void __asan_unpoison_memory_region(void const volatile *addr, size_t size); +#endif + +#endif /* ZSTD_COMPILER_H */ diff --git a/stage1/zstd/lib/common/cpu.h b/stage1/zstd/lib/common/cpu.h new file mode 100644 index 000000000000..8acd33be3cd0 --- /dev/null +++ b/stage1/zstd/lib/common/cpu.h @@ -0,0 +1,213 @@ +/* + * Copyright (c) Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under both the BSD-style license (found in the + * LICENSE file in the root directory of this source tree) and the GPLv2 (found + * in the COPYING file in the root directory of this source tree). + * You may select, at your option, one of the above-listed licenses. + */ + +#ifndef ZSTD_COMMON_CPU_H +#define ZSTD_COMMON_CPU_H + +/** + * Implementation taken from folly/CpuId.h + * https://github.com/facebook/folly/blob/master/folly/CpuId.h + */ + +#include "mem.h" + +#ifdef _MSC_VER +#include +#endif + +typedef struct { + U32 f1c; + U32 f1d; + U32 f7b; + U32 f7c; +} ZSTD_cpuid_t; + +MEM_STATIC ZSTD_cpuid_t ZSTD_cpuid(void) { + U32 f1c = 0; + U32 f1d = 0; + U32 f7b = 0; + U32 f7c = 0; +#if defined(_MSC_VER) && (defined(_M_X64) || defined(_M_IX86)) + int reg[4]; + __cpuid((int*)reg, 0); + { + int const n = reg[0]; + if (n >= 1) { + __cpuid((int*)reg, 1); + f1c = (U32)reg[2]; + f1d = (U32)reg[3]; + } + if (n >= 7) { + __cpuidex((int*)reg, 7, 0); + f7b = (U32)reg[1]; + f7c = (U32)reg[2]; + } + } +#elif defined(__i386__) && defined(__PIC__) && !defined(__clang__) && defined(__GNUC__) + /* The following block like the normal cpuid branch below, but gcc + * reserves ebx for use of its pic register so we must specially + * handle the save and restore to avoid clobbering the register + */ + U32 n; + __asm__( + "pushl %%ebx\n\t" + "cpuid\n\t" + "popl %%ebx\n\t" + : "=a"(n) + : "a"(0) + : "ecx", "edx"); + if (n >= 1) { + U32 f1a; + __asm__( + "pushl %%ebx\n\t" + "cpuid\n\t" + "popl %%ebx\n\t" + : "=a"(f1a), "=c"(f1c), "=d"(f1d) + : "a"(1)); + } + if (n >= 7) { + __asm__( + "pushl %%ebx\n\t" + "cpuid\n\t" + "movl %%ebx, %%eax\n\t" + "popl %%ebx" + : "=a"(f7b), "=c"(f7c) + : "a"(7), "c"(0) + : "edx"); + } +#elif defined(__x86_64__) || defined(_M_X64) || defined(__i386__) + U32 n; + __asm__("cpuid" : "=a"(n) : "a"(0) : "ebx", "ecx", "edx"); + if (n >= 1) { + U32 f1a; + __asm__("cpuid" : "=a"(f1a), "=c"(f1c), "=d"(f1d) : "a"(1) : "ebx"); + } + if (n >= 7) { + U32 f7a; + __asm__("cpuid" + : "=a"(f7a), "=b"(f7b), "=c"(f7c) + : "a"(7), "c"(0) + : "edx"); + } +#endif + { + ZSTD_cpuid_t cpuid; + cpuid.f1c = f1c; + cpuid.f1d = f1d; + cpuid.f7b = f7b; + cpuid.f7c = f7c; + return cpuid; + } +} + +#define X(name, r, bit) \ + MEM_STATIC int ZSTD_cpuid_##name(ZSTD_cpuid_t const cpuid) { \ + return ((cpuid.r) & (1U << bit)) != 0; \ + } + +/* cpuid(1): Processor Info and Feature Bits. */ +#define C(name, bit) X(name, f1c, bit) + C(sse3, 0) + C(pclmuldq, 1) + C(dtes64, 2) + C(monitor, 3) + C(dscpl, 4) + C(vmx, 5) + C(smx, 6) + C(eist, 7) + C(tm2, 8) + C(ssse3, 9) + C(cnxtid, 10) + C(fma, 12) + C(cx16, 13) + C(xtpr, 14) + C(pdcm, 15) + C(pcid, 17) + C(dca, 18) + C(sse41, 19) + C(sse42, 20) + C(x2apic, 21) + C(movbe, 22) + C(popcnt, 23) + C(tscdeadline, 24) + C(aes, 25) + C(xsave, 26) + C(osxsave, 27) + C(avx, 28) + C(f16c, 29) + C(rdrand, 30) +#undef C +#define D(name, bit) X(name, f1d, bit) + D(fpu, 0) + D(vme, 1) + D(de, 2) + D(pse, 3) + D(tsc, 4) + D(msr, 5) + D(pae, 6) + D(mce, 7) + D(cx8, 8) + D(apic, 9) + D(sep, 11) + D(mtrr, 12) + D(pge, 13) + D(mca, 14) + D(cmov, 15) + D(pat, 16) + D(pse36, 17) + D(psn, 18) + D(clfsh, 19) + D(ds, 21) + D(acpi, 22) + D(mmx, 23) + D(fxsr, 24) + D(sse, 25) + D(sse2, 26) + D(ss, 27) + D(htt, 28) + D(tm, 29) + D(pbe, 31) +#undef D + +/* cpuid(7): Extended Features. */ +#define B(name, bit) X(name, f7b, bit) + B(bmi1, 3) + B(hle, 4) + B(avx2, 5) + B(smep, 7) + B(bmi2, 8) + B(erms, 9) + B(invpcid, 10) + B(rtm, 11) + B(mpx, 14) + B(avx512f, 16) + B(avx512dq, 17) + B(rdseed, 18) + B(adx, 19) + B(smap, 20) + B(avx512ifma, 21) + B(pcommit, 22) + B(clflushopt, 23) + B(clwb, 24) + B(avx512pf, 26) + B(avx512er, 27) + B(avx512cd, 28) + B(sha, 29) + B(avx512bw, 30) + B(avx512vl, 31) +#undef B +#define C(name, bit) X(name, f7c, bit) + C(prefetchwt1, 0) + C(avx512vbmi, 1) +#undef C + +#undef X + +#endif /* ZSTD_COMMON_CPU_H */ diff --git a/stage1/zstd/lib/common/debug.c b/stage1/zstd/lib/common/debug.c new file mode 100644 index 000000000000..bb863c9ea616 --- /dev/null +++ b/stage1/zstd/lib/common/debug.c @@ -0,0 +1,24 @@ +/* ****************************************************************** + * debug + * Part of FSE library + * Copyright (c) Yann Collet, Facebook, Inc. + * + * You can contact the author at : + * - Source repository : https://github.com/Cyan4973/FiniteStateEntropy + * + * This source code is licensed under both the BSD-style license (found in the + * LICENSE file in the root directory of this source tree) and the GPLv2 (found + * in the COPYING file in the root directory of this source tree). + * You may select, at your option, one of the above-listed licenses. +****************************************************************** */ + + +/* + * This module only hosts one global variable + * which can be used to dynamically influence the verbosity of traces, + * such as DEBUGLOG and RAWLOG + */ + +#include "debug.h" + +int g_debuglevel = DEBUGLEVEL; diff --git a/stage1/zstd/lib/common/debug.h b/stage1/zstd/lib/common/debug.h new file mode 100644 index 000000000000..3b2a320a188d --- /dev/null +++ b/stage1/zstd/lib/common/debug.h @@ -0,0 +1,107 @@ +/* ****************************************************************** + * debug + * Part of FSE library + * Copyright (c) Yann Collet, Facebook, Inc. + * + * You can contact the author at : + * - Source repository : https://github.com/Cyan4973/FiniteStateEntropy + * + * This source code is licensed under both the BSD-style license (found in the + * LICENSE file in the root directory of this source tree) and the GPLv2 (found + * in the COPYING file in the root directory of this source tree). + * You may select, at your option, one of the above-listed licenses. +****************************************************************** */ + + +/* + * The purpose of this header is to enable debug functions. + * They regroup assert(), DEBUGLOG() and RAWLOG() for run-time, + * and DEBUG_STATIC_ASSERT() for compile-time. + * + * By default, DEBUGLEVEL==0, which means run-time debug is disabled. + * + * Level 1 enables assert() only. + * Starting level 2, traces can be generated and pushed to stderr. + * The higher the level, the more verbose the traces. + * + * It's possible to dynamically adjust level using variable g_debug_level, + * which is only declared if DEBUGLEVEL>=2, + * and is a global variable, not multi-thread protected (use with care) + */ + +#ifndef DEBUG_H_12987983217 +#define DEBUG_H_12987983217 + +#if defined (__cplusplus) +extern "C" { +#endif + + +/* static assert is triggered at compile time, leaving no runtime artefact. + * static assert only works with compile-time constants. + * Also, this variant can only be used inside a function. */ +#define DEBUG_STATIC_ASSERT(c) (void)sizeof(char[(c) ? 1 : -1]) + + +/* DEBUGLEVEL is expected to be defined externally, + * typically through compiler command line. + * Value must be a number. */ +#ifndef DEBUGLEVEL +# define DEBUGLEVEL 0 +#endif + + +/* recommended values for DEBUGLEVEL : + * 0 : release mode, no debug, all run-time checks disabled + * 1 : enables assert() only, no display + * 2 : reserved, for currently active debug path + * 3 : events once per object lifetime (CCtx, CDict, etc.) + * 4 : events once per frame + * 5 : events once per block + * 6 : events once per sequence (verbose) + * 7+: events at every position (*very* verbose) + * + * It's generally inconvenient to output traces > 5. + * In which case, it's possible to selectively trigger high verbosity levels + * by modifying g_debug_level. + */ + +#if (DEBUGLEVEL>=1) +# define ZSTD_DEPS_NEED_ASSERT +# include "zstd_deps.h" +#else +# ifndef assert /* assert may be already defined, due to prior #include */ +# define assert(condition) ((void)0) /* disable assert (default) */ +# endif +#endif + +#if (DEBUGLEVEL>=2) +# define ZSTD_DEPS_NEED_IO +# include "zstd_deps.h" +extern int g_debuglevel; /* the variable is only declared, + it actually lives in debug.c, + and is shared by the whole process. + It's not thread-safe. + It's useful when enabling very verbose levels + on selective conditions (such as position in src) */ + +# define RAWLOG(l, ...) { \ + if (l<=g_debuglevel) { \ + ZSTD_DEBUG_PRINT(__VA_ARGS__); \ + } } +# define DEBUGLOG(l, ...) { \ + if (l<=g_debuglevel) { \ + ZSTD_DEBUG_PRINT(__FILE__ ": " __VA_ARGS__); \ + ZSTD_DEBUG_PRINT(" \n"); \ + } } +#else +# define RAWLOG(l, ...) {} /* disabled */ +# define DEBUGLOG(l, ...) {} /* disabled */ +#endif + + +#if defined (__cplusplus) +} +#endif + +#endif /* DEBUG_H_12987983217 */ diff --git a/stage1/zstd/lib/common/entropy_common.c b/stage1/zstd/lib/common/entropy_common.c new file mode 100644 index 000000000000..4229b40c5eed --- /dev/null +++ b/stage1/zstd/lib/common/entropy_common.c @@ -0,0 +1,368 @@ +/* ****************************************************************** + * Common functions of New Generation Entropy library + * Copyright (c) Yann Collet, Facebook, Inc. + * + * You can contact the author at : + * - FSE+HUF source repository : https://github.com/Cyan4973/FiniteStateEntropy + * - Public forum : https://groups.google.com/forum/#!forum/lz4c + * + * This source code is licensed under both the BSD-style license (found in the + * LICENSE file in the root directory of this source tree) and the GPLv2 (found + * in the COPYING file in the root directory of this source tree). + * You may select, at your option, one of the above-listed licenses. +****************************************************************** */ + +/* ************************************* +* Dependencies +***************************************/ +#include "mem.h" +#include "error_private.h" /* ERR_*, ERROR */ +#define FSE_STATIC_LINKING_ONLY /* FSE_MIN_TABLELOG */ +#include "fse.h" +#define HUF_STATIC_LINKING_ONLY /* HUF_TABLELOG_ABSOLUTEMAX */ +#include "huf.h" + + +/*=== Version ===*/ +unsigned FSE_versionNumber(void) { return FSE_VERSION_NUMBER; } + + +/*=== Error Management ===*/ +unsigned FSE_isError(size_t code) { return ERR_isError(code); } +const char* FSE_getErrorName(size_t code) { return ERR_getErrorName(code); } + +unsigned HUF_isError(size_t code) { return ERR_isError(code); } +const char* HUF_getErrorName(size_t code) { return ERR_getErrorName(code); } + + +/*-************************************************************** +* FSE NCount encoding-decoding +****************************************************************/ +static U32 FSE_ctz(U32 val) +{ + assert(val != 0); + { +# if defined(_MSC_VER) /* Visual */ + if (val != 0) { + unsigned long r; + _BitScanForward(&r, val); + return (unsigned)r; + } else { + /* Should not reach this code path */ + __assume(0); + } +# elif defined(__GNUC__) && (__GNUC__ >= 3) /* GCC Intrinsic */ + return __builtin_ctz(val); +# elif defined(__ICCARM__) /* IAR Intrinsic */ + return __CTZ(val); +# else /* Software version */ + U32 count = 0; + while ((val & 1) == 0) { + val >>= 1; + ++count; + } + return count; +# endif + } +} + +FORCE_INLINE_TEMPLATE +size_t FSE_readNCount_body(short* normalizedCounter, unsigned* maxSVPtr, unsigned* tableLogPtr, + const void* headerBuffer, size_t hbSize) +{ + const BYTE* const istart = (const BYTE*) headerBuffer; + const BYTE* const iend = istart + hbSize; + const BYTE* ip = istart; + int nbBits; + int remaining; + int threshold; + U32 bitStream; + int bitCount; + unsigned charnum = 0; + unsigned const maxSV1 = *maxSVPtr + 1; + int previous0 = 0; + + if (hbSize < 8) { + /* This function only works when hbSize >= 8 */ + char buffer[8] = {0}; + ZSTD_memcpy(buffer, headerBuffer, hbSize); + { size_t const countSize = FSE_readNCount(normalizedCounter, maxSVPtr, tableLogPtr, + buffer, sizeof(buffer)); + if (FSE_isError(countSize)) return countSize; + if (countSize > hbSize) return ERROR(corruption_detected); + return countSize; + } } + assert(hbSize >= 8); + + /* init */ + ZSTD_memset(normalizedCounter, 0, (*maxSVPtr+1) * sizeof(normalizedCounter[0])); /* all symbols not present in NCount have a frequency of 0 */ + bitStream = MEM_readLE32(ip); + nbBits = (bitStream & 0xF) + FSE_MIN_TABLELOG; /* extract tableLog */ + if (nbBits > FSE_TABLELOG_ABSOLUTE_MAX) return ERROR(tableLog_tooLarge); + bitStream >>= 4; + bitCount = 4; + *tableLogPtr = nbBits; + remaining = (1<> 1; + while (repeats >= 12) { + charnum += 3 * 12; + if (LIKELY(ip <= iend-7)) { + ip += 3; + } else { + bitCount -= (int)(8 * (iend - 7 - ip)); + bitCount &= 31; + ip = iend - 4; + } + bitStream = MEM_readLE32(ip) >> bitCount; + repeats = FSE_ctz(~bitStream | 0x80000000) >> 1; + } + charnum += 3 * repeats; + bitStream >>= 2 * repeats; + bitCount += 2 * repeats; + + /* Add the final repeat which isn't 0b11. */ + assert((bitStream & 3) < 3); + charnum += bitStream & 3; + bitCount += 2; + + /* This is an error, but break and return an error + * at the end, because returning out of a loop makes + * it harder for the compiler to optimize. + */ + if (charnum >= maxSV1) break; + + /* We don't need to set the normalized count to 0 + * because we already memset the whole buffer to 0. + */ + + if (LIKELY(ip <= iend-7) || (ip + (bitCount>>3) <= iend-4)) { + assert((bitCount >> 3) <= 3); /* For first condition to work */ + ip += bitCount>>3; + bitCount &= 7; + } else { + bitCount -= (int)(8 * (iend - 4 - ip)); + bitCount &= 31; + ip = iend - 4; + } + bitStream = MEM_readLE32(ip) >> bitCount; + } + { + int const max = (2*threshold-1) - remaining; + int count; + + if ((bitStream & (threshold-1)) < (U32)max) { + count = bitStream & (threshold-1); + bitCount += nbBits-1; + } else { + count = bitStream & (2*threshold-1); + if (count >= threshold) count -= max; + bitCount += nbBits; + } + + count--; /* extra accuracy */ + /* When it matters (small blocks), this is a + * predictable branch, because we don't use -1. + */ + if (count >= 0) { + remaining -= count; + } else { + assert(count == -1); + remaining += count; + } + normalizedCounter[charnum++] = (short)count; + previous0 = !count; + + assert(threshold > 1); + if (remaining < threshold) { + /* This branch can be folded into the + * threshold update condition because we + * know that threshold > 1. + */ + if (remaining <= 1) break; + nbBits = BIT_highbit32(remaining) + 1; + threshold = 1 << (nbBits - 1); + } + if (charnum >= maxSV1) break; + + if (LIKELY(ip <= iend-7) || (ip + (bitCount>>3) <= iend-4)) { + ip += bitCount>>3; + bitCount &= 7; + } else { + bitCount -= (int)(8 * (iend - 4 - ip)); + bitCount &= 31; + ip = iend - 4; + } + bitStream = MEM_readLE32(ip) >> bitCount; + } } + if (remaining != 1) return ERROR(corruption_detected); + /* Only possible when there are too many zeros. */ + if (charnum > maxSV1) return ERROR(maxSymbolValue_tooSmall); + if (bitCount > 32) return ERROR(corruption_detected); + *maxSVPtr = charnum-1; + + ip += (bitCount+7)>>3; + return ip-istart; +} + +/* Avoids the FORCE_INLINE of the _body() function. */ +static size_t FSE_readNCount_body_default( + short* normalizedCounter, unsigned* maxSVPtr, unsigned* tableLogPtr, + const void* headerBuffer, size_t hbSize) +{ + return FSE_readNCount_body(normalizedCounter, maxSVPtr, tableLogPtr, headerBuffer, hbSize); +} + +#if DYNAMIC_BMI2 +BMI2_TARGET_ATTRIBUTE static size_t FSE_readNCount_body_bmi2( + short* normalizedCounter, unsigned* maxSVPtr, unsigned* tableLogPtr, + const void* headerBuffer, size_t hbSize) +{ + return FSE_readNCount_body(normalizedCounter, maxSVPtr, tableLogPtr, headerBuffer, hbSize); +} +#endif + +size_t FSE_readNCount_bmi2( + short* normalizedCounter, unsigned* maxSVPtr, unsigned* tableLogPtr, + const void* headerBuffer, size_t hbSize, int bmi2) +{ +#if DYNAMIC_BMI2 + if (bmi2) { + return FSE_readNCount_body_bmi2(normalizedCounter, maxSVPtr, tableLogPtr, headerBuffer, hbSize); + } +#endif + (void)bmi2; + return FSE_readNCount_body_default(normalizedCounter, maxSVPtr, tableLogPtr, headerBuffer, hbSize); +} + +size_t FSE_readNCount( + short* normalizedCounter, unsigned* maxSVPtr, unsigned* tableLogPtr, + const void* headerBuffer, size_t hbSize) +{ + return FSE_readNCount_bmi2(normalizedCounter, maxSVPtr, tableLogPtr, headerBuffer, hbSize, /* bmi2 */ 0); +} + + +/*! HUF_readStats() : + Read compact Huffman tree, saved by HUF_writeCTable(). + `huffWeight` is destination buffer. + `rankStats` is assumed to be a table of at least HUF_TABLELOG_MAX U32. + @return : size read from `src` , or an error Code . + Note : Needed by HUF_readCTable() and HUF_readDTableX?() . +*/ +size_t HUF_readStats(BYTE* huffWeight, size_t hwSize, U32* rankStats, + U32* nbSymbolsPtr, U32* tableLogPtr, + const void* src, size_t srcSize) +{ + U32 wksp[HUF_READ_STATS_WORKSPACE_SIZE_U32]; + return HUF_readStats_wksp(huffWeight, hwSize, rankStats, nbSymbolsPtr, tableLogPtr, src, srcSize, wksp, sizeof(wksp), /* bmi2 */ 0); +} + +FORCE_INLINE_TEMPLATE size_t +HUF_readStats_body(BYTE* huffWeight, size_t hwSize, U32* rankStats, + U32* nbSymbolsPtr, U32* tableLogPtr, + const void* src, size_t srcSize, + void* workSpace, size_t wkspSize, + int bmi2) +{ + U32 weightTotal; + const BYTE* ip = (const BYTE*) src; + size_t iSize; + size_t oSize; + + if (!srcSize) return ERROR(srcSize_wrong); + iSize = ip[0]; + /* ZSTD_memset(huffWeight, 0, hwSize); *//* is not necessary, even though some analyzer complain ... */ + + if (iSize >= 128) { /* special header */ + oSize = iSize - 127; + iSize = ((oSize+1)/2); + if (iSize+1 > srcSize) return ERROR(srcSize_wrong); + if (oSize >= hwSize) return ERROR(corruption_detected); + ip += 1; + { U32 n; + for (n=0; n> 4; + huffWeight[n+1] = ip[n/2] & 15; + } } } + else { /* header compressed with FSE (normal case) */ + if (iSize+1 > srcSize) return ERROR(srcSize_wrong); + /* max (hwSize-1) values decoded, as last one is implied */ + oSize = FSE_decompress_wksp_bmi2(huffWeight, hwSize-1, ip+1, iSize, 6, workSpace, wkspSize, bmi2); + if (FSE_isError(oSize)) return oSize; + } + + /* collect weight stats */ + ZSTD_memset(rankStats, 0, (HUF_TABLELOG_MAX + 1) * sizeof(U32)); + weightTotal = 0; + { U32 n; for (n=0; n HUF_TABLELOG_MAX) return ERROR(corruption_detected); + rankStats[huffWeight[n]]++; + weightTotal += (1 << huffWeight[n]) >> 1; + } } + if (weightTotal == 0) return ERROR(corruption_detected); + + /* get last non-null symbol weight (implied, total must be 2^n) */ + { U32 const tableLog = BIT_highbit32(weightTotal) + 1; + if (tableLog > HUF_TABLELOG_MAX) return ERROR(corruption_detected); + *tableLogPtr = tableLog; + /* determine last weight */ + { U32 const total = 1 << tableLog; + U32 const rest = total - weightTotal; + U32 const verif = 1 << BIT_highbit32(rest); + U32 const lastWeight = BIT_highbit32(rest) + 1; + if (verif != rest) return ERROR(corruption_detected); /* last value must be a clean power of 2 */ + huffWeight[oSize] = (BYTE)lastWeight; + rankStats[lastWeight]++; + } } + + /* check tree construction validity */ + if ((rankStats[1] < 2) || (rankStats[1] & 1)) return ERROR(corruption_detected); /* by construction : at least 2 elts of rank 1, must be even */ + + /* results */ + *nbSymbolsPtr = (U32)(oSize+1); + return iSize+1; +} + +/* Avoids the FORCE_INLINE of the _body() function. */ +static size_t HUF_readStats_body_default(BYTE* huffWeight, size_t hwSize, U32* rankStats, + U32* nbSymbolsPtr, U32* tableLogPtr, + const void* src, size_t srcSize, + void* workSpace, size_t wkspSize) +{ + return HUF_readStats_body(huffWeight, hwSize, rankStats, nbSymbolsPtr, tableLogPtr, src, srcSize, workSpace, wkspSize, 0); +} + +#if DYNAMIC_BMI2 +static BMI2_TARGET_ATTRIBUTE size_t HUF_readStats_body_bmi2(BYTE* huffWeight, size_t hwSize, U32* rankStats, + U32* nbSymbolsPtr, U32* tableLogPtr, + const void* src, size_t srcSize, + void* workSpace, size_t wkspSize) +{ + return HUF_readStats_body(huffWeight, hwSize, rankStats, nbSymbolsPtr, tableLogPtr, src, srcSize, workSpace, wkspSize, 1); +} +#endif + +size_t HUF_readStats_wksp(BYTE* huffWeight, size_t hwSize, U32* rankStats, + U32* nbSymbolsPtr, U32* tableLogPtr, + const void* src, size_t srcSize, + void* workSpace, size_t wkspSize, + int bmi2) +{ +#if DYNAMIC_BMI2 + if (bmi2) { + return HUF_readStats_body_bmi2(huffWeight, hwSize, rankStats, nbSymbolsPtr, tableLogPtr, src, srcSize, workSpace, wkspSize); + } +#endif + (void)bmi2; + return HUF_readStats_body_default(huffWeight, hwSize, rankStats, nbSymbolsPtr, tableLogPtr, src, srcSize, workSpace, wkspSize); +} diff --git a/stage1/zstd/lib/common/error_private.c b/stage1/zstd/lib/common/error_private.c new file mode 100644 index 000000000000..6d1135f8c373 --- /dev/null +++ b/stage1/zstd/lib/common/error_private.c @@ -0,0 +1,56 @@ +/* + * Copyright (c) Yann Collet, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under both the BSD-style license (found in the + * LICENSE file in the root directory of this source tree) and the GPLv2 (found + * in the COPYING file in the root directory of this source tree). + * You may select, at your option, one of the above-listed licenses. + */ + +/* The purpose of this file is to have a single list of error strings embedded in binary */ + +#include "error_private.h" + +const char* ERR_getErrorString(ERR_enum code) +{ +#ifdef ZSTD_STRIP_ERROR_STRINGS + (void)code; + return "Error strings stripped"; +#else + static const char* const notErrorCode = "Unspecified error code"; + switch( code ) + { + case PREFIX(no_error): return "No error detected"; + case PREFIX(GENERIC): return "Error (generic)"; + case PREFIX(prefix_unknown): return "Unknown frame descriptor"; + case PREFIX(version_unsupported): return "Version not supported"; + case PREFIX(frameParameter_unsupported): return "Unsupported frame parameter"; + case PREFIX(frameParameter_windowTooLarge): return "Frame requires too much memory for decoding"; + case PREFIX(corruption_detected): return "Corrupted block detected"; + case PREFIX(checksum_wrong): return "Restored data doesn't match checksum"; + case PREFIX(parameter_unsupported): return "Unsupported parameter"; + case PREFIX(parameter_outOfBound): return "Parameter is out of bound"; + case PREFIX(init_missing): return "Context should be init first"; + case PREFIX(memory_allocation): return "Allocation error : not enough memory"; + case PREFIX(workSpace_tooSmall): return "workSpace buffer is not large enough"; + case PREFIX(stage_wrong): return "Operation not authorized at current processing stage"; + case PREFIX(tableLog_tooLarge): return "tableLog requires too much memory : unsupported"; + case PREFIX(maxSymbolValue_tooLarge): return "Unsupported max Symbol Value : too large"; + case PREFIX(maxSymbolValue_tooSmall): return "Specified maxSymbolValue is too small"; + case PREFIX(dictionary_corrupted): return "Dictionary is corrupted"; + case PREFIX(dictionary_wrong): return "Dictionary mismatch"; + case PREFIX(dictionaryCreation_failed): return "Cannot create Dictionary from provided samples"; + case PREFIX(dstSize_tooSmall): return "Destination buffer is too small"; + case PREFIX(srcSize_wrong): return "Src size is incorrect"; + case PREFIX(dstBuffer_null): return "Operation on NULL destination buffer"; + /* following error codes are not stable and may be removed or changed in a future version */ + case PREFIX(frameIndex_tooLarge): return "Frame index is too large"; + case PREFIX(seekableIO): return "An I/O error occurred when reading/seeking"; + case PREFIX(dstBuffer_wrong): return "Destination buffer is wrong"; + case PREFIX(srcBuffer_wrong): return "Source buffer is wrong"; + case PREFIX(maxCode): + default: return notErrorCode; + } +#endif +} diff --git a/stage1/zstd/lib/common/error_private.h b/stage1/zstd/lib/common/error_private.h new file mode 100644 index 000000000000..007d81066abd --- /dev/null +++ b/stage1/zstd/lib/common/error_private.h @@ -0,0 +1,159 @@ +/* + * Copyright (c) Yann Collet, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under both the BSD-style license (found in the + * LICENSE file in the root directory of this source tree) and the GPLv2 (found + * in the COPYING file in the root directory of this source tree). + * You may select, at your option, one of the above-listed licenses. + */ + +/* Note : this module is expected to remain private, do not expose it */ + +#ifndef ERROR_H_MODULE +#define ERROR_H_MODULE + +#if defined (__cplusplus) +extern "C" { +#endif + + +/* **************************************** +* Dependencies +******************************************/ +#include "../zstd_errors.h" /* enum list */ +#include "compiler.h" +#include "debug.h" +#include "zstd_deps.h" /* size_t */ + + +/* **************************************** +* Compiler-specific +******************************************/ +#if defined(__GNUC__) +# define ERR_STATIC static __attribute__((unused)) +#elif defined (__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) +# define ERR_STATIC static inline +#elif defined(_MSC_VER) +# define ERR_STATIC static __inline +#else +# define ERR_STATIC static /* this version may generate warnings for unused static functions; disable the relevant warning */ +#endif + + +/*-**************************************** +* Customization (error_public.h) +******************************************/ +typedef ZSTD_ErrorCode ERR_enum; +#define PREFIX(name) ZSTD_error_##name + + +/*-**************************************** +* Error codes handling +******************************************/ +#undef ERROR /* already defined on Visual Studio */ +#define ERROR(name) ZSTD_ERROR(name) +#define ZSTD_ERROR(name) ((size_t)-PREFIX(name)) + +ERR_STATIC unsigned ERR_isError(size_t code) { return (code > ERROR(maxCode)); } + +ERR_STATIC ERR_enum ERR_getErrorCode(size_t code) { if (!ERR_isError(code)) return (ERR_enum)0; return (ERR_enum) (0-code); } + +/* check and forward error code */ +#define CHECK_V_F(e, f) size_t const e = f; if (ERR_isError(e)) return e +#define CHECK_F(f) { CHECK_V_F(_var_err__, f); } + + +/*-**************************************** +* Error Strings +******************************************/ + +const char* ERR_getErrorString(ERR_enum code); /* error_private.c */ + +ERR_STATIC const char* ERR_getErrorName(size_t code) +{ + return ERR_getErrorString(ERR_getErrorCode(code)); +} + +/** + * Ignore: this is an internal helper. + * + * This is a helper function to help force C99-correctness during compilation. + * Under strict compilation modes, variadic macro arguments can't be empty. + * However, variadic function arguments can be. Using a function therefore lets + * us statically check that at least one (string) argument was passed, + * independent of the compilation flags. + */ +static INLINE_KEYWORD UNUSED_ATTR +void _force_has_format_string(const char *format, ...) { + (void)format; +} + +/** + * Ignore: this is an internal helper. + * + * We want to force this function invocation to be syntactically correct, but + * we don't want to force runtime evaluation of its arguments. + */ +#define _FORCE_HAS_FORMAT_STRING(...) \ + if (0) { \ + _force_has_format_string(__VA_ARGS__); \ + } + +#define ERR_QUOTE(str) #str + +/** + * Return the specified error if the condition evaluates to true. + * + * In debug modes, prints additional information. + * In order to do that (particularly, printing the conditional that failed), + * this can't just wrap RETURN_ERROR(). + */ +#define RETURN_ERROR_IF(cond, err, ...) \ + if (cond) { \ + RAWLOG(3, "%s:%d: ERROR!: check %s failed, returning %s", \ + __FILE__, __LINE__, ERR_QUOTE(cond), ERR_QUOTE(ERROR(err))); \ + _FORCE_HAS_FORMAT_STRING(__VA_ARGS__); \ + RAWLOG(3, ": " __VA_ARGS__); \ + RAWLOG(3, "\n"); \ + return ERROR(err); \ + } + +/** + * Unconditionally return the specified error. + * + * In debug modes, prints additional information. + */ +#define RETURN_ERROR(err, ...) \ + do { \ + RAWLOG(3, "%s:%d: ERROR!: unconditional check failed, returning %s", \ + __FILE__, __LINE__, ERR_QUOTE(ERROR(err))); \ + _FORCE_HAS_FORMAT_STRING(__VA_ARGS__); \ + RAWLOG(3, ": " __VA_ARGS__); \ + RAWLOG(3, "\n"); \ + return ERROR(err); \ + } while(0); + +/** + * If the provided expression evaluates to an error code, returns that error code. + * + * In debug modes, prints additional information. + */ +#define FORWARD_IF_ERROR(err, ...) \ + do { \ + size_t const err_code = (err); \ + if (ERR_isError(err_code)) { \ + RAWLOG(3, "%s:%d: ERROR!: forwarding error in %s: %s", \ + __FILE__, __LINE__, ERR_QUOTE(err), ERR_getErrorName(err_code)); \ + _FORCE_HAS_FORMAT_STRING(__VA_ARGS__); \ + RAWLOG(3, ": " __VA_ARGS__); \ + RAWLOG(3, "\n"); \ + return err_code; \ + } \ + } while(0); + +#if defined (__cplusplus) +} +#endif + +#endif /* ERROR_H_MODULE */ diff --git a/stage1/zstd/lib/common/fse.h b/stage1/zstd/lib/common/fse.h new file mode 100644 index 000000000000..714bfd3e7f22 --- /dev/null +++ b/stage1/zstd/lib/common/fse.h @@ -0,0 +1,717 @@ +/* ****************************************************************** + * FSE : Finite State Entropy codec + * Public Prototypes declaration + * Copyright (c) Yann Collet, Facebook, Inc. + * + * You can contact the author at : + * - Source repository : https://github.com/Cyan4973/FiniteStateEntropy + * + * This source code is licensed under both the BSD-style license (found in the + * LICENSE file in the root directory of this source tree) and the GPLv2 (found + * in the COPYING file in the root directory of this source tree). + * You may select, at your option, one of the above-listed licenses. +****************************************************************** */ + +#if defined (__cplusplus) +extern "C" { +#endif + +#ifndef FSE_H +#define FSE_H + + +/*-***************************************** +* Dependencies +******************************************/ +#include "zstd_deps.h" /* size_t, ptrdiff_t */ + + +/*-***************************************** +* FSE_PUBLIC_API : control library symbols visibility +******************************************/ +#if defined(FSE_DLL_EXPORT) && (FSE_DLL_EXPORT==1) && defined(__GNUC__) && (__GNUC__ >= 4) +# define FSE_PUBLIC_API __attribute__ ((visibility ("default"))) +#elif defined(FSE_DLL_EXPORT) && (FSE_DLL_EXPORT==1) /* Visual expected */ +# define FSE_PUBLIC_API __declspec(dllexport) +#elif defined(FSE_DLL_IMPORT) && (FSE_DLL_IMPORT==1) +# define FSE_PUBLIC_API __declspec(dllimport) /* It isn't required but allows to generate better code, saving a function pointer load from the IAT and an indirect jump.*/ +#else +# define FSE_PUBLIC_API +#endif + +/*------ Version ------*/ +#define FSE_VERSION_MAJOR 0 +#define FSE_VERSION_MINOR 9 +#define FSE_VERSION_RELEASE 0 + +#define FSE_LIB_VERSION FSE_VERSION_MAJOR.FSE_VERSION_MINOR.FSE_VERSION_RELEASE +#define FSE_QUOTE(str) #str +#define FSE_EXPAND_AND_QUOTE(str) FSE_QUOTE(str) +#define FSE_VERSION_STRING FSE_EXPAND_AND_QUOTE(FSE_LIB_VERSION) + +#define FSE_VERSION_NUMBER (FSE_VERSION_MAJOR *100*100 + FSE_VERSION_MINOR *100 + FSE_VERSION_RELEASE) +FSE_PUBLIC_API unsigned FSE_versionNumber(void); /**< library version number; to be used when checking dll version */ + + +/*-**************************************** +* FSE simple functions +******************************************/ +/*! FSE_compress() : + Compress content of buffer 'src', of size 'srcSize', into destination buffer 'dst'. + 'dst' buffer must be already allocated. Compression runs faster is dstCapacity >= FSE_compressBound(srcSize). + @return : size of compressed data (<= dstCapacity). + Special values : if return == 0, srcData is not compressible => Nothing is stored within dst !!! + if return == 1, srcData is a single byte symbol * srcSize times. Use RLE compression instead. + if FSE_isError(return), compression failed (more details using FSE_getErrorName()) +*/ +FSE_PUBLIC_API size_t FSE_compress(void* dst, size_t dstCapacity, + const void* src, size_t srcSize); + +/*! FSE_decompress(): + Decompress FSE data from buffer 'cSrc', of size 'cSrcSize', + into already allocated destination buffer 'dst', of size 'dstCapacity'. + @return : size of regenerated data (<= maxDstSize), + or an error code, which can be tested using FSE_isError() . + + ** Important ** : FSE_decompress() does not decompress non-compressible nor RLE data !!! + Why ? : making this distinction requires a header. + Header management is intentionally delegated to the user layer, which can better manage special cases. +*/ +FSE_PUBLIC_API size_t FSE_decompress(void* dst, size_t dstCapacity, + const void* cSrc, size_t cSrcSize); + + +/*-***************************************** +* Tool functions +******************************************/ +FSE_PUBLIC_API size_t FSE_compressBound(size_t size); /* maximum compressed size */ + +/* Error Management */ +FSE_PUBLIC_API unsigned FSE_isError(size_t code); /* tells if a return value is an error code */ +FSE_PUBLIC_API const char* FSE_getErrorName(size_t code); /* provides error code string (useful for debugging) */ + + +/*-***************************************** +* FSE advanced functions +******************************************/ +/*! FSE_compress2() : + Same as FSE_compress(), but allows the selection of 'maxSymbolValue' and 'tableLog' + Both parameters can be defined as '0' to mean : use default value + @return : size of compressed data + Special values : if return == 0, srcData is not compressible => Nothing is stored within cSrc !!! + if return == 1, srcData is a single byte symbol * srcSize times. Use RLE compression. + if FSE_isError(return), it's an error code. +*/ +FSE_PUBLIC_API size_t FSE_compress2 (void* dst, size_t dstSize, const void* src, size_t srcSize, unsigned maxSymbolValue, unsigned tableLog); + + +/*-***************************************** +* FSE detailed API +******************************************/ +/*! +FSE_compress() does the following: +1. count symbol occurrence from source[] into table count[] (see hist.h) +2. normalize counters so that sum(count[]) == Power_of_2 (2^tableLog) +3. save normalized counters to memory buffer using writeNCount() +4. build encoding table 'CTable' from normalized counters +5. encode the data stream using encoding table 'CTable' + +FSE_decompress() does the following: +1. read normalized counters with readNCount() +2. build decoding table 'DTable' from normalized counters +3. decode the data stream using decoding table 'DTable' + +The following API allows targeting specific sub-functions for advanced tasks. +For example, it's possible to compress several blocks using the same 'CTable', +or to save and provide normalized distribution using external method. +*/ + +/* *** COMPRESSION *** */ + +/*! FSE_optimalTableLog(): + dynamically downsize 'tableLog' when conditions are met. + It saves CPU time, by using smaller tables, while preserving or even improving compression ratio. + @return : recommended tableLog (necessarily <= 'maxTableLog') */ +FSE_PUBLIC_API unsigned FSE_optimalTableLog(unsigned maxTableLog, size_t srcSize, unsigned maxSymbolValue); + +/*! FSE_normalizeCount(): + normalize counts so that sum(count[]) == Power_of_2 (2^tableLog) + 'normalizedCounter' is a table of short, of minimum size (maxSymbolValue+1). + useLowProbCount is a boolean parameter which trades off compressed size for + faster header decoding. When it is set to 1, the compressed data will be slightly + smaller. And when it is set to 0, FSE_readNCount() and FSE_buildDTable() will be + faster. If you are compressing a small amount of data (< 2 KB) then useLowProbCount=0 + is a good default, since header deserialization makes a big speed difference. + Otherwise, useLowProbCount=1 is a good default, since the speed difference is small. + @return : tableLog, + or an errorCode, which can be tested using FSE_isError() */ +FSE_PUBLIC_API size_t FSE_normalizeCount(short* normalizedCounter, unsigned tableLog, + const unsigned* count, size_t srcSize, unsigned maxSymbolValue, unsigned useLowProbCount); + +/*! FSE_NCountWriteBound(): + Provides the maximum possible size of an FSE normalized table, given 'maxSymbolValue' and 'tableLog'. + Typically useful for allocation purpose. */ +FSE_PUBLIC_API size_t FSE_NCountWriteBound(unsigned maxSymbolValue, unsigned tableLog); + +/*! FSE_writeNCount(): + Compactly save 'normalizedCounter' into 'buffer'. + @return : size of the compressed table, + or an errorCode, which can be tested using FSE_isError(). */ +FSE_PUBLIC_API size_t FSE_writeNCount (void* buffer, size_t bufferSize, + const short* normalizedCounter, + unsigned maxSymbolValue, unsigned tableLog); + +/*! Constructor and Destructor of FSE_CTable. + Note that FSE_CTable size depends on 'tableLog' and 'maxSymbolValue' */ +typedef unsigned FSE_CTable; /* don't allocate that. It's only meant to be more restrictive than void* */ +FSE_PUBLIC_API FSE_CTable* FSE_createCTable (unsigned maxSymbolValue, unsigned tableLog); +FSE_PUBLIC_API void FSE_freeCTable (FSE_CTable* ct); + +/*! FSE_buildCTable(): + Builds `ct`, which must be already allocated, using FSE_createCTable(). + @return : 0, or an errorCode, which can be tested using FSE_isError() */ +FSE_PUBLIC_API size_t FSE_buildCTable(FSE_CTable* ct, const short* normalizedCounter, unsigned maxSymbolValue, unsigned tableLog); + +/*! FSE_compress_usingCTable(): + Compress `src` using `ct` into `dst` which must be already allocated. + @return : size of compressed data (<= `dstCapacity`), + or 0 if compressed data could not fit into `dst`, + or an errorCode, which can be tested using FSE_isError() */ +FSE_PUBLIC_API size_t FSE_compress_usingCTable (void* dst, size_t dstCapacity, const void* src, size_t srcSize, const FSE_CTable* ct); + +/*! +Tutorial : +---------- +The first step is to count all symbols. FSE_count() does this job very fast. +Result will be saved into 'count', a table of unsigned int, which must be already allocated, and have 'maxSymbolValuePtr[0]+1' cells. +'src' is a table of bytes of size 'srcSize'. All values within 'src' MUST be <= maxSymbolValuePtr[0] +maxSymbolValuePtr[0] will be updated, with its real value (necessarily <= original value) +FSE_count() will return the number of occurrence of the most frequent symbol. +This can be used to know if there is a single symbol within 'src', and to quickly evaluate its compressibility. +If there is an error, the function will return an ErrorCode (which can be tested using FSE_isError()). + +The next step is to normalize the frequencies. +FSE_normalizeCount() will ensure that sum of frequencies is == 2 ^'tableLog'. +It also guarantees a minimum of 1 to any Symbol with frequency >= 1. +You can use 'tableLog'==0 to mean "use default tableLog value". +If you are unsure of which tableLog value to use, you can ask FSE_optimalTableLog(), +which will provide the optimal valid tableLog given sourceSize, maxSymbolValue, and a user-defined maximum (0 means "default"). + +The result of FSE_normalizeCount() will be saved into a table, +called 'normalizedCounter', which is a table of signed short. +'normalizedCounter' must be already allocated, and have at least 'maxSymbolValue+1' cells. +The return value is tableLog if everything proceeded as expected. +It is 0 if there is a single symbol within distribution. +If there is an error (ex: invalid tableLog value), the function will return an ErrorCode (which can be tested using FSE_isError()). + +'normalizedCounter' can be saved in a compact manner to a memory area using FSE_writeNCount(). +'buffer' must be already allocated. +For guaranteed success, buffer size must be at least FSE_headerBound(). +The result of the function is the number of bytes written into 'buffer'. +If there is an error, the function will return an ErrorCode (which can be tested using FSE_isError(); ex : buffer size too small). + +'normalizedCounter' can then be used to create the compression table 'CTable'. +The space required by 'CTable' must be already allocated, using FSE_createCTable(). +You can then use FSE_buildCTable() to fill 'CTable'. +If there is an error, both functions will return an ErrorCode (which can be tested using FSE_isError()). + +'CTable' can then be used to compress 'src', with FSE_compress_usingCTable(). +Similar to FSE_count(), the convention is that 'src' is assumed to be a table of char of size 'srcSize' +The function returns the size of compressed data (without header), necessarily <= `dstCapacity`. +If it returns '0', compressed data could not fit into 'dst'. +If there is an error, the function will return an ErrorCode (which can be tested using FSE_isError()). +*/ + + +/* *** DECOMPRESSION *** */ + +/*! FSE_readNCount(): + Read compactly saved 'normalizedCounter' from 'rBuffer'. + @return : size read from 'rBuffer', + or an errorCode, which can be tested using FSE_isError(). + maxSymbolValuePtr[0] and tableLogPtr[0] will also be updated with their respective values */ +FSE_PUBLIC_API size_t FSE_readNCount (short* normalizedCounter, + unsigned* maxSymbolValuePtr, unsigned* tableLogPtr, + const void* rBuffer, size_t rBuffSize); + +/*! FSE_readNCount_bmi2(): + * Same as FSE_readNCount() but pass bmi2=1 when your CPU supports BMI2 and 0 otherwise. + */ +FSE_PUBLIC_API size_t FSE_readNCount_bmi2(short* normalizedCounter, + unsigned* maxSymbolValuePtr, unsigned* tableLogPtr, + const void* rBuffer, size_t rBuffSize, int bmi2); + +/*! Constructor and Destructor of FSE_DTable. + Note that its size depends on 'tableLog' */ +typedef unsigned FSE_DTable; /* don't allocate that. It's just a way to be more restrictive than void* */ +FSE_PUBLIC_API FSE_DTable* FSE_createDTable(unsigned tableLog); +FSE_PUBLIC_API void FSE_freeDTable(FSE_DTable* dt); + +/*! FSE_buildDTable(): + Builds 'dt', which must be already allocated, using FSE_createDTable(). + return : 0, or an errorCode, which can be tested using FSE_isError() */ +FSE_PUBLIC_API size_t FSE_buildDTable (FSE_DTable* dt, const short* normalizedCounter, unsigned maxSymbolValue, unsigned tableLog); + +/*! FSE_decompress_usingDTable(): + Decompress compressed source `cSrc` of size `cSrcSize` using `dt` + into `dst` which must be already allocated. + @return : size of regenerated data (necessarily <= `dstCapacity`), + or an errorCode, which can be tested using FSE_isError() */ +FSE_PUBLIC_API size_t FSE_decompress_usingDTable(void* dst, size_t dstCapacity, const void* cSrc, size_t cSrcSize, const FSE_DTable* dt); + +/*! +Tutorial : +---------- +(Note : these functions only decompress FSE-compressed blocks. + If block is uncompressed, use memcpy() instead + If block is a single repeated byte, use memset() instead ) + +The first step is to obtain the normalized frequencies of symbols. +This can be performed by FSE_readNCount() if it was saved using FSE_writeNCount(). +'normalizedCounter' must be already allocated, and have at least 'maxSymbolValuePtr[0]+1' cells of signed short. +In practice, that means it's necessary to know 'maxSymbolValue' beforehand, +or size the table to handle worst case situations (typically 256). +FSE_readNCount() will provide 'tableLog' and 'maxSymbolValue'. +The result of FSE_readNCount() is the number of bytes read from 'rBuffer'. +Note that 'rBufferSize' must be at least 4 bytes, even if useful information is less than that. +If there is an error, the function will return an error code, which can be tested using FSE_isError(). + +The next step is to build the decompression tables 'FSE_DTable' from 'normalizedCounter'. +This is performed by the function FSE_buildDTable(). +The space required by 'FSE_DTable' must be already allocated using FSE_createDTable(). +If there is an error, the function will return an error code, which can be tested using FSE_isError(). + +`FSE_DTable` can then be used to decompress `cSrc`, with FSE_decompress_usingDTable(). +`cSrcSize` must be strictly correct, otherwise decompression will fail. +FSE_decompress_usingDTable() result will tell how many bytes were regenerated (<=`dstCapacity`). +If there is an error, the function will return an error code, which can be tested using FSE_isError(). (ex: dst buffer too small) +*/ + +#endif /* FSE_H */ + +#if defined(FSE_STATIC_LINKING_ONLY) && !defined(FSE_H_FSE_STATIC_LINKING_ONLY) +#define FSE_H_FSE_STATIC_LINKING_ONLY + +/* *** Dependency *** */ +#include "bitstream.h" + + +/* ***************************************** +* Static allocation +*******************************************/ +/* FSE buffer bounds */ +#define FSE_NCOUNTBOUND 512 +#define FSE_BLOCKBOUND(size) ((size) + ((size)>>7) + 4 /* fse states */ + sizeof(size_t) /* bitContainer */) +#define FSE_COMPRESSBOUND(size) (FSE_NCOUNTBOUND + FSE_BLOCKBOUND(size)) /* Macro version, useful for static allocation */ + +/* It is possible to statically allocate FSE CTable/DTable as a table of FSE_CTable/FSE_DTable using below macros */ +#define FSE_CTABLE_SIZE_U32(maxTableLog, maxSymbolValue) (1 + (1<<((maxTableLog)-1)) + (((maxSymbolValue)+1)*2)) +#define FSE_DTABLE_SIZE_U32(maxTableLog) (1 + (1<<(maxTableLog))) + +/* or use the size to malloc() space directly. Pay attention to alignment restrictions though */ +#define FSE_CTABLE_SIZE(maxTableLog, maxSymbolValue) (FSE_CTABLE_SIZE_U32(maxTableLog, maxSymbolValue) * sizeof(FSE_CTable)) +#define FSE_DTABLE_SIZE(maxTableLog) (FSE_DTABLE_SIZE_U32(maxTableLog) * sizeof(FSE_DTable)) + + +/* ***************************************** + * FSE advanced API + ***************************************** */ + +unsigned FSE_optimalTableLog_internal(unsigned maxTableLog, size_t srcSize, unsigned maxSymbolValue, unsigned minus); +/**< same as FSE_optimalTableLog(), which used `minus==2` */ + +/* FSE_compress_wksp() : + * Same as FSE_compress2(), but using an externally allocated scratch buffer (`workSpace`). + * FSE_COMPRESS_WKSP_SIZE_U32() provides the minimum size required for `workSpace` as a table of FSE_CTable. + */ +#define FSE_COMPRESS_WKSP_SIZE_U32(maxTableLog, maxSymbolValue) ( FSE_CTABLE_SIZE_U32(maxTableLog, maxSymbolValue) + ((maxTableLog > 12) ? (1 << (maxTableLog - 2)) : 1024) ) +size_t FSE_compress_wksp (void* dst, size_t dstSize, const void* src, size_t srcSize, unsigned maxSymbolValue, unsigned tableLog, void* workSpace, size_t wkspSize); + +size_t FSE_buildCTable_raw (FSE_CTable* ct, unsigned nbBits); +/**< build a fake FSE_CTable, designed for a flat distribution, where each symbol uses nbBits */ + +size_t FSE_buildCTable_rle (FSE_CTable* ct, unsigned char symbolValue); +/**< build a fake FSE_CTable, designed to compress always the same symbolValue */ + +/* FSE_buildCTable_wksp() : + * Same as FSE_buildCTable(), but using an externally allocated scratch buffer (`workSpace`). + * `wkspSize` must be >= `FSE_BUILD_CTABLE_WORKSPACE_SIZE_U32(maxSymbolValue, tableLog)` of `unsigned`. + * See FSE_buildCTable_wksp() for breakdown of workspace usage. + */ +#define FSE_BUILD_CTABLE_WORKSPACE_SIZE_U32(maxSymbolValue, tableLog) (((maxSymbolValue + 2) + (1ull << (tableLog)))/2 + sizeof(U64)/sizeof(U32) /* additional 8 bytes for potential table overwrite */) +#define FSE_BUILD_CTABLE_WORKSPACE_SIZE(maxSymbolValue, tableLog) (sizeof(unsigned) * FSE_BUILD_CTABLE_WORKSPACE_SIZE_U32(maxSymbolValue, tableLog)) +size_t FSE_buildCTable_wksp(FSE_CTable* ct, const short* normalizedCounter, unsigned maxSymbolValue, unsigned tableLog, void* workSpace, size_t wkspSize); + +#define FSE_BUILD_DTABLE_WKSP_SIZE(maxTableLog, maxSymbolValue) (sizeof(short) * (maxSymbolValue + 1) + (1ULL << maxTableLog) + 8) +#define FSE_BUILD_DTABLE_WKSP_SIZE_U32(maxTableLog, maxSymbolValue) ((FSE_BUILD_DTABLE_WKSP_SIZE(maxTableLog, maxSymbolValue) + sizeof(unsigned) - 1) / sizeof(unsigned)) +FSE_PUBLIC_API size_t FSE_buildDTable_wksp(FSE_DTable* dt, const short* normalizedCounter, unsigned maxSymbolValue, unsigned tableLog, void* workSpace, size_t wkspSize); +/**< Same as FSE_buildDTable(), using an externally allocated `workspace` produced with `FSE_BUILD_DTABLE_WKSP_SIZE_U32(maxSymbolValue)` */ + +size_t FSE_buildDTable_raw (FSE_DTable* dt, unsigned nbBits); +/**< build a fake FSE_DTable, designed to read a flat distribution where each symbol uses nbBits */ + +size_t FSE_buildDTable_rle (FSE_DTable* dt, unsigned char symbolValue); +/**< build a fake FSE_DTable, designed to always generate the same symbolValue */ + +#define FSE_DECOMPRESS_WKSP_SIZE_U32(maxTableLog, maxSymbolValue) (FSE_DTABLE_SIZE_U32(maxTableLog) + FSE_BUILD_DTABLE_WKSP_SIZE_U32(maxTableLog, maxSymbolValue) + (FSE_MAX_SYMBOL_VALUE + 1) / 2 + 1) +#define FSE_DECOMPRESS_WKSP_SIZE(maxTableLog, maxSymbolValue) (FSE_DECOMPRESS_WKSP_SIZE_U32(maxTableLog, maxSymbolValue) * sizeof(unsigned)) +size_t FSE_decompress_wksp(void* dst, size_t dstCapacity, const void* cSrc, size_t cSrcSize, unsigned maxLog, void* workSpace, size_t wkspSize); +/**< same as FSE_decompress(), using an externally allocated `workSpace` produced with `FSE_DECOMPRESS_WKSP_SIZE_U32(maxLog, maxSymbolValue)` */ + +size_t FSE_decompress_wksp_bmi2(void* dst, size_t dstCapacity, const void* cSrc, size_t cSrcSize, unsigned maxLog, void* workSpace, size_t wkspSize, int bmi2); +/**< Same as FSE_decompress_wksp() but with dynamic BMI2 support. Pass 1 if your CPU supports BMI2 or 0 if it doesn't. */ + +typedef enum { + FSE_repeat_none, /**< Cannot use the previous table */ + FSE_repeat_check, /**< Can use the previous table but it must be checked */ + FSE_repeat_valid /**< Can use the previous table and it is assumed to be valid */ + } FSE_repeat; + +/* ***************************************** +* FSE symbol compression API +*******************************************/ +/*! + This API consists of small unitary functions, which highly benefit from being inlined. + Hence their body are included in next section. +*/ +typedef struct { + ptrdiff_t value; + const void* stateTable; + const void* symbolTT; + unsigned stateLog; +} FSE_CState_t; + +static void FSE_initCState(FSE_CState_t* CStatePtr, const FSE_CTable* ct); + +static void FSE_encodeSymbol(BIT_CStream_t* bitC, FSE_CState_t* CStatePtr, unsigned symbol); + +static void FSE_flushCState(BIT_CStream_t* bitC, const FSE_CState_t* CStatePtr); + +/**< +These functions are inner components of FSE_compress_usingCTable(). +They allow the creation of custom streams, mixing multiple tables and bit sources. + +A key property to keep in mind is that encoding and decoding are done **in reverse direction**. +So the first symbol you will encode is the last you will decode, like a LIFO stack. + +You will need a few variables to track your CStream. They are : + +FSE_CTable ct; // Provided by FSE_buildCTable() +BIT_CStream_t bitStream; // bitStream tracking structure +FSE_CState_t state; // State tracking structure (can have several) + + +The first thing to do is to init bitStream and state. + size_t errorCode = BIT_initCStream(&bitStream, dstBuffer, maxDstSize); + FSE_initCState(&state, ct); + +Note that BIT_initCStream() can produce an error code, so its result should be tested, using FSE_isError(); +You can then encode your input data, byte after byte. +FSE_encodeSymbol() outputs a maximum of 'tableLog' bits at a time. +Remember decoding will be done in reverse direction. + FSE_encodeByte(&bitStream, &state, symbol); + +At any time, you can also add any bit sequence. +Note : maximum allowed nbBits is 25, for compatibility with 32-bits decoders + BIT_addBits(&bitStream, bitField, nbBits); + +The above methods don't commit data to memory, they just store it into local register, for speed. +Local register size is 64-bits on 64-bits systems, 32-bits on 32-bits systems (size_t). +Writing data to memory is a manual operation, performed by the flushBits function. + BIT_flushBits(&bitStream); + +Your last FSE encoding operation shall be to flush your last state value(s). + FSE_flushState(&bitStream, &state); + +Finally, you must close the bitStream. +The function returns the size of CStream in bytes. +If data couldn't fit into dstBuffer, it will return a 0 ( == not compressible) +If there is an error, it returns an errorCode (which can be tested using FSE_isError()). + size_t size = BIT_closeCStream(&bitStream); +*/ + + +/* ***************************************** +* FSE symbol decompression API +*******************************************/ +typedef struct { + size_t state; + const void* table; /* precise table may vary, depending on U16 */ +} FSE_DState_t; + + +static void FSE_initDState(FSE_DState_t* DStatePtr, BIT_DStream_t* bitD, const FSE_DTable* dt); + +static unsigned char FSE_decodeSymbol(FSE_DState_t* DStatePtr, BIT_DStream_t* bitD); + +static unsigned FSE_endOfDState(const FSE_DState_t* DStatePtr); + +/**< +Let's now decompose FSE_decompress_usingDTable() into its unitary components. +You will decode FSE-encoded symbols from the bitStream, +and also any other bitFields you put in, **in reverse order**. + +You will need a few variables to track your bitStream. They are : + +BIT_DStream_t DStream; // Stream context +FSE_DState_t DState; // State context. Multiple ones are possible +FSE_DTable* DTablePtr; // Decoding table, provided by FSE_buildDTable() + +The first thing to do is to init the bitStream. + errorCode = BIT_initDStream(&DStream, srcBuffer, srcSize); + +You should then retrieve your initial state(s) +(in reverse flushing order if you have several ones) : + errorCode = FSE_initDState(&DState, &DStream, DTablePtr); + +You can then decode your data, symbol after symbol. +For information the maximum number of bits read by FSE_decodeSymbol() is 'tableLog'. +Keep in mind that symbols are decoded in reverse order, like a LIFO stack (last in, first out). + unsigned char symbol = FSE_decodeSymbol(&DState, &DStream); + +You can retrieve any bitfield you eventually stored into the bitStream (in reverse order) +Note : maximum allowed nbBits is 25, for 32-bits compatibility + size_t bitField = BIT_readBits(&DStream, nbBits); + +All above operations only read from local register (which size depends on size_t). +Refueling the register from memory is manually performed by the reload method. + endSignal = FSE_reloadDStream(&DStream); + +BIT_reloadDStream() result tells if there is still some more data to read from DStream. +BIT_DStream_unfinished : there is still some data left into the DStream. +BIT_DStream_endOfBuffer : Dstream reached end of buffer. Its container may no longer be completely filled. +BIT_DStream_completed : Dstream reached its exact end, corresponding in general to decompression completed. +BIT_DStream_tooFar : Dstream went too far. Decompression result is corrupted. + +When reaching end of buffer (BIT_DStream_endOfBuffer), progress slowly, notably if you decode multiple symbols per loop, +to properly detect the exact end of stream. +After each decoded symbol, check if DStream is fully consumed using this simple test : + BIT_reloadDStream(&DStream) >= BIT_DStream_completed + +When it's done, verify decompression is fully completed, by checking both DStream and the relevant states. +Checking if DStream has reached its end is performed by : + BIT_endOfDStream(&DStream); +Check also the states. There might be some symbols left there, if some high probability ones (>50%) are possible. + FSE_endOfDState(&DState); +*/ + + +/* ***************************************** +* FSE unsafe API +*******************************************/ +static unsigned char FSE_decodeSymbolFast(FSE_DState_t* DStatePtr, BIT_DStream_t* bitD); +/* faster, but works only if nbBits is always >= 1 (otherwise, result will be corrupted) */ + + +/* ***************************************** +* Implementation of inlined functions +*******************************************/ +typedef struct { + int deltaFindState; + U32 deltaNbBits; +} FSE_symbolCompressionTransform; /* total 8 bytes */ + +MEM_STATIC void FSE_initCState(FSE_CState_t* statePtr, const FSE_CTable* ct) +{ + const void* ptr = ct; + const U16* u16ptr = (const U16*) ptr; + const U32 tableLog = MEM_read16(ptr); + statePtr->value = (ptrdiff_t)1<stateTable = u16ptr+2; + statePtr->symbolTT = ct + 1 + (tableLog ? (1<<(tableLog-1)) : 1); + statePtr->stateLog = tableLog; +} + + +/*! FSE_initCState2() : +* Same as FSE_initCState(), but the first symbol to include (which will be the last to be read) +* uses the smallest state value possible, saving the cost of this symbol */ +MEM_STATIC void FSE_initCState2(FSE_CState_t* statePtr, const FSE_CTable* ct, U32 symbol) +{ + FSE_initCState(statePtr, ct); + { const FSE_symbolCompressionTransform symbolTT = ((const FSE_symbolCompressionTransform*)(statePtr->symbolTT))[symbol]; + const U16* stateTable = (const U16*)(statePtr->stateTable); + U32 nbBitsOut = (U32)((symbolTT.deltaNbBits + (1<<15)) >> 16); + statePtr->value = (nbBitsOut << 16) - symbolTT.deltaNbBits; + statePtr->value = stateTable[(statePtr->value >> nbBitsOut) + symbolTT.deltaFindState]; + } +} + +MEM_STATIC void FSE_encodeSymbol(BIT_CStream_t* bitC, FSE_CState_t* statePtr, unsigned symbol) +{ + FSE_symbolCompressionTransform const symbolTT = ((const FSE_symbolCompressionTransform*)(statePtr->symbolTT))[symbol]; + const U16* const stateTable = (const U16*)(statePtr->stateTable); + U32 const nbBitsOut = (U32)((statePtr->value + symbolTT.deltaNbBits) >> 16); + BIT_addBits(bitC, statePtr->value, nbBitsOut); + statePtr->value = stateTable[ (statePtr->value >> nbBitsOut) + symbolTT.deltaFindState]; +} + +MEM_STATIC void FSE_flushCState(BIT_CStream_t* bitC, const FSE_CState_t* statePtr) +{ + BIT_addBits(bitC, statePtr->value, statePtr->stateLog); + BIT_flushBits(bitC); +} + + +/* FSE_getMaxNbBits() : + * Approximate maximum cost of a symbol, in bits. + * Fractional get rounded up (i.e : a symbol with a normalized frequency of 3 gives the same result as a frequency of 2) + * note 1 : assume symbolValue is valid (<= maxSymbolValue) + * note 2 : if freq[symbolValue]==0, @return a fake cost of tableLog+1 bits */ +MEM_STATIC U32 FSE_getMaxNbBits(const void* symbolTTPtr, U32 symbolValue) +{ + const FSE_symbolCompressionTransform* symbolTT = (const FSE_symbolCompressionTransform*) symbolTTPtr; + return (symbolTT[symbolValue].deltaNbBits + ((1<<16)-1)) >> 16; +} + +/* FSE_bitCost() : + * Approximate symbol cost, as fractional value, using fixed-point format (accuracyLog fractional bits) + * note 1 : assume symbolValue is valid (<= maxSymbolValue) + * note 2 : if freq[symbolValue]==0, @return a fake cost of tableLog+1 bits */ +MEM_STATIC U32 FSE_bitCost(const void* symbolTTPtr, U32 tableLog, U32 symbolValue, U32 accuracyLog) +{ + const FSE_symbolCompressionTransform* symbolTT = (const FSE_symbolCompressionTransform*) symbolTTPtr; + U32 const minNbBits = symbolTT[symbolValue].deltaNbBits >> 16; + U32 const threshold = (minNbBits+1) << 16; + assert(tableLog < 16); + assert(accuracyLog < 31-tableLog); /* ensure enough room for renormalization double shift */ + { U32 const tableSize = 1 << tableLog; + U32 const deltaFromThreshold = threshold - (symbolTT[symbolValue].deltaNbBits + tableSize); + U32 const normalizedDeltaFromThreshold = (deltaFromThreshold << accuracyLog) >> tableLog; /* linear interpolation (very approximate) */ + U32 const bitMultiplier = 1 << accuracyLog; + assert(symbolTT[symbolValue].deltaNbBits + tableSize <= threshold); + assert(normalizedDeltaFromThreshold <= bitMultiplier); + return (minNbBits+1)*bitMultiplier - normalizedDeltaFromThreshold; + } +} + + +/* ====== Decompression ====== */ + +typedef struct { + U16 tableLog; + U16 fastMode; +} FSE_DTableHeader; /* sizeof U32 */ + +typedef struct +{ + unsigned short newState; + unsigned char symbol; + unsigned char nbBits; +} FSE_decode_t; /* size == U32 */ + +MEM_STATIC void FSE_initDState(FSE_DState_t* DStatePtr, BIT_DStream_t* bitD, const FSE_DTable* dt) +{ + const void* ptr = dt; + const FSE_DTableHeader* const DTableH = (const FSE_DTableHeader*)ptr; + DStatePtr->state = BIT_readBits(bitD, DTableH->tableLog); + BIT_reloadDStream(bitD); + DStatePtr->table = dt + 1; +} + +MEM_STATIC BYTE FSE_peekSymbol(const FSE_DState_t* DStatePtr) +{ + FSE_decode_t const DInfo = ((const FSE_decode_t*)(DStatePtr->table))[DStatePtr->state]; + return DInfo.symbol; +} + +MEM_STATIC void FSE_updateState(FSE_DState_t* DStatePtr, BIT_DStream_t* bitD) +{ + FSE_decode_t const DInfo = ((const FSE_decode_t*)(DStatePtr->table))[DStatePtr->state]; + U32 const nbBits = DInfo.nbBits; + size_t const lowBits = BIT_readBits(bitD, nbBits); + DStatePtr->state = DInfo.newState + lowBits; +} + +MEM_STATIC BYTE FSE_decodeSymbol(FSE_DState_t* DStatePtr, BIT_DStream_t* bitD) +{ + FSE_decode_t const DInfo = ((const FSE_decode_t*)(DStatePtr->table))[DStatePtr->state]; + U32 const nbBits = DInfo.nbBits; + BYTE const symbol = DInfo.symbol; + size_t const lowBits = BIT_readBits(bitD, nbBits); + + DStatePtr->state = DInfo.newState + lowBits; + return symbol; +} + +/*! FSE_decodeSymbolFast() : + unsafe, only works if no symbol has a probability > 50% */ +MEM_STATIC BYTE FSE_decodeSymbolFast(FSE_DState_t* DStatePtr, BIT_DStream_t* bitD) +{ + FSE_decode_t const DInfo = ((const FSE_decode_t*)(DStatePtr->table))[DStatePtr->state]; + U32 const nbBits = DInfo.nbBits; + BYTE const symbol = DInfo.symbol; + size_t const lowBits = BIT_readBitsFast(bitD, nbBits); + + DStatePtr->state = DInfo.newState + lowBits; + return symbol; +} + +MEM_STATIC unsigned FSE_endOfDState(const FSE_DState_t* DStatePtr) +{ + return DStatePtr->state == 0; +} + + + +#ifndef FSE_COMMONDEFS_ONLY + +/* ************************************************************** +* Tuning parameters +****************************************************************/ +/*!MEMORY_USAGE : +* Memory usage formula : N->2^N Bytes (examples : 10 -> 1KB; 12 -> 4KB ; 16 -> 64KB; 20 -> 1MB; etc.) +* Increasing memory usage improves compression ratio +* Reduced memory usage can improve speed, due to cache effect +* Recommended max value is 14, for 16KB, which nicely fits into Intel x86 L1 cache */ +#ifndef FSE_MAX_MEMORY_USAGE +# define FSE_MAX_MEMORY_USAGE 14 +#endif +#ifndef FSE_DEFAULT_MEMORY_USAGE +# define FSE_DEFAULT_MEMORY_USAGE 13 +#endif +#if (FSE_DEFAULT_MEMORY_USAGE > FSE_MAX_MEMORY_USAGE) +# error "FSE_DEFAULT_MEMORY_USAGE must be <= FSE_MAX_MEMORY_USAGE" +#endif + +/*!FSE_MAX_SYMBOL_VALUE : +* Maximum symbol value authorized. +* Required for proper stack allocation */ +#ifndef FSE_MAX_SYMBOL_VALUE +# define FSE_MAX_SYMBOL_VALUE 255 +#endif + +/* ************************************************************** +* template functions type & suffix +****************************************************************/ +#define FSE_FUNCTION_TYPE BYTE +#define FSE_FUNCTION_EXTENSION +#define FSE_DECODE_TYPE FSE_decode_t + + +#endif /* !FSE_COMMONDEFS_ONLY */ + + +/* *************************************************************** +* Constants +*****************************************************************/ +#define FSE_MAX_TABLELOG (FSE_MAX_MEMORY_USAGE-2) +#define FSE_MAX_TABLESIZE (1U< FSE_TABLELOG_ABSOLUTE_MAX +# error "FSE_MAX_TABLELOG > FSE_TABLELOG_ABSOLUTE_MAX is not supported" +#endif + +#define FSE_TABLESTEP(tableSize) (((tableSize)>>1) + ((tableSize)>>3) + 3) + + +#endif /* FSE_STATIC_LINKING_ONLY */ + + +#if defined (__cplusplus) +} +#endif diff --git a/stage1/zstd/lib/common/fse_decompress.c b/stage1/zstd/lib/common/fse_decompress.c new file mode 100644 index 000000000000..a5a358015fc9 --- /dev/null +++ b/stage1/zstd/lib/common/fse_decompress.c @@ -0,0 +1,403 @@ +/* ****************************************************************** + * FSE : Finite State Entropy decoder + * Copyright (c) Yann Collet, Facebook, Inc. + * + * You can contact the author at : + * - FSE source repository : https://github.com/Cyan4973/FiniteStateEntropy + * - Public forum : https://groups.google.com/forum/#!forum/lz4c + * + * This source code is licensed under both the BSD-style license (found in the + * LICENSE file in the root directory of this source tree) and the GPLv2 (found + * in the COPYING file in the root directory of this source tree). + * You may select, at your option, one of the above-listed licenses. +****************************************************************** */ + + +/* ************************************************************** +* Includes +****************************************************************/ +#include "debug.h" /* assert */ +#include "bitstream.h" +#include "compiler.h" +#define FSE_STATIC_LINKING_ONLY +#include "fse.h" +#include "error_private.h" +#define ZSTD_DEPS_NEED_MALLOC +#include "zstd_deps.h" + + +/* ************************************************************** +* Error Management +****************************************************************/ +#define FSE_isError ERR_isError +#define FSE_STATIC_ASSERT(c) DEBUG_STATIC_ASSERT(c) /* use only *after* variable declarations */ + + +/* ************************************************************** +* Templates +****************************************************************/ +/* + designed to be included + for type-specific functions (template emulation in C) + Objective is to write these functions only once, for improved maintenance +*/ + +/* safety checks */ +#ifndef FSE_FUNCTION_EXTENSION +# error "FSE_FUNCTION_EXTENSION must be defined" +#endif +#ifndef FSE_FUNCTION_TYPE +# error "FSE_FUNCTION_TYPE must be defined" +#endif + +/* Function names */ +#define FSE_CAT(X,Y) X##Y +#define FSE_FUNCTION_NAME(X,Y) FSE_CAT(X,Y) +#define FSE_TYPE_NAME(X,Y) FSE_CAT(X,Y) + + +/* Function templates */ +FSE_DTable* FSE_createDTable (unsigned tableLog) +{ + if (tableLog > FSE_TABLELOG_ABSOLUTE_MAX) tableLog = FSE_TABLELOG_ABSOLUTE_MAX; + return (FSE_DTable*)ZSTD_malloc( FSE_DTABLE_SIZE_U32(tableLog) * sizeof (U32) ); +} + +void FSE_freeDTable (FSE_DTable* dt) +{ + ZSTD_free(dt); +} + +static size_t FSE_buildDTable_internal(FSE_DTable* dt, const short* normalizedCounter, unsigned maxSymbolValue, unsigned tableLog, void* workSpace, size_t wkspSize) +{ + void* const tdPtr = dt+1; /* because *dt is unsigned, 32-bits aligned on 32-bits */ + FSE_DECODE_TYPE* const tableDecode = (FSE_DECODE_TYPE*) (tdPtr); + U16* symbolNext = (U16*)workSpace; + BYTE* spread = (BYTE*)(symbolNext + maxSymbolValue + 1); + + U32 const maxSV1 = maxSymbolValue + 1; + U32 const tableSize = 1 << tableLog; + U32 highThreshold = tableSize-1; + + /* Sanity Checks */ + if (FSE_BUILD_DTABLE_WKSP_SIZE(tableLog, maxSymbolValue) > wkspSize) return ERROR(maxSymbolValue_tooLarge); + if (maxSymbolValue > FSE_MAX_SYMBOL_VALUE) return ERROR(maxSymbolValue_tooLarge); + if (tableLog > FSE_MAX_TABLELOG) return ERROR(tableLog_tooLarge); + + /* Init, lay down lowprob symbols */ + { FSE_DTableHeader DTableH; + DTableH.tableLog = (U16)tableLog; + DTableH.fastMode = 1; + { S16 const largeLimit= (S16)(1 << (tableLog-1)); + U32 s; + for (s=0; s= largeLimit) DTableH.fastMode=0; + symbolNext[s] = normalizedCounter[s]; + } } } + ZSTD_memcpy(dt, &DTableH, sizeof(DTableH)); + } + + /* Spread symbols */ + if (highThreshold == tableSize - 1) { + size_t const tableMask = tableSize-1; + size_t const step = FSE_TABLESTEP(tableSize); + /* First lay down the symbols in order. + * We use a uint64_t to lay down 8 bytes at a time. This reduces branch + * misses since small blocks generally have small table logs, so nearly + * all symbols have counts <= 8. We ensure we have 8 bytes at the end of + * our buffer to handle the over-write. + */ + { + U64 const add = 0x0101010101010101ull; + size_t pos = 0; + U64 sv = 0; + U32 s; + for (s=0; s highThreshold) position = (position + step) & tableMask; /* lowprob area */ + } } + if (position!=0) return ERROR(GENERIC); /* position must reach all cells once, otherwise normalizedCounter is incorrect */ + } + + /* Build Decoding table */ + { U32 u; + for (u=0; utableLog = 0; + DTableH->fastMode = 0; + + cell->newState = 0; + cell->symbol = symbolValue; + cell->nbBits = 0; + + return 0; +} + + +size_t FSE_buildDTable_raw (FSE_DTable* dt, unsigned nbBits) +{ + void* ptr = dt; + FSE_DTableHeader* const DTableH = (FSE_DTableHeader*)ptr; + void* dPtr = dt + 1; + FSE_decode_t* const dinfo = (FSE_decode_t*)dPtr; + const unsigned tableSize = 1 << nbBits; + const unsigned tableMask = tableSize - 1; + const unsigned maxSV1 = tableMask+1; + unsigned s; + + /* Sanity checks */ + if (nbBits < 1) return ERROR(GENERIC); /* min size */ + + /* Build Decoding Table */ + DTableH->tableLog = (U16)nbBits; + DTableH->fastMode = 1; + for (s=0; s sizeof(bitD.bitContainer)*8) /* This test must be static */ + BIT_reloadDStream(&bitD); + + op[1] = FSE_GETSYMBOL(&state2); + + if (FSE_MAX_TABLELOG*4+7 > sizeof(bitD.bitContainer)*8) /* This test must be static */ + { if (BIT_reloadDStream(&bitD) > BIT_DStream_unfinished) { op+=2; break; } } + + op[2] = FSE_GETSYMBOL(&state1); + + if (FSE_MAX_TABLELOG*2+7 > sizeof(bitD.bitContainer)*8) /* This test must be static */ + BIT_reloadDStream(&bitD); + + op[3] = FSE_GETSYMBOL(&state2); + } + + /* tail */ + /* note : BIT_reloadDStream(&bitD) >= FSE_DStream_partiallyFilled; Ends at exactly BIT_DStream_completed */ + while (1) { + if (op>(omax-2)) return ERROR(dstSize_tooSmall); + *op++ = FSE_GETSYMBOL(&state1); + if (BIT_reloadDStream(&bitD)==BIT_DStream_overflow) { + *op++ = FSE_GETSYMBOL(&state2); + break; + } + + if (op>(omax-2)) return ERROR(dstSize_tooSmall); + *op++ = FSE_GETSYMBOL(&state2); + if (BIT_reloadDStream(&bitD)==BIT_DStream_overflow) { + *op++ = FSE_GETSYMBOL(&state1); + break; + } } + + return op-ostart; +} + + +size_t FSE_decompress_usingDTable(void* dst, size_t originalSize, + const void* cSrc, size_t cSrcSize, + const FSE_DTable* dt) +{ + const void* ptr = dt; + const FSE_DTableHeader* DTableH = (const FSE_DTableHeader*)ptr; + const U32 fastMode = DTableH->fastMode; + + /* select fast mode (static) */ + if (fastMode) return FSE_decompress_usingDTable_generic(dst, originalSize, cSrc, cSrcSize, dt, 1); + return FSE_decompress_usingDTable_generic(dst, originalSize, cSrc, cSrcSize, dt, 0); +} + + +size_t FSE_decompress_wksp(void* dst, size_t dstCapacity, const void* cSrc, size_t cSrcSize, unsigned maxLog, void* workSpace, size_t wkspSize) +{ + return FSE_decompress_wksp_bmi2(dst, dstCapacity, cSrc, cSrcSize, maxLog, workSpace, wkspSize, /* bmi2 */ 0); +} + +typedef struct { + short ncount[FSE_MAX_SYMBOL_VALUE + 1]; + FSE_DTable dtable[1]; /* Dynamically sized */ +} FSE_DecompressWksp; + + +FORCE_INLINE_TEMPLATE size_t FSE_decompress_wksp_body( + void* dst, size_t dstCapacity, + const void* cSrc, size_t cSrcSize, + unsigned maxLog, void* workSpace, size_t wkspSize, + int bmi2) +{ + const BYTE* const istart = (const BYTE*)cSrc; + const BYTE* ip = istart; + unsigned tableLog; + unsigned maxSymbolValue = FSE_MAX_SYMBOL_VALUE; + FSE_DecompressWksp* const wksp = (FSE_DecompressWksp*)workSpace; + + DEBUG_STATIC_ASSERT((FSE_MAX_SYMBOL_VALUE + 1) % 2 == 0); + if (wkspSize < sizeof(*wksp)) return ERROR(GENERIC); + + /* normal FSE decoding mode */ + { + size_t const NCountLength = FSE_readNCount_bmi2(wksp->ncount, &maxSymbolValue, &tableLog, istart, cSrcSize, bmi2); + if (FSE_isError(NCountLength)) return NCountLength; + if (tableLog > maxLog) return ERROR(tableLog_tooLarge); + assert(NCountLength <= cSrcSize); + ip += NCountLength; + cSrcSize -= NCountLength; + } + + if (FSE_DECOMPRESS_WKSP_SIZE(tableLog, maxSymbolValue) > wkspSize) return ERROR(tableLog_tooLarge); + workSpace = wksp->dtable + FSE_DTABLE_SIZE_U32(tableLog); + wkspSize -= sizeof(*wksp) + FSE_DTABLE_SIZE(tableLog); + + CHECK_F( FSE_buildDTable_internal(wksp->dtable, wksp->ncount, maxSymbolValue, tableLog, workSpace, wkspSize) ); + + { + const void* ptr = wksp->dtable; + const FSE_DTableHeader* DTableH = (const FSE_DTableHeader*)ptr; + const U32 fastMode = DTableH->fastMode; + + /* select fast mode (static) */ + if (fastMode) return FSE_decompress_usingDTable_generic(dst, dstCapacity, ip, cSrcSize, wksp->dtable, 1); + return FSE_decompress_usingDTable_generic(dst, dstCapacity, ip, cSrcSize, wksp->dtable, 0); + } +} + +/* Avoids the FORCE_INLINE of the _body() function. */ +static size_t FSE_decompress_wksp_body_default(void* dst, size_t dstCapacity, const void* cSrc, size_t cSrcSize, unsigned maxLog, void* workSpace, size_t wkspSize) +{ + return FSE_decompress_wksp_body(dst, dstCapacity, cSrc, cSrcSize, maxLog, workSpace, wkspSize, 0); +} + +#if DYNAMIC_BMI2 +BMI2_TARGET_ATTRIBUTE static size_t FSE_decompress_wksp_body_bmi2(void* dst, size_t dstCapacity, const void* cSrc, size_t cSrcSize, unsigned maxLog, void* workSpace, size_t wkspSize) +{ + return FSE_decompress_wksp_body(dst, dstCapacity, cSrc, cSrcSize, maxLog, workSpace, wkspSize, 1); +} +#endif + +size_t FSE_decompress_wksp_bmi2(void* dst, size_t dstCapacity, const void* cSrc, size_t cSrcSize, unsigned maxLog, void* workSpace, size_t wkspSize, int bmi2) +{ +#if DYNAMIC_BMI2 + if (bmi2) { + return FSE_decompress_wksp_body_bmi2(dst, dstCapacity, cSrc, cSrcSize, maxLog, workSpace, wkspSize); + } +#endif + (void)bmi2; + return FSE_decompress_wksp_body_default(dst, dstCapacity, cSrc, cSrcSize, maxLog, workSpace, wkspSize); +} + + +typedef FSE_DTable DTable_max_t[FSE_DTABLE_SIZE_U32(FSE_MAX_TABLELOG)]; + +#ifndef ZSTD_NO_UNUSED_FUNCTIONS +size_t FSE_buildDTable(FSE_DTable* dt, const short* normalizedCounter, unsigned maxSymbolValue, unsigned tableLog) { + U32 wksp[FSE_BUILD_DTABLE_WKSP_SIZE_U32(FSE_TABLELOG_ABSOLUTE_MAX, FSE_MAX_SYMBOL_VALUE)]; + return FSE_buildDTable_wksp(dt, normalizedCounter, maxSymbolValue, tableLog, wksp, sizeof(wksp)); +} + +size_t FSE_decompress(void* dst, size_t dstCapacity, const void* cSrc, size_t cSrcSize) +{ + /* Static analyzer seems unable to understand this table will be properly initialized later */ + U32 wksp[FSE_DECOMPRESS_WKSP_SIZE_U32(FSE_MAX_TABLELOG, FSE_MAX_SYMBOL_VALUE)]; + return FSE_decompress_wksp(dst, dstCapacity, cSrc, cSrcSize, FSE_MAX_TABLELOG, wksp, sizeof(wksp)); +} +#endif + + +#endif /* FSE_COMMONDEFS_ONLY */ diff --git a/stage1/zstd/lib/common/huf.h b/stage1/zstd/lib/common/huf.h new file mode 100644 index 000000000000..85518481ec63 --- /dev/null +++ b/stage1/zstd/lib/common/huf.h @@ -0,0 +1,364 @@ +/* ****************************************************************** + * huff0 huffman codec, + * part of Finite State Entropy library + * Copyright (c) Yann Collet, Facebook, Inc. + * + * You can contact the author at : + * - Source repository : https://github.com/Cyan4973/FiniteStateEntropy + * + * This source code is licensed under both the BSD-style license (found in the + * LICENSE file in the root directory of this source tree) and the GPLv2 (found + * in the COPYING file in the root directory of this source tree). + * You may select, at your option, one of the above-listed licenses. +****************************************************************** */ + +#if defined (__cplusplus) +extern "C" { +#endif + +#ifndef HUF_H_298734234 +#define HUF_H_298734234 + +/* *** Dependencies *** */ +#include "zstd_deps.h" /* size_t */ + + +/* *** library symbols visibility *** */ +/* Note : when linking with -fvisibility=hidden on gcc, or by default on Visual, + * HUF symbols remain "private" (internal symbols for library only). + * Set macro FSE_DLL_EXPORT to 1 if you want HUF symbols visible on DLL interface */ +#if defined(FSE_DLL_EXPORT) && (FSE_DLL_EXPORT==1) && defined(__GNUC__) && (__GNUC__ >= 4) +# define HUF_PUBLIC_API __attribute__ ((visibility ("default"))) +#elif defined(FSE_DLL_EXPORT) && (FSE_DLL_EXPORT==1) /* Visual expected */ +# define HUF_PUBLIC_API __declspec(dllexport) +#elif defined(FSE_DLL_IMPORT) && (FSE_DLL_IMPORT==1) +# define HUF_PUBLIC_API __declspec(dllimport) /* not required, just to generate faster code (saves a function pointer load from IAT and an indirect jump) */ +#else +# define HUF_PUBLIC_API +#endif + + +/* ========================== */ +/* *** simple functions *** */ +/* ========================== */ + +/** HUF_compress() : + * Compress content from buffer 'src', of size 'srcSize', into buffer 'dst'. + * 'dst' buffer must be already allocated. + * Compression runs faster if `dstCapacity` >= HUF_compressBound(srcSize). + * `srcSize` must be <= `HUF_BLOCKSIZE_MAX` == 128 KB. + * @return : size of compressed data (<= `dstCapacity`). + * Special values : if return == 0, srcData is not compressible => Nothing is stored within dst !!! + * if HUF_isError(return), compression failed (more details using HUF_getErrorName()) + */ +HUF_PUBLIC_API size_t HUF_compress(void* dst, size_t dstCapacity, + const void* src, size_t srcSize); + +/** HUF_decompress() : + * Decompress HUF data from buffer 'cSrc', of size 'cSrcSize', + * into already allocated buffer 'dst', of minimum size 'dstSize'. + * `originalSize` : **must** be the ***exact*** size of original (uncompressed) data. + * Note : in contrast with FSE, HUF_decompress can regenerate + * RLE (cSrcSize==1) and uncompressed (cSrcSize==dstSize) data, + * because it knows size to regenerate (originalSize). + * @return : size of regenerated data (== originalSize), + * or an error code, which can be tested using HUF_isError() + */ +HUF_PUBLIC_API size_t HUF_decompress(void* dst, size_t originalSize, + const void* cSrc, size_t cSrcSize); + + +/* *** Tool functions *** */ +#define HUF_BLOCKSIZE_MAX (128 * 1024) /**< maximum input size for a single block compressed with HUF_compress */ +HUF_PUBLIC_API size_t HUF_compressBound(size_t size); /**< maximum compressed size (worst case) */ + +/* Error Management */ +HUF_PUBLIC_API unsigned HUF_isError(size_t code); /**< tells if a return value is an error code */ +HUF_PUBLIC_API const char* HUF_getErrorName(size_t code); /**< provides error code string (useful for debugging) */ + + +/* *** Advanced function *** */ + +/** HUF_compress2() : + * Same as HUF_compress(), but offers control over `maxSymbolValue` and `tableLog`. + * `maxSymbolValue` must be <= HUF_SYMBOLVALUE_MAX . + * `tableLog` must be `<= HUF_TABLELOG_MAX` . */ +HUF_PUBLIC_API size_t HUF_compress2 (void* dst, size_t dstCapacity, + const void* src, size_t srcSize, + unsigned maxSymbolValue, unsigned tableLog); + +/** HUF_compress4X_wksp() : + * Same as HUF_compress2(), but uses externally allocated `workSpace`. + * `workspace` must be at least as large as HUF_WORKSPACE_SIZE */ +#define HUF_WORKSPACE_SIZE ((8 << 10) + 512 /* sorting scratch space */) +#define HUF_WORKSPACE_SIZE_U64 (HUF_WORKSPACE_SIZE / sizeof(U64)) +HUF_PUBLIC_API size_t HUF_compress4X_wksp (void* dst, size_t dstCapacity, + const void* src, size_t srcSize, + unsigned maxSymbolValue, unsigned tableLog, + void* workSpace, size_t wkspSize); + +#endif /* HUF_H_298734234 */ + +/* ****************************************************************** + * WARNING !! + * The following section contains advanced and experimental definitions + * which shall never be used in the context of a dynamic library, + * because they are not guaranteed to remain stable in the future. + * Only consider them in association with static linking. + * *****************************************************************/ +#if defined(HUF_STATIC_LINKING_ONLY) && !defined(HUF_H_HUF_STATIC_LINKING_ONLY) +#define HUF_H_HUF_STATIC_LINKING_ONLY + +/* *** Dependencies *** */ +#include "mem.h" /* U32 */ +#define FSE_STATIC_LINKING_ONLY +#include "fse.h" + + +/* *** Constants *** */ +#define HUF_TABLELOG_MAX 12 /* max runtime value of tableLog (due to static allocation); can be modified up to HUF_TABLELOG_ABSOLUTEMAX */ +#define HUF_TABLELOG_DEFAULT 11 /* default tableLog value when none specified */ +#define HUF_SYMBOLVALUE_MAX 255 + +#define HUF_TABLELOG_ABSOLUTEMAX 12 /* absolute limit of HUF_MAX_TABLELOG. Beyond that value, code does not work */ +#if (HUF_TABLELOG_MAX > HUF_TABLELOG_ABSOLUTEMAX) +# error "HUF_TABLELOG_MAX is too large !" +#endif + + +/* **************************************** +* Static allocation +******************************************/ +/* HUF buffer bounds */ +#define HUF_CTABLEBOUND 129 +#define HUF_BLOCKBOUND(size) (size + (size>>8) + 8) /* only true when incompressible is pre-filtered with fast heuristic */ +#define HUF_COMPRESSBOUND(size) (HUF_CTABLEBOUND + HUF_BLOCKBOUND(size)) /* Macro version, useful for static allocation */ + +/* static allocation of HUF's Compression Table */ +/* this is a private definition, just exposed for allocation and strict aliasing purpose. never EVER access its members directly */ +typedef size_t HUF_CElt; /* consider it an incomplete type */ +#define HUF_CTABLE_SIZE_ST(maxSymbolValue) ((maxSymbolValue)+2) /* Use tables of size_t, for proper alignment */ +#define HUF_CTABLE_SIZE(maxSymbolValue) (HUF_CTABLE_SIZE_ST(maxSymbolValue) * sizeof(size_t)) +#define HUF_CREATE_STATIC_CTABLE(name, maxSymbolValue) \ + HUF_CElt name[HUF_CTABLE_SIZE_ST(maxSymbolValue)] /* no final ; */ + +/* static allocation of HUF's DTable */ +typedef U32 HUF_DTable; +#define HUF_DTABLE_SIZE(maxTableLog) (1 + (1<<(maxTableLog))) +#define HUF_CREATE_STATIC_DTABLEX1(DTable, maxTableLog) \ + HUF_DTable DTable[HUF_DTABLE_SIZE((maxTableLog)-1)] = { ((U32)((maxTableLog)-1) * 0x01000001) } +#define HUF_CREATE_STATIC_DTABLEX2(DTable, maxTableLog) \ + HUF_DTable DTable[HUF_DTABLE_SIZE(maxTableLog)] = { ((U32)(maxTableLog) * 0x01000001) } + + +/* **************************************** +* Advanced decompression functions +******************************************/ +size_t HUF_decompress4X1 (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); /**< single-symbol decoder */ +#ifndef HUF_FORCE_DECOMPRESS_X1 +size_t HUF_decompress4X2 (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); /**< double-symbols decoder */ +#endif + +size_t HUF_decompress4X_DCtx (HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); /**< decodes RLE and uncompressed */ +size_t HUF_decompress4X_hufOnly(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); /**< considers RLE and uncompressed as errors */ +size_t HUF_decompress4X_hufOnly_wksp(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize, void* workSpace, size_t wkspSize); /**< considers RLE and uncompressed as errors */ +size_t HUF_decompress4X1_DCtx(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); /**< single-symbol decoder */ +size_t HUF_decompress4X1_DCtx_wksp(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize, void* workSpace, size_t wkspSize); /**< single-symbol decoder */ +#ifndef HUF_FORCE_DECOMPRESS_X1 +size_t HUF_decompress4X2_DCtx(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); /**< double-symbols decoder */ +size_t HUF_decompress4X2_DCtx_wksp(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize, void* workSpace, size_t wkspSize); /**< double-symbols decoder */ +#endif + + +/* **************************************** + * HUF detailed API + * ****************************************/ + +/*! HUF_compress() does the following: + * 1. count symbol occurrence from source[] into table count[] using FSE_count() (exposed within "fse.h") + * 2. (optional) refine tableLog using HUF_optimalTableLog() + * 3. build Huffman table from count using HUF_buildCTable() + * 4. save Huffman table to memory buffer using HUF_writeCTable() + * 5. encode the data stream using HUF_compress4X_usingCTable() + * + * The following API allows targeting specific sub-functions for advanced tasks. + * For example, it's possible to compress several blocks using the same 'CTable', + * or to save and regenerate 'CTable' using external methods. + */ +unsigned HUF_optimalTableLog(unsigned maxTableLog, size_t srcSize, unsigned maxSymbolValue); +size_t HUF_buildCTable (HUF_CElt* CTable, const unsigned* count, unsigned maxSymbolValue, unsigned maxNbBits); /* @return : maxNbBits; CTable and count can overlap. In which case, CTable will overwrite count content */ +size_t HUF_writeCTable (void* dst, size_t maxDstSize, const HUF_CElt* CTable, unsigned maxSymbolValue, unsigned huffLog); +size_t HUF_writeCTable_wksp(void* dst, size_t maxDstSize, const HUF_CElt* CTable, unsigned maxSymbolValue, unsigned huffLog, void* workspace, size_t workspaceSize); +size_t HUF_compress4X_usingCTable(void* dst, size_t dstSize, const void* src, size_t srcSize, const HUF_CElt* CTable); +size_t HUF_compress4X_usingCTable_bmi2(void* dst, size_t dstSize, const void* src, size_t srcSize, const HUF_CElt* CTable, int bmi2); +size_t HUF_estimateCompressedSize(const HUF_CElt* CTable, const unsigned* count, unsigned maxSymbolValue); +int HUF_validateCTable(const HUF_CElt* CTable, const unsigned* count, unsigned maxSymbolValue); + +typedef enum { + HUF_repeat_none, /**< Cannot use the previous table */ + HUF_repeat_check, /**< Can use the previous table but it must be checked. Note : The previous table must have been constructed by HUF_compress{1, 4}X_repeat */ + HUF_repeat_valid /**< Can use the previous table and it is assumed to be valid */ + } HUF_repeat; +/** HUF_compress4X_repeat() : + * Same as HUF_compress4X_wksp(), but considers using hufTable if *repeat != HUF_repeat_none. + * If it uses hufTable it does not modify hufTable or repeat. + * If it doesn't, it sets *repeat = HUF_repeat_none, and it sets hufTable to the table used. + * If preferRepeat then the old table will always be used if valid. + * If suspectUncompressible then some sampling checks will be run to potentially skip huffman coding */ +size_t HUF_compress4X_repeat(void* dst, size_t dstSize, + const void* src, size_t srcSize, + unsigned maxSymbolValue, unsigned tableLog, + void* workSpace, size_t wkspSize, /**< `workSpace` must be aligned on 4-bytes boundaries, `wkspSize` must be >= HUF_WORKSPACE_SIZE */ + HUF_CElt* hufTable, HUF_repeat* repeat, int preferRepeat, int bmi2, unsigned suspectUncompressible); + +/** HUF_buildCTable_wksp() : + * Same as HUF_buildCTable(), but using externally allocated scratch buffer. + * `workSpace` must be aligned on 4-bytes boundaries, and its size must be >= HUF_CTABLE_WORKSPACE_SIZE. + */ +#define HUF_CTABLE_WORKSPACE_SIZE_U32 (2*HUF_SYMBOLVALUE_MAX +1 +1) +#define HUF_CTABLE_WORKSPACE_SIZE (HUF_CTABLE_WORKSPACE_SIZE_U32 * sizeof(unsigned)) +size_t HUF_buildCTable_wksp (HUF_CElt* tree, + const unsigned* count, U32 maxSymbolValue, U32 maxNbBits, + void* workSpace, size_t wkspSize); + +/*! HUF_readStats() : + * Read compact Huffman tree, saved by HUF_writeCTable(). + * `huffWeight` is destination buffer. + * @return : size read from `src` , or an error Code . + * Note : Needed by HUF_readCTable() and HUF_readDTableXn() . */ +size_t HUF_readStats(BYTE* huffWeight, size_t hwSize, + U32* rankStats, U32* nbSymbolsPtr, U32* tableLogPtr, + const void* src, size_t srcSize); + +/*! HUF_readStats_wksp() : + * Same as HUF_readStats() but takes an external workspace which must be + * 4-byte aligned and its size must be >= HUF_READ_STATS_WORKSPACE_SIZE. + * If the CPU has BMI2 support, pass bmi2=1, otherwise pass bmi2=0. + */ +#define HUF_READ_STATS_WORKSPACE_SIZE_U32 FSE_DECOMPRESS_WKSP_SIZE_U32(6, HUF_TABLELOG_MAX-1) +#define HUF_READ_STATS_WORKSPACE_SIZE (HUF_READ_STATS_WORKSPACE_SIZE_U32 * sizeof(unsigned)) +size_t HUF_readStats_wksp(BYTE* huffWeight, size_t hwSize, + U32* rankStats, U32* nbSymbolsPtr, U32* tableLogPtr, + const void* src, size_t srcSize, + void* workspace, size_t wkspSize, + int bmi2); + +/** HUF_readCTable() : + * Loading a CTable saved with HUF_writeCTable() */ +size_t HUF_readCTable (HUF_CElt* CTable, unsigned* maxSymbolValuePtr, const void* src, size_t srcSize, unsigned *hasZeroWeights); + +/** HUF_getNbBitsFromCTable() : + * Read nbBits from CTable symbolTable, for symbol `symbolValue` presumed <= HUF_SYMBOLVALUE_MAX + * Note 1 : is not inlined, as HUF_CElt definition is private */ +U32 HUF_getNbBitsFromCTable(const HUF_CElt* symbolTable, U32 symbolValue); + +/* + * HUF_decompress() does the following: + * 1. select the decompression algorithm (X1, X2) based on pre-computed heuristics + * 2. build Huffman table from save, using HUF_readDTableX?() + * 3. decode 1 or 4 segments in parallel using HUF_decompress?X?_usingDTable() + */ + +/** HUF_selectDecoder() : + * Tells which decoder is likely to decode faster, + * based on a set of pre-computed metrics. + * @return : 0==HUF_decompress4X1, 1==HUF_decompress4X2 . + * Assumption : 0 < dstSize <= 128 KB */ +U32 HUF_selectDecoder (size_t dstSize, size_t cSrcSize); + +/** + * The minimum workspace size for the `workSpace` used in + * HUF_readDTableX1_wksp() and HUF_readDTableX2_wksp(). + * + * The space used depends on HUF_TABLELOG_MAX, ranging from ~1500 bytes when + * HUF_TABLE_LOG_MAX=12 to ~1850 bytes when HUF_TABLE_LOG_MAX=15. + * Buffer overflow errors may potentially occur if code modifications result in + * a required workspace size greater than that specified in the following + * macro. + */ +#define HUF_DECOMPRESS_WORKSPACE_SIZE ((2 << 10) + (1 << 9)) +#define HUF_DECOMPRESS_WORKSPACE_SIZE_U32 (HUF_DECOMPRESS_WORKSPACE_SIZE / sizeof(U32)) + +#ifndef HUF_FORCE_DECOMPRESS_X2 +size_t HUF_readDTableX1 (HUF_DTable* DTable, const void* src, size_t srcSize); +size_t HUF_readDTableX1_wksp (HUF_DTable* DTable, const void* src, size_t srcSize, void* workSpace, size_t wkspSize); +#endif +#ifndef HUF_FORCE_DECOMPRESS_X1 +size_t HUF_readDTableX2 (HUF_DTable* DTable, const void* src, size_t srcSize); +size_t HUF_readDTableX2_wksp (HUF_DTable* DTable, const void* src, size_t srcSize, void* workSpace, size_t wkspSize); +#endif + +size_t HUF_decompress4X_usingDTable(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const HUF_DTable* DTable); +#ifndef HUF_FORCE_DECOMPRESS_X2 +size_t HUF_decompress4X1_usingDTable(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const HUF_DTable* DTable); +#endif +#ifndef HUF_FORCE_DECOMPRESS_X1 +size_t HUF_decompress4X2_usingDTable(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const HUF_DTable* DTable); +#endif + + +/* ====================== */ +/* single stream variants */ +/* ====================== */ + +size_t HUF_compress1X (void* dst, size_t dstSize, const void* src, size_t srcSize, unsigned maxSymbolValue, unsigned tableLog); +size_t HUF_compress1X_wksp (void* dst, size_t dstSize, const void* src, size_t srcSize, unsigned maxSymbolValue, unsigned tableLog, void* workSpace, size_t wkspSize); /**< `workSpace` must be a table of at least HUF_WORKSPACE_SIZE_U64 U64 */ +size_t HUF_compress1X_usingCTable(void* dst, size_t dstSize, const void* src, size_t srcSize, const HUF_CElt* CTable); +size_t HUF_compress1X_usingCTable_bmi2(void* dst, size_t dstSize, const void* src, size_t srcSize, const HUF_CElt* CTable, int bmi2); +/** HUF_compress1X_repeat() : + * Same as HUF_compress1X_wksp(), but considers using hufTable if *repeat != HUF_repeat_none. + * If it uses hufTable it does not modify hufTable or repeat. + * If it doesn't, it sets *repeat = HUF_repeat_none, and it sets hufTable to the table used. + * If preferRepeat then the old table will always be used if valid. + * If suspectUncompressible then some sampling checks will be run to potentially skip huffman coding */ +size_t HUF_compress1X_repeat(void* dst, size_t dstSize, + const void* src, size_t srcSize, + unsigned maxSymbolValue, unsigned tableLog, + void* workSpace, size_t wkspSize, /**< `workSpace` must be aligned on 4-bytes boundaries, `wkspSize` must be >= HUF_WORKSPACE_SIZE */ + HUF_CElt* hufTable, HUF_repeat* repeat, int preferRepeat, int bmi2, unsigned suspectUncompressible); + +size_t HUF_decompress1X1 (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); /* single-symbol decoder */ +#ifndef HUF_FORCE_DECOMPRESS_X1 +size_t HUF_decompress1X2 (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); /* double-symbol decoder */ +#endif + +size_t HUF_decompress1X_DCtx (HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); +size_t HUF_decompress1X_DCtx_wksp (HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize, void* workSpace, size_t wkspSize); +#ifndef HUF_FORCE_DECOMPRESS_X2 +size_t HUF_decompress1X1_DCtx(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); /**< single-symbol decoder */ +size_t HUF_decompress1X1_DCtx_wksp(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize, void* workSpace, size_t wkspSize); /**< single-symbol decoder */ +#endif +#ifndef HUF_FORCE_DECOMPRESS_X1 +size_t HUF_decompress1X2_DCtx(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); /**< double-symbols decoder */ +size_t HUF_decompress1X2_DCtx_wksp(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize, void* workSpace, size_t wkspSize); /**< double-symbols decoder */ +#endif + +size_t HUF_decompress1X_usingDTable(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const HUF_DTable* DTable); /**< automatic selection of sing or double symbol decoder, based on DTable */ +#ifndef HUF_FORCE_DECOMPRESS_X2 +size_t HUF_decompress1X1_usingDTable(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const HUF_DTable* DTable); +#endif +#ifndef HUF_FORCE_DECOMPRESS_X1 +size_t HUF_decompress1X2_usingDTable(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const HUF_DTable* DTable); +#endif + +/* BMI2 variants. + * If the CPU has BMI2 support, pass bmi2=1, otherwise pass bmi2=0. + */ +size_t HUF_decompress1X_usingDTable_bmi2(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const HUF_DTable* DTable, int bmi2); +#ifndef HUF_FORCE_DECOMPRESS_X2 +size_t HUF_decompress1X1_DCtx_wksp_bmi2(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize, void* workSpace, size_t wkspSize, int bmi2); +#endif +size_t HUF_decompress4X_usingDTable_bmi2(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const HUF_DTable* DTable, int bmi2); +size_t HUF_decompress4X_hufOnly_wksp_bmi2(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize, void* workSpace, size_t wkspSize, int bmi2); +#ifndef HUF_FORCE_DECOMPRESS_X2 +size_t HUF_readDTableX1_wksp_bmi2(HUF_DTable* DTable, const void* src, size_t srcSize, void* workSpace, size_t wkspSize, int bmi2); +#endif +#ifndef HUF_FORCE_DECOMPRESS_X1 +size_t HUF_readDTableX2_wksp_bmi2(HUF_DTable* DTable, const void* src, size_t srcSize, void* workSpace, size_t wkspSize, int bmi2); +#endif + +#endif /* HUF_STATIC_LINKING_ONLY */ + +#if defined (__cplusplus) +} +#endif diff --git a/stage1/zstd/lib/common/mem.h b/stage1/zstd/lib/common/mem.h new file mode 100644 index 000000000000..85581c38478e --- /dev/null +++ b/stage1/zstd/lib/common/mem.h @@ -0,0 +1,442 @@ +/* + * Copyright (c) Yann Collet, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under both the BSD-style license (found in the + * LICENSE file in the root directory of this source tree) and the GPLv2 (found + * in the COPYING file in the root directory of this source tree). + * You may select, at your option, one of the above-listed licenses. + */ + +#ifndef MEM_H_MODULE +#define MEM_H_MODULE + +#if defined (__cplusplus) +extern "C" { +#endif + +/*-**************************************** +* Dependencies +******************************************/ +#include /* size_t, ptrdiff_t */ +#include "compiler.h" /* __has_builtin */ +#include "debug.h" /* DEBUG_STATIC_ASSERT */ +#include "zstd_deps.h" /* ZSTD_memcpy */ + + +/*-**************************************** +* Compiler specifics +******************************************/ +#if defined(_MSC_VER) /* Visual Studio */ +# include /* _byteswap_ulong */ +# include /* _byteswap_* */ +#endif +#if defined(__GNUC__) +# define MEM_STATIC static __inline __attribute__((unused)) +#elif defined (__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) +# define MEM_STATIC static inline +#elif defined(_MSC_VER) +# define MEM_STATIC static __inline +#else +# define MEM_STATIC static /* this version may generate warnings for unused static functions; disable the relevant warning */ +#endif + +/*-************************************************************** +* Basic Types +*****************************************************************/ +#if !defined (__VMS) && (defined (__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) ) +# if defined(_AIX) +# include +# else +# include /* intptr_t */ +# endif + typedef uint8_t BYTE; + typedef uint8_t U8; + typedef int8_t S8; + typedef uint16_t U16; + typedef int16_t S16; + typedef uint32_t U32; + typedef int32_t S32; + typedef uint64_t U64; + typedef int64_t S64; +#else +# include +#if CHAR_BIT != 8 +# error "this implementation requires char to be exactly 8-bit type" +#endif + typedef unsigned char BYTE; + typedef unsigned char U8; + typedef signed char S8; +#if USHRT_MAX != 65535 +# error "this implementation requires short to be exactly 16-bit type" +#endif + typedef unsigned short U16; + typedef signed short S16; +#if UINT_MAX != 4294967295 +# error "this implementation requires int to be exactly 32-bit type" +#endif + typedef unsigned int U32; + typedef signed int S32; +/* note : there are no limits defined for long long type in C90. + * limits exist in C99, however, in such case, is preferred */ + typedef unsigned long long U64; + typedef signed long long S64; +#endif + + +/*-************************************************************** +* Memory I/O API +*****************************************************************/ +/*=== Static platform detection ===*/ +MEM_STATIC unsigned MEM_32bits(void); +MEM_STATIC unsigned MEM_64bits(void); +MEM_STATIC unsigned MEM_isLittleEndian(void); + +/*=== Native unaligned read/write ===*/ +MEM_STATIC U16 MEM_read16(const void* memPtr); +MEM_STATIC U32 MEM_read32(const void* memPtr); +MEM_STATIC U64 MEM_read64(const void* memPtr); +MEM_STATIC size_t MEM_readST(const void* memPtr); + +MEM_STATIC void MEM_write16(void* memPtr, U16 value); +MEM_STATIC void MEM_write32(void* memPtr, U32 value); +MEM_STATIC void MEM_write64(void* memPtr, U64 value); + +/*=== Little endian unaligned read/write ===*/ +MEM_STATIC U16 MEM_readLE16(const void* memPtr); +MEM_STATIC U32 MEM_readLE24(const void* memPtr); +MEM_STATIC U32 MEM_readLE32(const void* memPtr); +MEM_STATIC U64 MEM_readLE64(const void* memPtr); +MEM_STATIC size_t MEM_readLEST(const void* memPtr); + +MEM_STATIC void MEM_writeLE16(void* memPtr, U16 val); +MEM_STATIC void MEM_writeLE24(void* memPtr, U32 val); +MEM_STATIC void MEM_writeLE32(void* memPtr, U32 val32); +MEM_STATIC void MEM_writeLE64(void* memPtr, U64 val64); +MEM_STATIC void MEM_writeLEST(void* memPtr, size_t val); + +/*=== Big endian unaligned read/write ===*/ +MEM_STATIC U32 MEM_readBE32(const void* memPtr); +MEM_STATIC U64 MEM_readBE64(const void* memPtr); +MEM_STATIC size_t MEM_readBEST(const void* memPtr); + +MEM_STATIC void MEM_writeBE32(void* memPtr, U32 val32); +MEM_STATIC void MEM_writeBE64(void* memPtr, U64 val64); +MEM_STATIC void MEM_writeBEST(void* memPtr, size_t val); + +/*=== Byteswap ===*/ +MEM_STATIC U32 MEM_swap32(U32 in); +MEM_STATIC U64 MEM_swap64(U64 in); +MEM_STATIC size_t MEM_swapST(size_t in); + + +/*-************************************************************** +* Memory I/O Implementation +*****************************************************************/ +/* MEM_FORCE_MEMORY_ACCESS : + * By default, access to unaligned memory is controlled by `memcpy()`, which is safe and portable. + * Unfortunately, on some target/compiler combinations, the generated assembly is sub-optimal. + * The below switch allow to select different access method for improved performance. + * Method 0 (default) : use `memcpy()`. Safe and portable. + * Method 1 : `__packed` statement. It depends on compiler extension (i.e., not portable). + * This method is safe if your compiler supports it, and *generally* as fast or faster than `memcpy`. + * Method 2 : direct access. This method is portable but violate C standard. + * It can generate buggy code on targets depending on alignment. + * In some circumstances, it's the only known way to get the most performance (i.e. GCC + ARMv6) + * See http://fastcompression.blogspot.fr/2015/08/accessing-unaligned-memory.html for details. + * Prefer these methods in priority order (0 > 1 > 2) + */ +#ifndef MEM_FORCE_MEMORY_ACCESS /* can be defined externally, on command line for example */ +# if defined(__INTEL_COMPILER) || defined(__GNUC__) || defined(__ICCARM__) +# define MEM_FORCE_MEMORY_ACCESS 1 +# endif +#endif + +MEM_STATIC unsigned MEM_32bits(void) { return sizeof(size_t)==4; } +MEM_STATIC unsigned MEM_64bits(void) { return sizeof(size_t)==8; } + +MEM_STATIC unsigned MEM_isLittleEndian(void) +{ +#if defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) + return 1; +#elif defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) + return 0; +#elif defined(__clang__) && __LITTLE_ENDIAN__ + return 1; +#elif defined(__clang__) && __BIG_ENDIAN__ + return 0; +#elif defined(_MSC_VER) && (_M_AMD64 || _M_IX86) + return 1; +#elif defined(__DMC__) && defined(_M_IX86) + return 1; +#else + const union { U32 u; BYTE c[4]; } one = { 1 }; /* don't use static : performance detrimental */ + return one.c[0]; +#endif +} + +#if defined(MEM_FORCE_MEMORY_ACCESS) && (MEM_FORCE_MEMORY_ACCESS==2) + +/* violates C standard, by lying on structure alignment. +Only use if no other choice to achieve best performance on target platform */ +MEM_STATIC U16 MEM_read16(const void* memPtr) { return *(const U16*) memPtr; } +MEM_STATIC U32 MEM_read32(const void* memPtr) { return *(const U32*) memPtr; } +MEM_STATIC U64 MEM_read64(const void* memPtr) { return *(const U64*) memPtr; } +MEM_STATIC size_t MEM_readST(const void* memPtr) { return *(const size_t*) memPtr; } + +MEM_STATIC void MEM_write16(void* memPtr, U16 value) { *(U16*)memPtr = value; } +MEM_STATIC void MEM_write32(void* memPtr, U32 value) { *(U32*)memPtr = value; } +MEM_STATIC void MEM_write64(void* memPtr, U64 value) { *(U64*)memPtr = value; } + +#elif defined(MEM_FORCE_MEMORY_ACCESS) && (MEM_FORCE_MEMORY_ACCESS==1) + +/* __pack instructions are safer, but compiler specific, hence potentially problematic for some compilers */ +/* currently only defined for gcc and icc */ +#if defined(_MSC_VER) || (defined(__INTEL_COMPILER) && defined(WIN32)) + __pragma( pack(push, 1) ) + typedef struct { U16 v; } unalign16; + typedef struct { U32 v; } unalign32; + typedef struct { U64 v; } unalign64; + typedef struct { size_t v; } unalignArch; + __pragma( pack(pop) ) +#else + typedef struct { U16 v; } __attribute__((packed)) unalign16; + typedef struct { U32 v; } __attribute__((packed)) unalign32; + typedef struct { U64 v; } __attribute__((packed)) unalign64; + typedef struct { size_t v; } __attribute__((packed)) unalignArch; +#endif + +MEM_STATIC U16 MEM_read16(const void* ptr) { return ((const unalign16*)ptr)->v; } +MEM_STATIC U32 MEM_read32(const void* ptr) { return ((const unalign32*)ptr)->v; } +MEM_STATIC U64 MEM_read64(const void* ptr) { return ((const unalign64*)ptr)->v; } +MEM_STATIC size_t MEM_readST(const void* ptr) { return ((const unalignArch*)ptr)->v; } + +MEM_STATIC void MEM_write16(void* memPtr, U16 value) { ((unalign16*)memPtr)->v = value; } +MEM_STATIC void MEM_write32(void* memPtr, U32 value) { ((unalign32*)memPtr)->v = value; } +MEM_STATIC void MEM_write64(void* memPtr, U64 value) { ((unalign64*)memPtr)->v = value; } + +#else + +/* default method, safe and standard. + can sometimes prove slower */ + +MEM_STATIC U16 MEM_read16(const void* memPtr) +{ + U16 val; ZSTD_memcpy(&val, memPtr, sizeof(val)); return val; +} + +MEM_STATIC U32 MEM_read32(const void* memPtr) +{ + U32 val; ZSTD_memcpy(&val, memPtr, sizeof(val)); return val; +} + +MEM_STATIC U64 MEM_read64(const void* memPtr) +{ + U64 val; ZSTD_memcpy(&val, memPtr, sizeof(val)); return val; +} + +MEM_STATIC size_t MEM_readST(const void* memPtr) +{ + size_t val; ZSTD_memcpy(&val, memPtr, sizeof(val)); return val; +} + +MEM_STATIC void MEM_write16(void* memPtr, U16 value) +{ + ZSTD_memcpy(memPtr, &value, sizeof(value)); +} + +MEM_STATIC void MEM_write32(void* memPtr, U32 value) +{ + ZSTD_memcpy(memPtr, &value, sizeof(value)); +} + +MEM_STATIC void MEM_write64(void* memPtr, U64 value) +{ + ZSTD_memcpy(memPtr, &value, sizeof(value)); +} + +#endif /* MEM_FORCE_MEMORY_ACCESS */ + +MEM_STATIC U32 MEM_swap32(U32 in) +{ +#if defined(_MSC_VER) /* Visual Studio */ + return _byteswap_ulong(in); +#elif (defined (__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__ >= 403)) \ + || (defined(__clang__) && __has_builtin(__builtin_bswap32)) + return __builtin_bswap32(in); +#else + return ((in << 24) & 0xff000000 ) | + ((in << 8) & 0x00ff0000 ) | + ((in >> 8) & 0x0000ff00 ) | + ((in >> 24) & 0x000000ff ); +#endif +} + +MEM_STATIC U64 MEM_swap64(U64 in) +{ +#if defined(_MSC_VER) /* Visual Studio */ + return _byteswap_uint64(in); +#elif (defined (__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__ >= 403)) \ + || (defined(__clang__) && __has_builtin(__builtin_bswap64)) + return __builtin_bswap64(in); +#else + return ((in << 56) & 0xff00000000000000ULL) | + ((in << 40) & 0x00ff000000000000ULL) | + ((in << 24) & 0x0000ff0000000000ULL) | + ((in << 8) & 0x000000ff00000000ULL) | + ((in >> 8) & 0x00000000ff000000ULL) | + ((in >> 24) & 0x0000000000ff0000ULL) | + ((in >> 40) & 0x000000000000ff00ULL) | + ((in >> 56) & 0x00000000000000ffULL); +#endif +} + +MEM_STATIC size_t MEM_swapST(size_t in) +{ + if (MEM_32bits()) + return (size_t)MEM_swap32((U32)in); + else + return (size_t)MEM_swap64((U64)in); +} + +/*=== Little endian r/w ===*/ + +MEM_STATIC U16 MEM_readLE16(const void* memPtr) +{ + if (MEM_isLittleEndian()) + return MEM_read16(memPtr); + else { + const BYTE* p = (const BYTE*)memPtr; + return (U16)(p[0] + (p[1]<<8)); + } +} + +MEM_STATIC void MEM_writeLE16(void* memPtr, U16 val) +{ + if (MEM_isLittleEndian()) { + MEM_write16(memPtr, val); + } else { + BYTE* p = (BYTE*)memPtr; + p[0] = (BYTE)val; + p[1] = (BYTE)(val>>8); + } +} + +MEM_STATIC U32 MEM_readLE24(const void* memPtr) +{ + return (U32)MEM_readLE16(memPtr) + ((U32)(((const BYTE*)memPtr)[2]) << 16); +} + +MEM_STATIC void MEM_writeLE24(void* memPtr, U32 val) +{ + MEM_writeLE16(memPtr, (U16)val); + ((BYTE*)memPtr)[2] = (BYTE)(val>>16); +} + +MEM_STATIC U32 MEM_readLE32(const void* memPtr) +{ + if (MEM_isLittleEndian()) + return MEM_read32(memPtr); + else + return MEM_swap32(MEM_read32(memPtr)); +} + +MEM_STATIC void MEM_writeLE32(void* memPtr, U32 val32) +{ + if (MEM_isLittleEndian()) + MEM_write32(memPtr, val32); + else + MEM_write32(memPtr, MEM_swap32(val32)); +} + +MEM_STATIC U64 MEM_readLE64(const void* memPtr) +{ + if (MEM_isLittleEndian()) + return MEM_read64(memPtr); + else + return MEM_swap64(MEM_read64(memPtr)); +} + +MEM_STATIC void MEM_writeLE64(void* memPtr, U64 val64) +{ + if (MEM_isLittleEndian()) + MEM_write64(memPtr, val64); + else + MEM_write64(memPtr, MEM_swap64(val64)); +} + +MEM_STATIC size_t MEM_readLEST(const void* memPtr) +{ + if (MEM_32bits()) + return (size_t)MEM_readLE32(memPtr); + else + return (size_t)MEM_readLE64(memPtr); +} + +MEM_STATIC void MEM_writeLEST(void* memPtr, size_t val) +{ + if (MEM_32bits()) + MEM_writeLE32(memPtr, (U32)val); + else + MEM_writeLE64(memPtr, (U64)val); +} + +/*=== Big endian r/w ===*/ + +MEM_STATIC U32 MEM_readBE32(const void* memPtr) +{ + if (MEM_isLittleEndian()) + return MEM_swap32(MEM_read32(memPtr)); + else + return MEM_read32(memPtr); +} + +MEM_STATIC void MEM_writeBE32(void* memPtr, U32 val32) +{ + if (MEM_isLittleEndian()) + MEM_write32(memPtr, MEM_swap32(val32)); + else + MEM_write32(memPtr, val32); +} + +MEM_STATIC U64 MEM_readBE64(const void* memPtr) +{ + if (MEM_isLittleEndian()) + return MEM_swap64(MEM_read64(memPtr)); + else + return MEM_read64(memPtr); +} + +MEM_STATIC void MEM_writeBE64(void* memPtr, U64 val64) +{ + if (MEM_isLittleEndian()) + MEM_write64(memPtr, MEM_swap64(val64)); + else + MEM_write64(memPtr, val64); +} + +MEM_STATIC size_t MEM_readBEST(const void* memPtr) +{ + if (MEM_32bits()) + return (size_t)MEM_readBE32(memPtr); + else + return (size_t)MEM_readBE64(memPtr); +} + +MEM_STATIC void MEM_writeBEST(void* memPtr, size_t val) +{ + if (MEM_32bits()) + MEM_writeBE32(memPtr, (U32)val); + else + MEM_writeBE64(memPtr, (U64)val); +} + +/* code only tested on 32 and 64 bits systems */ +MEM_STATIC void MEM_check(void) { DEBUG_STATIC_ASSERT((sizeof(size_t)==4) || (sizeof(size_t)==8)); } + + +#if defined (__cplusplus) +} +#endif + +#endif /* MEM_H_MODULE */ diff --git a/stage1/zstd/lib/common/pool.c b/stage1/zstd/lib/common/pool.c new file mode 100644 index 000000000000..2e37cdd73c81 --- /dev/null +++ b/stage1/zstd/lib/common/pool.c @@ -0,0 +1,355 @@ +/* + * Copyright (c) Yann Collet, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under both the BSD-style license (found in the + * LICENSE file in the root directory of this source tree) and the GPLv2 (found + * in the COPYING file in the root directory of this source tree). + * You may select, at your option, one of the above-listed licenses. + */ + + +/* ====== Dependencies ======= */ +#include "zstd_deps.h" /* size_t */ +#include "debug.h" /* assert */ +#include "zstd_internal.h" /* ZSTD_customMalloc, ZSTD_customFree */ +#include "pool.h" + +/* ====== Compiler specifics ====== */ +#if defined(_MSC_VER) +# pragma warning(disable : 4204) /* disable: C4204: non-constant aggregate initializer */ +#endif + + +#ifdef ZSTD_MULTITHREAD + +#include "threading.h" /* pthread adaptation */ + +/* A job is a function and an opaque argument */ +typedef struct POOL_job_s { + POOL_function function; + void *opaque; +} POOL_job; + +struct POOL_ctx_s { + ZSTD_customMem customMem; + /* Keep track of the threads */ + ZSTD_pthread_t* threads; + size_t threadCapacity; + size_t threadLimit; + + /* The queue is a circular buffer */ + POOL_job *queue; + size_t queueHead; + size_t queueTail; + size_t queueSize; + + /* The number of threads working on jobs */ + size_t numThreadsBusy; + /* Indicates if the queue is empty */ + int queueEmpty; + + /* The mutex protects the queue */ + ZSTD_pthread_mutex_t queueMutex; + /* Condition variable for pushers to wait on when the queue is full */ + ZSTD_pthread_cond_t queuePushCond; + /* Condition variables for poppers to wait on when the queue is empty */ + ZSTD_pthread_cond_t queuePopCond; + /* Indicates if the queue is shutting down */ + int shutdown; +}; + +/* POOL_thread() : + * Work thread for the thread pool. + * Waits for jobs and executes them. + * @returns : NULL on failure else non-null. + */ +static void* POOL_thread(void* opaque) { + POOL_ctx* const ctx = (POOL_ctx*)opaque; + if (!ctx) { return NULL; } + for (;;) { + /* Lock the mutex and wait for a non-empty queue or until shutdown */ + ZSTD_pthread_mutex_lock(&ctx->queueMutex); + + while ( ctx->queueEmpty + || (ctx->numThreadsBusy >= ctx->threadLimit) ) { + if (ctx->shutdown) { + /* even if !queueEmpty, (possible if numThreadsBusy >= threadLimit), + * a few threads will be shutdown while !queueEmpty, + * but enough threads will remain active to finish the queue */ + ZSTD_pthread_mutex_unlock(&ctx->queueMutex); + return opaque; + } + ZSTD_pthread_cond_wait(&ctx->queuePopCond, &ctx->queueMutex); + } + /* Pop a job off the queue */ + { POOL_job const job = ctx->queue[ctx->queueHead]; + ctx->queueHead = (ctx->queueHead + 1) % ctx->queueSize; + ctx->numThreadsBusy++; + ctx->queueEmpty = (ctx->queueHead == ctx->queueTail); + /* Unlock the mutex, signal a pusher, and run the job */ + ZSTD_pthread_cond_signal(&ctx->queuePushCond); + ZSTD_pthread_mutex_unlock(&ctx->queueMutex); + + job.function(job.opaque); + + /* If the intended queue size was 0, signal after finishing job */ + ZSTD_pthread_mutex_lock(&ctx->queueMutex); + ctx->numThreadsBusy--; + if (ctx->queueSize == 1) { + ZSTD_pthread_cond_signal(&ctx->queuePushCond); + } + ZSTD_pthread_mutex_unlock(&ctx->queueMutex); + } + } /* for (;;) */ + assert(0); /* Unreachable */ +} + +/* ZSTD_createThreadPool() : public access point */ +POOL_ctx* ZSTD_createThreadPool(size_t numThreads) { + return POOL_create (numThreads, 0); +} + +POOL_ctx* POOL_create(size_t numThreads, size_t queueSize) { + return POOL_create_advanced(numThreads, queueSize, ZSTD_defaultCMem); +} + +POOL_ctx* POOL_create_advanced(size_t numThreads, size_t queueSize, + ZSTD_customMem customMem) +{ + POOL_ctx* ctx; + /* Check parameters */ + if (!numThreads) { return NULL; } + /* Allocate the context and zero initialize */ + ctx = (POOL_ctx*)ZSTD_customCalloc(sizeof(POOL_ctx), customMem); + if (!ctx) { return NULL; } + /* Initialize the job queue. + * It needs one extra space since one space is wasted to differentiate + * empty and full queues. + */ + ctx->queueSize = queueSize + 1; + ctx->queue = (POOL_job*)ZSTD_customMalloc(ctx->queueSize * sizeof(POOL_job), customMem); + ctx->queueHead = 0; + ctx->queueTail = 0; + ctx->numThreadsBusy = 0; + ctx->queueEmpty = 1; + { + int error = 0; + error |= ZSTD_pthread_mutex_init(&ctx->queueMutex, NULL); + error |= ZSTD_pthread_cond_init(&ctx->queuePushCond, NULL); + error |= ZSTD_pthread_cond_init(&ctx->queuePopCond, NULL); + if (error) { POOL_free(ctx); return NULL; } + } + ctx->shutdown = 0; + /* Allocate space for the thread handles */ + ctx->threads = (ZSTD_pthread_t*)ZSTD_customMalloc(numThreads * sizeof(ZSTD_pthread_t), customMem); + ctx->threadCapacity = 0; + ctx->customMem = customMem; + /* Check for errors */ + if (!ctx->threads || !ctx->queue) { POOL_free(ctx); return NULL; } + /* Initialize the threads */ + { size_t i; + for (i = 0; i < numThreads; ++i) { + if (ZSTD_pthread_create(&ctx->threads[i], NULL, &POOL_thread, ctx)) { + ctx->threadCapacity = i; + POOL_free(ctx); + return NULL; + } } + ctx->threadCapacity = numThreads; + ctx->threadLimit = numThreads; + } + return ctx; +} + +/*! POOL_join() : + Shutdown the queue, wake any sleeping threads, and join all of the threads. +*/ +static void POOL_join(POOL_ctx* ctx) { + /* Shut down the queue */ + ZSTD_pthread_mutex_lock(&ctx->queueMutex); + ctx->shutdown = 1; + ZSTD_pthread_mutex_unlock(&ctx->queueMutex); + /* Wake up sleeping threads */ + ZSTD_pthread_cond_broadcast(&ctx->queuePushCond); + ZSTD_pthread_cond_broadcast(&ctx->queuePopCond); + /* Join all of the threads */ + { size_t i; + for (i = 0; i < ctx->threadCapacity; ++i) { + ZSTD_pthread_join(ctx->threads[i], NULL); /* note : could fail */ + } } +} + +void POOL_free(POOL_ctx *ctx) { + if (!ctx) { return; } + POOL_join(ctx); + ZSTD_pthread_mutex_destroy(&ctx->queueMutex); + ZSTD_pthread_cond_destroy(&ctx->queuePushCond); + ZSTD_pthread_cond_destroy(&ctx->queuePopCond); + ZSTD_customFree(ctx->queue, ctx->customMem); + ZSTD_customFree(ctx->threads, ctx->customMem); + ZSTD_customFree(ctx, ctx->customMem); +} + +void ZSTD_freeThreadPool (ZSTD_threadPool* pool) { + POOL_free (pool); +} + +size_t POOL_sizeof(const POOL_ctx* ctx) { + if (ctx==NULL) return 0; /* supports sizeof NULL */ + return sizeof(*ctx) + + ctx->queueSize * sizeof(POOL_job) + + ctx->threadCapacity * sizeof(ZSTD_pthread_t); +} + + +/* @return : 0 on success, 1 on error */ +static int POOL_resize_internal(POOL_ctx* ctx, size_t numThreads) +{ + if (numThreads <= ctx->threadCapacity) { + if (!numThreads) return 1; + ctx->threadLimit = numThreads; + return 0; + } + /* numThreads > threadCapacity */ + { ZSTD_pthread_t* const threadPool = (ZSTD_pthread_t*)ZSTD_customMalloc(numThreads * sizeof(ZSTD_pthread_t), ctx->customMem); + if (!threadPool) return 1; + /* replace existing thread pool */ + ZSTD_memcpy(threadPool, ctx->threads, ctx->threadCapacity * sizeof(*threadPool)); + ZSTD_customFree(ctx->threads, ctx->customMem); + ctx->threads = threadPool; + /* Initialize additional threads */ + { size_t threadId; + for (threadId = ctx->threadCapacity; threadId < numThreads; ++threadId) { + if (ZSTD_pthread_create(&threadPool[threadId], NULL, &POOL_thread, ctx)) { + ctx->threadCapacity = threadId; + return 1; + } } + } } + /* successfully expanded */ + ctx->threadCapacity = numThreads; + ctx->threadLimit = numThreads; + return 0; +} + +/* @return : 0 on success, 1 on error */ +int POOL_resize(POOL_ctx* ctx, size_t numThreads) +{ + int result; + if (ctx==NULL) return 1; + ZSTD_pthread_mutex_lock(&ctx->queueMutex); + result = POOL_resize_internal(ctx, numThreads); + ZSTD_pthread_cond_broadcast(&ctx->queuePopCond); + ZSTD_pthread_mutex_unlock(&ctx->queueMutex); + return result; +} + +/** + * Returns 1 if the queue is full and 0 otherwise. + * + * When queueSize is 1 (pool was created with an intended queueSize of 0), + * then a queue is empty if there is a thread free _and_ no job is waiting. + */ +static int isQueueFull(POOL_ctx const* ctx) { + if (ctx->queueSize > 1) { + return ctx->queueHead == ((ctx->queueTail + 1) % ctx->queueSize); + } else { + return (ctx->numThreadsBusy == ctx->threadLimit) || + !ctx->queueEmpty; + } +} + + +static void +POOL_add_internal(POOL_ctx* ctx, POOL_function function, void *opaque) +{ + POOL_job const job = {function, opaque}; + assert(ctx != NULL); + if (ctx->shutdown) return; + + ctx->queueEmpty = 0; + ctx->queue[ctx->queueTail] = job; + ctx->queueTail = (ctx->queueTail + 1) % ctx->queueSize; + ZSTD_pthread_cond_signal(&ctx->queuePopCond); +} + +void POOL_add(POOL_ctx* ctx, POOL_function function, void* opaque) +{ + assert(ctx != NULL); + ZSTD_pthread_mutex_lock(&ctx->queueMutex); + /* Wait until there is space in the queue for the new job */ + while (isQueueFull(ctx) && (!ctx->shutdown)) { + ZSTD_pthread_cond_wait(&ctx->queuePushCond, &ctx->queueMutex); + } + POOL_add_internal(ctx, function, opaque); + ZSTD_pthread_mutex_unlock(&ctx->queueMutex); +} + + +int POOL_tryAdd(POOL_ctx* ctx, POOL_function function, void* opaque) +{ + assert(ctx != NULL); + ZSTD_pthread_mutex_lock(&ctx->queueMutex); + if (isQueueFull(ctx)) { + ZSTD_pthread_mutex_unlock(&ctx->queueMutex); + return 0; + } + POOL_add_internal(ctx, function, opaque); + ZSTD_pthread_mutex_unlock(&ctx->queueMutex); + return 1; +} + + +#else /* ZSTD_MULTITHREAD not defined */ + +/* ========================== */ +/* No multi-threading support */ +/* ========================== */ + + +/* We don't need any data, but if it is empty, malloc() might return NULL. */ +struct POOL_ctx_s { + int dummy; +}; +static POOL_ctx g_poolCtx; + +POOL_ctx* POOL_create(size_t numThreads, size_t queueSize) { + return POOL_create_advanced(numThreads, queueSize, ZSTD_defaultCMem); +} + +POOL_ctx* +POOL_create_advanced(size_t numThreads, size_t queueSize, ZSTD_customMem customMem) +{ + (void)numThreads; + (void)queueSize; + (void)customMem; + return &g_poolCtx; +} + +void POOL_free(POOL_ctx* ctx) { + assert(!ctx || ctx == &g_poolCtx); + (void)ctx; +} + +int POOL_resize(POOL_ctx* ctx, size_t numThreads) { + (void)ctx; (void)numThreads; + return 0; +} + +void POOL_add(POOL_ctx* ctx, POOL_function function, void* opaque) { + (void)ctx; + function(opaque); +} + +int POOL_tryAdd(POOL_ctx* ctx, POOL_function function, void* opaque) { + (void)ctx; + function(opaque); + return 1; +} + +size_t POOL_sizeof(const POOL_ctx* ctx) { + if (ctx==NULL) return 0; /* supports sizeof NULL */ + assert(ctx == &g_poolCtx); + return sizeof(*ctx); +} + +#endif /* ZSTD_MULTITHREAD */ diff --git a/stage1/zstd/lib/common/pool.h b/stage1/zstd/lib/common/pool.h new file mode 100644 index 000000000000..0ebde1805db5 --- /dev/null +++ b/stage1/zstd/lib/common/pool.h @@ -0,0 +1,84 @@ +/* + * Copyright (c) Yann Collet, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under both the BSD-style license (found in the + * LICENSE file in the root directory of this source tree) and the GPLv2 (found + * in the COPYING file in the root directory of this source tree). + * You may select, at your option, one of the above-listed licenses. + */ + +#ifndef POOL_H +#define POOL_H + +#if defined (__cplusplus) +extern "C" { +#endif + + +#include "zstd_deps.h" +#define ZSTD_STATIC_LINKING_ONLY /* ZSTD_customMem */ +#include "../zstd.h" + +typedef struct POOL_ctx_s POOL_ctx; + +/*! POOL_create() : + * Create a thread pool with at most `numThreads` threads. + * `numThreads` must be at least 1. + * The maximum number of queued jobs before blocking is `queueSize`. + * @return : POOL_ctx pointer on success, else NULL. +*/ +POOL_ctx* POOL_create(size_t numThreads, size_t queueSize); + +POOL_ctx* POOL_create_advanced(size_t numThreads, size_t queueSize, + ZSTD_customMem customMem); + +/*! POOL_free() : + * Free a thread pool returned by POOL_create(). + */ +void POOL_free(POOL_ctx* ctx); + +/*! POOL_resize() : + * Expands or shrinks pool's number of threads. + * This is more efficient than releasing + creating a new context, + * since it tries to preserve and re-use existing threads. + * `numThreads` must be at least 1. + * @return : 0 when resize was successful, + * !0 (typically 1) if there is an error. + * note : only numThreads can be resized, queueSize remains unchanged. + */ +int POOL_resize(POOL_ctx* ctx, size_t numThreads); + +/*! POOL_sizeof() : + * @return threadpool memory usage + * note : compatible with NULL (returns 0 in this case) + */ +size_t POOL_sizeof(const POOL_ctx* ctx); + +/*! POOL_function : + * The function type that can be added to a thread pool. + */ +typedef void (*POOL_function)(void*); + +/*! POOL_add() : + * Add the job `function(opaque)` to the thread pool. `ctx` must be valid. + * Possibly blocks until there is room in the queue. + * Note : The function may be executed asynchronously, + * therefore, `opaque` must live until function has been completed. + */ +void POOL_add(POOL_ctx* ctx, POOL_function function, void* opaque); + + +/*! POOL_tryAdd() : + * Add the job `function(opaque)` to thread pool _if_ a queue slot is available. + * Returns immediately even if not (does not block). + * @return : 1 if successful, 0 if not. + */ +int POOL_tryAdd(POOL_ctx* ctx, POOL_function function, void* opaque); + + +#if defined (__cplusplus) +} +#endif + +#endif diff --git a/stage1/zstd/lib/common/portability_macros.h b/stage1/zstd/lib/common/portability_macros.h new file mode 100644 index 000000000000..2143817f5747 --- /dev/null +++ b/stage1/zstd/lib/common/portability_macros.h @@ -0,0 +1,137 @@ +/* + * Copyright (c) Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under both the BSD-style license (found in the + * LICENSE file in the root directory of this source tree) and the GPLv2 (found + * in the COPYING file in the root directory of this source tree). + * You may select, at your option, one of the above-listed licenses. + */ + +#ifndef ZSTD_PORTABILITY_MACROS_H +#define ZSTD_PORTABILITY_MACROS_H + +/** + * This header file contains macro defintions to support portability. + * This header is shared between C and ASM code, so it MUST only + * contain macro definitions. It MUST not contain any C code. + * + * This header ONLY defines macros to detect platforms/feature support. + * + */ + + +/* compat. with non-clang compilers */ +#ifndef __has_attribute + #define __has_attribute(x) 0 +#endif + +/* compat. with non-clang compilers */ +#ifndef __has_builtin +# define __has_builtin(x) 0 +#endif + +/* compat. with non-clang compilers */ +#ifndef __has_feature +# define __has_feature(x) 0 +#endif + +/* detects whether we are being compiled under msan */ +#ifndef ZSTD_MEMORY_SANITIZER +# if __has_feature(memory_sanitizer) +# define ZSTD_MEMORY_SANITIZER 1 +# else +# define ZSTD_MEMORY_SANITIZER 0 +# endif +#endif + +/* detects whether we are being compiled under asan */ +#ifndef ZSTD_ADDRESS_SANITIZER +# if __has_feature(address_sanitizer) +# define ZSTD_ADDRESS_SANITIZER 1 +# elif defined(__SANITIZE_ADDRESS__) +# define ZSTD_ADDRESS_SANITIZER 1 +# else +# define ZSTD_ADDRESS_SANITIZER 0 +# endif +#endif + +/* detects whether we are being compiled under dfsan */ +#ifndef ZSTD_DATAFLOW_SANITIZER +# if __has_feature(dataflow_sanitizer) +# define ZSTD_DATAFLOW_SANITIZER 1 +# else +# define ZSTD_DATAFLOW_SANITIZER 0 +# endif +#endif + +/* Mark the internal assembly functions as hidden */ +#ifdef __ELF__ +# define ZSTD_HIDE_ASM_FUNCTION(func) .hidden func +#else +# define ZSTD_HIDE_ASM_FUNCTION(func) +#endif + +/* Enable runtime BMI2 dispatch based on the CPU. + * Enabled for clang & gcc >=4.8 on x86 when BMI2 isn't enabled by default. + */ +#ifndef DYNAMIC_BMI2 + #if ((defined(__clang__) && __has_attribute(__target__)) \ + || (defined(__GNUC__) \ + && (__GNUC__ >= 5 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8)))) \ + && (defined(__x86_64__) || defined(_M_X64)) \ + && !defined(__BMI2__) + # define DYNAMIC_BMI2 1 + #else + # define DYNAMIC_BMI2 0 + #endif +#endif + +/** + * Only enable assembly for GNUC comptabile compilers, + * because other platforms may not support GAS assembly syntax. + * + * Only enable assembly for Linux / MacOS, other platforms may + * work, but they haven't been tested. This could likely be + * extended to BSD systems. + * + * Disable assembly when MSAN is enabled, because MSAN requires + * 100% of code to be instrumented to work. + */ +#if defined(__GNUC__) +# if defined(__linux__) || defined(__linux) || defined(__APPLE__) +# if ZSTD_MEMORY_SANITIZER +# define ZSTD_ASM_SUPPORTED 0 +# elif ZSTD_DATAFLOW_SANITIZER +# define ZSTD_ASM_SUPPORTED 0 +# else +# define ZSTD_ASM_SUPPORTED 1 +# endif +# else +# define ZSTD_ASM_SUPPORTED 0 +# endif +#else +# define ZSTD_ASM_SUPPORTED 0 +#endif + +/** + * Determines whether we should enable assembly for x86-64 + * with BMI2. + * + * Enable if all of the following conditions hold: + * - ASM hasn't been explicitly disabled by defining ZSTD_DISABLE_ASM + * - Assembly is supported + * - We are compiling for x86-64 and either: + * - DYNAMIC_BMI2 is enabled + * - BMI2 is supported at compile time + */ +#if !defined(ZSTD_DISABLE_ASM) && \ + ZSTD_ASM_SUPPORTED && \ + defined(__x86_64__) && \ + (DYNAMIC_BMI2 || defined(__BMI2__)) +# define ZSTD_ENABLE_ASM_X86_64_BMI2 1 +#else +# define ZSTD_ENABLE_ASM_X86_64_BMI2 0 +#endif + +#endif /* ZSTD_PORTABILITY_MACROS_H */ diff --git a/stage1/zstd/lib/common/threading.c b/stage1/zstd/lib/common/threading.c new file mode 100644 index 000000000000..92cf57c195a5 --- /dev/null +++ b/stage1/zstd/lib/common/threading.c @@ -0,0 +1,122 @@ +/** + * Copyright (c) 2016 Tino Reichardt + * All rights reserved. + * + * You can contact the author at: + * - zstdmt source repository: https://github.com/mcmilk/zstdmt + * + * This source code is licensed under both the BSD-style license (found in the + * LICENSE file in the root directory of this source tree) and the GPLv2 (found + * in the COPYING file in the root directory of this source tree). + * You may select, at your option, one of the above-listed licenses. + */ + +/** + * This file will hold wrapper for systems, which do not support pthreads + */ + +#include "threading.h" + +/* create fake symbol to avoid empty translation unit warning */ +int g_ZSTD_threading_useless_symbol; + +#if defined(ZSTD_MULTITHREAD) && defined(_WIN32) + +/** + * Windows minimalist Pthread Wrapper, based on : + * http://www.cse.wustl.edu/~schmidt/win32-cv-1.html + */ + + +/* === Dependencies === */ +#include +#include + + +/* === Implementation === */ + +static unsigned __stdcall worker(void *arg) +{ + ZSTD_pthread_t* const thread = (ZSTD_pthread_t*) arg; + thread->arg = thread->start_routine(thread->arg); + return 0; +} + +int ZSTD_pthread_create(ZSTD_pthread_t* thread, const void* unused, + void* (*start_routine) (void*), void* arg) +{ + (void)unused; + thread->arg = arg; + thread->start_routine = start_routine; + thread->handle = (HANDLE) _beginthreadex(NULL, 0, worker, thread, 0, NULL); + + if (!thread->handle) + return errno; + else + return 0; +} + +int ZSTD_pthread_join(ZSTD_pthread_t thread, void **value_ptr) +{ + DWORD result; + + if (!thread.handle) return 0; + + result = WaitForSingleObject(thread.handle, INFINITE); + switch (result) { + case WAIT_OBJECT_0: + if (value_ptr) *value_ptr = thread.arg; + return 0; + case WAIT_ABANDONED: + return EINVAL; + default: + return GetLastError(); + } +} + +#endif /* ZSTD_MULTITHREAD */ + +#if defined(ZSTD_MULTITHREAD) && DEBUGLEVEL >= 1 && !defined(_WIN32) + +#define ZSTD_DEPS_NEED_MALLOC +#include "zstd_deps.h" + +int ZSTD_pthread_mutex_init(ZSTD_pthread_mutex_t* mutex, pthread_mutexattr_t const* attr) +{ + *mutex = (pthread_mutex_t*)ZSTD_malloc(sizeof(pthread_mutex_t)); + if (!*mutex) + return 1; + return pthread_mutex_init(*mutex, attr); +} + +int ZSTD_pthread_mutex_destroy(ZSTD_pthread_mutex_t* mutex) +{ + if (!*mutex) + return 0; + { + int const ret = pthread_mutex_destroy(*mutex); + ZSTD_free(*mutex); + return ret; + } +} + +int ZSTD_pthread_cond_init(ZSTD_pthread_cond_t* cond, pthread_condattr_t const* attr) +{ + *cond = (pthread_cond_t*)ZSTD_malloc(sizeof(pthread_cond_t)); + if (!*cond) + return 1; + return pthread_cond_init(*cond, attr); +} + +int ZSTD_pthread_cond_destroy(ZSTD_pthread_cond_t* cond) +{ + if (!*cond) + return 0; + { + int const ret = pthread_cond_destroy(*cond); + ZSTD_free(*cond); + return ret; + } +} + +#endif diff --git a/stage1/zstd/lib/common/threading.h b/stage1/zstd/lib/common/threading.h new file mode 100644 index 000000000000..fd0060d5aa2a --- /dev/null +++ b/stage1/zstd/lib/common/threading.h @@ -0,0 +1,155 @@ +/** + * Copyright (c) 2016 Tino Reichardt + * All rights reserved. + * + * You can contact the author at: + * - zstdmt source repository: https://github.com/mcmilk/zstdmt + * + * This source code is licensed under both the BSD-style license (found in the + * LICENSE file in the root directory of this source tree) and the GPLv2 (found + * in the COPYING file in the root directory of this source tree). + * You may select, at your option, one of the above-listed licenses. + */ + +#ifndef THREADING_H_938743 +#define THREADING_H_938743 + +#include "debug.h" + +#if defined (__cplusplus) +extern "C" { +#endif + +#if defined(ZSTD_MULTITHREAD) && defined(_WIN32) + +/** + * Windows minimalist Pthread Wrapper, based on : + * http://www.cse.wustl.edu/~schmidt/win32-cv-1.html + */ +#ifdef WINVER +# undef WINVER +#endif +#define WINVER 0x0600 + +#ifdef _WIN32_WINNT +# undef _WIN32_WINNT +#endif +#define _WIN32_WINNT 0x0600 + +#ifndef WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN +#endif + +#undef ERROR /* reported already defined on VS 2015 (Rich Geldreich) */ +#include +#undef ERROR +#define ERROR(name) ZSTD_ERROR(name) + + +/* mutex */ +#define ZSTD_pthread_mutex_t CRITICAL_SECTION +#define ZSTD_pthread_mutex_init(a, b) ((void)(b), InitializeCriticalSection((a)), 0) +#define ZSTD_pthread_mutex_destroy(a) DeleteCriticalSection((a)) +#define ZSTD_pthread_mutex_lock(a) EnterCriticalSection((a)) +#define ZSTD_pthread_mutex_unlock(a) LeaveCriticalSection((a)) + +/* condition variable */ +#define ZSTD_pthread_cond_t CONDITION_VARIABLE +#define ZSTD_pthread_cond_init(a, b) ((void)(b), InitializeConditionVariable((a)), 0) +#define ZSTD_pthread_cond_destroy(a) ((void)(a)) +#define ZSTD_pthread_cond_wait(a, b) SleepConditionVariableCS((a), (b), INFINITE) +#define ZSTD_pthread_cond_signal(a) WakeConditionVariable((a)) +#define ZSTD_pthread_cond_broadcast(a) WakeAllConditionVariable((a)) + +/* ZSTD_pthread_create() and ZSTD_pthread_join() */ +typedef struct { + HANDLE handle; + void* (*start_routine)(void*); + void* arg; +} ZSTD_pthread_t; + +int ZSTD_pthread_create(ZSTD_pthread_t* thread, const void* unused, + void* (*start_routine) (void*), void* arg); + +int ZSTD_pthread_join(ZSTD_pthread_t thread, void** value_ptr); + +/** + * add here more wrappers as required + */ + + +#elif defined(ZSTD_MULTITHREAD) /* posix assumed ; need a better detection method */ +/* === POSIX Systems === */ +# include + +#if DEBUGLEVEL < 1 + +#define ZSTD_pthread_mutex_t pthread_mutex_t +#define ZSTD_pthread_mutex_init(a, b) pthread_mutex_init((a), (b)) +#define ZSTD_pthread_mutex_destroy(a) pthread_mutex_destroy((a)) +#define ZSTD_pthread_mutex_lock(a) pthread_mutex_lock((a)) +#define ZSTD_pthread_mutex_unlock(a) pthread_mutex_unlock((a)) + +#define ZSTD_pthread_cond_t pthread_cond_t +#define ZSTD_pthread_cond_init(a, b) pthread_cond_init((a), (b)) +#define ZSTD_pthread_cond_destroy(a) pthread_cond_destroy((a)) +#define ZSTD_pthread_cond_wait(a, b) pthread_cond_wait((a), (b)) +#define ZSTD_pthread_cond_signal(a) pthread_cond_signal((a)) +#define ZSTD_pthread_cond_broadcast(a) pthread_cond_broadcast((a)) + +#define ZSTD_pthread_t pthread_t +#define ZSTD_pthread_create(a, b, c, d) pthread_create((a), (b), (c), (d)) +#define ZSTD_pthread_join(a, b) pthread_join((a),(b)) + +#else /* DEBUGLEVEL >= 1 */ + +/* Debug implementation of threading. + * In this implementation we use pointers for mutexes and condition variables. + * This way, if we forget to init/destroy them the program will crash or ASAN + * will report leaks. + */ + +#define ZSTD_pthread_mutex_t pthread_mutex_t* +int ZSTD_pthread_mutex_init(ZSTD_pthread_mutex_t* mutex, pthread_mutexattr_t const* attr); +int ZSTD_pthread_mutex_destroy(ZSTD_pthread_mutex_t* mutex); +#define ZSTD_pthread_mutex_lock(a) pthread_mutex_lock(*(a)) +#define ZSTD_pthread_mutex_unlock(a) pthread_mutex_unlock(*(a)) + +#define ZSTD_pthread_cond_t pthread_cond_t* +int ZSTD_pthread_cond_init(ZSTD_pthread_cond_t* cond, pthread_condattr_t const* attr); +int ZSTD_pthread_cond_destroy(ZSTD_pthread_cond_t* cond); +#define ZSTD_pthread_cond_wait(a, b) pthread_cond_wait(*(a), *(b)) +#define ZSTD_pthread_cond_signal(a) pthread_cond_signal(*(a)) +#define ZSTD_pthread_cond_broadcast(a) pthread_cond_broadcast(*(a)) + +#define ZSTD_pthread_t pthread_t +#define ZSTD_pthread_create(a, b, c, d) pthread_create((a), (b), (c), (d)) +#define ZSTD_pthread_join(a, b) pthread_join((a),(b)) + +#endif + +#else /* ZSTD_MULTITHREAD not defined */ +/* No multithreading support */ + +typedef int ZSTD_pthread_mutex_t; +#define ZSTD_pthread_mutex_init(a, b) ((void)(a), (void)(b), 0) +#define ZSTD_pthread_mutex_destroy(a) ((void)(a)) +#define ZSTD_pthread_mutex_lock(a) ((void)(a)) +#define ZSTD_pthread_mutex_unlock(a) ((void)(a)) + +typedef int ZSTD_pthread_cond_t; +#define ZSTD_pthread_cond_init(a, b) ((void)(a), (void)(b), 0) +#define ZSTD_pthread_cond_destroy(a) ((void)(a)) +#define ZSTD_pthread_cond_wait(a, b) ((void)(a), (void)(b)) +#define ZSTD_pthread_cond_signal(a) ((void)(a)) +#define ZSTD_pthread_cond_broadcast(a) ((void)(a)) + +/* do not use ZSTD_pthread_t */ + +#endif /* ZSTD_MULTITHREAD */ + +#if defined (__cplusplus) +} +#endif + +#endif /* THREADING_H_938743 */ diff --git a/stage1/zstd/lib/common/xxhash.c b/stage1/zstd/lib/common/xxhash.c new file mode 100644 index 000000000000..d49497cf1cfa --- /dev/null +++ b/stage1/zstd/lib/common/xxhash.c @@ -0,0 +1,24 @@ +/* + * xxHash - Fast Hash algorithm + * Copyright (c) Yann Collet, Facebook, Inc. + * + * You can contact the author at : + * - xxHash homepage: http://www.xxhash.com + * - xxHash source repository : https://github.com/Cyan4973/xxHash + * + * This source code is licensed under both the BSD-style license (found in the + * LICENSE file in the root directory of this source tree) and the GPLv2 (found + * in the COPYING file in the root directory of this source tree). + * You may select, at your option, one of the above-listed licenses. +*/ + + + +/* + * xxhash.c instantiates functions defined in xxhash.h + */ + +#define XXH_STATIC_LINKING_ONLY /* access advanced declarations */ +#define XXH_IMPLEMENTATION /* access definitions */ + +#include "xxhash.h" diff --git a/stage1/zstd/lib/common/xxhash.h b/stage1/zstd/lib/common/xxhash.h new file mode 100644 index 000000000000..8ebbfdd62616 --- /dev/null +++ b/stage1/zstd/lib/common/xxhash.h @@ -0,0 +1,5686 @@ +/* + * xxHash - Fast Hash algorithm + * Copyright (c) Yann Collet, Facebook, Inc. + * + * You can contact the author at : + * - xxHash homepage: http://www.xxhash.com + * - xxHash source repository : https://github.com/Cyan4973/xxHash + * + * This source code is licensed under both the BSD-style license (found in the + * LICENSE file in the root directory of this source tree) and the GPLv2 (found + * in the COPYING file in the root directory of this source tree). + * You may select, at your option, one of the above-listed licenses. +*/ + + +#ifndef XXH_NO_XXH3 +# define XXH_NO_XXH3 +#endif + +#ifndef XXH_NAMESPACE +# define XXH_NAMESPACE ZSTD_ +#endif + +/*! + * @mainpage xxHash + * + * @file xxhash.h + * xxHash prototypes and implementation + */ +/* TODO: update */ +/* Notice extracted from xxHash homepage: + +xxHash is an extremely fast hash algorithm, running at RAM speed limits. +It also successfully passes all tests from the SMHasher suite. + +Comparison (single thread, Windows Seven 32 bits, using SMHasher on a Core 2 Duo @3GHz) + +Name Speed Q.Score Author +xxHash 5.4 GB/s 10 +CrapWow 3.2 GB/s 2 Andrew +MurmurHash 3a 2.7 GB/s 10 Austin Appleby +SpookyHash 2.0 GB/s 10 Bob Jenkins +SBox 1.4 GB/s 9 Bret Mulvey +Lookup3 1.2 GB/s 9 Bob Jenkins +SuperFastHash 1.2 GB/s 1 Paul Hsieh +CityHash64 1.05 GB/s 10 Pike & Alakuijala +FNV 0.55 GB/s 5 Fowler, Noll, Vo +CRC32 0.43 GB/s 9 +MD5-32 0.33 GB/s 10 Ronald L. Rivest +SHA1-32 0.28 GB/s 10 + +Q.Score is a measure of quality of the hash function. +It depends on successfully passing SMHasher test set. +10 is a perfect score. + +Note: SMHasher's CRC32 implementation is not the fastest one. +Other speed-oriented implementations can be faster, +especially in combination with PCLMUL instruction: +https://fastcompression.blogspot.com/2019/03/presenting-xxh3.html?showComment=1552696407071#c3490092340461170735 + +A 64-bit version, named XXH64, is available since r35. +It offers much better speed, but for 64-bit applications only. +Name Speed on 64 bits Speed on 32 bits +XXH64 13.8 GB/s 1.9 GB/s +XXH32 6.8 GB/s 6.0 GB/s +*/ + +#if defined (__cplusplus) +extern "C" { +#endif + +/* **************************** + * INLINE mode + ******************************/ +/*! + * XXH_INLINE_ALL (and XXH_PRIVATE_API) + * Use these build macros to inline xxhash into the target unit. + * Inlining improves performance on small inputs, especially when the length is + * expressed as a compile-time constant: + * + * https://fastcompression.blogspot.com/2018/03/xxhash-for-small-keys-impressive-power.html + * + * It also keeps xxHash symbols private to the unit, so they are not exported. + * + * Usage: + * #define XXH_INLINE_ALL + * #include "xxhash.h" + * + * Do not compile and link xxhash.o as a separate object, as it is not useful. + */ +#if (defined(XXH_INLINE_ALL) || defined(XXH_PRIVATE_API)) \ + && !defined(XXH_INLINE_ALL_31684351384) + /* this section should be traversed only once */ +# define XXH_INLINE_ALL_31684351384 + /* give access to the advanced API, required to compile implementations */ +# undef XXH_STATIC_LINKING_ONLY /* avoid macro redef */ +# define XXH_STATIC_LINKING_ONLY + /* make all functions private */ +# undef XXH_PUBLIC_API +# if defined(__GNUC__) +# define XXH_PUBLIC_API static __inline __attribute__((unused)) +# elif defined (__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) +# define XXH_PUBLIC_API static inline +# elif defined(_MSC_VER) +# define XXH_PUBLIC_API static __inline +# else + /* note: this version may generate warnings for unused static functions */ +# define XXH_PUBLIC_API static +# endif + + /* + * This part deals with the special case where a unit wants to inline xxHash, + * but "xxhash.h" has previously been included without XXH_INLINE_ALL, + * such as part of some previously included *.h header file. + * Without further action, the new include would just be ignored, + * and functions would effectively _not_ be inlined (silent failure). + * The following macros solve this situation by prefixing all inlined names, + * avoiding naming collision with previous inclusions. + */ + /* Before that, we unconditionally #undef all symbols, + * in case they were already defined with XXH_NAMESPACE. + * They will then be redefined for XXH_INLINE_ALL + */ +# undef XXH_versionNumber + /* XXH32 */ +# undef XXH32 +# undef XXH32_createState +# undef XXH32_freeState +# undef XXH32_reset +# undef XXH32_update +# undef XXH32_digest +# undef XXH32_copyState +# undef XXH32_canonicalFromHash +# undef XXH32_hashFromCanonical + /* XXH64 */ +# undef XXH64 +# undef XXH64_createState +# undef XXH64_freeState +# undef XXH64_reset +# undef XXH64_update +# undef XXH64_digest +# undef XXH64_copyState +# undef XXH64_canonicalFromHash +# undef XXH64_hashFromCanonical + /* XXH3_64bits */ +# undef XXH3_64bits +# undef XXH3_64bits_withSecret +# undef XXH3_64bits_withSeed +# undef XXH3_64bits_withSecretandSeed +# undef XXH3_createState +# undef XXH3_freeState +# undef XXH3_copyState +# undef XXH3_64bits_reset +# undef XXH3_64bits_reset_withSeed +# undef XXH3_64bits_reset_withSecret +# undef XXH3_64bits_update +# undef XXH3_64bits_digest +# undef XXH3_generateSecret + /* XXH3_128bits */ +# undef XXH128 +# undef XXH3_128bits +# undef XXH3_128bits_withSeed +# undef XXH3_128bits_withSecret +# undef XXH3_128bits_reset +# undef XXH3_128bits_reset_withSeed +# undef XXH3_128bits_reset_withSecret +# undef XXH3_128bits_reset_withSecretandSeed +# undef XXH3_128bits_update +# undef XXH3_128bits_digest +# undef XXH128_isEqual +# undef XXH128_cmp +# undef XXH128_canonicalFromHash +# undef XXH128_hashFromCanonical + /* Finally, free the namespace itself */ +# undef XXH_NAMESPACE + + /* employ the namespace for XXH_INLINE_ALL */ +# define XXH_NAMESPACE XXH_INLINE_ + /* + * Some identifiers (enums, type names) are not symbols, + * but they must nonetheless be renamed to avoid redeclaration. + * Alternative solution: do not redeclare them. + * However, this requires some #ifdefs, and has a more dispersed impact. + * Meanwhile, renaming can be achieved in a single place. + */ +# define XXH_IPREF(Id) XXH_NAMESPACE ## Id +# define XXH_OK XXH_IPREF(XXH_OK) +# define XXH_ERROR XXH_IPREF(XXH_ERROR) +# define XXH_errorcode XXH_IPREF(XXH_errorcode) +# define XXH32_canonical_t XXH_IPREF(XXH32_canonical_t) +# define XXH64_canonical_t XXH_IPREF(XXH64_canonical_t) +# define XXH128_canonical_t XXH_IPREF(XXH128_canonical_t) +# define XXH32_state_s XXH_IPREF(XXH32_state_s) +# define XXH32_state_t XXH_IPREF(XXH32_state_t) +# define XXH64_state_s XXH_IPREF(XXH64_state_s) +# define XXH64_state_t XXH_IPREF(XXH64_state_t) +# define XXH3_state_s XXH_IPREF(XXH3_state_s) +# define XXH3_state_t XXH_IPREF(XXH3_state_t) +# define XXH128_hash_t XXH_IPREF(XXH128_hash_t) + /* Ensure the header is parsed again, even if it was previously included */ +# undef XXHASH_H_5627135585666179 +# undef XXHASH_H_STATIC_13879238742 +#endif /* XXH_INLINE_ALL || XXH_PRIVATE_API */ + + + +/* **************************************************************** + * Stable API + *****************************************************************/ +#ifndef XXHASH_H_5627135585666179 +#define XXHASH_H_5627135585666179 1 + + +/*! + * @defgroup public Public API + * Contains details on the public xxHash functions. + * @{ + */ +/* specific declaration modes for Windows */ +#if !defined(XXH_INLINE_ALL) && !defined(XXH_PRIVATE_API) +# if defined(WIN32) && defined(_MSC_VER) && (defined(XXH_IMPORT) || defined(XXH_EXPORT)) +# ifdef XXH_EXPORT +# define XXH_PUBLIC_API __declspec(dllexport) +# elif XXH_IMPORT +# define XXH_PUBLIC_API __declspec(dllimport) +# endif +# else +# define XXH_PUBLIC_API /* do nothing */ +# endif +#endif + +#ifdef XXH_DOXYGEN +/*! + * @brief Emulate a namespace by transparently prefixing all symbols. + * + * If you want to include _and expose_ xxHash functions from within your own + * library, but also want to avoid symbol collisions with other libraries which + * may also include xxHash, you can use XXH_NAMESPACE to automatically prefix + * any public symbol from xxhash library with the value of XXH_NAMESPACE + * (therefore, avoid empty or numeric values). + * + * Note that no change is required within the calling program as long as it + * includes `xxhash.h`: Regular symbol names will be automatically translated + * by this header. + */ +# define XXH_NAMESPACE /* YOUR NAME HERE */ +# undef XXH_NAMESPACE +#endif + +#ifdef XXH_NAMESPACE +# define XXH_CAT(A,B) A##B +# define XXH_NAME2(A,B) XXH_CAT(A,B) +# define XXH_versionNumber XXH_NAME2(XXH_NAMESPACE, XXH_versionNumber) +/* XXH32 */ +# define XXH32 XXH_NAME2(XXH_NAMESPACE, XXH32) +# define XXH32_createState XXH_NAME2(XXH_NAMESPACE, XXH32_createState) +# define XXH32_freeState XXH_NAME2(XXH_NAMESPACE, XXH32_freeState) +# define XXH32_reset XXH_NAME2(XXH_NAMESPACE, XXH32_reset) +# define XXH32_update XXH_NAME2(XXH_NAMESPACE, XXH32_update) +# define XXH32_digest XXH_NAME2(XXH_NAMESPACE, XXH32_digest) +# define XXH32_copyState XXH_NAME2(XXH_NAMESPACE, XXH32_copyState) +# define XXH32_canonicalFromHash XXH_NAME2(XXH_NAMESPACE, XXH32_canonicalFromHash) +# define XXH32_hashFromCanonical XXH_NAME2(XXH_NAMESPACE, XXH32_hashFromCanonical) +/* XXH64 */ +# define XXH64 XXH_NAME2(XXH_NAMESPACE, XXH64) +# define XXH64_createState XXH_NAME2(XXH_NAMESPACE, XXH64_createState) +# define XXH64_freeState XXH_NAME2(XXH_NAMESPACE, XXH64_freeState) +# define XXH64_reset XXH_NAME2(XXH_NAMESPACE, XXH64_reset) +# define XXH64_update XXH_NAME2(XXH_NAMESPACE, XXH64_update) +# define XXH64_digest XXH_NAME2(XXH_NAMESPACE, XXH64_digest) +# define XXH64_copyState XXH_NAME2(XXH_NAMESPACE, XXH64_copyState) +# define XXH64_canonicalFromHash XXH_NAME2(XXH_NAMESPACE, XXH64_canonicalFromHash) +# define XXH64_hashFromCanonical XXH_NAME2(XXH_NAMESPACE, XXH64_hashFromCanonical) +/* XXH3_64bits */ +# define XXH3_64bits XXH_NAME2(XXH_NAMESPACE, XXH3_64bits) +# define XXH3_64bits_withSecret XXH_NAME2(XXH_NAMESPACE, XXH3_64bits_withSecret) +# define XXH3_64bits_withSeed XXH_NAME2(XXH_NAMESPACE, XXH3_64bits_withSeed) +# define XXH3_64bits_withSecretandSeed XXH_NAME2(XXH_NAMESPACE, XXH3_64bits_withSecretandSeed) +# define XXH3_createState XXH_NAME2(XXH_NAMESPACE, XXH3_createState) +# define XXH3_freeState XXH_NAME2(XXH_NAMESPACE, XXH3_freeState) +# define XXH3_copyState XXH_NAME2(XXH_NAMESPACE, XXH3_copyState) +# define XXH3_64bits_reset XXH_NAME2(XXH_NAMESPACE, XXH3_64bits_reset) +# define XXH3_64bits_reset_withSeed XXH_NAME2(XXH_NAMESPACE, XXH3_64bits_reset_withSeed) +# define XXH3_64bits_reset_withSecret XXH_NAME2(XXH_NAMESPACE, XXH3_64bits_reset_withSecret) +# define XXH3_64bits_reset_withSecretandSeed XXH_NAME2(XXH_NAMESPACE, XXH3_64bits_reset_withSecretandSeed) +# define XXH3_64bits_update XXH_NAME2(XXH_NAMESPACE, XXH3_64bits_update) +# define XXH3_64bits_digest XXH_NAME2(XXH_NAMESPACE, XXH3_64bits_digest) +# define XXH3_generateSecret XXH_NAME2(XXH_NAMESPACE, XXH3_generateSecret) +# define XXH3_generateSecret_fromSeed XXH_NAME2(XXH_NAMESPACE, XXH3_generateSecret_fromSeed) +/* XXH3_128bits */ +# define XXH128 XXH_NAME2(XXH_NAMESPACE, XXH128) +# define XXH3_128bits XXH_NAME2(XXH_NAMESPACE, XXH3_128bits) +# define XXH3_128bits_withSeed XXH_NAME2(XXH_NAMESPACE, XXH3_128bits_withSeed) +# define XXH3_128bits_withSecret XXH_NAME2(XXH_NAMESPACE, XXH3_128bits_withSecret) +# define XXH3_128bits_withSecretandSeed XXH_NAME2(XXH_NAMESPACE, XXH3_128bits_withSecretandSeed) +# define XXH3_128bits_reset XXH_NAME2(XXH_NAMESPACE, XXH3_128bits_reset) +# define XXH3_128bits_reset_withSeed XXH_NAME2(XXH_NAMESPACE, XXH3_128bits_reset_withSeed) +# define XXH3_128bits_reset_withSecret XXH_NAME2(XXH_NAMESPACE, XXH3_128bits_reset_withSecret) +# define XXH3_128bits_reset_withSecretandSeed XXH_NAME2(XXH_NAMESPACE, XXH3_128bits_reset_withSecretandSeed) +# define XXH3_128bits_update XXH_NAME2(XXH_NAMESPACE, XXH3_128bits_update) +# define XXH3_128bits_digest XXH_NAME2(XXH_NAMESPACE, XXH3_128bits_digest) +# define XXH128_isEqual XXH_NAME2(XXH_NAMESPACE, XXH128_isEqual) +# define XXH128_cmp XXH_NAME2(XXH_NAMESPACE, XXH128_cmp) +# define XXH128_canonicalFromHash XXH_NAME2(XXH_NAMESPACE, XXH128_canonicalFromHash) +# define XXH128_hashFromCanonical XXH_NAME2(XXH_NAMESPACE, XXH128_hashFromCanonical) +#endif + + +/* ************************************* +* Version +***************************************/ +#define XXH_VERSION_MAJOR 0 +#define XXH_VERSION_MINOR 8 +#define XXH_VERSION_RELEASE 1 +#define XXH_VERSION_NUMBER (XXH_VERSION_MAJOR *100*100 + XXH_VERSION_MINOR *100 + XXH_VERSION_RELEASE) + +/*! + * @brief Obtains the xxHash version. + * + * This is mostly useful when xxHash is compiled as a shared library, + * since the returned value comes from the library, as opposed to header file. + * + * @return `XXH_VERSION_NUMBER` of the invoked library. + */ +XXH_PUBLIC_API unsigned XXH_versionNumber (void); + + +/* **************************** +* Common basic types +******************************/ +#include /* size_t */ +typedef enum { XXH_OK=0, XXH_ERROR } XXH_errorcode; + + +/*-********************************************************************** +* 32-bit hash +************************************************************************/ +#if defined(XXH_DOXYGEN) /* Don't show include */ +/*! + * @brief An unsigned 32-bit integer. + * + * Not necessarily defined to `uint32_t` but functionally equivalent. + */ +typedef uint32_t XXH32_hash_t; + +#elif !defined (__VMS) \ + && (defined (__cplusplus) \ + || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) ) +# include + typedef uint32_t XXH32_hash_t; + +#else +# include +# if UINT_MAX == 0xFFFFFFFFUL + typedef unsigned int XXH32_hash_t; +# else +# if ULONG_MAX == 0xFFFFFFFFUL + typedef unsigned long XXH32_hash_t; +# else +# error "unsupported platform: need a 32-bit type" +# endif +# endif +#endif + +/*! + * @} + * + * @defgroup xxh32_family XXH32 family + * @ingroup public + * Contains functions used in the classic 32-bit xxHash algorithm. + * + * @note + * XXH32 is useful for older platforms, with no or poor 64-bit performance. + * Note that @ref xxh3_family provides competitive speed + * for both 32-bit and 64-bit systems, and offers true 64/128 bit hash results. + * + * @see @ref xxh64_family, @ref xxh3_family : Other xxHash families + * @see @ref xxh32_impl for implementation details + * @{ + */ + +/*! + * @brief Calculates the 32-bit hash of @p input using xxHash32. + * + * Speed on Core 2 Duo @ 3 GHz (single thread, SMHasher benchmark): 5.4 GB/s + * + * @param input The block of data to be hashed, at least @p length bytes in size. + * @param length The length of @p input, in bytes. + * @param seed The 32-bit seed to alter the hash's output predictably. + * + * @pre + * The memory between @p input and @p input + @p length must be valid, + * readable, contiguous memory. However, if @p length is `0`, @p input may be + * `NULL`. In C++, this also must be *TriviallyCopyable*. + * + * @return The calculated 32-bit hash value. + * + * @see + * XXH64(), XXH3_64bits_withSeed(), XXH3_128bits_withSeed(), XXH128(): + * Direct equivalents for the other variants of xxHash. + * @see + * XXH32_createState(), XXH32_update(), XXH32_digest(): Streaming version. + */ +XXH_PUBLIC_API XXH32_hash_t XXH32 (const void* input, size_t length, XXH32_hash_t seed); + +/*! + * Streaming functions generate the xxHash value from an incremental input. + * This method is slower than single-call functions, due to state management. + * For small inputs, prefer `XXH32()` and `XXH64()`, which are better optimized. + * + * An XXH state must first be allocated using `XXH*_createState()`. + * + * Start a new hash by initializing the state with a seed using `XXH*_reset()`. + * + * Then, feed the hash state by calling `XXH*_update()` as many times as necessary. + * + * The function returns an error code, with 0 meaning OK, and any other value + * meaning there is an error. + * + * Finally, a hash value can be produced anytime, by using `XXH*_digest()`. + * This function returns the nn-bits hash as an int or long long. + * + * It's still possible to continue inserting input into the hash state after a + * digest, and generate new hash values later on by invoking `XXH*_digest()`. + * + * When done, release the state using `XXH*_freeState()`. + * + * Example code for incrementally hashing a file: + * @code{.c} + * #include + * #include + * #define BUFFER_SIZE 256 + * + * // Note: XXH64 and XXH3 use the same interface. + * XXH32_hash_t + * hashFile(FILE* stream) + * { + * XXH32_state_t* state; + * unsigned char buf[BUFFER_SIZE]; + * size_t amt; + * XXH32_hash_t hash; + * + * state = XXH32_createState(); // Create a state + * assert(state != NULL); // Error check here + * XXH32_reset(state, 0xbaad5eed); // Reset state with our seed + * while ((amt = fread(buf, 1, sizeof(buf), stream)) != 0) { + * XXH32_update(state, buf, amt); // Hash the file in chunks + * } + * hash = XXH32_digest(state); // Finalize the hash + * XXH32_freeState(state); // Clean up + * return hash; + * } + * @endcode + */ + +/*! + * @typedef struct XXH32_state_s XXH32_state_t + * @brief The opaque state struct for the XXH32 streaming API. + * + * @see XXH32_state_s for details. + */ +typedef struct XXH32_state_s XXH32_state_t; + +/*! + * @brief Allocates an @ref XXH32_state_t. + * + * Must be freed with XXH32_freeState(). + * @return An allocated XXH32_state_t on success, `NULL` on failure. + */ +XXH_PUBLIC_API XXH32_state_t* XXH32_createState(void); +/*! + * @brief Frees an @ref XXH32_state_t. + * + * Must be allocated with XXH32_createState(). + * @param statePtr A pointer to an @ref XXH32_state_t allocated with @ref XXH32_createState(). + * @return XXH_OK. + */ +XXH_PUBLIC_API XXH_errorcode XXH32_freeState(XXH32_state_t* statePtr); +/*! + * @brief Copies one @ref XXH32_state_t to another. + * + * @param dst_state The state to copy to. + * @param src_state The state to copy from. + * @pre + * @p dst_state and @p src_state must not be `NULL` and must not overlap. + */ +XXH_PUBLIC_API void XXH32_copyState(XXH32_state_t* dst_state, const XXH32_state_t* src_state); + +/*! + * @brief Resets an @ref XXH32_state_t to begin a new hash. + * + * This function resets and seeds a state. Call it before @ref XXH32_update(). + * + * @param statePtr The state struct to reset. + * @param seed The 32-bit seed to alter the hash result predictably. + * + * @pre + * @p statePtr must not be `NULL`. + * + * @return @ref XXH_OK on success, @ref XXH_ERROR on failure. + */ +XXH_PUBLIC_API XXH_errorcode XXH32_reset (XXH32_state_t* statePtr, XXH32_hash_t seed); + +/*! + * @brief Consumes a block of @p input to an @ref XXH32_state_t. + * + * Call this to incrementally consume blocks of data. + * + * @param statePtr The state struct to update. + * @param input The block of data to be hashed, at least @p length bytes in size. + * @param length The length of @p input, in bytes. + * + * @pre + * @p statePtr must not be `NULL`. + * @pre + * The memory between @p input and @p input + @p length must be valid, + * readable, contiguous memory. However, if @p length is `0`, @p input may be + * `NULL`. In C++, this also must be *TriviallyCopyable*. + * + * @return @ref XXH_OK on success, @ref XXH_ERROR on failure. + */ +XXH_PUBLIC_API XXH_errorcode XXH32_update (XXH32_state_t* statePtr, const void* input, size_t length); + +/*! + * @brief Returns the calculated hash value from an @ref XXH32_state_t. + * + * @note + * Calling XXH32_digest() will not affect @p statePtr, so you can update, + * digest, and update again. + * + * @param statePtr The state struct to calculate the hash from. + * + * @pre + * @p statePtr must not be `NULL`. + * + * @return The calculated xxHash32 value from that state. + */ +XXH_PUBLIC_API XXH32_hash_t XXH32_digest (const XXH32_state_t* statePtr); + +/******* Canonical representation *******/ + +/* + * The default return values from XXH functions are unsigned 32 and 64 bit + * integers. + * This the simplest and fastest format for further post-processing. + * + * However, this leaves open the question of what is the order on the byte level, + * since little and big endian conventions will store the same number differently. + * + * The canonical representation settles this issue by mandating big-endian + * convention, the same convention as human-readable numbers (large digits first). + * + * When writing hash values to storage, sending them over a network, or printing + * them, it's highly recommended to use the canonical representation to ensure + * portability across a wider range of systems, present and future. + * + * The following functions allow transformation of hash values to and from + * canonical format. + */ + +/*! + * @brief Canonical (big endian) representation of @ref XXH32_hash_t. + */ +typedef struct { + unsigned char digest[4]; /*!< Hash bytes, big endian */ +} XXH32_canonical_t; + +/*! + * @brief Converts an @ref XXH32_hash_t to a big endian @ref XXH32_canonical_t. + * + * @param dst The @ref XXH32_canonical_t pointer to be stored to. + * @param hash The @ref XXH32_hash_t to be converted. + * + * @pre + * @p dst must not be `NULL`. + */ +XXH_PUBLIC_API void XXH32_canonicalFromHash(XXH32_canonical_t* dst, XXH32_hash_t hash); + +/*! + * @brief Converts an @ref XXH32_canonical_t to a native @ref XXH32_hash_t. + * + * @param src The @ref XXH32_canonical_t to convert. + * + * @pre + * @p src must not be `NULL`. + * + * @return The converted hash. + */ +XXH_PUBLIC_API XXH32_hash_t XXH32_hashFromCanonical(const XXH32_canonical_t* src); + + +#ifdef __has_attribute +# define XXH_HAS_ATTRIBUTE(x) __has_attribute(x) +#else +# define XXH_HAS_ATTRIBUTE(x) 0 +#endif + +/* C-language Attributes are added in C23. */ +#if defined(__STDC_VERSION__) && (__STDC_VERSION__ > 201710L) && defined(__has_c_attribute) +# define XXH_HAS_C_ATTRIBUTE(x) __has_c_attribute(x) +#else +# define XXH_HAS_C_ATTRIBUTE(x) 0 +#endif + +#if defined(__cplusplus) && defined(__has_cpp_attribute) +# define XXH_HAS_CPP_ATTRIBUTE(x) __has_cpp_attribute(x) +#else +# define XXH_HAS_CPP_ATTRIBUTE(x) 0 +#endif + +/* +Define XXH_FALLTHROUGH macro for annotating switch case with the 'fallthrough' attribute +introduced in CPP17 and C23. +CPP17 : https://en.cppreference.com/w/cpp/language/attributes/fallthrough +C23 : https://en.cppreference.com/w/c/language/attributes/fallthrough +*/ +#if XXH_HAS_C_ATTRIBUTE(x) +# define XXH_FALLTHROUGH [[fallthrough]] +#elif XXH_HAS_CPP_ATTRIBUTE(x) +# define XXH_FALLTHROUGH [[fallthrough]] +#elif XXH_HAS_ATTRIBUTE(__fallthrough__) +# define XXH_FALLTHROUGH __attribute__ ((fallthrough)) +#else +# define XXH_FALLTHROUGH +#endif + +/*! + * @} + * @ingroup public + * @{ + */ + +#ifndef XXH_NO_LONG_LONG +/*-********************************************************************** +* 64-bit hash +************************************************************************/ +#if defined(XXH_DOXYGEN) /* don't include */ +/*! + * @brief An unsigned 64-bit integer. + * + * Not necessarily defined to `uint64_t` but functionally equivalent. + */ +typedef uint64_t XXH64_hash_t; +#elif !defined (__VMS) \ + && (defined (__cplusplus) \ + || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) ) +# include + typedef uint64_t XXH64_hash_t; +#else +# include +# if defined(__LP64__) && ULONG_MAX == 0xFFFFFFFFFFFFFFFFULL + /* LP64 ABI says uint64_t is unsigned long */ + typedef unsigned long XXH64_hash_t; +# else + /* the following type must have a width of 64-bit */ + typedef unsigned long long XXH64_hash_t; +# endif +#endif + +/*! + * @} + * + * @defgroup xxh64_family XXH64 family + * @ingroup public + * @{ + * Contains functions used in the classic 64-bit xxHash algorithm. + * + * @note + * XXH3 provides competitive speed for both 32-bit and 64-bit systems, + * and offers true 64/128 bit hash results. + * It provides better speed for systems with vector processing capabilities. + */ + + +/*! + * @brief Calculates the 64-bit hash of @p input using xxHash64. + * + * This function usually runs faster on 64-bit systems, but slower on 32-bit + * systems (see benchmark). + * + * @param input The block of data to be hashed, at least @p length bytes in size. + * @param length The length of @p input, in bytes. + * @param seed The 64-bit seed to alter the hash's output predictably. + * + * @pre + * The memory between @p input and @p input + @p length must be valid, + * readable, contiguous memory. However, if @p length is `0`, @p input may be + * `NULL`. In C++, this also must be *TriviallyCopyable*. + * + * @return The calculated 64-bit hash. + * + * @see + * XXH32(), XXH3_64bits_withSeed(), XXH3_128bits_withSeed(), XXH128(): + * Direct equivalents for the other variants of xxHash. + * @see + * XXH64_createState(), XXH64_update(), XXH64_digest(): Streaming version. + */ +XXH_PUBLIC_API XXH64_hash_t XXH64(const void* input, size_t length, XXH64_hash_t seed); + +/******* Streaming *******/ +/*! + * @brief The opaque state struct for the XXH64 streaming API. + * + * @see XXH64_state_s for details. + */ +typedef struct XXH64_state_s XXH64_state_t; /* incomplete type */ +XXH_PUBLIC_API XXH64_state_t* XXH64_createState(void); +XXH_PUBLIC_API XXH_errorcode XXH64_freeState(XXH64_state_t* statePtr); +XXH_PUBLIC_API void XXH64_copyState(XXH64_state_t* dst_state, const XXH64_state_t* src_state); + +XXH_PUBLIC_API XXH_errorcode XXH64_reset (XXH64_state_t* statePtr, XXH64_hash_t seed); +XXH_PUBLIC_API XXH_errorcode XXH64_update (XXH64_state_t* statePtr, const void* input, size_t length); +XXH_PUBLIC_API XXH64_hash_t XXH64_digest (const XXH64_state_t* statePtr); + +/******* Canonical representation *******/ +typedef struct { unsigned char digest[sizeof(XXH64_hash_t)]; } XXH64_canonical_t; +XXH_PUBLIC_API void XXH64_canonicalFromHash(XXH64_canonical_t* dst, XXH64_hash_t hash); +XXH_PUBLIC_API XXH64_hash_t XXH64_hashFromCanonical(const XXH64_canonical_t* src); + +#ifndef XXH_NO_XXH3 +/*! + * @} + * ************************************************************************ + * @defgroup xxh3_family XXH3 family + * @ingroup public + * @{ + * + * XXH3 is a more recent hash algorithm featuring: + * - Improved speed for both small and large inputs + * - True 64-bit and 128-bit outputs + * - SIMD acceleration + * - Improved 32-bit viability + * + * Speed analysis methodology is explained here: + * + * https://fastcompression.blogspot.com/2019/03/presenting-xxh3.html + * + * Compared to XXH64, expect XXH3 to run approximately + * ~2x faster on large inputs and >3x faster on small ones, + * exact differences vary depending on platform. + * + * XXH3's speed benefits greatly from SIMD and 64-bit arithmetic, + * but does not require it. + * Any 32-bit and 64-bit targets that can run XXH32 smoothly + * can run XXH3 at competitive speeds, even without vector support. + * Further details are explained in the implementation. + * + * Optimized implementations are provided for AVX512, AVX2, SSE2, NEON, POWER8, + * ZVector and scalar targets. This can be controlled via the XXH_VECTOR macro. + * + * XXH3 implementation is portable: + * it has a generic C90 formulation that can be compiled on any platform, + * all implementations generage exactly the same hash value on all platforms. + * Starting from v0.8.0, it's also labelled "stable", meaning that + * any future version will also generate the same hash value. + * + * XXH3 offers 2 variants, _64bits and _128bits. + * + * When only 64 bits are needed, prefer invoking the _64bits variant, as it + * reduces the amount of mixing, resulting in faster speed on small inputs. + * It's also generally simpler to manipulate a scalar return type than a struct. + * + * The API supports one-shot hashing, streaming mode, and custom secrets. + */ + +/*-********************************************************************** +* XXH3 64-bit variant +************************************************************************/ + +/* XXH3_64bits(): + * default 64-bit variant, using default secret and default seed of 0. + * It's the fastest variant. */ +XXH_PUBLIC_API XXH64_hash_t XXH3_64bits(const void* data, size_t len); + +/* + * XXH3_64bits_withSeed(): + * This variant generates a custom secret on the fly + * based on default secret altered using the `seed` value. + * While this operation is decently fast, note that it's not completely free. + * Note: seed==0 produces the same results as XXH3_64bits(). + */ +XXH_PUBLIC_API XXH64_hash_t XXH3_64bits_withSeed(const void* data, size_t len, XXH64_hash_t seed); + +/*! + * The bare minimum size for a custom secret. + * + * @see + * XXH3_64bits_withSecret(), XXH3_64bits_reset_withSecret(), + * XXH3_128bits_withSecret(), XXH3_128bits_reset_withSecret(). + */ +#define XXH3_SECRET_SIZE_MIN 136 + +/* + * XXH3_64bits_withSecret(): + * It's possible to provide any blob of bytes as a "secret" to generate the hash. + * This makes it more difficult for an external actor to prepare an intentional collision. + * The main condition is that secretSize *must* be large enough (>= XXH3_SECRET_SIZE_MIN). + * However, the quality of the secret impacts the dispersion of the hash algorithm. + * Therefore, the secret _must_ look like a bunch of random bytes. + * Avoid "trivial" or structured data such as repeated sequences or a text document. + * Whenever in doubt about the "randomness" of the blob of bytes, + * consider employing "XXH3_generateSecret()" instead (see below). + * It will generate a proper high entropy secret derived from the blob of bytes. + * Another advantage of using XXH3_generateSecret() is that + * it guarantees that all bits within the initial blob of bytes + * will impact every bit of the output. + * This is not necessarily the case when using the blob of bytes directly + * because, when hashing _small_ inputs, only a portion of the secret is employed. + */ +XXH_PUBLIC_API XXH64_hash_t XXH3_64bits_withSecret(const void* data, size_t len, const void* secret, size_t secretSize); + + +/******* Streaming *******/ +/* + * Streaming requires state maintenance. + * This operation costs memory and CPU. + * As a consequence, streaming is slower than one-shot hashing. + * For better performance, prefer one-shot functions whenever applicable. + */ + +/*! + * @brief The state struct for the XXH3 streaming API. + * + * @see XXH3_state_s for details. + */ +typedef struct XXH3_state_s XXH3_state_t; +XXH_PUBLIC_API XXH3_state_t* XXH3_createState(void); +XXH_PUBLIC_API XXH_errorcode XXH3_freeState(XXH3_state_t* statePtr); +XXH_PUBLIC_API void XXH3_copyState(XXH3_state_t* dst_state, const XXH3_state_t* src_state); + +/* + * XXH3_64bits_reset(): + * Initialize with default parameters. + * digest will be equivalent to `XXH3_64bits()`. + */ +XXH_PUBLIC_API XXH_errorcode XXH3_64bits_reset(XXH3_state_t* statePtr); +/* + * XXH3_64bits_reset_withSeed(): + * Generate a custom secret from `seed`, and store it into `statePtr`. + * digest will be equivalent to `XXH3_64bits_withSeed()`. + */ +XXH_PUBLIC_API XXH_errorcode XXH3_64bits_reset_withSeed(XXH3_state_t* statePtr, XXH64_hash_t seed); +/* + * XXH3_64bits_reset_withSecret(): + * `secret` is referenced, it _must outlive_ the hash streaming session. + * Similar to one-shot API, `secretSize` must be >= `XXH3_SECRET_SIZE_MIN`, + * and the quality of produced hash values depends on secret's entropy + * (secret's content should look like a bunch of random bytes). + * When in doubt about the randomness of a candidate `secret`, + * consider employing `XXH3_generateSecret()` instead (see below). + */ +XXH_PUBLIC_API XXH_errorcode XXH3_64bits_reset_withSecret(XXH3_state_t* statePtr, const void* secret, size_t secretSize); + +XXH_PUBLIC_API XXH_errorcode XXH3_64bits_update (XXH3_state_t* statePtr, const void* input, size_t length); +XXH_PUBLIC_API XXH64_hash_t XXH3_64bits_digest (const XXH3_state_t* statePtr); + +/* note : canonical representation of XXH3 is the same as XXH64 + * since they both produce XXH64_hash_t values */ + + +/*-********************************************************************** +* XXH3 128-bit variant +************************************************************************/ + +/*! + * @brief The return value from 128-bit hashes. + * + * Stored in little endian order, although the fields themselves are in native + * endianness. + */ +typedef struct { + XXH64_hash_t low64; /*!< `value & 0xFFFFFFFFFFFFFFFF` */ + XXH64_hash_t high64; /*!< `value >> 64` */ +} XXH128_hash_t; + +XXH_PUBLIC_API XXH128_hash_t XXH3_128bits(const void* data, size_t len); +XXH_PUBLIC_API XXH128_hash_t XXH3_128bits_withSeed(const void* data, size_t len, XXH64_hash_t seed); +XXH_PUBLIC_API XXH128_hash_t XXH3_128bits_withSecret(const void* data, size_t len, const void* secret, size_t secretSize); + +/******* Streaming *******/ +/* + * Streaming requires state maintenance. + * This operation costs memory and CPU. + * As a consequence, streaming is slower than one-shot hashing. + * For better performance, prefer one-shot functions whenever applicable. + * + * XXH3_128bits uses the same XXH3_state_t as XXH3_64bits(). + * Use already declared XXH3_createState() and XXH3_freeState(). + * + * All reset and streaming functions have same meaning as their 64-bit counterpart. + */ + +XXH_PUBLIC_API XXH_errorcode XXH3_128bits_reset(XXH3_state_t* statePtr); +XXH_PUBLIC_API XXH_errorcode XXH3_128bits_reset_withSeed(XXH3_state_t* statePtr, XXH64_hash_t seed); +XXH_PUBLIC_API XXH_errorcode XXH3_128bits_reset_withSecret(XXH3_state_t* statePtr, const void* secret, size_t secretSize); + +XXH_PUBLIC_API XXH_errorcode XXH3_128bits_update (XXH3_state_t* statePtr, const void* input, size_t length); +XXH_PUBLIC_API XXH128_hash_t XXH3_128bits_digest (const XXH3_state_t* statePtr); + +/* Following helper functions make it possible to compare XXH128_hast_t values. + * Since XXH128_hash_t is a structure, this capability is not offered by the language. + * Note: For better performance, these functions can be inlined using XXH_INLINE_ALL */ + +/*! + * XXH128_isEqual(): + * Return: 1 if `h1` and `h2` are equal, 0 if they are not. + */ +XXH_PUBLIC_API int XXH128_isEqual(XXH128_hash_t h1, XXH128_hash_t h2); + +/*! + * XXH128_cmp(): + * + * This comparator is compatible with stdlib's `qsort()`/`bsearch()`. + * + * return: >0 if *h128_1 > *h128_2 + * =0 if *h128_1 == *h128_2 + * <0 if *h128_1 < *h128_2 + */ +XXH_PUBLIC_API int XXH128_cmp(const void* h128_1, const void* h128_2); + + +/******* Canonical representation *******/ +typedef struct { unsigned char digest[sizeof(XXH128_hash_t)]; } XXH128_canonical_t; +XXH_PUBLIC_API void XXH128_canonicalFromHash(XXH128_canonical_t* dst, XXH128_hash_t hash); +XXH_PUBLIC_API XXH128_hash_t XXH128_hashFromCanonical(const XXH128_canonical_t* src); + + +#endif /* !XXH_NO_XXH3 */ +#endif /* XXH_NO_LONG_LONG */ + +/*! + * @} + */ +#endif /* XXHASH_H_5627135585666179 */ + + + +#if defined(XXH_STATIC_LINKING_ONLY) && !defined(XXHASH_H_STATIC_13879238742) +#define XXHASH_H_STATIC_13879238742 +/* **************************************************************************** + * This section contains declarations which are not guaranteed to remain stable. + * They may change in future versions, becoming incompatible with a different + * version of the library. + * These declarations should only be used with static linking. + * Never use them in association with dynamic linking! + ***************************************************************************** */ + +/* + * These definitions are only present to allow static allocation + * of XXH states, on stack or in a struct, for example. + * Never **ever** access their members directly. + */ + +/*! + * @internal + * @brief Structure for XXH32 streaming API. + * + * @note This is only defined when @ref XXH_STATIC_LINKING_ONLY, + * @ref XXH_INLINE_ALL, or @ref XXH_IMPLEMENTATION is defined. Otherwise it is + * an opaque type. This allows fields to safely be changed. + * + * Typedef'd to @ref XXH32_state_t. + * Do not access the members of this struct directly. + * @see XXH64_state_s, XXH3_state_s + */ +struct XXH32_state_s { + XXH32_hash_t total_len_32; /*!< Total length hashed, modulo 2^32 */ + XXH32_hash_t large_len; /*!< Whether the hash is >= 16 (handles @ref total_len_32 overflow) */ + XXH32_hash_t v[4]; /*!< Accumulator lanes */ + XXH32_hash_t mem32[4]; /*!< Internal buffer for partial reads. Treated as unsigned char[16]. */ + XXH32_hash_t memsize; /*!< Amount of data in @ref mem32 */ + XXH32_hash_t reserved; /*!< Reserved field. Do not read nor write to it. */ +}; /* typedef'd to XXH32_state_t */ + + +#ifndef XXH_NO_LONG_LONG /* defined when there is no 64-bit support */ + +/*! + * @internal + * @brief Structure for XXH64 streaming API. + * + * @note This is only defined when @ref XXH_STATIC_LINKING_ONLY, + * @ref XXH_INLINE_ALL, or @ref XXH_IMPLEMENTATION is defined. Otherwise it is + * an opaque type. This allows fields to safely be changed. + * + * Typedef'd to @ref XXH64_state_t. + * Do not access the members of this struct directly. + * @see XXH32_state_s, XXH3_state_s + */ +struct XXH64_state_s { + XXH64_hash_t total_len; /*!< Total length hashed. This is always 64-bit. */ + XXH64_hash_t v[4]; /*!< Accumulator lanes */ + XXH64_hash_t mem64[4]; /*!< Internal buffer for partial reads. Treated as unsigned char[32]. */ + XXH32_hash_t memsize; /*!< Amount of data in @ref mem64 */ + XXH32_hash_t reserved32; /*!< Reserved field, needed for padding anyways*/ + XXH64_hash_t reserved64; /*!< Reserved field. Do not read or write to it. */ +}; /* typedef'd to XXH64_state_t */ + + +#ifndef XXH_NO_XXH3 + +#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L) /* >= C11 */ +# include +# define XXH_ALIGN(n) alignas(n) +#elif defined(__cplusplus) && (__cplusplus >= 201103L) /* >= C++11 */ +/* In C++ alignas() is a keyword */ +# define XXH_ALIGN(n) alignas(n) +#elif defined(__GNUC__) +# define XXH_ALIGN(n) __attribute__ ((aligned(n))) +#elif defined(_MSC_VER) +# define XXH_ALIGN(n) __declspec(align(n)) +#else +# define XXH_ALIGN(n) /* disabled */ +#endif + +/* Old GCC versions only accept the attribute after the type in structures. */ +#if !(defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L)) /* C11+ */ \ + && ! (defined(__cplusplus) && (__cplusplus >= 201103L)) /* >= C++11 */ \ + && defined(__GNUC__) +# define XXH_ALIGN_MEMBER(align, type) type XXH_ALIGN(align) +#else +# define XXH_ALIGN_MEMBER(align, type) XXH_ALIGN(align) type +#endif + +/*! + * @brief The size of the internal XXH3 buffer. + * + * This is the optimal update size for incremental hashing. + * + * @see XXH3_64b_update(), XXH3_128b_update(). + */ +#define XXH3_INTERNALBUFFER_SIZE 256 + +/*! + * @brief Default size of the secret buffer (and @ref XXH3_kSecret). + * + * This is the size used in @ref XXH3_kSecret and the seeded functions. + * + * Not to be confused with @ref XXH3_SECRET_SIZE_MIN. + */ +#define XXH3_SECRET_DEFAULT_SIZE 192 + +/*! + * @internal + * @brief Structure for XXH3 streaming API. + * + * @note This is only defined when @ref XXH_STATIC_LINKING_ONLY, + * @ref XXH_INLINE_ALL, or @ref XXH_IMPLEMENTATION is defined. + * Otherwise it is an opaque type. + * Never use this definition in combination with dynamic library. + * This allows fields to safely be changed in the future. + * + * @note ** This structure has a strict alignment requirement of 64 bytes!! ** + * Do not allocate this with `malloc()` or `new`, + * it will not be sufficiently aligned. + * Use @ref XXH3_createState() and @ref XXH3_freeState(), or stack allocation. + * + * Typedef'd to @ref XXH3_state_t. + * Do never access the members of this struct directly. + * + * @see XXH3_INITSTATE() for stack initialization. + * @see XXH3_createState(), XXH3_freeState(). + * @see XXH32_state_s, XXH64_state_s + */ +struct XXH3_state_s { + XXH_ALIGN_MEMBER(64, XXH64_hash_t acc[8]); + /*!< The 8 accumulators. Similar to `vN` in @ref XXH32_state_s::v1 and @ref XXH64_state_s */ + XXH_ALIGN_MEMBER(64, unsigned char customSecret[XXH3_SECRET_DEFAULT_SIZE]); + /*!< Used to store a custom secret generated from a seed. */ + XXH_ALIGN_MEMBER(64, unsigned char buffer[XXH3_INTERNALBUFFER_SIZE]); + /*!< The internal buffer. @see XXH32_state_s::mem32 */ + XXH32_hash_t bufferedSize; + /*!< The amount of memory in @ref buffer, @see XXH32_state_s::memsize */ + XXH32_hash_t useSeed; + /*!< Reserved field. Needed for padding on 64-bit. */ + size_t nbStripesSoFar; + /*!< Number or stripes processed. */ + XXH64_hash_t totalLen; + /*!< Total length hashed. 64-bit even on 32-bit targets. */ + size_t nbStripesPerBlock; + /*!< Number of stripes per block. */ + size_t secretLimit; + /*!< Size of @ref customSecret or @ref extSecret */ + XXH64_hash_t seed; + /*!< Seed for _withSeed variants. Must be zero otherwise, @see XXH3_INITSTATE() */ + XXH64_hash_t reserved64; + /*!< Reserved field. */ + const unsigned char* extSecret; + /*!< Reference to an external secret for the _withSecret variants, NULL + * for other variants. */ + /* note: there may be some padding at the end due to alignment on 64 bytes */ +}; /* typedef'd to XXH3_state_t */ + +#undef XXH_ALIGN_MEMBER + +/*! + * @brief Initializes a stack-allocated `XXH3_state_s`. + * + * When the @ref XXH3_state_t structure is merely emplaced on stack, + * it should be initialized with XXH3_INITSTATE() or a memset() + * in case its first reset uses XXH3_NNbits_reset_withSeed(). + * This init can be omitted if the first reset uses default or _withSecret mode. + * This operation isn't necessary when the state is created with XXH3_createState(). + * Note that this doesn't prepare the state for a streaming operation, + * it's still necessary to use XXH3_NNbits_reset*() afterwards. + */ +#define XXH3_INITSTATE(XXH3_state_ptr) { (XXH3_state_ptr)->seed = 0; } + + +/* XXH128() : + * simple alias to pre-selected XXH3_128bits variant + */ +XXH_PUBLIC_API XXH128_hash_t XXH128(const void* data, size_t len, XXH64_hash_t seed); + + +/* === Experimental API === */ +/* Symbols defined below must be considered tied to a specific library version. */ + +/* + * XXH3_generateSecret(): + * + * Derive a high-entropy secret from any user-defined content, named customSeed. + * The generated secret can be used in combination with `*_withSecret()` functions. + * The `_withSecret()` variants are useful to provide a higher level of protection than 64-bit seed, + * as it becomes much more difficult for an external actor to guess how to impact the calculation logic. + * + * The function accepts as input a custom seed of any length and any content, + * and derives from it a high-entropy secret of length @secretSize + * into an already allocated buffer @secretBuffer. + * @secretSize must be >= XXH3_SECRET_SIZE_MIN + * + * The generated secret can then be used with any `*_withSecret()` variant. + * Functions `XXH3_128bits_withSecret()`, `XXH3_64bits_withSecret()`, + * `XXH3_128bits_reset_withSecret()` and `XXH3_64bits_reset_withSecret()` + * are part of this list. They all accept a `secret` parameter + * which must be large enough for implementation reasons (>= XXH3_SECRET_SIZE_MIN) + * _and_ feature very high entropy (consist of random-looking bytes). + * These conditions can be a high bar to meet, so + * XXH3_generateSecret() can be employed to ensure proper quality. + * + * customSeed can be anything. It can have any size, even small ones, + * and its content can be anything, even "poor entropy" sources such as a bunch of zeroes. + * The resulting `secret` will nonetheless provide all required qualities. + * + * When customSeedSize > 0, supplying NULL as customSeed is undefined behavior. + */ +XXH_PUBLIC_API XXH_errorcode XXH3_generateSecret(void* secretBuffer, size_t secretSize, const void* customSeed, size_t customSeedSize); + + +/* + * XXH3_generateSecret_fromSeed(): + * + * Generate the same secret as the _withSeed() variants. + * + * The resulting secret has a length of XXH3_SECRET_DEFAULT_SIZE (necessarily). + * @secretBuffer must be already allocated, of size at least XXH3_SECRET_DEFAULT_SIZE bytes. + * + * The generated secret can be used in combination with + *`*_withSecret()` and `_withSecretandSeed()` variants. + * This generator is notably useful in combination with `_withSecretandSeed()`, + * as a way to emulate a faster `_withSeed()` variant. + */ +XXH_PUBLIC_API void XXH3_generateSecret_fromSeed(void* secretBuffer, XXH64_hash_t seed); + +/* + * *_withSecretandSeed() : + * These variants generate hash values using either + * @seed for "short" keys (< XXH3_MIDSIZE_MAX = 240 bytes) + * or @secret for "large" keys (>= XXH3_MIDSIZE_MAX). + * + * This generally benefits speed, compared to `_withSeed()` or `_withSecret()`. + * `_withSeed()` has to generate the secret on the fly for "large" keys. + * It's fast, but can be perceptible for "not so large" keys (< 1 KB). + * `_withSecret()` has to generate the masks on the fly for "small" keys, + * which requires more instructions than _withSeed() variants. + * Therefore, _withSecretandSeed variant combines the best of both worlds. + * + * When @secret has been generated by XXH3_generateSecret_fromSeed(), + * this variant produces *exactly* the same results as `_withSeed()` variant, + * hence offering only a pure speed benefit on "large" input, + * by skipping the need to regenerate the secret for every large input. + * + * Another usage scenario is to hash the secret to a 64-bit hash value, + * for example with XXH3_64bits(), which then becomes the seed, + * and then employ both the seed and the secret in _withSecretandSeed(). + * On top of speed, an added benefit is that each bit in the secret + * has a 50% chance to swap each bit in the output, + * via its impact to the seed. + * This is not guaranteed when using the secret directly in "small data" scenarios, + * because only portions of the secret are employed for small data. + */ +XXH_PUBLIC_API XXH64_hash_t +XXH3_64bits_withSecretandSeed(const void* data, size_t len, + const void* secret, size_t secretSize, + XXH64_hash_t seed); + +XXH_PUBLIC_API XXH128_hash_t +XXH3_128bits_withSecretandSeed(const void* data, size_t len, + const void* secret, size_t secretSize, + XXH64_hash_t seed64); + +XXH_PUBLIC_API XXH_errorcode +XXH3_64bits_reset_withSecretandSeed(XXH3_state_t* statePtr, + const void* secret, size_t secretSize, + XXH64_hash_t seed64); + +XXH_PUBLIC_API XXH_errorcode +XXH3_128bits_reset_withSecretandSeed(XXH3_state_t* statePtr, + const void* secret, size_t secretSize, + XXH64_hash_t seed64); + + +#endif /* XXH_NO_XXH3 */ +#endif /* XXH_NO_LONG_LONG */ +#if defined(XXH_INLINE_ALL) || defined(XXH_PRIVATE_API) +# define XXH_IMPLEMENTATION +#endif + +#endif /* defined(XXH_STATIC_LINKING_ONLY) && !defined(XXHASH_H_STATIC_13879238742) */ + + +/* ======================================================================== */ +/* ======================================================================== */ +/* ======================================================================== */ + + +/*-********************************************************************** + * xxHash implementation + *-********************************************************************** + * xxHash's implementation used to be hosted inside xxhash.c. + * + * However, inlining requires implementation to be visible to the compiler, + * hence be included alongside the header. + * Previously, implementation was hosted inside xxhash.c, + * which was then #included when inlining was activated. + * This construction created issues with a few build and install systems, + * as it required xxhash.c to be stored in /include directory. + * + * xxHash implementation is now directly integrated within xxhash.h. + * As a consequence, xxhash.c is no longer needed in /include. + * + * xxhash.c is still available and is still useful. + * In a "normal" setup, when xxhash is not inlined, + * xxhash.h only exposes the prototypes and public symbols, + * while xxhash.c can be built into an object file xxhash.o + * which can then be linked into the final binary. + ************************************************************************/ + +#if ( defined(XXH_INLINE_ALL) || defined(XXH_PRIVATE_API) \ + || defined(XXH_IMPLEMENTATION) ) && !defined(XXH_IMPLEM_13a8737387) +# define XXH_IMPLEM_13a8737387 + +/* ************************************* +* Tuning parameters +***************************************/ + +/*! + * @defgroup tuning Tuning parameters + * @{ + * + * Various macros to control xxHash's behavior. + */ +#ifdef XXH_DOXYGEN +/*! + * @brief Define this to disable 64-bit code. + * + * Useful if only using the @ref xxh32_family and you have a strict C90 compiler. + */ +# define XXH_NO_LONG_LONG +# undef XXH_NO_LONG_LONG /* don't actually */ +/*! + * @brief Controls how unaligned memory is accessed. + * + * By default, access to unaligned memory is controlled by `memcpy()`, which is + * safe and portable. + * + * Unfortunately, on some target/compiler combinations, the generated assembly + * is sub-optimal. + * + * The below switch allow selection of a different access method + * in the search for improved performance. + * + * @par Possible options: + * + * - `XXH_FORCE_MEMORY_ACCESS=0` (default): `memcpy` + * @par + * Use `memcpy()`. Safe and portable. Note that most modern compilers will + * eliminate the function call and treat it as an unaligned access. + * + * - `XXH_FORCE_MEMORY_ACCESS=1`: `__attribute__((packed))` + * @par + * Depends on compiler extensions and is therefore not portable. + * This method is safe _if_ your compiler supports it, + * and *generally* as fast or faster than `memcpy`. + * + * - `XXH_FORCE_MEMORY_ACCESS=2`: Direct cast + * @par + * Casts directly and dereferences. This method doesn't depend on the + * compiler, but it violates the C standard as it directly dereferences an + * unaligned pointer. It can generate buggy code on targets which do not + * support unaligned memory accesses, but in some circumstances, it's the + * only known way to get the most performance. + * + * - `XXH_FORCE_MEMORY_ACCESS=3`: Byteshift + * @par + * Also portable. This can generate the best code on old compilers which don't + * inline small `memcpy()` calls, and it might also be faster on big-endian + * systems which lack a native byteswap instruction. However, some compilers + * will emit literal byteshifts even if the target supports unaligned access. + * . + * + * @warning + * Methods 1 and 2 rely on implementation-defined behavior. Use these with + * care, as what works on one compiler/platform/optimization level may cause + * another to read garbage data or even crash. + * + * See http://fastcompression.blogspot.com/2015/08/accessing-unaligned-memory.html for details. + * + * Prefer these methods in priority order (0 > 3 > 1 > 2) + */ +# define XXH_FORCE_MEMORY_ACCESS 0 + +/*! + * @def XXH_FORCE_ALIGN_CHECK + * @brief If defined to non-zero, adds a special path for aligned inputs (XXH32() + * and XXH64() only). + * + * This is an important performance trick for architectures without decent + * unaligned memory access performance. + * + * It checks for input alignment, and when conditions are met, uses a "fast + * path" employing direct 32-bit/64-bit reads, resulting in _dramatically + * faster_ read speed. + * + * The check costs one initial branch per hash, which is generally negligible, + * but not zero. + * + * Moreover, it's not useful to generate an additional code path if memory + * access uses the same instruction for both aligned and unaligned + * addresses (e.g. x86 and aarch64). + * + * In these cases, the alignment check can be removed by setting this macro to 0. + * Then the code will always use unaligned memory access. + * Align check is automatically disabled on x86, x64 & arm64, + * which are platforms known to offer good unaligned memory accesses performance. + * + * This option does not affect XXH3 (only XXH32 and XXH64). + */ +# define XXH_FORCE_ALIGN_CHECK 0 + +/*! + * @def XXH_NO_INLINE_HINTS + * @brief When non-zero, sets all functions to `static`. + * + * By default, xxHash tries to force the compiler to inline almost all internal + * functions. + * + * This can usually improve performance due to reduced jumping and improved + * constant folding, but significantly increases the size of the binary which + * might not be favorable. + * + * Additionally, sometimes the forced inlining can be detrimental to performance, + * depending on the architecture. + * + * XXH_NO_INLINE_HINTS marks all internal functions as static, giving the + * compiler full control on whether to inline or not. + * + * When not optimizing (-O0), optimizing for size (-Os, -Oz), or using + * -fno-inline with GCC or Clang, this will automatically be defined. + */ +# define XXH_NO_INLINE_HINTS 0 + +/*! + * @def XXH32_ENDJMP + * @brief Whether to use a jump for `XXH32_finalize`. + * + * For performance, `XXH32_finalize` uses multiple branches in the finalizer. + * This is generally preferable for performance, + * but depending on exact architecture, a jmp may be preferable. + * + * This setting is only possibly making a difference for very small inputs. + */ +# define XXH32_ENDJMP 0 + +/*! + * @internal + * @brief Redefines old internal names. + * + * For compatibility with code that uses xxHash's internals before the names + * were changed to improve namespacing. There is no other reason to use this. + */ +# define XXH_OLD_NAMES +# undef XXH_OLD_NAMES /* don't actually use, it is ugly. */ +#endif /* XXH_DOXYGEN */ +/*! + * @} + */ + +#ifndef XXH_FORCE_MEMORY_ACCESS /* can be defined externally, on command line for example */ + /* prefer __packed__ structures (method 1) for gcc on armv7+ and mips */ +# if !defined(__clang__) && \ +( \ + (defined(__INTEL_COMPILER) && !defined(_WIN32)) || \ + ( \ + defined(__GNUC__) && ( \ + (defined(__ARM_ARCH) && __ARM_ARCH >= 7) || \ + ( \ + defined(__mips__) && \ + (__mips <= 5 || __mips_isa_rev < 6) && \ + (!defined(__mips16) || defined(__mips_mips16e2)) \ + ) \ + ) \ + ) \ +) +# define XXH_FORCE_MEMORY_ACCESS 1 +# endif +#endif + +#ifndef XXH_FORCE_ALIGN_CHECK /* can be defined externally */ +# if defined(__i386) || defined(__x86_64__) || defined(__aarch64__) \ + || defined(_M_IX86) || defined(_M_X64) || defined(_M_ARM64) /* visual */ +# define XXH_FORCE_ALIGN_CHECK 0 +# else +# define XXH_FORCE_ALIGN_CHECK 1 +# endif +#endif + +#ifndef XXH_NO_INLINE_HINTS +# if defined(__OPTIMIZE_SIZE__) /* -Os, -Oz */ \ + || defined(__NO_INLINE__) /* -O0, -fno-inline */ +# define XXH_NO_INLINE_HINTS 1 +# else +# define XXH_NO_INLINE_HINTS 0 +# endif +#endif + +#ifndef XXH32_ENDJMP +/* generally preferable for performance */ +# define XXH32_ENDJMP 0 +#endif + +/*! + * @defgroup impl Implementation + * @{ + */ + + +/* ************************************* +* Includes & Memory related functions +***************************************/ +/* Modify the local functions below should you wish to use some other memory routines */ +/* for ZSTD_malloc(), ZSTD_free() */ +#define ZSTD_DEPS_NEED_MALLOC +#include "zstd_deps.h" /* size_t, ZSTD_malloc, ZSTD_free, ZSTD_memcpy */ +static void* XXH_malloc(size_t s) { return ZSTD_malloc(s); } +static void XXH_free (void* p) { ZSTD_free(p); } +static void* XXH_memcpy(void* dest, const void* src, size_t size) { return ZSTD_memcpy(dest,src,size); } + + +/* ************************************* +* Compiler Specific Options +***************************************/ +#ifdef _MSC_VER /* Visual Studio warning fix */ +# pragma warning(disable : 4127) /* disable: C4127: conditional expression is constant */ +#endif + +#if XXH_NO_INLINE_HINTS /* disable inlining hints */ +# if defined(__GNUC__) || defined(__clang__) +# define XXH_FORCE_INLINE static __attribute__((unused)) +# else +# define XXH_FORCE_INLINE static +# endif +# define XXH_NO_INLINE static +/* enable inlining hints */ +#elif defined(__GNUC__) || defined(__clang__) +# define XXH_FORCE_INLINE static __inline__ __attribute__((always_inline, unused)) +# define XXH_NO_INLINE static __attribute__((noinline)) +#elif defined(_MSC_VER) /* Visual Studio */ +# define XXH_FORCE_INLINE static __forceinline +# define XXH_NO_INLINE static __declspec(noinline) +#elif defined (__cplusplus) \ + || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)) /* C99 */ +# define XXH_FORCE_INLINE static inline +# define XXH_NO_INLINE static +#else +# define XXH_FORCE_INLINE static +# define XXH_NO_INLINE static +#endif + + + +/* ************************************* +* Debug +***************************************/ +/*! + * @ingroup tuning + * @def XXH_DEBUGLEVEL + * @brief Sets the debugging level. + * + * XXH_DEBUGLEVEL is expected to be defined externally, typically via the + * compiler's command line options. The value must be a number. + */ +#ifndef XXH_DEBUGLEVEL +# ifdef DEBUGLEVEL /* backwards compat */ +# define XXH_DEBUGLEVEL DEBUGLEVEL +# else +# define XXH_DEBUGLEVEL 0 +# endif +#endif + +#if (XXH_DEBUGLEVEL>=1) +# include /* note: can still be disabled with NDEBUG */ +# define XXH_ASSERT(c) assert(c) +#else +# define XXH_ASSERT(c) ((void)0) +#endif + +/* note: use after variable declarations */ +#ifndef XXH_STATIC_ASSERT +# if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L) /* C11 */ +# include +# define XXH_STATIC_ASSERT_WITH_MESSAGE(c,m) do { static_assert((c),m); } while(0) +# elif defined(__cplusplus) && (__cplusplus >= 201103L) /* C++11 */ +# define XXH_STATIC_ASSERT_WITH_MESSAGE(c,m) do { static_assert((c),m); } while(0) +# else +# define XXH_STATIC_ASSERT_WITH_MESSAGE(c,m) do { struct xxh_sa { char x[(c) ? 1 : -1]; }; } while(0) +# endif +# define XXH_STATIC_ASSERT(c) XXH_STATIC_ASSERT_WITH_MESSAGE((c),#c) +#endif + +/*! + * @internal + * @def XXH_COMPILER_GUARD(var) + * @brief Used to prevent unwanted optimizations for @p var. + * + * It uses an empty GCC inline assembly statement with a register constraint + * which forces @p var into a general purpose register (eg eax, ebx, ecx + * on x86) and marks it as modified. + * + * This is used in a few places to avoid unwanted autovectorization (e.g. + * XXH32_round()). All vectorization we want is explicit via intrinsics, + * and _usually_ isn't wanted elsewhere. + * + * We also use it to prevent unwanted constant folding for AArch64 in + * XXH3_initCustomSecret_scalar(). + */ +#if defined(__GNUC__) || defined(__clang__) +# define XXH_COMPILER_GUARD(var) __asm__ __volatile__("" : "+r" (var)) +#else +# define XXH_COMPILER_GUARD(var) ((void)0) +#endif + +/* ************************************* +* Basic Types +***************************************/ +#if !defined (__VMS) \ + && (defined (__cplusplus) \ + || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) ) +# include + typedef uint8_t xxh_u8; +#else + typedef unsigned char xxh_u8; +#endif +typedef XXH32_hash_t xxh_u32; + +#ifdef XXH_OLD_NAMES +# define BYTE xxh_u8 +# define U8 xxh_u8 +# define U32 xxh_u32 +#endif + +/* *** Memory access *** */ + +/*! + * @internal + * @fn xxh_u32 XXH_read32(const void* ptr) + * @brief Reads an unaligned 32-bit integer from @p ptr in native endianness. + * + * Affected by @ref XXH_FORCE_MEMORY_ACCESS. + * + * @param ptr The pointer to read from. + * @return The 32-bit native endian integer from the bytes at @p ptr. + */ + +/*! + * @internal + * @fn xxh_u32 XXH_readLE32(const void* ptr) + * @brief Reads an unaligned 32-bit little endian integer from @p ptr. + * + * Affected by @ref XXH_FORCE_MEMORY_ACCESS. + * + * @param ptr The pointer to read from. + * @return The 32-bit little endian integer from the bytes at @p ptr. + */ + +/*! + * @internal + * @fn xxh_u32 XXH_readBE32(const void* ptr) + * @brief Reads an unaligned 32-bit big endian integer from @p ptr. + * + * Affected by @ref XXH_FORCE_MEMORY_ACCESS. + * + * @param ptr The pointer to read from. + * @return The 32-bit big endian integer from the bytes at @p ptr. + */ + +/*! + * @internal + * @fn xxh_u32 XXH_readLE32_align(const void* ptr, XXH_alignment align) + * @brief Like @ref XXH_readLE32(), but has an option for aligned reads. + * + * Affected by @ref XXH_FORCE_MEMORY_ACCESS. + * Note that when @ref XXH_FORCE_ALIGN_CHECK == 0, the @p align parameter is + * always @ref XXH_alignment::XXH_unaligned. + * + * @param ptr The pointer to read from. + * @param align Whether @p ptr is aligned. + * @pre + * If @p align == @ref XXH_alignment::XXH_aligned, @p ptr must be 4 byte + * aligned. + * @return The 32-bit little endian integer from the bytes at @p ptr. + */ + +#if (defined(XXH_FORCE_MEMORY_ACCESS) && (XXH_FORCE_MEMORY_ACCESS==3)) +/* + * Manual byteshift. Best for old compilers which don't inline memcpy. + * We actually directly use XXH_readLE32 and XXH_readBE32. + */ +#elif (defined(XXH_FORCE_MEMORY_ACCESS) && (XXH_FORCE_MEMORY_ACCESS==2)) + +/* + * Force direct memory access. Only works on CPU which support unaligned memory + * access in hardware. + */ +static xxh_u32 XXH_read32(const void* memPtr) { return *(const xxh_u32*) memPtr; } + +#elif (defined(XXH_FORCE_MEMORY_ACCESS) && (XXH_FORCE_MEMORY_ACCESS==1)) + +/* + * __pack instructions are safer but compiler specific, hence potentially + * problematic for some compilers. + * + * Currently only defined for GCC and ICC. + */ +#ifdef XXH_OLD_NAMES +typedef union { xxh_u32 u32; } __attribute__((packed)) unalign; +#endif +static xxh_u32 XXH_read32(const void* ptr) +{ + typedef union { xxh_u32 u32; } __attribute__((packed)) xxh_unalign; + return ((const xxh_unalign*)ptr)->u32; +} + +#else + +/* + * Portable and safe solution. Generally efficient. + * see: http://fastcompression.blogspot.com/2015/08/accessing-unaligned-memory.html + */ +static xxh_u32 XXH_read32(const void* memPtr) +{ + xxh_u32 val; + XXH_memcpy(&val, memPtr, sizeof(val)); + return val; +} + +#endif /* XXH_FORCE_DIRECT_MEMORY_ACCESS */ + + +/* *** Endianness *** */ + +/*! + * @ingroup tuning + * @def XXH_CPU_LITTLE_ENDIAN + * @brief Whether the target is little endian. + * + * Defined to 1 if the target is little endian, or 0 if it is big endian. + * It can be defined externally, for example on the compiler command line. + * + * If it is not defined, + * a runtime check (which is usually constant folded) is used instead. + * + * @note + * This is not necessarily defined to an integer constant. + * + * @see XXH_isLittleEndian() for the runtime check. + */ +#ifndef XXH_CPU_LITTLE_ENDIAN +/* + * Try to detect endianness automatically, to avoid the nonstandard behavior + * in `XXH_isLittleEndian()` + */ +# if defined(_WIN32) /* Windows is always little endian */ \ + || defined(__LITTLE_ENDIAN__) \ + || (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) +# define XXH_CPU_LITTLE_ENDIAN 1 +# elif defined(__BIG_ENDIAN__) \ + || (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) +# define XXH_CPU_LITTLE_ENDIAN 0 +# else +/*! + * @internal + * @brief Runtime check for @ref XXH_CPU_LITTLE_ENDIAN. + * + * Most compilers will constant fold this. + */ +static int XXH_isLittleEndian(void) +{ + /* + * Portable and well-defined behavior. + * Don't use static: it is detrimental to performance. + */ + const union { xxh_u32 u; xxh_u8 c[4]; } one = { 1 }; + return one.c[0]; +} +# define XXH_CPU_LITTLE_ENDIAN XXH_isLittleEndian() +# endif +#endif + + + + +/* **************************************** +* Compiler-specific Functions and Macros +******************************************/ +#define XXH_GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__) + +#ifdef __has_builtin +# define XXH_HAS_BUILTIN(x) __has_builtin(x) +#else +# define XXH_HAS_BUILTIN(x) 0 +#endif + +/*! + * @internal + * @def XXH_rotl32(x,r) + * @brief 32-bit rotate left. + * + * @param x The 32-bit integer to be rotated. + * @param r The number of bits to rotate. + * @pre + * @p r > 0 && @p r < 32 + * @note + * @p x and @p r may be evaluated multiple times. + * @return The rotated result. + */ +#if !defined(NO_CLANG_BUILTIN) && XXH_HAS_BUILTIN(__builtin_rotateleft32) \ + && XXH_HAS_BUILTIN(__builtin_rotateleft64) +# define XXH_rotl32 __builtin_rotateleft32 +# define XXH_rotl64 __builtin_rotateleft64 +/* Note: although _rotl exists for minGW (GCC under windows), performance seems poor */ +#elif defined(_MSC_VER) +# define XXH_rotl32(x,r) _rotl(x,r) +# define XXH_rotl64(x,r) _rotl64(x,r) +#else +# define XXH_rotl32(x,r) (((x) << (r)) | ((x) >> (32 - (r)))) +# define XXH_rotl64(x,r) (((x) << (r)) | ((x) >> (64 - (r)))) +#endif + +/*! + * @internal + * @fn xxh_u32 XXH_swap32(xxh_u32 x) + * @brief A 32-bit byteswap. + * + * @param x The 32-bit integer to byteswap. + * @return @p x, byteswapped. + */ +#if defined(_MSC_VER) /* Visual Studio */ +# define XXH_swap32 _byteswap_ulong +#elif XXH_GCC_VERSION >= 403 +# define XXH_swap32 __builtin_bswap32 +#else +static xxh_u32 XXH_swap32 (xxh_u32 x) +{ + return ((x << 24) & 0xff000000 ) | + ((x << 8) & 0x00ff0000 ) | + ((x >> 8) & 0x0000ff00 ) | + ((x >> 24) & 0x000000ff ); +} +#endif + + +/* *************************** +* Memory reads +*****************************/ + +/*! + * @internal + * @brief Enum to indicate whether a pointer is aligned. + */ +typedef enum { + XXH_aligned, /*!< Aligned */ + XXH_unaligned /*!< Possibly unaligned */ +} XXH_alignment; + +/* + * XXH_FORCE_MEMORY_ACCESS==3 is an endian-independent byteshift load. + * + * This is ideal for older compilers which don't inline memcpy. + */ +#if (defined(XXH_FORCE_MEMORY_ACCESS) && (XXH_FORCE_MEMORY_ACCESS==3)) + +XXH_FORCE_INLINE xxh_u32 XXH_readLE32(const void* memPtr) +{ + const xxh_u8* bytePtr = (const xxh_u8 *)memPtr; + return bytePtr[0] + | ((xxh_u32)bytePtr[1] << 8) + | ((xxh_u32)bytePtr[2] << 16) + | ((xxh_u32)bytePtr[3] << 24); +} + +XXH_FORCE_INLINE xxh_u32 XXH_readBE32(const void* memPtr) +{ + const xxh_u8* bytePtr = (const xxh_u8 *)memPtr; + return bytePtr[3] + | ((xxh_u32)bytePtr[2] << 8) + | ((xxh_u32)bytePtr[1] << 16) + | ((xxh_u32)bytePtr[0] << 24); +} + +#else +XXH_FORCE_INLINE xxh_u32 XXH_readLE32(const void* ptr) +{ + return XXH_CPU_LITTLE_ENDIAN ? XXH_read32(ptr) : XXH_swap32(XXH_read32(ptr)); +} + +static xxh_u32 XXH_readBE32(const void* ptr) +{ + return XXH_CPU_LITTLE_ENDIAN ? XXH_swap32(XXH_read32(ptr)) : XXH_read32(ptr); +} +#endif + +XXH_FORCE_INLINE xxh_u32 +XXH_readLE32_align(const void* ptr, XXH_alignment align) +{ + if (align==XXH_unaligned) { + return XXH_readLE32(ptr); + } else { + return XXH_CPU_LITTLE_ENDIAN ? *(const xxh_u32*)ptr : XXH_swap32(*(const xxh_u32*)ptr); + } +} + + +/* ************************************* +* Misc +***************************************/ +/*! @ingroup public */ +XXH_PUBLIC_API unsigned XXH_versionNumber (void) { return XXH_VERSION_NUMBER; } + + +/* ******************************************************************* +* 32-bit hash functions +*********************************************************************/ +/*! + * @} + * @defgroup xxh32_impl XXH32 implementation + * @ingroup impl + * @{ + */ + /* #define instead of static const, to be used as initializers */ +#define XXH_PRIME32_1 0x9E3779B1U /*!< 0b10011110001101110111100110110001 */ +#define XXH_PRIME32_2 0x85EBCA77U /*!< 0b10000101111010111100101001110111 */ +#define XXH_PRIME32_3 0xC2B2AE3DU /*!< 0b11000010101100101010111000111101 */ +#define XXH_PRIME32_4 0x27D4EB2FU /*!< 0b00100111110101001110101100101111 */ +#define XXH_PRIME32_5 0x165667B1U /*!< 0b00010110010101100110011110110001 */ + +#ifdef XXH_OLD_NAMES +# define PRIME32_1 XXH_PRIME32_1 +# define PRIME32_2 XXH_PRIME32_2 +# define PRIME32_3 XXH_PRIME32_3 +# define PRIME32_4 XXH_PRIME32_4 +# define PRIME32_5 XXH_PRIME32_5 +#endif + +/*! + * @internal + * @brief Normal stripe processing routine. + * + * This shuffles the bits so that any bit from @p input impacts several bits in + * @p acc. + * + * @param acc The accumulator lane. + * @param input The stripe of input to mix. + * @return The mixed accumulator lane. + */ +static xxh_u32 XXH32_round(xxh_u32 acc, xxh_u32 input) +{ + acc += input * XXH_PRIME32_2; + acc = XXH_rotl32(acc, 13); + acc *= XXH_PRIME32_1; +#if (defined(__SSE4_1__) || defined(__aarch64__)) && !defined(XXH_ENABLE_AUTOVECTORIZE) + /* + * UGLY HACK: + * A compiler fence is the only thing that prevents GCC and Clang from + * autovectorizing the XXH32 loop (pragmas and attributes don't work for some + * reason) without globally disabling SSE4.1. + * + * The reason we want to avoid vectorization is because despite working on + * 4 integers at a time, there are multiple factors slowing XXH32 down on + * SSE4: + * - There's a ridiculous amount of lag from pmulld (10 cycles of latency on + * newer chips!) making it slightly slower to multiply four integers at + * once compared to four integers independently. Even when pmulld was + * fastest, Sandy/Ivy Bridge, it is still not worth it to go into SSE + * just to multiply unless doing a long operation. + * + * - Four instructions are required to rotate, + * movqda tmp, v // not required with VEX encoding + * pslld tmp, 13 // tmp <<= 13 + * psrld v, 19 // x >>= 19 + * por v, tmp // x |= tmp + * compared to one for scalar: + * roll v, 13 // reliably fast across the board + * shldl v, v, 13 // Sandy Bridge and later prefer this for some reason + * + * - Instruction level parallelism is actually more beneficial here because + * the SIMD actually serializes this operation: While v1 is rotating, v2 + * can load data, while v3 can multiply. SSE forces them to operate + * together. + * + * This is also enabled on AArch64, as Clang autovectorizes it incorrectly + * and it is pointless writing a NEON implementation that is basically the + * same speed as scalar for XXH32. + */ + XXH_COMPILER_GUARD(acc); +#endif + return acc; +} + +/*! + * @internal + * @brief Mixes all bits to finalize the hash. + * + * The final mix ensures that all input bits have a chance to impact any bit in + * the output digest, resulting in an unbiased distribution. + * + * @param h32 The hash to avalanche. + * @return The avalanched hash. + */ +static xxh_u32 XXH32_avalanche(xxh_u32 h32) +{ + h32 ^= h32 >> 15; + h32 *= XXH_PRIME32_2; + h32 ^= h32 >> 13; + h32 *= XXH_PRIME32_3; + h32 ^= h32 >> 16; + return(h32); +} + +#define XXH_get32bits(p) XXH_readLE32_align(p, align) + +/*! + * @internal + * @brief Processes the last 0-15 bytes of @p ptr. + * + * There may be up to 15 bytes remaining to consume from the input. + * This final stage will digest them to ensure that all input bytes are present + * in the final mix. + * + * @param h32 The hash to finalize. + * @param ptr The pointer to the remaining input. + * @param len The remaining length, modulo 16. + * @param align Whether @p ptr is aligned. + * @return The finalized hash. + */ +static xxh_u32 +XXH32_finalize(xxh_u32 h32, const xxh_u8* ptr, size_t len, XXH_alignment align) +{ +#define XXH_PROCESS1 do { \ + h32 += (*ptr++) * XXH_PRIME32_5; \ + h32 = XXH_rotl32(h32, 11) * XXH_PRIME32_1; \ +} while (0) + +#define XXH_PROCESS4 do { \ + h32 += XXH_get32bits(ptr) * XXH_PRIME32_3; \ + ptr += 4; \ + h32 = XXH_rotl32(h32, 17) * XXH_PRIME32_4; \ +} while (0) + + if (ptr==NULL) XXH_ASSERT(len == 0); + + /* Compact rerolled version; generally faster */ + if (!XXH32_ENDJMP) { + len &= 15; + while (len >= 4) { + XXH_PROCESS4; + len -= 4; + } + while (len > 0) { + XXH_PROCESS1; + --len; + } + return XXH32_avalanche(h32); + } else { + switch(len&15) /* or switch(bEnd - p) */ { + case 12: XXH_PROCESS4; + XXH_FALLTHROUGH; + case 8: XXH_PROCESS4; + XXH_FALLTHROUGH; + case 4: XXH_PROCESS4; + return XXH32_avalanche(h32); + + case 13: XXH_PROCESS4; + XXH_FALLTHROUGH; + case 9: XXH_PROCESS4; + XXH_FALLTHROUGH; + case 5: XXH_PROCESS4; + XXH_PROCESS1; + return XXH32_avalanche(h32); + + case 14: XXH_PROCESS4; + XXH_FALLTHROUGH; + case 10: XXH_PROCESS4; + XXH_FALLTHROUGH; + case 6: XXH_PROCESS4; + XXH_PROCESS1; + XXH_PROCESS1; + return XXH32_avalanche(h32); + + case 15: XXH_PROCESS4; + XXH_FALLTHROUGH; + case 11: XXH_PROCESS4; + XXH_FALLTHROUGH; + case 7: XXH_PROCESS4; + XXH_FALLTHROUGH; + case 3: XXH_PROCESS1; + XXH_FALLTHROUGH; + case 2: XXH_PROCESS1; + XXH_FALLTHROUGH; + case 1: XXH_PROCESS1; + XXH_FALLTHROUGH; + case 0: return XXH32_avalanche(h32); + } + XXH_ASSERT(0); + return h32; /* reaching this point is deemed impossible */ + } +} + +#ifdef XXH_OLD_NAMES +# define PROCESS1 XXH_PROCESS1 +# define PROCESS4 XXH_PROCESS4 +#else +# undef XXH_PROCESS1 +# undef XXH_PROCESS4 +#endif + +/*! + * @internal + * @brief The implementation for @ref XXH32(). + * + * @param input , len , seed Directly passed from @ref XXH32(). + * @param align Whether @p input is aligned. + * @return The calculated hash. + */ +XXH_FORCE_INLINE xxh_u32 +XXH32_endian_align(const xxh_u8* input, size_t len, xxh_u32 seed, XXH_alignment align) +{ + xxh_u32 h32; + + if (input==NULL) XXH_ASSERT(len == 0); + + if (len>=16) { + const xxh_u8* const bEnd = input + len; + const xxh_u8* const limit = bEnd - 15; + xxh_u32 v1 = seed + XXH_PRIME32_1 + XXH_PRIME32_2; + xxh_u32 v2 = seed + XXH_PRIME32_2; + xxh_u32 v3 = seed + 0; + xxh_u32 v4 = seed - XXH_PRIME32_1; + + do { + v1 = XXH32_round(v1, XXH_get32bits(input)); input += 4; + v2 = XXH32_round(v2, XXH_get32bits(input)); input += 4; + v3 = XXH32_round(v3, XXH_get32bits(input)); input += 4; + v4 = XXH32_round(v4, XXH_get32bits(input)); input += 4; + } while (input < limit); + + h32 = XXH_rotl32(v1, 1) + XXH_rotl32(v2, 7) + + XXH_rotl32(v3, 12) + XXH_rotl32(v4, 18); + } else { + h32 = seed + XXH_PRIME32_5; + } + + h32 += (xxh_u32)len; + + return XXH32_finalize(h32, input, len&15, align); +} + +/*! @ingroup xxh32_family */ +XXH_PUBLIC_API XXH32_hash_t XXH32 (const void* input, size_t len, XXH32_hash_t seed) +{ +#if 0 + /* Simple version, good for code maintenance, but unfortunately slow for small inputs */ + XXH32_state_t state; + XXH32_reset(&state, seed); + XXH32_update(&state, (const xxh_u8*)input, len); + return XXH32_digest(&state); +#else + if (XXH_FORCE_ALIGN_CHECK) { + if ((((size_t)input) & 3) == 0) { /* Input is 4-bytes aligned, leverage the speed benefit */ + return XXH32_endian_align((const xxh_u8*)input, len, seed, XXH_aligned); + } } + + return XXH32_endian_align((const xxh_u8*)input, len, seed, XXH_unaligned); +#endif +} + + + +/******* Hash streaming *******/ +/*! + * @ingroup xxh32_family + */ +XXH_PUBLIC_API XXH32_state_t* XXH32_createState(void) +{ + return (XXH32_state_t*)XXH_malloc(sizeof(XXH32_state_t)); +} +/*! @ingroup xxh32_family */ +XXH_PUBLIC_API XXH_errorcode XXH32_freeState(XXH32_state_t* statePtr) +{ + XXH_free(statePtr); + return XXH_OK; +} + +/*! @ingroup xxh32_family */ +XXH_PUBLIC_API void XXH32_copyState(XXH32_state_t* dstState, const XXH32_state_t* srcState) +{ + XXH_memcpy(dstState, srcState, sizeof(*dstState)); +} + +/*! @ingroup xxh32_family */ +XXH_PUBLIC_API XXH_errorcode XXH32_reset(XXH32_state_t* statePtr, XXH32_hash_t seed) +{ + XXH_ASSERT(statePtr != NULL); + memset(statePtr, 0, sizeof(*statePtr)); + statePtr->v[0] = seed + XXH_PRIME32_1 + XXH_PRIME32_2; + statePtr->v[1] = seed + XXH_PRIME32_2; + statePtr->v[2] = seed + 0; + statePtr->v[3] = seed - XXH_PRIME32_1; + return XXH_OK; +} + + +/*! @ingroup xxh32_family */ +XXH_PUBLIC_API XXH_errorcode +XXH32_update(XXH32_state_t* state, const void* input, size_t len) +{ + if (input==NULL) { + XXH_ASSERT(len == 0); + return XXH_OK; + } + + { const xxh_u8* p = (const xxh_u8*)input; + const xxh_u8* const bEnd = p + len; + + state->total_len_32 += (XXH32_hash_t)len; + state->large_len |= (XXH32_hash_t)((len>=16) | (state->total_len_32>=16)); + + if (state->memsize + len < 16) { /* fill in tmp buffer */ + XXH_memcpy((xxh_u8*)(state->mem32) + state->memsize, input, len); + state->memsize += (XXH32_hash_t)len; + return XXH_OK; + } + + if (state->memsize) { /* some data left from previous update */ + XXH_memcpy((xxh_u8*)(state->mem32) + state->memsize, input, 16-state->memsize); + { const xxh_u32* p32 = state->mem32; + state->v[0] = XXH32_round(state->v[0], XXH_readLE32(p32)); p32++; + state->v[1] = XXH32_round(state->v[1], XXH_readLE32(p32)); p32++; + state->v[2] = XXH32_round(state->v[2], XXH_readLE32(p32)); p32++; + state->v[3] = XXH32_round(state->v[3], XXH_readLE32(p32)); + } + p += 16-state->memsize; + state->memsize = 0; + } + + if (p <= bEnd-16) { + const xxh_u8* const limit = bEnd - 16; + + do { + state->v[0] = XXH32_round(state->v[0], XXH_readLE32(p)); p+=4; + state->v[1] = XXH32_round(state->v[1], XXH_readLE32(p)); p+=4; + state->v[2] = XXH32_round(state->v[2], XXH_readLE32(p)); p+=4; + state->v[3] = XXH32_round(state->v[3], XXH_readLE32(p)); p+=4; + } while (p<=limit); + + } + + if (p < bEnd) { + XXH_memcpy(state->mem32, p, (size_t)(bEnd-p)); + state->memsize = (unsigned)(bEnd-p); + } + } + + return XXH_OK; +} + + +/*! @ingroup xxh32_family */ +XXH_PUBLIC_API XXH32_hash_t XXH32_digest(const XXH32_state_t* state) +{ + xxh_u32 h32; + + if (state->large_len) { + h32 = XXH_rotl32(state->v[0], 1) + + XXH_rotl32(state->v[1], 7) + + XXH_rotl32(state->v[2], 12) + + XXH_rotl32(state->v[3], 18); + } else { + h32 = state->v[2] /* == seed */ + XXH_PRIME32_5; + } + + h32 += state->total_len_32; + + return XXH32_finalize(h32, (const xxh_u8*)state->mem32, state->memsize, XXH_aligned); +} + + +/******* Canonical representation *******/ + +/*! + * @ingroup xxh32_family + * The default return values from XXH functions are unsigned 32 and 64 bit + * integers. + * + * The canonical representation uses big endian convention, the same convention + * as human-readable numbers (large digits first). + * + * This way, hash values can be written into a file or buffer, remaining + * comparable across different systems. + * + * The following functions allow transformation of hash values to and from their + * canonical format. + */ +XXH_PUBLIC_API void XXH32_canonicalFromHash(XXH32_canonical_t* dst, XXH32_hash_t hash) +{ + /* XXH_STATIC_ASSERT(sizeof(XXH32_canonical_t) == sizeof(XXH32_hash_t)); */ + if (XXH_CPU_LITTLE_ENDIAN) hash = XXH_swap32(hash); + XXH_memcpy(dst, &hash, sizeof(*dst)); +} +/*! @ingroup xxh32_family */ +XXH_PUBLIC_API XXH32_hash_t XXH32_hashFromCanonical(const XXH32_canonical_t* src) +{ + return XXH_readBE32(src); +} + + +#ifndef XXH_NO_LONG_LONG + +/* ******************************************************************* +* 64-bit hash functions +*********************************************************************/ +/*! + * @} + * @ingroup impl + * @{ + */ +/******* Memory access *******/ + +typedef XXH64_hash_t xxh_u64; + +#ifdef XXH_OLD_NAMES +# define U64 xxh_u64 +#endif + +#if (defined(XXH_FORCE_MEMORY_ACCESS) && (XXH_FORCE_MEMORY_ACCESS==3)) +/* + * Manual byteshift. Best for old compilers which don't inline memcpy. + * We actually directly use XXH_readLE64 and XXH_readBE64. + */ +#elif (defined(XXH_FORCE_MEMORY_ACCESS) && (XXH_FORCE_MEMORY_ACCESS==2)) + +/* Force direct memory access. Only works on CPU which support unaligned memory access in hardware */ +static xxh_u64 XXH_read64(const void* memPtr) +{ + return *(const xxh_u64*) memPtr; +} + +#elif (defined(XXH_FORCE_MEMORY_ACCESS) && (XXH_FORCE_MEMORY_ACCESS==1)) + +/* + * __pack instructions are safer, but compiler specific, hence potentially + * problematic for some compilers. + * + * Currently only defined for GCC and ICC. + */ +#ifdef XXH_OLD_NAMES +typedef union { xxh_u32 u32; xxh_u64 u64; } __attribute__((packed)) unalign64; +#endif +static xxh_u64 XXH_read64(const void* ptr) +{ + typedef union { xxh_u32 u32; xxh_u64 u64; } __attribute__((packed)) xxh_unalign64; + return ((const xxh_unalign64*)ptr)->u64; +} + +#else + +/* + * Portable and safe solution. Generally efficient. + * see: http://fastcompression.blogspot.com/2015/08/accessing-unaligned-memory.html + */ +static xxh_u64 XXH_read64(const void* memPtr) +{ + xxh_u64 val; + XXH_memcpy(&val, memPtr, sizeof(val)); + return val; +} + +#endif /* XXH_FORCE_DIRECT_MEMORY_ACCESS */ + +#if defined(_MSC_VER) /* Visual Studio */ +# define XXH_swap64 _byteswap_uint64 +#elif XXH_GCC_VERSION >= 403 +# define XXH_swap64 __builtin_bswap64 +#else +static xxh_u64 XXH_swap64(xxh_u64 x) +{ + return ((x << 56) & 0xff00000000000000ULL) | + ((x << 40) & 0x00ff000000000000ULL) | + ((x << 24) & 0x0000ff0000000000ULL) | + ((x << 8) & 0x000000ff00000000ULL) | + ((x >> 8) & 0x00000000ff000000ULL) | + ((x >> 24) & 0x0000000000ff0000ULL) | + ((x >> 40) & 0x000000000000ff00ULL) | + ((x >> 56) & 0x00000000000000ffULL); +} +#endif + + +/* XXH_FORCE_MEMORY_ACCESS==3 is an endian-independent byteshift load. */ +#if (defined(XXH_FORCE_MEMORY_ACCESS) && (XXH_FORCE_MEMORY_ACCESS==3)) + +XXH_FORCE_INLINE xxh_u64 XXH_readLE64(const void* memPtr) +{ + const xxh_u8* bytePtr = (const xxh_u8 *)memPtr; + return bytePtr[0] + | ((xxh_u64)bytePtr[1] << 8) + | ((xxh_u64)bytePtr[2] << 16) + | ((xxh_u64)bytePtr[3] << 24) + | ((xxh_u64)bytePtr[4] << 32) + | ((xxh_u64)bytePtr[5] << 40) + | ((xxh_u64)bytePtr[6] << 48) + | ((xxh_u64)bytePtr[7] << 56); +} + +XXH_FORCE_INLINE xxh_u64 XXH_readBE64(const void* memPtr) +{ + const xxh_u8* bytePtr = (const xxh_u8 *)memPtr; + return bytePtr[7] + | ((xxh_u64)bytePtr[6] << 8) + | ((xxh_u64)bytePtr[5] << 16) + | ((xxh_u64)bytePtr[4] << 24) + | ((xxh_u64)bytePtr[3] << 32) + | ((xxh_u64)bytePtr[2] << 40) + | ((xxh_u64)bytePtr[1] << 48) + | ((xxh_u64)bytePtr[0] << 56); +} + +#else +XXH_FORCE_INLINE xxh_u64 XXH_readLE64(const void* ptr) +{ + return XXH_CPU_LITTLE_ENDIAN ? XXH_read64(ptr) : XXH_swap64(XXH_read64(ptr)); +} + +static xxh_u64 XXH_readBE64(const void* ptr) +{ + return XXH_CPU_LITTLE_ENDIAN ? XXH_swap64(XXH_read64(ptr)) : XXH_read64(ptr); +} +#endif + +XXH_FORCE_INLINE xxh_u64 +XXH_readLE64_align(const void* ptr, XXH_alignment align) +{ + if (align==XXH_unaligned) + return XXH_readLE64(ptr); + else + return XXH_CPU_LITTLE_ENDIAN ? *(const xxh_u64*)ptr : XXH_swap64(*(const xxh_u64*)ptr); +} + + +/******* xxh64 *******/ +/*! + * @} + * @defgroup xxh64_impl XXH64 implementation + * @ingroup impl + * @{ + */ +/* #define rather that static const, to be used as initializers */ +#define XXH_PRIME64_1 0x9E3779B185EBCA87ULL /*!< 0b1001111000110111011110011011000110000101111010111100101010000111 */ +#define XXH_PRIME64_2 0xC2B2AE3D27D4EB4FULL /*!< 0b1100001010110010101011100011110100100111110101001110101101001111 */ +#define XXH_PRIME64_3 0x165667B19E3779F9ULL /*!< 0b0001011001010110011001111011000110011110001101110111100111111001 */ +#define XXH_PRIME64_4 0x85EBCA77C2B2AE63ULL /*!< 0b1000010111101011110010100111011111000010101100101010111001100011 */ +#define XXH_PRIME64_5 0x27D4EB2F165667C5ULL /*!< 0b0010011111010100111010110010111100010110010101100110011111000101 */ + +#ifdef XXH_OLD_NAMES +# define PRIME64_1 XXH_PRIME64_1 +# define PRIME64_2 XXH_PRIME64_2 +# define PRIME64_3 XXH_PRIME64_3 +# define PRIME64_4 XXH_PRIME64_4 +# define PRIME64_5 XXH_PRIME64_5 +#endif + +static xxh_u64 XXH64_round(xxh_u64 acc, xxh_u64 input) +{ + acc += input * XXH_PRIME64_2; + acc = XXH_rotl64(acc, 31); + acc *= XXH_PRIME64_1; + return acc; +} + +static xxh_u64 XXH64_mergeRound(xxh_u64 acc, xxh_u64 val) +{ + val = XXH64_round(0, val); + acc ^= val; + acc = acc * XXH_PRIME64_1 + XXH_PRIME64_4; + return acc; +} + +static xxh_u64 XXH64_avalanche(xxh_u64 h64) +{ + h64 ^= h64 >> 33; + h64 *= XXH_PRIME64_2; + h64 ^= h64 >> 29; + h64 *= XXH_PRIME64_3; + h64 ^= h64 >> 32; + return h64; +} + + +#define XXH_get64bits(p) XXH_readLE64_align(p, align) + +static xxh_u64 +XXH64_finalize(xxh_u64 h64, const xxh_u8* ptr, size_t len, XXH_alignment align) +{ + if (ptr==NULL) XXH_ASSERT(len == 0); + len &= 31; + while (len >= 8) { + xxh_u64 const k1 = XXH64_round(0, XXH_get64bits(ptr)); + ptr += 8; + h64 ^= k1; + h64 = XXH_rotl64(h64,27) * XXH_PRIME64_1 + XXH_PRIME64_4; + len -= 8; + } + if (len >= 4) { + h64 ^= (xxh_u64)(XXH_get32bits(ptr)) * XXH_PRIME64_1; + ptr += 4; + h64 = XXH_rotl64(h64, 23) * XXH_PRIME64_2 + XXH_PRIME64_3; + len -= 4; + } + while (len > 0) { + h64 ^= (*ptr++) * XXH_PRIME64_5; + h64 = XXH_rotl64(h64, 11) * XXH_PRIME64_1; + --len; + } + return XXH64_avalanche(h64); +} + +#ifdef XXH_OLD_NAMES +# define PROCESS1_64 XXH_PROCESS1_64 +# define PROCESS4_64 XXH_PROCESS4_64 +# define PROCESS8_64 XXH_PROCESS8_64 +#else +# undef XXH_PROCESS1_64 +# undef XXH_PROCESS4_64 +# undef XXH_PROCESS8_64 +#endif + +XXH_FORCE_INLINE xxh_u64 +XXH64_endian_align(const xxh_u8* input, size_t len, xxh_u64 seed, XXH_alignment align) +{ + xxh_u64 h64; + if (input==NULL) XXH_ASSERT(len == 0); + + if (len>=32) { + const xxh_u8* const bEnd = input + len; + const xxh_u8* const limit = bEnd - 31; + xxh_u64 v1 = seed + XXH_PRIME64_1 + XXH_PRIME64_2; + xxh_u64 v2 = seed + XXH_PRIME64_2; + xxh_u64 v3 = seed + 0; + xxh_u64 v4 = seed - XXH_PRIME64_1; + + do { + v1 = XXH64_round(v1, XXH_get64bits(input)); input+=8; + v2 = XXH64_round(v2, XXH_get64bits(input)); input+=8; + v3 = XXH64_round(v3, XXH_get64bits(input)); input+=8; + v4 = XXH64_round(v4, XXH_get64bits(input)); input+=8; + } while (inputv[0] = seed + XXH_PRIME64_1 + XXH_PRIME64_2; + statePtr->v[1] = seed + XXH_PRIME64_2; + statePtr->v[2] = seed + 0; + statePtr->v[3] = seed - XXH_PRIME64_1; + return XXH_OK; +} + +/*! @ingroup xxh64_family */ +XXH_PUBLIC_API XXH_errorcode +XXH64_update (XXH64_state_t* state, const void* input, size_t len) +{ + if (input==NULL) { + XXH_ASSERT(len == 0); + return XXH_OK; + } + + { const xxh_u8* p = (const xxh_u8*)input; + const xxh_u8* const bEnd = p + len; + + state->total_len += len; + + if (state->memsize + len < 32) { /* fill in tmp buffer */ + XXH_memcpy(((xxh_u8*)state->mem64) + state->memsize, input, len); + state->memsize += (xxh_u32)len; + return XXH_OK; + } + + if (state->memsize) { /* tmp buffer is full */ + XXH_memcpy(((xxh_u8*)state->mem64) + state->memsize, input, 32-state->memsize); + state->v[0] = XXH64_round(state->v[0], XXH_readLE64(state->mem64+0)); + state->v[1] = XXH64_round(state->v[1], XXH_readLE64(state->mem64+1)); + state->v[2] = XXH64_round(state->v[2], XXH_readLE64(state->mem64+2)); + state->v[3] = XXH64_round(state->v[3], XXH_readLE64(state->mem64+3)); + p += 32 - state->memsize; + state->memsize = 0; + } + + if (p+32 <= bEnd) { + const xxh_u8* const limit = bEnd - 32; + + do { + state->v[0] = XXH64_round(state->v[0], XXH_readLE64(p)); p+=8; + state->v[1] = XXH64_round(state->v[1], XXH_readLE64(p)); p+=8; + state->v[2] = XXH64_round(state->v[2], XXH_readLE64(p)); p+=8; + state->v[3] = XXH64_round(state->v[3], XXH_readLE64(p)); p+=8; + } while (p<=limit); + + } + + if (p < bEnd) { + XXH_memcpy(state->mem64, p, (size_t)(bEnd-p)); + state->memsize = (unsigned)(bEnd-p); + } + } + + return XXH_OK; +} + + +/*! @ingroup xxh64_family */ +XXH_PUBLIC_API XXH64_hash_t XXH64_digest(const XXH64_state_t* state) +{ + xxh_u64 h64; + + if (state->total_len >= 32) { + h64 = XXH_rotl64(state->v[0], 1) + XXH_rotl64(state->v[1], 7) + XXH_rotl64(state->v[2], 12) + XXH_rotl64(state->v[3], 18); + h64 = XXH64_mergeRound(h64, state->v[0]); + h64 = XXH64_mergeRound(h64, state->v[1]); + h64 = XXH64_mergeRound(h64, state->v[2]); + h64 = XXH64_mergeRound(h64, state->v[3]); + } else { + h64 = state->v[2] /*seed*/ + XXH_PRIME64_5; + } + + h64 += (xxh_u64) state->total_len; + + return XXH64_finalize(h64, (const xxh_u8*)state->mem64, (size_t)state->total_len, XXH_aligned); +} + + +/******* Canonical representation *******/ + +/*! @ingroup xxh64_family */ +XXH_PUBLIC_API void XXH64_canonicalFromHash(XXH64_canonical_t* dst, XXH64_hash_t hash) +{ + /* XXH_STATIC_ASSERT(sizeof(XXH64_canonical_t) == sizeof(XXH64_hash_t)); */ + if (XXH_CPU_LITTLE_ENDIAN) hash = XXH_swap64(hash); + XXH_memcpy(dst, &hash, sizeof(*dst)); +} + +/*! @ingroup xxh64_family */ +XXH_PUBLIC_API XXH64_hash_t XXH64_hashFromCanonical(const XXH64_canonical_t* src) +{ + return XXH_readBE64(src); +} + +#ifndef XXH_NO_XXH3 + +/* ********************************************************************* +* XXH3 +* New generation hash designed for speed on small keys and vectorization +************************************************************************ */ +/*! + * @} + * @defgroup xxh3_impl XXH3 implementation + * @ingroup impl + * @{ + */ + +/* === Compiler specifics === */ + +#if ((defined(sun) || defined(__sun)) && __cplusplus) /* Solaris includes __STDC_VERSION__ with C++. Tested with GCC 5.5 */ +# define XXH_RESTRICT /* disable */ +#elif defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L /* >= C99 */ +# define XXH_RESTRICT restrict +#else +/* Note: it might be useful to define __restrict or __restrict__ for some C++ compilers */ +# define XXH_RESTRICT /* disable */ +#endif + +#if (defined(__GNUC__) && (__GNUC__ >= 3)) \ + || (defined(__INTEL_COMPILER) && (__INTEL_COMPILER >= 800)) \ + || defined(__clang__) +# define XXH_likely(x) __builtin_expect(x, 1) +# define XXH_unlikely(x) __builtin_expect(x, 0) +#else +# define XXH_likely(x) (x) +# define XXH_unlikely(x) (x) +#endif + +#if defined(__GNUC__) || defined(__clang__) +# if defined(__ARM_NEON__) || defined(__ARM_NEON) \ + || defined(__aarch64__) || defined(_M_ARM) \ + || defined(_M_ARM64) || defined(_M_ARM64EC) +# define inline __inline__ /* circumvent a clang bug */ +# include +# undef inline +# elif defined(__AVX2__) +# include +# elif defined(__SSE2__) +# include +# endif +#endif + +#if defined(_MSC_VER) +# include +#endif + +/* + * One goal of XXH3 is to make it fast on both 32-bit and 64-bit, while + * remaining a true 64-bit/128-bit hash function. + * + * This is done by prioritizing a subset of 64-bit operations that can be + * emulated without too many steps on the average 32-bit machine. + * + * For example, these two lines seem similar, and run equally fast on 64-bit: + * + * xxh_u64 x; + * x ^= (x >> 47); // good + * x ^= (x >> 13); // bad + * + * However, to a 32-bit machine, there is a major difference. + * + * x ^= (x >> 47) looks like this: + * + * x.lo ^= (x.hi >> (47 - 32)); + * + * while x ^= (x >> 13) looks like this: + * + * // note: funnel shifts are not usually cheap. + * x.lo ^= (x.lo >> 13) | (x.hi << (32 - 13)); + * x.hi ^= (x.hi >> 13); + * + * The first one is significantly faster than the second, simply because the + * shift is larger than 32. This means: + * - All the bits we need are in the upper 32 bits, so we can ignore the lower + * 32 bits in the shift. + * - The shift result will always fit in the lower 32 bits, and therefore, + * we can ignore the upper 32 bits in the xor. + * + * Thanks to this optimization, XXH3 only requires these features to be efficient: + * + * - Usable unaligned access + * - A 32-bit or 64-bit ALU + * - If 32-bit, a decent ADC instruction + * - A 32 or 64-bit multiply with a 64-bit result + * - For the 128-bit variant, a decent byteswap helps short inputs. + * + * The first two are already required by XXH32, and almost all 32-bit and 64-bit + * platforms which can run XXH32 can run XXH3 efficiently. + * + * Thumb-1, the classic 16-bit only subset of ARM's instruction set, is one + * notable exception. + * + * First of all, Thumb-1 lacks support for the UMULL instruction which + * performs the important long multiply. This means numerous __aeabi_lmul + * calls. + * + * Second of all, the 8 functional registers are just not enough. + * Setup for __aeabi_lmul, byteshift loads, pointers, and all arithmetic need + * Lo registers, and this shuffling results in thousands more MOVs than A32. + * + * A32 and T32 don't have this limitation. They can access all 14 registers, + * do a 32->64 multiply with UMULL, and the flexible operand allowing free + * shifts is helpful, too. + * + * Therefore, we do a quick sanity check. + * + * If compiling Thumb-1 for a target which supports ARM instructions, we will + * emit a warning, as it is not a "sane" platform to compile for. + * + * Usually, if this happens, it is because of an accident and you probably need + * to specify -march, as you likely meant to compile for a newer architecture. + * + * Credit: large sections of the vectorial and asm source code paths + * have been contributed by @easyaspi314 + */ +#if defined(__thumb__) && !defined(__thumb2__) && defined(__ARM_ARCH_ISA_ARM) +# warning "XXH3 is highly inefficient without ARM or Thumb-2." +#endif + +/* ========================================== + * Vectorization detection + * ========================================== */ + +#ifdef XXH_DOXYGEN +/*! + * @ingroup tuning + * @brief Overrides the vectorization implementation chosen for XXH3. + * + * Can be defined to 0 to disable SIMD or any of the values mentioned in + * @ref XXH_VECTOR_TYPE. + * + * If this is not defined, it uses predefined macros to determine the best + * implementation. + */ +# define XXH_VECTOR XXH_SCALAR +/*! + * @ingroup tuning + * @brief Possible values for @ref XXH_VECTOR. + * + * Note that these are actually implemented as macros. + * + * If this is not defined, it is detected automatically. + * @ref XXH_X86DISPATCH overrides this. + */ +enum XXH_VECTOR_TYPE /* fake enum */ { + XXH_SCALAR = 0, /*!< Portable scalar version */ + XXH_SSE2 = 1, /*!< + * SSE2 for Pentium 4, Opteron, all x86_64. + * + * @note SSE2 is also guaranteed on Windows 10, macOS, and + * Android x86. + */ + XXH_AVX2 = 2, /*!< AVX2 for Haswell and Bulldozer */ + XXH_AVX512 = 3, /*!< AVX512 for Skylake and Icelake */ + XXH_NEON = 4, /*!< NEON for most ARMv7-A and all AArch64 */ + XXH_VSX = 5, /*!< VSX and ZVector for POWER8/z13 (64-bit) */ +}; +/*! + * @ingroup tuning + * @brief Selects the minimum alignment for XXH3's accumulators. + * + * When using SIMD, this should match the alignment reqired for said vector + * type, so, for example, 32 for AVX2. + * + * Default: Auto detected. + */ +# define XXH_ACC_ALIGN 8 +#endif + +/* Actual definition */ +#ifndef XXH_DOXYGEN +# define XXH_SCALAR 0 +# define XXH_SSE2 1 +# define XXH_AVX2 2 +# define XXH_AVX512 3 +# define XXH_NEON 4 +# define XXH_VSX 5 +#endif + +#ifndef XXH_VECTOR /* can be defined on command line */ +# if ( \ + defined(__ARM_NEON__) || defined(__ARM_NEON) /* gcc */ \ + || defined(_M_ARM) || defined(_M_ARM64) || defined(_M_ARM64EC) /* msvc */ \ + ) && ( \ + defined(_WIN32) || defined(__LITTLE_ENDIAN__) /* little endian only */ \ + || (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) \ + ) +# define XXH_VECTOR XXH_NEON +# elif defined(__AVX512F__) +# define XXH_VECTOR XXH_AVX512 +# elif defined(__AVX2__) +# define XXH_VECTOR XXH_AVX2 +# elif defined(__SSE2__) || defined(_M_AMD64) || defined(_M_X64) || (defined(_M_IX86_FP) && (_M_IX86_FP == 2)) +# define XXH_VECTOR XXH_SSE2 +# elif (defined(__PPC64__) && defined(__POWER8_VECTOR__)) \ + || (defined(__s390x__) && defined(__VEC__)) \ + && defined(__GNUC__) /* TODO: IBM XL */ +# define XXH_VECTOR XXH_VSX +# else +# define XXH_VECTOR XXH_SCALAR +# endif +#endif + +/* + * Controls the alignment of the accumulator, + * for compatibility with aligned vector loads, which are usually faster. + */ +#ifndef XXH_ACC_ALIGN +# if defined(XXH_X86DISPATCH) +# define XXH_ACC_ALIGN 64 /* for compatibility with avx512 */ +# elif XXH_VECTOR == XXH_SCALAR /* scalar */ +# define XXH_ACC_ALIGN 8 +# elif XXH_VECTOR == XXH_SSE2 /* sse2 */ +# define XXH_ACC_ALIGN 16 +# elif XXH_VECTOR == XXH_AVX2 /* avx2 */ +# define XXH_ACC_ALIGN 32 +# elif XXH_VECTOR == XXH_NEON /* neon */ +# define XXH_ACC_ALIGN 16 +# elif XXH_VECTOR == XXH_VSX /* vsx */ +# define XXH_ACC_ALIGN 16 +# elif XXH_VECTOR == XXH_AVX512 /* avx512 */ +# define XXH_ACC_ALIGN 64 +# endif +#endif + +#if defined(XXH_X86DISPATCH) || XXH_VECTOR == XXH_SSE2 \ + || XXH_VECTOR == XXH_AVX2 || XXH_VECTOR == XXH_AVX512 +# define XXH_SEC_ALIGN XXH_ACC_ALIGN +#else +# define XXH_SEC_ALIGN 8 +#endif + +/* + * UGLY HACK: + * GCC usually generates the best code with -O3 for xxHash. + * + * However, when targeting AVX2, it is overzealous in its unrolling resulting + * in code roughly 3/4 the speed of Clang. + * + * There are other issues, such as GCC splitting _mm256_loadu_si256 into + * _mm_loadu_si128 + _mm256_inserti128_si256. This is an optimization which + * only applies to Sandy and Ivy Bridge... which don't even support AVX2. + * + * That is why when compiling the AVX2 version, it is recommended to use either + * -O2 -mavx2 -march=haswell + * or + * -O2 -mavx2 -mno-avx256-split-unaligned-load + * for decent performance, or to use Clang instead. + * + * Fortunately, we can control the first one with a pragma that forces GCC into + * -O2, but the other one we can't control without "failed to inline always + * inline function due to target mismatch" warnings. + */ +#if XXH_VECTOR == XXH_AVX2 /* AVX2 */ \ + && defined(__GNUC__) && !defined(__clang__) /* GCC, not Clang */ \ + && defined(__OPTIMIZE__) && !defined(__OPTIMIZE_SIZE__) /* respect -O0 and -Os */ +# pragma GCC push_options +# pragma GCC optimize("-O2") +#endif + + +#if XXH_VECTOR == XXH_NEON +/* + * NEON's setup for vmlal_u32 is a little more complicated than it is on + * SSE2, AVX2, and VSX. + * + * While PMULUDQ and VMULEUW both perform a mask, VMLAL.U32 performs an upcast. + * + * To do the same operation, the 128-bit 'Q' register needs to be split into + * two 64-bit 'D' registers, performing this operation:: + * + * [ a | b ] + * | '---------. .--------' | + * | x | + * | .---------' '--------. | + * [ a & 0xFFFFFFFF | b & 0xFFFFFFFF ],[ a >> 32 | b >> 32 ] + * + * Due to significant changes in aarch64, the fastest method for aarch64 is + * completely different than the fastest method for ARMv7-A. + * + * ARMv7-A treats D registers as unions overlaying Q registers, so modifying + * D11 will modify the high half of Q5. This is similar to how modifying AH + * will only affect bits 8-15 of AX on x86. + * + * VZIP takes two registers, and puts even lanes in one register and odd lanes + * in the other. + * + * On ARMv7-A, this strangely modifies both parameters in place instead of + * taking the usual 3-operand form. + * + * Therefore, if we want to do this, we can simply use a D-form VZIP.32 on the + * lower and upper halves of the Q register to end up with the high and low + * halves where we want - all in one instruction. + * + * vzip.32 d10, d11 @ d10 = { d10[0], d11[0] }; d11 = { d10[1], d11[1] } + * + * Unfortunately we need inline assembly for this: Instructions modifying two + * registers at once is not possible in GCC or Clang's IR, and they have to + * create a copy. + * + * aarch64 requires a different approach. + * + * In order to make it easier to write a decent compiler for aarch64, many + * quirks were removed, such as conditional execution. + * + * NEON was also affected by this. + * + * aarch64 cannot access the high bits of a Q-form register, and writes to a + * D-form register zero the high bits, similar to how writes to W-form scalar + * registers (or DWORD registers on x86_64) work. + * + * The formerly free vget_high intrinsics now require a vext (with a few + * exceptions) + * + * Additionally, VZIP was replaced by ZIP1 and ZIP2, which are the equivalent + * of PUNPCKL* and PUNPCKH* in SSE, respectively, in order to only modify one + * operand. + * + * The equivalent of the VZIP.32 on the lower and upper halves would be this + * mess: + * + * ext v2.4s, v0.4s, v0.4s, #2 // v2 = { v0[2], v0[3], v0[0], v0[1] } + * zip1 v1.2s, v0.2s, v2.2s // v1 = { v0[0], v2[0] } + * zip2 v0.2s, v0.2s, v1.2s // v0 = { v0[1], v2[1] } + * + * Instead, we use a literal downcast, vmovn_u64 (XTN), and vshrn_n_u64 (SHRN): + * + * shrn v1.2s, v0.2d, #32 // v1 = (uint32x2_t)(v0 >> 32); + * xtn v0.2s, v0.2d // v0 = (uint32x2_t)(v0 & 0xFFFFFFFF); + * + * This is available on ARMv7-A, but is less efficient than a single VZIP.32. + */ + +/*! + * Function-like macro: + * void XXH_SPLIT_IN_PLACE(uint64x2_t &in, uint32x2_t &outLo, uint32x2_t &outHi) + * { + * outLo = (uint32x2_t)(in & 0xFFFFFFFF); + * outHi = (uint32x2_t)(in >> 32); + * in = UNDEFINED; + * } + */ +# if !defined(XXH_NO_VZIP_HACK) /* define to disable */ \ + && (defined(__GNUC__) || defined(__clang__)) \ + && (defined(__arm__) || defined(__thumb__) || defined(_M_ARM)) +# define XXH_SPLIT_IN_PLACE(in, outLo, outHi) \ + do { \ + /* Undocumented GCC/Clang operand modifier: %e0 = lower D half, %f0 = upper D half */ \ + /* https://github.com/gcc-mirror/gcc/blob/38cf91e5/gcc/config/arm/arm.c#L22486 */ \ + /* https://github.com/llvm-mirror/llvm/blob/2c4ca683/lib/Target/ARM/ARMAsmPrinter.cpp#L399 */ \ + __asm__("vzip.32 %e0, %f0" : "+w" (in)); \ + (outLo) = vget_low_u32 (vreinterpretq_u32_u64(in)); \ + (outHi) = vget_high_u32(vreinterpretq_u32_u64(in)); \ + } while (0) +# else +# define XXH_SPLIT_IN_PLACE(in, outLo, outHi) \ + do { \ + (outLo) = vmovn_u64 (in); \ + (outHi) = vshrn_n_u64 ((in), 32); \ + } while (0) +# endif + +/*! + * @ingroup tuning + * @brief Controls the NEON to scalar ratio for XXH3 + * + * On AArch64 when not optimizing for size, XXH3 will run 6 lanes using NEON and + * 2 lanes on scalar by default. + * + * This can be set to 2, 4, 6, or 8. ARMv7 will default to all 8 NEON lanes, as the + * emulated 64-bit arithmetic is too slow. + * + * Modern ARM CPUs are _very_ sensitive to how their pipelines are used. + * + * For example, the Cortex-A73 can dispatch 3 micro-ops per cycle, but it can't + * have more than 2 NEON (F0/F1) micro-ops. If you are only using NEON instructions, + * you are only using 2/3 of the CPU bandwidth. + * + * This is even more noticable on the more advanced cores like the A76 which + * can dispatch 8 micro-ops per cycle, but still only 2 NEON micro-ops at once. + * + * Therefore, @ref XXH3_NEON_LANES lanes will be processed using NEON, and the + * remaining lanes will use scalar instructions. This improves the bandwidth + * and also gives the integer pipelines something to do besides twiddling loop + * counters and pointers. + * + * This change benefits CPUs with large micro-op buffers without negatively affecting + * other CPUs: + * + * | Chipset | Dispatch type | NEON only | 6:2 hybrid | Diff. | + * |:----------------------|:--------------------|----------:|-----------:|------:| + * | Snapdragon 730 (A76) | 2 NEON/8 micro-ops | 8.8 GB/s | 10.1 GB/s | ~16% | + * | Snapdragon 835 (A73) | 2 NEON/3 micro-ops | 5.1 GB/s | 5.3 GB/s | ~5% | + * | Marvell PXA1928 (A53) | In-order dual-issue | 1.9 GB/s | 1.9 GB/s | 0% | + * + * It also seems to fix some bad codegen on GCC, making it almost as fast as clang. + * + * @see XXH3_accumulate_512_neon() + */ +# ifndef XXH3_NEON_LANES +# if (defined(__aarch64__) || defined(__arm64__) || defined(_M_ARM64) || defined(_M_ARM64EC)) \ + && !defined(__OPTIMIZE_SIZE__) +# define XXH3_NEON_LANES 6 +# else +# define XXH3_NEON_LANES XXH_ACC_NB +# endif +# endif +#endif /* XXH_VECTOR == XXH_NEON */ + +/* + * VSX and Z Vector helpers. + * + * This is very messy, and any pull requests to clean this up are welcome. + * + * There are a lot of problems with supporting VSX and s390x, due to + * inconsistent intrinsics, spotty coverage, and multiple endiannesses. + */ +#if XXH_VECTOR == XXH_VSX +# if defined(__s390x__) +# include +# else +/* gcc's altivec.h can have the unwanted consequence to unconditionally + * #define bool, vector, and pixel keywords, + * with bad consequences for programs already using these keywords for other purposes. + * The paragraph defining these macros is skipped when __APPLE_ALTIVEC__ is defined. + * __APPLE_ALTIVEC__ is _generally_ defined automatically by the compiler, + * but it seems that, in some cases, it isn't. + * Force the build macro to be defined, so that keywords are not altered. + */ +# if defined(__GNUC__) && !defined(__APPLE_ALTIVEC__) +# define __APPLE_ALTIVEC__ +# endif +# include +# endif + +typedef __vector unsigned long long xxh_u64x2; +typedef __vector unsigned char xxh_u8x16; +typedef __vector unsigned xxh_u32x4; + +# ifndef XXH_VSX_BE +# if defined(__BIG_ENDIAN__) \ + || (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) +# define XXH_VSX_BE 1 +# elif defined(__VEC_ELEMENT_REG_ORDER__) && __VEC_ELEMENT_REG_ORDER__ == __ORDER_BIG_ENDIAN__ +# warning "-maltivec=be is not recommended. Please use native endianness." +# define XXH_VSX_BE 1 +# else +# define XXH_VSX_BE 0 +# endif +# endif /* !defined(XXH_VSX_BE) */ + +# if XXH_VSX_BE +# if defined(__POWER9_VECTOR__) || (defined(__clang__) && defined(__s390x__)) +# define XXH_vec_revb vec_revb +# else +/*! + * A polyfill for POWER9's vec_revb(). + */ +XXH_FORCE_INLINE xxh_u64x2 XXH_vec_revb(xxh_u64x2 val) +{ + xxh_u8x16 const vByteSwap = { 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00, + 0x0F, 0x0E, 0x0D, 0x0C, 0x0B, 0x0A, 0x09, 0x08 }; + return vec_perm(val, val, vByteSwap); +} +# endif +# endif /* XXH_VSX_BE */ + +/*! + * Performs an unaligned vector load and byte swaps it on big endian. + */ +XXH_FORCE_INLINE xxh_u64x2 XXH_vec_loadu(const void *ptr) +{ + xxh_u64x2 ret; + XXH_memcpy(&ret, ptr, sizeof(xxh_u64x2)); +# if XXH_VSX_BE + ret = XXH_vec_revb(ret); +# endif + return ret; +} + +/* + * vec_mulo and vec_mule are very problematic intrinsics on PowerPC + * + * These intrinsics weren't added until GCC 8, despite existing for a while, + * and they are endian dependent. Also, their meaning swap depending on version. + * */ +# if defined(__s390x__) + /* s390x is always big endian, no issue on this platform */ +# define XXH_vec_mulo vec_mulo +# define XXH_vec_mule vec_mule +# elif defined(__clang__) && XXH_HAS_BUILTIN(__builtin_altivec_vmuleuw) +/* Clang has a better way to control this, we can just use the builtin which doesn't swap. */ +# define XXH_vec_mulo __builtin_altivec_vmulouw +# define XXH_vec_mule __builtin_altivec_vmuleuw +# else +/* gcc needs inline assembly */ +/* Adapted from https://github.com/google/highwayhash/blob/master/highwayhash/hh_vsx.h. */ +XXH_FORCE_INLINE xxh_u64x2 XXH_vec_mulo(xxh_u32x4 a, xxh_u32x4 b) +{ + xxh_u64x2 result; + __asm__("vmulouw %0, %1, %2" : "=v" (result) : "v" (a), "v" (b)); + return result; +} +XXH_FORCE_INLINE xxh_u64x2 XXH_vec_mule(xxh_u32x4 a, xxh_u32x4 b) +{ + xxh_u64x2 result; + __asm__("vmuleuw %0, %1, %2" : "=v" (result) : "v" (a), "v" (b)); + return result; +} +# endif /* XXH_vec_mulo, XXH_vec_mule */ +#endif /* XXH_VECTOR == XXH_VSX */ + + +/* prefetch + * can be disabled, by declaring XXH_NO_PREFETCH build macro */ +#if defined(XXH_NO_PREFETCH) +# define XXH_PREFETCH(ptr) (void)(ptr) /* disabled */ +#else +# if defined(_MSC_VER) && (defined(_M_X64) || defined(_M_IX86)) /* _mm_prefetch() not defined outside of x86/x64 */ +# include /* https://msdn.microsoft.com/fr-fr/library/84szxsww(v=vs.90).aspx */ +# define XXH_PREFETCH(ptr) _mm_prefetch((const char*)(ptr), _MM_HINT_T0) +# elif defined(__GNUC__) && ( (__GNUC__ >= 4) || ( (__GNUC__ == 3) && (__GNUC_MINOR__ >= 1) ) ) +# define XXH_PREFETCH(ptr) __builtin_prefetch((ptr), 0 /* rw==read */, 3 /* locality */) +# else +# define XXH_PREFETCH(ptr) (void)(ptr) /* disabled */ +# endif +#endif /* XXH_NO_PREFETCH */ + + +/* ========================================== + * XXH3 default settings + * ========================================== */ + +#define XXH_SECRET_DEFAULT_SIZE 192 /* minimum XXH3_SECRET_SIZE_MIN */ + +#if (XXH_SECRET_DEFAULT_SIZE < XXH3_SECRET_SIZE_MIN) +# error "default keyset is not large enough" +#endif + +/*! Pseudorandom secret taken directly from FARSH. */ +XXH_ALIGN(64) static const xxh_u8 XXH3_kSecret[XXH_SECRET_DEFAULT_SIZE] = { + 0xb8, 0xfe, 0x6c, 0x39, 0x23, 0xa4, 0x4b, 0xbe, 0x7c, 0x01, 0x81, 0x2c, 0xf7, 0x21, 0xad, 0x1c, + 0xde, 0xd4, 0x6d, 0xe9, 0x83, 0x90, 0x97, 0xdb, 0x72, 0x40, 0xa4, 0xa4, 0xb7, 0xb3, 0x67, 0x1f, + 0xcb, 0x79, 0xe6, 0x4e, 0xcc, 0xc0, 0xe5, 0x78, 0x82, 0x5a, 0xd0, 0x7d, 0xcc, 0xff, 0x72, 0x21, + 0xb8, 0x08, 0x46, 0x74, 0xf7, 0x43, 0x24, 0x8e, 0xe0, 0x35, 0x90, 0xe6, 0x81, 0x3a, 0x26, 0x4c, + 0x3c, 0x28, 0x52, 0xbb, 0x91, 0xc3, 0x00, 0xcb, 0x88, 0xd0, 0x65, 0x8b, 0x1b, 0x53, 0x2e, 0xa3, + 0x71, 0x64, 0x48, 0x97, 0xa2, 0x0d, 0xf9, 0x4e, 0x38, 0x19, 0xef, 0x46, 0xa9, 0xde, 0xac, 0xd8, + 0xa8, 0xfa, 0x76, 0x3f, 0xe3, 0x9c, 0x34, 0x3f, 0xf9, 0xdc, 0xbb, 0xc7, 0xc7, 0x0b, 0x4f, 0x1d, + 0x8a, 0x51, 0xe0, 0x4b, 0xcd, 0xb4, 0x59, 0x31, 0xc8, 0x9f, 0x7e, 0xc9, 0xd9, 0x78, 0x73, 0x64, + 0xea, 0xc5, 0xac, 0x83, 0x34, 0xd3, 0xeb, 0xc3, 0xc5, 0x81, 0xa0, 0xff, 0xfa, 0x13, 0x63, 0xeb, + 0x17, 0x0d, 0xdd, 0x51, 0xb7, 0xf0, 0xda, 0x49, 0xd3, 0x16, 0x55, 0x26, 0x29, 0xd4, 0x68, 0x9e, + 0x2b, 0x16, 0xbe, 0x58, 0x7d, 0x47, 0xa1, 0xfc, 0x8f, 0xf8, 0xb8, 0xd1, 0x7a, 0xd0, 0x31, 0xce, + 0x45, 0xcb, 0x3a, 0x8f, 0x95, 0x16, 0x04, 0x28, 0xaf, 0xd7, 0xfb, 0xca, 0xbb, 0x4b, 0x40, 0x7e, +}; + + +#ifdef XXH_OLD_NAMES +# define kSecret XXH3_kSecret +#endif + +#ifdef XXH_DOXYGEN +/*! + * @brief Calculates a 32-bit to 64-bit long multiply. + * + * Implemented as a macro. + * + * Wraps `__emulu` on MSVC x86 because it tends to call `__allmul` when it doesn't + * need to (but it shouldn't need to anyways, it is about 7 instructions to do + * a 64x64 multiply...). Since we know that this will _always_ emit `MULL`, we + * use that instead of the normal method. + * + * If you are compiling for platforms like Thumb-1 and don't have a better option, + * you may also want to write your own long multiply routine here. + * + * @param x, y Numbers to be multiplied + * @return 64-bit product of the low 32 bits of @p x and @p y. + */ +XXH_FORCE_INLINE xxh_u64 +XXH_mult32to64(xxh_u64 x, xxh_u64 y) +{ + return (x & 0xFFFFFFFF) * (y & 0xFFFFFFFF); +} +#elif defined(_MSC_VER) && defined(_M_IX86) +# define XXH_mult32to64(x, y) __emulu((unsigned)(x), (unsigned)(y)) +#else +/* + * Downcast + upcast is usually better than masking on older compilers like + * GCC 4.2 (especially 32-bit ones), all without affecting newer compilers. + * + * The other method, (x & 0xFFFFFFFF) * (y & 0xFFFFFFFF), will AND both operands + * and perform a full 64x64 multiply -- entirely redundant on 32-bit. + */ +# define XXH_mult32to64(x, y) ((xxh_u64)(xxh_u32)(x) * (xxh_u64)(xxh_u32)(y)) +#endif + +/*! + * @brief Calculates a 64->128-bit long multiply. + * + * Uses `__uint128_t` and `_umul128` if available, otherwise uses a scalar + * version. + * + * @param lhs , rhs The 64-bit integers to be multiplied + * @return The 128-bit result represented in an @ref XXH128_hash_t. + */ +static XXH128_hash_t +XXH_mult64to128(xxh_u64 lhs, xxh_u64 rhs) +{ + /* + * GCC/Clang __uint128_t method. + * + * On most 64-bit targets, GCC and Clang define a __uint128_t type. + * This is usually the best way as it usually uses a native long 64-bit + * multiply, such as MULQ on x86_64 or MUL + UMULH on aarch64. + * + * Usually. + * + * Despite being a 32-bit platform, Clang (and emscripten) define this type + * despite not having the arithmetic for it. This results in a laggy + * compiler builtin call which calculates a full 128-bit multiply. + * In that case it is best to use the portable one. + * https://github.com/Cyan4973/xxHash/issues/211#issuecomment-515575677 + */ +#if (defined(__GNUC__) || defined(__clang__)) && !defined(__wasm__) \ + && defined(__SIZEOF_INT128__) \ + || (defined(_INTEGRAL_MAX_BITS) && _INTEGRAL_MAX_BITS >= 128) + + __uint128_t const product = (__uint128_t)lhs * (__uint128_t)rhs; + XXH128_hash_t r128; + r128.low64 = (xxh_u64)(product); + r128.high64 = (xxh_u64)(product >> 64); + return r128; + + /* + * MSVC for x64's _umul128 method. + * + * xxh_u64 _umul128(xxh_u64 Multiplier, xxh_u64 Multiplicand, xxh_u64 *HighProduct); + * + * This compiles to single operand MUL on x64. + */ +#elif (defined(_M_X64) || defined(_M_IA64)) && !defined(_M_ARM64EC) + +#ifndef _MSC_VER +# pragma intrinsic(_umul128) +#endif + xxh_u64 product_high; + xxh_u64 const product_low = _umul128(lhs, rhs, &product_high); + XXH128_hash_t r128; + r128.low64 = product_low; + r128.high64 = product_high; + return r128; + + /* + * MSVC for ARM64's __umulh method. + * + * This compiles to the same MUL + UMULH as GCC/Clang's __uint128_t method. + */ +#elif defined(_M_ARM64) || defined(_M_ARM64EC) + +#ifndef _MSC_VER +# pragma intrinsic(__umulh) +#endif + XXH128_hash_t r128; + r128.low64 = lhs * rhs; + r128.high64 = __umulh(lhs, rhs); + return r128; + +#else + /* + * Portable scalar method. Optimized for 32-bit and 64-bit ALUs. + * + * This is a fast and simple grade school multiply, which is shown below + * with base 10 arithmetic instead of base 0x100000000. + * + * 9 3 // D2 lhs = 93 + * x 7 5 // D2 rhs = 75 + * ---------- + * 1 5 // D2 lo_lo = (93 % 10) * (75 % 10) = 15 + * 4 5 | // D2 hi_lo = (93 / 10) * (75 % 10) = 45 + * 2 1 | // D2 lo_hi = (93 % 10) * (75 / 10) = 21 + * + 6 3 | | // D2 hi_hi = (93 / 10) * (75 / 10) = 63 + * --------- + * 2 7 | // D2 cross = (15 / 10) + (45 % 10) + 21 = 27 + * + 6 7 | | // D2 upper = (27 / 10) + (45 / 10) + 63 = 67 + * --------- + * 6 9 7 5 // D4 res = (27 * 10) + (15 % 10) + (67 * 100) = 6975 + * + * The reasons for adding the products like this are: + * 1. It avoids manual carry tracking. Just like how + * (9 * 9) + 9 + 9 = 99, the same applies with this for UINT64_MAX. + * This avoids a lot of complexity. + * + * 2. It hints for, and on Clang, compiles to, the powerful UMAAL + * instruction available in ARM's Digital Signal Processing extension + * in 32-bit ARMv6 and later, which is shown below: + * + * void UMAAL(xxh_u32 *RdLo, xxh_u32 *RdHi, xxh_u32 Rn, xxh_u32 Rm) + * { + * xxh_u64 product = (xxh_u64)*RdLo * (xxh_u64)*RdHi + Rn + Rm; + * *RdLo = (xxh_u32)(product & 0xFFFFFFFF); + * *RdHi = (xxh_u32)(product >> 32); + * } + * + * This instruction was designed for efficient long multiplication, and + * allows this to be calculated in only 4 instructions at speeds + * comparable to some 64-bit ALUs. + * + * 3. It isn't terrible on other platforms. Usually this will be a couple + * of 32-bit ADD/ADCs. + */ + + /* First calculate all of the cross products. */ + xxh_u64 const lo_lo = XXH_mult32to64(lhs & 0xFFFFFFFF, rhs & 0xFFFFFFFF); + xxh_u64 const hi_lo = XXH_mult32to64(lhs >> 32, rhs & 0xFFFFFFFF); + xxh_u64 const lo_hi = XXH_mult32to64(lhs & 0xFFFFFFFF, rhs >> 32); + xxh_u64 const hi_hi = XXH_mult32to64(lhs >> 32, rhs >> 32); + + /* Now add the products together. These will never overflow. */ + xxh_u64 const cross = (lo_lo >> 32) + (hi_lo & 0xFFFFFFFF) + lo_hi; + xxh_u64 const upper = (hi_lo >> 32) + (cross >> 32) + hi_hi; + xxh_u64 const lower = (cross << 32) | (lo_lo & 0xFFFFFFFF); + + XXH128_hash_t r128; + r128.low64 = lower; + r128.high64 = upper; + return r128; +#endif +} + +/*! + * @brief Calculates a 64-bit to 128-bit multiply, then XOR folds it. + * + * The reason for the separate function is to prevent passing too many structs + * around by value. This will hopefully inline the multiply, but we don't force it. + * + * @param lhs , rhs The 64-bit integers to multiply + * @return The low 64 bits of the product XOR'd by the high 64 bits. + * @see XXH_mult64to128() + */ +static xxh_u64 +XXH3_mul128_fold64(xxh_u64 lhs, xxh_u64 rhs) +{ + XXH128_hash_t product = XXH_mult64to128(lhs, rhs); + return product.low64 ^ product.high64; +} + +/*! Seems to produce slightly better code on GCC for some reason. */ +XXH_FORCE_INLINE xxh_u64 XXH_xorshift64(xxh_u64 v64, int shift) +{ + XXH_ASSERT(0 <= shift && shift < 64); + return v64 ^ (v64 >> shift); +} + +/* + * This is a fast avalanche stage, + * suitable when input bits are already partially mixed + */ +static XXH64_hash_t XXH3_avalanche(xxh_u64 h64) +{ + h64 = XXH_xorshift64(h64, 37); + h64 *= 0x165667919E3779F9ULL; + h64 = XXH_xorshift64(h64, 32); + return h64; +} + +/* + * This is a stronger avalanche, + * inspired by Pelle Evensen's rrmxmx + * preferable when input has not been previously mixed + */ +static XXH64_hash_t XXH3_rrmxmx(xxh_u64 h64, xxh_u64 len) +{ + /* this mix is inspired by Pelle Evensen's rrmxmx */ + h64 ^= XXH_rotl64(h64, 49) ^ XXH_rotl64(h64, 24); + h64 *= 0x9FB21C651E98DF25ULL; + h64 ^= (h64 >> 35) + len ; + h64 *= 0x9FB21C651E98DF25ULL; + return XXH_xorshift64(h64, 28); +} + + +/* ========================================== + * Short keys + * ========================================== + * One of the shortcomings of XXH32 and XXH64 was that their performance was + * sub-optimal on short lengths. It used an iterative algorithm which strongly + * favored lengths that were a multiple of 4 or 8. + * + * Instead of iterating over individual inputs, we use a set of single shot + * functions which piece together a range of lengths and operate in constant time. + * + * Additionally, the number of multiplies has been significantly reduced. This + * reduces latency, especially when emulating 64-bit multiplies on 32-bit. + * + * Depending on the platform, this may or may not be faster than XXH32, but it + * is almost guaranteed to be faster than XXH64. + */ + +/* + * At very short lengths, there isn't enough input to fully hide secrets, or use + * the entire secret. + * + * There is also only a limited amount of mixing we can do before significantly + * impacting performance. + * + * Therefore, we use different sections of the secret and always mix two secret + * samples with an XOR. This should have no effect on performance on the + * seedless or withSeed variants because everything _should_ be constant folded + * by modern compilers. + * + * The XOR mixing hides individual parts of the secret and increases entropy. + * + * This adds an extra layer of strength for custom secrets. + */ +XXH_FORCE_INLINE XXH64_hash_t +XXH3_len_1to3_64b(const xxh_u8* input, size_t len, const xxh_u8* secret, XXH64_hash_t seed) +{ + XXH_ASSERT(input != NULL); + XXH_ASSERT(1 <= len && len <= 3); + XXH_ASSERT(secret != NULL); + /* + * len = 1: combined = { input[0], 0x01, input[0], input[0] } + * len = 2: combined = { input[1], 0x02, input[0], input[1] } + * len = 3: combined = { input[2], 0x03, input[0], input[1] } + */ + { xxh_u8 const c1 = input[0]; + xxh_u8 const c2 = input[len >> 1]; + xxh_u8 const c3 = input[len - 1]; + xxh_u32 const combined = ((xxh_u32)c1 << 16) | ((xxh_u32)c2 << 24) + | ((xxh_u32)c3 << 0) | ((xxh_u32)len << 8); + xxh_u64 const bitflip = (XXH_readLE32(secret) ^ XXH_readLE32(secret+4)) + seed; + xxh_u64 const keyed = (xxh_u64)combined ^ bitflip; + return XXH64_avalanche(keyed); + } +} + +XXH_FORCE_INLINE XXH64_hash_t +XXH3_len_4to8_64b(const xxh_u8* input, size_t len, const xxh_u8* secret, XXH64_hash_t seed) +{ + XXH_ASSERT(input != NULL); + XXH_ASSERT(secret != NULL); + XXH_ASSERT(4 <= len && len <= 8); + seed ^= (xxh_u64)XXH_swap32((xxh_u32)seed) << 32; + { xxh_u32 const input1 = XXH_readLE32(input); + xxh_u32 const input2 = XXH_readLE32(input + len - 4); + xxh_u64 const bitflip = (XXH_readLE64(secret+8) ^ XXH_readLE64(secret+16)) - seed; + xxh_u64 const input64 = input2 + (((xxh_u64)input1) << 32); + xxh_u64 const keyed = input64 ^ bitflip; + return XXH3_rrmxmx(keyed, len); + } +} + +XXH_FORCE_INLINE XXH64_hash_t +XXH3_len_9to16_64b(const xxh_u8* input, size_t len, const xxh_u8* secret, XXH64_hash_t seed) +{ + XXH_ASSERT(input != NULL); + XXH_ASSERT(secret != NULL); + XXH_ASSERT(9 <= len && len <= 16); + { xxh_u64 const bitflip1 = (XXH_readLE64(secret+24) ^ XXH_readLE64(secret+32)) + seed; + xxh_u64 const bitflip2 = (XXH_readLE64(secret+40) ^ XXH_readLE64(secret+48)) - seed; + xxh_u64 const input_lo = XXH_readLE64(input) ^ bitflip1; + xxh_u64 const input_hi = XXH_readLE64(input + len - 8) ^ bitflip2; + xxh_u64 const acc = len + + XXH_swap64(input_lo) + input_hi + + XXH3_mul128_fold64(input_lo, input_hi); + return XXH3_avalanche(acc); + } +} + +XXH_FORCE_INLINE XXH64_hash_t +XXH3_len_0to16_64b(const xxh_u8* input, size_t len, const xxh_u8* secret, XXH64_hash_t seed) +{ + XXH_ASSERT(len <= 16); + { if (XXH_likely(len > 8)) return XXH3_len_9to16_64b(input, len, secret, seed); + if (XXH_likely(len >= 4)) return XXH3_len_4to8_64b(input, len, secret, seed); + if (len) return XXH3_len_1to3_64b(input, len, secret, seed); + return XXH64_avalanche(seed ^ (XXH_readLE64(secret+56) ^ XXH_readLE64(secret+64))); + } +} + +/* + * DISCLAIMER: There are known *seed-dependent* multicollisions here due to + * multiplication by zero, affecting hashes of lengths 17 to 240. + * + * However, they are very unlikely. + * + * Keep this in mind when using the unseeded XXH3_64bits() variant: As with all + * unseeded non-cryptographic hashes, it does not attempt to defend itself + * against specially crafted inputs, only random inputs. + * + * Compared to classic UMAC where a 1 in 2^31 chance of 4 consecutive bytes + * cancelling out the secret is taken an arbitrary number of times (addressed + * in XXH3_accumulate_512), this collision is very unlikely with random inputs + * and/or proper seeding: + * + * This only has a 1 in 2^63 chance of 8 consecutive bytes cancelling out, in a + * function that is only called up to 16 times per hash with up to 240 bytes of + * input. + * + * This is not too bad for a non-cryptographic hash function, especially with + * only 64 bit outputs. + * + * The 128-bit variant (which trades some speed for strength) is NOT affected + * by this, although it is always a good idea to use a proper seed if you care + * about strength. + */ +XXH_FORCE_INLINE xxh_u64 XXH3_mix16B(const xxh_u8* XXH_RESTRICT input, + const xxh_u8* XXH_RESTRICT secret, xxh_u64 seed64) +{ +#if defined(__GNUC__) && !defined(__clang__) /* GCC, not Clang */ \ + && defined(__i386__) && defined(__SSE2__) /* x86 + SSE2 */ \ + && !defined(XXH_ENABLE_AUTOVECTORIZE) /* Define to disable like XXH32 hack */ + /* + * UGLY HACK: + * GCC for x86 tends to autovectorize the 128-bit multiply, resulting in + * slower code. + * + * By forcing seed64 into a register, we disrupt the cost model and + * cause it to scalarize. See `XXH32_round()` + * + * FIXME: Clang's output is still _much_ faster -- On an AMD Ryzen 3600, + * XXH3_64bits @ len=240 runs at 4.6 GB/s with Clang 9, but 3.3 GB/s on + * GCC 9.2, despite both emitting scalar code. + * + * GCC generates much better scalar code than Clang for the rest of XXH3, + * which is why finding a more optimal codepath is an interest. + */ + XXH_COMPILER_GUARD(seed64); +#endif + { xxh_u64 const input_lo = XXH_readLE64(input); + xxh_u64 const input_hi = XXH_readLE64(input+8); + return XXH3_mul128_fold64( + input_lo ^ (XXH_readLE64(secret) + seed64), + input_hi ^ (XXH_readLE64(secret+8) - seed64) + ); + } +} + +/* For mid range keys, XXH3 uses a Mum-hash variant. */ +XXH_FORCE_INLINE XXH64_hash_t +XXH3_len_17to128_64b(const xxh_u8* XXH_RESTRICT input, size_t len, + const xxh_u8* XXH_RESTRICT secret, size_t secretSize, + XXH64_hash_t seed) +{ + XXH_ASSERT(secretSize >= XXH3_SECRET_SIZE_MIN); (void)secretSize; + XXH_ASSERT(16 < len && len <= 128); + + { xxh_u64 acc = len * XXH_PRIME64_1; + if (len > 32) { + if (len > 64) { + if (len > 96) { + acc += XXH3_mix16B(input+48, secret+96, seed); + acc += XXH3_mix16B(input+len-64, secret+112, seed); + } + acc += XXH3_mix16B(input+32, secret+64, seed); + acc += XXH3_mix16B(input+len-48, secret+80, seed); + } + acc += XXH3_mix16B(input+16, secret+32, seed); + acc += XXH3_mix16B(input+len-32, secret+48, seed); + } + acc += XXH3_mix16B(input+0, secret+0, seed); + acc += XXH3_mix16B(input+len-16, secret+16, seed); + + return XXH3_avalanche(acc); + } +} + +#define XXH3_MIDSIZE_MAX 240 + +XXH_NO_INLINE XXH64_hash_t +XXH3_len_129to240_64b(const xxh_u8* XXH_RESTRICT input, size_t len, + const xxh_u8* XXH_RESTRICT secret, size_t secretSize, + XXH64_hash_t seed) +{ + XXH_ASSERT(secretSize >= XXH3_SECRET_SIZE_MIN); (void)secretSize; + XXH_ASSERT(128 < len && len <= XXH3_MIDSIZE_MAX); + + #define XXH3_MIDSIZE_STARTOFFSET 3 + #define XXH3_MIDSIZE_LASTOFFSET 17 + + { xxh_u64 acc = len * XXH_PRIME64_1; + int const nbRounds = (int)len / 16; + int i; + for (i=0; i<8; i++) { + acc += XXH3_mix16B(input+(16*i), secret+(16*i), seed); + } + acc = XXH3_avalanche(acc); + XXH_ASSERT(nbRounds >= 8); +#if defined(__clang__) /* Clang */ \ + && (defined(__ARM_NEON) || defined(__ARM_NEON__)) /* NEON */ \ + && !defined(XXH_ENABLE_AUTOVECTORIZE) /* Define to disable */ + /* + * UGLY HACK: + * Clang for ARMv7-A tries to vectorize this loop, similar to GCC x86. + * In everywhere else, it uses scalar code. + * + * For 64->128-bit multiplies, even if the NEON was 100% optimal, it + * would still be slower than UMAAL (see XXH_mult64to128). + * + * Unfortunately, Clang doesn't handle the long multiplies properly and + * converts them to the nonexistent "vmulq_u64" intrinsic, which is then + * scalarized into an ugly mess of VMOV.32 instructions. + * + * This mess is difficult to avoid without turning autovectorization + * off completely, but they are usually relatively minor and/or not + * worth it to fix. + * + * This loop is the easiest to fix, as unlike XXH32, this pragma + * _actually works_ because it is a loop vectorization instead of an + * SLP vectorization. + */ + #pragma clang loop vectorize(disable) +#endif + for (i=8 ; i < nbRounds; i++) { + acc += XXH3_mix16B(input+(16*i), secret+(16*(i-8)) + XXH3_MIDSIZE_STARTOFFSET, seed); + } + /* last bytes */ + acc += XXH3_mix16B(input + len - 16, secret + XXH3_SECRET_SIZE_MIN - XXH3_MIDSIZE_LASTOFFSET, seed); + return XXH3_avalanche(acc); + } +} + + +/* ======= Long Keys ======= */ + +#define XXH_STRIPE_LEN 64 +#define XXH_SECRET_CONSUME_RATE 8 /* nb of secret bytes consumed at each accumulation */ +#define XXH_ACC_NB (XXH_STRIPE_LEN / sizeof(xxh_u64)) + +#ifdef XXH_OLD_NAMES +# define STRIPE_LEN XXH_STRIPE_LEN +# define ACC_NB XXH_ACC_NB +#endif + +XXH_FORCE_INLINE void XXH_writeLE64(void* dst, xxh_u64 v64) +{ + if (!XXH_CPU_LITTLE_ENDIAN) v64 = XXH_swap64(v64); + XXH_memcpy(dst, &v64, sizeof(v64)); +} + +/* Several intrinsic functions below are supposed to accept __int64 as argument, + * as documented in https://software.intel.com/sites/landingpage/IntrinsicsGuide/ . + * However, several environments do not define __int64 type, + * requiring a workaround. + */ +#if !defined (__VMS) \ + && (defined (__cplusplus) \ + || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) ) + typedef int64_t xxh_i64; +#else + /* the following type must have a width of 64-bit */ + typedef long long xxh_i64; +#endif + + +/* + * XXH3_accumulate_512 is the tightest loop for long inputs, and it is the most optimized. + * + * It is a hardened version of UMAC, based off of FARSH's implementation. + * + * This was chosen because it adapts quite well to 32-bit, 64-bit, and SIMD + * implementations, and it is ridiculously fast. + * + * We harden it by mixing the original input to the accumulators as well as the product. + * + * This means that in the (relatively likely) case of a multiply by zero, the + * original input is preserved. + * + * On 128-bit inputs, we swap 64-bit pairs when we add the input to improve + * cross-pollination, as otherwise the upper and lower halves would be + * essentially independent. + * + * This doesn't matter on 64-bit hashes since they all get merged together in + * the end, so we skip the extra step. + * + * Both XXH3_64bits and XXH3_128bits use this subroutine. + */ + +#if (XXH_VECTOR == XXH_AVX512) \ + || (defined(XXH_DISPATCH_AVX512) && XXH_DISPATCH_AVX512 != 0) + +#ifndef XXH_TARGET_AVX512 +# define XXH_TARGET_AVX512 /* disable attribute target */ +#endif + +XXH_FORCE_INLINE XXH_TARGET_AVX512 void +XXH3_accumulate_512_avx512(void* XXH_RESTRICT acc, + const void* XXH_RESTRICT input, + const void* XXH_RESTRICT secret) +{ + __m512i* const xacc = (__m512i *) acc; + XXH_ASSERT((((size_t)acc) & 63) == 0); + XXH_STATIC_ASSERT(XXH_STRIPE_LEN == sizeof(__m512i)); + + { + /* data_vec = input[0]; */ + __m512i const data_vec = _mm512_loadu_si512 (input); + /* key_vec = secret[0]; */ + __m512i const key_vec = _mm512_loadu_si512 (secret); + /* data_key = data_vec ^ key_vec; */ + __m512i const data_key = _mm512_xor_si512 (data_vec, key_vec); + /* data_key_lo = data_key >> 32; */ + __m512i const data_key_lo = _mm512_shuffle_epi32 (data_key, (_MM_PERM_ENUM)_MM_SHUFFLE(0, 3, 0, 1)); + /* product = (data_key & 0xffffffff) * (data_key_lo & 0xffffffff); */ + __m512i const product = _mm512_mul_epu32 (data_key, data_key_lo); + /* xacc[0] += swap(data_vec); */ + __m512i const data_swap = _mm512_shuffle_epi32(data_vec, (_MM_PERM_ENUM)_MM_SHUFFLE(1, 0, 3, 2)); + __m512i const sum = _mm512_add_epi64(*xacc, data_swap); + /* xacc[0] += product; */ + *xacc = _mm512_add_epi64(product, sum); + } +} + +/* + * XXH3_scrambleAcc: Scrambles the accumulators to improve mixing. + * + * Multiplication isn't perfect, as explained by Google in HighwayHash: + * + * // Multiplication mixes/scrambles bytes 0-7 of the 64-bit result to + * // varying degrees. In descending order of goodness, bytes + * // 3 4 2 5 1 6 0 7 have quality 228 224 164 160 100 96 36 32. + * // As expected, the upper and lower bytes are much worse. + * + * Source: https://github.com/google/highwayhash/blob/0aaf66b/highwayhash/hh_avx2.h#L291 + * + * Since our algorithm uses a pseudorandom secret to add some variance into the + * mix, we don't need to (or want to) mix as often or as much as HighwayHash does. + * + * This isn't as tight as XXH3_accumulate, but still written in SIMD to avoid + * extraction. + * + * Both XXH3_64bits and XXH3_128bits use this subroutine. + */ + +XXH_FORCE_INLINE XXH_TARGET_AVX512 void +XXH3_scrambleAcc_avx512(void* XXH_RESTRICT acc, const void* XXH_RESTRICT secret) +{ + XXH_ASSERT((((size_t)acc) & 63) == 0); + XXH_STATIC_ASSERT(XXH_STRIPE_LEN == sizeof(__m512i)); + { __m512i* const xacc = (__m512i*) acc; + const __m512i prime32 = _mm512_set1_epi32((int)XXH_PRIME32_1); + + /* xacc[0] ^= (xacc[0] >> 47) */ + __m512i const acc_vec = *xacc; + __m512i const shifted = _mm512_srli_epi64 (acc_vec, 47); + __m512i const data_vec = _mm512_xor_si512 (acc_vec, shifted); + /* xacc[0] ^= secret; */ + __m512i const key_vec = _mm512_loadu_si512 (secret); + __m512i const data_key = _mm512_xor_si512 (data_vec, key_vec); + + /* xacc[0] *= XXH_PRIME32_1; */ + __m512i const data_key_hi = _mm512_shuffle_epi32 (data_key, (_MM_PERM_ENUM)_MM_SHUFFLE(0, 3, 0, 1)); + __m512i const prod_lo = _mm512_mul_epu32 (data_key, prime32); + __m512i const prod_hi = _mm512_mul_epu32 (data_key_hi, prime32); + *xacc = _mm512_add_epi64(prod_lo, _mm512_slli_epi64(prod_hi, 32)); + } +} + +XXH_FORCE_INLINE XXH_TARGET_AVX512 void +XXH3_initCustomSecret_avx512(void* XXH_RESTRICT customSecret, xxh_u64 seed64) +{ + XXH_STATIC_ASSERT((XXH_SECRET_DEFAULT_SIZE & 63) == 0); + XXH_STATIC_ASSERT(XXH_SEC_ALIGN == 64); + XXH_ASSERT(((size_t)customSecret & 63) == 0); + (void)(&XXH_writeLE64); + { int const nbRounds = XXH_SECRET_DEFAULT_SIZE / sizeof(__m512i); + __m512i const seed = _mm512_mask_set1_epi64(_mm512_set1_epi64((xxh_i64)seed64), 0xAA, (xxh_i64)(0U - seed64)); + + const __m512i* const src = (const __m512i*) ((const void*) XXH3_kSecret); + __m512i* const dest = ( __m512i*) customSecret; + int i; + XXH_ASSERT(((size_t)src & 63) == 0); /* control alignment */ + XXH_ASSERT(((size_t)dest & 63) == 0); + for (i=0; i < nbRounds; ++i) { + /* GCC has a bug, _mm512_stream_load_si512 accepts 'void*', not 'void const*', + * this will warn "discards 'const' qualifier". */ + union { + const __m512i* cp; + void* p; + } remote_const_void; + remote_const_void.cp = src + i; + dest[i] = _mm512_add_epi64(_mm512_stream_load_si512(remote_const_void.p), seed); + } } +} + +#endif + +#if (XXH_VECTOR == XXH_AVX2) \ + || (defined(XXH_DISPATCH_AVX2) && XXH_DISPATCH_AVX2 != 0) + +#ifndef XXH_TARGET_AVX2 +# define XXH_TARGET_AVX2 /* disable attribute target */ +#endif + +XXH_FORCE_INLINE XXH_TARGET_AVX2 void +XXH3_accumulate_512_avx2( void* XXH_RESTRICT acc, + const void* XXH_RESTRICT input, + const void* XXH_RESTRICT secret) +{ + XXH_ASSERT((((size_t)acc) & 31) == 0); + { __m256i* const xacc = (__m256i *) acc; + /* Unaligned. This is mainly for pointer arithmetic, and because + * _mm256_loadu_si256 requires a const __m256i * pointer for some reason. */ + const __m256i* const xinput = (const __m256i *) input; + /* Unaligned. This is mainly for pointer arithmetic, and because + * _mm256_loadu_si256 requires a const __m256i * pointer for some reason. */ + const __m256i* const xsecret = (const __m256i *) secret; + + size_t i; + for (i=0; i < XXH_STRIPE_LEN/sizeof(__m256i); i++) { + /* data_vec = xinput[i]; */ + __m256i const data_vec = _mm256_loadu_si256 (xinput+i); + /* key_vec = xsecret[i]; */ + __m256i const key_vec = _mm256_loadu_si256 (xsecret+i); + /* data_key = data_vec ^ key_vec; */ + __m256i const data_key = _mm256_xor_si256 (data_vec, key_vec); + /* data_key_lo = data_key >> 32; */ + __m256i const data_key_lo = _mm256_shuffle_epi32 (data_key, _MM_SHUFFLE(0, 3, 0, 1)); + /* product = (data_key & 0xffffffff) * (data_key_lo & 0xffffffff); */ + __m256i const product = _mm256_mul_epu32 (data_key, data_key_lo); + /* xacc[i] += swap(data_vec); */ + __m256i const data_swap = _mm256_shuffle_epi32(data_vec, _MM_SHUFFLE(1, 0, 3, 2)); + __m256i const sum = _mm256_add_epi64(xacc[i], data_swap); + /* xacc[i] += product; */ + xacc[i] = _mm256_add_epi64(product, sum); + } } +} + +XXH_FORCE_INLINE XXH_TARGET_AVX2 void +XXH3_scrambleAcc_avx2(void* XXH_RESTRICT acc, const void* XXH_RESTRICT secret) +{ + XXH_ASSERT((((size_t)acc) & 31) == 0); + { __m256i* const xacc = (__m256i*) acc; + /* Unaligned. This is mainly for pointer arithmetic, and because + * _mm256_loadu_si256 requires a const __m256i * pointer for some reason. */ + const __m256i* const xsecret = (const __m256i *) secret; + const __m256i prime32 = _mm256_set1_epi32((int)XXH_PRIME32_1); + + size_t i; + for (i=0; i < XXH_STRIPE_LEN/sizeof(__m256i); i++) { + /* xacc[i] ^= (xacc[i] >> 47) */ + __m256i const acc_vec = xacc[i]; + __m256i const shifted = _mm256_srli_epi64 (acc_vec, 47); + __m256i const data_vec = _mm256_xor_si256 (acc_vec, shifted); + /* xacc[i] ^= xsecret; */ + __m256i const key_vec = _mm256_loadu_si256 (xsecret+i); + __m256i const data_key = _mm256_xor_si256 (data_vec, key_vec); + + /* xacc[i] *= XXH_PRIME32_1; */ + __m256i const data_key_hi = _mm256_shuffle_epi32 (data_key, _MM_SHUFFLE(0, 3, 0, 1)); + __m256i const prod_lo = _mm256_mul_epu32 (data_key, prime32); + __m256i const prod_hi = _mm256_mul_epu32 (data_key_hi, prime32); + xacc[i] = _mm256_add_epi64(prod_lo, _mm256_slli_epi64(prod_hi, 32)); + } + } +} + +XXH_FORCE_INLINE XXH_TARGET_AVX2 void XXH3_initCustomSecret_avx2(void* XXH_RESTRICT customSecret, xxh_u64 seed64) +{ + XXH_STATIC_ASSERT((XXH_SECRET_DEFAULT_SIZE & 31) == 0); + XXH_STATIC_ASSERT((XXH_SECRET_DEFAULT_SIZE / sizeof(__m256i)) == 6); + XXH_STATIC_ASSERT(XXH_SEC_ALIGN <= 64); + (void)(&XXH_writeLE64); + XXH_PREFETCH(customSecret); + { __m256i const seed = _mm256_set_epi64x((xxh_i64)(0U - seed64), (xxh_i64)seed64, (xxh_i64)(0U - seed64), (xxh_i64)seed64); + + const __m256i* const src = (const __m256i*) ((const void*) XXH3_kSecret); + __m256i* dest = ( __m256i*) customSecret; + +# if defined(__GNUC__) || defined(__clang__) + /* + * On GCC & Clang, marking 'dest' as modified will cause the compiler: + * - do not extract the secret from sse registers in the internal loop + * - use less common registers, and avoid pushing these reg into stack + */ + XXH_COMPILER_GUARD(dest); +# endif + XXH_ASSERT(((size_t)src & 31) == 0); /* control alignment */ + XXH_ASSERT(((size_t)dest & 31) == 0); + + /* GCC -O2 need unroll loop manually */ + dest[0] = _mm256_add_epi64(_mm256_stream_load_si256(src+0), seed); + dest[1] = _mm256_add_epi64(_mm256_stream_load_si256(src+1), seed); + dest[2] = _mm256_add_epi64(_mm256_stream_load_si256(src+2), seed); + dest[3] = _mm256_add_epi64(_mm256_stream_load_si256(src+3), seed); + dest[4] = _mm256_add_epi64(_mm256_stream_load_si256(src+4), seed); + dest[5] = _mm256_add_epi64(_mm256_stream_load_si256(src+5), seed); + } +} + +#endif + +/* x86dispatch always generates SSE2 */ +#if (XXH_VECTOR == XXH_SSE2) || defined(XXH_X86DISPATCH) + +#ifndef XXH_TARGET_SSE2 +# define XXH_TARGET_SSE2 /* disable attribute target */ +#endif + +XXH_FORCE_INLINE XXH_TARGET_SSE2 void +XXH3_accumulate_512_sse2( void* XXH_RESTRICT acc, + const void* XXH_RESTRICT input, + const void* XXH_RESTRICT secret) +{ + /* SSE2 is just a half-scale version of the AVX2 version. */ + XXH_ASSERT((((size_t)acc) & 15) == 0); + { __m128i* const xacc = (__m128i *) acc; + /* Unaligned. This is mainly for pointer arithmetic, and because + * _mm_loadu_si128 requires a const __m128i * pointer for some reason. */ + const __m128i* const xinput = (const __m128i *) input; + /* Unaligned. This is mainly for pointer arithmetic, and because + * _mm_loadu_si128 requires a const __m128i * pointer for some reason. */ + const __m128i* const xsecret = (const __m128i *) secret; + + size_t i; + for (i=0; i < XXH_STRIPE_LEN/sizeof(__m128i); i++) { + /* data_vec = xinput[i]; */ + __m128i const data_vec = _mm_loadu_si128 (xinput+i); + /* key_vec = xsecret[i]; */ + __m128i const key_vec = _mm_loadu_si128 (xsecret+i); + /* data_key = data_vec ^ key_vec; */ + __m128i const data_key = _mm_xor_si128 (data_vec, key_vec); + /* data_key_lo = data_key >> 32; */ + __m128i const data_key_lo = _mm_shuffle_epi32 (data_key, _MM_SHUFFLE(0, 3, 0, 1)); + /* product = (data_key & 0xffffffff) * (data_key_lo & 0xffffffff); */ + __m128i const product = _mm_mul_epu32 (data_key, data_key_lo); + /* xacc[i] += swap(data_vec); */ + __m128i const data_swap = _mm_shuffle_epi32(data_vec, _MM_SHUFFLE(1,0,3,2)); + __m128i const sum = _mm_add_epi64(xacc[i], data_swap); + /* xacc[i] += product; */ + xacc[i] = _mm_add_epi64(product, sum); + } } +} + +XXH_FORCE_INLINE XXH_TARGET_SSE2 void +XXH3_scrambleAcc_sse2(void* XXH_RESTRICT acc, const void* XXH_RESTRICT secret) +{ + XXH_ASSERT((((size_t)acc) & 15) == 0); + { __m128i* const xacc = (__m128i*) acc; + /* Unaligned. This is mainly for pointer arithmetic, and because + * _mm_loadu_si128 requires a const __m128i * pointer for some reason. */ + const __m128i* const xsecret = (const __m128i *) secret; + const __m128i prime32 = _mm_set1_epi32((int)XXH_PRIME32_1); + + size_t i; + for (i=0; i < XXH_STRIPE_LEN/sizeof(__m128i); i++) { + /* xacc[i] ^= (xacc[i] >> 47) */ + __m128i const acc_vec = xacc[i]; + __m128i const shifted = _mm_srli_epi64 (acc_vec, 47); + __m128i const data_vec = _mm_xor_si128 (acc_vec, shifted); + /* xacc[i] ^= xsecret[i]; */ + __m128i const key_vec = _mm_loadu_si128 (xsecret+i); + __m128i const data_key = _mm_xor_si128 (data_vec, key_vec); + + /* xacc[i] *= XXH_PRIME32_1; */ + __m128i const data_key_hi = _mm_shuffle_epi32 (data_key, _MM_SHUFFLE(0, 3, 0, 1)); + __m128i const prod_lo = _mm_mul_epu32 (data_key, prime32); + __m128i const prod_hi = _mm_mul_epu32 (data_key_hi, prime32); + xacc[i] = _mm_add_epi64(prod_lo, _mm_slli_epi64(prod_hi, 32)); + } + } +} + +XXH_FORCE_INLINE XXH_TARGET_SSE2 void XXH3_initCustomSecret_sse2(void* XXH_RESTRICT customSecret, xxh_u64 seed64) +{ + XXH_STATIC_ASSERT((XXH_SECRET_DEFAULT_SIZE & 15) == 0); + (void)(&XXH_writeLE64); + { int const nbRounds = XXH_SECRET_DEFAULT_SIZE / sizeof(__m128i); + +# if defined(_MSC_VER) && defined(_M_IX86) && _MSC_VER < 1900 + /* MSVC 32bit mode does not support _mm_set_epi64x before 2015 */ + XXH_ALIGN(16) const xxh_i64 seed64x2[2] = { (xxh_i64)seed64, (xxh_i64)(0U - seed64) }; + __m128i const seed = _mm_load_si128((__m128i const*)seed64x2); +# else + __m128i const seed = _mm_set_epi64x((xxh_i64)(0U - seed64), (xxh_i64)seed64); +# endif + int i; + + const void* const src16 = XXH3_kSecret; + __m128i* dst16 = (__m128i*) customSecret; +# if defined(__GNUC__) || defined(__clang__) + /* + * On GCC & Clang, marking 'dest' as modified will cause the compiler: + * - do not extract the secret from sse registers in the internal loop + * - use less common registers, and avoid pushing these reg into stack + */ + XXH_COMPILER_GUARD(dst16); +# endif + XXH_ASSERT(((size_t)src16 & 15) == 0); /* control alignment */ + XXH_ASSERT(((size_t)dst16 & 15) == 0); + + for (i=0; i < nbRounds; ++i) { + dst16[i] = _mm_add_epi64(_mm_load_si128((const __m128i *)src16+i), seed); + } } +} + +#endif + +#if (XXH_VECTOR == XXH_NEON) + +/* forward declarations for the scalar routines */ +XXH_FORCE_INLINE void +XXH3_scalarRound(void* XXH_RESTRICT acc, void const* XXH_RESTRICT input, + void const* XXH_RESTRICT secret, size_t lane); + +XXH_FORCE_INLINE void +XXH3_scalarScrambleRound(void* XXH_RESTRICT acc, + void const* XXH_RESTRICT secret, size_t lane); + +/*! + * @internal + * @brief The bulk processing loop for NEON. + * + * The NEON code path is actually partially scalar when running on AArch64. This + * is to optimize the pipelining and can have up to 15% speedup depending on the + * CPU, and it also mitigates some GCC codegen issues. + * + * @see XXH3_NEON_LANES for configuring this and details about this optimization. + */ +XXH_FORCE_INLINE void +XXH3_accumulate_512_neon( void* XXH_RESTRICT acc, + const void* XXH_RESTRICT input, + const void* XXH_RESTRICT secret) +{ + XXH_ASSERT((((size_t)acc) & 15) == 0); + XXH_STATIC_ASSERT(XXH3_NEON_LANES > 0 && XXH3_NEON_LANES <= XXH_ACC_NB && XXH3_NEON_LANES % 2 == 0); + { + uint64x2_t* const xacc = (uint64x2_t *) acc; + /* We don't use a uint32x4_t pointer because it causes bus errors on ARMv7. */ + uint8_t const* const xinput = (const uint8_t *) input; + uint8_t const* const xsecret = (const uint8_t *) secret; + + size_t i; + /* NEON for the first few lanes (these loops are normally interleaved) */ + for (i=0; i < XXH3_NEON_LANES / 2; i++) { + /* data_vec = xinput[i]; */ + uint8x16_t data_vec = vld1q_u8(xinput + (i * 16)); + /* key_vec = xsecret[i]; */ + uint8x16_t key_vec = vld1q_u8(xsecret + (i * 16)); + uint64x2_t data_key; + uint32x2_t data_key_lo, data_key_hi; + /* xacc[i] += swap(data_vec); */ + uint64x2_t const data64 = vreinterpretq_u64_u8(data_vec); + uint64x2_t const swapped = vextq_u64(data64, data64, 1); + xacc[i] = vaddq_u64 (xacc[i], swapped); + /* data_key = data_vec ^ key_vec; */ + data_key = vreinterpretq_u64_u8(veorq_u8(data_vec, key_vec)); + /* data_key_lo = (uint32x2_t) (data_key & 0xFFFFFFFF); + * data_key_hi = (uint32x2_t) (data_key >> 32); + * data_key = UNDEFINED; */ + XXH_SPLIT_IN_PLACE(data_key, data_key_lo, data_key_hi); + /* xacc[i] += (uint64x2_t) data_key_lo * (uint64x2_t) data_key_hi; */ + xacc[i] = vmlal_u32 (xacc[i], data_key_lo, data_key_hi); + + } + /* Scalar for the remainder. This may be a zero iteration loop. */ + for (i = XXH3_NEON_LANES; i < XXH_ACC_NB; i++) { + XXH3_scalarRound(acc, input, secret, i); + } + } +} + +XXH_FORCE_INLINE void +XXH3_scrambleAcc_neon(void* XXH_RESTRICT acc, const void* XXH_RESTRICT secret) +{ + XXH_ASSERT((((size_t)acc) & 15) == 0); + + { uint64x2_t* xacc = (uint64x2_t*) acc; + uint8_t const* xsecret = (uint8_t const*) secret; + uint32x2_t prime = vdup_n_u32 (XXH_PRIME32_1); + + size_t i; + /* NEON for the first few lanes (these loops are normally interleaved) */ + for (i=0; i < XXH3_NEON_LANES / 2; i++) { + /* xacc[i] ^= (xacc[i] >> 47); */ + uint64x2_t acc_vec = xacc[i]; + uint64x2_t shifted = vshrq_n_u64 (acc_vec, 47); + uint64x2_t data_vec = veorq_u64 (acc_vec, shifted); + + /* xacc[i] ^= xsecret[i]; */ + uint8x16_t key_vec = vld1q_u8 (xsecret + (i * 16)); + uint64x2_t data_key = veorq_u64 (data_vec, vreinterpretq_u64_u8(key_vec)); + + /* xacc[i] *= XXH_PRIME32_1 */ + uint32x2_t data_key_lo, data_key_hi; + /* data_key_lo = (uint32x2_t) (xacc[i] & 0xFFFFFFFF); + * data_key_hi = (uint32x2_t) (xacc[i] >> 32); + * xacc[i] = UNDEFINED; */ + XXH_SPLIT_IN_PLACE(data_key, data_key_lo, data_key_hi); + { /* + * prod_hi = (data_key >> 32) * XXH_PRIME32_1; + * + * Avoid vmul_u32 + vshll_n_u32 since Clang 6 and 7 will + * incorrectly "optimize" this: + * tmp = vmul_u32(vmovn_u64(a), vmovn_u64(b)); + * shifted = vshll_n_u32(tmp, 32); + * to this: + * tmp = "vmulq_u64"(a, b); // no such thing! + * shifted = vshlq_n_u64(tmp, 32); + * + * However, unlike SSE, Clang lacks a 64-bit multiply routine + * for NEON, and it scalarizes two 64-bit multiplies instead. + * + * vmull_u32 has the same timing as vmul_u32, and it avoids + * this bug completely. + * See https://bugs.llvm.org/show_bug.cgi?id=39967 + */ + uint64x2_t prod_hi = vmull_u32 (data_key_hi, prime); + /* xacc[i] = prod_hi << 32; */ + xacc[i] = vshlq_n_u64(prod_hi, 32); + /* xacc[i] += (prod_hi & 0xFFFFFFFF) * XXH_PRIME32_1; */ + xacc[i] = vmlal_u32(xacc[i], data_key_lo, prime); + } + } + /* Scalar for the remainder. This may be a zero iteration loop. */ + for (i = XXH3_NEON_LANES; i < XXH_ACC_NB; i++) { + XXH3_scalarScrambleRound(acc, secret, i); + } + } +} + +#endif + +#if (XXH_VECTOR == XXH_VSX) + +XXH_FORCE_INLINE void +XXH3_accumulate_512_vsx( void* XXH_RESTRICT acc, + const void* XXH_RESTRICT input, + const void* XXH_RESTRICT secret) +{ + /* presumed aligned */ + unsigned int* const xacc = (unsigned int*) acc; + xxh_u64x2 const* const xinput = (xxh_u64x2 const*) input; /* no alignment restriction */ + xxh_u64x2 const* const xsecret = (xxh_u64x2 const*) secret; /* no alignment restriction */ + xxh_u64x2 const v32 = { 32, 32 }; + size_t i; + for (i = 0; i < XXH_STRIPE_LEN / sizeof(xxh_u64x2); i++) { + /* data_vec = xinput[i]; */ + xxh_u64x2 const data_vec = XXH_vec_loadu(xinput + i); + /* key_vec = xsecret[i]; */ + xxh_u64x2 const key_vec = XXH_vec_loadu(xsecret + i); + xxh_u64x2 const data_key = data_vec ^ key_vec; + /* shuffled = (data_key << 32) | (data_key >> 32); */ + xxh_u32x4 const shuffled = (xxh_u32x4)vec_rl(data_key, v32); + /* product = ((xxh_u64x2)data_key & 0xFFFFFFFF) * ((xxh_u64x2)shuffled & 0xFFFFFFFF); */ + xxh_u64x2 const product = XXH_vec_mulo((xxh_u32x4)data_key, shuffled); + /* acc_vec = xacc[i]; */ + xxh_u64x2 acc_vec = (xxh_u64x2)vec_xl(0, xacc + 4 * i); + acc_vec += product; + + /* swap high and low halves */ +#ifdef __s390x__ + acc_vec += vec_permi(data_vec, data_vec, 2); +#else + acc_vec += vec_xxpermdi(data_vec, data_vec, 2); +#endif + /* xacc[i] = acc_vec; */ + vec_xst((xxh_u32x4)acc_vec, 0, xacc + 4 * i); + } +} + +XXH_FORCE_INLINE void +XXH3_scrambleAcc_vsx(void* XXH_RESTRICT acc, const void* XXH_RESTRICT secret) +{ + XXH_ASSERT((((size_t)acc) & 15) == 0); + + { xxh_u64x2* const xacc = (xxh_u64x2*) acc; + const xxh_u64x2* const xsecret = (const xxh_u64x2*) secret; + /* constants */ + xxh_u64x2 const v32 = { 32, 32 }; + xxh_u64x2 const v47 = { 47, 47 }; + xxh_u32x4 const prime = { XXH_PRIME32_1, XXH_PRIME32_1, XXH_PRIME32_1, XXH_PRIME32_1 }; + size_t i; + for (i = 0; i < XXH_STRIPE_LEN / sizeof(xxh_u64x2); i++) { + /* xacc[i] ^= (xacc[i] >> 47); */ + xxh_u64x2 const acc_vec = xacc[i]; + xxh_u64x2 const data_vec = acc_vec ^ (acc_vec >> v47); + + /* xacc[i] ^= xsecret[i]; */ + xxh_u64x2 const key_vec = XXH_vec_loadu(xsecret + i); + xxh_u64x2 const data_key = data_vec ^ key_vec; + + /* xacc[i] *= XXH_PRIME32_1 */ + /* prod_lo = ((xxh_u64x2)data_key & 0xFFFFFFFF) * ((xxh_u64x2)prime & 0xFFFFFFFF); */ + xxh_u64x2 const prod_even = XXH_vec_mule((xxh_u32x4)data_key, prime); + /* prod_hi = ((xxh_u64x2)data_key >> 32) * ((xxh_u64x2)prime >> 32); */ + xxh_u64x2 const prod_odd = XXH_vec_mulo((xxh_u32x4)data_key, prime); + xacc[i] = prod_odd + (prod_even << v32); + } } +} + +#endif + +/* scalar variants - universal */ + +/*! + * @internal + * @brief Scalar round for @ref XXH3_accumulate_512_scalar(). + * + * This is extracted to its own function because the NEON path uses a combination + * of NEON and scalar. + */ +XXH_FORCE_INLINE void +XXH3_scalarRound(void* XXH_RESTRICT acc, + void const* XXH_RESTRICT input, + void const* XXH_RESTRICT secret, + size_t lane) +{ + xxh_u64* xacc = (xxh_u64*) acc; + xxh_u8 const* xinput = (xxh_u8 const*) input; + xxh_u8 const* xsecret = (xxh_u8 const*) secret; + XXH_ASSERT(lane < XXH_ACC_NB); + XXH_ASSERT(((size_t)acc & (XXH_ACC_ALIGN-1)) == 0); + { + xxh_u64 const data_val = XXH_readLE64(xinput + lane * 8); + xxh_u64 const data_key = data_val ^ XXH_readLE64(xsecret + lane * 8); + xacc[lane ^ 1] += data_val; /* swap adjacent lanes */ + xacc[lane] += XXH_mult32to64(data_key & 0xFFFFFFFF, data_key >> 32); + } +} + +/*! + * @internal + * @brief Processes a 64 byte block of data using the scalar path. + */ +XXH_FORCE_INLINE void +XXH3_accumulate_512_scalar(void* XXH_RESTRICT acc, + const void* XXH_RESTRICT input, + const void* XXH_RESTRICT secret) +{ + size_t i; + for (i=0; i < XXH_ACC_NB; i++) { + XXH3_scalarRound(acc, input, secret, i); + } +} + +/*! + * @internal + * @brief Scalar scramble step for @ref XXH3_scrambleAcc_scalar(). + * + * This is extracted to its own function because the NEON path uses a combination + * of NEON and scalar. + */ +XXH_FORCE_INLINE void +XXH3_scalarScrambleRound(void* XXH_RESTRICT acc, + void const* XXH_RESTRICT secret, + size_t lane) +{ + xxh_u64* const xacc = (xxh_u64*) acc; /* presumed aligned */ + const xxh_u8* const xsecret = (const xxh_u8*) secret; /* no alignment restriction */ + XXH_ASSERT((((size_t)acc) & (XXH_ACC_ALIGN-1)) == 0); + XXH_ASSERT(lane < XXH_ACC_NB); + { + xxh_u64 const key64 = XXH_readLE64(xsecret + lane * 8); + xxh_u64 acc64 = xacc[lane]; + acc64 = XXH_xorshift64(acc64, 47); + acc64 ^= key64; + acc64 *= XXH_PRIME32_1; + xacc[lane] = acc64; + } +} + +/*! + * @internal + * @brief Scrambles the accumulators after a large chunk has been read + */ +XXH_FORCE_INLINE void +XXH3_scrambleAcc_scalar(void* XXH_RESTRICT acc, const void* XXH_RESTRICT secret) +{ + size_t i; + for (i=0; i < XXH_ACC_NB; i++) { + XXH3_scalarScrambleRound(acc, secret, i); + } +} + +XXH_FORCE_INLINE void +XXH3_initCustomSecret_scalar(void* XXH_RESTRICT customSecret, xxh_u64 seed64) +{ + /* + * We need a separate pointer for the hack below, + * which requires a non-const pointer. + * Any decent compiler will optimize this out otherwise. + */ + const xxh_u8* kSecretPtr = XXH3_kSecret; + XXH_STATIC_ASSERT((XXH_SECRET_DEFAULT_SIZE & 15) == 0); + +#if defined(__clang__) && defined(__aarch64__) + /* + * UGLY HACK: + * Clang generates a bunch of MOV/MOVK pairs for aarch64, and they are + * placed sequentially, in order, at the top of the unrolled loop. + * + * While MOVK is great for generating constants (2 cycles for a 64-bit + * constant compared to 4 cycles for LDR), it fights for bandwidth with + * the arithmetic instructions. + * + * I L S + * MOVK + * MOVK + * MOVK + * MOVK + * ADD + * SUB STR + * STR + * By forcing loads from memory (as the asm line causes Clang to assume + * that XXH3_kSecretPtr has been changed), the pipelines are used more + * efficiently: + * I L S + * LDR + * ADD LDR + * SUB STR + * STR + * + * See XXH3_NEON_LANES for details on the pipsline. + * + * XXH3_64bits_withSeed, len == 256, Snapdragon 835 + * without hack: 2654.4 MB/s + * with hack: 3202.9 MB/s + */ + XXH_COMPILER_GUARD(kSecretPtr); +#endif + /* + * Note: in debug mode, this overrides the asm optimization + * and Clang will emit MOVK chains again. + */ + XXH_ASSERT(kSecretPtr == XXH3_kSecret); + + { int const nbRounds = XXH_SECRET_DEFAULT_SIZE / 16; + int i; + for (i=0; i < nbRounds; i++) { + /* + * The asm hack causes Clang to assume that kSecretPtr aliases with + * customSecret, and on aarch64, this prevented LDP from merging two + * loads together for free. Putting the loads together before the stores + * properly generates LDP. + */ + xxh_u64 lo = XXH_readLE64(kSecretPtr + 16*i) + seed64; + xxh_u64 hi = XXH_readLE64(kSecretPtr + 16*i + 8) - seed64; + XXH_writeLE64((xxh_u8*)customSecret + 16*i, lo); + XXH_writeLE64((xxh_u8*)customSecret + 16*i + 8, hi); + } } +} + + +typedef void (*XXH3_f_accumulate_512)(void* XXH_RESTRICT, const void*, const void*); +typedef void (*XXH3_f_scrambleAcc)(void* XXH_RESTRICT, const void*); +typedef void (*XXH3_f_initCustomSecret)(void* XXH_RESTRICT, xxh_u64); + + +#if (XXH_VECTOR == XXH_AVX512) + +#define XXH3_accumulate_512 XXH3_accumulate_512_avx512 +#define XXH3_scrambleAcc XXH3_scrambleAcc_avx512 +#define XXH3_initCustomSecret XXH3_initCustomSecret_avx512 + +#elif (XXH_VECTOR == XXH_AVX2) + +#define XXH3_accumulate_512 XXH3_accumulate_512_avx2 +#define XXH3_scrambleAcc XXH3_scrambleAcc_avx2 +#define XXH3_initCustomSecret XXH3_initCustomSecret_avx2 + +#elif (XXH_VECTOR == XXH_SSE2) + +#define XXH3_accumulate_512 XXH3_accumulate_512_sse2 +#define XXH3_scrambleAcc XXH3_scrambleAcc_sse2 +#define XXH3_initCustomSecret XXH3_initCustomSecret_sse2 + +#elif (XXH_VECTOR == XXH_NEON) + +#define XXH3_accumulate_512 XXH3_accumulate_512_neon +#define XXH3_scrambleAcc XXH3_scrambleAcc_neon +#define XXH3_initCustomSecret XXH3_initCustomSecret_scalar + +#elif (XXH_VECTOR == XXH_VSX) + +#define XXH3_accumulate_512 XXH3_accumulate_512_vsx +#define XXH3_scrambleAcc XXH3_scrambleAcc_vsx +#define XXH3_initCustomSecret XXH3_initCustomSecret_scalar + +#else /* scalar */ + +#define XXH3_accumulate_512 XXH3_accumulate_512_scalar +#define XXH3_scrambleAcc XXH3_scrambleAcc_scalar +#define XXH3_initCustomSecret XXH3_initCustomSecret_scalar + +#endif + + + +#ifndef XXH_PREFETCH_DIST +# ifdef __clang__ +# define XXH_PREFETCH_DIST 320 +# else +# if (XXH_VECTOR == XXH_AVX512) +# define XXH_PREFETCH_DIST 512 +# else +# define XXH_PREFETCH_DIST 384 +# endif +# endif /* __clang__ */ +#endif /* XXH_PREFETCH_DIST */ + +/* + * XXH3_accumulate() + * Loops over XXH3_accumulate_512(). + * Assumption: nbStripes will not overflow the secret size + */ +XXH_FORCE_INLINE void +XXH3_accumulate( xxh_u64* XXH_RESTRICT acc, + const xxh_u8* XXH_RESTRICT input, + const xxh_u8* XXH_RESTRICT secret, + size_t nbStripes, + XXH3_f_accumulate_512 f_acc512) +{ + size_t n; + for (n = 0; n < nbStripes; n++ ) { + const xxh_u8* const in = input + n*XXH_STRIPE_LEN; + XXH_PREFETCH(in + XXH_PREFETCH_DIST); + f_acc512(acc, + in, + secret + n*XXH_SECRET_CONSUME_RATE); + } +} + +XXH_FORCE_INLINE void +XXH3_hashLong_internal_loop(xxh_u64* XXH_RESTRICT acc, + const xxh_u8* XXH_RESTRICT input, size_t len, + const xxh_u8* XXH_RESTRICT secret, size_t secretSize, + XXH3_f_accumulate_512 f_acc512, + XXH3_f_scrambleAcc f_scramble) +{ + size_t const nbStripesPerBlock = (secretSize - XXH_STRIPE_LEN) / XXH_SECRET_CONSUME_RATE; + size_t const block_len = XXH_STRIPE_LEN * nbStripesPerBlock; + size_t const nb_blocks = (len - 1) / block_len; + + size_t n; + + XXH_ASSERT(secretSize >= XXH3_SECRET_SIZE_MIN); + + for (n = 0; n < nb_blocks; n++) { + XXH3_accumulate(acc, input + n*block_len, secret, nbStripesPerBlock, f_acc512); + f_scramble(acc, secret + secretSize - XXH_STRIPE_LEN); + } + + /* last partial block */ + XXH_ASSERT(len > XXH_STRIPE_LEN); + { size_t const nbStripes = ((len - 1) - (block_len * nb_blocks)) / XXH_STRIPE_LEN; + XXH_ASSERT(nbStripes <= (secretSize / XXH_SECRET_CONSUME_RATE)); + XXH3_accumulate(acc, input + nb_blocks*block_len, secret, nbStripes, f_acc512); + + /* last stripe */ + { const xxh_u8* const p = input + len - XXH_STRIPE_LEN; +#define XXH_SECRET_LASTACC_START 7 /* not aligned on 8, last secret is different from acc & scrambler */ + f_acc512(acc, p, secret + secretSize - XXH_STRIPE_LEN - XXH_SECRET_LASTACC_START); + } } +} + +XXH_FORCE_INLINE xxh_u64 +XXH3_mix2Accs(const xxh_u64* XXH_RESTRICT acc, const xxh_u8* XXH_RESTRICT secret) +{ + return XXH3_mul128_fold64( + acc[0] ^ XXH_readLE64(secret), + acc[1] ^ XXH_readLE64(secret+8) ); +} + +static XXH64_hash_t +XXH3_mergeAccs(const xxh_u64* XXH_RESTRICT acc, const xxh_u8* XXH_RESTRICT secret, xxh_u64 start) +{ + xxh_u64 result64 = start; + size_t i = 0; + + for (i = 0; i < 4; i++) { + result64 += XXH3_mix2Accs(acc+2*i, secret + 16*i); +#if defined(__clang__) /* Clang */ \ + && (defined(__arm__) || defined(__thumb__)) /* ARMv7 */ \ + && (defined(__ARM_NEON) || defined(__ARM_NEON__)) /* NEON */ \ + && !defined(XXH_ENABLE_AUTOVECTORIZE) /* Define to disable */ + /* + * UGLY HACK: + * Prevent autovectorization on Clang ARMv7-a. Exact same problem as + * the one in XXH3_len_129to240_64b. Speeds up shorter keys > 240b. + * XXH3_64bits, len == 256, Snapdragon 835: + * without hack: 2063.7 MB/s + * with hack: 2560.7 MB/s + */ + XXH_COMPILER_GUARD(result64); +#endif + } + + return XXH3_avalanche(result64); +} + +#define XXH3_INIT_ACC { XXH_PRIME32_3, XXH_PRIME64_1, XXH_PRIME64_2, XXH_PRIME64_3, \ + XXH_PRIME64_4, XXH_PRIME32_2, XXH_PRIME64_5, XXH_PRIME32_1 } + +XXH_FORCE_INLINE XXH64_hash_t +XXH3_hashLong_64b_internal(const void* XXH_RESTRICT input, size_t len, + const void* XXH_RESTRICT secret, size_t secretSize, + XXH3_f_accumulate_512 f_acc512, + XXH3_f_scrambleAcc f_scramble) +{ + XXH_ALIGN(XXH_ACC_ALIGN) xxh_u64 acc[XXH_ACC_NB] = XXH3_INIT_ACC; + + XXH3_hashLong_internal_loop(acc, (const xxh_u8*)input, len, (const xxh_u8*)secret, secretSize, f_acc512, f_scramble); + + /* converge into final hash */ + XXH_STATIC_ASSERT(sizeof(acc) == 64); + /* do not align on 8, so that the secret is different from the accumulator */ +#define XXH_SECRET_MERGEACCS_START 11 + XXH_ASSERT(secretSize >= sizeof(acc) + XXH_SECRET_MERGEACCS_START); + return XXH3_mergeAccs(acc, (const xxh_u8*)secret + XXH_SECRET_MERGEACCS_START, (xxh_u64)len * XXH_PRIME64_1); +} + +/* + * It's important for performance to transmit secret's size (when it's static) + * so that the compiler can properly optimize the vectorized loop. + * This makes a big performance difference for "medium" keys (<1 KB) when using AVX instruction set. + */ +XXH_FORCE_INLINE XXH64_hash_t +XXH3_hashLong_64b_withSecret(const void* XXH_RESTRICT input, size_t len, + XXH64_hash_t seed64, const xxh_u8* XXH_RESTRICT secret, size_t secretLen) +{ + (void)seed64; + return XXH3_hashLong_64b_internal(input, len, secret, secretLen, XXH3_accumulate_512, XXH3_scrambleAcc); +} + +/* + * It's preferable for performance that XXH3_hashLong is not inlined, + * as it results in a smaller function for small data, easier to the instruction cache. + * Note that inside this no_inline function, we do inline the internal loop, + * and provide a statically defined secret size to allow optimization of vector loop. + */ +XXH_NO_INLINE XXH64_hash_t +XXH3_hashLong_64b_default(const void* XXH_RESTRICT input, size_t len, + XXH64_hash_t seed64, const xxh_u8* XXH_RESTRICT secret, size_t secretLen) +{ + (void)seed64; (void)secret; (void)secretLen; + return XXH3_hashLong_64b_internal(input, len, XXH3_kSecret, sizeof(XXH3_kSecret), XXH3_accumulate_512, XXH3_scrambleAcc); +} + +/* + * XXH3_hashLong_64b_withSeed(): + * Generate a custom key based on alteration of default XXH3_kSecret with the seed, + * and then use this key for long mode hashing. + * + * This operation is decently fast but nonetheless costs a little bit of time. + * Try to avoid it whenever possible (typically when seed==0). + * + * It's important for performance that XXH3_hashLong is not inlined. Not sure + * why (uop cache maybe?), but the difference is large and easily measurable. + */ +XXH_FORCE_INLINE XXH64_hash_t +XXH3_hashLong_64b_withSeed_internal(const void* input, size_t len, + XXH64_hash_t seed, + XXH3_f_accumulate_512 f_acc512, + XXH3_f_scrambleAcc f_scramble, + XXH3_f_initCustomSecret f_initSec) +{ + if (seed == 0) + return XXH3_hashLong_64b_internal(input, len, + XXH3_kSecret, sizeof(XXH3_kSecret), + f_acc512, f_scramble); + { XXH_ALIGN(XXH_SEC_ALIGN) xxh_u8 secret[XXH_SECRET_DEFAULT_SIZE]; + f_initSec(secret, seed); + return XXH3_hashLong_64b_internal(input, len, secret, sizeof(secret), + f_acc512, f_scramble); + } +} + +/* + * It's important for performance that XXH3_hashLong is not inlined. + */ +XXH_NO_INLINE XXH64_hash_t +XXH3_hashLong_64b_withSeed(const void* input, size_t len, + XXH64_hash_t seed, const xxh_u8* secret, size_t secretLen) +{ + (void)secret; (void)secretLen; + return XXH3_hashLong_64b_withSeed_internal(input, len, seed, + XXH3_accumulate_512, XXH3_scrambleAcc, XXH3_initCustomSecret); +} + + +typedef XXH64_hash_t (*XXH3_hashLong64_f)(const void* XXH_RESTRICT, size_t, + XXH64_hash_t, const xxh_u8* XXH_RESTRICT, size_t); + +XXH_FORCE_INLINE XXH64_hash_t +XXH3_64bits_internal(const void* XXH_RESTRICT input, size_t len, + XXH64_hash_t seed64, const void* XXH_RESTRICT secret, size_t secretLen, + XXH3_hashLong64_f f_hashLong) +{ + XXH_ASSERT(secretLen >= XXH3_SECRET_SIZE_MIN); + /* + * If an action is to be taken if `secretLen` condition is not respected, + * it should be done here. + * For now, it's a contract pre-condition. + * Adding a check and a branch here would cost performance at every hash. + * Also, note that function signature doesn't offer room to return an error. + */ + if (len <= 16) + return XXH3_len_0to16_64b((const xxh_u8*)input, len, (const xxh_u8*)secret, seed64); + if (len <= 128) + return XXH3_len_17to128_64b((const xxh_u8*)input, len, (const xxh_u8*)secret, secretLen, seed64); + if (len <= XXH3_MIDSIZE_MAX) + return XXH3_len_129to240_64b((const xxh_u8*)input, len, (const xxh_u8*)secret, secretLen, seed64); + return f_hashLong(input, len, seed64, (const xxh_u8*)secret, secretLen); +} + + +/* === Public entry point === */ + +/*! @ingroup xxh3_family */ +XXH_PUBLIC_API XXH64_hash_t XXH3_64bits(const void* input, size_t len) +{ + return XXH3_64bits_internal(input, len, 0, XXH3_kSecret, sizeof(XXH3_kSecret), XXH3_hashLong_64b_default); +} + +/*! @ingroup xxh3_family */ +XXH_PUBLIC_API XXH64_hash_t +XXH3_64bits_withSecret(const void* input, size_t len, const void* secret, size_t secretSize) +{ + return XXH3_64bits_internal(input, len, 0, secret, secretSize, XXH3_hashLong_64b_withSecret); +} + +/*! @ingroup xxh3_family */ +XXH_PUBLIC_API XXH64_hash_t +XXH3_64bits_withSeed(const void* input, size_t len, XXH64_hash_t seed) +{ + return XXH3_64bits_internal(input, len, seed, XXH3_kSecret, sizeof(XXH3_kSecret), XXH3_hashLong_64b_withSeed); +} + +XXH_PUBLIC_API XXH64_hash_t +XXH3_64bits_withSecretandSeed(const void* input, size_t len, const void* secret, size_t secretSize, XXH64_hash_t seed) +{ + if (len <= XXH3_MIDSIZE_MAX) + return XXH3_64bits_internal(input, len, seed, XXH3_kSecret, sizeof(XXH3_kSecret), NULL); + return XXH3_hashLong_64b_withSecret(input, len, seed, (const xxh_u8*)secret, secretSize); +} + + +/* === XXH3 streaming === */ + +/* + * Malloc's a pointer that is always aligned to align. + * + * This must be freed with `XXH_alignedFree()`. + * + * malloc typically guarantees 16 byte alignment on 64-bit systems and 8 byte + * alignment on 32-bit. This isn't enough for the 32 byte aligned loads in AVX2 + * or on 32-bit, the 16 byte aligned loads in SSE2 and NEON. + * + * This underalignment previously caused a rather obvious crash which went + * completely unnoticed due to XXH3_createState() not actually being tested. + * Credit to RedSpah for noticing this bug. + * + * The alignment is done manually: Functions like posix_memalign or _mm_malloc + * are avoided: To maintain portability, we would have to write a fallback + * like this anyways, and besides, testing for the existence of library + * functions without relying on external build tools is impossible. + * + * The method is simple: Overallocate, manually align, and store the offset + * to the original behind the returned pointer. + * + * Align must be a power of 2 and 8 <= align <= 128. + */ +static void* XXH_alignedMalloc(size_t s, size_t align) +{ + XXH_ASSERT(align <= 128 && align >= 8); /* range check */ + XXH_ASSERT((align & (align-1)) == 0); /* power of 2 */ + XXH_ASSERT(s != 0 && s < (s + align)); /* empty/overflow */ + { /* Overallocate to make room for manual realignment and an offset byte */ + xxh_u8* base = (xxh_u8*)XXH_malloc(s + align); + if (base != NULL) { + /* + * Get the offset needed to align this pointer. + * + * Even if the returned pointer is aligned, there will always be + * at least one byte to store the offset to the original pointer. + */ + size_t offset = align - ((size_t)base & (align - 1)); /* base % align */ + /* Add the offset for the now-aligned pointer */ + xxh_u8* ptr = base + offset; + + XXH_ASSERT((size_t)ptr % align == 0); + + /* Store the offset immediately before the returned pointer. */ + ptr[-1] = (xxh_u8)offset; + return ptr; + } + return NULL; + } +} +/* + * Frees an aligned pointer allocated by XXH_alignedMalloc(). Don't pass + * normal malloc'd pointers, XXH_alignedMalloc has a specific data layout. + */ +static void XXH_alignedFree(void* p) +{ + if (p != NULL) { + xxh_u8* ptr = (xxh_u8*)p; + /* Get the offset byte we added in XXH_malloc. */ + xxh_u8 offset = ptr[-1]; + /* Free the original malloc'd pointer */ + xxh_u8* base = ptr - offset; + XXH_free(base); + } +} +/*! @ingroup xxh3_family */ +XXH_PUBLIC_API XXH3_state_t* XXH3_createState(void) +{ + XXH3_state_t* const state = (XXH3_state_t*)XXH_alignedMalloc(sizeof(XXH3_state_t), 64); + if (state==NULL) return NULL; + XXH3_INITSTATE(state); + return state; +} + +/*! @ingroup xxh3_family */ +XXH_PUBLIC_API XXH_errorcode XXH3_freeState(XXH3_state_t* statePtr) +{ + XXH_alignedFree(statePtr); + return XXH_OK; +} + +/*! @ingroup xxh3_family */ +XXH_PUBLIC_API void +XXH3_copyState(XXH3_state_t* dst_state, const XXH3_state_t* src_state) +{ + XXH_memcpy(dst_state, src_state, sizeof(*dst_state)); +} + +static void +XXH3_reset_internal(XXH3_state_t* statePtr, + XXH64_hash_t seed, + const void* secret, size_t secretSize) +{ + size_t const initStart = offsetof(XXH3_state_t, bufferedSize); + size_t const initLength = offsetof(XXH3_state_t, nbStripesPerBlock) - initStart; + XXH_ASSERT(offsetof(XXH3_state_t, nbStripesPerBlock) > initStart); + XXH_ASSERT(statePtr != NULL); + /* set members from bufferedSize to nbStripesPerBlock (excluded) to 0 */ + memset((char*)statePtr + initStart, 0, initLength); + statePtr->acc[0] = XXH_PRIME32_3; + statePtr->acc[1] = XXH_PRIME64_1; + statePtr->acc[2] = XXH_PRIME64_2; + statePtr->acc[3] = XXH_PRIME64_3; + statePtr->acc[4] = XXH_PRIME64_4; + statePtr->acc[5] = XXH_PRIME32_2; + statePtr->acc[6] = XXH_PRIME64_5; + statePtr->acc[7] = XXH_PRIME32_1; + statePtr->seed = seed; + statePtr->useSeed = (seed != 0); + statePtr->extSecret = (const unsigned char*)secret; + XXH_ASSERT(secretSize >= XXH3_SECRET_SIZE_MIN); + statePtr->secretLimit = secretSize - XXH_STRIPE_LEN; + statePtr->nbStripesPerBlock = statePtr->secretLimit / XXH_SECRET_CONSUME_RATE; +} + +/*! @ingroup xxh3_family */ +XXH_PUBLIC_API XXH_errorcode +XXH3_64bits_reset(XXH3_state_t* statePtr) +{ + if (statePtr == NULL) return XXH_ERROR; + XXH3_reset_internal(statePtr, 0, XXH3_kSecret, XXH_SECRET_DEFAULT_SIZE); + return XXH_OK; +} + +/*! @ingroup xxh3_family */ +XXH_PUBLIC_API XXH_errorcode +XXH3_64bits_reset_withSecret(XXH3_state_t* statePtr, const void* secret, size_t secretSize) +{ + if (statePtr == NULL) return XXH_ERROR; + XXH3_reset_internal(statePtr, 0, secret, secretSize); + if (secret == NULL) return XXH_ERROR; + if (secretSize < XXH3_SECRET_SIZE_MIN) return XXH_ERROR; + return XXH_OK; +} + +/*! @ingroup xxh3_family */ +XXH_PUBLIC_API XXH_errorcode +XXH3_64bits_reset_withSeed(XXH3_state_t* statePtr, XXH64_hash_t seed) +{ + if (statePtr == NULL) return XXH_ERROR; + if (seed==0) return XXH3_64bits_reset(statePtr); + if ((seed != statePtr->seed) || (statePtr->extSecret != NULL)) + XXH3_initCustomSecret(statePtr->customSecret, seed); + XXH3_reset_internal(statePtr, seed, NULL, XXH_SECRET_DEFAULT_SIZE); + return XXH_OK; +} + +/*! @ingroup xxh3_family */ +XXH_PUBLIC_API XXH_errorcode +XXH3_64bits_reset_withSecretandSeed(XXH3_state_t* statePtr, const void* secret, size_t secretSize, XXH64_hash_t seed64) +{ + if (statePtr == NULL) return XXH_ERROR; + if (secret == NULL) return XXH_ERROR; + if (secretSize < XXH3_SECRET_SIZE_MIN) return XXH_ERROR; + XXH3_reset_internal(statePtr, seed64, secret, secretSize); + statePtr->useSeed = 1; /* always, even if seed64==0 */ + return XXH_OK; +} + +/* Note : when XXH3_consumeStripes() is invoked, + * there must be a guarantee that at least one more byte must be consumed from input + * so that the function can blindly consume all stripes using the "normal" secret segment */ +XXH_FORCE_INLINE void +XXH3_consumeStripes(xxh_u64* XXH_RESTRICT acc, + size_t* XXH_RESTRICT nbStripesSoFarPtr, size_t nbStripesPerBlock, + const xxh_u8* XXH_RESTRICT input, size_t nbStripes, + const xxh_u8* XXH_RESTRICT secret, size_t secretLimit, + XXH3_f_accumulate_512 f_acc512, + XXH3_f_scrambleAcc f_scramble) +{ + XXH_ASSERT(nbStripes <= nbStripesPerBlock); /* can handle max 1 scramble per invocation */ + XXH_ASSERT(*nbStripesSoFarPtr < nbStripesPerBlock); + if (nbStripesPerBlock - *nbStripesSoFarPtr <= nbStripes) { + /* need a scrambling operation */ + size_t const nbStripesToEndofBlock = nbStripesPerBlock - *nbStripesSoFarPtr; + size_t const nbStripesAfterBlock = nbStripes - nbStripesToEndofBlock; + XXH3_accumulate(acc, input, secret + nbStripesSoFarPtr[0] * XXH_SECRET_CONSUME_RATE, nbStripesToEndofBlock, f_acc512); + f_scramble(acc, secret + secretLimit); + XXH3_accumulate(acc, input + nbStripesToEndofBlock * XXH_STRIPE_LEN, secret, nbStripesAfterBlock, f_acc512); + *nbStripesSoFarPtr = nbStripesAfterBlock; + } else { + XXH3_accumulate(acc, input, secret + nbStripesSoFarPtr[0] * XXH_SECRET_CONSUME_RATE, nbStripes, f_acc512); + *nbStripesSoFarPtr += nbStripes; + } +} + +#ifndef XXH3_STREAM_USE_STACK +# ifndef __clang__ /* clang doesn't need additional stack space */ +# define XXH3_STREAM_USE_STACK 1 +# endif +#endif +/* + * Both XXH3_64bits_update and XXH3_128bits_update use this routine. + */ +XXH_FORCE_INLINE XXH_errorcode +XXH3_update(XXH3_state_t* XXH_RESTRICT const state, + const xxh_u8* XXH_RESTRICT input, size_t len, + XXH3_f_accumulate_512 f_acc512, + XXH3_f_scrambleAcc f_scramble) +{ + if (input==NULL) { + XXH_ASSERT(len == 0); + return XXH_OK; + } + + XXH_ASSERT(state != NULL); + { const xxh_u8* const bEnd = input + len; + const unsigned char* const secret = (state->extSecret == NULL) ? state->customSecret : state->extSecret; +#if defined(XXH3_STREAM_USE_STACK) && XXH3_STREAM_USE_STACK >= 1 + /* For some reason, gcc and MSVC seem to suffer greatly + * when operating accumulators directly into state. + * Operating into stack space seems to enable proper optimization. + * clang, on the other hand, doesn't seem to need this trick */ + XXH_ALIGN(XXH_ACC_ALIGN) xxh_u64 acc[8]; memcpy(acc, state->acc, sizeof(acc)); +#else + xxh_u64* XXH_RESTRICT const acc = state->acc; +#endif + state->totalLen += len; + XXH_ASSERT(state->bufferedSize <= XXH3_INTERNALBUFFER_SIZE); + + /* small input : just fill in tmp buffer */ + if (state->bufferedSize + len <= XXH3_INTERNALBUFFER_SIZE) { + XXH_memcpy(state->buffer + state->bufferedSize, input, len); + state->bufferedSize += (XXH32_hash_t)len; + return XXH_OK; + } + + /* total input is now > XXH3_INTERNALBUFFER_SIZE */ + #define XXH3_INTERNALBUFFER_STRIPES (XXH3_INTERNALBUFFER_SIZE / XXH_STRIPE_LEN) + XXH_STATIC_ASSERT(XXH3_INTERNALBUFFER_SIZE % XXH_STRIPE_LEN == 0); /* clean multiple */ + + /* + * Internal buffer is partially filled (always, except at beginning) + * Complete it, then consume it. + */ + if (state->bufferedSize) { + size_t const loadSize = XXH3_INTERNALBUFFER_SIZE - state->bufferedSize; + XXH_memcpy(state->buffer + state->bufferedSize, input, loadSize); + input += loadSize; + XXH3_consumeStripes(acc, + &state->nbStripesSoFar, state->nbStripesPerBlock, + state->buffer, XXH3_INTERNALBUFFER_STRIPES, + secret, state->secretLimit, + f_acc512, f_scramble); + state->bufferedSize = 0; + } + XXH_ASSERT(input < bEnd); + + /* large input to consume : ingest per full block */ + if ((size_t)(bEnd - input) > state->nbStripesPerBlock * XXH_STRIPE_LEN) { + size_t nbStripes = (size_t)(bEnd - 1 - input) / XXH_STRIPE_LEN; + XXH_ASSERT(state->nbStripesPerBlock >= state->nbStripesSoFar); + /* join to current block's end */ + { size_t const nbStripesToEnd = state->nbStripesPerBlock - state->nbStripesSoFar; + XXH_ASSERT(nbStripesToEnd <= nbStripes); + XXH3_accumulate(acc, input, secret + state->nbStripesSoFar * XXH_SECRET_CONSUME_RATE, nbStripesToEnd, f_acc512); + f_scramble(acc, secret + state->secretLimit); + state->nbStripesSoFar = 0; + input += nbStripesToEnd * XXH_STRIPE_LEN; + nbStripes -= nbStripesToEnd; + } + /* consume per entire blocks */ + while(nbStripes >= state->nbStripesPerBlock) { + XXH3_accumulate(acc, input, secret, state->nbStripesPerBlock, f_acc512); + f_scramble(acc, secret + state->secretLimit); + input += state->nbStripesPerBlock * XXH_STRIPE_LEN; + nbStripes -= state->nbStripesPerBlock; + } + /* consume last partial block */ + XXH3_accumulate(acc, input, secret, nbStripes, f_acc512); + input += nbStripes * XXH_STRIPE_LEN; + XXH_ASSERT(input < bEnd); /* at least some bytes left */ + state->nbStripesSoFar = nbStripes; + /* buffer predecessor of last partial stripe */ + XXH_memcpy(state->buffer + sizeof(state->buffer) - XXH_STRIPE_LEN, input - XXH_STRIPE_LEN, XXH_STRIPE_LEN); + XXH_ASSERT(bEnd - input <= XXH_STRIPE_LEN); + } else { + /* content to consume <= block size */ + /* Consume input by a multiple of internal buffer size */ + if (bEnd - input > XXH3_INTERNALBUFFER_SIZE) { + const xxh_u8* const limit = bEnd - XXH3_INTERNALBUFFER_SIZE; + do { + XXH3_consumeStripes(acc, + &state->nbStripesSoFar, state->nbStripesPerBlock, + input, XXH3_INTERNALBUFFER_STRIPES, + secret, state->secretLimit, + f_acc512, f_scramble); + input += XXH3_INTERNALBUFFER_SIZE; + } while (inputbuffer + sizeof(state->buffer) - XXH_STRIPE_LEN, input - XXH_STRIPE_LEN, XXH_STRIPE_LEN); + } + } + + /* Some remaining input (always) : buffer it */ + XXH_ASSERT(input < bEnd); + XXH_ASSERT(bEnd - input <= XXH3_INTERNALBUFFER_SIZE); + XXH_ASSERT(state->bufferedSize == 0); + XXH_memcpy(state->buffer, input, (size_t)(bEnd-input)); + state->bufferedSize = (XXH32_hash_t)(bEnd-input); +#if defined(XXH3_STREAM_USE_STACK) && XXH3_STREAM_USE_STACK >= 1 + /* save stack accumulators into state */ + memcpy(state->acc, acc, sizeof(acc)); +#endif + } + + return XXH_OK; +} + +/*! @ingroup xxh3_family */ +XXH_PUBLIC_API XXH_errorcode +XXH3_64bits_update(XXH3_state_t* state, const void* input, size_t len) +{ + return XXH3_update(state, (const xxh_u8*)input, len, + XXH3_accumulate_512, XXH3_scrambleAcc); +} + + +XXH_FORCE_INLINE void +XXH3_digest_long (XXH64_hash_t* acc, + const XXH3_state_t* state, + const unsigned char* secret) +{ + /* + * Digest on a local copy. This way, the state remains unaltered, and it can + * continue ingesting more input afterwards. + */ + XXH_memcpy(acc, state->acc, sizeof(state->acc)); + if (state->bufferedSize >= XXH_STRIPE_LEN) { + size_t const nbStripes = (state->bufferedSize - 1) / XXH_STRIPE_LEN; + size_t nbStripesSoFar = state->nbStripesSoFar; + XXH3_consumeStripes(acc, + &nbStripesSoFar, state->nbStripesPerBlock, + state->buffer, nbStripes, + secret, state->secretLimit, + XXH3_accumulate_512, XXH3_scrambleAcc); + /* last stripe */ + XXH3_accumulate_512(acc, + state->buffer + state->bufferedSize - XXH_STRIPE_LEN, + secret + state->secretLimit - XXH_SECRET_LASTACC_START); + } else { /* bufferedSize < XXH_STRIPE_LEN */ + xxh_u8 lastStripe[XXH_STRIPE_LEN]; + size_t const catchupSize = XXH_STRIPE_LEN - state->bufferedSize; + XXH_ASSERT(state->bufferedSize > 0); /* there is always some input buffered */ + XXH_memcpy(lastStripe, state->buffer + sizeof(state->buffer) - catchupSize, catchupSize); + XXH_memcpy(lastStripe + catchupSize, state->buffer, state->bufferedSize); + XXH3_accumulate_512(acc, + lastStripe, + secret + state->secretLimit - XXH_SECRET_LASTACC_START); + } +} + +/*! @ingroup xxh3_family */ +XXH_PUBLIC_API XXH64_hash_t XXH3_64bits_digest (const XXH3_state_t* state) +{ + const unsigned char* const secret = (state->extSecret == NULL) ? state->customSecret : state->extSecret; + if (state->totalLen > XXH3_MIDSIZE_MAX) { + XXH_ALIGN(XXH_ACC_ALIGN) XXH64_hash_t acc[XXH_ACC_NB]; + XXH3_digest_long(acc, state, secret); + return XXH3_mergeAccs(acc, + secret + XXH_SECRET_MERGEACCS_START, + (xxh_u64)state->totalLen * XXH_PRIME64_1); + } + /* totalLen <= XXH3_MIDSIZE_MAX: digesting a short input */ + if (state->useSeed) + return XXH3_64bits_withSeed(state->buffer, (size_t)state->totalLen, state->seed); + return XXH3_64bits_withSecret(state->buffer, (size_t)(state->totalLen), + secret, state->secretLimit + XXH_STRIPE_LEN); +} + + + +/* ========================================== + * XXH3 128 bits (a.k.a XXH128) + * ========================================== + * XXH3's 128-bit variant has better mixing and strength than the 64-bit variant, + * even without counting the significantly larger output size. + * + * For example, extra steps are taken to avoid the seed-dependent collisions + * in 17-240 byte inputs (See XXH3_mix16B and XXH128_mix32B). + * + * This strength naturally comes at the cost of some speed, especially on short + * lengths. Note that longer hashes are about as fast as the 64-bit version + * due to it using only a slight modification of the 64-bit loop. + * + * XXH128 is also more oriented towards 64-bit machines. It is still extremely + * fast for a _128-bit_ hash on 32-bit (it usually clears XXH64). + */ + +XXH_FORCE_INLINE XXH128_hash_t +XXH3_len_1to3_128b(const xxh_u8* input, size_t len, const xxh_u8* secret, XXH64_hash_t seed) +{ + /* A doubled version of 1to3_64b with different constants. */ + XXH_ASSERT(input != NULL); + XXH_ASSERT(1 <= len && len <= 3); + XXH_ASSERT(secret != NULL); + /* + * len = 1: combinedl = { input[0], 0x01, input[0], input[0] } + * len = 2: combinedl = { input[1], 0x02, input[0], input[1] } + * len = 3: combinedl = { input[2], 0x03, input[0], input[1] } + */ + { xxh_u8 const c1 = input[0]; + xxh_u8 const c2 = input[len >> 1]; + xxh_u8 const c3 = input[len - 1]; + xxh_u32 const combinedl = ((xxh_u32)c1 <<16) | ((xxh_u32)c2 << 24) + | ((xxh_u32)c3 << 0) | ((xxh_u32)len << 8); + xxh_u32 const combinedh = XXH_rotl32(XXH_swap32(combinedl), 13); + xxh_u64 const bitflipl = (XXH_readLE32(secret) ^ XXH_readLE32(secret+4)) + seed; + xxh_u64 const bitfliph = (XXH_readLE32(secret+8) ^ XXH_readLE32(secret+12)) - seed; + xxh_u64 const keyed_lo = (xxh_u64)combinedl ^ bitflipl; + xxh_u64 const keyed_hi = (xxh_u64)combinedh ^ bitfliph; + XXH128_hash_t h128; + h128.low64 = XXH64_avalanche(keyed_lo); + h128.high64 = XXH64_avalanche(keyed_hi); + return h128; + } +} + +XXH_FORCE_INLINE XXH128_hash_t +XXH3_len_4to8_128b(const xxh_u8* input, size_t len, const xxh_u8* secret, XXH64_hash_t seed) +{ + XXH_ASSERT(input != NULL); + XXH_ASSERT(secret != NULL); + XXH_ASSERT(4 <= len && len <= 8); + seed ^= (xxh_u64)XXH_swap32((xxh_u32)seed) << 32; + { xxh_u32 const input_lo = XXH_readLE32(input); + xxh_u32 const input_hi = XXH_readLE32(input + len - 4); + xxh_u64 const input_64 = input_lo + ((xxh_u64)input_hi << 32); + xxh_u64 const bitflip = (XXH_readLE64(secret+16) ^ XXH_readLE64(secret+24)) + seed; + xxh_u64 const keyed = input_64 ^ bitflip; + + /* Shift len to the left to ensure it is even, this avoids even multiplies. */ + XXH128_hash_t m128 = XXH_mult64to128(keyed, XXH_PRIME64_1 + (len << 2)); + + m128.high64 += (m128.low64 << 1); + m128.low64 ^= (m128.high64 >> 3); + + m128.low64 = XXH_xorshift64(m128.low64, 35); + m128.low64 *= 0x9FB21C651E98DF25ULL; + m128.low64 = XXH_xorshift64(m128.low64, 28); + m128.high64 = XXH3_avalanche(m128.high64); + return m128; + } +} + +XXH_FORCE_INLINE XXH128_hash_t +XXH3_len_9to16_128b(const xxh_u8* input, size_t len, const xxh_u8* secret, XXH64_hash_t seed) +{ + XXH_ASSERT(input != NULL); + XXH_ASSERT(secret != NULL); + XXH_ASSERT(9 <= len && len <= 16); + { xxh_u64 const bitflipl = (XXH_readLE64(secret+32) ^ XXH_readLE64(secret+40)) - seed; + xxh_u64 const bitfliph = (XXH_readLE64(secret+48) ^ XXH_readLE64(secret+56)) + seed; + xxh_u64 const input_lo = XXH_readLE64(input); + xxh_u64 input_hi = XXH_readLE64(input + len - 8); + XXH128_hash_t m128 = XXH_mult64to128(input_lo ^ input_hi ^ bitflipl, XXH_PRIME64_1); + /* + * Put len in the middle of m128 to ensure that the length gets mixed to + * both the low and high bits in the 128x64 multiply below. + */ + m128.low64 += (xxh_u64)(len - 1) << 54; + input_hi ^= bitfliph; + /* + * Add the high 32 bits of input_hi to the high 32 bits of m128, then + * add the long product of the low 32 bits of input_hi and XXH_PRIME32_2 to + * the high 64 bits of m128. + * + * The best approach to this operation is different on 32-bit and 64-bit. + */ + if (sizeof(void *) < sizeof(xxh_u64)) { /* 32-bit */ + /* + * 32-bit optimized version, which is more readable. + * + * On 32-bit, it removes an ADC and delays a dependency between the two + * halves of m128.high64, but it generates an extra mask on 64-bit. + */ + m128.high64 += (input_hi & 0xFFFFFFFF00000000ULL) + XXH_mult32to64((xxh_u32)input_hi, XXH_PRIME32_2); + } else { + /* + * 64-bit optimized (albeit more confusing) version. + * + * Uses some properties of addition and multiplication to remove the mask: + * + * Let: + * a = input_hi.lo = (input_hi & 0x00000000FFFFFFFF) + * b = input_hi.hi = (input_hi & 0xFFFFFFFF00000000) + * c = XXH_PRIME32_2 + * + * a + (b * c) + * Inverse Property: x + y - x == y + * a + (b * (1 + c - 1)) + * Distributive Property: x * (y + z) == (x * y) + (x * z) + * a + (b * 1) + (b * (c - 1)) + * Identity Property: x * 1 == x + * a + b + (b * (c - 1)) + * + * Substitute a, b, and c: + * input_hi.hi + input_hi.lo + ((xxh_u64)input_hi.lo * (XXH_PRIME32_2 - 1)) + * + * Since input_hi.hi + input_hi.lo == input_hi, we get this: + * input_hi + ((xxh_u64)input_hi.lo * (XXH_PRIME32_2 - 1)) + */ + m128.high64 += input_hi + XXH_mult32to64((xxh_u32)input_hi, XXH_PRIME32_2 - 1); + } + /* m128 ^= XXH_swap64(m128 >> 64); */ + m128.low64 ^= XXH_swap64(m128.high64); + + { /* 128x64 multiply: h128 = m128 * XXH_PRIME64_2; */ + XXH128_hash_t h128 = XXH_mult64to128(m128.low64, XXH_PRIME64_2); + h128.high64 += m128.high64 * XXH_PRIME64_2; + + h128.low64 = XXH3_avalanche(h128.low64); + h128.high64 = XXH3_avalanche(h128.high64); + return h128; + } } +} + +/* + * Assumption: `secret` size is >= XXH3_SECRET_SIZE_MIN + */ +XXH_FORCE_INLINE XXH128_hash_t +XXH3_len_0to16_128b(const xxh_u8* input, size_t len, const xxh_u8* secret, XXH64_hash_t seed) +{ + XXH_ASSERT(len <= 16); + { if (len > 8) return XXH3_len_9to16_128b(input, len, secret, seed); + if (len >= 4) return XXH3_len_4to8_128b(input, len, secret, seed); + if (len) return XXH3_len_1to3_128b(input, len, secret, seed); + { XXH128_hash_t h128; + xxh_u64 const bitflipl = XXH_readLE64(secret+64) ^ XXH_readLE64(secret+72); + xxh_u64 const bitfliph = XXH_readLE64(secret+80) ^ XXH_readLE64(secret+88); + h128.low64 = XXH64_avalanche(seed ^ bitflipl); + h128.high64 = XXH64_avalanche( seed ^ bitfliph); + return h128; + } } +} + +/* + * A bit slower than XXH3_mix16B, but handles multiply by zero better. + */ +XXH_FORCE_INLINE XXH128_hash_t +XXH128_mix32B(XXH128_hash_t acc, const xxh_u8* input_1, const xxh_u8* input_2, + const xxh_u8* secret, XXH64_hash_t seed) +{ + acc.low64 += XXH3_mix16B (input_1, secret+0, seed); + acc.low64 ^= XXH_readLE64(input_2) + XXH_readLE64(input_2 + 8); + acc.high64 += XXH3_mix16B (input_2, secret+16, seed); + acc.high64 ^= XXH_readLE64(input_1) + XXH_readLE64(input_1 + 8); + return acc; +} + + +XXH_FORCE_INLINE XXH128_hash_t +XXH3_len_17to128_128b(const xxh_u8* XXH_RESTRICT input, size_t len, + const xxh_u8* XXH_RESTRICT secret, size_t secretSize, + XXH64_hash_t seed) +{ + XXH_ASSERT(secretSize >= XXH3_SECRET_SIZE_MIN); (void)secretSize; + XXH_ASSERT(16 < len && len <= 128); + + { XXH128_hash_t acc; + acc.low64 = len * XXH_PRIME64_1; + acc.high64 = 0; + if (len > 32) { + if (len > 64) { + if (len > 96) { + acc = XXH128_mix32B(acc, input+48, input+len-64, secret+96, seed); + } + acc = XXH128_mix32B(acc, input+32, input+len-48, secret+64, seed); + } + acc = XXH128_mix32B(acc, input+16, input+len-32, secret+32, seed); + } + acc = XXH128_mix32B(acc, input, input+len-16, secret, seed); + { XXH128_hash_t h128; + h128.low64 = acc.low64 + acc.high64; + h128.high64 = (acc.low64 * XXH_PRIME64_1) + + (acc.high64 * XXH_PRIME64_4) + + ((len - seed) * XXH_PRIME64_2); + h128.low64 = XXH3_avalanche(h128.low64); + h128.high64 = (XXH64_hash_t)0 - XXH3_avalanche(h128.high64); + return h128; + } + } +} + +XXH_NO_INLINE XXH128_hash_t +XXH3_len_129to240_128b(const xxh_u8* XXH_RESTRICT input, size_t len, + const xxh_u8* XXH_RESTRICT secret, size_t secretSize, + XXH64_hash_t seed) +{ + XXH_ASSERT(secretSize >= XXH3_SECRET_SIZE_MIN); (void)secretSize; + XXH_ASSERT(128 < len && len <= XXH3_MIDSIZE_MAX); + + { XXH128_hash_t acc; + int const nbRounds = (int)len / 32; + int i; + acc.low64 = len * XXH_PRIME64_1; + acc.high64 = 0; + for (i=0; i<4; i++) { + acc = XXH128_mix32B(acc, + input + (32 * i), + input + (32 * i) + 16, + secret + (32 * i), + seed); + } + acc.low64 = XXH3_avalanche(acc.low64); + acc.high64 = XXH3_avalanche(acc.high64); + XXH_ASSERT(nbRounds >= 4); + for (i=4 ; i < nbRounds; i++) { + acc = XXH128_mix32B(acc, + input + (32 * i), + input + (32 * i) + 16, + secret + XXH3_MIDSIZE_STARTOFFSET + (32 * (i - 4)), + seed); + } + /* last bytes */ + acc = XXH128_mix32B(acc, + input + len - 16, + input + len - 32, + secret + XXH3_SECRET_SIZE_MIN - XXH3_MIDSIZE_LASTOFFSET - 16, + 0ULL - seed); + + { XXH128_hash_t h128; + h128.low64 = acc.low64 + acc.high64; + h128.high64 = (acc.low64 * XXH_PRIME64_1) + + (acc.high64 * XXH_PRIME64_4) + + ((len - seed) * XXH_PRIME64_2); + h128.low64 = XXH3_avalanche(h128.low64); + h128.high64 = (XXH64_hash_t)0 - XXH3_avalanche(h128.high64); + return h128; + } + } +} + +XXH_FORCE_INLINE XXH128_hash_t +XXH3_hashLong_128b_internal(const void* XXH_RESTRICT input, size_t len, + const xxh_u8* XXH_RESTRICT secret, size_t secretSize, + XXH3_f_accumulate_512 f_acc512, + XXH3_f_scrambleAcc f_scramble) +{ + XXH_ALIGN(XXH_ACC_ALIGN) xxh_u64 acc[XXH_ACC_NB] = XXH3_INIT_ACC; + + XXH3_hashLong_internal_loop(acc, (const xxh_u8*)input, len, secret, secretSize, f_acc512, f_scramble); + + /* converge into final hash */ + XXH_STATIC_ASSERT(sizeof(acc) == 64); + XXH_ASSERT(secretSize >= sizeof(acc) + XXH_SECRET_MERGEACCS_START); + { XXH128_hash_t h128; + h128.low64 = XXH3_mergeAccs(acc, + secret + XXH_SECRET_MERGEACCS_START, + (xxh_u64)len * XXH_PRIME64_1); + h128.high64 = XXH3_mergeAccs(acc, + secret + secretSize + - sizeof(acc) - XXH_SECRET_MERGEACCS_START, + ~((xxh_u64)len * XXH_PRIME64_2)); + return h128; + } +} + +/* + * It's important for performance that XXH3_hashLong is not inlined. + */ +XXH_NO_INLINE XXH128_hash_t +XXH3_hashLong_128b_default(const void* XXH_RESTRICT input, size_t len, + XXH64_hash_t seed64, + const void* XXH_RESTRICT secret, size_t secretLen) +{ + (void)seed64; (void)secret; (void)secretLen; + return XXH3_hashLong_128b_internal(input, len, XXH3_kSecret, sizeof(XXH3_kSecret), + XXH3_accumulate_512, XXH3_scrambleAcc); +} + +/* + * It's important for performance to pass @secretLen (when it's static) + * to the compiler, so that it can properly optimize the vectorized loop. + */ +XXH_FORCE_INLINE XXH128_hash_t +XXH3_hashLong_128b_withSecret(const void* XXH_RESTRICT input, size_t len, + XXH64_hash_t seed64, + const void* XXH_RESTRICT secret, size_t secretLen) +{ + (void)seed64; + return XXH3_hashLong_128b_internal(input, len, (const xxh_u8*)secret, secretLen, + XXH3_accumulate_512, XXH3_scrambleAcc); +} + +XXH_FORCE_INLINE XXH128_hash_t +XXH3_hashLong_128b_withSeed_internal(const void* XXH_RESTRICT input, size_t len, + XXH64_hash_t seed64, + XXH3_f_accumulate_512 f_acc512, + XXH3_f_scrambleAcc f_scramble, + XXH3_f_initCustomSecret f_initSec) +{ + if (seed64 == 0) + return XXH3_hashLong_128b_internal(input, len, + XXH3_kSecret, sizeof(XXH3_kSecret), + f_acc512, f_scramble); + { XXH_ALIGN(XXH_SEC_ALIGN) xxh_u8 secret[XXH_SECRET_DEFAULT_SIZE]; + f_initSec(secret, seed64); + return XXH3_hashLong_128b_internal(input, len, (const xxh_u8*)secret, sizeof(secret), + f_acc512, f_scramble); + } +} + +/* + * It's important for performance that XXH3_hashLong is not inlined. + */ +XXH_NO_INLINE XXH128_hash_t +XXH3_hashLong_128b_withSeed(const void* input, size_t len, + XXH64_hash_t seed64, const void* XXH_RESTRICT secret, size_t secretLen) +{ + (void)secret; (void)secretLen; + return XXH3_hashLong_128b_withSeed_internal(input, len, seed64, + XXH3_accumulate_512, XXH3_scrambleAcc, XXH3_initCustomSecret); +} + +typedef XXH128_hash_t (*XXH3_hashLong128_f)(const void* XXH_RESTRICT, size_t, + XXH64_hash_t, const void* XXH_RESTRICT, size_t); + +XXH_FORCE_INLINE XXH128_hash_t +XXH3_128bits_internal(const void* input, size_t len, + XXH64_hash_t seed64, const void* XXH_RESTRICT secret, size_t secretLen, + XXH3_hashLong128_f f_hl128) +{ + XXH_ASSERT(secretLen >= XXH3_SECRET_SIZE_MIN); + /* + * If an action is to be taken if `secret` conditions are not respected, + * it should be done here. + * For now, it's a contract pre-condition. + * Adding a check and a branch here would cost performance at every hash. + */ + if (len <= 16) + return XXH3_len_0to16_128b((const xxh_u8*)input, len, (const xxh_u8*)secret, seed64); + if (len <= 128) + return XXH3_len_17to128_128b((const xxh_u8*)input, len, (const xxh_u8*)secret, secretLen, seed64); + if (len <= XXH3_MIDSIZE_MAX) + return XXH3_len_129to240_128b((const xxh_u8*)input, len, (const xxh_u8*)secret, secretLen, seed64); + return f_hl128(input, len, seed64, secret, secretLen); +} + + +/* === Public XXH128 API === */ + +/*! @ingroup xxh3_family */ +XXH_PUBLIC_API XXH128_hash_t XXH3_128bits(const void* input, size_t len) +{ + return XXH3_128bits_internal(input, len, 0, + XXH3_kSecret, sizeof(XXH3_kSecret), + XXH3_hashLong_128b_default); +} + +/*! @ingroup xxh3_family */ +XXH_PUBLIC_API XXH128_hash_t +XXH3_128bits_withSecret(const void* input, size_t len, const void* secret, size_t secretSize) +{ + return XXH3_128bits_internal(input, len, 0, + (const xxh_u8*)secret, secretSize, + XXH3_hashLong_128b_withSecret); +} + +/*! @ingroup xxh3_family */ +XXH_PUBLIC_API XXH128_hash_t +XXH3_128bits_withSeed(const void* input, size_t len, XXH64_hash_t seed) +{ + return XXH3_128bits_internal(input, len, seed, + XXH3_kSecret, sizeof(XXH3_kSecret), + XXH3_hashLong_128b_withSeed); +} + +/*! @ingroup xxh3_family */ +XXH_PUBLIC_API XXH128_hash_t +XXH3_128bits_withSecretandSeed(const void* input, size_t len, const void* secret, size_t secretSize, XXH64_hash_t seed) +{ + if (len <= XXH3_MIDSIZE_MAX) + return XXH3_128bits_internal(input, len, seed, XXH3_kSecret, sizeof(XXH3_kSecret), NULL); + return XXH3_hashLong_128b_withSecret(input, len, seed, secret, secretSize); +} + +/*! @ingroup xxh3_family */ +XXH_PUBLIC_API XXH128_hash_t +XXH128(const void* input, size_t len, XXH64_hash_t seed) +{ + return XXH3_128bits_withSeed(input, len, seed); +} + + +/* === XXH3 128-bit streaming === */ + +/* + * All initialization and update functions are identical to 64-bit streaming variant. + * The only difference is the finalization routine. + */ + +/*! @ingroup xxh3_family */ +XXH_PUBLIC_API XXH_errorcode +XXH3_128bits_reset(XXH3_state_t* statePtr) +{ + return XXH3_64bits_reset(statePtr); +} + +/*! @ingroup xxh3_family */ +XXH_PUBLIC_API XXH_errorcode +XXH3_128bits_reset_withSecret(XXH3_state_t* statePtr, const void* secret, size_t secretSize) +{ + return XXH3_64bits_reset_withSecret(statePtr, secret, secretSize); +} + +/*! @ingroup xxh3_family */ +XXH_PUBLIC_API XXH_errorcode +XXH3_128bits_reset_withSeed(XXH3_state_t* statePtr, XXH64_hash_t seed) +{ + return XXH3_64bits_reset_withSeed(statePtr, seed); +} + +/*! @ingroup xxh3_family */ +XXH_PUBLIC_API XXH_errorcode +XXH3_128bits_reset_withSecretandSeed(XXH3_state_t* statePtr, const void* secret, size_t secretSize, XXH64_hash_t seed) +{ + return XXH3_64bits_reset_withSecretandSeed(statePtr, secret, secretSize, seed); +} + +/*! @ingroup xxh3_family */ +XXH_PUBLIC_API XXH_errorcode +XXH3_128bits_update(XXH3_state_t* state, const void* input, size_t len) +{ + return XXH3_update(state, (const xxh_u8*)input, len, + XXH3_accumulate_512, XXH3_scrambleAcc); +} + +/*! @ingroup xxh3_family */ +XXH_PUBLIC_API XXH128_hash_t XXH3_128bits_digest (const XXH3_state_t* state) +{ + const unsigned char* const secret = (state->extSecret == NULL) ? state->customSecret : state->extSecret; + if (state->totalLen > XXH3_MIDSIZE_MAX) { + XXH_ALIGN(XXH_ACC_ALIGN) XXH64_hash_t acc[XXH_ACC_NB]; + XXH3_digest_long(acc, state, secret); + XXH_ASSERT(state->secretLimit + XXH_STRIPE_LEN >= sizeof(acc) + XXH_SECRET_MERGEACCS_START); + { XXH128_hash_t h128; + h128.low64 = XXH3_mergeAccs(acc, + secret + XXH_SECRET_MERGEACCS_START, + (xxh_u64)state->totalLen * XXH_PRIME64_1); + h128.high64 = XXH3_mergeAccs(acc, + secret + state->secretLimit + XXH_STRIPE_LEN + - sizeof(acc) - XXH_SECRET_MERGEACCS_START, + ~((xxh_u64)state->totalLen * XXH_PRIME64_2)); + return h128; + } + } + /* len <= XXH3_MIDSIZE_MAX : short code */ + if (state->seed) + return XXH3_128bits_withSeed(state->buffer, (size_t)state->totalLen, state->seed); + return XXH3_128bits_withSecret(state->buffer, (size_t)(state->totalLen), + secret, state->secretLimit + XXH_STRIPE_LEN); +} + +/* 128-bit utility functions */ + +#include /* memcmp, memcpy */ + +/* return : 1 is equal, 0 if different */ +/*! @ingroup xxh3_family */ +XXH_PUBLIC_API int XXH128_isEqual(XXH128_hash_t h1, XXH128_hash_t h2) +{ + /* note : XXH128_hash_t is compact, it has no padding byte */ + return !(memcmp(&h1, &h2, sizeof(h1))); +} + +/* This prototype is compatible with stdlib's qsort(). + * return : >0 if *h128_1 > *h128_2 + * <0 if *h128_1 < *h128_2 + * =0 if *h128_1 == *h128_2 */ +/*! @ingroup xxh3_family */ +XXH_PUBLIC_API int XXH128_cmp(const void* h128_1, const void* h128_2) +{ + XXH128_hash_t const h1 = *(const XXH128_hash_t*)h128_1; + XXH128_hash_t const h2 = *(const XXH128_hash_t*)h128_2; + int const hcmp = (h1.high64 > h2.high64) - (h2.high64 > h1.high64); + /* note : bets that, in most cases, hash values are different */ + if (hcmp) return hcmp; + return (h1.low64 > h2.low64) - (h2.low64 > h1.low64); +} + + +/*====== Canonical representation ======*/ +/*! @ingroup xxh3_family */ +XXH_PUBLIC_API void +XXH128_canonicalFromHash(XXH128_canonical_t* dst, XXH128_hash_t hash) +{ + XXH_STATIC_ASSERT(sizeof(XXH128_canonical_t) == sizeof(XXH128_hash_t)); + if (XXH_CPU_LITTLE_ENDIAN) { + hash.high64 = XXH_swap64(hash.high64); + hash.low64 = XXH_swap64(hash.low64); + } + XXH_memcpy(dst, &hash.high64, sizeof(hash.high64)); + XXH_memcpy((char*)dst + sizeof(hash.high64), &hash.low64, sizeof(hash.low64)); +} + +/*! @ingroup xxh3_family */ +XXH_PUBLIC_API XXH128_hash_t +XXH128_hashFromCanonical(const XXH128_canonical_t* src) +{ + XXH128_hash_t h; + h.high64 = XXH_readBE64(src); + h.low64 = XXH_readBE64(src->digest + 8); + return h; +} + + + +/* ========================================== + * Secret generators + * ========================================== + */ +#define XXH_MIN(x, y) (((x) > (y)) ? (y) : (x)) + +XXH_FORCE_INLINE void XXH3_combine16(void* dst, XXH128_hash_t h128) +{ + XXH_writeLE64( dst, XXH_readLE64(dst) ^ h128.low64 ); + XXH_writeLE64( (char*)dst+8, XXH_readLE64((char*)dst+8) ^ h128.high64 ); +} + +/*! @ingroup xxh3_family */ +XXH_PUBLIC_API XXH_errorcode +XXH3_generateSecret(void* secretBuffer, size_t secretSize, const void* customSeed, size_t customSeedSize) +{ +#if (XXH_DEBUGLEVEL >= 1) + XXH_ASSERT(secretBuffer != NULL); + XXH_ASSERT(secretSize >= XXH3_SECRET_SIZE_MIN); +#else + /* production mode, assert() are disabled */ + if (secretBuffer == NULL) return XXH_ERROR; + if (secretSize < XXH3_SECRET_SIZE_MIN) return XXH_ERROR; +#endif + + if (customSeedSize == 0) { + customSeed = XXH3_kSecret; + customSeedSize = XXH_SECRET_DEFAULT_SIZE; + } +#if (XXH_DEBUGLEVEL >= 1) + XXH_ASSERT(customSeed != NULL); +#else + if (customSeed == NULL) return XXH_ERROR; +#endif + + /* Fill secretBuffer with a copy of customSeed - repeat as needed */ + { size_t pos = 0; + while (pos < secretSize) { + size_t const toCopy = XXH_MIN((secretSize - pos), customSeedSize); + memcpy((char*)secretBuffer + pos, customSeed, toCopy); + pos += toCopy; + } } + + { size_t const nbSeg16 = secretSize / 16; + size_t n; + XXH128_canonical_t scrambler; + XXH128_canonicalFromHash(&scrambler, XXH128(customSeed, customSeedSize, 0)); + for (n=0; n +#include +#include + +#if defined(__GNUC__) && __GNUC__ >= 4 +# define ZSTD_memcpy(d,s,l) __builtin_memcpy((d),(s),(l)) +# define ZSTD_memmove(d,s,l) __builtin_memmove((d),(s),(l)) +# define ZSTD_memset(p,v,l) __builtin_memset((p),(v),(l)) +#else +# define ZSTD_memcpy(d,s,l) memcpy((d),(s),(l)) +# define ZSTD_memmove(d,s,l) memmove((d),(s),(l)) +# define ZSTD_memset(p,v,l) memset((p),(v),(l)) +#endif + +#endif /* ZSTD_DEPS_COMMON */ + +/* Need: + * ZSTD_malloc() + * ZSTD_free() + * ZSTD_calloc() + */ +#ifdef ZSTD_DEPS_NEED_MALLOC +#ifndef ZSTD_DEPS_MALLOC +#define ZSTD_DEPS_MALLOC + +#include + +#define ZSTD_malloc(s) malloc(s) +#define ZSTD_calloc(n,s) calloc((n), (s)) +#define ZSTD_free(p) free((p)) + +#endif /* ZSTD_DEPS_MALLOC */ +#endif /* ZSTD_DEPS_NEED_MALLOC */ + +/* + * Provides 64-bit math support. + * Need: + * U64 ZSTD_div64(U64 dividend, U32 divisor) + */ +#ifdef ZSTD_DEPS_NEED_MATH64 +#ifndef ZSTD_DEPS_MATH64 +#define ZSTD_DEPS_MATH64 + +#define ZSTD_div64(dividend, divisor) ((dividend) / (divisor)) + +#endif /* ZSTD_DEPS_MATH64 */ +#endif /* ZSTD_DEPS_NEED_MATH64 */ + +/* Need: + * assert() + */ +#ifdef ZSTD_DEPS_NEED_ASSERT +#ifndef ZSTD_DEPS_ASSERT +#define ZSTD_DEPS_ASSERT + +#include + +#endif /* ZSTD_DEPS_ASSERT */ +#endif /* ZSTD_DEPS_NEED_ASSERT */ + +/* Need: + * ZSTD_DEBUG_PRINT() + */ +#ifdef ZSTD_DEPS_NEED_IO +#ifndef ZSTD_DEPS_IO +#define ZSTD_DEPS_IO + +#include +#define ZSTD_DEBUG_PRINT(...) fprintf(stderr, __VA_ARGS__) + +#endif /* ZSTD_DEPS_IO */ +#endif /* ZSTD_DEPS_NEED_IO */ + +/* Only requested when is known to be present. + * Need: + * intptr_t + */ +#ifdef ZSTD_DEPS_NEED_STDINT +#ifndef ZSTD_DEPS_STDINT +#define ZSTD_DEPS_STDINT + +#include + +#endif /* ZSTD_DEPS_STDINT */ +#endif /* ZSTD_DEPS_NEED_STDINT */ diff --git a/stage1/zstd/lib/common/zstd_internal.h b/stage1/zstd/lib/common/zstd_internal.h new file mode 100644 index 000000000000..e4d36ce09051 --- /dev/null +++ b/stage1/zstd/lib/common/zstd_internal.h @@ -0,0 +1,493 @@ +/* + * Copyright (c) Yann Collet, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under both the BSD-style license (found in the + * LICENSE file in the root directory of this source tree) and the GPLv2 (found + * in the COPYING file in the root directory of this source tree). + * You may select, at your option, one of the above-listed licenses. + */ + +#ifndef ZSTD_CCOMMON_H_MODULE +#define ZSTD_CCOMMON_H_MODULE + +/* this module contains definitions which must be identical + * across compression, decompression and dictBuilder. + * It also contains a few functions useful to at least 2 of them + * and which benefit from being inlined */ + +/*-************************************* +* Dependencies +***************************************/ +#include "compiler.h" +#include "cpu.h" +#include "mem.h" +#include "debug.h" /* assert, DEBUGLOG, RAWLOG, g_debuglevel */ +#include "error_private.h" +#define ZSTD_STATIC_LINKING_ONLY +#include "../zstd.h" +#define FSE_STATIC_LINKING_ONLY +#include "fse.h" +#define HUF_STATIC_LINKING_ONLY +#include "huf.h" +#ifndef XXH_STATIC_LINKING_ONLY +# define XXH_STATIC_LINKING_ONLY /* XXH64_state_t */ +#endif +#include "xxhash.h" /* XXH_reset, update, digest */ +#ifndef ZSTD_NO_TRACE +# include "zstd_trace.h" +#else +# define ZSTD_TRACE 0 +#endif + +#if defined (__cplusplus) +extern "C" { +#endif + +/* ---- static assert (debug) --- */ +#define ZSTD_STATIC_ASSERT(c) DEBUG_STATIC_ASSERT(c) +#define ZSTD_isError ERR_isError /* for inlining */ +#define FSE_isError ERR_isError +#define HUF_isError ERR_isError + + +/*-************************************* +* shared macros +***************************************/ +#undef MIN +#undef MAX +#define MIN(a,b) ((a)<(b) ? (a) : (b)) +#define MAX(a,b) ((a)>(b) ? (a) : (b)) +#define BOUNDED(min,val,max) (MAX(min,MIN(val,max))) + + +/*-************************************* +* Common constants +***************************************/ +#define ZSTD_OPT_NUM (1<<12) + +#define ZSTD_REP_NUM 3 /* number of repcodes */ +static UNUSED_ATTR const U32 repStartValue[ZSTD_REP_NUM] = { 1, 4, 8 }; + +#define KB *(1 <<10) +#define MB *(1 <<20) +#define GB *(1U<<30) + +#define BIT7 128 +#define BIT6 64 +#define BIT5 32 +#define BIT4 16 +#define BIT1 2 +#define BIT0 1 + +#define ZSTD_WINDOWLOG_ABSOLUTEMIN 10 +static UNUSED_ATTR const size_t ZSTD_fcs_fieldSize[4] = { 0, 2, 4, 8 }; +static UNUSED_ATTR const size_t ZSTD_did_fieldSize[4] = { 0, 1, 2, 4 }; + +#define ZSTD_FRAMEIDSIZE 4 /* magic number size */ + +#define ZSTD_BLOCKHEADERSIZE 3 /* C standard doesn't allow `static const` variable to be init using another `static const` variable */ +static UNUSED_ATTR const size_t ZSTD_blockHeaderSize = ZSTD_BLOCKHEADERSIZE; +typedef enum { bt_raw, bt_rle, bt_compressed, bt_reserved } blockType_e; + +#define ZSTD_FRAMECHECKSUMSIZE 4 + +#define MIN_SEQUENCES_SIZE 1 /* nbSeq==0 */ +#define MIN_CBLOCK_SIZE (1 /*litCSize*/ + 1 /* RLE or RAW */ + MIN_SEQUENCES_SIZE /* nbSeq==0 */) /* for a non-null block */ + +#define HufLog 12 +typedef enum { set_basic, set_rle, set_compressed, set_repeat } symbolEncodingType_e; + +#define LONGNBSEQ 0x7F00 + +#define MINMATCH 3 + +#define Litbits 8 +#define MaxLit ((1<= WILDCOPY_VECLEN || diff <= -WILDCOPY_VECLEN); + /* Separate out the first COPY16() call because the copy length is + * almost certain to be short, so the branches have different + * probabilities. Since it is almost certain to be short, only do + * one COPY16() in the first call. Then, do two calls per loop since + * at that point it is more likely to have a high trip count. + */ +#ifdef __aarch64__ + do { + COPY16(op, ip); + } + while (op < oend); +#else + ZSTD_copy16(op, ip); + if (16 >= length) return; + op += 16; + ip += 16; + do { + COPY16(op, ip); + COPY16(op, ip); + } + while (op < oend); +#endif + } +} + +MEM_STATIC size_t ZSTD_limitCopy(void* dst, size_t dstCapacity, const void* src, size_t srcSize) +{ + size_t const length = MIN(dstCapacity, srcSize); + if (length > 0) { + ZSTD_memcpy(dst, src, length); + } + return length; +} + +/* define "workspace is too large" as this number of times larger than needed */ +#define ZSTD_WORKSPACETOOLARGE_FACTOR 3 + +/* when workspace is continuously too large + * during at least this number of times, + * context's memory usage is considered wasteful, + * because it's sized to handle a worst case scenario which rarely happens. + * In which case, resize it down to free some memory */ +#define ZSTD_WORKSPACETOOLARGE_MAXDURATION 128 + +/* Controls whether the input/output buffer is buffered or stable. */ +typedef enum { + ZSTD_bm_buffered = 0, /* Buffer the input/output */ + ZSTD_bm_stable = 1 /* ZSTD_inBuffer/ZSTD_outBuffer is stable */ +} ZSTD_bufferMode_e; + + +/*-******************************************* +* Private declarations +*********************************************/ +typedef struct seqDef_s { + U32 offBase; /* offBase == Offset + ZSTD_REP_NUM, or repcode 1,2,3 */ + U16 litLength; + U16 mlBase; /* mlBase == matchLength - MINMATCH */ +} seqDef; + +/* Controls whether seqStore has a single "long" litLength or matchLength. See seqStore_t. */ +typedef enum { + ZSTD_llt_none = 0, /* no longLengthType */ + ZSTD_llt_literalLength = 1, /* represents a long literal */ + ZSTD_llt_matchLength = 2 /* represents a long match */ +} ZSTD_longLengthType_e; + +typedef struct { + seqDef* sequencesStart; + seqDef* sequences; /* ptr to end of sequences */ + BYTE* litStart; + BYTE* lit; /* ptr to end of literals */ + BYTE* llCode; + BYTE* mlCode; + BYTE* ofCode; + size_t maxNbSeq; + size_t maxNbLit; + + /* longLengthPos and longLengthType to allow us to represent either a single litLength or matchLength + * in the seqStore that has a value larger than U16 (if it exists). To do so, we increment + * the existing value of the litLength or matchLength by 0x10000. + */ + ZSTD_longLengthType_e longLengthType; + U32 longLengthPos; /* Index of the sequence to apply long length modification to */ +} seqStore_t; + +typedef struct { + U32 litLength; + U32 matchLength; +} ZSTD_sequenceLength; + +/** + * Returns the ZSTD_sequenceLength for the given sequences. It handles the decoding of long sequences + * indicated by longLengthPos and longLengthType, and adds MINMATCH back to matchLength. + */ +MEM_STATIC ZSTD_sequenceLength ZSTD_getSequenceLength(seqStore_t const* seqStore, seqDef const* seq) +{ + ZSTD_sequenceLength seqLen; + seqLen.litLength = seq->litLength; + seqLen.matchLength = seq->mlBase + MINMATCH; + if (seqStore->longLengthPos == (U32)(seq - seqStore->sequencesStart)) { + if (seqStore->longLengthType == ZSTD_llt_literalLength) { + seqLen.litLength += 0xFFFF; + } + if (seqStore->longLengthType == ZSTD_llt_matchLength) { + seqLen.matchLength += 0xFFFF; + } + } + return seqLen; +} + +/** + * Contains the compressed frame size and an upper-bound for the decompressed frame size. + * Note: before using `compressedSize`, check for errors using ZSTD_isError(). + * similarly, before using `decompressedBound`, check for errors using: + * `decompressedBound != ZSTD_CONTENTSIZE_ERROR` + */ +typedef struct { + size_t compressedSize; + unsigned long long decompressedBound; +} ZSTD_frameSizeInfo; /* decompress & legacy */ + +const seqStore_t* ZSTD_getSeqStore(const ZSTD_CCtx* ctx); /* compress & dictBuilder */ +void ZSTD_seqToCodes(const seqStore_t* seqStorePtr); /* compress, dictBuilder, decodeCorpus (shouldn't get its definition from here) */ + +/* custom memory allocation functions */ +void* ZSTD_customMalloc(size_t size, ZSTD_customMem customMem); +void* ZSTD_customCalloc(size_t size, ZSTD_customMem customMem); +void ZSTD_customFree(void* ptr, ZSTD_customMem customMem); + + +MEM_STATIC U32 ZSTD_highbit32(U32 val) /* compress, dictBuilder, decodeCorpus */ +{ + assert(val != 0); + { +# if defined(_MSC_VER) /* Visual */ +# if STATIC_BMI2 == 1 + return _lzcnt_u32(val)^31; +# else + if (val != 0) { + unsigned long r; + _BitScanReverse(&r, val); + return (unsigned)r; + } else { + /* Should not reach this code path */ + __assume(0); + } +# endif +# elif defined(__GNUC__) && (__GNUC__ >= 3) /* GCC Intrinsic */ + return __builtin_clz (val) ^ 31; +# elif defined(__ICCARM__) /* IAR Intrinsic */ + return 31 - __CLZ(val); +# else /* Software version */ + static const U32 DeBruijnClz[32] = { 0, 9, 1, 10, 13, 21, 2, 29, 11, 14, 16, 18, 22, 25, 3, 30, 8, 12, 20, 28, 15, 17, 24, 7, 19, 27, 23, 6, 26, 5, 4, 31 }; + U32 v = val; + v |= v >> 1; + v |= v >> 2; + v |= v >> 4; + v |= v >> 8; + v |= v >> 16; + return DeBruijnClz[(v * 0x07C4ACDDU) >> 27]; +# endif + } +} + +/** + * Counts the number of trailing zeros of a `size_t`. + * Most compilers should support CTZ as a builtin. A backup + * implementation is provided if the builtin isn't supported, but + * it may not be terribly efficient. + */ +MEM_STATIC unsigned ZSTD_countTrailingZeros(size_t val) +{ + if (MEM_64bits()) { +# if defined(_MSC_VER) && defined(_WIN64) +# if STATIC_BMI2 + return _tzcnt_u64(val); +# else + if (val != 0) { + unsigned long r; + _BitScanForward64(&r, (U64)val); + return (unsigned)r; + } else { + /* Should not reach this code path */ + __assume(0); + } +# endif +# elif defined(__GNUC__) && (__GNUC__ >= 4) + return __builtin_ctzll((U64)val); +# else + static const int DeBruijnBytePos[64] = { 0, 1, 2, 7, 3, 13, 8, 19, + 4, 25, 14, 28, 9, 34, 20, 56, + 5, 17, 26, 54, 15, 41, 29, 43, + 10, 31, 38, 35, 21, 45, 49, 57, + 63, 6, 12, 18, 24, 27, 33, 55, + 16, 53, 40, 42, 30, 37, 44, 48, + 62, 11, 23, 32, 52, 39, 36, 47, + 61, 22, 51, 46, 60, 50, 59, 58 }; + return DeBruijnBytePos[((U64)((val & -(long long)val) * 0x0218A392CDABBD3FULL)) >> 58]; +# endif + } else { /* 32 bits */ +# if defined(_MSC_VER) + if (val != 0) { + unsigned long r; + _BitScanForward(&r, (U32)val); + return (unsigned)r; + } else { + /* Should not reach this code path */ + __assume(0); + } +# elif defined(__GNUC__) && (__GNUC__ >= 3) + return __builtin_ctz((U32)val); +# else + static const int DeBruijnBytePos[32] = { 0, 1, 28, 2, 29, 14, 24, 3, + 30, 22, 20, 15, 25, 17, 4, 8, + 31, 27, 13, 23, 21, 19, 16, 7, + 26, 12, 18, 6, 11, 5, 10, 9 }; + return DeBruijnBytePos[((U32)((val & -(S32)val) * 0x077CB531U)) >> 27]; +# endif + } +} + + +/* ZSTD_invalidateRepCodes() : + * ensures next compression will not use repcodes from previous block. + * Note : only works with regular variant; + * do not use with extDict variant ! */ +void ZSTD_invalidateRepCodes(ZSTD_CCtx* cctx); /* zstdmt, adaptive_compression (shouldn't get this definition from here) */ + + +typedef struct { + blockType_e blockType; + U32 lastBlock; + U32 origSize; +} blockProperties_t; /* declared here for decompress and fullbench */ + +/*! ZSTD_getcBlockSize() : + * Provides the size of compressed block from block header `src` */ +/* Used by: decompress, fullbench (does not get its definition from here) */ +size_t ZSTD_getcBlockSize(const void* src, size_t srcSize, + blockProperties_t* bpPtr); + +/*! ZSTD_decodeSeqHeaders() : + * decode sequence header from src */ +/* Used by: decompress, fullbench (does not get its definition from here) */ +size_t ZSTD_decodeSeqHeaders(ZSTD_DCtx* dctx, int* nbSeqPtr, + const void* src, size_t srcSize); + +/** + * @returns true iff the CPU supports dynamic BMI2 dispatch. + */ +MEM_STATIC int ZSTD_cpuSupportsBmi2(void) +{ + ZSTD_cpuid_t cpuid = ZSTD_cpuid(); + return ZSTD_cpuid_bmi1(cpuid) && ZSTD_cpuid_bmi2(cpuid); +} + +#if defined (__cplusplus) +} +#endif + +#endif /* ZSTD_CCOMMON_H_MODULE */ diff --git a/stage1/zstd/lib/common/zstd_trace.h b/stage1/zstd/lib/common/zstd_trace.h new file mode 100644 index 000000000000..f9121f7d8ed5 --- /dev/null +++ b/stage1/zstd/lib/common/zstd_trace.h @@ -0,0 +1,163 @@ +/* + * Copyright (c) Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under both the BSD-style license (found in the + * LICENSE file in the root directory of this source tree) and the GPLv2 (found + * in the COPYING file in the root directory of this source tree). + * You may select, at your option, one of the above-listed licenses. + */ + +#ifndef ZSTD_TRACE_H +#define ZSTD_TRACE_H + +#if defined (__cplusplus) +extern "C" { +#endif + +#include + +/* weak symbol support + * For now, enable conservatively: + * - Only GNUC + * - Only ELF + * - Only x86-64 and i386 + * Also, explicitly disable on platforms known not to work so they aren't + * forgotten in the future. + */ +#if !defined(ZSTD_HAVE_WEAK_SYMBOLS) && \ + defined(__GNUC__) && defined(__ELF__) && \ + (defined(__x86_64__) || defined(_M_X64) || defined(__i386__) || defined(_M_IX86)) && \ + !defined(__APPLE__) && !defined(_WIN32) && !defined(__MINGW32__) && \ + !defined(__CYGWIN__) && !defined(_AIX) +# define ZSTD_HAVE_WEAK_SYMBOLS 1 +#else +# define ZSTD_HAVE_WEAK_SYMBOLS 0 +#endif +#if ZSTD_HAVE_WEAK_SYMBOLS +# define ZSTD_WEAK_ATTR __attribute__((__weak__)) +#else +# define ZSTD_WEAK_ATTR +#endif + +/* Only enable tracing when weak symbols are available. */ +#ifndef ZSTD_TRACE +# define ZSTD_TRACE ZSTD_HAVE_WEAK_SYMBOLS +#endif + +#if ZSTD_TRACE + +struct ZSTD_CCtx_s; +struct ZSTD_DCtx_s; +struct ZSTD_CCtx_params_s; + +typedef struct { + /** + * ZSTD_VERSION_NUMBER + * + * This is guaranteed to be the first member of ZSTD_trace. + * Otherwise, this struct is not stable between versions. If + * the version number does not match your expectation, you + * should not interpret the rest of the struct. + */ + unsigned version; + /** + * Non-zero if streaming (de)compression is used. + */ + unsigned streaming; + /** + * The dictionary ID. + */ + unsigned dictionaryID; + /** + * Is the dictionary cold? + * Only set on decompression. + */ + unsigned dictionaryIsCold; + /** + * The dictionary size or zero if no dictionary. + */ + size_t dictionarySize; + /** + * The uncompressed size of the data. + */ + size_t uncompressedSize; + /** + * The compressed size of the data. + */ + size_t compressedSize; + /** + * The fully resolved CCtx parameters (NULL on decompression). + */ + struct ZSTD_CCtx_params_s const* params; + /** + * The ZSTD_CCtx pointer (NULL on decompression). + */ + struct ZSTD_CCtx_s const* cctx; + /** + * The ZSTD_DCtx pointer (NULL on compression). + */ + struct ZSTD_DCtx_s const* dctx; +} ZSTD_Trace; + +/** + * A tracing context. It must be 0 when tracing is disabled. + * Otherwise, any non-zero value returned by a tracing begin() + * function is presented to any subsequent calls to end(). + * + * Any non-zero value is treated as tracing is enabled and not + * interpreted by the library. + * + * Two possible uses are: + * * A timestamp for when the begin() function was called. + * * A unique key identifying the (de)compression, like the + * address of the [dc]ctx pointer if you need to track + * more information than just a timestamp. + */ +typedef unsigned long long ZSTD_TraceCtx; + +/** + * Trace the beginning of a compression call. + * @param cctx The dctx pointer for the compression. + * It can be used as a key to map begin() to end(). + * @returns Non-zero if tracing is enabled. The return value is + * passed to ZSTD_trace_compress_end(). + */ +ZSTD_WEAK_ATTR ZSTD_TraceCtx ZSTD_trace_compress_begin( + struct ZSTD_CCtx_s const* cctx); + +/** + * Trace the end of a compression call. + * @param ctx The return value of ZSTD_trace_compress_begin(). + * @param trace The zstd tracing info. + */ +ZSTD_WEAK_ATTR void ZSTD_trace_compress_end( + ZSTD_TraceCtx ctx, + ZSTD_Trace const* trace); + +/** + * Trace the beginning of a decompression call. + * @param dctx The dctx pointer for the decompression. + * It can be used as a key to map begin() to end(). + * @returns Non-zero if tracing is enabled. The return value is + * passed to ZSTD_trace_compress_end(). + */ +ZSTD_WEAK_ATTR ZSTD_TraceCtx ZSTD_trace_decompress_begin( + struct ZSTD_DCtx_s const* dctx); + +/** + * Trace the end of a decompression call. + * @param ctx The return value of ZSTD_trace_decompress_begin(). + * @param trace The zstd tracing info. + */ +ZSTD_WEAK_ATTR void ZSTD_trace_decompress_end( + ZSTD_TraceCtx ctx, + ZSTD_Trace const* trace); + +#endif /* ZSTD_TRACE */ + +#if defined (__cplusplus) +} +#endif + +#endif /* ZSTD_TRACE_H */ diff --git a/stage1/zstd/lib/decompress/huf_decompress.c b/stage1/zstd/lib/decompress/huf_decompress.c new file mode 100644 index 000000000000..2027188255e1 --- /dev/null +++ b/stage1/zstd/lib/decompress/huf_decompress.c @@ -0,0 +1,1889 @@ +/* ****************************************************************** + * huff0 huffman decoder, + * part of Finite State Entropy library + * Copyright (c) Yann Collet, Facebook, Inc. + * + * You can contact the author at : + * - FSE+HUF source repository : https://github.com/Cyan4973/FiniteStateEntropy + * + * This source code is licensed under both the BSD-style license (found in the + * LICENSE file in the root directory of this source tree) and the GPLv2 (found + * in the COPYING file in the root directory of this source tree). + * You may select, at your option, one of the above-listed licenses. +****************************************************************** */ + +/* ************************************************************** +* Dependencies +****************************************************************/ +#include "../common/zstd_deps.h" /* ZSTD_memcpy, ZSTD_memset */ +#include "../common/compiler.h" +#include "../common/bitstream.h" /* BIT_* */ +#include "../common/fse.h" /* to compress headers */ +#define HUF_STATIC_LINKING_ONLY +#include "../common/huf.h" +#include "../common/error_private.h" +#include "../common/zstd_internal.h" + +/* ************************************************************** +* Constants +****************************************************************/ + +#define HUF_DECODER_FAST_TABLELOG 11 + +/* ************************************************************** +* Macros +****************************************************************/ + +/* These two optional macros force the use one way or another of the two + * Huffman decompression implementations. You can't force in both directions + * at the same time. + */ +#if defined(HUF_FORCE_DECOMPRESS_X1) && \ + defined(HUF_FORCE_DECOMPRESS_X2) +#error "Cannot force the use of the X1 and X2 decoders at the same time!" +#endif + +#if ZSTD_ENABLE_ASM_X86_64_BMI2 && DYNAMIC_BMI2 +# define HUF_ASM_X86_64_BMI2_ATTRS BMI2_TARGET_ATTRIBUTE +#else +# define HUF_ASM_X86_64_BMI2_ATTRS +#endif + +#ifdef __cplusplus +# define HUF_EXTERN_C extern "C" +#else +# define HUF_EXTERN_C +#endif +#define HUF_ASM_DECL HUF_EXTERN_C + +#if DYNAMIC_BMI2 || (ZSTD_ENABLE_ASM_X86_64_BMI2 && defined(__BMI2__)) +# define HUF_NEED_BMI2_FUNCTION 1 +#else +# define HUF_NEED_BMI2_FUNCTION 0 +#endif + +#if !(ZSTD_ENABLE_ASM_X86_64_BMI2 && defined(__BMI2__)) +# define HUF_NEED_DEFAULT_FUNCTION 1 +#else +# define HUF_NEED_DEFAULT_FUNCTION 0 +#endif + +/* ************************************************************** +* Error Management +****************************************************************/ +#define HUF_isError ERR_isError + + +/* ************************************************************** +* Byte alignment for workSpace management +****************************************************************/ +#define HUF_ALIGN(x, a) HUF_ALIGN_MASK((x), (a) - 1) +#define HUF_ALIGN_MASK(x, mask) (((x) + (mask)) & ~(mask)) + + +/* ************************************************************** +* BMI2 Variant Wrappers +****************************************************************/ +#if DYNAMIC_BMI2 + +#define HUF_DGEN(fn) \ + \ + static size_t fn##_default( \ + void* dst, size_t dstSize, \ + const void* cSrc, size_t cSrcSize, \ + const HUF_DTable* DTable) \ + { \ + return fn##_body(dst, dstSize, cSrc, cSrcSize, DTable); \ + } \ + \ + static BMI2_TARGET_ATTRIBUTE size_t fn##_bmi2( \ + void* dst, size_t dstSize, \ + const void* cSrc, size_t cSrcSize, \ + const HUF_DTable* DTable) \ + { \ + return fn##_body(dst, dstSize, cSrc, cSrcSize, DTable); \ + } \ + \ + static size_t fn(void* dst, size_t dstSize, void const* cSrc, \ + size_t cSrcSize, HUF_DTable const* DTable, int bmi2) \ + { \ + if (bmi2) { \ + return fn##_bmi2(dst, dstSize, cSrc, cSrcSize, DTable); \ + } \ + return fn##_default(dst, dstSize, cSrc, cSrcSize, DTable); \ + } + +#else + +#define HUF_DGEN(fn) \ + static size_t fn(void* dst, size_t dstSize, void const* cSrc, \ + size_t cSrcSize, HUF_DTable const* DTable, int bmi2) \ + { \ + (void)bmi2; \ + return fn##_body(dst, dstSize, cSrc, cSrcSize, DTable); \ + } + +#endif + + +/*-***************************/ +/* generic DTableDesc */ +/*-***************************/ +typedef struct { BYTE maxTableLog; BYTE tableType; BYTE tableLog; BYTE reserved; } DTableDesc; + +static DTableDesc HUF_getDTableDesc(const HUF_DTable* table) +{ + DTableDesc dtd; + ZSTD_memcpy(&dtd, table, sizeof(dtd)); + return dtd; +} + +#if ZSTD_ENABLE_ASM_X86_64_BMI2 + +static size_t HUF_initDStream(BYTE const* ip) { + BYTE const lastByte = ip[7]; + size_t const bitsConsumed = lastByte ? 8 - BIT_highbit32(lastByte) : 0; + size_t const value = MEM_readLEST(ip) | 1; + assert(bitsConsumed <= 8); + return value << bitsConsumed; +} +typedef struct { + BYTE const* ip[4]; + BYTE* op[4]; + U64 bits[4]; + void const* dt; + BYTE const* ilimit; + BYTE* oend; + BYTE const* iend[4]; +} HUF_DecompressAsmArgs; + +/** + * Initializes args for the asm decoding loop. + * @returns 0 on success + * 1 if the fallback implementation should be used. + * Or an error code on failure. + */ +static size_t HUF_DecompressAsmArgs_init(HUF_DecompressAsmArgs* args, void* dst, size_t dstSize, void const* src, size_t srcSize, const HUF_DTable* DTable) +{ + void const* dt = DTable + 1; + U32 const dtLog = HUF_getDTableDesc(DTable).tableLog; + + const BYTE* const ilimit = (const BYTE*)src + 6 + 8; + + BYTE* const oend = (BYTE*)dst + dstSize; + + /* The following condition is false on x32 platform, + * but HUF_asm is not compatible with this ABI */ + if (!(MEM_isLittleEndian() && !MEM_32bits())) return 1; + + /* strict minimum : jump table + 1 byte per stream */ + if (srcSize < 10) + return ERROR(corruption_detected); + + /* Must have at least 8 bytes per stream because we don't handle initializing smaller bit containers. + * If table log is not correct at this point, fallback to the old decoder. + * On small inputs we don't have enough data to trigger the fast loop, so use the old decoder. + */ + if (dtLog != HUF_DECODER_FAST_TABLELOG) + return 1; + + /* Read the jump table. */ + { + const BYTE* const istart = (const BYTE*)src; + size_t const length1 = MEM_readLE16(istart); + size_t const length2 = MEM_readLE16(istart+2); + size_t const length3 = MEM_readLE16(istart+4); + size_t const length4 = srcSize - (length1 + length2 + length3 + 6); + args->iend[0] = istart + 6; /* jumpTable */ + args->iend[1] = args->iend[0] + length1; + args->iend[2] = args->iend[1] + length2; + args->iend[3] = args->iend[2] + length3; + + /* HUF_initDStream() requires this, and this small of an input + * won't benefit from the ASM loop anyways. + * length1 must be >= 16 so that ip[0] >= ilimit before the loop + * starts. + */ + if (length1 < 16 || length2 < 8 || length3 < 8 || length4 < 8) + return 1; + if (length4 > srcSize) return ERROR(corruption_detected); /* overflow */ + } + /* ip[] contains the position that is currently loaded into bits[]. */ + args->ip[0] = args->iend[1] - sizeof(U64); + args->ip[1] = args->iend[2] - sizeof(U64); + args->ip[2] = args->iend[3] - sizeof(U64); + args->ip[3] = (BYTE const*)src + srcSize - sizeof(U64); + + /* op[] contains the output pointers. */ + args->op[0] = (BYTE*)dst; + args->op[1] = args->op[0] + (dstSize+3)/4; + args->op[2] = args->op[1] + (dstSize+3)/4; + args->op[3] = args->op[2] + (dstSize+3)/4; + + /* No point to call the ASM loop for tiny outputs. */ + if (args->op[3] >= oend) + return 1; + + /* bits[] is the bit container. + * It is read from the MSB down to the LSB. + * It is shifted left as it is read, and zeros are + * shifted in. After the lowest valid bit a 1 is + * set, so that CountTrailingZeros(bits[]) can be used + * to count how many bits we've consumed. + */ + args->bits[0] = HUF_initDStream(args->ip[0]); + args->bits[1] = HUF_initDStream(args->ip[1]); + args->bits[2] = HUF_initDStream(args->ip[2]); + args->bits[3] = HUF_initDStream(args->ip[3]); + + /* If ip[] >= ilimit, it is guaranteed to be safe to + * reload bits[]. It may be beyond its section, but is + * guaranteed to be valid (>= istart). + */ + args->ilimit = ilimit; + + args->oend = oend; + args->dt = dt; + + return 0; +} + +static size_t HUF_initRemainingDStream(BIT_DStream_t* bit, HUF_DecompressAsmArgs const* args, int stream, BYTE* segmentEnd) +{ + /* Validate that we haven't overwritten. */ + if (args->op[stream] > segmentEnd) + return ERROR(corruption_detected); + /* Validate that we haven't read beyond iend[]. + * Note that ip[] may be < iend[] because the MSB is + * the next bit to read, and we may have consumed 100% + * of the stream, so down to iend[i] - 8 is valid. + */ + if (args->ip[stream] < args->iend[stream] - 8) + return ERROR(corruption_detected); + + /* Construct the BIT_DStream_t. */ + bit->bitContainer = MEM_readLE64(args->ip[stream]); + bit->bitsConsumed = ZSTD_countTrailingZeros((size_t)args->bits[stream]); + bit->start = (const char*)args->iend[0]; + bit->limitPtr = bit->start + sizeof(size_t); + bit->ptr = (const char*)args->ip[stream]; + + return 0; +} +#endif + + +#ifndef HUF_FORCE_DECOMPRESS_X2 + +/*-***************************/ +/* single-symbol decoding */ +/*-***************************/ +typedef struct { BYTE nbBits; BYTE byte; } HUF_DEltX1; /* single-symbol decoding */ + +/** + * Packs 4 HUF_DEltX1 structs into a U64. This is used to lay down 4 entries at + * a time. + */ +static U64 HUF_DEltX1_set4(BYTE symbol, BYTE nbBits) { + U64 D4; + if (MEM_isLittleEndian()) { + D4 = (symbol << 8) + nbBits; + } else { + D4 = symbol + (nbBits << 8); + } + D4 *= 0x0001000100010001ULL; + return D4; +} + +/** + * Increase the tableLog to targetTableLog and rescales the stats. + * If tableLog > targetTableLog this is a no-op. + * @returns New tableLog + */ +static U32 HUF_rescaleStats(BYTE* huffWeight, U32* rankVal, U32 nbSymbols, U32 tableLog, U32 targetTableLog) +{ + if (tableLog > targetTableLog) + return tableLog; + if (tableLog < targetTableLog) { + U32 const scale = targetTableLog - tableLog; + U32 s; + /* Increase the weight for all non-zero probability symbols by scale. */ + for (s = 0; s < nbSymbols; ++s) { + huffWeight[s] += (BYTE)((huffWeight[s] == 0) ? 0 : scale); + } + /* Update rankVal to reflect the new weights. + * All weights except 0 get moved to weight + scale. + * Weights [1, scale] are empty. + */ + for (s = targetTableLog; s > scale; --s) { + rankVal[s] = rankVal[s - scale]; + } + for (s = scale; s > 0; --s) { + rankVal[s] = 0; + } + } + return targetTableLog; +} + +typedef struct { + U32 rankVal[HUF_TABLELOG_ABSOLUTEMAX + 1]; + U32 rankStart[HUF_TABLELOG_ABSOLUTEMAX + 1]; + U32 statsWksp[HUF_READ_STATS_WORKSPACE_SIZE_U32]; + BYTE symbols[HUF_SYMBOLVALUE_MAX + 1]; + BYTE huffWeight[HUF_SYMBOLVALUE_MAX + 1]; +} HUF_ReadDTableX1_Workspace; + + +size_t HUF_readDTableX1_wksp(HUF_DTable* DTable, const void* src, size_t srcSize, void* workSpace, size_t wkspSize) +{ + return HUF_readDTableX1_wksp_bmi2(DTable, src, srcSize, workSpace, wkspSize, /* bmi2 */ 0); +} + +size_t HUF_readDTableX1_wksp_bmi2(HUF_DTable* DTable, const void* src, size_t srcSize, void* workSpace, size_t wkspSize, int bmi2) +{ + U32 tableLog = 0; + U32 nbSymbols = 0; + size_t iSize; + void* const dtPtr = DTable + 1; + HUF_DEltX1* const dt = (HUF_DEltX1*)dtPtr; + HUF_ReadDTableX1_Workspace* wksp = (HUF_ReadDTableX1_Workspace*)workSpace; + + DEBUG_STATIC_ASSERT(HUF_DECOMPRESS_WORKSPACE_SIZE >= sizeof(*wksp)); + if (sizeof(*wksp) > wkspSize) return ERROR(tableLog_tooLarge); + + DEBUG_STATIC_ASSERT(sizeof(DTableDesc) == sizeof(HUF_DTable)); + /* ZSTD_memset(huffWeight, 0, sizeof(huffWeight)); */ /* is not necessary, even though some analyzer complain ... */ + + iSize = HUF_readStats_wksp(wksp->huffWeight, HUF_SYMBOLVALUE_MAX + 1, wksp->rankVal, &nbSymbols, &tableLog, src, srcSize, wksp->statsWksp, sizeof(wksp->statsWksp), bmi2); + if (HUF_isError(iSize)) return iSize; + + + /* Table header */ + { DTableDesc dtd = HUF_getDTableDesc(DTable); + U32 const maxTableLog = dtd.maxTableLog + 1; + U32 const targetTableLog = MIN(maxTableLog, HUF_DECODER_FAST_TABLELOG); + tableLog = HUF_rescaleStats(wksp->huffWeight, wksp->rankVal, nbSymbols, tableLog, targetTableLog); + if (tableLog > (U32)(dtd.maxTableLog+1)) return ERROR(tableLog_tooLarge); /* DTable too small, Huffman tree cannot fit in */ + dtd.tableType = 0; + dtd.tableLog = (BYTE)tableLog; + ZSTD_memcpy(DTable, &dtd, sizeof(dtd)); + } + + /* Compute symbols and rankStart given rankVal: + * + * rankVal already contains the number of values of each weight. + * + * symbols contains the symbols ordered by weight. First are the rankVal[0] + * weight 0 symbols, followed by the rankVal[1] weight 1 symbols, and so on. + * symbols[0] is filled (but unused) to avoid a branch. + * + * rankStart contains the offset where each rank belongs in the DTable. + * rankStart[0] is not filled because there are no entries in the table for + * weight 0. + */ + { + int n; + int nextRankStart = 0; + int const unroll = 4; + int const nLimit = (int)nbSymbols - unroll + 1; + for (n=0; n<(int)tableLog+1; n++) { + U32 const curr = nextRankStart; + nextRankStart += wksp->rankVal[n]; + wksp->rankStart[n] = curr; + } + for (n=0; n < nLimit; n += unroll) { + int u; + for (u=0; u < unroll; ++u) { + size_t const w = wksp->huffWeight[n+u]; + wksp->symbols[wksp->rankStart[w]++] = (BYTE)(n+u); + } + } + for (; n < (int)nbSymbols; ++n) { + size_t const w = wksp->huffWeight[n]; + wksp->symbols[wksp->rankStart[w]++] = (BYTE)n; + } + } + + /* fill DTable + * We fill all entries of each weight in order. + * That way length is a constant for each iteration of the outer loop. + * We can switch based on the length to a different inner loop which is + * optimized for that particular case. + */ + { + U32 w; + int symbol=wksp->rankVal[0]; + int rankStart=0; + for (w=1; wrankVal[w]; + int const length = (1 << w) >> 1; + int uStart = rankStart; + BYTE const nbBits = (BYTE)(tableLog + 1 - w); + int s; + int u; + switch (length) { + case 1: + for (s=0; ssymbols[symbol + s]; + D.nbBits = nbBits; + dt[uStart] = D; + uStart += 1; + } + break; + case 2: + for (s=0; ssymbols[symbol + s]; + D.nbBits = nbBits; + dt[uStart+0] = D; + dt[uStart+1] = D; + uStart += 2; + } + break; + case 4: + for (s=0; ssymbols[symbol + s], nbBits); + MEM_write64(dt + uStart, D4); + uStart += 4; + } + break; + case 8: + for (s=0; ssymbols[symbol + s], nbBits); + MEM_write64(dt + uStart, D4); + MEM_write64(dt + uStart + 4, D4); + uStart += 8; + } + break; + default: + for (s=0; ssymbols[symbol + s], nbBits); + for (u=0; u < length; u += 16) { + MEM_write64(dt + uStart + u + 0, D4); + MEM_write64(dt + uStart + u + 4, D4); + MEM_write64(dt + uStart + u + 8, D4); + MEM_write64(dt + uStart + u + 12, D4); + } + assert(u == length); + uStart += length; + } + break; + } + symbol += symbolCount; + rankStart += symbolCount * length; + } + } + return iSize; +} + +FORCE_INLINE_TEMPLATE BYTE +HUF_decodeSymbolX1(BIT_DStream_t* Dstream, const HUF_DEltX1* dt, const U32 dtLog) +{ + size_t const val = BIT_lookBitsFast(Dstream, dtLog); /* note : dtLog >= 1 */ + BYTE const c = dt[val].byte; + BIT_skipBits(Dstream, dt[val].nbBits); + return c; +} + +#define HUF_DECODE_SYMBOLX1_0(ptr, DStreamPtr) \ + *ptr++ = HUF_decodeSymbolX1(DStreamPtr, dt, dtLog) + +#define HUF_DECODE_SYMBOLX1_1(ptr, DStreamPtr) \ + if (MEM_64bits() || (HUF_TABLELOG_MAX<=12)) \ + HUF_DECODE_SYMBOLX1_0(ptr, DStreamPtr) + +#define HUF_DECODE_SYMBOLX1_2(ptr, DStreamPtr) \ + if (MEM_64bits()) \ + HUF_DECODE_SYMBOLX1_0(ptr, DStreamPtr) + +HINT_INLINE size_t +HUF_decodeStreamX1(BYTE* p, BIT_DStream_t* const bitDPtr, BYTE* const pEnd, const HUF_DEltX1* const dt, const U32 dtLog) +{ + BYTE* const pStart = p; + + /* up to 4 symbols at a time */ + if ((pEnd - p) > 3) { + while ((BIT_reloadDStream(bitDPtr) == BIT_DStream_unfinished) & (p < pEnd-3)) { + HUF_DECODE_SYMBOLX1_2(p, bitDPtr); + HUF_DECODE_SYMBOLX1_1(p, bitDPtr); + HUF_DECODE_SYMBOLX1_2(p, bitDPtr); + HUF_DECODE_SYMBOLX1_0(p, bitDPtr); + } + } else { + BIT_reloadDStream(bitDPtr); + } + + /* [0-3] symbols remaining */ + if (MEM_32bits()) + while ((BIT_reloadDStream(bitDPtr) == BIT_DStream_unfinished) & (p < pEnd)) + HUF_DECODE_SYMBOLX1_0(p, bitDPtr); + + /* no more data to retrieve from bitstream, no need to reload */ + while (p < pEnd) + HUF_DECODE_SYMBOLX1_0(p, bitDPtr); + + return pEnd-pStart; +} + +FORCE_INLINE_TEMPLATE size_t +HUF_decompress1X1_usingDTable_internal_body( + void* dst, size_t dstSize, + const void* cSrc, size_t cSrcSize, + const HUF_DTable* DTable) +{ + BYTE* op = (BYTE*)dst; + BYTE* const oend = op + dstSize; + const void* dtPtr = DTable + 1; + const HUF_DEltX1* const dt = (const HUF_DEltX1*)dtPtr; + BIT_DStream_t bitD; + DTableDesc const dtd = HUF_getDTableDesc(DTable); + U32 const dtLog = dtd.tableLog; + + CHECK_F( BIT_initDStream(&bitD, cSrc, cSrcSize) ); + + HUF_decodeStreamX1(op, &bitD, oend, dt, dtLog); + + if (!BIT_endOfDStream(&bitD)) return ERROR(corruption_detected); + + return dstSize; +} + +FORCE_INLINE_TEMPLATE size_t +HUF_decompress4X1_usingDTable_internal_body( + void* dst, size_t dstSize, + const void* cSrc, size_t cSrcSize, + const HUF_DTable* DTable) +{ + /* Check */ + if (cSrcSize < 10) return ERROR(corruption_detected); /* strict minimum : jump table + 1 byte per stream */ + + { const BYTE* const istart = (const BYTE*) cSrc; + BYTE* const ostart = (BYTE*) dst; + BYTE* const oend = ostart + dstSize; + BYTE* const olimit = oend - 3; + const void* const dtPtr = DTable + 1; + const HUF_DEltX1* const dt = (const HUF_DEltX1*)dtPtr; + + /* Init */ + BIT_DStream_t bitD1; + BIT_DStream_t bitD2; + BIT_DStream_t bitD3; + BIT_DStream_t bitD4; + size_t const length1 = MEM_readLE16(istart); + size_t const length2 = MEM_readLE16(istart+2); + size_t const length3 = MEM_readLE16(istart+4); + size_t const length4 = cSrcSize - (length1 + length2 + length3 + 6); + const BYTE* const istart1 = istart + 6; /* jumpTable */ + const BYTE* const istart2 = istart1 + length1; + const BYTE* const istart3 = istart2 + length2; + const BYTE* const istart4 = istart3 + length3; + const size_t segmentSize = (dstSize+3) / 4; + BYTE* const opStart2 = ostart + segmentSize; + BYTE* const opStart3 = opStart2 + segmentSize; + BYTE* const opStart4 = opStart3 + segmentSize; + BYTE* op1 = ostart; + BYTE* op2 = opStart2; + BYTE* op3 = opStart3; + BYTE* op4 = opStart4; + DTableDesc const dtd = HUF_getDTableDesc(DTable); + U32 const dtLog = dtd.tableLog; + U32 endSignal = 1; + + if (length4 > cSrcSize) return ERROR(corruption_detected); /* overflow */ + if (opStart4 > oend) return ERROR(corruption_detected); /* overflow */ + CHECK_F( BIT_initDStream(&bitD1, istart1, length1) ); + CHECK_F( BIT_initDStream(&bitD2, istart2, length2) ); + CHECK_F( BIT_initDStream(&bitD3, istart3, length3) ); + CHECK_F( BIT_initDStream(&bitD4, istart4, length4) ); + + /* up to 16 symbols per loop (4 symbols per stream) in 64-bit mode */ + if ((size_t)(oend - op4) >= sizeof(size_t)) { + for ( ; (endSignal) & (op4 < olimit) ; ) { + HUF_DECODE_SYMBOLX1_2(op1, &bitD1); + HUF_DECODE_SYMBOLX1_2(op2, &bitD2); + HUF_DECODE_SYMBOLX1_2(op3, &bitD3); + HUF_DECODE_SYMBOLX1_2(op4, &bitD4); + HUF_DECODE_SYMBOLX1_1(op1, &bitD1); + HUF_DECODE_SYMBOLX1_1(op2, &bitD2); + HUF_DECODE_SYMBOLX1_1(op3, &bitD3); + HUF_DECODE_SYMBOLX1_1(op4, &bitD4); + HUF_DECODE_SYMBOLX1_2(op1, &bitD1); + HUF_DECODE_SYMBOLX1_2(op2, &bitD2); + HUF_DECODE_SYMBOLX1_2(op3, &bitD3); + HUF_DECODE_SYMBOLX1_2(op4, &bitD4); + HUF_DECODE_SYMBOLX1_0(op1, &bitD1); + HUF_DECODE_SYMBOLX1_0(op2, &bitD2); + HUF_DECODE_SYMBOLX1_0(op3, &bitD3); + HUF_DECODE_SYMBOLX1_0(op4, &bitD4); + endSignal &= BIT_reloadDStreamFast(&bitD1) == BIT_DStream_unfinished; + endSignal &= BIT_reloadDStreamFast(&bitD2) == BIT_DStream_unfinished; + endSignal &= BIT_reloadDStreamFast(&bitD3) == BIT_DStream_unfinished; + endSignal &= BIT_reloadDStreamFast(&bitD4) == BIT_DStream_unfinished; + } + } + + /* check corruption */ + /* note : should not be necessary : op# advance in lock step, and we control op4. + * but curiously, binary generated by gcc 7.2 & 7.3 with -mbmi2 runs faster when >=1 test is present */ + if (op1 > opStart2) return ERROR(corruption_detected); + if (op2 > opStart3) return ERROR(corruption_detected); + if (op3 > opStart4) return ERROR(corruption_detected); + /* note : op4 supposed already verified within main loop */ + + /* finish bitStreams one by one */ + HUF_decodeStreamX1(op1, &bitD1, opStart2, dt, dtLog); + HUF_decodeStreamX1(op2, &bitD2, opStart3, dt, dtLog); + HUF_decodeStreamX1(op3, &bitD3, opStart4, dt, dtLog); + HUF_decodeStreamX1(op4, &bitD4, oend, dt, dtLog); + + /* check */ + { U32 const endCheck = BIT_endOfDStream(&bitD1) & BIT_endOfDStream(&bitD2) & BIT_endOfDStream(&bitD3) & BIT_endOfDStream(&bitD4); + if (!endCheck) return ERROR(corruption_detected); } + + /* decoded size */ + return dstSize; + } +} + +#if HUF_NEED_BMI2_FUNCTION +static BMI2_TARGET_ATTRIBUTE +size_t HUF_decompress4X1_usingDTable_internal_bmi2(void* dst, size_t dstSize, void const* cSrc, + size_t cSrcSize, HUF_DTable const* DTable) { + return HUF_decompress4X1_usingDTable_internal_body(dst, dstSize, cSrc, cSrcSize, DTable); +} +#endif + +#if HUF_NEED_DEFAULT_FUNCTION +static +size_t HUF_decompress4X1_usingDTable_internal_default(void* dst, size_t dstSize, void const* cSrc, + size_t cSrcSize, HUF_DTable const* DTable) { + return HUF_decompress4X1_usingDTable_internal_body(dst, dstSize, cSrc, cSrcSize, DTable); +} +#endif + +#if ZSTD_ENABLE_ASM_X86_64_BMI2 + +HUF_ASM_DECL void HUF_decompress4X1_usingDTable_internal_bmi2_asm_loop(HUF_DecompressAsmArgs* args) ZSTDLIB_HIDDEN; + +static HUF_ASM_X86_64_BMI2_ATTRS +size_t +HUF_decompress4X1_usingDTable_internal_bmi2_asm( + void* dst, size_t dstSize, + const void* cSrc, size_t cSrcSize, + const HUF_DTable* DTable) +{ + void const* dt = DTable + 1; + const BYTE* const iend = (const BYTE*)cSrc + 6; + BYTE* const oend = (BYTE*)dst + dstSize; + HUF_DecompressAsmArgs args; + { + size_t const ret = HUF_DecompressAsmArgs_init(&args, dst, dstSize, cSrc, cSrcSize, DTable); + FORWARD_IF_ERROR(ret, "Failed to init asm args"); + if (ret != 0) + return HUF_decompress4X1_usingDTable_internal_bmi2(dst, dstSize, cSrc, cSrcSize, DTable); + } + + assert(args.ip[0] >= args.ilimit); + HUF_decompress4X1_usingDTable_internal_bmi2_asm_loop(&args); + + /* Our loop guarantees that ip[] >= ilimit and that we haven't + * overwritten any op[]. + */ + assert(args.ip[0] >= iend); + assert(args.ip[1] >= iend); + assert(args.ip[2] >= iend); + assert(args.ip[3] >= iend); + assert(args.op[3] <= oend); + (void)iend; + + /* finish bit streams one by one. */ + { + size_t const segmentSize = (dstSize+3) / 4; + BYTE* segmentEnd = (BYTE*)dst; + int i; + for (i = 0; i < 4; ++i) { + BIT_DStream_t bit; + if (segmentSize <= (size_t)(oend - segmentEnd)) + segmentEnd += segmentSize; + else + segmentEnd = oend; + FORWARD_IF_ERROR(HUF_initRemainingDStream(&bit, &args, i, segmentEnd), "corruption"); + /* Decompress and validate that we've produced exactly the expected length. */ + args.op[i] += HUF_decodeStreamX1(args.op[i], &bit, segmentEnd, (HUF_DEltX1 const*)dt, HUF_DECODER_FAST_TABLELOG); + if (args.op[i] != segmentEnd) return ERROR(corruption_detected); + } + } + + /* decoded size */ + return dstSize; +} +#endif /* ZSTD_ENABLE_ASM_X86_64_BMI2 */ + +typedef size_t (*HUF_decompress_usingDTable_t)(void *dst, size_t dstSize, + const void *cSrc, + size_t cSrcSize, + const HUF_DTable *DTable); + +HUF_DGEN(HUF_decompress1X1_usingDTable_internal) + +static size_t HUF_decompress4X1_usingDTable_internal(void* dst, size_t dstSize, void const* cSrc, + size_t cSrcSize, HUF_DTable const* DTable, int bmi2) +{ +#if DYNAMIC_BMI2 + if (bmi2) { +# if ZSTD_ENABLE_ASM_X86_64_BMI2 + return HUF_decompress4X1_usingDTable_internal_bmi2_asm(dst, dstSize, cSrc, cSrcSize, DTable); +# else + return HUF_decompress4X1_usingDTable_internal_bmi2(dst, dstSize, cSrc, cSrcSize, DTable); +# endif + } +#else + (void)bmi2; +#endif + +#if ZSTD_ENABLE_ASM_X86_64_BMI2 && defined(__BMI2__) + return HUF_decompress4X1_usingDTable_internal_bmi2_asm(dst, dstSize, cSrc, cSrcSize, DTable); +#else + return HUF_decompress4X1_usingDTable_internal_default(dst, dstSize, cSrc, cSrcSize, DTable); +#endif +} + + +size_t HUF_decompress1X1_usingDTable( + void* dst, size_t dstSize, + const void* cSrc, size_t cSrcSize, + const HUF_DTable* DTable) +{ + DTableDesc dtd = HUF_getDTableDesc(DTable); + if (dtd.tableType != 0) return ERROR(GENERIC); + return HUF_decompress1X1_usingDTable_internal(dst, dstSize, cSrc, cSrcSize, DTable, /* bmi2 */ 0); +} + +size_t HUF_decompress1X1_DCtx_wksp(HUF_DTable* DCtx, void* dst, size_t dstSize, + const void* cSrc, size_t cSrcSize, + void* workSpace, size_t wkspSize) +{ + const BYTE* ip = (const BYTE*) cSrc; + + size_t const hSize = HUF_readDTableX1_wksp(DCtx, cSrc, cSrcSize, workSpace, wkspSize); + if (HUF_isError(hSize)) return hSize; + if (hSize >= cSrcSize) return ERROR(srcSize_wrong); + ip += hSize; cSrcSize -= hSize; + + return HUF_decompress1X1_usingDTable_internal(dst, dstSize, ip, cSrcSize, DCtx, /* bmi2 */ 0); +} + + +size_t HUF_decompress4X1_usingDTable( + void* dst, size_t dstSize, + const void* cSrc, size_t cSrcSize, + const HUF_DTable* DTable) +{ + DTableDesc dtd = HUF_getDTableDesc(DTable); + if (dtd.tableType != 0) return ERROR(GENERIC); + return HUF_decompress4X1_usingDTable_internal(dst, dstSize, cSrc, cSrcSize, DTable, /* bmi2 */ 0); +} + +static size_t HUF_decompress4X1_DCtx_wksp_bmi2(HUF_DTable* dctx, void* dst, size_t dstSize, + const void* cSrc, size_t cSrcSize, + void* workSpace, size_t wkspSize, int bmi2) +{ + const BYTE* ip = (const BYTE*) cSrc; + + size_t const hSize = HUF_readDTableX1_wksp_bmi2(dctx, cSrc, cSrcSize, workSpace, wkspSize, bmi2); + if (HUF_isError(hSize)) return hSize; + if (hSize >= cSrcSize) return ERROR(srcSize_wrong); + ip += hSize; cSrcSize -= hSize; + + return HUF_decompress4X1_usingDTable_internal(dst, dstSize, ip, cSrcSize, dctx, bmi2); +} + +size_t HUF_decompress4X1_DCtx_wksp(HUF_DTable* dctx, void* dst, size_t dstSize, + const void* cSrc, size_t cSrcSize, + void* workSpace, size_t wkspSize) +{ + return HUF_decompress4X1_DCtx_wksp_bmi2(dctx, dst, dstSize, cSrc, cSrcSize, workSpace, wkspSize, 0); +} + + +#endif /* HUF_FORCE_DECOMPRESS_X2 */ + + +#ifndef HUF_FORCE_DECOMPRESS_X1 + +/* *************************/ +/* double-symbols decoding */ +/* *************************/ + +typedef struct { U16 sequence; BYTE nbBits; BYTE length; } HUF_DEltX2; /* double-symbols decoding */ +typedef struct { BYTE symbol; } sortedSymbol_t; +typedef U32 rankValCol_t[HUF_TABLELOG_MAX + 1]; +typedef rankValCol_t rankVal_t[HUF_TABLELOG_MAX]; + +/** + * Constructs a HUF_DEltX2 in a U32. + */ +static U32 HUF_buildDEltX2U32(U32 symbol, U32 nbBits, U32 baseSeq, int level) +{ + U32 seq; + DEBUG_STATIC_ASSERT(offsetof(HUF_DEltX2, sequence) == 0); + DEBUG_STATIC_ASSERT(offsetof(HUF_DEltX2, nbBits) == 2); + DEBUG_STATIC_ASSERT(offsetof(HUF_DEltX2, length) == 3); + DEBUG_STATIC_ASSERT(sizeof(HUF_DEltX2) == sizeof(U32)); + if (MEM_isLittleEndian()) { + seq = level == 1 ? symbol : (baseSeq + (symbol << 8)); + return seq + (nbBits << 16) + ((U32)level << 24); + } else { + seq = level == 1 ? (symbol << 8) : ((baseSeq << 8) + symbol); + return (seq << 16) + (nbBits << 8) + (U32)level; + } +} + +/** + * Constructs a HUF_DEltX2. + */ +static HUF_DEltX2 HUF_buildDEltX2(U32 symbol, U32 nbBits, U32 baseSeq, int level) +{ + HUF_DEltX2 DElt; + U32 const val = HUF_buildDEltX2U32(symbol, nbBits, baseSeq, level); + DEBUG_STATIC_ASSERT(sizeof(DElt) == sizeof(val)); + ZSTD_memcpy(&DElt, &val, sizeof(val)); + return DElt; +} + +/** + * Constructs 2 HUF_DEltX2s and packs them into a U64. + */ +static U64 HUF_buildDEltX2U64(U32 symbol, U32 nbBits, U16 baseSeq, int level) +{ + U32 DElt = HUF_buildDEltX2U32(symbol, nbBits, baseSeq, level); + return (U64)DElt + ((U64)DElt << 32); +} + +/** + * Fills the DTable rank with all the symbols from [begin, end) that are each + * nbBits long. + * + * @param DTableRank The start of the rank in the DTable. + * @param begin The first symbol to fill (inclusive). + * @param end The last symbol to fill (exclusive). + * @param nbBits Each symbol is nbBits long. + * @param tableLog The table log. + * @param baseSeq If level == 1 { 0 } else { the first level symbol } + * @param level The level in the table. Must be 1 or 2. + */ +static void HUF_fillDTableX2ForWeight( + HUF_DEltX2* DTableRank, + sortedSymbol_t const* begin, sortedSymbol_t const* end, + U32 nbBits, U32 tableLog, + U16 baseSeq, int const level) +{ + U32 const length = 1U << ((tableLog - nbBits) & 0x1F /* quiet static-analyzer */); + const sortedSymbol_t* ptr; + assert(level >= 1 && level <= 2); + switch (length) { + case 1: + for (ptr = begin; ptr != end; ++ptr) { + HUF_DEltX2 const DElt = HUF_buildDEltX2(ptr->symbol, nbBits, baseSeq, level); + *DTableRank++ = DElt; + } + break; + case 2: + for (ptr = begin; ptr != end; ++ptr) { + HUF_DEltX2 const DElt = HUF_buildDEltX2(ptr->symbol, nbBits, baseSeq, level); + DTableRank[0] = DElt; + DTableRank[1] = DElt; + DTableRank += 2; + } + break; + case 4: + for (ptr = begin; ptr != end; ++ptr) { + U64 const DEltX2 = HUF_buildDEltX2U64(ptr->symbol, nbBits, baseSeq, level); + ZSTD_memcpy(DTableRank + 0, &DEltX2, sizeof(DEltX2)); + ZSTD_memcpy(DTableRank + 2, &DEltX2, sizeof(DEltX2)); + DTableRank += 4; + } + break; + case 8: + for (ptr = begin; ptr != end; ++ptr) { + U64 const DEltX2 = HUF_buildDEltX2U64(ptr->symbol, nbBits, baseSeq, level); + ZSTD_memcpy(DTableRank + 0, &DEltX2, sizeof(DEltX2)); + ZSTD_memcpy(DTableRank + 2, &DEltX2, sizeof(DEltX2)); + ZSTD_memcpy(DTableRank + 4, &DEltX2, sizeof(DEltX2)); + ZSTD_memcpy(DTableRank + 6, &DEltX2, sizeof(DEltX2)); + DTableRank += 8; + } + break; + default: + for (ptr = begin; ptr != end; ++ptr) { + U64 const DEltX2 = HUF_buildDEltX2U64(ptr->symbol, nbBits, baseSeq, level); + HUF_DEltX2* const DTableRankEnd = DTableRank + length; + for (; DTableRank != DTableRankEnd; DTableRank += 8) { + ZSTD_memcpy(DTableRank + 0, &DEltX2, sizeof(DEltX2)); + ZSTD_memcpy(DTableRank + 2, &DEltX2, sizeof(DEltX2)); + ZSTD_memcpy(DTableRank + 4, &DEltX2, sizeof(DEltX2)); + ZSTD_memcpy(DTableRank + 6, &DEltX2, sizeof(DEltX2)); + } + } + break; + } +} + +/* HUF_fillDTableX2Level2() : + * `rankValOrigin` must be a table of at least (HUF_TABLELOG_MAX + 1) U32 */ +static void HUF_fillDTableX2Level2(HUF_DEltX2* DTable, U32 targetLog, const U32 consumedBits, + const U32* rankVal, const int minWeight, const int maxWeight1, + const sortedSymbol_t* sortedSymbols, U32 const* rankStart, + U32 nbBitsBaseline, U16 baseSeq) +{ + /* Fill skipped values (all positions up to rankVal[minWeight]). + * These are positions only get a single symbol because the combined weight + * is too large. + */ + if (minWeight>1) { + U32 const length = 1U << ((targetLog - consumedBits) & 0x1F /* quiet static-analyzer */); + U64 const DEltX2 = HUF_buildDEltX2U64(baseSeq, consumedBits, /* baseSeq */ 0, /* level */ 1); + int const skipSize = rankVal[minWeight]; + assert(length > 1); + assert((U32)skipSize < length); + switch (length) { + case 2: + assert(skipSize == 1); + ZSTD_memcpy(DTable, &DEltX2, sizeof(DEltX2)); + break; + case 4: + assert(skipSize <= 4); + ZSTD_memcpy(DTable + 0, &DEltX2, sizeof(DEltX2)); + ZSTD_memcpy(DTable + 2, &DEltX2, sizeof(DEltX2)); + break; + default: + { + int i; + for (i = 0; i < skipSize; i += 8) { + ZSTD_memcpy(DTable + i + 0, &DEltX2, sizeof(DEltX2)); + ZSTD_memcpy(DTable + i + 2, &DEltX2, sizeof(DEltX2)); + ZSTD_memcpy(DTable + i + 4, &DEltX2, sizeof(DEltX2)); + ZSTD_memcpy(DTable + i + 6, &DEltX2, sizeof(DEltX2)); + } + } + } + } + + /* Fill each of the second level symbols by weight. */ + { + int w; + for (w = minWeight; w < maxWeight1; ++w) { + int const begin = rankStart[w]; + int const end = rankStart[w+1]; + U32 const nbBits = nbBitsBaseline - w; + U32 const totalBits = nbBits + consumedBits; + HUF_fillDTableX2ForWeight( + DTable + rankVal[w], + sortedSymbols + begin, sortedSymbols + end, + totalBits, targetLog, + baseSeq, /* level */ 2); + } + } +} + +static void HUF_fillDTableX2(HUF_DEltX2* DTable, const U32 targetLog, + const sortedSymbol_t* sortedList, + const U32* rankStart, rankVal_t rankValOrigin, const U32 maxWeight, + const U32 nbBitsBaseline) +{ + U32* const rankVal = rankValOrigin[0]; + const int scaleLog = nbBitsBaseline - targetLog; /* note : targetLog >= srcLog, hence scaleLog <= 1 */ + const U32 minBits = nbBitsBaseline - maxWeight; + int w; + int const wEnd = (int)maxWeight + 1; + + /* Fill DTable in order of weight. */ + for (w = 1; w < wEnd; ++w) { + int const begin = (int)rankStart[w]; + int const end = (int)rankStart[w+1]; + U32 const nbBits = nbBitsBaseline - w; + + if (targetLog-nbBits >= minBits) { + /* Enough room for a second symbol. */ + int start = rankVal[w]; + U32 const length = 1U << ((targetLog - nbBits) & 0x1F /* quiet static-analyzer */); + int minWeight = nbBits + scaleLog; + int s; + if (minWeight < 1) minWeight = 1; + /* Fill the DTable for every symbol of weight w. + * These symbols get at least 1 second symbol. + */ + for (s = begin; s != end; ++s) { + HUF_fillDTableX2Level2( + DTable + start, targetLog, nbBits, + rankValOrigin[nbBits], minWeight, wEnd, + sortedList, rankStart, + nbBitsBaseline, sortedList[s].symbol); + start += length; + } + } else { + /* Only a single symbol. */ + HUF_fillDTableX2ForWeight( + DTable + rankVal[w], + sortedList + begin, sortedList + end, + nbBits, targetLog, + /* baseSeq */ 0, /* level */ 1); + } + } +} + +typedef struct { + rankValCol_t rankVal[HUF_TABLELOG_MAX]; + U32 rankStats[HUF_TABLELOG_MAX + 1]; + U32 rankStart0[HUF_TABLELOG_MAX + 3]; + sortedSymbol_t sortedSymbol[HUF_SYMBOLVALUE_MAX + 1]; + BYTE weightList[HUF_SYMBOLVALUE_MAX + 1]; + U32 calleeWksp[HUF_READ_STATS_WORKSPACE_SIZE_U32]; +} HUF_ReadDTableX2_Workspace; + +size_t HUF_readDTableX2_wksp(HUF_DTable* DTable, + const void* src, size_t srcSize, + void* workSpace, size_t wkspSize) +{ + return HUF_readDTableX2_wksp_bmi2(DTable, src, srcSize, workSpace, wkspSize, /* bmi2 */ 0); +} + +size_t HUF_readDTableX2_wksp_bmi2(HUF_DTable* DTable, + const void* src, size_t srcSize, + void* workSpace, size_t wkspSize, int bmi2) +{ + U32 tableLog, maxW, nbSymbols; + DTableDesc dtd = HUF_getDTableDesc(DTable); + U32 maxTableLog = dtd.maxTableLog; + size_t iSize; + void* dtPtr = DTable+1; /* force compiler to avoid strict-aliasing */ + HUF_DEltX2* const dt = (HUF_DEltX2*)dtPtr; + U32 *rankStart; + + HUF_ReadDTableX2_Workspace* const wksp = (HUF_ReadDTableX2_Workspace*)workSpace; + + if (sizeof(*wksp) > wkspSize) return ERROR(GENERIC); + + rankStart = wksp->rankStart0 + 1; + ZSTD_memset(wksp->rankStats, 0, sizeof(wksp->rankStats)); + ZSTD_memset(wksp->rankStart0, 0, sizeof(wksp->rankStart0)); + + DEBUG_STATIC_ASSERT(sizeof(HUF_DEltX2) == sizeof(HUF_DTable)); /* if compiler fails here, assertion is wrong */ + if (maxTableLog > HUF_TABLELOG_MAX) return ERROR(tableLog_tooLarge); + /* ZSTD_memset(weightList, 0, sizeof(weightList)); */ /* is not necessary, even though some analyzer complain ... */ + + iSize = HUF_readStats_wksp(wksp->weightList, HUF_SYMBOLVALUE_MAX + 1, wksp->rankStats, &nbSymbols, &tableLog, src, srcSize, wksp->calleeWksp, sizeof(wksp->calleeWksp), bmi2); + if (HUF_isError(iSize)) return iSize; + + /* check result */ + if (tableLog > maxTableLog) return ERROR(tableLog_tooLarge); /* DTable can't fit code depth */ + if (tableLog <= HUF_DECODER_FAST_TABLELOG && maxTableLog > HUF_DECODER_FAST_TABLELOG) maxTableLog = HUF_DECODER_FAST_TABLELOG; + + /* find maxWeight */ + for (maxW = tableLog; wksp->rankStats[maxW]==0; maxW--) {} /* necessarily finds a solution before 0 */ + + /* Get start index of each weight */ + { U32 w, nextRankStart = 0; + for (w=1; wrankStats[w]; + rankStart[w] = curr; + } + rankStart[0] = nextRankStart; /* put all 0w symbols at the end of sorted list*/ + rankStart[maxW+1] = nextRankStart; + } + + /* sort symbols by weight */ + { U32 s; + for (s=0; sweightList[s]; + U32 const r = rankStart[w]++; + wksp->sortedSymbol[r].symbol = (BYTE)s; + } + rankStart[0] = 0; /* forget 0w symbols; this is beginning of weight(1) */ + } + + /* Build rankVal */ + { U32* const rankVal0 = wksp->rankVal[0]; + { int const rescale = (maxTableLog-tableLog) - 1; /* tableLog <= maxTableLog */ + U32 nextRankVal = 0; + U32 w; + for (w=1; wrankStats[w] << (w+rescale); + rankVal0[w] = curr; + } } + { U32 const minBits = tableLog+1 - maxW; + U32 consumed; + for (consumed = minBits; consumed < maxTableLog - minBits + 1; consumed++) { + U32* const rankValPtr = wksp->rankVal[consumed]; + U32 w; + for (w = 1; w < maxW+1; w++) { + rankValPtr[w] = rankVal0[w] >> consumed; + } } } } + + HUF_fillDTableX2(dt, maxTableLog, + wksp->sortedSymbol, + wksp->rankStart0, wksp->rankVal, maxW, + tableLog+1); + + dtd.tableLog = (BYTE)maxTableLog; + dtd.tableType = 1; + ZSTD_memcpy(DTable, &dtd, sizeof(dtd)); + return iSize; +} + + +FORCE_INLINE_TEMPLATE U32 +HUF_decodeSymbolX2(void* op, BIT_DStream_t* DStream, const HUF_DEltX2* dt, const U32 dtLog) +{ + size_t const val = BIT_lookBitsFast(DStream, dtLog); /* note : dtLog >= 1 */ + ZSTD_memcpy(op, &dt[val].sequence, 2); + BIT_skipBits(DStream, dt[val].nbBits); + return dt[val].length; +} + +FORCE_INLINE_TEMPLATE U32 +HUF_decodeLastSymbolX2(void* op, BIT_DStream_t* DStream, const HUF_DEltX2* dt, const U32 dtLog) +{ + size_t const val = BIT_lookBitsFast(DStream, dtLog); /* note : dtLog >= 1 */ + ZSTD_memcpy(op, &dt[val].sequence, 1); + if (dt[val].length==1) { + BIT_skipBits(DStream, dt[val].nbBits); + } else { + if (DStream->bitsConsumed < (sizeof(DStream->bitContainer)*8)) { + BIT_skipBits(DStream, dt[val].nbBits); + if (DStream->bitsConsumed > (sizeof(DStream->bitContainer)*8)) + /* ugly hack; works only because it's the last symbol. Note : can't easily extract nbBits from just this symbol */ + DStream->bitsConsumed = (sizeof(DStream->bitContainer)*8); + } + } + return 1; +} + +#define HUF_DECODE_SYMBOLX2_0(ptr, DStreamPtr) \ + ptr += HUF_decodeSymbolX2(ptr, DStreamPtr, dt, dtLog) + +#define HUF_DECODE_SYMBOLX2_1(ptr, DStreamPtr) \ + if (MEM_64bits() || (HUF_TABLELOG_MAX<=12)) \ + ptr += HUF_decodeSymbolX2(ptr, DStreamPtr, dt, dtLog) + +#define HUF_DECODE_SYMBOLX2_2(ptr, DStreamPtr) \ + if (MEM_64bits()) \ + ptr += HUF_decodeSymbolX2(ptr, DStreamPtr, dt, dtLog) + +HINT_INLINE size_t +HUF_decodeStreamX2(BYTE* p, BIT_DStream_t* bitDPtr, BYTE* const pEnd, + const HUF_DEltX2* const dt, const U32 dtLog) +{ + BYTE* const pStart = p; + + /* up to 8 symbols at a time */ + if ((size_t)(pEnd - p) >= sizeof(bitDPtr->bitContainer)) { + if (dtLog <= 11 && MEM_64bits()) { + /* up to 10 symbols at a time */ + while ((BIT_reloadDStream(bitDPtr) == BIT_DStream_unfinished) & (p < pEnd-9)) { + HUF_DECODE_SYMBOLX2_0(p, bitDPtr); + HUF_DECODE_SYMBOLX2_0(p, bitDPtr); + HUF_DECODE_SYMBOLX2_0(p, bitDPtr); + HUF_DECODE_SYMBOLX2_0(p, bitDPtr); + HUF_DECODE_SYMBOLX2_0(p, bitDPtr); + } + } else { + /* up to 8 symbols at a time */ + while ((BIT_reloadDStream(bitDPtr) == BIT_DStream_unfinished) & (p < pEnd-(sizeof(bitDPtr->bitContainer)-1))) { + HUF_DECODE_SYMBOLX2_2(p, bitDPtr); + HUF_DECODE_SYMBOLX2_1(p, bitDPtr); + HUF_DECODE_SYMBOLX2_2(p, bitDPtr); + HUF_DECODE_SYMBOLX2_0(p, bitDPtr); + } + } + } else { + BIT_reloadDStream(bitDPtr); + } + + /* closer to end : up to 2 symbols at a time */ + if ((size_t)(pEnd - p) >= 2) { + while ((BIT_reloadDStream(bitDPtr) == BIT_DStream_unfinished) & (p <= pEnd-2)) + HUF_DECODE_SYMBOLX2_0(p, bitDPtr); + + while (p <= pEnd-2) + HUF_DECODE_SYMBOLX2_0(p, bitDPtr); /* no need to reload : reached the end of DStream */ + } + + if (p < pEnd) + p += HUF_decodeLastSymbolX2(p, bitDPtr, dt, dtLog); + + return p-pStart; +} + +FORCE_INLINE_TEMPLATE size_t +HUF_decompress1X2_usingDTable_internal_body( + void* dst, size_t dstSize, + const void* cSrc, size_t cSrcSize, + const HUF_DTable* DTable) +{ + BIT_DStream_t bitD; + + /* Init */ + CHECK_F( BIT_initDStream(&bitD, cSrc, cSrcSize) ); + + /* decode */ + { BYTE* const ostart = (BYTE*) dst; + BYTE* const oend = ostart + dstSize; + const void* const dtPtr = DTable+1; /* force compiler to not use strict-aliasing */ + const HUF_DEltX2* const dt = (const HUF_DEltX2*)dtPtr; + DTableDesc const dtd = HUF_getDTableDesc(DTable); + HUF_decodeStreamX2(ostart, &bitD, oend, dt, dtd.tableLog); + } + + /* check */ + if (!BIT_endOfDStream(&bitD)) return ERROR(corruption_detected); + + /* decoded size */ + return dstSize; +} +FORCE_INLINE_TEMPLATE size_t +HUF_decompress4X2_usingDTable_internal_body( + void* dst, size_t dstSize, + const void* cSrc, size_t cSrcSize, + const HUF_DTable* DTable) +{ + if (cSrcSize < 10) return ERROR(corruption_detected); /* strict minimum : jump table + 1 byte per stream */ + + { const BYTE* const istart = (const BYTE*) cSrc; + BYTE* const ostart = (BYTE*) dst; + BYTE* const oend = ostart + dstSize; + BYTE* const olimit = oend - (sizeof(size_t)-1); + const void* const dtPtr = DTable+1; + const HUF_DEltX2* const dt = (const HUF_DEltX2*)dtPtr; + + /* Init */ + BIT_DStream_t bitD1; + BIT_DStream_t bitD2; + BIT_DStream_t bitD3; + BIT_DStream_t bitD4; + size_t const length1 = MEM_readLE16(istart); + size_t const length2 = MEM_readLE16(istart+2); + size_t const length3 = MEM_readLE16(istart+4); + size_t const length4 = cSrcSize - (length1 + length2 + length3 + 6); + const BYTE* const istart1 = istart + 6; /* jumpTable */ + const BYTE* const istart2 = istart1 + length1; + const BYTE* const istart3 = istart2 + length2; + const BYTE* const istart4 = istart3 + length3; + size_t const segmentSize = (dstSize+3) / 4; + BYTE* const opStart2 = ostart + segmentSize; + BYTE* const opStart3 = opStart2 + segmentSize; + BYTE* const opStart4 = opStart3 + segmentSize; + BYTE* op1 = ostart; + BYTE* op2 = opStart2; + BYTE* op3 = opStart3; + BYTE* op4 = opStart4; + U32 endSignal = 1; + DTableDesc const dtd = HUF_getDTableDesc(DTable); + U32 const dtLog = dtd.tableLog; + + if (length4 > cSrcSize) return ERROR(corruption_detected); /* overflow */ + if (opStart4 > oend) return ERROR(corruption_detected); /* overflow */ + CHECK_F( BIT_initDStream(&bitD1, istart1, length1) ); + CHECK_F( BIT_initDStream(&bitD2, istart2, length2) ); + CHECK_F( BIT_initDStream(&bitD3, istart3, length3) ); + CHECK_F( BIT_initDStream(&bitD4, istart4, length4) ); + + /* 16-32 symbols per loop (4-8 symbols per stream) */ + if ((size_t)(oend - op4) >= sizeof(size_t)) { + for ( ; (endSignal) & (op4 < olimit); ) { +#if defined(__clang__) && (defined(__x86_64__) || defined(__i386__)) + HUF_DECODE_SYMBOLX2_2(op1, &bitD1); + HUF_DECODE_SYMBOLX2_1(op1, &bitD1); + HUF_DECODE_SYMBOLX2_2(op1, &bitD1); + HUF_DECODE_SYMBOLX2_0(op1, &bitD1); + HUF_DECODE_SYMBOLX2_2(op2, &bitD2); + HUF_DECODE_SYMBOLX2_1(op2, &bitD2); + HUF_DECODE_SYMBOLX2_2(op2, &bitD2); + HUF_DECODE_SYMBOLX2_0(op2, &bitD2); + endSignal &= BIT_reloadDStreamFast(&bitD1) == BIT_DStream_unfinished; + endSignal &= BIT_reloadDStreamFast(&bitD2) == BIT_DStream_unfinished; + HUF_DECODE_SYMBOLX2_2(op3, &bitD3); + HUF_DECODE_SYMBOLX2_1(op3, &bitD3); + HUF_DECODE_SYMBOLX2_2(op3, &bitD3); + HUF_DECODE_SYMBOLX2_0(op3, &bitD3); + HUF_DECODE_SYMBOLX2_2(op4, &bitD4); + HUF_DECODE_SYMBOLX2_1(op4, &bitD4); + HUF_DECODE_SYMBOLX2_2(op4, &bitD4); + HUF_DECODE_SYMBOLX2_0(op4, &bitD4); + endSignal &= BIT_reloadDStreamFast(&bitD3) == BIT_DStream_unfinished; + endSignal &= BIT_reloadDStreamFast(&bitD4) == BIT_DStream_unfinished; +#else + HUF_DECODE_SYMBOLX2_2(op1, &bitD1); + HUF_DECODE_SYMBOLX2_2(op2, &bitD2); + HUF_DECODE_SYMBOLX2_2(op3, &bitD3); + HUF_DECODE_SYMBOLX2_2(op4, &bitD4); + HUF_DECODE_SYMBOLX2_1(op1, &bitD1); + HUF_DECODE_SYMBOLX2_1(op2, &bitD2); + HUF_DECODE_SYMBOLX2_1(op3, &bitD3); + HUF_DECODE_SYMBOLX2_1(op4, &bitD4); + HUF_DECODE_SYMBOLX2_2(op1, &bitD1); + HUF_DECODE_SYMBOLX2_2(op2, &bitD2); + HUF_DECODE_SYMBOLX2_2(op3, &bitD3); + HUF_DECODE_SYMBOLX2_2(op4, &bitD4); + HUF_DECODE_SYMBOLX2_0(op1, &bitD1); + HUF_DECODE_SYMBOLX2_0(op2, &bitD2); + HUF_DECODE_SYMBOLX2_0(op3, &bitD3); + HUF_DECODE_SYMBOLX2_0(op4, &bitD4); + endSignal = (U32)LIKELY((U32) + (BIT_reloadDStreamFast(&bitD1) == BIT_DStream_unfinished) + & (BIT_reloadDStreamFast(&bitD2) == BIT_DStream_unfinished) + & (BIT_reloadDStreamFast(&bitD3) == BIT_DStream_unfinished) + & (BIT_reloadDStreamFast(&bitD4) == BIT_DStream_unfinished)); +#endif + } + } + + /* check corruption */ + if (op1 > opStart2) return ERROR(corruption_detected); + if (op2 > opStart3) return ERROR(corruption_detected); + if (op3 > opStart4) return ERROR(corruption_detected); + /* note : op4 already verified within main loop */ + + /* finish bitStreams one by one */ + HUF_decodeStreamX2(op1, &bitD1, opStart2, dt, dtLog); + HUF_decodeStreamX2(op2, &bitD2, opStart3, dt, dtLog); + HUF_decodeStreamX2(op3, &bitD3, opStart4, dt, dtLog); + HUF_decodeStreamX2(op4, &bitD4, oend, dt, dtLog); + + /* check */ + { U32 const endCheck = BIT_endOfDStream(&bitD1) & BIT_endOfDStream(&bitD2) & BIT_endOfDStream(&bitD3) & BIT_endOfDStream(&bitD4); + if (!endCheck) return ERROR(corruption_detected); } + + /* decoded size */ + return dstSize; + } +} + +#if HUF_NEED_BMI2_FUNCTION +static BMI2_TARGET_ATTRIBUTE +size_t HUF_decompress4X2_usingDTable_internal_bmi2(void* dst, size_t dstSize, void const* cSrc, + size_t cSrcSize, HUF_DTable const* DTable) { + return HUF_decompress4X2_usingDTable_internal_body(dst, dstSize, cSrc, cSrcSize, DTable); +} +#endif + +#if HUF_NEED_DEFAULT_FUNCTION +static +size_t HUF_decompress4X2_usingDTable_internal_default(void* dst, size_t dstSize, void const* cSrc, + size_t cSrcSize, HUF_DTable const* DTable) { + return HUF_decompress4X2_usingDTable_internal_body(dst, dstSize, cSrc, cSrcSize, DTable); +} +#endif + +#if ZSTD_ENABLE_ASM_X86_64_BMI2 + +HUF_ASM_DECL void HUF_decompress4X2_usingDTable_internal_bmi2_asm_loop(HUF_DecompressAsmArgs* args) ZSTDLIB_HIDDEN; + +static HUF_ASM_X86_64_BMI2_ATTRS size_t +HUF_decompress4X2_usingDTable_internal_bmi2_asm( + void* dst, size_t dstSize, + const void* cSrc, size_t cSrcSize, + const HUF_DTable* DTable) { + void const* dt = DTable + 1; + const BYTE* const iend = (const BYTE*)cSrc + 6; + BYTE* const oend = (BYTE*)dst + dstSize; + HUF_DecompressAsmArgs args; + { + size_t const ret = HUF_DecompressAsmArgs_init(&args, dst, dstSize, cSrc, cSrcSize, DTable); + FORWARD_IF_ERROR(ret, "Failed to init asm args"); + if (ret != 0) + return HUF_decompress4X2_usingDTable_internal_bmi2(dst, dstSize, cSrc, cSrcSize, DTable); + } + + assert(args.ip[0] >= args.ilimit); + HUF_decompress4X2_usingDTable_internal_bmi2_asm_loop(&args); + + /* note : op4 already verified within main loop */ + assert(args.ip[0] >= iend); + assert(args.ip[1] >= iend); + assert(args.ip[2] >= iend); + assert(args.ip[3] >= iend); + assert(args.op[3] <= oend); + (void)iend; + + /* finish bitStreams one by one */ + { + size_t const segmentSize = (dstSize+3) / 4; + BYTE* segmentEnd = (BYTE*)dst; + int i; + for (i = 0; i < 4; ++i) { + BIT_DStream_t bit; + if (segmentSize <= (size_t)(oend - segmentEnd)) + segmentEnd += segmentSize; + else + segmentEnd = oend; + FORWARD_IF_ERROR(HUF_initRemainingDStream(&bit, &args, i, segmentEnd), "corruption"); + args.op[i] += HUF_decodeStreamX2(args.op[i], &bit, segmentEnd, (HUF_DEltX2 const*)dt, HUF_DECODER_FAST_TABLELOG); + if (args.op[i] != segmentEnd) + return ERROR(corruption_detected); + } + } + + /* decoded size */ + return dstSize; +} +#endif /* ZSTD_ENABLE_ASM_X86_64_BMI2 */ + +static size_t HUF_decompress4X2_usingDTable_internal(void* dst, size_t dstSize, void const* cSrc, + size_t cSrcSize, HUF_DTable const* DTable, int bmi2) +{ +#if DYNAMIC_BMI2 + if (bmi2) { +# if ZSTD_ENABLE_ASM_X86_64_BMI2 + return HUF_decompress4X2_usingDTable_internal_bmi2_asm(dst, dstSize, cSrc, cSrcSize, DTable); +# else + return HUF_decompress4X2_usingDTable_internal_bmi2(dst, dstSize, cSrc, cSrcSize, DTable); +# endif + } +#else + (void)bmi2; +#endif + +#if ZSTD_ENABLE_ASM_X86_64_BMI2 && defined(__BMI2__) + return HUF_decompress4X2_usingDTable_internal_bmi2_asm(dst, dstSize, cSrc, cSrcSize, DTable); +#else + return HUF_decompress4X2_usingDTable_internal_default(dst, dstSize, cSrc, cSrcSize, DTable); +#endif +} + +HUF_DGEN(HUF_decompress1X2_usingDTable_internal) + +size_t HUF_decompress1X2_usingDTable( + void* dst, size_t dstSize, + const void* cSrc, size_t cSrcSize, + const HUF_DTable* DTable) +{ + DTableDesc dtd = HUF_getDTableDesc(DTable); + if (dtd.tableType != 1) return ERROR(GENERIC); + return HUF_decompress1X2_usingDTable_internal(dst, dstSize, cSrc, cSrcSize, DTable, /* bmi2 */ 0); +} + +size_t HUF_decompress1X2_DCtx_wksp(HUF_DTable* DCtx, void* dst, size_t dstSize, + const void* cSrc, size_t cSrcSize, + void* workSpace, size_t wkspSize) +{ + const BYTE* ip = (const BYTE*) cSrc; + + size_t const hSize = HUF_readDTableX2_wksp(DCtx, cSrc, cSrcSize, + workSpace, wkspSize); + if (HUF_isError(hSize)) return hSize; + if (hSize >= cSrcSize) return ERROR(srcSize_wrong); + ip += hSize; cSrcSize -= hSize; + + return HUF_decompress1X2_usingDTable_internal(dst, dstSize, ip, cSrcSize, DCtx, /* bmi2 */ 0); +} + + +size_t HUF_decompress4X2_usingDTable( + void* dst, size_t dstSize, + const void* cSrc, size_t cSrcSize, + const HUF_DTable* DTable) +{ + DTableDesc dtd = HUF_getDTableDesc(DTable); + if (dtd.tableType != 1) return ERROR(GENERIC); + return HUF_decompress4X2_usingDTable_internal(dst, dstSize, cSrc, cSrcSize, DTable, /* bmi2 */ 0); +} + +static size_t HUF_decompress4X2_DCtx_wksp_bmi2(HUF_DTable* dctx, void* dst, size_t dstSize, + const void* cSrc, size_t cSrcSize, + void* workSpace, size_t wkspSize, int bmi2) +{ + const BYTE* ip = (const BYTE*) cSrc; + + size_t hSize = HUF_readDTableX2_wksp(dctx, cSrc, cSrcSize, + workSpace, wkspSize); + if (HUF_isError(hSize)) return hSize; + if (hSize >= cSrcSize) return ERROR(srcSize_wrong); + ip += hSize; cSrcSize -= hSize; + + return HUF_decompress4X2_usingDTable_internal(dst, dstSize, ip, cSrcSize, dctx, bmi2); +} + +size_t HUF_decompress4X2_DCtx_wksp(HUF_DTable* dctx, void* dst, size_t dstSize, + const void* cSrc, size_t cSrcSize, + void* workSpace, size_t wkspSize) +{ + return HUF_decompress4X2_DCtx_wksp_bmi2(dctx, dst, dstSize, cSrc, cSrcSize, workSpace, wkspSize, /* bmi2 */ 0); +} + + +#endif /* HUF_FORCE_DECOMPRESS_X1 */ + + +/* ***********************************/ +/* Universal decompression selectors */ +/* ***********************************/ + +size_t HUF_decompress1X_usingDTable(void* dst, size_t maxDstSize, + const void* cSrc, size_t cSrcSize, + const HUF_DTable* DTable) +{ + DTableDesc const dtd = HUF_getDTableDesc(DTable); +#if defined(HUF_FORCE_DECOMPRESS_X1) + (void)dtd; + assert(dtd.tableType == 0); + return HUF_decompress1X1_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, /* bmi2 */ 0); +#elif defined(HUF_FORCE_DECOMPRESS_X2) + (void)dtd; + assert(dtd.tableType == 1); + return HUF_decompress1X2_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, /* bmi2 */ 0); +#else + return dtd.tableType ? HUF_decompress1X2_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, /* bmi2 */ 0) : + HUF_decompress1X1_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, /* bmi2 */ 0); +#endif +} + +size_t HUF_decompress4X_usingDTable(void* dst, size_t maxDstSize, + const void* cSrc, size_t cSrcSize, + const HUF_DTable* DTable) +{ + DTableDesc const dtd = HUF_getDTableDesc(DTable); +#if defined(HUF_FORCE_DECOMPRESS_X1) + (void)dtd; + assert(dtd.tableType == 0); + return HUF_decompress4X1_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, /* bmi2 */ 0); +#elif defined(HUF_FORCE_DECOMPRESS_X2) + (void)dtd; + assert(dtd.tableType == 1); + return HUF_decompress4X2_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, /* bmi2 */ 0); +#else + return dtd.tableType ? HUF_decompress4X2_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, /* bmi2 */ 0) : + HUF_decompress4X1_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, /* bmi2 */ 0); +#endif +} + + +#if !defined(HUF_FORCE_DECOMPRESS_X1) && !defined(HUF_FORCE_DECOMPRESS_X2) +typedef struct { U32 tableTime; U32 decode256Time; } algo_time_t; +static const algo_time_t algoTime[16 /* Quantization */][2 /* single, double */] = +{ + /* single, double, quad */ + {{0,0}, {1,1}}, /* Q==0 : impossible */ + {{0,0}, {1,1}}, /* Q==1 : impossible */ + {{ 150,216}, { 381,119}}, /* Q == 2 : 12-18% */ + {{ 170,205}, { 514,112}}, /* Q == 3 : 18-25% */ + {{ 177,199}, { 539,110}}, /* Q == 4 : 25-32% */ + {{ 197,194}, { 644,107}}, /* Q == 5 : 32-38% */ + {{ 221,192}, { 735,107}}, /* Q == 6 : 38-44% */ + {{ 256,189}, { 881,106}}, /* Q == 7 : 44-50% */ + {{ 359,188}, {1167,109}}, /* Q == 8 : 50-56% */ + {{ 582,187}, {1570,114}}, /* Q == 9 : 56-62% */ + {{ 688,187}, {1712,122}}, /* Q ==10 : 62-69% */ + {{ 825,186}, {1965,136}}, /* Q ==11 : 69-75% */ + {{ 976,185}, {2131,150}}, /* Q ==12 : 75-81% */ + {{1180,186}, {2070,175}}, /* Q ==13 : 81-87% */ + {{1377,185}, {1731,202}}, /* Q ==14 : 87-93% */ + {{1412,185}, {1695,202}}, /* Q ==15 : 93-99% */ +}; +#endif + +/** HUF_selectDecoder() : + * Tells which decoder is likely to decode faster, + * based on a set of pre-computed metrics. + * @return : 0==HUF_decompress4X1, 1==HUF_decompress4X2 . + * Assumption : 0 < dstSize <= 128 KB */ +U32 HUF_selectDecoder (size_t dstSize, size_t cSrcSize) +{ + assert(dstSize > 0); + assert(dstSize <= 128*1024); +#if defined(HUF_FORCE_DECOMPRESS_X1) + (void)dstSize; + (void)cSrcSize; + return 0; +#elif defined(HUF_FORCE_DECOMPRESS_X2) + (void)dstSize; + (void)cSrcSize; + return 1; +#else + /* decoder timing evaluation */ + { U32 const Q = (cSrcSize >= dstSize) ? 15 : (U32)(cSrcSize * 16 / dstSize); /* Q < 16 */ + U32 const D256 = (U32)(dstSize >> 8); + U32 const DTime0 = algoTime[Q][0].tableTime + (algoTime[Q][0].decode256Time * D256); + U32 DTime1 = algoTime[Q][1].tableTime + (algoTime[Q][1].decode256Time * D256); + DTime1 += DTime1 >> 5; /* small advantage to algorithm using less memory, to reduce cache eviction */ + return DTime1 < DTime0; + } +#endif +} + + +size_t HUF_decompress4X_hufOnly_wksp(HUF_DTable* dctx, void* dst, + size_t dstSize, const void* cSrc, + size_t cSrcSize, void* workSpace, + size_t wkspSize) +{ + /* validation checks */ + if (dstSize == 0) return ERROR(dstSize_tooSmall); + if (cSrcSize == 0) return ERROR(corruption_detected); + + { U32 const algoNb = HUF_selectDecoder(dstSize, cSrcSize); +#if defined(HUF_FORCE_DECOMPRESS_X1) + (void)algoNb; + assert(algoNb == 0); + return HUF_decompress4X1_DCtx_wksp(dctx, dst, dstSize, cSrc, cSrcSize, workSpace, wkspSize); +#elif defined(HUF_FORCE_DECOMPRESS_X2) + (void)algoNb; + assert(algoNb == 1); + return HUF_decompress4X2_DCtx_wksp(dctx, dst, dstSize, cSrc, cSrcSize, workSpace, wkspSize); +#else + return algoNb ? HUF_decompress4X2_DCtx_wksp(dctx, dst, dstSize, cSrc, + cSrcSize, workSpace, wkspSize): + HUF_decompress4X1_DCtx_wksp(dctx, dst, dstSize, cSrc, cSrcSize, workSpace, wkspSize); +#endif + } +} + +size_t HUF_decompress1X_DCtx_wksp(HUF_DTable* dctx, void* dst, size_t dstSize, + const void* cSrc, size_t cSrcSize, + void* workSpace, size_t wkspSize) +{ + /* validation checks */ + if (dstSize == 0) return ERROR(dstSize_tooSmall); + if (cSrcSize > dstSize) return ERROR(corruption_detected); /* invalid */ + if (cSrcSize == dstSize) { ZSTD_memcpy(dst, cSrc, dstSize); return dstSize; } /* not compressed */ + if (cSrcSize == 1) { ZSTD_memset(dst, *(const BYTE*)cSrc, dstSize); return dstSize; } /* RLE */ + + { U32 const algoNb = HUF_selectDecoder(dstSize, cSrcSize); +#if defined(HUF_FORCE_DECOMPRESS_X1) + (void)algoNb; + assert(algoNb == 0); + return HUF_decompress1X1_DCtx_wksp(dctx, dst, dstSize, cSrc, + cSrcSize, workSpace, wkspSize); +#elif defined(HUF_FORCE_DECOMPRESS_X2) + (void)algoNb; + assert(algoNb == 1); + return HUF_decompress1X2_DCtx_wksp(dctx, dst, dstSize, cSrc, + cSrcSize, workSpace, wkspSize); +#else + return algoNb ? HUF_decompress1X2_DCtx_wksp(dctx, dst, dstSize, cSrc, + cSrcSize, workSpace, wkspSize): + HUF_decompress1X1_DCtx_wksp(dctx, dst, dstSize, cSrc, + cSrcSize, workSpace, wkspSize); +#endif + } +} + + +size_t HUF_decompress1X_usingDTable_bmi2(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const HUF_DTable* DTable, int bmi2) +{ + DTableDesc const dtd = HUF_getDTableDesc(DTable); +#if defined(HUF_FORCE_DECOMPRESS_X1) + (void)dtd; + assert(dtd.tableType == 0); + return HUF_decompress1X1_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, bmi2); +#elif defined(HUF_FORCE_DECOMPRESS_X2) + (void)dtd; + assert(dtd.tableType == 1); + return HUF_decompress1X2_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, bmi2); +#else + return dtd.tableType ? HUF_decompress1X2_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, bmi2) : + HUF_decompress1X1_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, bmi2); +#endif +} + +#ifndef HUF_FORCE_DECOMPRESS_X2 +size_t HUF_decompress1X1_DCtx_wksp_bmi2(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize, void* workSpace, size_t wkspSize, int bmi2) +{ + const BYTE* ip = (const BYTE*) cSrc; + + size_t const hSize = HUF_readDTableX1_wksp_bmi2(dctx, cSrc, cSrcSize, workSpace, wkspSize, bmi2); + if (HUF_isError(hSize)) return hSize; + if (hSize >= cSrcSize) return ERROR(srcSize_wrong); + ip += hSize; cSrcSize -= hSize; + + return HUF_decompress1X1_usingDTable_internal(dst, dstSize, ip, cSrcSize, dctx, bmi2); +} +#endif + +size_t HUF_decompress4X_usingDTable_bmi2(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const HUF_DTable* DTable, int bmi2) +{ + DTableDesc const dtd = HUF_getDTableDesc(DTable); +#if defined(HUF_FORCE_DECOMPRESS_X1) + (void)dtd; + assert(dtd.tableType == 0); + return HUF_decompress4X1_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, bmi2); +#elif defined(HUF_FORCE_DECOMPRESS_X2) + (void)dtd; + assert(dtd.tableType == 1); + return HUF_decompress4X2_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, bmi2); +#else + return dtd.tableType ? HUF_decompress4X2_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, bmi2) : + HUF_decompress4X1_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, bmi2); +#endif +} + +size_t HUF_decompress4X_hufOnly_wksp_bmi2(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize, void* workSpace, size_t wkspSize, int bmi2) +{ + /* validation checks */ + if (dstSize == 0) return ERROR(dstSize_tooSmall); + if (cSrcSize == 0) return ERROR(corruption_detected); + + { U32 const algoNb = HUF_selectDecoder(dstSize, cSrcSize); +#if defined(HUF_FORCE_DECOMPRESS_X1) + (void)algoNb; + assert(algoNb == 0); + return HUF_decompress4X1_DCtx_wksp_bmi2(dctx, dst, dstSize, cSrc, cSrcSize, workSpace, wkspSize, bmi2); +#elif defined(HUF_FORCE_DECOMPRESS_X2) + (void)algoNb; + assert(algoNb == 1); + return HUF_decompress4X2_DCtx_wksp_bmi2(dctx, dst, dstSize, cSrc, cSrcSize, workSpace, wkspSize, bmi2); +#else + return algoNb ? HUF_decompress4X2_DCtx_wksp_bmi2(dctx, dst, dstSize, cSrc, cSrcSize, workSpace, wkspSize, bmi2) : + HUF_decompress4X1_DCtx_wksp_bmi2(dctx, dst, dstSize, cSrc, cSrcSize, workSpace, wkspSize, bmi2); +#endif + } +} + +#ifndef ZSTD_NO_UNUSED_FUNCTIONS +#ifndef HUF_FORCE_DECOMPRESS_X2 +size_t HUF_readDTableX1(HUF_DTable* DTable, const void* src, size_t srcSize) +{ + U32 workSpace[HUF_DECOMPRESS_WORKSPACE_SIZE_U32]; + return HUF_readDTableX1_wksp(DTable, src, srcSize, + workSpace, sizeof(workSpace)); +} + +size_t HUF_decompress1X1_DCtx(HUF_DTable* DCtx, void* dst, size_t dstSize, + const void* cSrc, size_t cSrcSize) +{ + U32 workSpace[HUF_DECOMPRESS_WORKSPACE_SIZE_U32]; + return HUF_decompress1X1_DCtx_wksp(DCtx, dst, dstSize, cSrc, cSrcSize, + workSpace, sizeof(workSpace)); +} + +size_t HUF_decompress1X1 (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize) +{ + HUF_CREATE_STATIC_DTABLEX1(DTable, HUF_TABLELOG_MAX); + return HUF_decompress1X1_DCtx (DTable, dst, dstSize, cSrc, cSrcSize); +} +#endif + +#ifndef HUF_FORCE_DECOMPRESS_X1 +size_t HUF_readDTableX2(HUF_DTable* DTable, const void* src, size_t srcSize) +{ + U32 workSpace[HUF_DECOMPRESS_WORKSPACE_SIZE_U32]; + return HUF_readDTableX2_wksp(DTable, src, srcSize, + workSpace, sizeof(workSpace)); +} + +size_t HUF_decompress1X2_DCtx(HUF_DTable* DCtx, void* dst, size_t dstSize, + const void* cSrc, size_t cSrcSize) +{ + U32 workSpace[HUF_DECOMPRESS_WORKSPACE_SIZE_U32]; + return HUF_decompress1X2_DCtx_wksp(DCtx, dst, dstSize, cSrc, cSrcSize, + workSpace, sizeof(workSpace)); +} + +size_t HUF_decompress1X2 (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize) +{ + HUF_CREATE_STATIC_DTABLEX2(DTable, HUF_TABLELOG_MAX); + return HUF_decompress1X2_DCtx(DTable, dst, dstSize, cSrc, cSrcSize); +} +#endif + +#ifndef HUF_FORCE_DECOMPRESS_X2 +size_t HUF_decompress4X1_DCtx (HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize) +{ + U32 workSpace[HUF_DECOMPRESS_WORKSPACE_SIZE_U32]; + return HUF_decompress4X1_DCtx_wksp(dctx, dst, dstSize, cSrc, cSrcSize, + workSpace, sizeof(workSpace)); +} +size_t HUF_decompress4X1 (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize) +{ + HUF_CREATE_STATIC_DTABLEX1(DTable, HUF_TABLELOG_MAX); + return HUF_decompress4X1_DCtx(DTable, dst, dstSize, cSrc, cSrcSize); +} +#endif + +#ifndef HUF_FORCE_DECOMPRESS_X1 +size_t HUF_decompress4X2_DCtx(HUF_DTable* dctx, void* dst, size_t dstSize, + const void* cSrc, size_t cSrcSize) +{ + U32 workSpace[HUF_DECOMPRESS_WORKSPACE_SIZE_U32]; + return HUF_decompress4X2_DCtx_wksp(dctx, dst, dstSize, cSrc, cSrcSize, + workSpace, sizeof(workSpace)); +} + +size_t HUF_decompress4X2 (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize) +{ + HUF_CREATE_STATIC_DTABLEX2(DTable, HUF_TABLELOG_MAX); + return HUF_decompress4X2_DCtx(DTable, dst, dstSize, cSrc, cSrcSize); +} +#endif + +typedef size_t (*decompressionAlgo)(void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); + +size_t HUF_decompress (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize) +{ +#if !defined(HUF_FORCE_DECOMPRESS_X1) && !defined(HUF_FORCE_DECOMPRESS_X2) + static const decompressionAlgo decompress[2] = { HUF_decompress4X1, HUF_decompress4X2 }; +#endif + + /* validation checks */ + if (dstSize == 0) return ERROR(dstSize_tooSmall); + if (cSrcSize > dstSize) return ERROR(corruption_detected); /* invalid */ + if (cSrcSize == dstSize) { ZSTD_memcpy(dst, cSrc, dstSize); return dstSize; } /* not compressed */ + if (cSrcSize == 1) { ZSTD_memset(dst, *(const BYTE*)cSrc, dstSize); return dstSize; } /* RLE */ + + { U32 const algoNb = HUF_selectDecoder(dstSize, cSrcSize); +#if defined(HUF_FORCE_DECOMPRESS_X1) + (void)algoNb; + assert(algoNb == 0); + return HUF_decompress4X1(dst, dstSize, cSrc, cSrcSize); +#elif defined(HUF_FORCE_DECOMPRESS_X2) + (void)algoNb; + assert(algoNb == 1); + return HUF_decompress4X2(dst, dstSize, cSrc, cSrcSize); +#else + return decompress[algoNb](dst, dstSize, cSrc, cSrcSize); +#endif + } +} + +size_t HUF_decompress4X_DCtx (HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize) +{ + /* validation checks */ + if (dstSize == 0) return ERROR(dstSize_tooSmall); + if (cSrcSize > dstSize) return ERROR(corruption_detected); /* invalid */ + if (cSrcSize == dstSize) { ZSTD_memcpy(dst, cSrc, dstSize); return dstSize; } /* not compressed */ + if (cSrcSize == 1) { ZSTD_memset(dst, *(const BYTE*)cSrc, dstSize); return dstSize; } /* RLE */ + + { U32 const algoNb = HUF_selectDecoder(dstSize, cSrcSize); +#if defined(HUF_FORCE_DECOMPRESS_X1) + (void)algoNb; + assert(algoNb == 0); + return HUF_decompress4X1_DCtx(dctx, dst, dstSize, cSrc, cSrcSize); +#elif defined(HUF_FORCE_DECOMPRESS_X2) + (void)algoNb; + assert(algoNb == 1); + return HUF_decompress4X2_DCtx(dctx, dst, dstSize, cSrc, cSrcSize); +#else + return algoNb ? HUF_decompress4X2_DCtx(dctx, dst, dstSize, cSrc, cSrcSize) : + HUF_decompress4X1_DCtx(dctx, dst, dstSize, cSrc, cSrcSize) ; +#endif + } +} + +size_t HUF_decompress4X_hufOnly(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize) +{ + U32 workSpace[HUF_DECOMPRESS_WORKSPACE_SIZE_U32]; + return HUF_decompress4X_hufOnly_wksp(dctx, dst, dstSize, cSrc, cSrcSize, + workSpace, sizeof(workSpace)); +} + +size_t HUF_decompress1X_DCtx(HUF_DTable* dctx, void* dst, size_t dstSize, + const void* cSrc, size_t cSrcSize) +{ + U32 workSpace[HUF_DECOMPRESS_WORKSPACE_SIZE_U32]; + return HUF_decompress1X_DCtx_wksp(dctx, dst, dstSize, cSrc, cSrcSize, + workSpace, sizeof(workSpace)); +} +#endif diff --git a/stage1/zstd/lib/decompress/zstd_ddict.c b/stage1/zstd/lib/decompress/zstd_ddict.c new file mode 100644 index 000000000000..ce335477b32d --- /dev/null +++ b/stage1/zstd/lib/decompress/zstd_ddict.c @@ -0,0 +1,244 @@ +/* + * Copyright (c) Yann Collet, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under both the BSD-style license (found in the + * LICENSE file in the root directory of this source tree) and the GPLv2 (found + * in the COPYING file in the root directory of this source tree). + * You may select, at your option, one of the above-listed licenses. + */ + +/* zstd_ddict.c : + * concentrates all logic that needs to know the internals of ZSTD_DDict object */ + +/*-******************************************************* +* Dependencies +*********************************************************/ +#include "../common/zstd_deps.h" /* ZSTD_memcpy, ZSTD_memmove, ZSTD_memset */ +#include "../common/cpu.h" /* bmi2 */ +#include "../common/mem.h" /* low level memory routines */ +#define FSE_STATIC_LINKING_ONLY +#include "../common/fse.h" +#define HUF_STATIC_LINKING_ONLY +#include "../common/huf.h" +#include "zstd_decompress_internal.h" +#include "zstd_ddict.h" + +#if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT>=1) +# include "../legacy/zstd_legacy.h" +#endif + + + +/*-******************************************************* +* Types +*********************************************************/ +struct ZSTD_DDict_s { + void* dictBuffer; + const void* dictContent; + size_t dictSize; + ZSTD_entropyDTables_t entropy; + U32 dictID; + U32 entropyPresent; + ZSTD_customMem cMem; +}; /* typedef'd to ZSTD_DDict within "zstd.h" */ + +const void* ZSTD_DDict_dictContent(const ZSTD_DDict* ddict) +{ + assert(ddict != NULL); + return ddict->dictContent; +} + +size_t ZSTD_DDict_dictSize(const ZSTD_DDict* ddict) +{ + assert(ddict != NULL); + return ddict->dictSize; +} + +void ZSTD_copyDDictParameters(ZSTD_DCtx* dctx, const ZSTD_DDict* ddict) +{ + DEBUGLOG(4, "ZSTD_copyDDictParameters"); + assert(dctx != NULL); + assert(ddict != NULL); + dctx->dictID = ddict->dictID; + dctx->prefixStart = ddict->dictContent; + dctx->virtualStart = ddict->dictContent; + dctx->dictEnd = (const BYTE*)ddict->dictContent + ddict->dictSize; + dctx->previousDstEnd = dctx->dictEnd; +#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION + dctx->dictContentBeginForFuzzing = dctx->prefixStart; + dctx->dictContentEndForFuzzing = dctx->previousDstEnd; +#endif + if (ddict->entropyPresent) { + dctx->litEntropy = 1; + dctx->fseEntropy = 1; + dctx->LLTptr = ddict->entropy.LLTable; + dctx->MLTptr = ddict->entropy.MLTable; + dctx->OFTptr = ddict->entropy.OFTable; + dctx->HUFptr = ddict->entropy.hufTable; + dctx->entropy.rep[0] = ddict->entropy.rep[0]; + dctx->entropy.rep[1] = ddict->entropy.rep[1]; + dctx->entropy.rep[2] = ddict->entropy.rep[2]; + } else { + dctx->litEntropy = 0; + dctx->fseEntropy = 0; + } +} + + +static size_t +ZSTD_loadEntropy_intoDDict(ZSTD_DDict* ddict, + ZSTD_dictContentType_e dictContentType) +{ + ddict->dictID = 0; + ddict->entropyPresent = 0; + if (dictContentType == ZSTD_dct_rawContent) return 0; + + if (ddict->dictSize < 8) { + if (dictContentType == ZSTD_dct_fullDict) + return ERROR(dictionary_corrupted); /* only accept specified dictionaries */ + return 0; /* pure content mode */ + } + { U32 const magic = MEM_readLE32(ddict->dictContent); + if (magic != ZSTD_MAGIC_DICTIONARY) { + if (dictContentType == ZSTD_dct_fullDict) + return ERROR(dictionary_corrupted); /* only accept specified dictionaries */ + return 0; /* pure content mode */ + } + } + ddict->dictID = MEM_readLE32((const char*)ddict->dictContent + ZSTD_FRAMEIDSIZE); + + /* load entropy tables */ + RETURN_ERROR_IF(ZSTD_isError(ZSTD_loadDEntropy( + &ddict->entropy, ddict->dictContent, ddict->dictSize)), + dictionary_corrupted, ""); + ddict->entropyPresent = 1; + return 0; +} + + +static size_t ZSTD_initDDict_internal(ZSTD_DDict* ddict, + const void* dict, size_t dictSize, + ZSTD_dictLoadMethod_e dictLoadMethod, + ZSTD_dictContentType_e dictContentType) +{ + if ((dictLoadMethod == ZSTD_dlm_byRef) || (!dict) || (!dictSize)) { + ddict->dictBuffer = NULL; + ddict->dictContent = dict; + if (!dict) dictSize = 0; + } else { + void* const internalBuffer = ZSTD_customMalloc(dictSize, ddict->cMem); + ddict->dictBuffer = internalBuffer; + ddict->dictContent = internalBuffer; + if (!internalBuffer) return ERROR(memory_allocation); + ZSTD_memcpy(internalBuffer, dict, dictSize); + } + ddict->dictSize = dictSize; + ddict->entropy.hufTable[0] = (HUF_DTable)((HufLog)*0x1000001); /* cover both little and big endian */ + + /* parse dictionary content */ + FORWARD_IF_ERROR( ZSTD_loadEntropy_intoDDict(ddict, dictContentType) , ""); + + return 0; +} + +ZSTD_DDict* ZSTD_createDDict_advanced(const void* dict, size_t dictSize, + ZSTD_dictLoadMethod_e dictLoadMethod, + ZSTD_dictContentType_e dictContentType, + ZSTD_customMem customMem) +{ + if ((!customMem.customAlloc) ^ (!customMem.customFree)) return NULL; + + { ZSTD_DDict* const ddict = (ZSTD_DDict*) ZSTD_customMalloc(sizeof(ZSTD_DDict), customMem); + if (ddict == NULL) return NULL; + ddict->cMem = customMem; + { size_t const initResult = ZSTD_initDDict_internal(ddict, + dict, dictSize, + dictLoadMethod, dictContentType); + if (ZSTD_isError(initResult)) { + ZSTD_freeDDict(ddict); + return NULL; + } } + return ddict; + } +} + +/*! ZSTD_createDDict() : +* Create a digested dictionary, to start decompression without startup delay. +* `dict` content is copied inside DDict. +* Consequently, `dict` can be released after `ZSTD_DDict` creation */ +ZSTD_DDict* ZSTD_createDDict(const void* dict, size_t dictSize) +{ + ZSTD_customMem const allocator = { NULL, NULL, NULL }; + return ZSTD_createDDict_advanced(dict, dictSize, ZSTD_dlm_byCopy, ZSTD_dct_auto, allocator); +} + +/*! ZSTD_createDDict_byReference() : + * Create a digested dictionary, to start decompression without startup delay. + * Dictionary content is simply referenced, it will be accessed during decompression. + * Warning : dictBuffer must outlive DDict (DDict must be freed before dictBuffer) */ +ZSTD_DDict* ZSTD_createDDict_byReference(const void* dictBuffer, size_t dictSize) +{ + ZSTD_customMem const allocator = { NULL, NULL, NULL }; + return ZSTD_createDDict_advanced(dictBuffer, dictSize, ZSTD_dlm_byRef, ZSTD_dct_auto, allocator); +} + + +const ZSTD_DDict* ZSTD_initStaticDDict( + void* sBuffer, size_t sBufferSize, + const void* dict, size_t dictSize, + ZSTD_dictLoadMethod_e dictLoadMethod, + ZSTD_dictContentType_e dictContentType) +{ + size_t const neededSpace = sizeof(ZSTD_DDict) + + (dictLoadMethod == ZSTD_dlm_byRef ? 0 : dictSize); + ZSTD_DDict* const ddict = (ZSTD_DDict*)sBuffer; + assert(sBuffer != NULL); + assert(dict != NULL); + if ((size_t)sBuffer & 7) return NULL; /* 8-aligned */ + if (sBufferSize < neededSpace) return NULL; + if (dictLoadMethod == ZSTD_dlm_byCopy) { + ZSTD_memcpy(ddict+1, dict, dictSize); /* local copy */ + dict = ddict+1; + } + if (ZSTD_isError( ZSTD_initDDict_internal(ddict, + dict, dictSize, + ZSTD_dlm_byRef, dictContentType) )) + return NULL; + return ddict; +} + + +size_t ZSTD_freeDDict(ZSTD_DDict* ddict) +{ + if (ddict==NULL) return 0; /* support free on NULL */ + { ZSTD_customMem const cMem = ddict->cMem; + ZSTD_customFree(ddict->dictBuffer, cMem); + ZSTD_customFree(ddict, cMem); + return 0; + } +} + +/*! ZSTD_estimateDDictSize() : + * Estimate amount of memory that will be needed to create a dictionary for decompression. + * Note : dictionary created by reference using ZSTD_dlm_byRef are smaller */ +size_t ZSTD_estimateDDictSize(size_t dictSize, ZSTD_dictLoadMethod_e dictLoadMethod) +{ + return sizeof(ZSTD_DDict) + (dictLoadMethod == ZSTD_dlm_byRef ? 0 : dictSize); +} + +size_t ZSTD_sizeof_DDict(const ZSTD_DDict* ddict) +{ + if (ddict==NULL) return 0; /* support sizeof on NULL */ + return sizeof(*ddict) + (ddict->dictBuffer ? ddict->dictSize : 0) ; +} + +/*! ZSTD_getDictID_fromDDict() : + * Provides the dictID of the dictionary loaded into `ddict`. + * If @return == 0, the dictionary is not conformant to Zstandard specification, or empty. + * Non-conformant dictionaries can still be loaded, but as content-only dictionaries. */ +unsigned ZSTD_getDictID_fromDDict(const ZSTD_DDict* ddict) +{ + if (ddict==NULL) return 0; + return ZSTD_getDictID_fromDict(ddict->dictContent, ddict->dictSize); +} diff --git a/stage1/zstd/lib/decompress/zstd_ddict.h b/stage1/zstd/lib/decompress/zstd_ddict.h new file mode 100644 index 000000000000..bd03268b5087 --- /dev/null +++ b/stage1/zstd/lib/decompress/zstd_ddict.h @@ -0,0 +1,44 @@ +/* + * Copyright (c) Yann Collet, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under both the BSD-style license (found in the + * LICENSE file in the root directory of this source tree) and the GPLv2 (found + * in the COPYING file in the root directory of this source tree). + * You may select, at your option, one of the above-listed licenses. + */ + + +#ifndef ZSTD_DDICT_H +#define ZSTD_DDICT_H + +/*-******************************************************* + * Dependencies + *********************************************************/ +#include "../common/zstd_deps.h" /* size_t */ +#include "../zstd.h" /* ZSTD_DDict, and several public functions */ + + +/*-******************************************************* + * Interface + *********************************************************/ + +/* note: several prototypes are already published in `zstd.h` : + * ZSTD_createDDict() + * ZSTD_createDDict_byReference() + * ZSTD_createDDict_advanced() + * ZSTD_freeDDict() + * ZSTD_initStaticDDict() + * ZSTD_sizeof_DDict() + * ZSTD_estimateDDictSize() + * ZSTD_getDictID_fromDict() + */ + +const void* ZSTD_DDict_dictContent(const ZSTD_DDict* ddict); +size_t ZSTD_DDict_dictSize(const ZSTD_DDict* ddict); + +void ZSTD_copyDDictParameters(ZSTD_DCtx* dctx, const ZSTD_DDict* ddict); + + + +#endif /* ZSTD_DDICT_H */ diff --git a/stage1/zstd/lib/decompress/zstd_decompress.c b/stage1/zstd/lib/decompress/zstd_decompress.c new file mode 100644 index 000000000000..0031e98cfb1a --- /dev/null +++ b/stage1/zstd/lib/decompress/zstd_decompress.c @@ -0,0 +1,2230 @@ +/* + * Copyright (c) Yann Collet, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under both the BSD-style license (found in the + * LICENSE file in the root directory of this source tree) and the GPLv2 (found + * in the COPYING file in the root directory of this source tree). + * You may select, at your option, one of the above-listed licenses. + */ + + +/* *************************************************************** +* Tuning parameters +*****************************************************************/ +/*! + * HEAPMODE : + * Select how default decompression function ZSTD_decompress() allocates its context, + * on stack (0), or into heap (1, default; requires malloc()). + * Note that functions with explicit context such as ZSTD_decompressDCtx() are unaffected. + */ +#ifndef ZSTD_HEAPMODE +# define ZSTD_HEAPMODE 1 +#endif + +/*! +* LEGACY_SUPPORT : +* if set to 1+, ZSTD_decompress() can decode older formats (v0.1+) +*/ +#ifndef ZSTD_LEGACY_SUPPORT +# define ZSTD_LEGACY_SUPPORT 0 +#endif + +/*! + * MAXWINDOWSIZE_DEFAULT : + * maximum window size accepted by DStream __by default__. + * Frames requiring more memory will be rejected. + * It's possible to set a different limit using ZSTD_DCtx_setMaxWindowSize(). + */ +#ifndef ZSTD_MAXWINDOWSIZE_DEFAULT +# define ZSTD_MAXWINDOWSIZE_DEFAULT (((U32)1 << ZSTD_WINDOWLOG_LIMIT_DEFAULT) + 1) +#endif + +/*! + * NO_FORWARD_PROGRESS_MAX : + * maximum allowed nb of calls to ZSTD_decompressStream() + * without any forward progress + * (defined as: no byte read from input, and no byte flushed to output) + * before triggering an error. + */ +#ifndef ZSTD_NO_FORWARD_PROGRESS_MAX +# define ZSTD_NO_FORWARD_PROGRESS_MAX 16 +#endif + + +/*-******************************************************* +* Dependencies +*********************************************************/ +#include "../common/zstd_deps.h" /* ZSTD_memcpy, ZSTD_memmove, ZSTD_memset */ +#include "../common/mem.h" /* low level memory routines */ +#define FSE_STATIC_LINKING_ONLY +#include "../common/fse.h" +#define HUF_STATIC_LINKING_ONLY +#include "../common/huf.h" +#include "../common/xxhash.h" /* XXH64_reset, XXH64_update, XXH64_digest, XXH64 */ +#include "../common/zstd_internal.h" /* blockProperties_t */ +#include "zstd_decompress_internal.h" /* ZSTD_DCtx */ +#include "zstd_ddict.h" /* ZSTD_DDictDictContent */ +#include "zstd_decompress_block.h" /* ZSTD_decompressBlock_internal */ + +#if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT>=1) +# include "../legacy/zstd_legacy.h" +#endif + + + +/************************************* + * Multiple DDicts Hashset internals * + *************************************/ + +#define DDICT_HASHSET_MAX_LOAD_FACTOR_COUNT_MULT 4 +#define DDICT_HASHSET_MAX_LOAD_FACTOR_SIZE_MULT 3 /* These two constants represent SIZE_MULT/COUNT_MULT load factor without using a float. + * Currently, that means a 0.75 load factor. + * So, if count * COUNT_MULT / size * SIZE_MULT != 0, then we've exceeded + * the load factor of the ddict hash set. + */ + +#define DDICT_HASHSET_TABLE_BASE_SIZE 64 +#define DDICT_HASHSET_RESIZE_FACTOR 2 + +/* Hash function to determine starting position of dict insertion within the table + * Returns an index between [0, hashSet->ddictPtrTableSize] + */ +static size_t ZSTD_DDictHashSet_getIndex(const ZSTD_DDictHashSet* hashSet, U32 dictID) { + const U64 hash = XXH64(&dictID, sizeof(U32), 0); + /* DDict ptr table size is a multiple of 2, use size - 1 as mask to get index within [0, hashSet->ddictPtrTableSize) */ + return hash & (hashSet->ddictPtrTableSize - 1); +} + +/* Adds DDict to a hashset without resizing it. + * If inserting a DDict with a dictID that already exists in the set, replaces the one in the set. + * Returns 0 if successful, or a zstd error code if something went wrong. + */ +static size_t ZSTD_DDictHashSet_emplaceDDict(ZSTD_DDictHashSet* hashSet, const ZSTD_DDict* ddict) { + const U32 dictID = ZSTD_getDictID_fromDDict(ddict); + size_t idx = ZSTD_DDictHashSet_getIndex(hashSet, dictID); + const size_t idxRangeMask = hashSet->ddictPtrTableSize - 1; + RETURN_ERROR_IF(hashSet->ddictPtrCount == hashSet->ddictPtrTableSize, GENERIC, "Hash set is full!"); + DEBUGLOG(4, "Hashed index: for dictID: %u is %zu", dictID, idx); + while (hashSet->ddictPtrTable[idx] != NULL) { + /* Replace existing ddict if inserting ddict with same dictID */ + if (ZSTD_getDictID_fromDDict(hashSet->ddictPtrTable[idx]) == dictID) { + DEBUGLOG(4, "DictID already exists, replacing rather than adding"); + hashSet->ddictPtrTable[idx] = ddict; + return 0; + } + idx &= idxRangeMask; + idx++; + } + DEBUGLOG(4, "Final idx after probing for dictID %u is: %zu", dictID, idx); + hashSet->ddictPtrTable[idx] = ddict; + hashSet->ddictPtrCount++; + return 0; +} + +/* Expands hash table by factor of DDICT_HASHSET_RESIZE_FACTOR and + * rehashes all values, allocates new table, frees old table. + * Returns 0 on success, otherwise a zstd error code. + */ +static size_t ZSTD_DDictHashSet_expand(ZSTD_DDictHashSet* hashSet, ZSTD_customMem customMem) { + size_t newTableSize = hashSet->ddictPtrTableSize * DDICT_HASHSET_RESIZE_FACTOR; + const ZSTD_DDict** newTable = (const ZSTD_DDict**)ZSTD_customCalloc(sizeof(ZSTD_DDict*) * newTableSize, customMem); + const ZSTD_DDict** oldTable = hashSet->ddictPtrTable; + size_t oldTableSize = hashSet->ddictPtrTableSize; + size_t i; + + DEBUGLOG(4, "Expanding DDict hash table! Old size: %zu new size: %zu", oldTableSize, newTableSize); + RETURN_ERROR_IF(!newTable, memory_allocation, "Expanded hashset allocation failed!"); + hashSet->ddictPtrTable = newTable; + hashSet->ddictPtrTableSize = newTableSize; + hashSet->ddictPtrCount = 0; + for (i = 0; i < oldTableSize; ++i) { + if (oldTable[i] != NULL) { + FORWARD_IF_ERROR(ZSTD_DDictHashSet_emplaceDDict(hashSet, oldTable[i]), ""); + } + } + ZSTD_customFree((void*)oldTable, customMem); + DEBUGLOG(4, "Finished re-hash"); + return 0; +} + +/* Fetches a DDict with the given dictID + * Returns the ZSTD_DDict* with the requested dictID. If it doesn't exist, then returns NULL. + */ +static const ZSTD_DDict* ZSTD_DDictHashSet_getDDict(ZSTD_DDictHashSet* hashSet, U32 dictID) { + size_t idx = ZSTD_DDictHashSet_getIndex(hashSet, dictID); + const size_t idxRangeMask = hashSet->ddictPtrTableSize - 1; + DEBUGLOG(4, "Hashed index: for dictID: %u is %zu", dictID, idx); + for (;;) { + size_t currDictID = ZSTD_getDictID_fromDDict(hashSet->ddictPtrTable[idx]); + if (currDictID == dictID || currDictID == 0) { + /* currDictID == 0 implies a NULL ddict entry */ + break; + } else { + idx &= idxRangeMask; /* Goes to start of table when we reach the end */ + idx++; + } + } + DEBUGLOG(4, "Final idx after probing for dictID %u is: %zu", dictID, idx); + return hashSet->ddictPtrTable[idx]; +} + +/* Allocates space for and returns a ddict hash set + * The hash set's ZSTD_DDict* table has all values automatically set to NULL to begin with. + * Returns NULL if allocation failed. + */ +static ZSTD_DDictHashSet* ZSTD_createDDictHashSet(ZSTD_customMem customMem) { + ZSTD_DDictHashSet* ret = (ZSTD_DDictHashSet*)ZSTD_customMalloc(sizeof(ZSTD_DDictHashSet), customMem); + DEBUGLOG(4, "Allocating new hash set"); + if (!ret) + return NULL; + ret->ddictPtrTable = (const ZSTD_DDict**)ZSTD_customCalloc(DDICT_HASHSET_TABLE_BASE_SIZE * sizeof(ZSTD_DDict*), customMem); + if (!ret->ddictPtrTable) { + ZSTD_customFree(ret, customMem); + return NULL; + } + ret->ddictPtrTableSize = DDICT_HASHSET_TABLE_BASE_SIZE; + ret->ddictPtrCount = 0; + return ret; +} + +/* Frees the table of ZSTD_DDict* within a hashset, then frees the hashset itself. + * Note: The ZSTD_DDict* within the table are NOT freed. + */ +static void ZSTD_freeDDictHashSet(ZSTD_DDictHashSet* hashSet, ZSTD_customMem customMem) { + DEBUGLOG(4, "Freeing ddict hash set"); + if (hashSet && hashSet->ddictPtrTable) { + ZSTD_customFree((void*)hashSet->ddictPtrTable, customMem); + } + if (hashSet) { + ZSTD_customFree(hashSet, customMem); + } +} + +/* Public function: Adds a DDict into the ZSTD_DDictHashSet, possibly triggering a resize of the hash set. + * Returns 0 on success, or a ZSTD error. + */ +static size_t ZSTD_DDictHashSet_addDDict(ZSTD_DDictHashSet* hashSet, const ZSTD_DDict* ddict, ZSTD_customMem customMem) { + DEBUGLOG(4, "Adding dict ID: %u to hashset with - Count: %zu Tablesize: %zu", ZSTD_getDictID_fromDDict(ddict), hashSet->ddictPtrCount, hashSet->ddictPtrTableSize); + if (hashSet->ddictPtrCount * DDICT_HASHSET_MAX_LOAD_FACTOR_COUNT_MULT / hashSet->ddictPtrTableSize * DDICT_HASHSET_MAX_LOAD_FACTOR_SIZE_MULT != 0) { + FORWARD_IF_ERROR(ZSTD_DDictHashSet_expand(hashSet, customMem), ""); + } + FORWARD_IF_ERROR(ZSTD_DDictHashSet_emplaceDDict(hashSet, ddict), ""); + return 0; +} + +/*-************************************************************* +* Context management +***************************************************************/ +size_t ZSTD_sizeof_DCtx (const ZSTD_DCtx* dctx) +{ + if (dctx==NULL) return 0; /* support sizeof NULL */ + return sizeof(*dctx) + + ZSTD_sizeof_DDict(dctx->ddictLocal) + + dctx->inBuffSize + dctx->outBuffSize; +} + +size_t ZSTD_estimateDCtxSize(void) { return sizeof(ZSTD_DCtx); } + + +static size_t ZSTD_startingInputLength(ZSTD_format_e format) +{ + size_t const startingInputLength = ZSTD_FRAMEHEADERSIZE_PREFIX(format); + /* only supports formats ZSTD_f_zstd1 and ZSTD_f_zstd1_magicless */ + assert( (format == ZSTD_f_zstd1) || (format == ZSTD_f_zstd1_magicless) ); + return startingInputLength; +} + +static void ZSTD_DCtx_resetParameters(ZSTD_DCtx* dctx) +{ + assert(dctx->streamStage == zdss_init); + dctx->format = ZSTD_f_zstd1; + dctx->maxWindowSize = ZSTD_MAXWINDOWSIZE_DEFAULT; + dctx->outBufferMode = ZSTD_bm_buffered; + dctx->forceIgnoreChecksum = ZSTD_d_validateChecksum; + dctx->refMultipleDDicts = ZSTD_rmd_refSingleDDict; +} + +static void ZSTD_initDCtx_internal(ZSTD_DCtx* dctx) +{ + dctx->staticSize = 0; + dctx->ddict = NULL; + dctx->ddictLocal = NULL; + dctx->dictEnd = NULL; + dctx->ddictIsCold = 0; + dctx->dictUses = ZSTD_dont_use; + dctx->inBuff = NULL; + dctx->inBuffSize = 0; + dctx->outBuffSize = 0; + dctx->streamStage = zdss_init; +#if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT>=1) + dctx->legacyContext = NULL; + dctx->previousLegacyVersion = 0; +#endif + dctx->noForwardProgress = 0; + dctx->oversizedDuration = 0; +#if DYNAMIC_BMI2 + dctx->bmi2 = ZSTD_cpuSupportsBmi2(); +#endif + dctx->ddictSet = NULL; + ZSTD_DCtx_resetParameters(dctx); +#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION + dctx->dictContentEndForFuzzing = NULL; +#endif +} + +ZSTD_DCtx* ZSTD_initStaticDCtx(void *workspace, size_t workspaceSize) +{ + ZSTD_DCtx* const dctx = (ZSTD_DCtx*) workspace; + + if ((size_t)workspace & 7) return NULL; /* 8-aligned */ + if (workspaceSize < sizeof(ZSTD_DCtx)) return NULL; /* minimum size */ + + ZSTD_initDCtx_internal(dctx); + dctx->staticSize = workspaceSize; + dctx->inBuff = (char*)(dctx+1); + return dctx; +} + +static ZSTD_DCtx* ZSTD_createDCtx_internal(ZSTD_customMem customMem) { + if ((!customMem.customAlloc) ^ (!customMem.customFree)) return NULL; + + { ZSTD_DCtx* const dctx = (ZSTD_DCtx*)ZSTD_customMalloc(sizeof(*dctx), customMem); + if (!dctx) return NULL; + dctx->customMem = customMem; + ZSTD_initDCtx_internal(dctx); + return dctx; + } +} + +ZSTD_DCtx* ZSTD_createDCtx_advanced(ZSTD_customMem customMem) +{ + return ZSTD_createDCtx_internal(customMem); +} + +ZSTD_DCtx* ZSTD_createDCtx(void) +{ + DEBUGLOG(3, "ZSTD_createDCtx"); + return ZSTD_createDCtx_internal(ZSTD_defaultCMem); +} + +static void ZSTD_clearDict(ZSTD_DCtx* dctx) +{ + ZSTD_freeDDict(dctx->ddictLocal); + dctx->ddictLocal = NULL; + dctx->ddict = NULL; + dctx->dictUses = ZSTD_dont_use; +} + +size_t ZSTD_freeDCtx(ZSTD_DCtx* dctx) +{ + if (dctx==NULL) return 0; /* support free on NULL */ + RETURN_ERROR_IF(dctx->staticSize, memory_allocation, "not compatible with static DCtx"); + { ZSTD_customMem const cMem = dctx->customMem; + ZSTD_clearDict(dctx); + ZSTD_customFree(dctx->inBuff, cMem); + dctx->inBuff = NULL; +#if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT >= 1) + if (dctx->legacyContext) + ZSTD_freeLegacyStreamContext(dctx->legacyContext, dctx->previousLegacyVersion); +#endif + if (dctx->ddictSet) { + ZSTD_freeDDictHashSet(dctx->ddictSet, cMem); + dctx->ddictSet = NULL; + } + ZSTD_customFree(dctx, cMem); + return 0; + } +} + +/* no longer useful */ +void ZSTD_copyDCtx(ZSTD_DCtx* dstDCtx, const ZSTD_DCtx* srcDCtx) +{ + size_t const toCopy = (size_t)((char*)(&dstDCtx->inBuff) - (char*)dstDCtx); + ZSTD_memcpy(dstDCtx, srcDCtx, toCopy); /* no need to copy workspace */ +} + +/* Given a dctx with a digested frame params, re-selects the correct ZSTD_DDict based on + * the requested dict ID from the frame. If there exists a reference to the correct ZSTD_DDict, then + * accordingly sets the ddict to be used to decompress the frame. + * + * If no DDict is found, then no action is taken, and the ZSTD_DCtx::ddict remains as-is. + * + * ZSTD_d_refMultipleDDicts must be enabled for this function to be called. + */ +static void ZSTD_DCtx_selectFrameDDict(ZSTD_DCtx* dctx) { + assert(dctx->refMultipleDDicts && dctx->ddictSet); + DEBUGLOG(4, "Adjusting DDict based on requested dict ID from frame"); + if (dctx->ddict) { + const ZSTD_DDict* frameDDict = ZSTD_DDictHashSet_getDDict(dctx->ddictSet, dctx->fParams.dictID); + if (frameDDict) { + DEBUGLOG(4, "DDict found!"); + ZSTD_clearDict(dctx); + dctx->dictID = dctx->fParams.dictID; + dctx->ddict = frameDDict; + dctx->dictUses = ZSTD_use_indefinitely; + } + } +} + + +/*-************************************************************* + * Frame header decoding + ***************************************************************/ + +/*! ZSTD_isFrame() : + * Tells if the content of `buffer` starts with a valid Frame Identifier. + * Note : Frame Identifier is 4 bytes. If `size < 4`, @return will always be 0. + * Note 2 : Legacy Frame Identifiers are considered valid only if Legacy Support is enabled. + * Note 3 : Skippable Frame Identifiers are considered valid. */ +unsigned ZSTD_isFrame(const void* buffer, size_t size) +{ + if (size < ZSTD_FRAMEIDSIZE) return 0; + { U32 const magic = MEM_readLE32(buffer); + if (magic == ZSTD_MAGICNUMBER) return 1; + if ((magic & ZSTD_MAGIC_SKIPPABLE_MASK) == ZSTD_MAGIC_SKIPPABLE_START) return 1; + } +#if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT >= 1) + if (ZSTD_isLegacy(buffer, size)) return 1; +#endif + return 0; +} + +/*! ZSTD_isSkippableFrame() : + * Tells if the content of `buffer` starts with a valid Frame Identifier for a skippable frame. + * Note : Frame Identifier is 4 bytes. If `size < 4`, @return will always be 0. + */ +unsigned ZSTD_isSkippableFrame(const void* buffer, size_t size) +{ + if (size < ZSTD_FRAMEIDSIZE) return 0; + { U32 const magic = MEM_readLE32(buffer); + if ((magic & ZSTD_MAGIC_SKIPPABLE_MASK) == ZSTD_MAGIC_SKIPPABLE_START) return 1; + } + return 0; +} + +/** ZSTD_frameHeaderSize_internal() : + * srcSize must be large enough to reach header size fields. + * note : only works for formats ZSTD_f_zstd1 and ZSTD_f_zstd1_magicless. + * @return : size of the Frame Header + * or an error code, which can be tested with ZSTD_isError() */ +static size_t ZSTD_frameHeaderSize_internal(const void* src, size_t srcSize, ZSTD_format_e format) +{ + size_t const minInputSize = ZSTD_startingInputLength(format); + RETURN_ERROR_IF(srcSize < minInputSize, srcSize_wrong, ""); + + { BYTE const fhd = ((const BYTE*)src)[minInputSize-1]; + U32 const dictID= fhd & 3; + U32 const singleSegment = (fhd >> 5) & 1; + U32 const fcsId = fhd >> 6; + return minInputSize + !singleSegment + + ZSTD_did_fieldSize[dictID] + ZSTD_fcs_fieldSize[fcsId] + + (singleSegment && !fcsId); + } +} + +/** ZSTD_frameHeaderSize() : + * srcSize must be >= ZSTD_frameHeaderSize_prefix. + * @return : size of the Frame Header, + * or an error code (if srcSize is too small) */ +size_t ZSTD_frameHeaderSize(const void* src, size_t srcSize) +{ + return ZSTD_frameHeaderSize_internal(src, srcSize, ZSTD_f_zstd1); +} + + +/** ZSTD_getFrameHeader_advanced() : + * decode Frame Header, or require larger `srcSize`. + * note : only works for formats ZSTD_f_zstd1 and ZSTD_f_zstd1_magicless + * @return : 0, `zfhPtr` is correctly filled, + * >0, `srcSize` is too small, value is wanted `srcSize` amount, + * or an error code, which can be tested using ZSTD_isError() */ +size_t ZSTD_getFrameHeader_advanced(ZSTD_frameHeader* zfhPtr, const void* src, size_t srcSize, ZSTD_format_e format) +{ + const BYTE* ip = (const BYTE*)src; + size_t const minInputSize = ZSTD_startingInputLength(format); + + ZSTD_memset(zfhPtr, 0, sizeof(*zfhPtr)); /* not strictly necessary, but static analyzer do not understand that zfhPtr is only going to be read only if return value is zero, since they are 2 different signals */ + if (srcSize < minInputSize) return minInputSize; + RETURN_ERROR_IF(src==NULL, GENERIC, "invalid parameter"); + + if ( (format != ZSTD_f_zstd1_magicless) + && (MEM_readLE32(src) != ZSTD_MAGICNUMBER) ) { + if ((MEM_readLE32(src) & ZSTD_MAGIC_SKIPPABLE_MASK) == ZSTD_MAGIC_SKIPPABLE_START) { + /* skippable frame */ + if (srcSize < ZSTD_SKIPPABLEHEADERSIZE) + return ZSTD_SKIPPABLEHEADERSIZE; /* magic number + frame length */ + ZSTD_memset(zfhPtr, 0, sizeof(*zfhPtr)); + zfhPtr->frameContentSize = MEM_readLE32((const char *)src + ZSTD_FRAMEIDSIZE); + zfhPtr->frameType = ZSTD_skippableFrame; + return 0; + } + RETURN_ERROR(prefix_unknown, ""); + } + + /* ensure there is enough `srcSize` to fully read/decode frame header */ + { size_t const fhsize = ZSTD_frameHeaderSize_internal(src, srcSize, format); + if (srcSize < fhsize) return fhsize; + zfhPtr->headerSize = (U32)fhsize; + } + + { BYTE const fhdByte = ip[minInputSize-1]; + size_t pos = minInputSize; + U32 const dictIDSizeCode = fhdByte&3; + U32 const checksumFlag = (fhdByte>>2)&1; + U32 const singleSegment = (fhdByte>>5)&1; + U32 const fcsID = fhdByte>>6; + U64 windowSize = 0; + U32 dictID = 0; + U64 frameContentSize = ZSTD_CONTENTSIZE_UNKNOWN; + RETURN_ERROR_IF((fhdByte & 0x08) != 0, frameParameter_unsupported, + "reserved bits, must be zero"); + + if (!singleSegment) { + BYTE const wlByte = ip[pos++]; + U32 const windowLog = (wlByte >> 3) + ZSTD_WINDOWLOG_ABSOLUTEMIN; + RETURN_ERROR_IF(windowLog > ZSTD_WINDOWLOG_MAX, frameParameter_windowTooLarge, ""); + windowSize = (1ULL << windowLog); + windowSize += (windowSize >> 3) * (wlByte&7); + } + switch(dictIDSizeCode) + { + default: + assert(0); /* impossible */ + ZSTD_FALLTHROUGH; + case 0 : break; + case 1 : dictID = ip[pos]; pos++; break; + case 2 : dictID = MEM_readLE16(ip+pos); pos+=2; break; + case 3 : dictID = MEM_readLE32(ip+pos); pos+=4; break; + } + switch(fcsID) + { + default: + assert(0); /* impossible */ + ZSTD_FALLTHROUGH; + case 0 : if (singleSegment) frameContentSize = ip[pos]; break; + case 1 : frameContentSize = MEM_readLE16(ip+pos)+256; break; + case 2 : frameContentSize = MEM_readLE32(ip+pos); break; + case 3 : frameContentSize = MEM_readLE64(ip+pos); break; + } + if (singleSegment) windowSize = frameContentSize; + + zfhPtr->frameType = ZSTD_frame; + zfhPtr->frameContentSize = frameContentSize; + zfhPtr->windowSize = windowSize; + zfhPtr->blockSizeMax = (unsigned) MIN(windowSize, ZSTD_BLOCKSIZE_MAX); + zfhPtr->dictID = dictID; + zfhPtr->checksumFlag = checksumFlag; + } + return 0; +} + +/** ZSTD_getFrameHeader() : + * decode Frame Header, or require larger `srcSize`. + * note : this function does not consume input, it only reads it. + * @return : 0, `zfhPtr` is correctly filled, + * >0, `srcSize` is too small, value is wanted `srcSize` amount, + * or an error code, which can be tested using ZSTD_isError() */ +size_t ZSTD_getFrameHeader(ZSTD_frameHeader* zfhPtr, const void* src, size_t srcSize) +{ + return ZSTD_getFrameHeader_advanced(zfhPtr, src, srcSize, ZSTD_f_zstd1); +} + +/** ZSTD_getFrameContentSize() : + * compatible with legacy mode + * @return : decompressed size of the single frame pointed to be `src` if known, otherwise + * - ZSTD_CONTENTSIZE_UNKNOWN if the size cannot be determined + * - ZSTD_CONTENTSIZE_ERROR if an error occurred (e.g. invalid magic number, srcSize too small) */ +unsigned long long ZSTD_getFrameContentSize(const void *src, size_t srcSize) +{ +#if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT >= 1) + if (ZSTD_isLegacy(src, srcSize)) { + unsigned long long const ret = ZSTD_getDecompressedSize_legacy(src, srcSize); + return ret == 0 ? ZSTD_CONTENTSIZE_UNKNOWN : ret; + } +#endif + { ZSTD_frameHeader zfh; + if (ZSTD_getFrameHeader(&zfh, src, srcSize) != 0) + return ZSTD_CONTENTSIZE_ERROR; + if (zfh.frameType == ZSTD_skippableFrame) { + return 0; + } else { + return zfh.frameContentSize; + } } +} + +static size_t readSkippableFrameSize(void const* src, size_t srcSize) +{ + size_t const skippableHeaderSize = ZSTD_SKIPPABLEHEADERSIZE; + U32 sizeU32; + + RETURN_ERROR_IF(srcSize < ZSTD_SKIPPABLEHEADERSIZE, srcSize_wrong, ""); + + sizeU32 = MEM_readLE32((BYTE const*)src + ZSTD_FRAMEIDSIZE); + RETURN_ERROR_IF((U32)(sizeU32 + ZSTD_SKIPPABLEHEADERSIZE) < sizeU32, + frameParameter_unsupported, ""); + { + size_t const skippableSize = skippableHeaderSize + sizeU32; + RETURN_ERROR_IF(skippableSize > srcSize, srcSize_wrong, ""); + return skippableSize; + } +} + +/*! ZSTD_readSkippableFrame() : + * Retrieves a zstd skippable frame containing data given by src, and writes it to dst buffer. + * + * The parameter magicVariant will receive the magicVariant that was supplied when the frame was written, + * i.e. magicNumber - ZSTD_MAGIC_SKIPPABLE_START. This can be NULL if the caller is not interested + * in the magicVariant. + * + * Returns an error if destination buffer is not large enough, or if the frame is not skippable. + * + * @return : number of bytes written or a ZSTD error. + */ +ZSTDLIB_API size_t ZSTD_readSkippableFrame(void* dst, size_t dstCapacity, unsigned* magicVariant, + const void* src, size_t srcSize) +{ + U32 const magicNumber = MEM_readLE32(src); + size_t skippableFrameSize = readSkippableFrameSize(src, srcSize); + size_t skippableContentSize = skippableFrameSize - ZSTD_SKIPPABLEHEADERSIZE; + + /* check input validity */ + RETURN_ERROR_IF(!ZSTD_isSkippableFrame(src, srcSize), frameParameter_unsupported, ""); + RETURN_ERROR_IF(skippableFrameSize < ZSTD_SKIPPABLEHEADERSIZE || skippableFrameSize > srcSize, srcSize_wrong, ""); + RETURN_ERROR_IF(skippableContentSize > dstCapacity, dstSize_tooSmall, ""); + + /* deliver payload */ + if (skippableContentSize > 0 && dst != NULL) + ZSTD_memcpy(dst, (const BYTE *)src + ZSTD_SKIPPABLEHEADERSIZE, skippableContentSize); + if (magicVariant != NULL) + *magicVariant = magicNumber - ZSTD_MAGIC_SKIPPABLE_START; + return skippableContentSize; +} + +/** ZSTD_findDecompressedSize() : + * compatible with legacy mode + * `srcSize` must be the exact length of some number of ZSTD compressed and/or + * skippable frames + * @return : decompressed size of the frames contained */ +unsigned long long ZSTD_findDecompressedSize(const void* src, size_t srcSize) +{ + unsigned long long totalDstSize = 0; + + while (srcSize >= ZSTD_startingInputLength(ZSTD_f_zstd1)) { + U32 const magicNumber = MEM_readLE32(src); + + if ((magicNumber & ZSTD_MAGIC_SKIPPABLE_MASK) == ZSTD_MAGIC_SKIPPABLE_START) { + size_t const skippableSize = readSkippableFrameSize(src, srcSize); + if (ZSTD_isError(skippableSize)) { + return ZSTD_CONTENTSIZE_ERROR; + } + assert(skippableSize <= srcSize); + + src = (const BYTE *)src + skippableSize; + srcSize -= skippableSize; + continue; + } + + { unsigned long long const ret = ZSTD_getFrameContentSize(src, srcSize); + if (ret >= ZSTD_CONTENTSIZE_ERROR) return ret; + + /* check for overflow */ + if (totalDstSize + ret < totalDstSize) return ZSTD_CONTENTSIZE_ERROR; + totalDstSize += ret; + } + { size_t const frameSrcSize = ZSTD_findFrameCompressedSize(src, srcSize); + if (ZSTD_isError(frameSrcSize)) { + return ZSTD_CONTENTSIZE_ERROR; + } + + src = (const BYTE *)src + frameSrcSize; + srcSize -= frameSrcSize; + } + } /* while (srcSize >= ZSTD_frameHeaderSize_prefix) */ + + if (srcSize) return ZSTD_CONTENTSIZE_ERROR; + + return totalDstSize; +} + +/** ZSTD_getDecompressedSize() : + * compatible with legacy mode + * @return : decompressed size if known, 0 otherwise + note : 0 can mean any of the following : + - frame content is empty + - decompressed size field is not present in frame header + - frame header unknown / not supported + - frame header not complete (`srcSize` too small) */ +unsigned long long ZSTD_getDecompressedSize(const void* src, size_t srcSize) +{ + unsigned long long const ret = ZSTD_getFrameContentSize(src, srcSize); + ZSTD_STATIC_ASSERT(ZSTD_CONTENTSIZE_ERROR < ZSTD_CONTENTSIZE_UNKNOWN); + return (ret >= ZSTD_CONTENTSIZE_ERROR) ? 0 : ret; +} + + +/** ZSTD_decodeFrameHeader() : + * `headerSize` must be the size provided by ZSTD_frameHeaderSize(). + * If multiple DDict references are enabled, also will choose the correct DDict to use. + * @return : 0 if success, or an error code, which can be tested using ZSTD_isError() */ +static size_t ZSTD_decodeFrameHeader(ZSTD_DCtx* dctx, const void* src, size_t headerSize) +{ + size_t const result = ZSTD_getFrameHeader_advanced(&(dctx->fParams), src, headerSize, dctx->format); + if (ZSTD_isError(result)) return result; /* invalid header */ + RETURN_ERROR_IF(result>0, srcSize_wrong, "headerSize too small"); + + /* Reference DDict requested by frame if dctx references multiple ddicts */ + if (dctx->refMultipleDDicts == ZSTD_rmd_refMultipleDDicts && dctx->ddictSet) { + ZSTD_DCtx_selectFrameDDict(dctx); + } + +#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION + /* Skip the dictID check in fuzzing mode, because it makes the search + * harder. + */ + RETURN_ERROR_IF(dctx->fParams.dictID && (dctx->dictID != dctx->fParams.dictID), + dictionary_wrong, ""); +#endif + dctx->validateChecksum = (dctx->fParams.checksumFlag && !dctx->forceIgnoreChecksum) ? 1 : 0; + if (dctx->validateChecksum) XXH64_reset(&dctx->xxhState, 0); + dctx->processedCSize += headerSize; + return 0; +} + +static ZSTD_frameSizeInfo ZSTD_errorFrameSizeInfo(size_t ret) +{ + ZSTD_frameSizeInfo frameSizeInfo; + frameSizeInfo.compressedSize = ret; + frameSizeInfo.decompressedBound = ZSTD_CONTENTSIZE_ERROR; + return frameSizeInfo; +} + +static ZSTD_frameSizeInfo ZSTD_findFrameSizeInfo(const void* src, size_t srcSize) +{ + ZSTD_frameSizeInfo frameSizeInfo; + ZSTD_memset(&frameSizeInfo, 0, sizeof(ZSTD_frameSizeInfo)); + +#if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT >= 1) + if (ZSTD_isLegacy(src, srcSize)) + return ZSTD_findFrameSizeInfoLegacy(src, srcSize); +#endif + + if ((srcSize >= ZSTD_SKIPPABLEHEADERSIZE) + && (MEM_readLE32(src) & ZSTD_MAGIC_SKIPPABLE_MASK) == ZSTD_MAGIC_SKIPPABLE_START) { + frameSizeInfo.compressedSize = readSkippableFrameSize(src, srcSize); + assert(ZSTD_isError(frameSizeInfo.compressedSize) || + frameSizeInfo.compressedSize <= srcSize); + return frameSizeInfo; + } else { + const BYTE* ip = (const BYTE*)src; + const BYTE* const ipstart = ip; + size_t remainingSize = srcSize; + size_t nbBlocks = 0; + ZSTD_frameHeader zfh; + + /* Extract Frame Header */ + { size_t const ret = ZSTD_getFrameHeader(&zfh, src, srcSize); + if (ZSTD_isError(ret)) + return ZSTD_errorFrameSizeInfo(ret); + if (ret > 0) + return ZSTD_errorFrameSizeInfo(ERROR(srcSize_wrong)); + } + + ip += zfh.headerSize; + remainingSize -= zfh.headerSize; + + /* Iterate over each block */ + while (1) { + blockProperties_t blockProperties; + size_t const cBlockSize = ZSTD_getcBlockSize(ip, remainingSize, &blockProperties); + if (ZSTD_isError(cBlockSize)) + return ZSTD_errorFrameSizeInfo(cBlockSize); + + if (ZSTD_blockHeaderSize + cBlockSize > remainingSize) + return ZSTD_errorFrameSizeInfo(ERROR(srcSize_wrong)); + + ip += ZSTD_blockHeaderSize + cBlockSize; + remainingSize -= ZSTD_blockHeaderSize + cBlockSize; + nbBlocks++; + + if (blockProperties.lastBlock) break; + } + + /* Final frame content checksum */ + if (zfh.checksumFlag) { + if (remainingSize < 4) + return ZSTD_errorFrameSizeInfo(ERROR(srcSize_wrong)); + ip += 4; + } + + frameSizeInfo.compressedSize = (size_t)(ip - ipstart); + frameSizeInfo.decompressedBound = (zfh.frameContentSize != ZSTD_CONTENTSIZE_UNKNOWN) + ? zfh.frameContentSize + : nbBlocks * zfh.blockSizeMax; + return frameSizeInfo; + } +} + +/** ZSTD_findFrameCompressedSize() : + * compatible with legacy mode + * `src` must point to the start of a ZSTD frame, ZSTD legacy frame, or skippable frame + * `srcSize` must be at least as large as the frame contained + * @return : the compressed size of the frame starting at `src` */ +size_t ZSTD_findFrameCompressedSize(const void *src, size_t srcSize) +{ + ZSTD_frameSizeInfo const frameSizeInfo = ZSTD_findFrameSizeInfo(src, srcSize); + return frameSizeInfo.compressedSize; +} + +/** ZSTD_decompressBound() : + * compatible with legacy mode + * `src` must point to the start of a ZSTD frame or a skippeable frame + * `srcSize` must be at least as large as the frame contained + * @return : the maximum decompressed size of the compressed source + */ +unsigned long long ZSTD_decompressBound(const void* src, size_t srcSize) +{ + unsigned long long bound = 0; + /* Iterate over each frame */ + while (srcSize > 0) { + ZSTD_frameSizeInfo const frameSizeInfo = ZSTD_findFrameSizeInfo(src, srcSize); + size_t const compressedSize = frameSizeInfo.compressedSize; + unsigned long long const decompressedBound = frameSizeInfo.decompressedBound; + if (ZSTD_isError(compressedSize) || decompressedBound == ZSTD_CONTENTSIZE_ERROR) + return ZSTD_CONTENTSIZE_ERROR; + assert(srcSize >= compressedSize); + src = (const BYTE*)src + compressedSize; + srcSize -= compressedSize; + bound += decompressedBound; + } + return bound; +} + + +/*-************************************************************* + * Frame decoding + ***************************************************************/ + +/** ZSTD_insertBlock() : + * insert `src` block into `dctx` history. Useful to track uncompressed blocks. */ +size_t ZSTD_insertBlock(ZSTD_DCtx* dctx, const void* blockStart, size_t blockSize) +{ + DEBUGLOG(5, "ZSTD_insertBlock: %u bytes", (unsigned)blockSize); + ZSTD_checkContinuity(dctx, blockStart, blockSize); + dctx->previousDstEnd = (const char*)blockStart + blockSize; + return blockSize; +} + + +static size_t ZSTD_copyRawBlock(void* dst, size_t dstCapacity, + const void* src, size_t srcSize) +{ + DEBUGLOG(5, "ZSTD_copyRawBlock"); + RETURN_ERROR_IF(srcSize > dstCapacity, dstSize_tooSmall, ""); + if (dst == NULL) { + if (srcSize == 0) return 0; + RETURN_ERROR(dstBuffer_null, ""); + } + ZSTD_memcpy(dst, src, srcSize); + return srcSize; +} + +static size_t ZSTD_setRleBlock(void* dst, size_t dstCapacity, + BYTE b, + size_t regenSize) +{ + RETURN_ERROR_IF(regenSize > dstCapacity, dstSize_tooSmall, ""); + if (dst == NULL) { + if (regenSize == 0) return 0; + RETURN_ERROR(dstBuffer_null, ""); + } + ZSTD_memset(dst, b, regenSize); + return regenSize; +} + +static void ZSTD_DCtx_trace_end(ZSTD_DCtx const* dctx, U64 uncompressedSize, U64 compressedSize, unsigned streaming) +{ +#if ZSTD_TRACE + if (dctx->traceCtx && ZSTD_trace_decompress_end != NULL) { + ZSTD_Trace trace; + ZSTD_memset(&trace, 0, sizeof(trace)); + trace.version = ZSTD_VERSION_NUMBER; + trace.streaming = streaming; + if (dctx->ddict) { + trace.dictionaryID = ZSTD_getDictID_fromDDict(dctx->ddict); + trace.dictionarySize = ZSTD_DDict_dictSize(dctx->ddict); + trace.dictionaryIsCold = dctx->ddictIsCold; + } + trace.uncompressedSize = (size_t)uncompressedSize; + trace.compressedSize = (size_t)compressedSize; + trace.dctx = dctx; + ZSTD_trace_decompress_end(dctx->traceCtx, &trace); + } +#else + (void)dctx; + (void)uncompressedSize; + (void)compressedSize; + (void)streaming; +#endif +} + + +/*! ZSTD_decompressFrame() : + * @dctx must be properly initialized + * will update *srcPtr and *srcSizePtr, + * to make *srcPtr progress by one frame. */ +static size_t ZSTD_decompressFrame(ZSTD_DCtx* dctx, + void* dst, size_t dstCapacity, + const void** srcPtr, size_t *srcSizePtr) +{ + const BYTE* const istart = (const BYTE*)(*srcPtr); + const BYTE* ip = istart; + BYTE* const ostart = (BYTE*)dst; + BYTE* const oend = dstCapacity != 0 ? ostart + dstCapacity : ostart; + BYTE* op = ostart; + size_t remainingSrcSize = *srcSizePtr; + + DEBUGLOG(4, "ZSTD_decompressFrame (srcSize:%i)", (int)*srcSizePtr); + + /* check */ + RETURN_ERROR_IF( + remainingSrcSize < ZSTD_FRAMEHEADERSIZE_MIN(dctx->format)+ZSTD_blockHeaderSize, + srcSize_wrong, ""); + + /* Frame Header */ + { size_t const frameHeaderSize = ZSTD_frameHeaderSize_internal( + ip, ZSTD_FRAMEHEADERSIZE_PREFIX(dctx->format), dctx->format); + if (ZSTD_isError(frameHeaderSize)) return frameHeaderSize; + RETURN_ERROR_IF(remainingSrcSize < frameHeaderSize+ZSTD_blockHeaderSize, + srcSize_wrong, ""); + FORWARD_IF_ERROR( ZSTD_decodeFrameHeader(dctx, ip, frameHeaderSize) , ""); + ip += frameHeaderSize; remainingSrcSize -= frameHeaderSize; + } + + /* Loop on each block */ + while (1) { + size_t decodedSize; + blockProperties_t blockProperties; + size_t const cBlockSize = ZSTD_getcBlockSize(ip, remainingSrcSize, &blockProperties); + if (ZSTD_isError(cBlockSize)) return cBlockSize; + + ip += ZSTD_blockHeaderSize; + remainingSrcSize -= ZSTD_blockHeaderSize; + RETURN_ERROR_IF(cBlockSize > remainingSrcSize, srcSize_wrong, ""); + + switch(blockProperties.blockType) + { + case bt_compressed: + decodedSize = ZSTD_decompressBlock_internal(dctx, op, (size_t)(oend-op), ip, cBlockSize, /* frame */ 1, not_streaming); + break; + case bt_raw : + decodedSize = ZSTD_copyRawBlock(op, (size_t)(oend-op), ip, cBlockSize); + break; + case bt_rle : + decodedSize = ZSTD_setRleBlock(op, (size_t)(oend-op), *ip, blockProperties.origSize); + break; + case bt_reserved : + default: + RETURN_ERROR(corruption_detected, "invalid block type"); + } + + if (ZSTD_isError(decodedSize)) return decodedSize; + if (dctx->validateChecksum) + XXH64_update(&dctx->xxhState, op, decodedSize); + if (decodedSize != 0) + op += decodedSize; + assert(ip != NULL); + ip += cBlockSize; + remainingSrcSize -= cBlockSize; + if (blockProperties.lastBlock) break; + } + + if (dctx->fParams.frameContentSize != ZSTD_CONTENTSIZE_UNKNOWN) { + RETURN_ERROR_IF((U64)(op-ostart) != dctx->fParams.frameContentSize, + corruption_detected, ""); + } + if (dctx->fParams.checksumFlag) { /* Frame content checksum verification */ + RETURN_ERROR_IF(remainingSrcSize<4, checksum_wrong, ""); + if (!dctx->forceIgnoreChecksum) { + U32 const checkCalc = (U32)XXH64_digest(&dctx->xxhState); + U32 checkRead; + checkRead = MEM_readLE32(ip); + RETURN_ERROR_IF(checkRead != checkCalc, checksum_wrong, ""); + } + ip += 4; + remainingSrcSize -= 4; + } + ZSTD_DCtx_trace_end(dctx, (U64)(op-ostart), (U64)(ip-istart), /* streaming */ 0); + /* Allow caller to get size read */ + *srcPtr = ip; + *srcSizePtr = remainingSrcSize; + return (size_t)(op-ostart); +} + +static size_t ZSTD_decompressMultiFrame(ZSTD_DCtx* dctx, + void* dst, size_t dstCapacity, + const void* src, size_t srcSize, + const void* dict, size_t dictSize, + const ZSTD_DDict* ddict) +{ + void* const dststart = dst; + int moreThan1Frame = 0; + + DEBUGLOG(5, "ZSTD_decompressMultiFrame"); + assert(dict==NULL || ddict==NULL); /* either dict or ddict set, not both */ + + if (ddict) { + dict = ZSTD_DDict_dictContent(ddict); + dictSize = ZSTD_DDict_dictSize(ddict); + } + + while (srcSize >= ZSTD_startingInputLength(dctx->format)) { + +#if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT >= 1) + if (ZSTD_isLegacy(src, srcSize)) { + size_t decodedSize; + size_t const frameSize = ZSTD_findFrameCompressedSizeLegacy(src, srcSize); + if (ZSTD_isError(frameSize)) return frameSize; + RETURN_ERROR_IF(dctx->staticSize, memory_allocation, + "legacy support is not compatible with static dctx"); + + decodedSize = ZSTD_decompressLegacy(dst, dstCapacity, src, frameSize, dict, dictSize); + if (ZSTD_isError(decodedSize)) return decodedSize; + + assert(decodedSize <= dstCapacity); + dst = (BYTE*)dst + decodedSize; + dstCapacity -= decodedSize; + + src = (const BYTE*)src + frameSize; + srcSize -= frameSize; + + continue; + } +#endif + + { U32 const magicNumber = MEM_readLE32(src); + DEBUGLOG(4, "reading magic number %08X (expecting %08X)", + (unsigned)magicNumber, ZSTD_MAGICNUMBER); + if ((magicNumber & ZSTD_MAGIC_SKIPPABLE_MASK) == ZSTD_MAGIC_SKIPPABLE_START) { + size_t const skippableSize = readSkippableFrameSize(src, srcSize); + FORWARD_IF_ERROR(skippableSize, "readSkippableFrameSize failed"); + assert(skippableSize <= srcSize); + + src = (const BYTE *)src + skippableSize; + srcSize -= skippableSize; + continue; + } } + + if (ddict) { + /* we were called from ZSTD_decompress_usingDDict */ + FORWARD_IF_ERROR(ZSTD_decompressBegin_usingDDict(dctx, ddict), ""); + } else { + /* this will initialize correctly with no dict if dict == NULL, so + * use this in all cases but ddict */ + FORWARD_IF_ERROR(ZSTD_decompressBegin_usingDict(dctx, dict, dictSize), ""); + } + ZSTD_checkContinuity(dctx, dst, dstCapacity); + + { const size_t res = ZSTD_decompressFrame(dctx, dst, dstCapacity, + &src, &srcSize); + RETURN_ERROR_IF( + (ZSTD_getErrorCode(res) == ZSTD_error_prefix_unknown) + && (moreThan1Frame==1), + srcSize_wrong, + "At least one frame successfully completed, " + "but following bytes are garbage: " + "it's more likely to be a srcSize error, " + "specifying more input bytes than size of frame(s). " + "Note: one could be unlucky, it might be a corruption error instead, " + "happening right at the place where we expect zstd magic bytes. " + "But this is _much_ less likely than a srcSize field error."); + if (ZSTD_isError(res)) return res; + assert(res <= dstCapacity); + if (res != 0) + dst = (BYTE*)dst + res; + dstCapacity -= res; + } + moreThan1Frame = 1; + } /* while (srcSize >= ZSTD_frameHeaderSize_prefix) */ + + RETURN_ERROR_IF(srcSize, srcSize_wrong, "input not entirely consumed"); + + return (size_t)((BYTE*)dst - (BYTE*)dststart); +} + +size_t ZSTD_decompress_usingDict(ZSTD_DCtx* dctx, + void* dst, size_t dstCapacity, + const void* src, size_t srcSize, + const void* dict, size_t dictSize) +{ + return ZSTD_decompressMultiFrame(dctx, dst, dstCapacity, src, srcSize, dict, dictSize, NULL); +} + + +static ZSTD_DDict const* ZSTD_getDDict(ZSTD_DCtx* dctx) +{ + switch (dctx->dictUses) { + default: + assert(0 /* Impossible */); + ZSTD_FALLTHROUGH; + case ZSTD_dont_use: + ZSTD_clearDict(dctx); + return NULL; + case ZSTD_use_indefinitely: + return dctx->ddict; + case ZSTD_use_once: + dctx->dictUses = ZSTD_dont_use; + return dctx->ddict; + } +} + +size_t ZSTD_decompressDCtx(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize) +{ + return ZSTD_decompress_usingDDict(dctx, dst, dstCapacity, src, srcSize, ZSTD_getDDict(dctx)); +} + + +size_t ZSTD_decompress(void* dst, size_t dstCapacity, const void* src, size_t srcSize) +{ +#if defined(ZSTD_HEAPMODE) && (ZSTD_HEAPMODE>=1) + size_t regenSize; + ZSTD_DCtx* const dctx = ZSTD_createDCtx_internal(ZSTD_defaultCMem); + RETURN_ERROR_IF(dctx==NULL, memory_allocation, "NULL pointer!"); + regenSize = ZSTD_decompressDCtx(dctx, dst, dstCapacity, src, srcSize); + ZSTD_freeDCtx(dctx); + return regenSize; +#else /* stack mode */ + ZSTD_DCtx dctx; + ZSTD_initDCtx_internal(&dctx); + return ZSTD_decompressDCtx(&dctx, dst, dstCapacity, src, srcSize); +#endif +} + + +/*-************************************** +* Advanced Streaming Decompression API +* Bufferless and synchronous +****************************************/ +size_t ZSTD_nextSrcSizeToDecompress(ZSTD_DCtx* dctx) { return dctx->expected; } + +/** + * Similar to ZSTD_nextSrcSizeToDecompress(), but when when a block input can be streamed, + * we allow taking a partial block as the input. Currently only raw uncompressed blocks can + * be streamed. + * + * For blocks that can be streamed, this allows us to reduce the latency until we produce + * output, and avoid copying the input. + * + * @param inputSize - The total amount of input that the caller currently has. + */ +static size_t ZSTD_nextSrcSizeToDecompressWithInputSize(ZSTD_DCtx* dctx, size_t inputSize) { + if (!(dctx->stage == ZSTDds_decompressBlock || dctx->stage == ZSTDds_decompressLastBlock)) + return dctx->expected; + if (dctx->bType != bt_raw) + return dctx->expected; + return BOUNDED(1, inputSize, dctx->expected); +} + +ZSTD_nextInputType_e ZSTD_nextInputType(ZSTD_DCtx* dctx) { + switch(dctx->stage) + { + default: /* should not happen */ + assert(0); + ZSTD_FALLTHROUGH; + case ZSTDds_getFrameHeaderSize: + ZSTD_FALLTHROUGH; + case ZSTDds_decodeFrameHeader: + return ZSTDnit_frameHeader; + case ZSTDds_decodeBlockHeader: + return ZSTDnit_blockHeader; + case ZSTDds_decompressBlock: + return ZSTDnit_block; + case ZSTDds_decompressLastBlock: + return ZSTDnit_lastBlock; + case ZSTDds_checkChecksum: + return ZSTDnit_checksum; + case ZSTDds_decodeSkippableHeader: + ZSTD_FALLTHROUGH; + case ZSTDds_skipFrame: + return ZSTDnit_skippableFrame; + } +} + +static int ZSTD_isSkipFrame(ZSTD_DCtx* dctx) { return dctx->stage == ZSTDds_skipFrame; } + +/** ZSTD_decompressContinue() : + * srcSize : must be the exact nb of bytes expected (see ZSTD_nextSrcSizeToDecompress()) + * @return : nb of bytes generated into `dst` (necessarily <= `dstCapacity) + * or an error code, which can be tested using ZSTD_isError() */ +size_t ZSTD_decompressContinue(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize) +{ + DEBUGLOG(5, "ZSTD_decompressContinue (srcSize:%u)", (unsigned)srcSize); + /* Sanity check */ + RETURN_ERROR_IF(srcSize != ZSTD_nextSrcSizeToDecompressWithInputSize(dctx, srcSize), srcSize_wrong, "not allowed"); + ZSTD_checkContinuity(dctx, dst, dstCapacity); + + dctx->processedCSize += srcSize; + + switch (dctx->stage) + { + case ZSTDds_getFrameHeaderSize : + assert(src != NULL); + if (dctx->format == ZSTD_f_zstd1) { /* allows header */ + assert(srcSize >= ZSTD_FRAMEIDSIZE); /* to read skippable magic number */ + if ((MEM_readLE32(src) & ZSTD_MAGIC_SKIPPABLE_MASK) == ZSTD_MAGIC_SKIPPABLE_START) { /* skippable frame */ + ZSTD_memcpy(dctx->headerBuffer, src, srcSize); + dctx->expected = ZSTD_SKIPPABLEHEADERSIZE - srcSize; /* remaining to load to get full skippable frame header */ + dctx->stage = ZSTDds_decodeSkippableHeader; + return 0; + } } + dctx->headerSize = ZSTD_frameHeaderSize_internal(src, srcSize, dctx->format); + if (ZSTD_isError(dctx->headerSize)) return dctx->headerSize; + ZSTD_memcpy(dctx->headerBuffer, src, srcSize); + dctx->expected = dctx->headerSize - srcSize; + dctx->stage = ZSTDds_decodeFrameHeader; + return 0; + + case ZSTDds_decodeFrameHeader: + assert(src != NULL); + ZSTD_memcpy(dctx->headerBuffer + (dctx->headerSize - srcSize), src, srcSize); + FORWARD_IF_ERROR(ZSTD_decodeFrameHeader(dctx, dctx->headerBuffer, dctx->headerSize), ""); + dctx->expected = ZSTD_blockHeaderSize; + dctx->stage = ZSTDds_decodeBlockHeader; + return 0; + + case ZSTDds_decodeBlockHeader: + { blockProperties_t bp; + size_t const cBlockSize = ZSTD_getcBlockSize(src, ZSTD_blockHeaderSize, &bp); + if (ZSTD_isError(cBlockSize)) return cBlockSize; + RETURN_ERROR_IF(cBlockSize > dctx->fParams.blockSizeMax, corruption_detected, "Block Size Exceeds Maximum"); + dctx->expected = cBlockSize; + dctx->bType = bp.blockType; + dctx->rleSize = bp.origSize; + if (cBlockSize) { + dctx->stage = bp.lastBlock ? ZSTDds_decompressLastBlock : ZSTDds_decompressBlock; + return 0; + } + /* empty block */ + if (bp.lastBlock) { + if (dctx->fParams.checksumFlag) { + dctx->expected = 4; + dctx->stage = ZSTDds_checkChecksum; + } else { + dctx->expected = 0; /* end of frame */ + dctx->stage = ZSTDds_getFrameHeaderSize; + } + } else { + dctx->expected = ZSTD_blockHeaderSize; /* jump to next header */ + dctx->stage = ZSTDds_decodeBlockHeader; + } + return 0; + } + + case ZSTDds_decompressLastBlock: + case ZSTDds_decompressBlock: + DEBUGLOG(5, "ZSTD_decompressContinue: case ZSTDds_decompressBlock"); + { size_t rSize; + switch(dctx->bType) + { + case bt_compressed: + DEBUGLOG(5, "ZSTD_decompressContinue: case bt_compressed"); + rSize = ZSTD_decompressBlock_internal(dctx, dst, dstCapacity, src, srcSize, /* frame */ 1, is_streaming); + dctx->expected = 0; /* Streaming not supported */ + break; + case bt_raw : + assert(srcSize <= dctx->expected); + rSize = ZSTD_copyRawBlock(dst, dstCapacity, src, srcSize); + FORWARD_IF_ERROR(rSize, "ZSTD_copyRawBlock failed"); + assert(rSize == srcSize); + dctx->expected -= rSize; + break; + case bt_rle : + rSize = ZSTD_setRleBlock(dst, dstCapacity, *(const BYTE*)src, dctx->rleSize); + dctx->expected = 0; /* Streaming not supported */ + break; + case bt_reserved : /* should never happen */ + default: + RETURN_ERROR(corruption_detected, "invalid block type"); + } + FORWARD_IF_ERROR(rSize, ""); + RETURN_ERROR_IF(rSize > dctx->fParams.blockSizeMax, corruption_detected, "Decompressed Block Size Exceeds Maximum"); + DEBUGLOG(5, "ZSTD_decompressContinue: decoded size from block : %u", (unsigned)rSize); + dctx->decodedSize += rSize; + if (dctx->validateChecksum) XXH64_update(&dctx->xxhState, dst, rSize); + dctx->previousDstEnd = (char*)dst + rSize; + + /* Stay on the same stage until we are finished streaming the block. */ + if (dctx->expected > 0) { + return rSize; + } + + if (dctx->stage == ZSTDds_decompressLastBlock) { /* end of frame */ + DEBUGLOG(4, "ZSTD_decompressContinue: decoded size from frame : %u", (unsigned)dctx->decodedSize); + RETURN_ERROR_IF( + dctx->fParams.frameContentSize != ZSTD_CONTENTSIZE_UNKNOWN + && dctx->decodedSize != dctx->fParams.frameContentSize, + corruption_detected, ""); + if (dctx->fParams.checksumFlag) { /* another round for frame checksum */ + dctx->expected = 4; + dctx->stage = ZSTDds_checkChecksum; + } else { + ZSTD_DCtx_trace_end(dctx, dctx->decodedSize, dctx->processedCSize, /* streaming */ 1); + dctx->expected = 0; /* ends here */ + dctx->stage = ZSTDds_getFrameHeaderSize; + } + } else { + dctx->stage = ZSTDds_decodeBlockHeader; + dctx->expected = ZSTD_blockHeaderSize; + } + return rSize; + } + + case ZSTDds_checkChecksum: + assert(srcSize == 4); /* guaranteed by dctx->expected */ + { + if (dctx->validateChecksum) { + U32 const h32 = (U32)XXH64_digest(&dctx->xxhState); + U32 const check32 = MEM_readLE32(src); + DEBUGLOG(4, "ZSTD_decompressContinue: checksum : calculated %08X :: %08X read", (unsigned)h32, (unsigned)check32); + RETURN_ERROR_IF(check32 != h32, checksum_wrong, ""); + } + ZSTD_DCtx_trace_end(dctx, dctx->decodedSize, dctx->processedCSize, /* streaming */ 1); + dctx->expected = 0; + dctx->stage = ZSTDds_getFrameHeaderSize; + return 0; + } + + case ZSTDds_decodeSkippableHeader: + assert(src != NULL); + assert(srcSize <= ZSTD_SKIPPABLEHEADERSIZE); + ZSTD_memcpy(dctx->headerBuffer + (ZSTD_SKIPPABLEHEADERSIZE - srcSize), src, srcSize); /* complete skippable header */ + dctx->expected = MEM_readLE32(dctx->headerBuffer + ZSTD_FRAMEIDSIZE); /* note : dctx->expected can grow seriously large, beyond local buffer size */ + dctx->stage = ZSTDds_skipFrame; + return 0; + + case ZSTDds_skipFrame: + dctx->expected = 0; + dctx->stage = ZSTDds_getFrameHeaderSize; + return 0; + + default: + assert(0); /* impossible */ + RETURN_ERROR(GENERIC, "impossible to reach"); /* some compiler require default to do something */ + } +} + + +static size_t ZSTD_refDictContent(ZSTD_DCtx* dctx, const void* dict, size_t dictSize) +{ + dctx->dictEnd = dctx->previousDstEnd; + dctx->virtualStart = (const char*)dict - ((const char*)(dctx->previousDstEnd) - (const char*)(dctx->prefixStart)); + dctx->prefixStart = dict; + dctx->previousDstEnd = (const char*)dict + dictSize; +#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION + dctx->dictContentBeginForFuzzing = dctx->prefixStart; + dctx->dictContentEndForFuzzing = dctx->previousDstEnd; +#endif + return 0; +} + +/*! ZSTD_loadDEntropy() : + * dict : must point at beginning of a valid zstd dictionary. + * @return : size of entropy tables read */ +size_t +ZSTD_loadDEntropy(ZSTD_entropyDTables_t* entropy, + const void* const dict, size_t const dictSize) +{ + const BYTE* dictPtr = (const BYTE*)dict; + const BYTE* const dictEnd = dictPtr + dictSize; + + RETURN_ERROR_IF(dictSize <= 8, dictionary_corrupted, "dict is too small"); + assert(MEM_readLE32(dict) == ZSTD_MAGIC_DICTIONARY); /* dict must be valid */ + dictPtr += 8; /* skip header = magic + dictID */ + + ZSTD_STATIC_ASSERT(offsetof(ZSTD_entropyDTables_t, OFTable) == offsetof(ZSTD_entropyDTables_t, LLTable) + sizeof(entropy->LLTable)); + ZSTD_STATIC_ASSERT(offsetof(ZSTD_entropyDTables_t, MLTable) == offsetof(ZSTD_entropyDTables_t, OFTable) + sizeof(entropy->OFTable)); + ZSTD_STATIC_ASSERT(sizeof(entropy->LLTable) + sizeof(entropy->OFTable) + sizeof(entropy->MLTable) >= HUF_DECOMPRESS_WORKSPACE_SIZE); + { void* const workspace = &entropy->LLTable; /* use fse tables as temporary workspace; implies fse tables are grouped together */ + size_t const workspaceSize = sizeof(entropy->LLTable) + sizeof(entropy->OFTable) + sizeof(entropy->MLTable); +#ifdef HUF_FORCE_DECOMPRESS_X1 + /* in minimal huffman, we always use X1 variants */ + size_t const hSize = HUF_readDTableX1_wksp(entropy->hufTable, + dictPtr, dictEnd - dictPtr, + workspace, workspaceSize); +#else + size_t const hSize = HUF_readDTableX2_wksp(entropy->hufTable, + dictPtr, (size_t)(dictEnd - dictPtr), + workspace, workspaceSize); +#endif + RETURN_ERROR_IF(HUF_isError(hSize), dictionary_corrupted, ""); + dictPtr += hSize; + } + + { short offcodeNCount[MaxOff+1]; + unsigned offcodeMaxValue = MaxOff, offcodeLog; + size_t const offcodeHeaderSize = FSE_readNCount(offcodeNCount, &offcodeMaxValue, &offcodeLog, dictPtr, (size_t)(dictEnd-dictPtr)); + RETURN_ERROR_IF(FSE_isError(offcodeHeaderSize), dictionary_corrupted, ""); + RETURN_ERROR_IF(offcodeMaxValue > MaxOff, dictionary_corrupted, ""); + RETURN_ERROR_IF(offcodeLog > OffFSELog, dictionary_corrupted, ""); + ZSTD_buildFSETable( entropy->OFTable, + offcodeNCount, offcodeMaxValue, + OF_base, OF_bits, + offcodeLog, + entropy->workspace, sizeof(entropy->workspace), + /* bmi2 */0); + dictPtr += offcodeHeaderSize; + } + + { short matchlengthNCount[MaxML+1]; + unsigned matchlengthMaxValue = MaxML, matchlengthLog; + size_t const matchlengthHeaderSize = FSE_readNCount(matchlengthNCount, &matchlengthMaxValue, &matchlengthLog, dictPtr, (size_t)(dictEnd-dictPtr)); + RETURN_ERROR_IF(FSE_isError(matchlengthHeaderSize), dictionary_corrupted, ""); + RETURN_ERROR_IF(matchlengthMaxValue > MaxML, dictionary_corrupted, ""); + RETURN_ERROR_IF(matchlengthLog > MLFSELog, dictionary_corrupted, ""); + ZSTD_buildFSETable( entropy->MLTable, + matchlengthNCount, matchlengthMaxValue, + ML_base, ML_bits, + matchlengthLog, + entropy->workspace, sizeof(entropy->workspace), + /* bmi2 */ 0); + dictPtr += matchlengthHeaderSize; + } + + { short litlengthNCount[MaxLL+1]; + unsigned litlengthMaxValue = MaxLL, litlengthLog; + size_t const litlengthHeaderSize = FSE_readNCount(litlengthNCount, &litlengthMaxValue, &litlengthLog, dictPtr, (size_t)(dictEnd-dictPtr)); + RETURN_ERROR_IF(FSE_isError(litlengthHeaderSize), dictionary_corrupted, ""); + RETURN_ERROR_IF(litlengthMaxValue > MaxLL, dictionary_corrupted, ""); + RETURN_ERROR_IF(litlengthLog > LLFSELog, dictionary_corrupted, ""); + ZSTD_buildFSETable( entropy->LLTable, + litlengthNCount, litlengthMaxValue, + LL_base, LL_bits, + litlengthLog, + entropy->workspace, sizeof(entropy->workspace), + /* bmi2 */ 0); + dictPtr += litlengthHeaderSize; + } + + RETURN_ERROR_IF(dictPtr+12 > dictEnd, dictionary_corrupted, ""); + { int i; + size_t const dictContentSize = (size_t)(dictEnd - (dictPtr+12)); + for (i=0; i<3; i++) { + U32 const rep = MEM_readLE32(dictPtr); dictPtr += 4; + RETURN_ERROR_IF(rep==0 || rep > dictContentSize, + dictionary_corrupted, ""); + entropy->rep[i] = rep; + } } + + return (size_t)(dictPtr - (const BYTE*)dict); +} + +static size_t ZSTD_decompress_insertDictionary(ZSTD_DCtx* dctx, const void* dict, size_t dictSize) +{ + if (dictSize < 8) return ZSTD_refDictContent(dctx, dict, dictSize); + { U32 const magic = MEM_readLE32(dict); + if (magic != ZSTD_MAGIC_DICTIONARY) { + return ZSTD_refDictContent(dctx, dict, dictSize); /* pure content mode */ + } } + dctx->dictID = MEM_readLE32((const char*)dict + ZSTD_FRAMEIDSIZE); + + /* load entropy tables */ + { size_t const eSize = ZSTD_loadDEntropy(&dctx->entropy, dict, dictSize); + RETURN_ERROR_IF(ZSTD_isError(eSize), dictionary_corrupted, ""); + dict = (const char*)dict + eSize; + dictSize -= eSize; + } + dctx->litEntropy = dctx->fseEntropy = 1; + + /* reference dictionary content */ + return ZSTD_refDictContent(dctx, dict, dictSize); +} + +size_t ZSTD_decompressBegin(ZSTD_DCtx* dctx) +{ + assert(dctx != NULL); +#if ZSTD_TRACE + dctx->traceCtx = (ZSTD_trace_decompress_begin != NULL) ? ZSTD_trace_decompress_begin(dctx) : 0; +#endif + dctx->expected = ZSTD_startingInputLength(dctx->format); /* dctx->format must be properly set */ + dctx->stage = ZSTDds_getFrameHeaderSize; + dctx->processedCSize = 0; + dctx->decodedSize = 0; + dctx->previousDstEnd = NULL; + dctx->prefixStart = NULL; + dctx->virtualStart = NULL; + dctx->dictEnd = NULL; + dctx->entropy.hufTable[0] = (HUF_DTable)((HufLog)*0x1000001); /* cover both little and big endian */ + dctx->litEntropy = dctx->fseEntropy = 0; + dctx->dictID = 0; + dctx->bType = bt_reserved; + ZSTD_STATIC_ASSERT(sizeof(dctx->entropy.rep) == sizeof(repStartValue)); + ZSTD_memcpy(dctx->entropy.rep, repStartValue, sizeof(repStartValue)); /* initial repcodes */ + dctx->LLTptr = dctx->entropy.LLTable; + dctx->MLTptr = dctx->entropy.MLTable; + dctx->OFTptr = dctx->entropy.OFTable; + dctx->HUFptr = dctx->entropy.hufTable; + return 0; +} + +size_t ZSTD_decompressBegin_usingDict(ZSTD_DCtx* dctx, const void* dict, size_t dictSize) +{ + FORWARD_IF_ERROR( ZSTD_decompressBegin(dctx) , ""); + if (dict && dictSize) + RETURN_ERROR_IF( + ZSTD_isError(ZSTD_decompress_insertDictionary(dctx, dict, dictSize)), + dictionary_corrupted, ""); + return 0; +} + + +/* ====== ZSTD_DDict ====== */ + +size_t ZSTD_decompressBegin_usingDDict(ZSTD_DCtx* dctx, const ZSTD_DDict* ddict) +{ + DEBUGLOG(4, "ZSTD_decompressBegin_usingDDict"); + assert(dctx != NULL); + if (ddict) { + const char* const dictStart = (const char*)ZSTD_DDict_dictContent(ddict); + size_t const dictSize = ZSTD_DDict_dictSize(ddict); + const void* const dictEnd = dictStart + dictSize; + dctx->ddictIsCold = (dctx->dictEnd != dictEnd); + DEBUGLOG(4, "DDict is %s", + dctx->ddictIsCold ? "~cold~" : "hot!"); + } + FORWARD_IF_ERROR( ZSTD_decompressBegin(dctx) , ""); + if (ddict) { /* NULL ddict is equivalent to no dictionary */ + ZSTD_copyDDictParameters(dctx, ddict); + } + return 0; +} + +/*! ZSTD_getDictID_fromDict() : + * Provides the dictID stored within dictionary. + * if @return == 0, the dictionary is not conformant with Zstandard specification. + * It can still be loaded, but as a content-only dictionary. */ +unsigned ZSTD_getDictID_fromDict(const void* dict, size_t dictSize) +{ + if (dictSize < 8) return 0; + if (MEM_readLE32(dict) != ZSTD_MAGIC_DICTIONARY) return 0; + return MEM_readLE32((const char*)dict + ZSTD_FRAMEIDSIZE); +} + +/*! ZSTD_getDictID_fromFrame() : + * Provides the dictID required to decompress frame stored within `src`. + * If @return == 0, the dictID could not be decoded. + * This could for one of the following reasons : + * - The frame does not require a dictionary (most common case). + * - The frame was built with dictID intentionally removed. + * Needed dictionary is a hidden information. + * Note : this use case also happens when using a non-conformant dictionary. + * - `srcSize` is too small, and as a result, frame header could not be decoded. + * Note : possible if `srcSize < ZSTD_FRAMEHEADERSIZE_MAX`. + * - This is not a Zstandard frame. + * When identifying the exact failure cause, it's possible to use + * ZSTD_getFrameHeader(), which will provide a more precise error code. */ +unsigned ZSTD_getDictID_fromFrame(const void* src, size_t srcSize) +{ + ZSTD_frameHeader zfp = { 0, 0, 0, ZSTD_frame, 0, 0, 0 }; + size_t const hError = ZSTD_getFrameHeader(&zfp, src, srcSize); + if (ZSTD_isError(hError)) return 0; + return zfp.dictID; +} + + +/*! ZSTD_decompress_usingDDict() : +* Decompression using a pre-digested Dictionary +* Use dictionary without significant overhead. */ +size_t ZSTD_decompress_usingDDict(ZSTD_DCtx* dctx, + void* dst, size_t dstCapacity, + const void* src, size_t srcSize, + const ZSTD_DDict* ddict) +{ + /* pass content and size in case legacy frames are encountered */ + return ZSTD_decompressMultiFrame(dctx, dst, dstCapacity, src, srcSize, + NULL, 0, + ddict); +} + + +/*===================================== +* Streaming decompression +*====================================*/ + +ZSTD_DStream* ZSTD_createDStream(void) +{ + DEBUGLOG(3, "ZSTD_createDStream"); + return ZSTD_createDCtx_internal(ZSTD_defaultCMem); +} + +ZSTD_DStream* ZSTD_initStaticDStream(void *workspace, size_t workspaceSize) +{ + return ZSTD_initStaticDCtx(workspace, workspaceSize); +} + +ZSTD_DStream* ZSTD_createDStream_advanced(ZSTD_customMem customMem) +{ + return ZSTD_createDCtx_internal(customMem); +} + +size_t ZSTD_freeDStream(ZSTD_DStream* zds) +{ + return ZSTD_freeDCtx(zds); +} + + +/* *** Initialization *** */ + +size_t ZSTD_DStreamInSize(void) { return ZSTD_BLOCKSIZE_MAX + ZSTD_blockHeaderSize; } +size_t ZSTD_DStreamOutSize(void) { return ZSTD_BLOCKSIZE_MAX; } + +size_t ZSTD_DCtx_loadDictionary_advanced(ZSTD_DCtx* dctx, + const void* dict, size_t dictSize, + ZSTD_dictLoadMethod_e dictLoadMethod, + ZSTD_dictContentType_e dictContentType) +{ + RETURN_ERROR_IF(dctx->streamStage != zdss_init, stage_wrong, ""); + ZSTD_clearDict(dctx); + if (dict && dictSize != 0) { + dctx->ddictLocal = ZSTD_createDDict_advanced(dict, dictSize, dictLoadMethod, dictContentType, dctx->customMem); + RETURN_ERROR_IF(dctx->ddictLocal == NULL, memory_allocation, "NULL pointer!"); + dctx->ddict = dctx->ddictLocal; + dctx->dictUses = ZSTD_use_indefinitely; + } + return 0; +} + +size_t ZSTD_DCtx_loadDictionary_byReference(ZSTD_DCtx* dctx, const void* dict, size_t dictSize) +{ + return ZSTD_DCtx_loadDictionary_advanced(dctx, dict, dictSize, ZSTD_dlm_byRef, ZSTD_dct_auto); +} + +size_t ZSTD_DCtx_loadDictionary(ZSTD_DCtx* dctx, const void* dict, size_t dictSize) +{ + return ZSTD_DCtx_loadDictionary_advanced(dctx, dict, dictSize, ZSTD_dlm_byCopy, ZSTD_dct_auto); +} + +size_t ZSTD_DCtx_refPrefix_advanced(ZSTD_DCtx* dctx, const void* prefix, size_t prefixSize, ZSTD_dictContentType_e dictContentType) +{ + FORWARD_IF_ERROR(ZSTD_DCtx_loadDictionary_advanced(dctx, prefix, prefixSize, ZSTD_dlm_byRef, dictContentType), ""); + dctx->dictUses = ZSTD_use_once; + return 0; +} + +size_t ZSTD_DCtx_refPrefix(ZSTD_DCtx* dctx, const void* prefix, size_t prefixSize) +{ + return ZSTD_DCtx_refPrefix_advanced(dctx, prefix, prefixSize, ZSTD_dct_rawContent); +} + + +/* ZSTD_initDStream_usingDict() : + * return : expected size, aka ZSTD_startingInputLength(). + * this function cannot fail */ +size_t ZSTD_initDStream_usingDict(ZSTD_DStream* zds, const void* dict, size_t dictSize) +{ + DEBUGLOG(4, "ZSTD_initDStream_usingDict"); + FORWARD_IF_ERROR( ZSTD_DCtx_reset(zds, ZSTD_reset_session_only) , ""); + FORWARD_IF_ERROR( ZSTD_DCtx_loadDictionary(zds, dict, dictSize) , ""); + return ZSTD_startingInputLength(zds->format); +} + +/* note : this variant can't fail */ +size_t ZSTD_initDStream(ZSTD_DStream* zds) +{ + DEBUGLOG(4, "ZSTD_initDStream"); + return ZSTD_initDStream_usingDDict(zds, NULL); +} + +/* ZSTD_initDStream_usingDDict() : + * ddict will just be referenced, and must outlive decompression session + * this function cannot fail */ +size_t ZSTD_initDStream_usingDDict(ZSTD_DStream* dctx, const ZSTD_DDict* ddict) +{ + FORWARD_IF_ERROR( ZSTD_DCtx_reset(dctx, ZSTD_reset_session_only) , ""); + FORWARD_IF_ERROR( ZSTD_DCtx_refDDict(dctx, ddict) , ""); + return ZSTD_startingInputLength(dctx->format); +} + +/* ZSTD_resetDStream() : + * return : expected size, aka ZSTD_startingInputLength(). + * this function cannot fail */ +size_t ZSTD_resetDStream(ZSTD_DStream* dctx) +{ + FORWARD_IF_ERROR(ZSTD_DCtx_reset(dctx, ZSTD_reset_session_only), ""); + return ZSTD_startingInputLength(dctx->format); +} + + +size_t ZSTD_DCtx_refDDict(ZSTD_DCtx* dctx, const ZSTD_DDict* ddict) +{ + RETURN_ERROR_IF(dctx->streamStage != zdss_init, stage_wrong, ""); + ZSTD_clearDict(dctx); + if (ddict) { + dctx->ddict = ddict; + dctx->dictUses = ZSTD_use_indefinitely; + if (dctx->refMultipleDDicts == ZSTD_rmd_refMultipleDDicts) { + if (dctx->ddictSet == NULL) { + dctx->ddictSet = ZSTD_createDDictHashSet(dctx->customMem); + if (!dctx->ddictSet) { + RETURN_ERROR(memory_allocation, "Failed to allocate memory for hash set!"); + } + } + assert(!dctx->staticSize); /* Impossible: ddictSet cannot have been allocated if static dctx */ + FORWARD_IF_ERROR(ZSTD_DDictHashSet_addDDict(dctx->ddictSet, ddict, dctx->customMem), ""); + } + } + return 0; +} + +/* ZSTD_DCtx_setMaxWindowSize() : + * note : no direct equivalence in ZSTD_DCtx_setParameter, + * since this version sets windowSize, and the other sets windowLog */ +size_t ZSTD_DCtx_setMaxWindowSize(ZSTD_DCtx* dctx, size_t maxWindowSize) +{ + ZSTD_bounds const bounds = ZSTD_dParam_getBounds(ZSTD_d_windowLogMax); + size_t const min = (size_t)1 << bounds.lowerBound; + size_t const max = (size_t)1 << bounds.upperBound; + RETURN_ERROR_IF(dctx->streamStage != zdss_init, stage_wrong, ""); + RETURN_ERROR_IF(maxWindowSize < min, parameter_outOfBound, ""); + RETURN_ERROR_IF(maxWindowSize > max, parameter_outOfBound, ""); + dctx->maxWindowSize = maxWindowSize; + return 0; +} + +size_t ZSTD_DCtx_setFormat(ZSTD_DCtx* dctx, ZSTD_format_e format) +{ + return ZSTD_DCtx_setParameter(dctx, ZSTD_d_format, (int)format); +} + +ZSTD_bounds ZSTD_dParam_getBounds(ZSTD_dParameter dParam) +{ + ZSTD_bounds bounds = { 0, 0, 0 }; + switch(dParam) { + case ZSTD_d_windowLogMax: + bounds.lowerBound = ZSTD_WINDOWLOG_ABSOLUTEMIN; + bounds.upperBound = ZSTD_WINDOWLOG_MAX; + return bounds; + case ZSTD_d_format: + bounds.lowerBound = (int)ZSTD_f_zstd1; + bounds.upperBound = (int)ZSTD_f_zstd1_magicless; + ZSTD_STATIC_ASSERT(ZSTD_f_zstd1 < ZSTD_f_zstd1_magicless); + return bounds; + case ZSTD_d_stableOutBuffer: + bounds.lowerBound = (int)ZSTD_bm_buffered; + bounds.upperBound = (int)ZSTD_bm_stable; + return bounds; + case ZSTD_d_forceIgnoreChecksum: + bounds.lowerBound = (int)ZSTD_d_validateChecksum; + bounds.upperBound = (int)ZSTD_d_ignoreChecksum; + return bounds; + case ZSTD_d_refMultipleDDicts: + bounds.lowerBound = (int)ZSTD_rmd_refSingleDDict; + bounds.upperBound = (int)ZSTD_rmd_refMultipleDDicts; + return bounds; + default:; + } + bounds.error = ERROR(parameter_unsupported); + return bounds; +} + +/* ZSTD_dParam_withinBounds: + * @return 1 if value is within dParam bounds, + * 0 otherwise */ +static int ZSTD_dParam_withinBounds(ZSTD_dParameter dParam, int value) +{ + ZSTD_bounds const bounds = ZSTD_dParam_getBounds(dParam); + if (ZSTD_isError(bounds.error)) return 0; + if (value < bounds.lowerBound) return 0; + if (value > bounds.upperBound) return 0; + return 1; +} + +#define CHECK_DBOUNDS(p,v) { \ + RETURN_ERROR_IF(!ZSTD_dParam_withinBounds(p, v), parameter_outOfBound, ""); \ +} + +size_t ZSTD_DCtx_getParameter(ZSTD_DCtx* dctx, ZSTD_dParameter param, int* value) +{ + switch (param) { + case ZSTD_d_windowLogMax: + *value = (int)ZSTD_highbit32((U32)dctx->maxWindowSize); + return 0; + case ZSTD_d_format: + *value = (int)dctx->format; + return 0; + case ZSTD_d_stableOutBuffer: + *value = (int)dctx->outBufferMode; + return 0; + case ZSTD_d_forceIgnoreChecksum: + *value = (int)dctx->forceIgnoreChecksum; + return 0; + case ZSTD_d_refMultipleDDicts: + *value = (int)dctx->refMultipleDDicts; + return 0; + default:; + } + RETURN_ERROR(parameter_unsupported, ""); +} + +size_t ZSTD_DCtx_setParameter(ZSTD_DCtx* dctx, ZSTD_dParameter dParam, int value) +{ + RETURN_ERROR_IF(dctx->streamStage != zdss_init, stage_wrong, ""); + switch(dParam) { + case ZSTD_d_windowLogMax: + if (value == 0) value = ZSTD_WINDOWLOG_LIMIT_DEFAULT; + CHECK_DBOUNDS(ZSTD_d_windowLogMax, value); + dctx->maxWindowSize = ((size_t)1) << value; + return 0; + case ZSTD_d_format: + CHECK_DBOUNDS(ZSTD_d_format, value); + dctx->format = (ZSTD_format_e)value; + return 0; + case ZSTD_d_stableOutBuffer: + CHECK_DBOUNDS(ZSTD_d_stableOutBuffer, value); + dctx->outBufferMode = (ZSTD_bufferMode_e)value; + return 0; + case ZSTD_d_forceIgnoreChecksum: + CHECK_DBOUNDS(ZSTD_d_forceIgnoreChecksum, value); + dctx->forceIgnoreChecksum = (ZSTD_forceIgnoreChecksum_e)value; + return 0; + case ZSTD_d_refMultipleDDicts: + CHECK_DBOUNDS(ZSTD_d_refMultipleDDicts, value); + if (dctx->staticSize != 0) { + RETURN_ERROR(parameter_unsupported, "Static dctx does not support multiple DDicts!"); + } + dctx->refMultipleDDicts = (ZSTD_refMultipleDDicts_e)value; + return 0; + default:; + } + RETURN_ERROR(parameter_unsupported, ""); +} + +size_t ZSTD_DCtx_reset(ZSTD_DCtx* dctx, ZSTD_ResetDirective reset) +{ + if ( (reset == ZSTD_reset_session_only) + || (reset == ZSTD_reset_session_and_parameters) ) { + dctx->streamStage = zdss_init; + dctx->noForwardProgress = 0; + } + if ( (reset == ZSTD_reset_parameters) + || (reset == ZSTD_reset_session_and_parameters) ) { + RETURN_ERROR_IF(dctx->streamStage != zdss_init, stage_wrong, ""); + ZSTD_clearDict(dctx); + ZSTD_DCtx_resetParameters(dctx); + } + return 0; +} + + +size_t ZSTD_sizeof_DStream(const ZSTD_DStream* dctx) +{ + return ZSTD_sizeof_DCtx(dctx); +} + +size_t ZSTD_decodingBufferSize_min(unsigned long long windowSize, unsigned long long frameContentSize) +{ + size_t const blockSize = (size_t) MIN(windowSize, ZSTD_BLOCKSIZE_MAX); + /* space is needed to store the litbuffer after the output of a given block without stomping the extDict of a previous run, as well as to cover both windows against wildcopy*/ + unsigned long long const neededRBSize = windowSize + blockSize + ZSTD_BLOCKSIZE_MAX + (WILDCOPY_OVERLENGTH * 2); + unsigned long long const neededSize = MIN(frameContentSize, neededRBSize); + size_t const minRBSize = (size_t) neededSize; + RETURN_ERROR_IF((unsigned long long)minRBSize != neededSize, + frameParameter_windowTooLarge, ""); + return minRBSize; +} + +size_t ZSTD_estimateDStreamSize(size_t windowSize) +{ + size_t const blockSize = MIN(windowSize, ZSTD_BLOCKSIZE_MAX); + size_t const inBuffSize = blockSize; /* no block can be larger */ + size_t const outBuffSize = ZSTD_decodingBufferSize_min(windowSize, ZSTD_CONTENTSIZE_UNKNOWN); + return ZSTD_estimateDCtxSize() + inBuffSize + outBuffSize; +} + +size_t ZSTD_estimateDStreamSize_fromFrame(const void* src, size_t srcSize) +{ + U32 const windowSizeMax = 1U << ZSTD_WINDOWLOG_MAX; /* note : should be user-selectable, but requires an additional parameter (or a dctx) */ + ZSTD_frameHeader zfh; + size_t const err = ZSTD_getFrameHeader(&zfh, src, srcSize); + if (ZSTD_isError(err)) return err; + RETURN_ERROR_IF(err>0, srcSize_wrong, ""); + RETURN_ERROR_IF(zfh.windowSize > windowSizeMax, + frameParameter_windowTooLarge, ""); + return ZSTD_estimateDStreamSize((size_t)zfh.windowSize); +} + + +/* ***** Decompression ***** */ + +static int ZSTD_DCtx_isOverflow(ZSTD_DStream* zds, size_t const neededInBuffSize, size_t const neededOutBuffSize) +{ + return (zds->inBuffSize + zds->outBuffSize) >= (neededInBuffSize + neededOutBuffSize) * ZSTD_WORKSPACETOOLARGE_FACTOR; +} + +static void ZSTD_DCtx_updateOversizedDuration(ZSTD_DStream* zds, size_t const neededInBuffSize, size_t const neededOutBuffSize) +{ + if (ZSTD_DCtx_isOverflow(zds, neededInBuffSize, neededOutBuffSize)) + zds->oversizedDuration++; + else + zds->oversizedDuration = 0; +} + +static int ZSTD_DCtx_isOversizedTooLong(ZSTD_DStream* zds) +{ + return zds->oversizedDuration >= ZSTD_WORKSPACETOOLARGE_MAXDURATION; +} + +/* Checks that the output buffer hasn't changed if ZSTD_obm_stable is used. */ +static size_t ZSTD_checkOutBuffer(ZSTD_DStream const* zds, ZSTD_outBuffer const* output) +{ + ZSTD_outBuffer const expect = zds->expectedOutBuffer; + /* No requirement when ZSTD_obm_stable is not enabled. */ + if (zds->outBufferMode != ZSTD_bm_stable) + return 0; + /* Any buffer is allowed in zdss_init, this must be the same for every other call until + * the context is reset. + */ + if (zds->streamStage == zdss_init) + return 0; + /* The buffer must match our expectation exactly. */ + if (expect.dst == output->dst && expect.pos == output->pos && expect.size == output->size) + return 0; + RETURN_ERROR(dstBuffer_wrong, "ZSTD_d_stableOutBuffer enabled but output differs!"); +} + +/* Calls ZSTD_decompressContinue() with the right parameters for ZSTD_decompressStream() + * and updates the stage and the output buffer state. This call is extracted so it can be + * used both when reading directly from the ZSTD_inBuffer, and in buffered input mode. + * NOTE: You must break after calling this function since the streamStage is modified. + */ +static size_t ZSTD_decompressContinueStream( + ZSTD_DStream* zds, char** op, char* oend, + void const* src, size_t srcSize) { + int const isSkipFrame = ZSTD_isSkipFrame(zds); + if (zds->outBufferMode == ZSTD_bm_buffered) { + size_t const dstSize = isSkipFrame ? 0 : zds->outBuffSize - zds->outStart; + size_t const decodedSize = ZSTD_decompressContinue(zds, + zds->outBuff + zds->outStart, dstSize, src, srcSize); + FORWARD_IF_ERROR(decodedSize, ""); + if (!decodedSize && !isSkipFrame) { + zds->streamStage = zdss_read; + } else { + zds->outEnd = zds->outStart + decodedSize; + zds->streamStage = zdss_flush; + } + } else { + /* Write directly into the output buffer */ + size_t const dstSize = isSkipFrame ? 0 : (size_t)(oend - *op); + size_t const decodedSize = ZSTD_decompressContinue(zds, *op, dstSize, src, srcSize); + FORWARD_IF_ERROR(decodedSize, ""); + *op += decodedSize; + /* Flushing is not needed. */ + zds->streamStage = zdss_read; + assert(*op <= oend); + assert(zds->outBufferMode == ZSTD_bm_stable); + } + return 0; +} + +size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* output, ZSTD_inBuffer* input) +{ + const char* const src = (const char*)input->src; + const char* const istart = input->pos != 0 ? src + input->pos : src; + const char* const iend = input->size != 0 ? src + input->size : src; + const char* ip = istart; + char* const dst = (char*)output->dst; + char* const ostart = output->pos != 0 ? dst + output->pos : dst; + char* const oend = output->size != 0 ? dst + output->size : dst; + char* op = ostart; + U32 someMoreWork = 1; + + DEBUGLOG(5, "ZSTD_decompressStream"); + RETURN_ERROR_IF( + input->pos > input->size, + srcSize_wrong, + "forbidden. in: pos: %u vs size: %u", + (U32)input->pos, (U32)input->size); + RETURN_ERROR_IF( + output->pos > output->size, + dstSize_tooSmall, + "forbidden. out: pos: %u vs size: %u", + (U32)output->pos, (U32)output->size); + DEBUGLOG(5, "input size : %u", (U32)(input->size - input->pos)); + FORWARD_IF_ERROR(ZSTD_checkOutBuffer(zds, output), ""); + + while (someMoreWork) { + switch(zds->streamStage) + { + case zdss_init : + DEBUGLOG(5, "stage zdss_init => transparent reset "); + zds->streamStage = zdss_loadHeader; + zds->lhSize = zds->inPos = zds->outStart = zds->outEnd = 0; +#if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT>=1) + zds->legacyVersion = 0; +#endif + zds->hostageByte = 0; + zds->expectedOutBuffer = *output; + ZSTD_FALLTHROUGH; + + case zdss_loadHeader : + DEBUGLOG(5, "stage zdss_loadHeader (srcSize : %u)", (U32)(iend - ip)); +#if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT>=1) + if (zds->legacyVersion) { + RETURN_ERROR_IF(zds->staticSize, memory_allocation, + "legacy support is incompatible with static dctx"); + { size_t const hint = ZSTD_decompressLegacyStream(zds->legacyContext, zds->legacyVersion, output, input); + if (hint==0) zds->streamStage = zdss_init; + return hint; + } } +#endif + { size_t const hSize = ZSTD_getFrameHeader_advanced(&zds->fParams, zds->headerBuffer, zds->lhSize, zds->format); + if (zds->refMultipleDDicts && zds->ddictSet) { + ZSTD_DCtx_selectFrameDDict(zds); + } + DEBUGLOG(5, "header size : %u", (U32)hSize); + if (ZSTD_isError(hSize)) { +#if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT>=1) + U32 const legacyVersion = ZSTD_isLegacy(istart, iend-istart); + if (legacyVersion) { + ZSTD_DDict const* const ddict = ZSTD_getDDict(zds); + const void* const dict = ddict ? ZSTD_DDict_dictContent(ddict) : NULL; + size_t const dictSize = ddict ? ZSTD_DDict_dictSize(ddict) : 0; + DEBUGLOG(5, "ZSTD_decompressStream: detected legacy version v0.%u", legacyVersion); + RETURN_ERROR_IF(zds->staticSize, memory_allocation, + "legacy support is incompatible with static dctx"); + FORWARD_IF_ERROR(ZSTD_initLegacyStream(&zds->legacyContext, + zds->previousLegacyVersion, legacyVersion, + dict, dictSize), ""); + zds->legacyVersion = zds->previousLegacyVersion = legacyVersion; + { size_t const hint = ZSTD_decompressLegacyStream(zds->legacyContext, legacyVersion, output, input); + if (hint==0) zds->streamStage = zdss_init; /* or stay in stage zdss_loadHeader */ + return hint; + } } +#endif + return hSize; /* error */ + } + if (hSize != 0) { /* need more input */ + size_t const toLoad = hSize - zds->lhSize; /* if hSize!=0, hSize > zds->lhSize */ + size_t const remainingInput = (size_t)(iend-ip); + assert(iend >= ip); + if (toLoad > remainingInput) { /* not enough input to load full header */ + if (remainingInput > 0) { + ZSTD_memcpy(zds->headerBuffer + zds->lhSize, ip, remainingInput); + zds->lhSize += remainingInput; + } + input->pos = input->size; + return (MAX((size_t)ZSTD_FRAMEHEADERSIZE_MIN(zds->format), hSize) - zds->lhSize) + ZSTD_blockHeaderSize; /* remaining header bytes + next block header */ + } + assert(ip != NULL); + ZSTD_memcpy(zds->headerBuffer + zds->lhSize, ip, toLoad); zds->lhSize = hSize; ip += toLoad; + break; + } } + + /* check for single-pass mode opportunity */ + if (zds->fParams.frameContentSize != ZSTD_CONTENTSIZE_UNKNOWN + && zds->fParams.frameType != ZSTD_skippableFrame + && (U64)(size_t)(oend-op) >= zds->fParams.frameContentSize) { + size_t const cSize = ZSTD_findFrameCompressedSize(istart, (size_t)(iend-istart)); + if (cSize <= (size_t)(iend-istart)) { + /* shortcut : using single-pass mode */ + size_t const decompressedSize = ZSTD_decompress_usingDDict(zds, op, (size_t)(oend-op), istart, cSize, ZSTD_getDDict(zds)); + if (ZSTD_isError(decompressedSize)) return decompressedSize; + DEBUGLOG(4, "shortcut to single-pass ZSTD_decompress_usingDDict()") + ip = istart + cSize; + op += decompressedSize; + zds->expected = 0; + zds->streamStage = zdss_init; + someMoreWork = 0; + break; + } } + + /* Check output buffer is large enough for ZSTD_odm_stable. */ + if (zds->outBufferMode == ZSTD_bm_stable + && zds->fParams.frameType != ZSTD_skippableFrame + && zds->fParams.frameContentSize != ZSTD_CONTENTSIZE_UNKNOWN + && (U64)(size_t)(oend-op) < zds->fParams.frameContentSize) { + RETURN_ERROR(dstSize_tooSmall, "ZSTD_obm_stable passed but ZSTD_outBuffer is too small"); + } + + /* Consume header (see ZSTDds_decodeFrameHeader) */ + DEBUGLOG(4, "Consume header"); + FORWARD_IF_ERROR(ZSTD_decompressBegin_usingDDict(zds, ZSTD_getDDict(zds)), ""); + + if ((MEM_readLE32(zds->headerBuffer) & ZSTD_MAGIC_SKIPPABLE_MASK) == ZSTD_MAGIC_SKIPPABLE_START) { /* skippable frame */ + zds->expected = MEM_readLE32(zds->headerBuffer + ZSTD_FRAMEIDSIZE); + zds->stage = ZSTDds_skipFrame; + } else { + FORWARD_IF_ERROR(ZSTD_decodeFrameHeader(zds, zds->headerBuffer, zds->lhSize), ""); + zds->expected = ZSTD_blockHeaderSize; + zds->stage = ZSTDds_decodeBlockHeader; + } + + /* control buffer memory usage */ + DEBUGLOG(4, "Control max memory usage (%u KB <= max %u KB)", + (U32)(zds->fParams.windowSize >>10), + (U32)(zds->maxWindowSize >> 10) ); + zds->fParams.windowSize = MAX(zds->fParams.windowSize, 1U << ZSTD_WINDOWLOG_ABSOLUTEMIN); + RETURN_ERROR_IF(zds->fParams.windowSize > zds->maxWindowSize, + frameParameter_windowTooLarge, ""); + + /* Adapt buffer sizes to frame header instructions */ + { size_t const neededInBuffSize = MAX(zds->fParams.blockSizeMax, 4 /* frame checksum */); + size_t const neededOutBuffSize = zds->outBufferMode == ZSTD_bm_buffered + ? ZSTD_decodingBufferSize_min(zds->fParams.windowSize, zds->fParams.frameContentSize) + : 0; + + ZSTD_DCtx_updateOversizedDuration(zds, neededInBuffSize, neededOutBuffSize); + + { int const tooSmall = (zds->inBuffSize < neededInBuffSize) || (zds->outBuffSize < neededOutBuffSize); + int const tooLarge = ZSTD_DCtx_isOversizedTooLong(zds); + + if (tooSmall || tooLarge) { + size_t const bufferSize = neededInBuffSize + neededOutBuffSize; + DEBUGLOG(4, "inBuff : from %u to %u", + (U32)zds->inBuffSize, (U32)neededInBuffSize); + DEBUGLOG(4, "outBuff : from %u to %u", + (U32)zds->outBuffSize, (U32)neededOutBuffSize); + if (zds->staticSize) { /* static DCtx */ + DEBUGLOG(4, "staticSize : %u", (U32)zds->staticSize); + assert(zds->staticSize >= sizeof(ZSTD_DCtx)); /* controlled at init */ + RETURN_ERROR_IF( + bufferSize > zds->staticSize - sizeof(ZSTD_DCtx), + memory_allocation, ""); + } else { + ZSTD_customFree(zds->inBuff, zds->customMem); + zds->inBuffSize = 0; + zds->outBuffSize = 0; + zds->inBuff = (char*)ZSTD_customMalloc(bufferSize, zds->customMem); + RETURN_ERROR_IF(zds->inBuff == NULL, memory_allocation, ""); + } + zds->inBuffSize = neededInBuffSize; + zds->outBuff = zds->inBuff + zds->inBuffSize; + zds->outBuffSize = neededOutBuffSize; + } } } + zds->streamStage = zdss_read; + ZSTD_FALLTHROUGH; + + case zdss_read: + DEBUGLOG(5, "stage zdss_read"); + { size_t const neededInSize = ZSTD_nextSrcSizeToDecompressWithInputSize(zds, (size_t)(iend - ip)); + DEBUGLOG(5, "neededInSize = %u", (U32)neededInSize); + if (neededInSize==0) { /* end of frame */ + zds->streamStage = zdss_init; + someMoreWork = 0; + break; + } + if ((size_t)(iend-ip) >= neededInSize) { /* decode directly from src */ + FORWARD_IF_ERROR(ZSTD_decompressContinueStream(zds, &op, oend, ip, neededInSize), ""); + ip += neededInSize; + /* Function modifies the stage so we must break */ + break; + } } + if (ip==iend) { someMoreWork = 0; break; } /* no more input */ + zds->streamStage = zdss_load; + ZSTD_FALLTHROUGH; + + case zdss_load: + { size_t const neededInSize = ZSTD_nextSrcSizeToDecompress(zds); + size_t const toLoad = neededInSize - zds->inPos; + int const isSkipFrame = ZSTD_isSkipFrame(zds); + size_t loadedSize; + /* At this point we shouldn't be decompressing a block that we can stream. */ + assert(neededInSize == ZSTD_nextSrcSizeToDecompressWithInputSize(zds, iend - ip)); + if (isSkipFrame) { + loadedSize = MIN(toLoad, (size_t)(iend-ip)); + } else { + RETURN_ERROR_IF(toLoad > zds->inBuffSize - zds->inPos, + corruption_detected, + "should never happen"); + loadedSize = ZSTD_limitCopy(zds->inBuff + zds->inPos, toLoad, ip, (size_t)(iend-ip)); + } + ip += loadedSize; + zds->inPos += loadedSize; + if (loadedSize < toLoad) { someMoreWork = 0; break; } /* not enough input, wait for more */ + + /* decode loaded input */ + zds->inPos = 0; /* input is consumed */ + FORWARD_IF_ERROR(ZSTD_decompressContinueStream(zds, &op, oend, zds->inBuff, neededInSize), ""); + /* Function modifies the stage so we must break */ + break; + } + case zdss_flush: + { size_t const toFlushSize = zds->outEnd - zds->outStart; + size_t const flushedSize = ZSTD_limitCopy(op, (size_t)(oend-op), zds->outBuff + zds->outStart, toFlushSize); + op += flushedSize; + zds->outStart += flushedSize; + if (flushedSize == toFlushSize) { /* flush completed */ + zds->streamStage = zdss_read; + if ( (zds->outBuffSize < zds->fParams.frameContentSize) + && (zds->outStart + zds->fParams.blockSizeMax > zds->outBuffSize) ) { + DEBUGLOG(5, "restart filling outBuff from beginning (left:%i, needed:%u)", + (int)(zds->outBuffSize - zds->outStart), + (U32)zds->fParams.blockSizeMax); + zds->outStart = zds->outEnd = 0; + } + break; + } } + /* cannot complete flush */ + someMoreWork = 0; + break; + + default: + assert(0); /* impossible */ + RETURN_ERROR(GENERIC, "impossible to reach"); /* some compiler require default to do something */ + } } + + /* result */ + input->pos = (size_t)(ip - (const char*)(input->src)); + output->pos = (size_t)(op - (char*)(output->dst)); + + /* Update the expected output buffer for ZSTD_obm_stable. */ + zds->expectedOutBuffer = *output; + + if ((ip==istart) && (op==ostart)) { /* no forward progress */ + zds->noForwardProgress ++; + if (zds->noForwardProgress >= ZSTD_NO_FORWARD_PROGRESS_MAX) { + RETURN_ERROR_IF(op==oend, dstSize_tooSmall, ""); + RETURN_ERROR_IF(ip==iend, srcSize_wrong, ""); + assert(0); + } + } else { + zds->noForwardProgress = 0; + } + { size_t nextSrcSizeHint = ZSTD_nextSrcSizeToDecompress(zds); + if (!nextSrcSizeHint) { /* frame fully decoded */ + if (zds->outEnd == zds->outStart) { /* output fully flushed */ + if (zds->hostageByte) { + if (input->pos >= input->size) { + /* can't release hostage (not present) */ + zds->streamStage = zdss_read; + return 1; + } + input->pos++; /* release hostage */ + } /* zds->hostageByte */ + return 0; + } /* zds->outEnd == zds->outStart */ + if (!zds->hostageByte) { /* output not fully flushed; keep last byte as hostage; will be released when all output is flushed */ + input->pos--; /* note : pos > 0, otherwise, impossible to finish reading last block */ + zds->hostageByte=1; + } + return 1; + } /* nextSrcSizeHint==0 */ + nextSrcSizeHint += ZSTD_blockHeaderSize * (ZSTD_nextInputType(zds) == ZSTDnit_block); /* preload header of next block */ + assert(zds->inPos <= nextSrcSizeHint); + nextSrcSizeHint -= zds->inPos; /* part already loaded*/ + return nextSrcSizeHint; + } +} + +size_t ZSTD_decompressStream_simpleArgs ( + ZSTD_DCtx* dctx, + void* dst, size_t dstCapacity, size_t* dstPos, + const void* src, size_t srcSize, size_t* srcPos) +{ + ZSTD_outBuffer output = { dst, dstCapacity, *dstPos }; + ZSTD_inBuffer input = { src, srcSize, *srcPos }; + /* ZSTD_compress_generic() will check validity of dstPos and srcPos */ + size_t const cErr = ZSTD_decompressStream(dctx, &output, &input); + *dstPos = output.pos; + *srcPos = input.pos; + return cErr; +} diff --git a/stage1/zstd/lib/decompress/zstd_decompress_block.c b/stage1/zstd/lib/decompress/zstd_decompress_block.c new file mode 100644 index 000000000000..2e44d30d2f37 --- /dev/null +++ b/stage1/zstd/lib/decompress/zstd_decompress_block.c @@ -0,0 +1,2072 @@ +/* + * Copyright (c) Yann Collet, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under both the BSD-style license (found in the + * LICENSE file in the root directory of this source tree) and the GPLv2 (found + * in the COPYING file in the root directory of this source tree). + * You may select, at your option, one of the above-listed licenses. + */ + +/* zstd_decompress_block : + * this module takes care of decompressing _compressed_ block */ + +/*-******************************************************* +* Dependencies +*********************************************************/ +#include "../common/zstd_deps.h" /* ZSTD_memcpy, ZSTD_memmove, ZSTD_memset */ +#include "../common/compiler.h" /* prefetch */ +#include "../common/cpu.h" /* bmi2 */ +#include "../common/mem.h" /* low level memory routines */ +#define FSE_STATIC_LINKING_ONLY +#include "../common/fse.h" +#define HUF_STATIC_LINKING_ONLY +#include "../common/huf.h" +#include "../common/zstd_internal.h" +#include "zstd_decompress_internal.h" /* ZSTD_DCtx */ +#include "zstd_ddict.h" /* ZSTD_DDictDictContent */ +#include "zstd_decompress_block.h" + +/*_******************************************************* +* Macros +**********************************************************/ + +/* These two optional macros force the use one way or another of the two + * ZSTD_decompressSequences implementations. You can't force in both directions + * at the same time. + */ +#if defined(ZSTD_FORCE_DECOMPRESS_SEQUENCES_SHORT) && \ + defined(ZSTD_FORCE_DECOMPRESS_SEQUENCES_LONG) +#error "Cannot force the use of the short and the long ZSTD_decompressSequences variants!" +#endif + + +/*_******************************************************* +* Memory operations +**********************************************************/ +static void ZSTD_copy4(void* dst, const void* src) { ZSTD_memcpy(dst, src, 4); } + + +/*-************************************************************* + * Block decoding + ***************************************************************/ + +/*! ZSTD_getcBlockSize() : + * Provides the size of compressed block from block header `src` */ +size_t ZSTD_getcBlockSize(const void* src, size_t srcSize, + blockProperties_t* bpPtr) +{ + RETURN_ERROR_IF(srcSize < ZSTD_blockHeaderSize, srcSize_wrong, ""); + + { U32 const cBlockHeader = MEM_readLE24(src); + U32 const cSize = cBlockHeader >> 3; + bpPtr->lastBlock = cBlockHeader & 1; + bpPtr->blockType = (blockType_e)((cBlockHeader >> 1) & 3); + bpPtr->origSize = cSize; /* only useful for RLE */ + if (bpPtr->blockType == bt_rle) return 1; + RETURN_ERROR_IF(bpPtr->blockType == bt_reserved, corruption_detected, ""); + return cSize; + } +} + +/* Allocate buffer for literals, either overlapping current dst, or split between dst and litExtraBuffer, or stored entirely within litExtraBuffer */ +static void ZSTD_allocateLiteralsBuffer(ZSTD_DCtx* dctx, void* const dst, const size_t dstCapacity, const size_t litSize, + const streaming_operation streaming, const size_t expectedWriteSize, const unsigned splitImmediately) +{ + if (streaming == not_streaming && dstCapacity > ZSTD_BLOCKSIZE_MAX + WILDCOPY_OVERLENGTH + litSize + WILDCOPY_OVERLENGTH) + { + /* room for litbuffer to fit without read faulting */ + dctx->litBuffer = (BYTE*)dst + ZSTD_BLOCKSIZE_MAX + WILDCOPY_OVERLENGTH; + dctx->litBufferEnd = dctx->litBuffer + litSize; + dctx->litBufferLocation = ZSTD_in_dst; + } + else if (litSize > ZSTD_LITBUFFEREXTRASIZE) + { + /* won't fit in litExtraBuffer, so it will be split between end of dst and extra buffer */ + if (splitImmediately) { + /* won't fit in litExtraBuffer, so it will be split between end of dst and extra buffer */ + dctx->litBuffer = (BYTE*)dst + expectedWriteSize - litSize + ZSTD_LITBUFFEREXTRASIZE - WILDCOPY_OVERLENGTH; + dctx->litBufferEnd = dctx->litBuffer + litSize - ZSTD_LITBUFFEREXTRASIZE; + } + else { + /* initially this will be stored entirely in dst during huffman decoding, it will partially shifted to litExtraBuffer after */ + dctx->litBuffer = (BYTE*)dst + expectedWriteSize - litSize; + dctx->litBufferEnd = (BYTE*)dst + expectedWriteSize; + } + dctx->litBufferLocation = ZSTD_split; + } + else + { + /* fits entirely within litExtraBuffer, so no split is necessary */ + dctx->litBuffer = dctx->litExtraBuffer; + dctx->litBufferEnd = dctx->litBuffer + litSize; + dctx->litBufferLocation = ZSTD_not_in_dst; + } +} + +/* Hidden declaration for fullbench */ +size_t ZSTD_decodeLiteralsBlock(ZSTD_DCtx* dctx, + const void* src, size_t srcSize, + void* dst, size_t dstCapacity, const streaming_operation streaming); +/*! ZSTD_decodeLiteralsBlock() : + * Where it is possible to do so without being stomped by the output during decompression, the literals block will be stored + * in the dstBuffer. If there is room to do so, it will be stored in full in the excess dst space after where the current + * block will be output. Otherwise it will be stored at the end of the current dst blockspace, with a small portion being + * stored in dctx->litExtraBuffer to help keep it "ahead" of the current output write. + * + * @return : nb of bytes read from src (< srcSize ) + * note : symbol not declared but exposed for fullbench */ +size_t ZSTD_decodeLiteralsBlock(ZSTD_DCtx* dctx, + const void* src, size_t srcSize, /* note : srcSize < BLOCKSIZE */ + void* dst, size_t dstCapacity, const streaming_operation streaming) +{ + DEBUGLOG(5, "ZSTD_decodeLiteralsBlock"); + RETURN_ERROR_IF(srcSize < MIN_CBLOCK_SIZE, corruption_detected, ""); + + { const BYTE* const istart = (const BYTE*) src; + symbolEncodingType_e const litEncType = (symbolEncodingType_e)(istart[0] & 3); + + switch(litEncType) + { + case set_repeat: + DEBUGLOG(5, "set_repeat flag : re-using stats from previous compressed literals block"); + RETURN_ERROR_IF(dctx->litEntropy==0, dictionary_corrupted, ""); + ZSTD_FALLTHROUGH; + + case set_compressed: + RETURN_ERROR_IF(srcSize < 5, corruption_detected, "srcSize >= MIN_CBLOCK_SIZE == 3; here we need up to 5 for case 3"); + { size_t lhSize, litSize, litCSize; + U32 singleStream=0; + U32 const lhlCode = (istart[0] >> 2) & 3; + U32 const lhc = MEM_readLE32(istart); + size_t hufSuccess; + size_t expectedWriteSize = MIN(ZSTD_BLOCKSIZE_MAX, dstCapacity); + switch(lhlCode) + { + case 0: case 1: default: /* note : default is impossible, since lhlCode into [0..3] */ + /* 2 - 2 - 10 - 10 */ + singleStream = !lhlCode; + lhSize = 3; + litSize = (lhc >> 4) & 0x3FF; + litCSize = (lhc >> 14) & 0x3FF; + break; + case 2: + /* 2 - 2 - 14 - 14 */ + lhSize = 4; + litSize = (lhc >> 4) & 0x3FFF; + litCSize = lhc >> 18; + break; + case 3: + /* 2 - 2 - 18 - 18 */ + lhSize = 5; + litSize = (lhc >> 4) & 0x3FFFF; + litCSize = (lhc >> 22) + ((size_t)istart[4] << 10); + break; + } + RETURN_ERROR_IF(litSize > 0 && dst == NULL, dstSize_tooSmall, "NULL not handled"); + RETURN_ERROR_IF(litSize > ZSTD_BLOCKSIZE_MAX, corruption_detected, ""); + RETURN_ERROR_IF(litCSize + lhSize > srcSize, corruption_detected, ""); + RETURN_ERROR_IF(expectedWriteSize < litSize , dstSize_tooSmall, ""); + ZSTD_allocateLiteralsBuffer(dctx, dst, dstCapacity, litSize, streaming, expectedWriteSize, 0); + + /* prefetch huffman table if cold */ + if (dctx->ddictIsCold && (litSize > 768 /* heuristic */)) { + PREFETCH_AREA(dctx->HUFptr, sizeof(dctx->entropy.hufTable)); + } + + if (litEncType==set_repeat) { + if (singleStream) { + hufSuccess = HUF_decompress1X_usingDTable_bmi2( + dctx->litBuffer, litSize, istart+lhSize, litCSize, + dctx->HUFptr, ZSTD_DCtx_get_bmi2(dctx)); + } else { + hufSuccess = HUF_decompress4X_usingDTable_bmi2( + dctx->litBuffer, litSize, istart+lhSize, litCSize, + dctx->HUFptr, ZSTD_DCtx_get_bmi2(dctx)); + } + } else { + if (singleStream) { +#if defined(HUF_FORCE_DECOMPRESS_X2) + hufSuccess = HUF_decompress1X_DCtx_wksp( + dctx->entropy.hufTable, dctx->litBuffer, litSize, + istart+lhSize, litCSize, dctx->workspace, + sizeof(dctx->workspace)); +#else + hufSuccess = HUF_decompress1X1_DCtx_wksp_bmi2( + dctx->entropy.hufTable, dctx->litBuffer, litSize, + istart+lhSize, litCSize, dctx->workspace, + sizeof(dctx->workspace), ZSTD_DCtx_get_bmi2(dctx)); +#endif + } else { + hufSuccess = HUF_decompress4X_hufOnly_wksp_bmi2( + dctx->entropy.hufTable, dctx->litBuffer, litSize, + istart+lhSize, litCSize, dctx->workspace, + sizeof(dctx->workspace), ZSTD_DCtx_get_bmi2(dctx)); + } + } + if (dctx->litBufferLocation == ZSTD_split) + { + ZSTD_memcpy(dctx->litExtraBuffer, dctx->litBufferEnd - ZSTD_LITBUFFEREXTRASIZE, ZSTD_LITBUFFEREXTRASIZE); + ZSTD_memmove(dctx->litBuffer + ZSTD_LITBUFFEREXTRASIZE - WILDCOPY_OVERLENGTH, dctx->litBuffer, litSize - ZSTD_LITBUFFEREXTRASIZE); + dctx->litBuffer += ZSTD_LITBUFFEREXTRASIZE - WILDCOPY_OVERLENGTH; + dctx->litBufferEnd -= WILDCOPY_OVERLENGTH; + } + + RETURN_ERROR_IF(HUF_isError(hufSuccess), corruption_detected, ""); + + dctx->litPtr = dctx->litBuffer; + dctx->litSize = litSize; + dctx->litEntropy = 1; + if (litEncType==set_compressed) dctx->HUFptr = dctx->entropy.hufTable; + return litCSize + lhSize; + } + + case set_basic: + { size_t litSize, lhSize; + U32 const lhlCode = ((istart[0]) >> 2) & 3; + size_t expectedWriteSize = MIN(ZSTD_BLOCKSIZE_MAX, dstCapacity); + switch(lhlCode) + { + case 0: case 2: default: /* note : default is impossible, since lhlCode into [0..3] */ + lhSize = 1; + litSize = istart[0] >> 3; + break; + case 1: + lhSize = 2; + litSize = MEM_readLE16(istart) >> 4; + break; + case 3: + lhSize = 3; + litSize = MEM_readLE24(istart) >> 4; + break; + } + + RETURN_ERROR_IF(litSize > 0 && dst == NULL, dstSize_tooSmall, "NULL not handled"); + RETURN_ERROR_IF(expectedWriteSize < litSize, dstSize_tooSmall, ""); + ZSTD_allocateLiteralsBuffer(dctx, dst, dstCapacity, litSize, streaming, expectedWriteSize, 1); + if (lhSize+litSize+WILDCOPY_OVERLENGTH > srcSize) { /* risk reading beyond src buffer with wildcopy */ + RETURN_ERROR_IF(litSize+lhSize > srcSize, corruption_detected, ""); + if (dctx->litBufferLocation == ZSTD_split) + { + ZSTD_memcpy(dctx->litBuffer, istart + lhSize, litSize - ZSTD_LITBUFFEREXTRASIZE); + ZSTD_memcpy(dctx->litExtraBuffer, istart + lhSize + litSize - ZSTD_LITBUFFEREXTRASIZE, ZSTD_LITBUFFEREXTRASIZE); + } + else + { + ZSTD_memcpy(dctx->litBuffer, istart + lhSize, litSize); + } + dctx->litPtr = dctx->litBuffer; + dctx->litSize = litSize; + return lhSize+litSize; + } + /* direct reference into compressed stream */ + dctx->litPtr = istart+lhSize; + dctx->litSize = litSize; + dctx->litBufferEnd = dctx->litPtr + litSize; + dctx->litBufferLocation = ZSTD_not_in_dst; + return lhSize+litSize; + } + + case set_rle: + { U32 const lhlCode = ((istart[0]) >> 2) & 3; + size_t litSize, lhSize; + size_t expectedWriteSize = MIN(ZSTD_BLOCKSIZE_MAX, dstCapacity); + switch(lhlCode) + { + case 0: case 2: default: /* note : default is impossible, since lhlCode into [0..3] */ + lhSize = 1; + litSize = istart[0] >> 3; + break; + case 1: + lhSize = 2; + litSize = MEM_readLE16(istart) >> 4; + break; + case 3: + lhSize = 3; + litSize = MEM_readLE24(istart) >> 4; + RETURN_ERROR_IF(srcSize<4, corruption_detected, "srcSize >= MIN_CBLOCK_SIZE == 3; here we need lhSize+1 = 4"); + break; + } + RETURN_ERROR_IF(litSize > 0 && dst == NULL, dstSize_tooSmall, "NULL not handled"); + RETURN_ERROR_IF(litSize > ZSTD_BLOCKSIZE_MAX, corruption_detected, ""); + RETURN_ERROR_IF(expectedWriteSize < litSize, dstSize_tooSmall, ""); + ZSTD_allocateLiteralsBuffer(dctx, dst, dstCapacity, litSize, streaming, expectedWriteSize, 1); + if (dctx->litBufferLocation == ZSTD_split) + { + ZSTD_memset(dctx->litBuffer, istart[lhSize], litSize - ZSTD_LITBUFFEREXTRASIZE); + ZSTD_memset(dctx->litExtraBuffer, istart[lhSize], ZSTD_LITBUFFEREXTRASIZE); + } + else + { + ZSTD_memset(dctx->litBuffer, istart[lhSize], litSize); + } + dctx->litPtr = dctx->litBuffer; + dctx->litSize = litSize; + return lhSize+1; + } + default: + RETURN_ERROR(corruption_detected, "impossible"); + } + } +} + +/* Default FSE distribution tables. + * These are pre-calculated FSE decoding tables using default distributions as defined in specification : + * https://github.com/facebook/zstd/blob/release/doc/zstd_compression_format.md#default-distributions + * They were generated programmatically with following method : + * - start from default distributions, present in /lib/common/zstd_internal.h + * - generate tables normally, using ZSTD_buildFSETable() + * - printout the content of tables + * - pretify output, report below, test with fuzzer to ensure it's correct */ + +/* Default FSE distribution table for Literal Lengths */ +static const ZSTD_seqSymbol LL_defaultDTable[(1<tableLog = 0; + DTableH->fastMode = 0; + + cell->nbBits = 0; + cell->nextState = 0; + assert(nbAddBits < 255); + cell->nbAdditionalBits = nbAddBits; + cell->baseValue = baseValue; +} + + +/* ZSTD_buildFSETable() : + * generate FSE decoding table for one symbol (ll, ml or off) + * cannot fail if input is valid => + * all inputs are presumed validated at this stage */ +FORCE_INLINE_TEMPLATE +void ZSTD_buildFSETable_body(ZSTD_seqSymbol* dt, + const short* normalizedCounter, unsigned maxSymbolValue, + const U32* baseValue, const U8* nbAdditionalBits, + unsigned tableLog, void* wksp, size_t wkspSize) +{ + ZSTD_seqSymbol* const tableDecode = dt+1; + U32 const maxSV1 = maxSymbolValue + 1; + U32 const tableSize = 1 << tableLog; + + U16* symbolNext = (U16*)wksp; + BYTE* spread = (BYTE*)(symbolNext + MaxSeq + 1); + U32 highThreshold = tableSize - 1; + + + /* Sanity Checks */ + assert(maxSymbolValue <= MaxSeq); + assert(tableLog <= MaxFSELog); + assert(wkspSize >= ZSTD_BUILD_FSE_TABLE_WKSP_SIZE); + (void)wkspSize; + /* Init, lay down lowprob symbols */ + { ZSTD_seqSymbol_header DTableH; + DTableH.tableLog = tableLog; + DTableH.fastMode = 1; + { S16 const largeLimit= (S16)(1 << (tableLog-1)); + U32 s; + for (s=0; s= largeLimit) DTableH.fastMode=0; + assert(normalizedCounter[s]>=0); + symbolNext[s] = (U16)normalizedCounter[s]; + } } } + ZSTD_memcpy(dt, &DTableH, sizeof(DTableH)); + } + + /* Spread symbols */ + assert(tableSize <= 512); + /* Specialized symbol spreading for the case when there are + * no low probability (-1 count) symbols. When compressing + * small blocks we avoid low probability symbols to hit this + * case, since header decoding speed matters more. + */ + if (highThreshold == tableSize - 1) { + size_t const tableMask = tableSize-1; + size_t const step = FSE_TABLESTEP(tableSize); + /* First lay down the symbols in order. + * We use a uint64_t to lay down 8 bytes at a time. This reduces branch + * misses since small blocks generally have small table logs, so nearly + * all symbols have counts <= 8. We ensure we have 8 bytes at the end of + * our buffer to handle the over-write. + */ + { + U64 const add = 0x0101010101010101ull; + size_t pos = 0; + U64 sv = 0; + U32 s; + for (s=0; s highThreshold) position = (position + step) & tableMask; /* lowprob area */ + } } + assert(position == 0); /* position must reach all cells once, otherwise normalizedCounter is incorrect */ + } + + /* Build Decoding table */ + { + U32 u; + for (u=0; u max, corruption_detected, ""); + { U32 const symbol = *(const BYTE*)src; + U32 const baseline = baseValue[symbol]; + U8 const nbBits = nbAdditionalBits[symbol]; + ZSTD_buildSeqTable_rle(DTableSpace, baseline, nbBits); + } + *DTablePtr = DTableSpace; + return 1; + case set_basic : + *DTablePtr = defaultTable; + return 0; + case set_repeat: + RETURN_ERROR_IF(!flagRepeatTable, corruption_detected, ""); + /* prefetch FSE table if used */ + if (ddictIsCold && (nbSeq > 24 /* heuristic */)) { + const void* const pStart = *DTablePtr; + size_t const pSize = sizeof(ZSTD_seqSymbol) * (SEQSYMBOL_TABLE_SIZE(maxLog)); + PREFETCH_AREA(pStart, pSize); + } + return 0; + case set_compressed : + { unsigned tableLog; + S16 norm[MaxSeq+1]; + size_t const headerSize = FSE_readNCount(norm, &max, &tableLog, src, srcSize); + RETURN_ERROR_IF(FSE_isError(headerSize), corruption_detected, ""); + RETURN_ERROR_IF(tableLog > maxLog, corruption_detected, ""); + ZSTD_buildFSETable(DTableSpace, norm, max, baseValue, nbAdditionalBits, tableLog, wksp, wkspSize, bmi2); + *DTablePtr = DTableSpace; + return headerSize; + } + default : + assert(0); + RETURN_ERROR(GENERIC, "impossible"); + } +} + +size_t ZSTD_decodeSeqHeaders(ZSTD_DCtx* dctx, int* nbSeqPtr, + const void* src, size_t srcSize) +{ + const BYTE* const istart = (const BYTE*)src; + const BYTE* const iend = istart + srcSize; + const BYTE* ip = istart; + int nbSeq; + DEBUGLOG(5, "ZSTD_decodeSeqHeaders"); + + /* check */ + RETURN_ERROR_IF(srcSize < MIN_SEQUENCES_SIZE, srcSize_wrong, ""); + + /* SeqHead */ + nbSeq = *ip++; + if (!nbSeq) { + *nbSeqPtr=0; + RETURN_ERROR_IF(srcSize != 1, srcSize_wrong, ""); + return 1; + } + if (nbSeq > 0x7F) { + if (nbSeq == 0xFF) { + RETURN_ERROR_IF(ip+2 > iend, srcSize_wrong, ""); + nbSeq = MEM_readLE16(ip) + LONGNBSEQ; + ip+=2; + } else { + RETURN_ERROR_IF(ip >= iend, srcSize_wrong, ""); + nbSeq = ((nbSeq-0x80)<<8) + *ip++; + } + } + *nbSeqPtr = nbSeq; + + /* FSE table descriptors */ + RETURN_ERROR_IF(ip+1 > iend, srcSize_wrong, ""); /* minimum possible size: 1 byte for symbol encoding types */ + { symbolEncodingType_e const LLtype = (symbolEncodingType_e)(*ip >> 6); + symbolEncodingType_e const OFtype = (symbolEncodingType_e)((*ip >> 4) & 3); + symbolEncodingType_e const MLtype = (symbolEncodingType_e)((*ip >> 2) & 3); + ip++; + + /* Build DTables */ + { size_t const llhSize = ZSTD_buildSeqTable(dctx->entropy.LLTable, &dctx->LLTptr, + LLtype, MaxLL, LLFSELog, + ip, iend-ip, + LL_base, LL_bits, + LL_defaultDTable, dctx->fseEntropy, + dctx->ddictIsCold, nbSeq, + dctx->workspace, sizeof(dctx->workspace), + ZSTD_DCtx_get_bmi2(dctx)); + RETURN_ERROR_IF(ZSTD_isError(llhSize), corruption_detected, "ZSTD_buildSeqTable failed"); + ip += llhSize; + } + + { size_t const ofhSize = ZSTD_buildSeqTable(dctx->entropy.OFTable, &dctx->OFTptr, + OFtype, MaxOff, OffFSELog, + ip, iend-ip, + OF_base, OF_bits, + OF_defaultDTable, dctx->fseEntropy, + dctx->ddictIsCold, nbSeq, + dctx->workspace, sizeof(dctx->workspace), + ZSTD_DCtx_get_bmi2(dctx)); + RETURN_ERROR_IF(ZSTD_isError(ofhSize), corruption_detected, "ZSTD_buildSeqTable failed"); + ip += ofhSize; + } + + { size_t const mlhSize = ZSTD_buildSeqTable(dctx->entropy.MLTable, &dctx->MLTptr, + MLtype, MaxML, MLFSELog, + ip, iend-ip, + ML_base, ML_bits, + ML_defaultDTable, dctx->fseEntropy, + dctx->ddictIsCold, nbSeq, + dctx->workspace, sizeof(dctx->workspace), + ZSTD_DCtx_get_bmi2(dctx)); + RETURN_ERROR_IF(ZSTD_isError(mlhSize), corruption_detected, "ZSTD_buildSeqTable failed"); + ip += mlhSize; + } + } + + return ip-istart; +} + + +typedef struct { + size_t litLength; + size_t matchLength; + size_t offset; +} seq_t; + +typedef struct { + size_t state; + const ZSTD_seqSymbol* table; +} ZSTD_fseState; + +typedef struct { + BIT_DStream_t DStream; + ZSTD_fseState stateLL; + ZSTD_fseState stateOffb; + ZSTD_fseState stateML; + size_t prevOffset[ZSTD_REP_NUM]; +} seqState_t; + +/*! ZSTD_overlapCopy8() : + * Copies 8 bytes from ip to op and updates op and ip where ip <= op. + * If the offset is < 8 then the offset is spread to at least 8 bytes. + * + * Precondition: *ip <= *op + * Postcondition: *op - *op >= 8 + */ +HINT_INLINE void ZSTD_overlapCopy8(BYTE** op, BYTE const** ip, size_t offset) { + assert(*ip <= *op); + if (offset < 8) { + /* close range match, overlap */ + static const U32 dec32table[] = { 0, 1, 2, 1, 4, 4, 4, 4 }; /* added */ + static const int dec64table[] = { 8, 8, 8, 7, 8, 9,10,11 }; /* subtracted */ + int const sub2 = dec64table[offset]; + (*op)[0] = (*ip)[0]; + (*op)[1] = (*ip)[1]; + (*op)[2] = (*ip)[2]; + (*op)[3] = (*ip)[3]; + *ip += dec32table[offset]; + ZSTD_copy4(*op+4, *ip); + *ip -= sub2; + } else { + ZSTD_copy8(*op, *ip); + } + *ip += 8; + *op += 8; + assert(*op - *ip >= 8); +} + +/*! ZSTD_safecopy() : + * Specialized version of memcpy() that is allowed to READ up to WILDCOPY_OVERLENGTH past the input buffer + * and write up to 16 bytes past oend_w (op >= oend_w is allowed). + * This function is only called in the uncommon case where the sequence is near the end of the block. It + * should be fast for a single long sequence, but can be slow for several short sequences. + * + * @param ovtype controls the overlap detection + * - ZSTD_no_overlap: The source and destination are guaranteed to be at least WILDCOPY_VECLEN bytes apart. + * - ZSTD_overlap_src_before_dst: The src and dst may overlap and may be any distance apart. + * The src buffer must be before the dst buffer. + */ +static void ZSTD_safecopy(BYTE* op, const BYTE* const oend_w, BYTE const* ip, ptrdiff_t length, ZSTD_overlap_e ovtype) { + ptrdiff_t const diff = op - ip; + BYTE* const oend = op + length; + + assert((ovtype == ZSTD_no_overlap && (diff <= -8 || diff >= 8 || op >= oend_w)) || + (ovtype == ZSTD_overlap_src_before_dst && diff >= 0)); + + if (length < 8) { + /* Handle short lengths. */ + while (op < oend) *op++ = *ip++; + return; + } + if (ovtype == ZSTD_overlap_src_before_dst) { + /* Copy 8 bytes and ensure the offset >= 8 when there can be overlap. */ + assert(length >= 8); + ZSTD_overlapCopy8(&op, &ip, diff); + length -= 8; + assert(op - ip >= 8); + assert(op <= oend); + } + + if (oend <= oend_w) { + /* No risk of overwrite. */ + ZSTD_wildcopy(op, ip, length, ovtype); + return; + } + if (op <= oend_w) { + /* Wildcopy until we get close to the end. */ + assert(oend > oend_w); + ZSTD_wildcopy(op, ip, oend_w - op, ovtype); + ip += oend_w - op; + op += oend_w - op; + } + /* Handle the leftovers. */ + while (op < oend) *op++ = *ip++; +} + +/* ZSTD_safecopyDstBeforeSrc(): + * This version allows overlap with dst before src, or handles the non-overlap case with dst after src + * Kept separate from more common ZSTD_safecopy case to avoid performance impact to the safecopy common case */ +static void ZSTD_safecopyDstBeforeSrc(BYTE* op, BYTE const* ip, ptrdiff_t length) { + ptrdiff_t const diff = op - ip; + BYTE* const oend = op + length; + + if (length < 8 || diff > -8) { + /* Handle short lengths, close overlaps, and dst not before src. */ + while (op < oend) *op++ = *ip++; + return; + } + + if (op <= oend - WILDCOPY_OVERLENGTH && diff < -WILDCOPY_VECLEN) { + ZSTD_wildcopy(op, ip, oend - WILDCOPY_OVERLENGTH - op, ZSTD_no_overlap); + ip += oend - WILDCOPY_OVERLENGTH - op; + op += oend - WILDCOPY_OVERLENGTH - op; + } + + /* Handle the leftovers. */ + while (op < oend) *op++ = *ip++; +} + +/* ZSTD_execSequenceEnd(): + * This version handles cases that are near the end of the output buffer. It requires + * more careful checks to make sure there is no overflow. By separating out these hard + * and unlikely cases, we can speed up the common cases. + * + * NOTE: This function needs to be fast for a single long sequence, but doesn't need + * to be optimized for many small sequences, since those fall into ZSTD_execSequence(). + */ +FORCE_NOINLINE +size_t ZSTD_execSequenceEnd(BYTE* op, + BYTE* const oend, seq_t sequence, + const BYTE** litPtr, const BYTE* const litLimit, + const BYTE* const prefixStart, const BYTE* const virtualStart, const BYTE* const dictEnd) +{ + BYTE* const oLitEnd = op + sequence.litLength; + size_t const sequenceLength = sequence.litLength + sequence.matchLength; + const BYTE* const iLitEnd = *litPtr + sequence.litLength; + const BYTE* match = oLitEnd - sequence.offset; + BYTE* const oend_w = oend - WILDCOPY_OVERLENGTH; + + /* bounds checks : careful of address space overflow in 32-bit mode */ + RETURN_ERROR_IF(sequenceLength > (size_t)(oend - op), dstSize_tooSmall, "last match must fit within dstBuffer"); + RETURN_ERROR_IF(sequence.litLength > (size_t)(litLimit - *litPtr), corruption_detected, "try to read beyond literal buffer"); + assert(op < op + sequenceLength); + assert(oLitEnd < op + sequenceLength); + + /* copy literals */ + ZSTD_safecopy(op, oend_w, *litPtr, sequence.litLength, ZSTD_no_overlap); + op = oLitEnd; + *litPtr = iLitEnd; + + /* copy Match */ + if (sequence.offset > (size_t)(oLitEnd - prefixStart)) { + /* offset beyond prefix */ + RETURN_ERROR_IF(sequence.offset > (size_t)(oLitEnd - virtualStart), corruption_detected, ""); + match = dictEnd - (prefixStart - match); + if (match + sequence.matchLength <= dictEnd) { + ZSTD_memmove(oLitEnd, match, sequence.matchLength); + return sequenceLength; + } + /* span extDict & currentPrefixSegment */ + { size_t const length1 = dictEnd - match; + ZSTD_memmove(oLitEnd, match, length1); + op = oLitEnd + length1; + sequence.matchLength -= length1; + match = prefixStart; + } + } + ZSTD_safecopy(op, oend_w, match, sequence.matchLength, ZSTD_overlap_src_before_dst); + return sequenceLength; +} + +/* ZSTD_execSequenceEndSplitLitBuffer(): + * This version is intended to be used during instances where the litBuffer is still split. It is kept separate to avoid performance impact for the good case. + */ +FORCE_NOINLINE +size_t ZSTD_execSequenceEndSplitLitBuffer(BYTE* op, + BYTE* const oend, const BYTE* const oend_w, seq_t sequence, + const BYTE** litPtr, const BYTE* const litLimit, + const BYTE* const prefixStart, const BYTE* const virtualStart, const BYTE* const dictEnd) +{ + BYTE* const oLitEnd = op + sequence.litLength; + size_t const sequenceLength = sequence.litLength + sequence.matchLength; + const BYTE* const iLitEnd = *litPtr + sequence.litLength; + const BYTE* match = oLitEnd - sequence.offset; + + + /* bounds checks : careful of address space overflow in 32-bit mode */ + RETURN_ERROR_IF(sequenceLength > (size_t)(oend - op), dstSize_tooSmall, "last match must fit within dstBuffer"); + RETURN_ERROR_IF(sequence.litLength > (size_t)(litLimit - *litPtr), corruption_detected, "try to read beyond literal buffer"); + assert(op < op + sequenceLength); + assert(oLitEnd < op + sequenceLength); + + /* copy literals */ + RETURN_ERROR_IF(op > *litPtr && op < *litPtr + sequence.litLength, dstSize_tooSmall, "output should not catch up to and overwrite literal buffer"); + ZSTD_safecopyDstBeforeSrc(op, *litPtr, sequence.litLength); + op = oLitEnd; + *litPtr = iLitEnd; + + /* copy Match */ + if (sequence.offset > (size_t)(oLitEnd - prefixStart)) { + /* offset beyond prefix */ + RETURN_ERROR_IF(sequence.offset > (size_t)(oLitEnd - virtualStart), corruption_detected, ""); + match = dictEnd - (prefixStart - match); + if (match + sequence.matchLength <= dictEnd) { + ZSTD_memmove(oLitEnd, match, sequence.matchLength); + return sequenceLength; + } + /* span extDict & currentPrefixSegment */ + { size_t const length1 = dictEnd - match; + ZSTD_memmove(oLitEnd, match, length1); + op = oLitEnd + length1; + sequence.matchLength -= length1; + match = prefixStart; + } + } + ZSTD_safecopy(op, oend_w, match, sequence.matchLength, ZSTD_overlap_src_before_dst); + return sequenceLength; +} + +HINT_INLINE +size_t ZSTD_execSequence(BYTE* op, + BYTE* const oend, seq_t sequence, + const BYTE** litPtr, const BYTE* const litLimit, + const BYTE* const prefixStart, const BYTE* const virtualStart, const BYTE* const dictEnd) +{ + BYTE* const oLitEnd = op + sequence.litLength; + size_t const sequenceLength = sequence.litLength + sequence.matchLength; + BYTE* const oMatchEnd = op + sequenceLength; /* risk : address space overflow (32-bits) */ + BYTE* const oend_w = oend - WILDCOPY_OVERLENGTH; /* risk : address space underflow on oend=NULL */ + const BYTE* const iLitEnd = *litPtr + sequence.litLength; + const BYTE* match = oLitEnd - sequence.offset; + + assert(op != NULL /* Precondition */); + assert(oend_w < oend /* No underflow */); + /* Handle edge cases in a slow path: + * - Read beyond end of literals + * - Match end is within WILDCOPY_OVERLIMIT of oend + * - 32-bit mode and the match length overflows + */ + if (UNLIKELY( + iLitEnd > litLimit || + oMatchEnd > oend_w || + (MEM_32bits() && (size_t)(oend - op) < sequenceLength + WILDCOPY_OVERLENGTH))) + return ZSTD_execSequenceEnd(op, oend, sequence, litPtr, litLimit, prefixStart, virtualStart, dictEnd); + + /* Assumptions (everything else goes into ZSTD_execSequenceEnd()) */ + assert(op <= oLitEnd /* No overflow */); + assert(oLitEnd < oMatchEnd /* Non-zero match & no overflow */); + assert(oMatchEnd <= oend /* No underflow */); + assert(iLitEnd <= litLimit /* Literal length is in bounds */); + assert(oLitEnd <= oend_w /* Can wildcopy literals */); + assert(oMatchEnd <= oend_w /* Can wildcopy matches */); + + /* Copy Literals: + * Split out litLength <= 16 since it is nearly always true. +1.6% on gcc-9. + * We likely don't need the full 32-byte wildcopy. + */ + assert(WILDCOPY_OVERLENGTH >= 16); + ZSTD_copy16(op, (*litPtr)); + if (UNLIKELY(sequence.litLength > 16)) { + ZSTD_wildcopy(op + 16, (*litPtr) + 16, sequence.litLength - 16, ZSTD_no_overlap); + } + op = oLitEnd; + *litPtr = iLitEnd; /* update for next sequence */ + + /* Copy Match */ + if (sequence.offset > (size_t)(oLitEnd - prefixStart)) { + /* offset beyond prefix -> go into extDict */ + RETURN_ERROR_IF(UNLIKELY(sequence.offset > (size_t)(oLitEnd - virtualStart)), corruption_detected, ""); + match = dictEnd + (match - prefixStart); + if (match + sequence.matchLength <= dictEnd) { + ZSTD_memmove(oLitEnd, match, sequence.matchLength); + return sequenceLength; + } + /* span extDict & currentPrefixSegment */ + { size_t const length1 = dictEnd - match; + ZSTD_memmove(oLitEnd, match, length1); + op = oLitEnd + length1; + sequence.matchLength -= length1; + match = prefixStart; + } + } + /* Match within prefix of 1 or more bytes */ + assert(op <= oMatchEnd); + assert(oMatchEnd <= oend_w); + assert(match >= prefixStart); + assert(sequence.matchLength >= 1); + + /* Nearly all offsets are >= WILDCOPY_VECLEN bytes, which means we can use wildcopy + * without overlap checking. + */ + if (LIKELY(sequence.offset >= WILDCOPY_VECLEN)) { + /* We bet on a full wildcopy for matches, since we expect matches to be + * longer than literals (in general). In silesia, ~10% of matches are longer + * than 16 bytes. + */ + ZSTD_wildcopy(op, match, (ptrdiff_t)sequence.matchLength, ZSTD_no_overlap); + return sequenceLength; + } + assert(sequence.offset < WILDCOPY_VECLEN); + + /* Copy 8 bytes and spread the offset to be >= 8. */ + ZSTD_overlapCopy8(&op, &match, sequence.offset); + + /* If the match length is > 8 bytes, then continue with the wildcopy. */ + if (sequence.matchLength > 8) { + assert(op < oMatchEnd); + ZSTD_wildcopy(op, match, (ptrdiff_t)sequence.matchLength - 8, ZSTD_overlap_src_before_dst); + } + return sequenceLength; +} + +HINT_INLINE +size_t ZSTD_execSequenceSplitLitBuffer(BYTE* op, + BYTE* const oend, const BYTE* const oend_w, seq_t sequence, + const BYTE** litPtr, const BYTE* const litLimit, + const BYTE* const prefixStart, const BYTE* const virtualStart, const BYTE* const dictEnd) +{ + BYTE* const oLitEnd = op + sequence.litLength; + size_t const sequenceLength = sequence.litLength + sequence.matchLength; + BYTE* const oMatchEnd = op + sequenceLength; /* risk : address space overflow (32-bits) */ + const BYTE* const iLitEnd = *litPtr + sequence.litLength; + const BYTE* match = oLitEnd - sequence.offset; + + assert(op != NULL /* Precondition */); + assert(oend_w < oend /* No underflow */); + /* Handle edge cases in a slow path: + * - Read beyond end of literals + * - Match end is within WILDCOPY_OVERLIMIT of oend + * - 32-bit mode and the match length overflows + */ + if (UNLIKELY( + iLitEnd > litLimit || + oMatchEnd > oend_w || + (MEM_32bits() && (size_t)(oend - op) < sequenceLength + WILDCOPY_OVERLENGTH))) + return ZSTD_execSequenceEndSplitLitBuffer(op, oend, oend_w, sequence, litPtr, litLimit, prefixStart, virtualStart, dictEnd); + + /* Assumptions (everything else goes into ZSTD_execSequenceEnd()) */ + assert(op <= oLitEnd /* No overflow */); + assert(oLitEnd < oMatchEnd /* Non-zero match & no overflow */); + assert(oMatchEnd <= oend /* No underflow */); + assert(iLitEnd <= litLimit /* Literal length is in bounds */); + assert(oLitEnd <= oend_w /* Can wildcopy literals */); + assert(oMatchEnd <= oend_w /* Can wildcopy matches */); + + /* Copy Literals: + * Split out litLength <= 16 since it is nearly always true. +1.6% on gcc-9. + * We likely don't need the full 32-byte wildcopy. + */ + assert(WILDCOPY_OVERLENGTH >= 16); + ZSTD_copy16(op, (*litPtr)); + if (UNLIKELY(sequence.litLength > 16)) { + ZSTD_wildcopy(op+16, (*litPtr)+16, sequence.litLength-16, ZSTD_no_overlap); + } + op = oLitEnd; + *litPtr = iLitEnd; /* update for next sequence */ + + /* Copy Match */ + if (sequence.offset > (size_t)(oLitEnd - prefixStart)) { + /* offset beyond prefix -> go into extDict */ + RETURN_ERROR_IF(UNLIKELY(sequence.offset > (size_t)(oLitEnd - virtualStart)), corruption_detected, ""); + match = dictEnd + (match - prefixStart); + if (match + sequence.matchLength <= dictEnd) { + ZSTD_memmove(oLitEnd, match, sequence.matchLength); + return sequenceLength; + } + /* span extDict & currentPrefixSegment */ + { size_t const length1 = dictEnd - match; + ZSTD_memmove(oLitEnd, match, length1); + op = oLitEnd + length1; + sequence.matchLength -= length1; + match = prefixStart; + } } + /* Match within prefix of 1 or more bytes */ + assert(op <= oMatchEnd); + assert(oMatchEnd <= oend_w); + assert(match >= prefixStart); + assert(sequence.matchLength >= 1); + + /* Nearly all offsets are >= WILDCOPY_VECLEN bytes, which means we can use wildcopy + * without overlap checking. + */ + if (LIKELY(sequence.offset >= WILDCOPY_VECLEN)) { + /* We bet on a full wildcopy for matches, since we expect matches to be + * longer than literals (in general). In silesia, ~10% of matches are longer + * than 16 bytes. + */ + ZSTD_wildcopy(op, match, (ptrdiff_t)sequence.matchLength, ZSTD_no_overlap); + return sequenceLength; + } + assert(sequence.offset < WILDCOPY_VECLEN); + + /* Copy 8 bytes and spread the offset to be >= 8. */ + ZSTD_overlapCopy8(&op, &match, sequence.offset); + + /* If the match length is > 8 bytes, then continue with the wildcopy. */ + if (sequence.matchLength > 8) { + assert(op < oMatchEnd); + ZSTD_wildcopy(op, match, (ptrdiff_t)sequence.matchLength-8, ZSTD_overlap_src_before_dst); + } + return sequenceLength; +} + + +static void +ZSTD_initFseState(ZSTD_fseState* DStatePtr, BIT_DStream_t* bitD, const ZSTD_seqSymbol* dt) +{ + const void* ptr = dt; + const ZSTD_seqSymbol_header* const DTableH = (const ZSTD_seqSymbol_header*)ptr; + DStatePtr->state = BIT_readBits(bitD, DTableH->tableLog); + DEBUGLOG(6, "ZSTD_initFseState : val=%u using %u bits", + (U32)DStatePtr->state, DTableH->tableLog); + BIT_reloadDStream(bitD); + DStatePtr->table = dt + 1; +} + +FORCE_INLINE_TEMPLATE void +ZSTD_updateFseStateWithDInfo(ZSTD_fseState* DStatePtr, BIT_DStream_t* bitD, U16 nextState, U32 nbBits) +{ + size_t const lowBits = BIT_readBits(bitD, nbBits); + DStatePtr->state = nextState + lowBits; +} + +/* We need to add at most (ZSTD_WINDOWLOG_MAX_32 - 1) bits to read the maximum + * offset bits. But we can only read at most (STREAM_ACCUMULATOR_MIN_32 - 1) + * bits before reloading. This value is the maximum number of bytes we read + * after reloading when we are decoding long offsets. + */ +#define LONG_OFFSETS_MAX_EXTRA_BITS_32 \ + (ZSTD_WINDOWLOG_MAX_32 > STREAM_ACCUMULATOR_MIN_32 \ + ? ZSTD_WINDOWLOG_MAX_32 - STREAM_ACCUMULATOR_MIN_32 \ + : 0) + +typedef enum { ZSTD_lo_isRegularOffset, ZSTD_lo_isLongOffset=1 } ZSTD_longOffset_e; + +FORCE_INLINE_TEMPLATE seq_t +ZSTD_decodeSequence(seqState_t* seqState, const ZSTD_longOffset_e longOffsets) +{ + seq_t seq; + const ZSTD_seqSymbol* const llDInfo = seqState->stateLL.table + seqState->stateLL.state; + const ZSTD_seqSymbol* const mlDInfo = seqState->stateML.table + seqState->stateML.state; + const ZSTD_seqSymbol* const ofDInfo = seqState->stateOffb.table + seqState->stateOffb.state; + seq.matchLength = mlDInfo->baseValue; + seq.litLength = llDInfo->baseValue; + { U32 const ofBase = ofDInfo->baseValue; + BYTE const llBits = llDInfo->nbAdditionalBits; + BYTE const mlBits = mlDInfo->nbAdditionalBits; + BYTE const ofBits = ofDInfo->nbAdditionalBits; + BYTE const totalBits = llBits+mlBits+ofBits; + + U16 const llNext = llDInfo->nextState; + U16 const mlNext = mlDInfo->nextState; + U16 const ofNext = ofDInfo->nextState; + U32 const llnbBits = llDInfo->nbBits; + U32 const mlnbBits = mlDInfo->nbBits; + U32 const ofnbBits = ofDInfo->nbBits; + /* + * As gcc has better branch and block analyzers, sometimes it is only + * valuable to mark likelyness for clang, it gives around 3-4% of + * performance. + */ + + /* sequence */ + { size_t offset; + #if defined(__clang__) + if (LIKELY(ofBits > 1)) { + #else + if (ofBits > 1) { + #endif + ZSTD_STATIC_ASSERT(ZSTD_lo_isLongOffset == 1); + ZSTD_STATIC_ASSERT(LONG_OFFSETS_MAX_EXTRA_BITS_32 == 5); + assert(ofBits <= MaxOff); + if (MEM_32bits() && longOffsets && (ofBits >= STREAM_ACCUMULATOR_MIN_32)) { + U32 const extraBits = ofBits - MIN(ofBits, 32 - seqState->DStream.bitsConsumed); + offset = ofBase + (BIT_readBitsFast(&seqState->DStream, ofBits - extraBits) << extraBits); + BIT_reloadDStream(&seqState->DStream); + if (extraBits) offset += BIT_readBitsFast(&seqState->DStream, extraBits); + assert(extraBits <= LONG_OFFSETS_MAX_EXTRA_BITS_32); /* to avoid another reload */ + } else { + offset = ofBase + BIT_readBitsFast(&seqState->DStream, ofBits/*>0*/); /* <= (ZSTD_WINDOWLOG_MAX-1) bits */ + if (MEM_32bits()) BIT_reloadDStream(&seqState->DStream); + } + seqState->prevOffset[2] = seqState->prevOffset[1]; + seqState->prevOffset[1] = seqState->prevOffset[0]; + seqState->prevOffset[0] = offset; + } else { + U32 const ll0 = (llDInfo->baseValue == 0); + if (LIKELY((ofBits == 0))) { + offset = seqState->prevOffset[ll0]; + seqState->prevOffset[1] = seqState->prevOffset[!ll0]; + seqState->prevOffset[0] = offset; + } else { + offset = ofBase + ll0 + BIT_readBitsFast(&seqState->DStream, 1); + { size_t temp = (offset==3) ? seqState->prevOffset[0] - 1 : seqState->prevOffset[offset]; + temp += !temp; /* 0 is not valid; input is corrupted; force offset to 1 */ + if (offset != 1) seqState->prevOffset[2] = seqState->prevOffset[1]; + seqState->prevOffset[1] = seqState->prevOffset[0]; + seqState->prevOffset[0] = offset = temp; + } } } + seq.offset = offset; + } + + #if defined(__clang__) + if (UNLIKELY(mlBits > 0)) + #else + if (mlBits > 0) + #endif + seq.matchLength += BIT_readBitsFast(&seqState->DStream, mlBits/*>0*/); + + if (MEM_32bits() && (mlBits+llBits >= STREAM_ACCUMULATOR_MIN_32-LONG_OFFSETS_MAX_EXTRA_BITS_32)) + BIT_reloadDStream(&seqState->DStream); + if (MEM_64bits() && UNLIKELY(totalBits >= STREAM_ACCUMULATOR_MIN_64-(LLFSELog+MLFSELog+OffFSELog))) + BIT_reloadDStream(&seqState->DStream); + /* Ensure there are enough bits to read the rest of data in 64-bit mode. */ + ZSTD_STATIC_ASSERT(16+LLFSELog+MLFSELog+OffFSELog < STREAM_ACCUMULATOR_MIN_64); + + #if defined(__clang__) + if (UNLIKELY(llBits > 0)) + #else + if (llBits > 0) + #endif + seq.litLength += BIT_readBitsFast(&seqState->DStream, llBits/*>0*/); + + if (MEM_32bits()) + BIT_reloadDStream(&seqState->DStream); + + DEBUGLOG(6, "seq: litL=%u, matchL=%u, offset=%u", + (U32)seq.litLength, (U32)seq.matchLength, (U32)seq.offset); + + ZSTD_updateFseStateWithDInfo(&seqState->stateLL, &seqState->DStream, llNext, llnbBits); /* <= 9 bits */ + ZSTD_updateFseStateWithDInfo(&seqState->stateML, &seqState->DStream, mlNext, mlnbBits); /* <= 9 bits */ + if (MEM_32bits()) BIT_reloadDStream(&seqState->DStream); /* <= 18 bits */ + ZSTD_updateFseStateWithDInfo(&seqState->stateOffb, &seqState->DStream, ofNext, ofnbBits); /* <= 8 bits */ + } + + return seq; +} + +#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION +MEM_STATIC int ZSTD_dictionaryIsActive(ZSTD_DCtx const* dctx, BYTE const* prefixStart, BYTE const* oLitEnd) +{ + size_t const windowSize = dctx->fParams.windowSize; + /* No dictionary used. */ + if (dctx->dictContentEndForFuzzing == NULL) return 0; + /* Dictionary is our prefix. */ + if (prefixStart == dctx->dictContentBeginForFuzzing) return 1; + /* Dictionary is not our ext-dict. */ + if (dctx->dictEnd != dctx->dictContentEndForFuzzing) return 0; + /* Dictionary is not within our window size. */ + if ((size_t)(oLitEnd - prefixStart) >= windowSize) return 0; + /* Dictionary is active. */ + return 1; +} + +MEM_STATIC void ZSTD_assertValidSequence( + ZSTD_DCtx const* dctx, + BYTE const* op, BYTE const* oend, + seq_t const seq, + BYTE const* prefixStart, BYTE const* virtualStart) +{ +#if DEBUGLEVEL >= 1 + size_t const windowSize = dctx->fParams.windowSize; + size_t const sequenceSize = seq.litLength + seq.matchLength; + BYTE const* const oLitEnd = op + seq.litLength; + DEBUGLOG(6, "Checking sequence: litL=%u matchL=%u offset=%u", + (U32)seq.litLength, (U32)seq.matchLength, (U32)seq.offset); + assert(op <= oend); + assert((size_t)(oend - op) >= sequenceSize); + assert(sequenceSize <= ZSTD_BLOCKSIZE_MAX); + if (ZSTD_dictionaryIsActive(dctx, prefixStart, oLitEnd)) { + size_t const dictSize = (size_t)((char const*)dctx->dictContentEndForFuzzing - (char const*)dctx->dictContentBeginForFuzzing); + /* Offset must be within the dictionary. */ + assert(seq.offset <= (size_t)(oLitEnd - virtualStart)); + assert(seq.offset <= windowSize + dictSize); + } else { + /* Offset must be within our window. */ + assert(seq.offset <= windowSize); + } +#else + (void)dctx, (void)op, (void)oend, (void)seq, (void)prefixStart, (void)virtualStart; +#endif +} +#endif + +#ifndef ZSTD_FORCE_DECOMPRESS_SEQUENCES_LONG + + +FORCE_INLINE_TEMPLATE size_t +DONT_VECTORIZE +ZSTD_decompressSequences_bodySplitLitBuffer( ZSTD_DCtx* dctx, + void* dst, size_t maxDstSize, + const void* seqStart, size_t seqSize, int nbSeq, + const ZSTD_longOffset_e isLongOffset, + const int frame) +{ + const BYTE* ip = (const BYTE*)seqStart; + const BYTE* const iend = ip + seqSize; + BYTE* const ostart = (BYTE*)dst; + BYTE* const oend = ostart + maxDstSize; + BYTE* op = ostart; + const BYTE* litPtr = dctx->litPtr; + const BYTE* litBufferEnd = dctx->litBufferEnd; + const BYTE* const prefixStart = (const BYTE*) (dctx->prefixStart); + const BYTE* const vBase = (const BYTE*) (dctx->virtualStart); + const BYTE* const dictEnd = (const BYTE*) (dctx->dictEnd); + DEBUGLOG(5, "ZSTD_decompressSequences_bodySplitLitBuffer"); + (void)frame; + + /* Regen sequences */ + if (nbSeq) { + seqState_t seqState; + dctx->fseEntropy = 1; + { U32 i; for (i=0; ientropy.rep[i]; } + RETURN_ERROR_IF( + ERR_isError(BIT_initDStream(&seqState.DStream, ip, iend-ip)), + corruption_detected, ""); + ZSTD_initFseState(&seqState.stateLL, &seqState.DStream, dctx->LLTptr); + ZSTD_initFseState(&seqState.stateOffb, &seqState.DStream, dctx->OFTptr); + ZSTD_initFseState(&seqState.stateML, &seqState.DStream, dctx->MLTptr); + assert(dst != NULL); + + ZSTD_STATIC_ASSERT( + BIT_DStream_unfinished < BIT_DStream_completed && + BIT_DStream_endOfBuffer < BIT_DStream_completed && + BIT_DStream_completed < BIT_DStream_overflow); + + /* decompress without overrunning litPtr begins */ + { + seq_t sequence = ZSTD_decodeSequence(&seqState, isLongOffset); + /* Align the decompression loop to 32 + 16 bytes. + * + * zstd compiled with gcc-9 on an Intel i9-9900k shows 10% decompression + * speed swings based on the alignment of the decompression loop. This + * performance swing is caused by parts of the decompression loop falling + * out of the DSB. The entire decompression loop should fit in the DSB, + * when it can't we get much worse performance. You can measure if you've + * hit the good case or the bad case with this perf command for some + * compressed file test.zst: + * + * perf stat -e cycles -e instructions -e idq.all_dsb_cycles_any_uops \ + * -e idq.all_mite_cycles_any_uops -- ./zstd -tq test.zst + * + * If you see most cycles served out of the MITE you've hit the bad case. + * If you see most cycles served out of the DSB you've hit the good case. + * If it is pretty even then you may be in an okay case. + * + * This issue has been reproduced on the following CPUs: + * - Kabylake: Macbook Pro (15-inch, 2019) 2.4 GHz Intel Core i9 + * Use Instruments->Counters to get DSB/MITE cycles. + * I never got performance swings, but I was able to + * go from the good case of mostly DSB to half of the + * cycles served from MITE. + * - Coffeelake: Intel i9-9900k + * - Coffeelake: Intel i7-9700k + * + * I haven't been able to reproduce the instability or DSB misses on any + * of the following CPUS: + * - Haswell + * - Broadwell: Intel(R) Xeon(R) CPU E5-2680 v4 @ 2.40GH + * - Skylake + * + * Alignment is done for each of the three major decompression loops: + * - ZSTD_decompressSequences_bodySplitLitBuffer - presplit section of the literal buffer + * - ZSTD_decompressSequences_bodySplitLitBuffer - postsplit section of the literal buffer + * - ZSTD_decompressSequences_body + * Alignment choices are made to minimize large swings on bad cases and influence on performance + * from changes external to this code, rather than to overoptimize on the current commit. + * + * If you are seeing performance stability this script can help test. + * It tests on 4 commits in zstd where I saw performance change. + * + * https://gist.github.com/terrelln/9889fc06a423fd5ca6e99351564473f4 + */ +#if defined(__GNUC__) && defined(__x86_64__) + __asm__(".p2align 6"); +# if __GNUC__ >= 7 + /* good for gcc-7, gcc-9, and gcc-11 */ + __asm__("nop"); + __asm__(".p2align 5"); + __asm__("nop"); + __asm__(".p2align 4"); +# if __GNUC__ == 8 || __GNUC__ == 10 + /* good for gcc-8 and gcc-10 */ + __asm__("nop"); + __asm__(".p2align 3"); +# endif +# endif +#endif + + /* Handle the initial state where litBuffer is currently split between dst and litExtraBuffer */ + for (; litPtr + sequence.litLength <= dctx->litBufferEnd; ) { + size_t const oneSeqSize = ZSTD_execSequenceSplitLitBuffer(op, oend, litPtr + sequence.litLength - WILDCOPY_OVERLENGTH, sequence, &litPtr, litBufferEnd, prefixStart, vBase, dictEnd); +#if defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION) && defined(FUZZING_ASSERT_VALID_SEQUENCE) + assert(!ZSTD_isError(oneSeqSize)); + if (frame) ZSTD_assertValidSequence(dctx, op, oend, sequence, prefixStart, vBase); +#endif + if (UNLIKELY(ZSTD_isError(oneSeqSize))) + return oneSeqSize; + DEBUGLOG(6, "regenerated sequence size : %u", (U32)oneSeqSize); + op += oneSeqSize; + if (UNLIKELY(!--nbSeq)) + break; + BIT_reloadDStream(&(seqState.DStream)); + sequence = ZSTD_decodeSequence(&seqState, isLongOffset); + } + + /* If there are more sequences, they will need to read literals from litExtraBuffer; copy over the remainder from dst and update litPtr and litEnd */ + if (nbSeq > 0) { + const size_t leftoverLit = dctx->litBufferEnd - litPtr; + if (leftoverLit) + { + RETURN_ERROR_IF(leftoverLit > (size_t)(oend - op), dstSize_tooSmall, "remaining lit must fit within dstBuffer"); + ZSTD_safecopyDstBeforeSrc(op, litPtr, leftoverLit); + sequence.litLength -= leftoverLit; + op += leftoverLit; + } + litPtr = dctx->litExtraBuffer; + litBufferEnd = dctx->litExtraBuffer + ZSTD_LITBUFFEREXTRASIZE; + dctx->litBufferLocation = ZSTD_not_in_dst; + { + size_t const oneSeqSize = ZSTD_execSequence(op, oend, sequence, &litPtr, litBufferEnd, prefixStart, vBase, dictEnd); +#if defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION) && defined(FUZZING_ASSERT_VALID_SEQUENCE) + assert(!ZSTD_isError(oneSeqSize)); + if (frame) ZSTD_assertValidSequence(dctx, op, oend, sequence, prefixStart, vBase); +#endif + if (UNLIKELY(ZSTD_isError(oneSeqSize))) + return oneSeqSize; + DEBUGLOG(6, "regenerated sequence size : %u", (U32)oneSeqSize); + op += oneSeqSize; + if (--nbSeq) + BIT_reloadDStream(&(seqState.DStream)); + } + } + } + + if (nbSeq > 0) /* there is remaining lit from extra buffer */ + { + +#if defined(__GNUC__) && defined(__x86_64__) + __asm__(".p2align 6"); + __asm__("nop"); +# if __GNUC__ != 7 + /* worse for gcc-7 better for gcc-8, gcc-9, and gcc-10 and clang */ + __asm__(".p2align 4"); + __asm__("nop"); + __asm__(".p2align 3"); +# elif __GNUC__ >= 11 + __asm__(".p2align 3"); +# else + __asm__(".p2align 5"); + __asm__("nop"); + __asm__(".p2align 3"); +# endif +#endif + + for (; ; ) { + seq_t const sequence = ZSTD_decodeSequence(&seqState, isLongOffset); + size_t const oneSeqSize = ZSTD_execSequence(op, oend, sequence, &litPtr, litBufferEnd, prefixStart, vBase, dictEnd); +#if defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION) && defined(FUZZING_ASSERT_VALID_SEQUENCE) + assert(!ZSTD_isError(oneSeqSize)); + if (frame) ZSTD_assertValidSequence(dctx, op, oend, sequence, prefixStart, vBase); +#endif + if (UNLIKELY(ZSTD_isError(oneSeqSize))) + return oneSeqSize; + DEBUGLOG(6, "regenerated sequence size : %u", (U32)oneSeqSize); + op += oneSeqSize; + if (UNLIKELY(!--nbSeq)) + break; + BIT_reloadDStream(&(seqState.DStream)); + } + } + + /* check if reached exact end */ + DEBUGLOG(5, "ZSTD_decompressSequences_bodySplitLitBuffer: after decode loop, remaining nbSeq : %i", nbSeq); + RETURN_ERROR_IF(nbSeq, corruption_detected, ""); + RETURN_ERROR_IF(BIT_reloadDStream(&seqState.DStream) < BIT_DStream_completed, corruption_detected, ""); + /* save reps for next block */ + { U32 i; for (i=0; ientropy.rep[i] = (U32)(seqState.prevOffset[i]); } + } + + /* last literal segment */ + if (dctx->litBufferLocation == ZSTD_split) /* split hasn't been reached yet, first get dst then copy litExtraBuffer */ + { + size_t const lastLLSize = litBufferEnd - litPtr; + RETURN_ERROR_IF(lastLLSize > (size_t)(oend - op), dstSize_tooSmall, ""); + if (op != NULL) { + ZSTD_memmove(op, litPtr, lastLLSize); + op += lastLLSize; + } + litPtr = dctx->litExtraBuffer; + litBufferEnd = dctx->litExtraBuffer + ZSTD_LITBUFFEREXTRASIZE; + dctx->litBufferLocation = ZSTD_not_in_dst; + } + { size_t const lastLLSize = litBufferEnd - litPtr; + RETURN_ERROR_IF(lastLLSize > (size_t)(oend-op), dstSize_tooSmall, ""); + if (op != NULL) { + ZSTD_memcpy(op, litPtr, lastLLSize); + op += lastLLSize; + } + } + + return op-ostart; +} + +FORCE_INLINE_TEMPLATE size_t +DONT_VECTORIZE +ZSTD_decompressSequences_body(ZSTD_DCtx* dctx, + void* dst, size_t maxDstSize, + const void* seqStart, size_t seqSize, int nbSeq, + const ZSTD_longOffset_e isLongOffset, + const int frame) +{ + const BYTE* ip = (const BYTE*)seqStart; + const BYTE* const iend = ip + seqSize; + BYTE* const ostart = (BYTE*)dst; + BYTE* const oend = dctx->litBufferLocation == ZSTD_not_in_dst ? ostart + maxDstSize : dctx->litBuffer; + BYTE* op = ostart; + const BYTE* litPtr = dctx->litPtr; + const BYTE* const litEnd = litPtr + dctx->litSize; + const BYTE* const prefixStart = (const BYTE*)(dctx->prefixStart); + const BYTE* const vBase = (const BYTE*)(dctx->virtualStart); + const BYTE* const dictEnd = (const BYTE*)(dctx->dictEnd); + DEBUGLOG(5, "ZSTD_decompressSequences_body"); + (void)frame; + + /* Regen sequences */ + if (nbSeq) { + seqState_t seqState; + dctx->fseEntropy = 1; + { U32 i; for (i = 0; i < ZSTD_REP_NUM; i++) seqState.prevOffset[i] = dctx->entropy.rep[i]; } + RETURN_ERROR_IF( + ERR_isError(BIT_initDStream(&seqState.DStream, ip, iend - ip)), + corruption_detected, ""); + ZSTD_initFseState(&seqState.stateLL, &seqState.DStream, dctx->LLTptr); + ZSTD_initFseState(&seqState.stateOffb, &seqState.DStream, dctx->OFTptr); + ZSTD_initFseState(&seqState.stateML, &seqState.DStream, dctx->MLTptr); + assert(dst != NULL); + + ZSTD_STATIC_ASSERT( + BIT_DStream_unfinished < BIT_DStream_completed && + BIT_DStream_endOfBuffer < BIT_DStream_completed && + BIT_DStream_completed < BIT_DStream_overflow); + +#if defined(__GNUC__) && defined(__x86_64__) + __asm__(".p2align 6"); + __asm__("nop"); +# if __GNUC__ >= 7 + __asm__(".p2align 5"); + __asm__("nop"); + __asm__(".p2align 3"); +# else + __asm__(".p2align 4"); + __asm__("nop"); + __asm__(".p2align 3"); +# endif +#endif + + for ( ; ; ) { + seq_t const sequence = ZSTD_decodeSequence(&seqState, isLongOffset); + size_t const oneSeqSize = ZSTD_execSequence(op, oend, sequence, &litPtr, litEnd, prefixStart, vBase, dictEnd); +#if defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION) && defined(FUZZING_ASSERT_VALID_SEQUENCE) + assert(!ZSTD_isError(oneSeqSize)); + if (frame) ZSTD_assertValidSequence(dctx, op, oend, sequence, prefixStart, vBase); +#endif + if (UNLIKELY(ZSTD_isError(oneSeqSize))) + return oneSeqSize; + DEBUGLOG(6, "regenerated sequence size : %u", (U32)oneSeqSize); + op += oneSeqSize; + if (UNLIKELY(!--nbSeq)) + break; + BIT_reloadDStream(&(seqState.DStream)); + } + + /* check if reached exact end */ + DEBUGLOG(5, "ZSTD_decompressSequences_body: after decode loop, remaining nbSeq : %i", nbSeq); + RETURN_ERROR_IF(nbSeq, corruption_detected, ""); + RETURN_ERROR_IF(BIT_reloadDStream(&seqState.DStream) < BIT_DStream_completed, corruption_detected, ""); + /* save reps for next block */ + { U32 i; for (i=0; ientropy.rep[i] = (U32)(seqState.prevOffset[i]); } + } + + /* last literal segment */ + { size_t const lastLLSize = litEnd - litPtr; + RETURN_ERROR_IF(lastLLSize > (size_t)(oend-op), dstSize_tooSmall, ""); + if (op != NULL) { + ZSTD_memcpy(op, litPtr, lastLLSize); + op += lastLLSize; + } + } + + return op-ostart; +} + +static size_t +ZSTD_decompressSequences_default(ZSTD_DCtx* dctx, + void* dst, size_t maxDstSize, + const void* seqStart, size_t seqSize, int nbSeq, + const ZSTD_longOffset_e isLongOffset, + const int frame) +{ + return ZSTD_decompressSequences_body(dctx, dst, maxDstSize, seqStart, seqSize, nbSeq, isLongOffset, frame); +} + +static size_t +ZSTD_decompressSequencesSplitLitBuffer_default(ZSTD_DCtx* dctx, + void* dst, size_t maxDstSize, + const void* seqStart, size_t seqSize, int nbSeq, + const ZSTD_longOffset_e isLongOffset, + const int frame) +{ + return ZSTD_decompressSequences_bodySplitLitBuffer(dctx, dst, maxDstSize, seqStart, seqSize, nbSeq, isLongOffset, frame); +} +#endif /* ZSTD_FORCE_DECOMPRESS_SEQUENCES_LONG */ + +#ifndef ZSTD_FORCE_DECOMPRESS_SEQUENCES_SHORT + +FORCE_INLINE_TEMPLATE size_t +ZSTD_prefetchMatch(size_t prefetchPos, seq_t const sequence, + const BYTE* const prefixStart, const BYTE* const dictEnd) +{ + prefetchPos += sequence.litLength; + { const BYTE* const matchBase = (sequence.offset > prefetchPos) ? dictEnd : prefixStart; + const BYTE* const match = matchBase + prefetchPos - sequence.offset; /* note : this operation can overflow when seq.offset is really too large, which can only happen when input is corrupted. + * No consequence though : memory address is only used for prefetching, not for dereferencing */ + PREFETCH_L1(match); PREFETCH_L1(match+CACHELINE_SIZE); /* note : it's safe to invoke PREFETCH() on any memory address, including invalid ones */ + } + return prefetchPos + sequence.matchLength; +} + +/* This decoding function employs prefetching + * to reduce latency impact of cache misses. + * It's generally employed when block contains a significant portion of long-distance matches + * or when coupled with a "cold" dictionary */ +FORCE_INLINE_TEMPLATE size_t +ZSTD_decompressSequencesLong_body( + ZSTD_DCtx* dctx, + void* dst, size_t maxDstSize, + const void* seqStart, size_t seqSize, int nbSeq, + const ZSTD_longOffset_e isLongOffset, + const int frame) +{ + const BYTE* ip = (const BYTE*)seqStart; + const BYTE* const iend = ip + seqSize; + BYTE* const ostart = (BYTE*)dst; + BYTE* const oend = dctx->litBufferLocation == ZSTD_in_dst ? dctx->litBuffer : ostart + maxDstSize; + BYTE* op = ostart; + const BYTE* litPtr = dctx->litPtr; + const BYTE* litBufferEnd = dctx->litBufferEnd; + const BYTE* const prefixStart = (const BYTE*) (dctx->prefixStart); + const BYTE* const dictStart = (const BYTE*) (dctx->virtualStart); + const BYTE* const dictEnd = (const BYTE*) (dctx->dictEnd); + (void)frame; + + /* Regen sequences */ + if (nbSeq) { +#define STORED_SEQS 8 +#define STORED_SEQS_MASK (STORED_SEQS-1) +#define ADVANCED_SEQS STORED_SEQS + seq_t sequences[STORED_SEQS]; + int const seqAdvance = MIN(nbSeq, ADVANCED_SEQS); + seqState_t seqState; + int seqNb; + size_t prefetchPos = (size_t)(op-prefixStart); /* track position relative to prefixStart */ + + dctx->fseEntropy = 1; + { int i; for (i=0; ientropy.rep[i]; } + assert(dst != NULL); + assert(iend >= ip); + RETURN_ERROR_IF( + ERR_isError(BIT_initDStream(&seqState.DStream, ip, iend-ip)), + corruption_detected, ""); + ZSTD_initFseState(&seqState.stateLL, &seqState.DStream, dctx->LLTptr); + ZSTD_initFseState(&seqState.stateOffb, &seqState.DStream, dctx->OFTptr); + ZSTD_initFseState(&seqState.stateML, &seqState.DStream, dctx->MLTptr); + + /* prepare in advance */ + for (seqNb=0; (BIT_reloadDStream(&seqState.DStream) <= BIT_DStream_completed) && (seqNblitBufferLocation == ZSTD_split && litPtr + sequences[(seqNb - ADVANCED_SEQS) & STORED_SEQS_MASK].litLength > dctx->litBufferEnd) + { + /* lit buffer is reaching split point, empty out the first buffer and transition to litExtraBuffer */ + const size_t leftoverLit = dctx->litBufferEnd - litPtr; + if (leftoverLit) + { + RETURN_ERROR_IF(leftoverLit > (size_t)(oend - op), dstSize_tooSmall, "remaining lit must fit within dstBuffer"); + ZSTD_safecopyDstBeforeSrc(op, litPtr, leftoverLit); + sequences[(seqNb - ADVANCED_SEQS) & STORED_SEQS_MASK].litLength -= leftoverLit; + op += leftoverLit; + } + litPtr = dctx->litExtraBuffer; + litBufferEnd = dctx->litExtraBuffer + ZSTD_LITBUFFEREXTRASIZE; + dctx->litBufferLocation = ZSTD_not_in_dst; + oneSeqSize = ZSTD_execSequence(op, oend, sequences[(seqNb - ADVANCED_SEQS) & STORED_SEQS_MASK], &litPtr, litBufferEnd, prefixStart, dictStart, dictEnd); +#if defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION) && defined(FUZZING_ASSERT_VALID_SEQUENCE) + assert(!ZSTD_isError(oneSeqSize)); + if (frame) ZSTD_assertValidSequence(dctx, op, oend, sequences[(seqNb - ADVANCED_SEQS) & STORED_SEQS_MASK], prefixStart, dictStart); +#endif + if (ZSTD_isError(oneSeqSize)) return oneSeqSize; + + prefetchPos = ZSTD_prefetchMatch(prefetchPos, sequence, prefixStart, dictEnd); + sequences[seqNb & STORED_SEQS_MASK] = sequence; + op += oneSeqSize; + } + else + { + /* lit buffer is either wholly contained in first or second split, or not split at all*/ + oneSeqSize = dctx->litBufferLocation == ZSTD_split ? + ZSTD_execSequenceSplitLitBuffer(op, oend, litPtr + sequences[(seqNb - ADVANCED_SEQS) & STORED_SEQS_MASK].litLength - WILDCOPY_OVERLENGTH, sequences[(seqNb - ADVANCED_SEQS) & STORED_SEQS_MASK], &litPtr, litBufferEnd, prefixStart, dictStart, dictEnd) : + ZSTD_execSequence(op, oend, sequences[(seqNb - ADVANCED_SEQS) & STORED_SEQS_MASK], &litPtr, litBufferEnd, prefixStart, dictStart, dictEnd); +#if defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION) && defined(FUZZING_ASSERT_VALID_SEQUENCE) + assert(!ZSTD_isError(oneSeqSize)); + if (frame) ZSTD_assertValidSequence(dctx, op, oend, sequences[(seqNb - ADVANCED_SEQS) & STORED_SEQS_MASK], prefixStart, dictStart); +#endif + if (ZSTD_isError(oneSeqSize)) return oneSeqSize; + + prefetchPos = ZSTD_prefetchMatch(prefetchPos, sequence, prefixStart, dictEnd); + sequences[seqNb & STORED_SEQS_MASK] = sequence; + op += oneSeqSize; + } + } + RETURN_ERROR_IF(seqNblitBufferLocation == ZSTD_split && litPtr + sequence->litLength > dctx->litBufferEnd) + { + const size_t leftoverLit = dctx->litBufferEnd - litPtr; + if (leftoverLit) + { + RETURN_ERROR_IF(leftoverLit > (size_t)(oend - op), dstSize_tooSmall, "remaining lit must fit within dstBuffer"); + ZSTD_safecopyDstBeforeSrc(op, litPtr, leftoverLit); + sequence->litLength -= leftoverLit; + op += leftoverLit; + } + litPtr = dctx->litExtraBuffer; + litBufferEnd = dctx->litExtraBuffer + ZSTD_LITBUFFEREXTRASIZE; + dctx->litBufferLocation = ZSTD_not_in_dst; + { + size_t const oneSeqSize = ZSTD_execSequence(op, oend, *sequence, &litPtr, litBufferEnd, prefixStart, dictStart, dictEnd); +#if defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION) && defined(FUZZING_ASSERT_VALID_SEQUENCE) + assert(!ZSTD_isError(oneSeqSize)); + if (frame) ZSTD_assertValidSequence(dctx, op, oend, sequences[seqNb&STORED_SEQS_MASK], prefixStart, dictStart); +#endif + if (ZSTD_isError(oneSeqSize)) return oneSeqSize; + op += oneSeqSize; + } + } + else + { + size_t const oneSeqSize = dctx->litBufferLocation == ZSTD_split ? + ZSTD_execSequenceSplitLitBuffer(op, oend, litPtr + sequence->litLength - WILDCOPY_OVERLENGTH, *sequence, &litPtr, litBufferEnd, prefixStart, dictStart, dictEnd) : + ZSTD_execSequence(op, oend, *sequence, &litPtr, litBufferEnd, prefixStart, dictStart, dictEnd); +#if defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION) && defined(FUZZING_ASSERT_VALID_SEQUENCE) + assert(!ZSTD_isError(oneSeqSize)); + if (frame) ZSTD_assertValidSequence(dctx, op, oend, sequences[seqNb&STORED_SEQS_MASK], prefixStart, dictStart); +#endif + if (ZSTD_isError(oneSeqSize)) return oneSeqSize; + op += oneSeqSize; + } + } + + /* save reps for next block */ + { U32 i; for (i=0; ientropy.rep[i] = (U32)(seqState.prevOffset[i]); } + } + + /* last literal segment */ + if (dctx->litBufferLocation == ZSTD_split) /* first deplete literal buffer in dst, then copy litExtraBuffer */ + { + size_t const lastLLSize = litBufferEnd - litPtr; + RETURN_ERROR_IF(lastLLSize > (size_t)(oend - op), dstSize_tooSmall, ""); + if (op != NULL) { + ZSTD_memmove(op, litPtr, lastLLSize); + op += lastLLSize; + } + litPtr = dctx->litExtraBuffer; + litBufferEnd = dctx->litExtraBuffer + ZSTD_LITBUFFEREXTRASIZE; + } + { size_t const lastLLSize = litBufferEnd - litPtr; + RETURN_ERROR_IF(lastLLSize > (size_t)(oend-op), dstSize_tooSmall, ""); + if (op != NULL) { + ZSTD_memmove(op, litPtr, lastLLSize); + op += lastLLSize; + } + } + + return op-ostart; +} + +static size_t +ZSTD_decompressSequencesLong_default(ZSTD_DCtx* dctx, + void* dst, size_t maxDstSize, + const void* seqStart, size_t seqSize, int nbSeq, + const ZSTD_longOffset_e isLongOffset, + const int frame) +{ + return ZSTD_decompressSequencesLong_body(dctx, dst, maxDstSize, seqStart, seqSize, nbSeq, isLongOffset, frame); +} +#endif /* ZSTD_FORCE_DECOMPRESS_SEQUENCES_SHORT */ + + + +#if DYNAMIC_BMI2 + +#ifndef ZSTD_FORCE_DECOMPRESS_SEQUENCES_LONG +static BMI2_TARGET_ATTRIBUTE size_t +DONT_VECTORIZE +ZSTD_decompressSequences_bmi2(ZSTD_DCtx* dctx, + void* dst, size_t maxDstSize, + const void* seqStart, size_t seqSize, int nbSeq, + const ZSTD_longOffset_e isLongOffset, + const int frame) +{ + return ZSTD_decompressSequences_body(dctx, dst, maxDstSize, seqStart, seqSize, nbSeq, isLongOffset, frame); +} +static BMI2_TARGET_ATTRIBUTE size_t +DONT_VECTORIZE +ZSTD_decompressSequencesSplitLitBuffer_bmi2(ZSTD_DCtx* dctx, + void* dst, size_t maxDstSize, + const void* seqStart, size_t seqSize, int nbSeq, + const ZSTD_longOffset_e isLongOffset, + const int frame) +{ + return ZSTD_decompressSequences_bodySplitLitBuffer(dctx, dst, maxDstSize, seqStart, seqSize, nbSeq, isLongOffset, frame); +} +#endif /* ZSTD_FORCE_DECOMPRESS_SEQUENCES_LONG */ + +#ifndef ZSTD_FORCE_DECOMPRESS_SEQUENCES_SHORT +static BMI2_TARGET_ATTRIBUTE size_t +ZSTD_decompressSequencesLong_bmi2(ZSTD_DCtx* dctx, + void* dst, size_t maxDstSize, + const void* seqStart, size_t seqSize, int nbSeq, + const ZSTD_longOffset_e isLongOffset, + const int frame) +{ + return ZSTD_decompressSequencesLong_body(dctx, dst, maxDstSize, seqStart, seqSize, nbSeq, isLongOffset, frame); +} +#endif /* ZSTD_FORCE_DECOMPRESS_SEQUENCES_SHORT */ + +#endif /* DYNAMIC_BMI2 */ + +typedef size_t (*ZSTD_decompressSequences_t)( + ZSTD_DCtx* dctx, + void* dst, size_t maxDstSize, + const void* seqStart, size_t seqSize, int nbSeq, + const ZSTD_longOffset_e isLongOffset, + const int frame); + +#ifndef ZSTD_FORCE_DECOMPRESS_SEQUENCES_LONG +static size_t +ZSTD_decompressSequences(ZSTD_DCtx* dctx, void* dst, size_t maxDstSize, + const void* seqStart, size_t seqSize, int nbSeq, + const ZSTD_longOffset_e isLongOffset, + const int frame) +{ + DEBUGLOG(5, "ZSTD_decompressSequences"); +#if DYNAMIC_BMI2 + if (ZSTD_DCtx_get_bmi2(dctx)) { + return ZSTD_decompressSequences_bmi2(dctx, dst, maxDstSize, seqStart, seqSize, nbSeq, isLongOffset, frame); + } +#endif + return ZSTD_decompressSequences_default(dctx, dst, maxDstSize, seqStart, seqSize, nbSeq, isLongOffset, frame); +} +static size_t +ZSTD_decompressSequencesSplitLitBuffer(ZSTD_DCtx* dctx, void* dst, size_t maxDstSize, + const void* seqStart, size_t seqSize, int nbSeq, + const ZSTD_longOffset_e isLongOffset, + const int frame) +{ + DEBUGLOG(5, "ZSTD_decompressSequencesSplitLitBuffer"); +#if DYNAMIC_BMI2 + if (ZSTD_DCtx_get_bmi2(dctx)) { + return ZSTD_decompressSequencesSplitLitBuffer_bmi2(dctx, dst, maxDstSize, seqStart, seqSize, nbSeq, isLongOffset, frame); + } +#endif + return ZSTD_decompressSequencesSplitLitBuffer_default(dctx, dst, maxDstSize, seqStart, seqSize, nbSeq, isLongOffset, frame); +} +#endif /* ZSTD_FORCE_DECOMPRESS_SEQUENCES_LONG */ + + +#ifndef ZSTD_FORCE_DECOMPRESS_SEQUENCES_SHORT +/* ZSTD_decompressSequencesLong() : + * decompression function triggered when a minimum share of offsets is considered "long", + * aka out of cache. + * note : "long" definition seems overloaded here, sometimes meaning "wider than bitstream register", and sometimes meaning "farther than memory cache distance". + * This function will try to mitigate main memory latency through the use of prefetching */ +static size_t +ZSTD_decompressSequencesLong(ZSTD_DCtx* dctx, + void* dst, size_t maxDstSize, + const void* seqStart, size_t seqSize, int nbSeq, + const ZSTD_longOffset_e isLongOffset, + const int frame) +{ + DEBUGLOG(5, "ZSTD_decompressSequencesLong"); +#if DYNAMIC_BMI2 + if (ZSTD_DCtx_get_bmi2(dctx)) { + return ZSTD_decompressSequencesLong_bmi2(dctx, dst, maxDstSize, seqStart, seqSize, nbSeq, isLongOffset, frame); + } +#endif + return ZSTD_decompressSequencesLong_default(dctx, dst, maxDstSize, seqStart, seqSize, nbSeq, isLongOffset, frame); +} +#endif /* ZSTD_FORCE_DECOMPRESS_SEQUENCES_SHORT */ + + + +#if !defined(ZSTD_FORCE_DECOMPRESS_SEQUENCES_SHORT) && \ + !defined(ZSTD_FORCE_DECOMPRESS_SEQUENCES_LONG) +/* ZSTD_getLongOffsetsShare() : + * condition : offTable must be valid + * @return : "share" of long offsets (arbitrarily defined as > (1<<23)) + * compared to maximum possible of (1< 22) total += 1; + } + + assert(tableLog <= OffFSELog); + total <<= (OffFSELog - tableLog); /* scale to OffFSELog */ + + return total; +} +#endif + +size_t +ZSTD_decompressBlock_internal(ZSTD_DCtx* dctx, + void* dst, size_t dstCapacity, + const void* src, size_t srcSize, const int frame, const streaming_operation streaming) +{ /* blockType == blockCompressed */ + const BYTE* ip = (const BYTE*)src; + /* isLongOffset must be true if there are long offsets. + * Offsets are long if they are larger than 2^STREAM_ACCUMULATOR_MIN. + * We don't expect that to be the case in 64-bit mode. + * In block mode, window size is not known, so we have to be conservative. + * (note: but it could be evaluated from current-lowLimit) + */ + ZSTD_longOffset_e const isLongOffset = (ZSTD_longOffset_e)(MEM_32bits() && (!frame || (dctx->fParams.windowSize > (1ULL << STREAM_ACCUMULATOR_MIN)))); + DEBUGLOG(5, "ZSTD_decompressBlock_internal (size : %u)", (U32)srcSize); + + RETURN_ERROR_IF(srcSize >= ZSTD_BLOCKSIZE_MAX, srcSize_wrong, ""); + + /* Decode literals section */ + { size_t const litCSize = ZSTD_decodeLiteralsBlock(dctx, src, srcSize, dst, dstCapacity, streaming); + DEBUGLOG(5, "ZSTD_decodeLiteralsBlock : %u", (U32)litCSize); + if (ZSTD_isError(litCSize)) return litCSize; + ip += litCSize; + srcSize -= litCSize; + } + + /* Build Decoding Tables */ + { + /* These macros control at build-time which decompressor implementation + * we use. If neither is defined, we do some inspection and dispatch at + * runtime. + */ +#if !defined(ZSTD_FORCE_DECOMPRESS_SEQUENCES_SHORT) && \ + !defined(ZSTD_FORCE_DECOMPRESS_SEQUENCES_LONG) + int usePrefetchDecoder = dctx->ddictIsCold; +#endif + int nbSeq; + size_t const seqHSize = ZSTD_decodeSeqHeaders(dctx, &nbSeq, ip, srcSize); + if (ZSTD_isError(seqHSize)) return seqHSize; + ip += seqHSize; + srcSize -= seqHSize; + + RETURN_ERROR_IF(dst == NULL && nbSeq > 0, dstSize_tooSmall, "NULL not handled"); + +#if !defined(ZSTD_FORCE_DECOMPRESS_SEQUENCES_SHORT) && \ + !defined(ZSTD_FORCE_DECOMPRESS_SEQUENCES_LONG) + if ( !usePrefetchDecoder + && (!frame || (dctx->fParams.windowSize > (1<<24))) + && (nbSeq>ADVANCED_SEQS) ) { /* could probably use a larger nbSeq limit */ + U32 const shareLongOffsets = ZSTD_getLongOffsetsShare(dctx->OFTptr); + U32 const minShare = MEM_64bits() ? 7 : 20; /* heuristic values, correspond to 2.73% and 7.81% */ + usePrefetchDecoder = (shareLongOffsets >= minShare); + } +#endif + + dctx->ddictIsCold = 0; + +#if !defined(ZSTD_FORCE_DECOMPRESS_SEQUENCES_SHORT) && \ + !defined(ZSTD_FORCE_DECOMPRESS_SEQUENCES_LONG) + if (usePrefetchDecoder) +#endif +#ifndef ZSTD_FORCE_DECOMPRESS_SEQUENCES_SHORT + return ZSTD_decompressSequencesLong(dctx, dst, dstCapacity, ip, srcSize, nbSeq, isLongOffset, frame); +#endif + +#ifndef ZSTD_FORCE_DECOMPRESS_SEQUENCES_LONG + /* else */ + if (dctx->litBufferLocation == ZSTD_split) + return ZSTD_decompressSequencesSplitLitBuffer(dctx, dst, dstCapacity, ip, srcSize, nbSeq, isLongOffset, frame); + else + return ZSTD_decompressSequences(dctx, dst, dstCapacity, ip, srcSize, nbSeq, isLongOffset, frame); +#endif + } +} + + +void ZSTD_checkContinuity(ZSTD_DCtx* dctx, const void* dst, size_t dstSize) +{ + if (dst != dctx->previousDstEnd && dstSize > 0) { /* not contiguous */ + dctx->dictEnd = dctx->previousDstEnd; + dctx->virtualStart = (const char*)dst - ((const char*)(dctx->previousDstEnd) - (const char*)(dctx->prefixStart)); + dctx->prefixStart = dst; + dctx->previousDstEnd = dst; + } +} + + +size_t ZSTD_decompressBlock(ZSTD_DCtx* dctx, + void* dst, size_t dstCapacity, + const void* src, size_t srcSize) +{ + size_t dSize; + ZSTD_checkContinuity(dctx, dst, dstCapacity); + dSize = ZSTD_decompressBlock_internal(dctx, dst, dstCapacity, src, srcSize, /* frame */ 0, not_streaming); + dctx->previousDstEnd = (char*)dst + dSize; + return dSize; +} diff --git a/stage1/zstd/lib/decompress/zstd_decompress_block.h b/stage1/zstd/lib/decompress/zstd_decompress_block.h new file mode 100644 index 000000000000..c61a9d0c4b36 --- /dev/null +++ b/stage1/zstd/lib/decompress/zstd_decompress_block.h @@ -0,0 +1,68 @@ +/* + * Copyright (c) Yann Collet, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under both the BSD-style license (found in the + * LICENSE file in the root directory of this source tree) and the GPLv2 (found + * in the COPYING file in the root directory of this source tree). + * You may select, at your option, one of the above-listed licenses. + */ + + +#ifndef ZSTD_DEC_BLOCK_H +#define ZSTD_DEC_BLOCK_H + +/*-******************************************************* + * Dependencies + *********************************************************/ +#include "../common/zstd_deps.h" /* size_t */ +#include "../zstd.h" /* DCtx, and some public functions */ +#include "../common/zstd_internal.h" /* blockProperties_t, and some public functions */ +#include "zstd_decompress_internal.h" /* ZSTD_seqSymbol */ + + +/* === Prototypes === */ + +/* note: prototypes already published within `zstd.h` : + * ZSTD_decompressBlock() + */ + +/* note: prototypes already published within `zstd_internal.h` : + * ZSTD_getcBlockSize() + * ZSTD_decodeSeqHeaders() + */ + + + /* Streaming state is used to inform allocation of the literal buffer */ +typedef enum { + not_streaming = 0, + is_streaming = 1 +} streaming_operation; + +/* ZSTD_decompressBlock_internal() : + * decompress block, starting at `src`, + * into destination buffer `dst`. + * @return : decompressed block size, + * or an error code (which can be tested using ZSTD_isError()) + */ +size_t ZSTD_decompressBlock_internal(ZSTD_DCtx* dctx, + void* dst, size_t dstCapacity, + const void* src, size_t srcSize, const int frame, const streaming_operation streaming); + +/* ZSTD_buildFSETable() : + * generate FSE decoding table for one symbol (ll, ml or off) + * this function must be called with valid parameters only + * (dt is large enough, normalizedCounter distribution total is a power of 2, max is within range, etc.) + * in which case it cannot fail. + * The workspace must be 4-byte aligned and at least ZSTD_BUILD_FSE_TABLE_WKSP_SIZE bytes, which is + * defined in zstd_decompress_internal.h. + * Internal use only. + */ +void ZSTD_buildFSETable(ZSTD_seqSymbol* dt, + const short* normalizedCounter, unsigned maxSymbolValue, + const U32* baseValue, const U8* nbAdditionalBits, + unsigned tableLog, void* wksp, size_t wkspSize, + int bmi2); + + +#endif /* ZSTD_DEC_BLOCK_H */ diff --git a/stage1/zstd/lib/decompress/zstd_decompress_internal.h b/stage1/zstd/lib/decompress/zstd_decompress_internal.h new file mode 100644 index 000000000000..2b5a53850ac2 --- /dev/null +++ b/stage1/zstd/lib/decompress/zstd_decompress_internal.h @@ -0,0 +1,236 @@ +/* + * Copyright (c) Yann Collet, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under both the BSD-style license (found in the + * LICENSE file in the root directory of this source tree) and the GPLv2 (found + * in the COPYING file in the root directory of this source tree). + * You may select, at your option, one of the above-listed licenses. + */ + + +/* zstd_decompress_internal: + * objects and definitions shared within lib/decompress modules */ + + #ifndef ZSTD_DECOMPRESS_INTERNAL_H + #define ZSTD_DECOMPRESS_INTERNAL_H + + +/*-******************************************************* + * Dependencies + *********************************************************/ +#include "../common/mem.h" /* BYTE, U16, U32 */ +#include "../common/zstd_internal.h" /* constants : MaxLL, MaxML, MaxOff, LLFSELog, etc. */ + + + +/*-******************************************************* + * Constants + *********************************************************/ +static UNUSED_ATTR const U32 LL_base[MaxLL+1] = { + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 10, 11, 12, 13, 14, 15, + 16, 18, 20, 22, 24, 28, 32, 40, + 48, 64, 0x80, 0x100, 0x200, 0x400, 0x800, 0x1000, + 0x2000, 0x4000, 0x8000, 0x10000 }; + +static UNUSED_ATTR const U32 OF_base[MaxOff+1] = { + 0, 1, 1, 5, 0xD, 0x1D, 0x3D, 0x7D, + 0xFD, 0x1FD, 0x3FD, 0x7FD, 0xFFD, 0x1FFD, 0x3FFD, 0x7FFD, + 0xFFFD, 0x1FFFD, 0x3FFFD, 0x7FFFD, 0xFFFFD, 0x1FFFFD, 0x3FFFFD, 0x7FFFFD, + 0xFFFFFD, 0x1FFFFFD, 0x3FFFFFD, 0x7FFFFFD, 0xFFFFFFD, 0x1FFFFFFD, 0x3FFFFFFD, 0x7FFFFFFD }; + +static UNUSED_ATTR const U8 OF_bits[MaxOff+1] = { + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, + 24, 25, 26, 27, 28, 29, 30, 31 }; + +static UNUSED_ATTR const U32 ML_base[MaxML+1] = { + 3, 4, 5, 6, 7, 8, 9, 10, + 11, 12, 13, 14, 15, 16, 17, 18, + 19, 20, 21, 22, 23, 24, 25, 26, + 27, 28, 29, 30, 31, 32, 33, 34, + 35, 37, 39, 41, 43, 47, 51, 59, + 67, 83, 99, 0x83, 0x103, 0x203, 0x403, 0x803, + 0x1003, 0x2003, 0x4003, 0x8003, 0x10003 }; + + +/*-******************************************************* + * Decompression types + *********************************************************/ + typedef struct { + U32 fastMode; + U32 tableLog; + } ZSTD_seqSymbol_header; + + typedef struct { + U16 nextState; + BYTE nbAdditionalBits; + BYTE nbBits; + U32 baseValue; + } ZSTD_seqSymbol; + + #define SEQSYMBOL_TABLE_SIZE(log) (1 + (1 << (log))) + +#define ZSTD_BUILD_FSE_TABLE_WKSP_SIZE (sizeof(S16) * (MaxSeq + 1) + (1u << MaxFSELog) + sizeof(U64)) +#define ZSTD_BUILD_FSE_TABLE_WKSP_SIZE_U32 ((ZSTD_BUILD_FSE_TABLE_WKSP_SIZE + sizeof(U32) - 1) / sizeof(U32)) + +typedef struct { + ZSTD_seqSymbol LLTable[SEQSYMBOL_TABLE_SIZE(LLFSELog)]; /* Note : Space reserved for FSE Tables */ + ZSTD_seqSymbol OFTable[SEQSYMBOL_TABLE_SIZE(OffFSELog)]; /* is also used as temporary workspace while building hufTable during DDict creation */ + ZSTD_seqSymbol MLTable[SEQSYMBOL_TABLE_SIZE(MLFSELog)]; /* and therefore must be at least HUF_DECOMPRESS_WORKSPACE_SIZE large */ + HUF_DTable hufTable[HUF_DTABLE_SIZE(HufLog)]; /* can accommodate HUF_decompress4X */ + U32 rep[ZSTD_REP_NUM]; + U32 workspace[ZSTD_BUILD_FSE_TABLE_WKSP_SIZE_U32]; +} ZSTD_entropyDTables_t; + +typedef enum { ZSTDds_getFrameHeaderSize, ZSTDds_decodeFrameHeader, + ZSTDds_decodeBlockHeader, ZSTDds_decompressBlock, + ZSTDds_decompressLastBlock, ZSTDds_checkChecksum, + ZSTDds_decodeSkippableHeader, ZSTDds_skipFrame } ZSTD_dStage; + +typedef enum { zdss_init=0, zdss_loadHeader, + zdss_read, zdss_load, zdss_flush } ZSTD_dStreamStage; + +typedef enum { + ZSTD_use_indefinitely = -1, /* Use the dictionary indefinitely */ + ZSTD_dont_use = 0, /* Do not use the dictionary (if one exists free it) */ + ZSTD_use_once = 1 /* Use the dictionary once and set to ZSTD_dont_use */ +} ZSTD_dictUses_e; + +/* Hashset for storing references to multiple ZSTD_DDict within ZSTD_DCtx */ +typedef struct { + const ZSTD_DDict** ddictPtrTable; + size_t ddictPtrTableSize; + size_t ddictPtrCount; +} ZSTD_DDictHashSet; + +#ifndef ZSTD_DECODER_INTERNAL_BUFFER +# define ZSTD_DECODER_INTERNAL_BUFFER (1 << 16) +#endif + +#define ZSTD_LBMIN 64 +#define ZSTD_LBMAX (128 << 10) + +/* extra buffer, compensates when dst is not large enough to store litBuffer */ +#define ZSTD_LITBUFFEREXTRASIZE BOUNDED(ZSTD_LBMIN, ZSTD_DECODER_INTERNAL_BUFFER, ZSTD_LBMAX) + +typedef enum { + ZSTD_not_in_dst = 0, /* Stored entirely within litExtraBuffer */ + ZSTD_in_dst = 1, /* Stored entirely within dst (in memory after current output write) */ + ZSTD_split = 2 /* Split between litExtraBuffer and dst */ +} ZSTD_litLocation_e; + +struct ZSTD_DCtx_s +{ + const ZSTD_seqSymbol* LLTptr; + const ZSTD_seqSymbol* MLTptr; + const ZSTD_seqSymbol* OFTptr; + const HUF_DTable* HUFptr; + ZSTD_entropyDTables_t entropy; + U32 workspace[HUF_DECOMPRESS_WORKSPACE_SIZE_U32]; /* space needed when building huffman tables */ + const void* previousDstEnd; /* detect continuity */ + const void* prefixStart; /* start of current segment */ + const void* virtualStart; /* virtual start of previous segment if it was just before current one */ + const void* dictEnd; /* end of previous segment */ + size_t expected; + ZSTD_frameHeader fParams; + U64 processedCSize; + U64 decodedSize; + blockType_e bType; /* used in ZSTD_decompressContinue(), store blockType between block header decoding and block decompression stages */ + ZSTD_dStage stage; + U32 litEntropy; + U32 fseEntropy; + XXH64_state_t xxhState; + size_t headerSize; + ZSTD_format_e format; + ZSTD_forceIgnoreChecksum_e forceIgnoreChecksum; /* User specified: if == 1, will ignore checksums in compressed frame. Default == 0 */ + U32 validateChecksum; /* if == 1, will validate checksum. Is == 1 if (fParams.checksumFlag == 1) and (forceIgnoreChecksum == 0). */ + const BYTE* litPtr; + ZSTD_customMem customMem; + size_t litSize; + size_t rleSize; + size_t staticSize; +#if DYNAMIC_BMI2 != 0 + int bmi2; /* == 1 if the CPU supports BMI2 and 0 otherwise. CPU support is determined dynamically once per context lifetime. */ +#endif + + /* dictionary */ + ZSTD_DDict* ddictLocal; + const ZSTD_DDict* ddict; /* set by ZSTD_initDStream_usingDDict(), or ZSTD_DCtx_refDDict() */ + U32 dictID; + int ddictIsCold; /* if == 1 : dictionary is "new" for working context, and presumed "cold" (not in cpu cache) */ + ZSTD_dictUses_e dictUses; + ZSTD_DDictHashSet* ddictSet; /* Hash set for multiple ddicts */ + ZSTD_refMultipleDDicts_e refMultipleDDicts; /* User specified: if == 1, will allow references to multiple DDicts. Default == 0 (disabled) */ + + /* streaming */ + ZSTD_dStreamStage streamStage; + char* inBuff; + size_t inBuffSize; + size_t inPos; + size_t maxWindowSize; + char* outBuff; + size_t outBuffSize; + size_t outStart; + size_t outEnd; + size_t lhSize; +#if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT>=1) + void* legacyContext; + U32 previousLegacyVersion; + U32 legacyVersion; +#endif + U32 hostageByte; + int noForwardProgress; + ZSTD_bufferMode_e outBufferMode; + ZSTD_outBuffer expectedOutBuffer; + + /* workspace */ + BYTE* litBuffer; + const BYTE* litBufferEnd; + ZSTD_litLocation_e litBufferLocation; + BYTE litExtraBuffer[ZSTD_LITBUFFEREXTRASIZE + WILDCOPY_OVERLENGTH]; /* literal buffer can be split between storage within dst and within this scratch buffer */ + BYTE headerBuffer[ZSTD_FRAMEHEADERSIZE_MAX]; + + size_t oversizedDuration; + +#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION + void const* dictContentBeginForFuzzing; + void const* dictContentEndForFuzzing; +#endif + + /* Tracing */ +#if ZSTD_TRACE + ZSTD_TraceCtx traceCtx; +#endif +}; /* typedef'd to ZSTD_DCtx within "zstd.h" */ + +MEM_STATIC int ZSTD_DCtx_get_bmi2(const struct ZSTD_DCtx_s *dctx) { +#if DYNAMIC_BMI2 != 0 + return dctx->bmi2; +#else + (void)dctx; + return 0; +#endif +} + +/*-******************************************************* + * Shared internal functions + *********************************************************/ + +/*! ZSTD_loadDEntropy() : + * dict : must point at beginning of a valid zstd dictionary. + * @return : size of dictionary header (size of magic number + dict ID + entropy tables) */ +size_t ZSTD_loadDEntropy(ZSTD_entropyDTables_t* entropy, + const void* const dict, size_t const dictSize); + +/*! ZSTD_checkContinuity() : + * check if next `dst` follows previous position, where decompression ended. + * If yes, do nothing (continue on current segment). + * If not, classify previous segment as "external dictionary", and start a new segment. + * This function cannot fail. */ +void ZSTD_checkContinuity(ZSTD_DCtx* dctx, const void* dst, size_t dstSize); + + +#endif /* ZSTD_DECOMPRESS_INTERNAL_H */ diff --git a/stage1/zstd/lib/zstd.h b/stage1/zstd/lib/zstd.h new file mode 100644 index 000000000000..a88ae7bf8ed5 --- /dev/null +++ b/stage1/zstd/lib/zstd.h @@ -0,0 +1,2575 @@ +/* + * Copyright (c) Yann Collet, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under both the BSD-style license (found in the + * LICENSE file in the root directory of this source tree) and the GPLv2 (found + * in the COPYING file in the root directory of this source tree). + * You may select, at your option, one of the above-listed licenses. + */ +#if defined (__cplusplus) +extern "C" { +#endif + +#ifndef ZSTD_H_235446 +#define ZSTD_H_235446 + +/* ====== Dependency ======*/ +#include /* INT_MAX */ +#include /* size_t */ + + +/* ===== ZSTDLIB_API : control library symbols visibility ===== */ +#ifndef ZSTDLIB_VISIBLE +# if defined(__GNUC__) && (__GNUC__ >= 4) && !defined(__MINGW32__) +# define ZSTDLIB_VISIBLE __attribute__ ((visibility ("default"))) +# define ZSTDLIB_HIDDEN __attribute__ ((visibility ("hidden"))) +# else +# define ZSTDLIB_VISIBLE +# define ZSTDLIB_HIDDEN +# endif +#endif +#if defined(ZSTD_DLL_EXPORT) && (ZSTD_DLL_EXPORT==1) +# define ZSTDLIB_API __declspec(dllexport) ZSTDLIB_VISIBLE +#elif defined(ZSTD_DLL_IMPORT) && (ZSTD_DLL_IMPORT==1) +# define ZSTDLIB_API __declspec(dllimport) ZSTDLIB_VISIBLE /* It isn't required but allows to generate better code, saving a function pointer load from the IAT and an indirect jump.*/ +#else +# define ZSTDLIB_API ZSTDLIB_VISIBLE +#endif + + +/******************************************************************************* + Introduction + + zstd, short for Zstandard, is a fast lossless compression algorithm, targeting + real-time compression scenarios at zlib-level and better compression ratios. + The zstd compression library provides in-memory compression and decompression + functions. + + The library supports regular compression levels from 1 up to ZSTD_maxCLevel(), + which is currently 22. Levels >= 20, labeled `--ultra`, should be used with + caution, as they require more memory. The library also offers negative + compression levels, which extend the range of speed vs. ratio preferences. + The lower the level, the faster the speed (at the cost of compression). + + Compression can be done in: + - a single step (described as Simple API) + - a single step, reusing a context (described as Explicit context) + - unbounded multiple steps (described as Streaming compression) + + The compression ratio achievable on small data can be highly improved using + a dictionary. Dictionary compression can be performed in: + - a single step (described as Simple dictionary API) + - a single step, reusing a dictionary (described as Bulk-processing + dictionary API) + + Advanced experimental functions can be accessed using + `#define ZSTD_STATIC_LINKING_ONLY` before including zstd.h. + + Advanced experimental APIs should never be used with a dynamically-linked + library. They are not "stable"; their definitions or signatures may change in + the future. Only static linking is allowed. +*******************************************************************************/ + +/*------ Version ------*/ +#define ZSTD_VERSION_MAJOR 1 +#define ZSTD_VERSION_MINOR 5 +#define ZSTD_VERSION_RELEASE 2 +#define ZSTD_VERSION_NUMBER (ZSTD_VERSION_MAJOR *100*100 + ZSTD_VERSION_MINOR *100 + ZSTD_VERSION_RELEASE) + +/*! ZSTD_versionNumber() : + * Return runtime library version, the value is (MAJOR*100*100 + MINOR*100 + RELEASE). */ +ZSTDLIB_API unsigned ZSTD_versionNumber(void); + +#define ZSTD_LIB_VERSION ZSTD_VERSION_MAJOR.ZSTD_VERSION_MINOR.ZSTD_VERSION_RELEASE +#define ZSTD_QUOTE(str) #str +#define ZSTD_EXPAND_AND_QUOTE(str) ZSTD_QUOTE(str) +#define ZSTD_VERSION_STRING ZSTD_EXPAND_AND_QUOTE(ZSTD_LIB_VERSION) + +/*! ZSTD_versionString() : + * Return runtime library version, like "1.4.5". Requires v1.3.0+. */ +ZSTDLIB_API const char* ZSTD_versionString(void); + +/* ************************************* + * Default constant + ***************************************/ +#ifndef ZSTD_CLEVEL_DEFAULT +# define ZSTD_CLEVEL_DEFAULT 3 +#endif + +/* ************************************* + * Constants + ***************************************/ + +/* All magic numbers are supposed read/written to/from files/memory using little-endian convention */ +#define ZSTD_MAGICNUMBER 0xFD2FB528 /* valid since v0.8.0 */ +#define ZSTD_MAGIC_DICTIONARY 0xEC30A437 /* valid since v0.7.0 */ +#define ZSTD_MAGIC_SKIPPABLE_START 0x184D2A50 /* all 16 values, from 0x184D2A50 to 0x184D2A5F, signal the beginning of a skippable frame */ +#define ZSTD_MAGIC_SKIPPABLE_MASK 0xFFFFFFF0 + +#define ZSTD_BLOCKSIZELOG_MAX 17 +#define ZSTD_BLOCKSIZE_MAX (1<= `ZSTD_compressBound(srcSize)`. + * @return : compressed size written into `dst` (<= `dstCapacity), + * or an error code if it fails (which can be tested using ZSTD_isError()). */ +ZSTDLIB_API size_t ZSTD_compress( void* dst, size_t dstCapacity, + const void* src, size_t srcSize, + int compressionLevel); + +/*! ZSTD_decompress() : + * `compressedSize` : must be the _exact_ size of some number of compressed and/or skippable frames. + * `dstCapacity` is an upper bound of originalSize to regenerate. + * If user cannot imply a maximum upper bound, it's better to use streaming mode to decompress data. + * @return : the number of bytes decompressed into `dst` (<= `dstCapacity`), + * or an errorCode if it fails (which can be tested using ZSTD_isError()). */ +ZSTDLIB_API size_t ZSTD_decompress( void* dst, size_t dstCapacity, + const void* src, size_t compressedSize); + +/*! ZSTD_getFrameContentSize() : requires v1.3.0+ + * `src` should point to the start of a ZSTD encoded frame. + * `srcSize` must be at least as large as the frame header. + * hint : any size >= `ZSTD_frameHeaderSize_max` is large enough. + * @return : - decompressed size of `src` frame content, if known + * - ZSTD_CONTENTSIZE_UNKNOWN if the size cannot be determined + * - ZSTD_CONTENTSIZE_ERROR if an error occurred (e.g. invalid magic number, srcSize too small) + * note 1 : a 0 return value means the frame is valid but "empty". + * note 2 : decompressed size is an optional field, it may not be present, typically in streaming mode. + * When `return==ZSTD_CONTENTSIZE_UNKNOWN`, data to decompress could be any size. + * In which case, it's necessary to use streaming mode to decompress data. + * Optionally, application can rely on some implicit limit, + * as ZSTD_decompress() only needs an upper bound of decompressed size. + * (For example, data could be necessarily cut into blocks <= 16 KB). + * note 3 : decompressed size is always present when compression is completed using single-pass functions, + * such as ZSTD_compress(), ZSTD_compressCCtx() ZSTD_compress_usingDict() or ZSTD_compress_usingCDict(). + * note 4 : decompressed size can be very large (64-bits value), + * potentially larger than what local system can handle as a single memory segment. + * In which case, it's necessary to use streaming mode to decompress data. + * note 5 : If source is untrusted, decompressed size could be wrong or intentionally modified. + * Always ensure return value fits within application's authorized limits. + * Each application can set its own limits. + * note 6 : This function replaces ZSTD_getDecompressedSize() */ +#define ZSTD_CONTENTSIZE_UNKNOWN (0ULL - 1) +#define ZSTD_CONTENTSIZE_ERROR (0ULL - 2) +ZSTDLIB_API unsigned long long ZSTD_getFrameContentSize(const void *src, size_t srcSize); + +/*! ZSTD_getDecompressedSize() : + * NOTE: This function is now obsolete, in favor of ZSTD_getFrameContentSize(). + * Both functions work the same way, but ZSTD_getDecompressedSize() blends + * "empty", "unknown" and "error" results to the same return value (0), + * while ZSTD_getFrameContentSize() gives them separate return values. + * @return : decompressed size of `src` frame content _if known and not empty_, 0 otherwise. */ +ZSTDLIB_API unsigned long long ZSTD_getDecompressedSize(const void* src, size_t srcSize); + +/*! ZSTD_findFrameCompressedSize() : Requires v1.4.0+ + * `src` should point to the start of a ZSTD frame or skippable frame. + * `srcSize` must be >= first frame size + * @return : the compressed size of the first frame starting at `src`, + * suitable to pass as `srcSize` to `ZSTD_decompress` or similar, + * or an error code if input is invalid */ +ZSTDLIB_API size_t ZSTD_findFrameCompressedSize(const void* src, size_t srcSize); + + +/*====== Helper functions ======*/ +#define ZSTD_COMPRESSBOUND(srcSize) ((srcSize) + ((srcSize)>>8) + (((srcSize) < (128<<10)) ? (((128<<10) - (srcSize)) >> 11) /* margin, from 64 to 0 */ : 0)) /* this formula ensures that bound(A) + bound(B) <= bound(A+B) as long as A and B >= 128 KB */ +ZSTDLIB_API size_t ZSTD_compressBound(size_t srcSize); /*!< maximum compressed size in worst case single-pass scenario */ +ZSTDLIB_API unsigned ZSTD_isError(size_t code); /*!< tells if a `size_t` function result is an error code */ +ZSTDLIB_API const char* ZSTD_getErrorName(size_t code); /*!< provides readable string from an error code */ +ZSTDLIB_API int ZSTD_minCLevel(void); /*!< minimum negative compression level allowed, requires v1.4.0+ */ +ZSTDLIB_API int ZSTD_maxCLevel(void); /*!< maximum compression level available */ +ZSTDLIB_API int ZSTD_defaultCLevel(void); /*!< default compression level, specified by ZSTD_CLEVEL_DEFAULT, requires v1.5.0+ */ + + +/*************************************** +* Explicit context +***************************************/ +/*= Compression context + * When compressing many times, + * it is recommended to allocate a context just once, + * and re-use it for each successive compression operation. + * This will make workload friendlier for system's memory. + * Note : re-using context is just a speed / resource optimization. + * It doesn't change the compression ratio, which remains identical. + * Note 2 : In multi-threaded environments, + * use one different context per thread for parallel execution. + */ +typedef struct ZSTD_CCtx_s ZSTD_CCtx; +ZSTDLIB_API ZSTD_CCtx* ZSTD_createCCtx(void); +ZSTDLIB_API size_t ZSTD_freeCCtx(ZSTD_CCtx* cctx); /* accept NULL pointer */ + +/*! ZSTD_compressCCtx() : + * Same as ZSTD_compress(), using an explicit ZSTD_CCtx. + * Important : in order to behave similarly to `ZSTD_compress()`, + * this function compresses at requested compression level, + * __ignoring any other parameter__ . + * If any advanced parameter was set using the advanced API, + * they will all be reset. Only `compressionLevel` remains. + */ +ZSTDLIB_API size_t ZSTD_compressCCtx(ZSTD_CCtx* cctx, + void* dst, size_t dstCapacity, + const void* src, size_t srcSize, + int compressionLevel); + +/*= Decompression context + * When decompressing many times, + * it is recommended to allocate a context only once, + * and re-use it for each successive compression operation. + * This will make workload friendlier for system's memory. + * Use one context per thread for parallel execution. */ +typedef struct ZSTD_DCtx_s ZSTD_DCtx; +ZSTDLIB_API ZSTD_DCtx* ZSTD_createDCtx(void); +ZSTDLIB_API size_t ZSTD_freeDCtx(ZSTD_DCtx* dctx); /* accept NULL pointer */ + +/*! ZSTD_decompressDCtx() : + * Same as ZSTD_decompress(), + * requires an allocated ZSTD_DCtx. + * Compatible with sticky parameters. + */ +ZSTDLIB_API size_t ZSTD_decompressDCtx(ZSTD_DCtx* dctx, + void* dst, size_t dstCapacity, + const void* src, size_t srcSize); + + +/********************************************* +* Advanced compression API (Requires v1.4.0+) +**********************************************/ + +/* API design : + * Parameters are pushed one by one into an existing context, + * using ZSTD_CCtx_set*() functions. + * Pushed parameters are sticky : they are valid for next compressed frame, and any subsequent frame. + * "sticky" parameters are applicable to `ZSTD_compress2()` and `ZSTD_compressStream*()` ! + * __They do not apply to "simple" one-shot variants such as ZSTD_compressCCtx()__ . + * + * It's possible to reset all parameters to "default" using ZSTD_CCtx_reset(). + * + * This API supersedes all other "advanced" API entry points in the experimental section. + * In the future, we expect to remove from experimental API entry points which are redundant with this API. + */ + + +/* Compression strategies, listed from fastest to strongest */ +typedef enum { ZSTD_fast=1, + ZSTD_dfast=2, + ZSTD_greedy=3, + ZSTD_lazy=4, + ZSTD_lazy2=5, + ZSTD_btlazy2=6, + ZSTD_btopt=7, + ZSTD_btultra=8, + ZSTD_btultra2=9 + /* note : new strategies _might_ be added in the future. + Only the order (from fast to strong) is guaranteed */ +} ZSTD_strategy; + +typedef enum { + + /* compression parameters + * Note: When compressing with a ZSTD_CDict these parameters are superseded + * by the parameters used to construct the ZSTD_CDict. + * See ZSTD_CCtx_refCDict() for more info (superseded-by-cdict). */ + ZSTD_c_compressionLevel=100, /* Set compression parameters according to pre-defined cLevel table. + * Note that exact compression parameters are dynamically determined, + * depending on both compression level and srcSize (when known). + * Default level is ZSTD_CLEVEL_DEFAULT==3. + * Special: value 0 means default, which is controlled by ZSTD_CLEVEL_DEFAULT. + * Note 1 : it's possible to pass a negative compression level. + * Note 2 : setting a level does not automatically set all other compression parameters + * to default. Setting this will however eventually dynamically impact the compression + * parameters which have not been manually set. The manually set + * ones will 'stick'. */ + /* Advanced compression parameters : + * It's possible to pin down compression parameters to some specific values. + * In which case, these values are no longer dynamically selected by the compressor */ + ZSTD_c_windowLog=101, /* Maximum allowed back-reference distance, expressed as power of 2. + * This will set a memory budget for streaming decompression, + * with larger values requiring more memory + * and typically compressing more. + * Must be clamped between ZSTD_WINDOWLOG_MIN and ZSTD_WINDOWLOG_MAX. + * Special: value 0 means "use default windowLog". + * Note: Using a windowLog greater than ZSTD_WINDOWLOG_LIMIT_DEFAULT + * requires explicitly allowing such size at streaming decompression stage. */ + ZSTD_c_hashLog=102, /* Size of the initial probe table, as a power of 2. + * Resulting memory usage is (1 << (hashLog+2)). + * Must be clamped between ZSTD_HASHLOG_MIN and ZSTD_HASHLOG_MAX. + * Larger tables improve compression ratio of strategies <= dFast, + * and improve speed of strategies > dFast. + * Special: value 0 means "use default hashLog". */ + ZSTD_c_chainLog=103, /* Size of the multi-probe search table, as a power of 2. + * Resulting memory usage is (1 << (chainLog+2)). + * Must be clamped between ZSTD_CHAINLOG_MIN and ZSTD_CHAINLOG_MAX. + * Larger tables result in better and slower compression. + * This parameter is useless for "fast" strategy. + * It's still useful when using "dfast" strategy, + * in which case it defines a secondary probe table. + * Special: value 0 means "use default chainLog". */ + ZSTD_c_searchLog=104, /* Number of search attempts, as a power of 2. + * More attempts result in better and slower compression. + * This parameter is useless for "fast" and "dFast" strategies. + * Special: value 0 means "use default searchLog". */ + ZSTD_c_minMatch=105, /* Minimum size of searched matches. + * Note that Zstandard can still find matches of smaller size, + * it just tweaks its search algorithm to look for this size and larger. + * Larger values increase compression and decompression speed, but decrease ratio. + * Must be clamped between ZSTD_MINMATCH_MIN and ZSTD_MINMATCH_MAX. + * Note that currently, for all strategies < btopt, effective minimum is 4. + * , for all strategies > fast, effective maximum is 6. + * Special: value 0 means "use default minMatchLength". */ + ZSTD_c_targetLength=106, /* Impact of this field depends on strategy. + * For strategies btopt, btultra & btultra2: + * Length of Match considered "good enough" to stop search. + * Larger values make compression stronger, and slower. + * For strategy fast: + * Distance between match sampling. + * Larger values make compression faster, and weaker. + * Special: value 0 means "use default targetLength". */ + ZSTD_c_strategy=107, /* See ZSTD_strategy enum definition. + * The higher the value of selected strategy, the more complex it is, + * resulting in stronger and slower compression. + * Special: value 0 means "use default strategy". */ + /* LDM mode parameters */ + ZSTD_c_enableLongDistanceMatching=160, /* Enable long distance matching. + * This parameter is designed to improve compression ratio + * for large inputs, by finding large matches at long distance. + * It increases memory usage and window size. + * Note: enabling this parameter increases default ZSTD_c_windowLog to 128 MB + * except when expressly set to a different value. + * Note: will be enabled by default if ZSTD_c_windowLog >= 128 MB and + * compression strategy >= ZSTD_btopt (== compression level 16+) */ + ZSTD_c_ldmHashLog=161, /* Size of the table for long distance matching, as a power of 2. + * Larger values increase memory usage and compression ratio, + * but decrease compression speed. + * Must be clamped between ZSTD_HASHLOG_MIN and ZSTD_HASHLOG_MAX + * default: windowlog - 7. + * Special: value 0 means "automatically determine hashlog". */ + ZSTD_c_ldmMinMatch=162, /* Minimum match size for long distance matcher. + * Larger/too small values usually decrease compression ratio. + * Must be clamped between ZSTD_LDM_MINMATCH_MIN and ZSTD_LDM_MINMATCH_MAX. + * Special: value 0 means "use default value" (default: 64). */ + ZSTD_c_ldmBucketSizeLog=163, /* Log size of each bucket in the LDM hash table for collision resolution. + * Larger values improve collision resolution but decrease compression speed. + * The maximum value is ZSTD_LDM_BUCKETSIZELOG_MAX. + * Special: value 0 means "use default value" (default: 3). */ + ZSTD_c_ldmHashRateLog=164, /* Frequency of inserting/looking up entries into the LDM hash table. + * Must be clamped between 0 and (ZSTD_WINDOWLOG_MAX - ZSTD_HASHLOG_MIN). + * Default is MAX(0, (windowLog - ldmHashLog)), optimizing hash table usage. + * Larger values improve compression speed. + * Deviating far from default value will likely result in a compression ratio decrease. + * Special: value 0 means "automatically determine hashRateLog". */ + + /* frame parameters */ + ZSTD_c_contentSizeFlag=200, /* Content size will be written into frame header _whenever known_ (default:1) + * Content size must be known at the beginning of compression. + * This is automatically the case when using ZSTD_compress2(), + * For streaming scenarios, content size must be provided with ZSTD_CCtx_setPledgedSrcSize() */ + ZSTD_c_checksumFlag=201, /* A 32-bits checksum of content is written at end of frame (default:0) */ + ZSTD_c_dictIDFlag=202, /* When applicable, dictionary's ID is written into frame header (default:1) */ + + /* multi-threading parameters */ + /* These parameters are only active if multi-threading is enabled (compiled with build macro ZSTD_MULTITHREAD). + * Otherwise, trying to set any other value than default (0) will be a no-op and return an error. + * In a situation where it's unknown if the linked library supports multi-threading or not, + * setting ZSTD_c_nbWorkers to any value >= 1 and consulting the return value provides a quick way to check this property. + */ + ZSTD_c_nbWorkers=400, /* Select how many threads will be spawned to compress in parallel. + * When nbWorkers >= 1, triggers asynchronous mode when invoking ZSTD_compressStream*() : + * ZSTD_compressStream*() consumes input and flush output if possible, but immediately gives back control to caller, + * while compression is performed in parallel, within worker thread(s). + * (note : a strong exception to this rule is when first invocation of ZSTD_compressStream2() sets ZSTD_e_end : + * in which case, ZSTD_compressStream2() delegates to ZSTD_compress2(), which is always a blocking call). + * More workers improve speed, but also increase memory usage. + * Default value is `0`, aka "single-threaded mode" : no worker is spawned, + * compression is performed inside Caller's thread, and all invocations are blocking */ + ZSTD_c_jobSize=401, /* Size of a compression job. This value is enforced only when nbWorkers >= 1. + * Each compression job is completed in parallel, so this value can indirectly impact the nb of active threads. + * 0 means default, which is dynamically determined based on compression parameters. + * Job size must be a minimum of overlap size, or ZSTDMT_JOBSIZE_MIN (= 512 KB), whichever is largest. + * The minimum size is automatically and transparently enforced. */ + ZSTD_c_overlapLog=402, /* Control the overlap size, as a fraction of window size. + * The overlap size is an amount of data reloaded from previous job at the beginning of a new job. + * It helps preserve compression ratio, while each job is compressed in parallel. + * This value is enforced only when nbWorkers >= 1. + * Larger values increase compression ratio, but decrease speed. + * Possible values range from 0 to 9 : + * - 0 means "default" : value will be determined by the library, depending on strategy + * - 1 means "no overlap" + * - 9 means "full overlap", using a full window size. + * Each intermediate rank increases/decreases load size by a factor 2 : + * 9: full window; 8: w/2; 7: w/4; 6: w/8; 5:w/16; 4: w/32; 3:w/64; 2:w/128; 1:no overlap; 0:default + * default value varies between 6 and 9, depending on strategy */ + + /* note : additional experimental parameters are also available + * within the experimental section of the API. + * At the time of this writing, they include : + * ZSTD_c_rsyncable + * ZSTD_c_format + * ZSTD_c_forceMaxWindow + * ZSTD_c_forceAttachDict + * ZSTD_c_literalCompressionMode + * ZSTD_c_targetCBlockSize + * ZSTD_c_srcSizeHint + * ZSTD_c_enableDedicatedDictSearch + * ZSTD_c_stableInBuffer + * ZSTD_c_stableOutBuffer + * ZSTD_c_blockDelimiters + * ZSTD_c_validateSequences + * ZSTD_c_useBlockSplitter + * ZSTD_c_useRowMatchFinder + * Because they are not stable, it's necessary to define ZSTD_STATIC_LINKING_ONLY to access them. + * note : never ever use experimentalParam? names directly; + * also, the enums values themselves are unstable and can still change. + */ + ZSTD_c_experimentalParam1=500, + ZSTD_c_experimentalParam2=10, + ZSTD_c_experimentalParam3=1000, + ZSTD_c_experimentalParam4=1001, + ZSTD_c_experimentalParam5=1002, + ZSTD_c_experimentalParam6=1003, + ZSTD_c_experimentalParam7=1004, + ZSTD_c_experimentalParam8=1005, + ZSTD_c_experimentalParam9=1006, + ZSTD_c_experimentalParam10=1007, + ZSTD_c_experimentalParam11=1008, + ZSTD_c_experimentalParam12=1009, + ZSTD_c_experimentalParam13=1010, + ZSTD_c_experimentalParam14=1011, + ZSTD_c_experimentalParam15=1012 +} ZSTD_cParameter; + +typedef struct { + size_t error; + int lowerBound; + int upperBound; +} ZSTD_bounds; + +/*! ZSTD_cParam_getBounds() : + * All parameters must belong to an interval with lower and upper bounds, + * otherwise they will either trigger an error or be automatically clamped. + * @return : a structure, ZSTD_bounds, which contains + * - an error status field, which must be tested using ZSTD_isError() + * - lower and upper bounds, both inclusive + */ +ZSTDLIB_API ZSTD_bounds ZSTD_cParam_getBounds(ZSTD_cParameter cParam); + +/*! ZSTD_CCtx_setParameter() : + * Set one compression parameter, selected by enum ZSTD_cParameter. + * All parameters have valid bounds. Bounds can be queried using ZSTD_cParam_getBounds(). + * Providing a value beyond bound will either clamp it, or trigger an error (depending on parameter). + * Setting a parameter is generally only possible during frame initialization (before starting compression). + * Exception : when using multi-threading mode (nbWorkers >= 1), + * the following parameters can be updated _during_ compression (within same frame): + * => compressionLevel, hashLog, chainLog, searchLog, minMatch, targetLength and strategy. + * new parameters will be active for next job only (after a flush()). + * @return : an error code (which can be tested using ZSTD_isError()). + */ +ZSTDLIB_API size_t ZSTD_CCtx_setParameter(ZSTD_CCtx* cctx, ZSTD_cParameter param, int value); + +/*! ZSTD_CCtx_setPledgedSrcSize() : + * Total input data size to be compressed as a single frame. + * Value will be written in frame header, unless if explicitly forbidden using ZSTD_c_contentSizeFlag. + * This value will also be controlled at end of frame, and trigger an error if not respected. + * @result : 0, or an error code (which can be tested with ZSTD_isError()). + * Note 1 : pledgedSrcSize==0 actually means zero, aka an empty frame. + * In order to mean "unknown content size", pass constant ZSTD_CONTENTSIZE_UNKNOWN. + * ZSTD_CONTENTSIZE_UNKNOWN is default value for any new frame. + * Note 2 : pledgedSrcSize is only valid once, for the next frame. + * It's discarded at the end of the frame, and replaced by ZSTD_CONTENTSIZE_UNKNOWN. + * Note 3 : Whenever all input data is provided and consumed in a single round, + * for example with ZSTD_compress2(), + * or invoking immediately ZSTD_compressStream2(,,,ZSTD_e_end), + * this value is automatically overridden by srcSize instead. + */ +ZSTDLIB_API size_t ZSTD_CCtx_setPledgedSrcSize(ZSTD_CCtx* cctx, unsigned long long pledgedSrcSize); + +typedef enum { + ZSTD_reset_session_only = 1, + ZSTD_reset_parameters = 2, + ZSTD_reset_session_and_parameters = 3 +} ZSTD_ResetDirective; + +/*! ZSTD_CCtx_reset() : + * There are 2 different things that can be reset, independently or jointly : + * - The session : will stop compressing current frame, and make CCtx ready to start a new one. + * Useful after an error, or to interrupt any ongoing compression. + * Any internal data not yet flushed is cancelled. + * Compression parameters and dictionary remain unchanged. + * They will be used to compress next frame. + * Resetting session never fails. + * - The parameters : changes all parameters back to "default". + * This removes any reference to any dictionary too. + * Parameters can only be changed between 2 sessions (i.e. no compression is currently ongoing) + * otherwise the reset fails, and function returns an error value (which can be tested using ZSTD_isError()) + * - Both : similar to resetting the session, followed by resetting parameters. + */ +ZSTDLIB_API size_t ZSTD_CCtx_reset(ZSTD_CCtx* cctx, ZSTD_ResetDirective reset); + +/*! ZSTD_compress2() : + * Behave the same as ZSTD_compressCCtx(), but compression parameters are set using the advanced API. + * ZSTD_compress2() always starts a new frame. + * Should cctx hold data from a previously unfinished frame, everything about it is forgotten. + * - Compression parameters are pushed into CCtx before starting compression, using ZSTD_CCtx_set*() + * - The function is always blocking, returns when compression is completed. + * Hint : compression runs faster if `dstCapacity` >= `ZSTD_compressBound(srcSize)`. + * @return : compressed size written into `dst` (<= `dstCapacity), + * or an error code if it fails (which can be tested using ZSTD_isError()). + */ +ZSTDLIB_API size_t ZSTD_compress2( ZSTD_CCtx* cctx, + void* dst, size_t dstCapacity, + const void* src, size_t srcSize); + + +/*********************************************** +* Advanced decompression API (Requires v1.4.0+) +************************************************/ + +/* The advanced API pushes parameters one by one into an existing DCtx context. + * Parameters are sticky, and remain valid for all following frames + * using the same DCtx context. + * It's possible to reset parameters to default values using ZSTD_DCtx_reset(). + * Note : This API is compatible with existing ZSTD_decompressDCtx() and ZSTD_decompressStream(). + * Therefore, no new decompression function is necessary. + */ + +typedef enum { + + ZSTD_d_windowLogMax=100, /* Select a size limit (in power of 2) beyond which + * the streaming API will refuse to allocate memory buffer + * in order to protect the host from unreasonable memory requirements. + * This parameter is only useful in streaming mode, since no internal buffer is allocated in single-pass mode. + * By default, a decompression context accepts window sizes <= (1 << ZSTD_WINDOWLOG_LIMIT_DEFAULT). + * Special: value 0 means "use default maximum windowLog". */ + + /* note : additional experimental parameters are also available + * within the experimental section of the API. + * At the time of this writing, they include : + * ZSTD_d_format + * ZSTD_d_stableOutBuffer + * ZSTD_d_forceIgnoreChecksum + * ZSTD_d_refMultipleDDicts + * Because they are not stable, it's necessary to define ZSTD_STATIC_LINKING_ONLY to access them. + * note : never ever use experimentalParam? names directly + */ + ZSTD_d_experimentalParam1=1000, + ZSTD_d_experimentalParam2=1001, + ZSTD_d_experimentalParam3=1002, + ZSTD_d_experimentalParam4=1003 + +} ZSTD_dParameter; + +/*! ZSTD_dParam_getBounds() : + * All parameters must belong to an interval with lower and upper bounds, + * otherwise they will either trigger an error or be automatically clamped. + * @return : a structure, ZSTD_bounds, which contains + * - an error status field, which must be tested using ZSTD_isError() + * - both lower and upper bounds, inclusive + */ +ZSTDLIB_API ZSTD_bounds ZSTD_dParam_getBounds(ZSTD_dParameter dParam); + +/*! ZSTD_DCtx_setParameter() : + * Set one compression parameter, selected by enum ZSTD_dParameter. + * All parameters have valid bounds. Bounds can be queried using ZSTD_dParam_getBounds(). + * Providing a value beyond bound will either clamp it, or trigger an error (depending on parameter). + * Setting a parameter is only possible during frame initialization (before starting decompression). + * @return : 0, or an error code (which can be tested using ZSTD_isError()). + */ +ZSTDLIB_API size_t ZSTD_DCtx_setParameter(ZSTD_DCtx* dctx, ZSTD_dParameter param, int value); + +/*! ZSTD_DCtx_reset() : + * Return a DCtx to clean state. + * Session and parameters can be reset jointly or separately. + * Parameters can only be reset when no active frame is being decompressed. + * @return : 0, or an error code, which can be tested with ZSTD_isError() + */ +ZSTDLIB_API size_t ZSTD_DCtx_reset(ZSTD_DCtx* dctx, ZSTD_ResetDirective reset); + + +/**************************** +* Streaming +****************************/ + +typedef struct ZSTD_inBuffer_s { + const void* src; /**< start of input buffer */ + size_t size; /**< size of input buffer */ + size_t pos; /**< position where reading stopped. Will be updated. Necessarily 0 <= pos <= size */ +} ZSTD_inBuffer; + +typedef struct ZSTD_outBuffer_s { + void* dst; /**< start of output buffer */ + size_t size; /**< size of output buffer */ + size_t pos; /**< position where writing stopped. Will be updated. Necessarily 0 <= pos <= size */ +} ZSTD_outBuffer; + + + +/*-*********************************************************************** +* Streaming compression - HowTo +* +* A ZSTD_CStream object is required to track streaming operation. +* Use ZSTD_createCStream() and ZSTD_freeCStream() to create/release resources. +* ZSTD_CStream objects can be reused multiple times on consecutive compression operations. +* It is recommended to re-use ZSTD_CStream since it will play nicer with system's memory, by re-using already allocated memory. +* +* For parallel execution, use one separate ZSTD_CStream per thread. +* +* note : since v1.3.0, ZSTD_CStream and ZSTD_CCtx are the same thing. +* +* Parameters are sticky : when starting a new compression on the same context, +* it will re-use the same sticky parameters as previous compression session. +* When in doubt, it's recommended to fully initialize the context before usage. +* Use ZSTD_CCtx_reset() to reset the context and ZSTD_CCtx_setParameter(), +* ZSTD_CCtx_setPledgedSrcSize(), or ZSTD_CCtx_loadDictionary() and friends to +* set more specific parameters, the pledged source size, or load a dictionary. +* +* Use ZSTD_compressStream2() with ZSTD_e_continue as many times as necessary to +* consume input stream. The function will automatically update both `pos` +* fields within `input` and `output`. +* Note that the function may not consume the entire input, for example, because +* the output buffer is already full, in which case `input.pos < input.size`. +* The caller must check if input has been entirely consumed. +* If not, the caller must make some room to receive more compressed data, +* and then present again remaining input data. +* note: ZSTD_e_continue is guaranteed to make some forward progress when called, +* but doesn't guarantee maximal forward progress. This is especially relevant +* when compressing with multiple threads. The call won't block if it can +* consume some input, but if it can't it will wait for some, but not all, +* output to be flushed. +* @return : provides a minimum amount of data remaining to be flushed from internal buffers +* or an error code, which can be tested using ZSTD_isError(). +* +* At any moment, it's possible to flush whatever data might remain stuck within internal buffer, +* using ZSTD_compressStream2() with ZSTD_e_flush. `output->pos` will be updated. +* Note that, if `output->size` is too small, a single invocation with ZSTD_e_flush might not be enough (return code > 0). +* In which case, make some room to receive more compressed data, and call again ZSTD_compressStream2() with ZSTD_e_flush. +* You must continue calling ZSTD_compressStream2() with ZSTD_e_flush until it returns 0, at which point you can change the +* operation. +* note: ZSTD_e_flush will flush as much output as possible, meaning when compressing with multiple threads, it will +* block until the flush is complete or the output buffer is full. +* @return : 0 if internal buffers are entirely flushed, +* >0 if some data still present within internal buffer (the value is minimal estimation of remaining size), +* or an error code, which can be tested using ZSTD_isError(). +* +* Calling ZSTD_compressStream2() with ZSTD_e_end instructs to finish a frame. +* It will perform a flush and write frame epilogue. +* The epilogue is required for decoders to consider a frame completed. +* flush operation is the same, and follows same rules as calling ZSTD_compressStream2() with ZSTD_e_flush. +* You must continue calling ZSTD_compressStream2() with ZSTD_e_end until it returns 0, at which point you are free to +* start a new frame. +* note: ZSTD_e_end will flush as much output as possible, meaning when compressing with multiple threads, it will +* block until the flush is complete or the output buffer is full. +* @return : 0 if frame fully completed and fully flushed, +* >0 if some data still present within internal buffer (the value is minimal estimation of remaining size), +* or an error code, which can be tested using ZSTD_isError(). +* +* *******************************************************************/ + +typedef ZSTD_CCtx ZSTD_CStream; /**< CCtx and CStream are now effectively same object (>= v1.3.0) */ + /* Continue to distinguish them for compatibility with older versions <= v1.2.0 */ +/*===== ZSTD_CStream management functions =====*/ +ZSTDLIB_API ZSTD_CStream* ZSTD_createCStream(void); +ZSTDLIB_API size_t ZSTD_freeCStream(ZSTD_CStream* zcs); /* accept NULL pointer */ + +/*===== Streaming compression functions =====*/ +typedef enum { + ZSTD_e_continue=0, /* collect more data, encoder decides when to output compressed result, for optimal compression ratio */ + ZSTD_e_flush=1, /* flush any data provided so far, + * it creates (at least) one new block, that can be decoded immediately on reception; + * frame will continue: any future data can still reference previously compressed data, improving compression. + * note : multithreaded compression will block to flush as much output as possible. */ + ZSTD_e_end=2 /* flush any remaining data _and_ close current frame. + * note that frame is only closed after compressed data is fully flushed (return value == 0). + * After that point, any additional data starts a new frame. + * note : each frame is independent (does not reference any content from previous frame). + : note : multithreaded compression will block to flush as much output as possible. */ +} ZSTD_EndDirective; + +/*! ZSTD_compressStream2() : Requires v1.4.0+ + * Behaves about the same as ZSTD_compressStream, with additional control on end directive. + * - Compression parameters are pushed into CCtx before starting compression, using ZSTD_CCtx_set*() + * - Compression parameters cannot be changed once compression is started (save a list of exceptions in multi-threading mode) + * - output->pos must be <= dstCapacity, input->pos must be <= srcSize + * - output->pos and input->pos will be updated. They are guaranteed to remain below their respective limit. + * - endOp must be a valid directive + * - When nbWorkers==0 (default), function is blocking : it completes its job before returning to caller. + * - When nbWorkers>=1, function is non-blocking : it copies a portion of input, distributes jobs to internal worker threads, flush to output whatever is available, + * and then immediately returns, just indicating that there is some data remaining to be flushed. + * The function nonetheless guarantees forward progress : it will return only after it reads or write at least 1+ byte. + * - Exception : if the first call requests a ZSTD_e_end directive and provides enough dstCapacity, the function delegates to ZSTD_compress2() which is always blocking. + * - @return provides a minimum amount of data remaining to be flushed from internal buffers + * or an error code, which can be tested using ZSTD_isError(). + * if @return != 0, flush is not fully completed, there is still some data left within internal buffers. + * This is useful for ZSTD_e_flush, since in this case more flushes are necessary to empty all buffers. + * For ZSTD_e_end, @return == 0 when internal buffers are fully flushed and frame is completed. + * - after a ZSTD_e_end directive, if internal buffer is not fully flushed (@return != 0), + * only ZSTD_e_end or ZSTD_e_flush operations are allowed. + * Before starting a new compression job, or changing compression parameters, + * it is required to fully flush internal buffers. + */ +ZSTDLIB_API size_t ZSTD_compressStream2( ZSTD_CCtx* cctx, + ZSTD_outBuffer* output, + ZSTD_inBuffer* input, + ZSTD_EndDirective endOp); + + +/* These buffer sizes are softly recommended. + * They are not required : ZSTD_compressStream*() happily accepts any buffer size, for both input and output. + * Respecting the recommended size just makes it a bit easier for ZSTD_compressStream*(), + * reducing the amount of memory shuffling and buffering, resulting in minor performance savings. + * + * However, note that these recommendations are from the perspective of a C caller program. + * If the streaming interface is invoked from some other language, + * especially managed ones such as Java or Go, through a foreign function interface such as jni or cgo, + * a major performance rule is to reduce crossing such interface to an absolute minimum. + * It's not rare that performance ends being spent more into the interface, rather than compression itself. + * In which cases, prefer using large buffers, as large as practical, + * for both input and output, to reduce the nb of roundtrips. + */ +ZSTDLIB_API size_t ZSTD_CStreamInSize(void); /**< recommended size for input buffer */ +ZSTDLIB_API size_t ZSTD_CStreamOutSize(void); /**< recommended size for output buffer. Guarantee to successfully flush at least one complete compressed block. */ + + +/* ***************************************************************************** + * This following is a legacy streaming API, available since v1.0+ . + * It can be replaced by ZSTD_CCtx_reset() and ZSTD_compressStream2(). + * It is redundant, but remains fully supported. + * Streaming in combination with advanced parameters and dictionary compression + * can only be used through the new API. + ******************************************************************************/ + +/*! + * Equivalent to: + * + * ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only); + * ZSTD_CCtx_refCDict(zcs, NULL); // clear the dictionary (if any) + * ZSTD_CCtx_setParameter(zcs, ZSTD_c_compressionLevel, compressionLevel); + */ +ZSTDLIB_API size_t ZSTD_initCStream(ZSTD_CStream* zcs, int compressionLevel); +/*! + * Alternative for ZSTD_compressStream2(zcs, output, input, ZSTD_e_continue). + * NOTE: The return value is different. ZSTD_compressStream() returns a hint for + * the next read size (if non-zero and not an error). ZSTD_compressStream2() + * returns the minimum nb of bytes left to flush (if non-zero and not an error). + */ +ZSTDLIB_API size_t ZSTD_compressStream(ZSTD_CStream* zcs, ZSTD_outBuffer* output, ZSTD_inBuffer* input); +/*! Equivalent to ZSTD_compressStream2(zcs, output, &emptyInput, ZSTD_e_flush). */ +ZSTDLIB_API size_t ZSTD_flushStream(ZSTD_CStream* zcs, ZSTD_outBuffer* output); +/*! Equivalent to ZSTD_compressStream2(zcs, output, &emptyInput, ZSTD_e_end). */ +ZSTDLIB_API size_t ZSTD_endStream(ZSTD_CStream* zcs, ZSTD_outBuffer* output); + + +/*-*************************************************************************** +* Streaming decompression - HowTo +* +* A ZSTD_DStream object is required to track streaming operations. +* Use ZSTD_createDStream() and ZSTD_freeDStream() to create/release resources. +* ZSTD_DStream objects can be re-used multiple times. +* +* Use ZSTD_initDStream() to start a new decompression operation. +* @return : recommended first input size +* Alternatively, use advanced API to set specific properties. +* +* Use ZSTD_decompressStream() repetitively to consume your input. +* The function will update both `pos` fields. +* If `input.pos < input.size`, some input has not been consumed. +* It's up to the caller to present again remaining data. +* The function tries to flush all data decoded immediately, respecting output buffer size. +* If `output.pos < output.size`, decoder has flushed everything it could. +* But if `output.pos == output.size`, there might be some data left within internal buffers., +* In which case, call ZSTD_decompressStream() again to flush whatever remains in the buffer. +* Note : with no additional input provided, amount of data flushed is necessarily <= ZSTD_BLOCKSIZE_MAX. +* @return : 0 when a frame is completely decoded and fully flushed, +* or an error code, which can be tested using ZSTD_isError(), +* or any other value > 0, which means there is still some decoding or flushing to do to complete current frame : +* the return value is a suggested next input size (just a hint for better latency) +* that will never request more than the remaining frame size. +* *******************************************************************************/ + +typedef ZSTD_DCtx ZSTD_DStream; /**< DCtx and DStream are now effectively same object (>= v1.3.0) */ + /* For compatibility with versions <= v1.2.0, prefer differentiating them. */ +/*===== ZSTD_DStream management functions =====*/ +ZSTDLIB_API ZSTD_DStream* ZSTD_createDStream(void); +ZSTDLIB_API size_t ZSTD_freeDStream(ZSTD_DStream* zds); /* accept NULL pointer */ + +/*===== Streaming decompression functions =====*/ + +/* This function is redundant with the advanced API and equivalent to: + * + * ZSTD_DCtx_reset(zds, ZSTD_reset_session_only); + * ZSTD_DCtx_refDDict(zds, NULL); + */ +ZSTDLIB_API size_t ZSTD_initDStream(ZSTD_DStream* zds); + +ZSTDLIB_API size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* output, ZSTD_inBuffer* input); + +ZSTDLIB_API size_t ZSTD_DStreamInSize(void); /*!< recommended size for input buffer */ +ZSTDLIB_API size_t ZSTD_DStreamOutSize(void); /*!< recommended size for output buffer. Guarantee to successfully flush at least one complete block in all circumstances. */ + + +/************************** +* Simple dictionary API +***************************/ +/*! ZSTD_compress_usingDict() : + * Compression at an explicit compression level using a Dictionary. + * A dictionary can be any arbitrary data segment (also called a prefix), + * or a buffer with specified information (see zdict.h). + * Note : This function loads the dictionary, resulting in significant startup delay. + * It's intended for a dictionary used only once. + * Note 2 : When `dict == NULL || dictSize < 8` no dictionary is used. */ +ZSTDLIB_API size_t ZSTD_compress_usingDict(ZSTD_CCtx* ctx, + void* dst, size_t dstCapacity, + const void* src, size_t srcSize, + const void* dict,size_t dictSize, + int compressionLevel); + +/*! ZSTD_decompress_usingDict() : + * Decompression using a known Dictionary. + * Dictionary must be identical to the one used during compression. + * Note : This function loads the dictionary, resulting in significant startup delay. + * It's intended for a dictionary used only once. + * Note : When `dict == NULL || dictSize < 8` no dictionary is used. */ +ZSTDLIB_API size_t ZSTD_decompress_usingDict(ZSTD_DCtx* dctx, + void* dst, size_t dstCapacity, + const void* src, size_t srcSize, + const void* dict,size_t dictSize); + + +/*********************************** + * Bulk processing dictionary API + **********************************/ +typedef struct ZSTD_CDict_s ZSTD_CDict; + +/*! ZSTD_createCDict() : + * When compressing multiple messages or blocks using the same dictionary, + * it's recommended to digest the dictionary only once, since it's a costly operation. + * ZSTD_createCDict() will create a state from digesting a dictionary. + * The resulting state can be used for future compression operations with very limited startup cost. + * ZSTD_CDict can be created once and shared by multiple threads concurrently, since its usage is read-only. + * @dictBuffer can be released after ZSTD_CDict creation, because its content is copied within CDict. + * Note 1 : Consider experimental function `ZSTD_createCDict_byReference()` if you prefer to not duplicate @dictBuffer content. + * Note 2 : A ZSTD_CDict can be created from an empty @dictBuffer, + * in which case the only thing that it transports is the @compressionLevel. + * This can be useful in a pipeline featuring ZSTD_compress_usingCDict() exclusively, + * expecting a ZSTD_CDict parameter with any data, including those without a known dictionary. */ +ZSTDLIB_API ZSTD_CDict* ZSTD_createCDict(const void* dictBuffer, size_t dictSize, + int compressionLevel); + +/*! ZSTD_freeCDict() : + * Function frees memory allocated by ZSTD_createCDict(). + * If a NULL pointer is passed, no operation is performed. */ +ZSTDLIB_API size_t ZSTD_freeCDict(ZSTD_CDict* CDict); + +/*! ZSTD_compress_usingCDict() : + * Compression using a digested Dictionary. + * Recommended when same dictionary is used multiple times. + * Note : compression level is _decided at dictionary creation time_, + * and frame parameters are hardcoded (dictID=yes, contentSize=yes, checksum=no) */ +ZSTDLIB_API size_t ZSTD_compress_usingCDict(ZSTD_CCtx* cctx, + void* dst, size_t dstCapacity, + const void* src, size_t srcSize, + const ZSTD_CDict* cdict); + + +typedef struct ZSTD_DDict_s ZSTD_DDict; + +/*! ZSTD_createDDict() : + * Create a digested dictionary, ready to start decompression operation without startup delay. + * dictBuffer can be released after DDict creation, as its content is copied inside DDict. */ +ZSTDLIB_API ZSTD_DDict* ZSTD_createDDict(const void* dictBuffer, size_t dictSize); + +/*! ZSTD_freeDDict() : + * Function frees memory allocated with ZSTD_createDDict() + * If a NULL pointer is passed, no operation is performed. */ +ZSTDLIB_API size_t ZSTD_freeDDict(ZSTD_DDict* ddict); + +/*! ZSTD_decompress_usingDDict() : + * Decompression using a digested Dictionary. + * Recommended when same dictionary is used multiple times. */ +ZSTDLIB_API size_t ZSTD_decompress_usingDDict(ZSTD_DCtx* dctx, + void* dst, size_t dstCapacity, + const void* src, size_t srcSize, + const ZSTD_DDict* ddict); + + +/******************************** + * Dictionary helper functions + *******************************/ + +/*! ZSTD_getDictID_fromDict() : Requires v1.4.0+ + * Provides the dictID stored within dictionary. + * if @return == 0, the dictionary is not conformant with Zstandard specification. + * It can still be loaded, but as a content-only dictionary. */ +ZSTDLIB_API unsigned ZSTD_getDictID_fromDict(const void* dict, size_t dictSize); + +/*! ZSTD_getDictID_fromCDict() : Requires v1.5.0+ + * Provides the dictID of the dictionary loaded into `cdict`. + * If @return == 0, the dictionary is not conformant to Zstandard specification, or empty. + * Non-conformant dictionaries can still be loaded, but as content-only dictionaries. */ +ZSTDLIB_API unsigned ZSTD_getDictID_fromCDict(const ZSTD_CDict* cdict); + +/*! ZSTD_getDictID_fromDDict() : Requires v1.4.0+ + * Provides the dictID of the dictionary loaded into `ddict`. + * If @return == 0, the dictionary is not conformant to Zstandard specification, or empty. + * Non-conformant dictionaries can still be loaded, but as content-only dictionaries. */ +ZSTDLIB_API unsigned ZSTD_getDictID_fromDDict(const ZSTD_DDict* ddict); + +/*! ZSTD_getDictID_fromFrame() : Requires v1.4.0+ + * Provides the dictID required to decompressed the frame stored within `src`. + * If @return == 0, the dictID could not be decoded. + * This could for one of the following reasons : + * - The frame does not require a dictionary to be decoded (most common case). + * - The frame was built with dictID intentionally removed. Whatever dictionary is necessary is a hidden information. + * Note : this use case also happens when using a non-conformant dictionary. + * - `srcSize` is too small, and as a result, the frame header could not be decoded (only possible if `srcSize < ZSTD_FRAMEHEADERSIZE_MAX`). + * - This is not a Zstandard frame. + * When identifying the exact failure cause, it's possible to use ZSTD_getFrameHeader(), which will provide a more precise error code. */ +ZSTDLIB_API unsigned ZSTD_getDictID_fromFrame(const void* src, size_t srcSize); + + +/******************************************************************************* + * Advanced dictionary and prefix API (Requires v1.4.0+) + * + * This API allows dictionaries to be used with ZSTD_compress2(), + * ZSTD_compressStream2(), and ZSTD_decompressDCtx(). Dictionaries are sticky, and + * only reset with the context is reset with ZSTD_reset_parameters or + * ZSTD_reset_session_and_parameters. Prefixes are single-use. + ******************************************************************************/ + + +/*! ZSTD_CCtx_loadDictionary() : Requires v1.4.0+ + * Create an internal CDict from `dict` buffer. + * Decompression will have to use same dictionary. + * @result : 0, or an error code (which can be tested with ZSTD_isError()). + * Special: Loading a NULL (or 0-size) dictionary invalidates previous dictionary, + * meaning "return to no-dictionary mode". + * Note 1 : Dictionary is sticky, it will be used for all future compressed frames. + * To return to "no-dictionary" situation, load a NULL dictionary (or reset parameters). + * Note 2 : Loading a dictionary involves building tables. + * It's also a CPU consuming operation, with non-negligible impact on latency. + * Tables are dependent on compression parameters, and for this reason, + * compression parameters can no longer be changed after loading a dictionary. + * Note 3 :`dict` content will be copied internally. + * Use experimental ZSTD_CCtx_loadDictionary_byReference() to reference content instead. + * In such a case, dictionary buffer must outlive its users. + * Note 4 : Use ZSTD_CCtx_loadDictionary_advanced() + * to precisely select how dictionary content must be interpreted. */ +ZSTDLIB_API size_t ZSTD_CCtx_loadDictionary(ZSTD_CCtx* cctx, const void* dict, size_t dictSize); + +/*! ZSTD_CCtx_refCDict() : Requires v1.4.0+ + * Reference a prepared dictionary, to be used for all next compressed frames. + * Note that compression parameters are enforced from within CDict, + * and supersede any compression parameter previously set within CCtx. + * The parameters ignored are labelled as "superseded-by-cdict" in the ZSTD_cParameter enum docs. + * The ignored parameters will be used again if the CCtx is returned to no-dictionary mode. + * The dictionary will remain valid for future compressed frames using same CCtx. + * @result : 0, or an error code (which can be tested with ZSTD_isError()). + * Special : Referencing a NULL CDict means "return to no-dictionary mode". + * Note 1 : Currently, only one dictionary can be managed. + * Referencing a new dictionary effectively "discards" any previous one. + * Note 2 : CDict is just referenced, its lifetime must outlive its usage within CCtx. */ +ZSTDLIB_API size_t ZSTD_CCtx_refCDict(ZSTD_CCtx* cctx, const ZSTD_CDict* cdict); + +/*! ZSTD_CCtx_refPrefix() : Requires v1.4.0+ + * Reference a prefix (single-usage dictionary) for next compressed frame. + * A prefix is **only used once**. Tables are discarded at end of frame (ZSTD_e_end). + * Decompression will need same prefix to properly regenerate data. + * Compressing with a prefix is similar in outcome as performing a diff and compressing it, + * but performs much faster, especially during decompression (compression speed is tunable with compression level). + * @result : 0, or an error code (which can be tested with ZSTD_isError()). + * Special: Adding any prefix (including NULL) invalidates any previous prefix or dictionary + * Note 1 : Prefix buffer is referenced. It **must** outlive compression. + * Its content must remain unmodified during compression. + * Note 2 : If the intention is to diff some large src data blob with some prior version of itself, + * ensure that the window size is large enough to contain the entire source. + * See ZSTD_c_windowLog. + * Note 3 : Referencing a prefix involves building tables, which are dependent on compression parameters. + * It's a CPU consuming operation, with non-negligible impact on latency. + * If there is a need to use the same prefix multiple times, consider loadDictionary instead. + * Note 4 : By default, the prefix is interpreted as raw content (ZSTD_dct_rawContent). + * Use experimental ZSTD_CCtx_refPrefix_advanced() to alter dictionary interpretation. */ +ZSTDLIB_API size_t ZSTD_CCtx_refPrefix(ZSTD_CCtx* cctx, + const void* prefix, size_t prefixSize); + +/*! ZSTD_DCtx_loadDictionary() : Requires v1.4.0+ + * Create an internal DDict from dict buffer, + * to be used to decompress next frames. + * The dictionary remains valid for all future frames, until explicitly invalidated. + * @result : 0, or an error code (which can be tested with ZSTD_isError()). + * Special : Adding a NULL (or 0-size) dictionary invalidates any previous dictionary, + * meaning "return to no-dictionary mode". + * Note 1 : Loading a dictionary involves building tables, + * which has a non-negligible impact on CPU usage and latency. + * It's recommended to "load once, use many times", to amortize the cost + * Note 2 :`dict` content will be copied internally, so `dict` can be released after loading. + * Use ZSTD_DCtx_loadDictionary_byReference() to reference dictionary content instead. + * Note 3 : Use ZSTD_DCtx_loadDictionary_advanced() to take control of + * how dictionary content is loaded and interpreted. + */ +ZSTDLIB_API size_t ZSTD_DCtx_loadDictionary(ZSTD_DCtx* dctx, const void* dict, size_t dictSize); + +/*! ZSTD_DCtx_refDDict() : Requires v1.4.0+ + * Reference a prepared dictionary, to be used to decompress next frames. + * The dictionary remains active for decompression of future frames using same DCtx. + * + * If called with ZSTD_d_refMultipleDDicts enabled, repeated calls of this function + * will store the DDict references in a table, and the DDict used for decompression + * will be determined at decompression time, as per the dict ID in the frame. + * The memory for the table is allocated on the first call to refDDict, and can be + * freed with ZSTD_freeDCtx(). + * + * @result : 0, or an error code (which can be tested with ZSTD_isError()). + * Note 1 : Currently, only one dictionary can be managed. + * Referencing a new dictionary effectively "discards" any previous one. + * Special: referencing a NULL DDict means "return to no-dictionary mode". + * Note 2 : DDict is just referenced, its lifetime must outlive its usage from DCtx. + */ +ZSTDLIB_API size_t ZSTD_DCtx_refDDict(ZSTD_DCtx* dctx, const ZSTD_DDict* ddict); + +/*! ZSTD_DCtx_refPrefix() : Requires v1.4.0+ + * Reference a prefix (single-usage dictionary) to decompress next frame. + * This is the reverse operation of ZSTD_CCtx_refPrefix(), + * and must use the same prefix as the one used during compression. + * Prefix is **only used once**. Reference is discarded at end of frame. + * End of frame is reached when ZSTD_decompressStream() returns 0. + * @result : 0, or an error code (which can be tested with ZSTD_isError()). + * Note 1 : Adding any prefix (including NULL) invalidates any previously set prefix or dictionary + * Note 2 : Prefix buffer is referenced. It **must** outlive decompression. + * Prefix buffer must remain unmodified up to the end of frame, + * reached when ZSTD_decompressStream() returns 0. + * Note 3 : By default, the prefix is treated as raw content (ZSTD_dct_rawContent). + * Use ZSTD_CCtx_refPrefix_advanced() to alter dictMode (Experimental section) + * Note 4 : Referencing a raw content prefix has almost no cpu nor memory cost. + * A full dictionary is more costly, as it requires building tables. + */ +ZSTDLIB_API size_t ZSTD_DCtx_refPrefix(ZSTD_DCtx* dctx, + const void* prefix, size_t prefixSize); + +/* === Memory management === */ + +/*! ZSTD_sizeof_*() : Requires v1.4.0+ + * These functions give the _current_ memory usage of selected object. + * Note that object memory usage can evolve (increase or decrease) over time. */ +ZSTDLIB_API size_t ZSTD_sizeof_CCtx(const ZSTD_CCtx* cctx); +ZSTDLIB_API size_t ZSTD_sizeof_DCtx(const ZSTD_DCtx* dctx); +ZSTDLIB_API size_t ZSTD_sizeof_CStream(const ZSTD_CStream* zcs); +ZSTDLIB_API size_t ZSTD_sizeof_DStream(const ZSTD_DStream* zds); +ZSTDLIB_API size_t ZSTD_sizeof_CDict(const ZSTD_CDict* cdict); +ZSTDLIB_API size_t ZSTD_sizeof_DDict(const ZSTD_DDict* ddict); + +#endif /* ZSTD_H_235446 */ + + +/* ************************************************************************************** + * ADVANCED AND EXPERIMENTAL FUNCTIONS + **************************************************************************************** + * The definitions in the following section are considered experimental. + * They are provided for advanced scenarios. + * They should never be used with a dynamic library, as prototypes may change in the future. + * Use them only in association with static linking. + * ***************************************************************************************/ + +#if defined(ZSTD_STATIC_LINKING_ONLY) && !defined(ZSTD_H_ZSTD_STATIC_LINKING_ONLY) +#define ZSTD_H_ZSTD_STATIC_LINKING_ONLY + +/* This can be overridden externally to hide static symbols. */ +#ifndef ZSTDLIB_STATIC_API +# if defined(ZSTD_DLL_EXPORT) && (ZSTD_DLL_EXPORT==1) +# define ZSTDLIB_STATIC_API __declspec(dllexport) ZSTDLIB_VISIBLE +# elif defined(ZSTD_DLL_IMPORT) && (ZSTD_DLL_IMPORT==1) +# define ZSTDLIB_STATIC_API __declspec(dllimport) ZSTDLIB_VISIBLE +# else +# define ZSTDLIB_STATIC_API ZSTDLIB_VISIBLE +# endif +#endif + +/* Deprecation warnings : + * Should these warnings be a problem, it is generally possible to disable them, + * typically with -Wno-deprecated-declarations for gcc or _CRT_SECURE_NO_WARNINGS in Visual. + * Otherwise, it's also possible to define ZSTD_DISABLE_DEPRECATE_WARNINGS. + */ +#ifdef ZSTD_DISABLE_DEPRECATE_WARNINGS +# define ZSTD_DEPRECATED(message) ZSTDLIB_STATIC_API /* disable deprecation warnings */ +#else +# if defined (__cplusplus) && (__cplusplus >= 201402) /* C++14 or greater */ +# define ZSTD_DEPRECATED(message) [[deprecated(message)]] ZSTDLIB_STATIC_API +# elif (defined(GNUC) && (GNUC > 4 || (GNUC == 4 && GNUC_MINOR >= 5))) || defined(__clang__) +# define ZSTD_DEPRECATED(message) ZSTDLIB_STATIC_API __attribute__((deprecated(message))) +# elif defined(__GNUC__) && (__GNUC__ >= 3) +# define ZSTD_DEPRECATED(message) ZSTDLIB_STATIC_API __attribute__((deprecated)) +# elif defined(_MSC_VER) +# define ZSTD_DEPRECATED(message) ZSTDLIB_STATIC_API __declspec(deprecated(message)) +# else +# pragma message("WARNING: You need to implement ZSTD_DEPRECATED for this compiler") +# define ZSTD_DEPRECATED(message) ZSTDLIB_STATIC_API +# endif +#endif /* ZSTD_DISABLE_DEPRECATE_WARNINGS */ + +/**************************************************************************************** + * experimental API (static linking only) + **************************************************************************************** + * The following symbols and constants + * are not planned to join "stable API" status in the near future. + * They can still change in future versions. + * Some of them are planned to remain in the static_only section indefinitely. + * Some of them might be removed in the future (especially when redundant with existing stable functions) + * ***************************************************************************************/ + +#define ZSTD_FRAMEHEADERSIZE_PREFIX(format) ((format) == ZSTD_f_zstd1 ? 5 : 1) /* minimum input size required to query frame header size */ +#define ZSTD_FRAMEHEADERSIZE_MIN(format) ((format) == ZSTD_f_zstd1 ? 6 : 2) +#define ZSTD_FRAMEHEADERSIZE_MAX 18 /* can be useful for static allocation */ +#define ZSTD_SKIPPABLEHEADERSIZE 8 + +/* compression parameter bounds */ +#define ZSTD_WINDOWLOG_MAX_32 30 +#define ZSTD_WINDOWLOG_MAX_64 31 +#define ZSTD_WINDOWLOG_MAX ((int)(sizeof(size_t) == 4 ? ZSTD_WINDOWLOG_MAX_32 : ZSTD_WINDOWLOG_MAX_64)) +#define ZSTD_WINDOWLOG_MIN 10 +#define ZSTD_HASHLOG_MAX ((ZSTD_WINDOWLOG_MAX < 30) ? ZSTD_WINDOWLOG_MAX : 30) +#define ZSTD_HASHLOG_MIN 6 +#define ZSTD_CHAINLOG_MAX_32 29 +#define ZSTD_CHAINLOG_MAX_64 30 +#define ZSTD_CHAINLOG_MAX ((int)(sizeof(size_t) == 4 ? ZSTD_CHAINLOG_MAX_32 : ZSTD_CHAINLOG_MAX_64)) +#define ZSTD_CHAINLOG_MIN ZSTD_HASHLOG_MIN +#define ZSTD_SEARCHLOG_MAX (ZSTD_WINDOWLOG_MAX-1) +#define ZSTD_SEARCHLOG_MIN 1 +#define ZSTD_MINMATCH_MAX 7 /* only for ZSTD_fast, other strategies are limited to 6 */ +#define ZSTD_MINMATCH_MIN 3 /* only for ZSTD_btopt+, faster strategies are limited to 4 */ +#define ZSTD_TARGETLENGTH_MAX ZSTD_BLOCKSIZE_MAX +#define ZSTD_TARGETLENGTH_MIN 0 /* note : comparing this constant to an unsigned results in a tautological test */ +#define ZSTD_STRATEGY_MIN ZSTD_fast +#define ZSTD_STRATEGY_MAX ZSTD_btultra2 + + +#define ZSTD_OVERLAPLOG_MIN 0 +#define ZSTD_OVERLAPLOG_MAX 9 + +#define ZSTD_WINDOWLOG_LIMIT_DEFAULT 27 /* by default, the streaming decoder will refuse any frame + * requiring larger than (1< 0: + * If litLength != 0: + * rep == 1 --> offset == repeat_offset_1 + * rep == 2 --> offset == repeat_offset_2 + * rep == 3 --> offset == repeat_offset_3 + * If litLength == 0: + * rep == 1 --> offset == repeat_offset_2 + * rep == 2 --> offset == repeat_offset_3 + * rep == 3 --> offset == repeat_offset_1 - 1 + * + * Note: This field is optional. ZSTD_generateSequences() will calculate the value of + * 'rep', but repeat offsets do not necessarily need to be calculated from an external + * sequence provider's perspective. For example, ZSTD_compressSequences() does not + * use this 'rep' field at all (as of now). + */ +} ZSTD_Sequence; + +typedef struct { + unsigned windowLog; /**< largest match distance : larger == more compression, more memory needed during decompression */ + unsigned chainLog; /**< fully searched segment : larger == more compression, slower, more memory (useless for fast) */ + unsigned hashLog; /**< dispatch table : larger == faster, more memory */ + unsigned searchLog; /**< nb of searches : larger == more compression, slower */ + unsigned minMatch; /**< match length searched : larger == faster decompression, sometimes less compression */ + unsigned targetLength; /**< acceptable match size for optimal parser (only) : larger == more compression, slower */ + ZSTD_strategy strategy; /**< see ZSTD_strategy definition above */ +} ZSTD_compressionParameters; + +typedef struct { + int contentSizeFlag; /**< 1: content size will be in frame header (when known) */ + int checksumFlag; /**< 1: generate a 32-bits checksum using XXH64 algorithm at end of frame, for error detection */ + int noDictIDFlag; /**< 1: no dictID will be saved into frame header (dictID is only useful for dictionary compression) */ +} ZSTD_frameParameters; + +typedef struct { + ZSTD_compressionParameters cParams; + ZSTD_frameParameters fParams; +} ZSTD_parameters; + +typedef enum { + ZSTD_dct_auto = 0, /* dictionary is "full" when starting with ZSTD_MAGIC_DICTIONARY, otherwise it is "rawContent" */ + ZSTD_dct_rawContent = 1, /* ensures dictionary is always loaded as rawContent, even if it starts with ZSTD_MAGIC_DICTIONARY */ + ZSTD_dct_fullDict = 2 /* refuses to load a dictionary if it does not respect Zstandard's specification, starting with ZSTD_MAGIC_DICTIONARY */ +} ZSTD_dictContentType_e; + +typedef enum { + ZSTD_dlm_byCopy = 0, /**< Copy dictionary content internally */ + ZSTD_dlm_byRef = 1 /**< Reference dictionary content -- the dictionary buffer must outlive its users. */ +} ZSTD_dictLoadMethod_e; + +typedef enum { + ZSTD_f_zstd1 = 0, /* zstd frame format, specified in zstd_compression_format.md (default) */ + ZSTD_f_zstd1_magicless = 1 /* Variant of zstd frame format, without initial 4-bytes magic number. + * Useful to save 4 bytes per generated frame. + * Decoder cannot recognise automatically this format, requiring this instruction. */ +} ZSTD_format_e; + +typedef enum { + /* Note: this enum controls ZSTD_d_forceIgnoreChecksum */ + ZSTD_d_validateChecksum = 0, + ZSTD_d_ignoreChecksum = 1 +} ZSTD_forceIgnoreChecksum_e; + +typedef enum { + /* Note: this enum controls ZSTD_d_refMultipleDDicts */ + ZSTD_rmd_refSingleDDict = 0, + ZSTD_rmd_refMultipleDDicts = 1 +} ZSTD_refMultipleDDicts_e; + +typedef enum { + /* Note: this enum and the behavior it controls are effectively internal + * implementation details of the compressor. They are expected to continue + * to evolve and should be considered only in the context of extremely + * advanced performance tuning. + * + * Zstd currently supports the use of a CDict in three ways: + * + * - The contents of the CDict can be copied into the working context. This + * means that the compression can search both the dictionary and input + * while operating on a single set of internal tables. This makes + * the compression faster per-byte of input. However, the initial copy of + * the CDict's tables incurs a fixed cost at the beginning of the + * compression. For small compressions (< 8 KB), that copy can dominate + * the cost of the compression. + * + * - The CDict's tables can be used in-place. In this model, compression is + * slower per input byte, because the compressor has to search two sets of + * tables. However, this model incurs no start-up cost (as long as the + * working context's tables can be reused). For small inputs, this can be + * faster than copying the CDict's tables. + * + * - The CDict's tables are not used at all, and instead we use the working + * context alone to reload the dictionary and use params based on the source + * size. See ZSTD_compress_insertDictionary() and ZSTD_compress_usingDict(). + * This method is effective when the dictionary sizes are very small relative + * to the input size, and the input size is fairly large to begin with. + * + * Zstd has a simple internal heuristic that selects which strategy to use + * at the beginning of a compression. However, if experimentation shows that + * Zstd is making poor choices, it is possible to override that choice with + * this enum. + */ + ZSTD_dictDefaultAttach = 0, /* Use the default heuristic. */ + ZSTD_dictForceAttach = 1, /* Never copy the dictionary. */ + ZSTD_dictForceCopy = 2, /* Always copy the dictionary. */ + ZSTD_dictForceLoad = 3 /* Always reload the dictionary */ +} ZSTD_dictAttachPref_e; + +typedef enum { + ZSTD_lcm_auto = 0, /**< Automatically determine the compression mode based on the compression level. + * Negative compression levels will be uncompressed, and positive compression + * levels will be compressed. */ + ZSTD_lcm_huffman = 1, /**< Always attempt Huffman compression. Uncompressed literals will still be + * emitted if Huffman compression is not profitable. */ + ZSTD_lcm_uncompressed = 2 /**< Always emit uncompressed literals. */ +} ZSTD_literalCompressionMode_e; + +typedef enum { + /* Note: This enum controls features which are conditionally beneficial. Zstd typically will make a final + * decision on whether or not to enable the feature (ZSTD_ps_auto), but setting the switch to ZSTD_ps_enable + * or ZSTD_ps_disable allow for a force enable/disable the feature. + */ + ZSTD_ps_auto = 0, /* Let the library automatically determine whether the feature shall be enabled */ + ZSTD_ps_enable = 1, /* Force-enable the feature */ + ZSTD_ps_disable = 2 /* Do not use the feature */ +} ZSTD_paramSwitch_e; + +/*************************************** +* Frame size functions +***************************************/ + +/*! ZSTD_findDecompressedSize() : + * `src` should point to the start of a series of ZSTD encoded and/or skippable frames + * `srcSize` must be the _exact_ size of this series + * (i.e. there should be a frame boundary at `src + srcSize`) + * @return : - decompressed size of all data in all successive frames + * - if the decompressed size cannot be determined: ZSTD_CONTENTSIZE_UNKNOWN + * - if an error occurred: ZSTD_CONTENTSIZE_ERROR + * + * note 1 : decompressed size is an optional field, that may not be present, especially in streaming mode. + * When `return==ZSTD_CONTENTSIZE_UNKNOWN`, data to decompress could be any size. + * In which case, it's necessary to use streaming mode to decompress data. + * note 2 : decompressed size is always present when compression is done with ZSTD_compress() + * note 3 : decompressed size can be very large (64-bits value), + * potentially larger than what local system can handle as a single memory segment. + * In which case, it's necessary to use streaming mode to decompress data. + * note 4 : If source is untrusted, decompressed size could be wrong or intentionally modified. + * Always ensure result fits within application's authorized limits. + * Each application can set its own limits. + * note 5 : ZSTD_findDecompressedSize handles multiple frames, and so it must traverse the input to + * read each contained frame header. This is fast as most of the data is skipped, + * however it does mean that all frame data must be present and valid. */ +ZSTDLIB_STATIC_API unsigned long long ZSTD_findDecompressedSize(const void* src, size_t srcSize); + +/*! ZSTD_decompressBound() : + * `src` should point to the start of a series of ZSTD encoded and/or skippable frames + * `srcSize` must be the _exact_ size of this series + * (i.e. there should be a frame boundary at `src + srcSize`) + * @return : - upper-bound for the decompressed size of all data in all successive frames + * - if an error occurred: ZSTD_CONTENTSIZE_ERROR + * + * note 1 : an error can occur if `src` contains an invalid or incorrectly formatted frame. + * note 2 : the upper-bound is exact when the decompressed size field is available in every ZSTD encoded frame of `src`. + * in this case, `ZSTD_findDecompressedSize` and `ZSTD_decompressBound` return the same value. + * note 3 : when the decompressed size field isn't available, the upper-bound for that frame is calculated by: + * upper-bound = # blocks * min(128 KB, Window_Size) + */ +ZSTDLIB_STATIC_API unsigned long long ZSTD_decompressBound(const void* src, size_t srcSize); + +/*! ZSTD_frameHeaderSize() : + * srcSize must be >= ZSTD_FRAMEHEADERSIZE_PREFIX. + * @return : size of the Frame Header, + * or an error code (if srcSize is too small) */ +ZSTDLIB_STATIC_API size_t ZSTD_frameHeaderSize(const void* src, size_t srcSize); + +typedef enum { + ZSTD_sf_noBlockDelimiters = 0, /* Representation of ZSTD_Sequence has no block delimiters, sequences only */ + ZSTD_sf_explicitBlockDelimiters = 1 /* Representation of ZSTD_Sequence contains explicit block delimiters */ +} ZSTD_sequenceFormat_e; + +/*! ZSTD_generateSequences() : + * Generate sequences using ZSTD_compress2, given a source buffer. + * + * Each block will end with a dummy sequence + * with offset == 0, matchLength == 0, and litLength == length of last literals. + * litLength may be == 0, and if so, then the sequence of (of: 0 ml: 0 ll: 0) + * simply acts as a block delimiter. + * + * zc can be used to insert custom compression params. + * This function invokes ZSTD_compress2 + * + * The output of this function can be fed into ZSTD_compressSequences() with CCtx + * setting of ZSTD_c_blockDelimiters as ZSTD_sf_explicitBlockDelimiters + * @return : number of sequences generated + */ + +ZSTDLIB_STATIC_API size_t ZSTD_generateSequences(ZSTD_CCtx* zc, ZSTD_Sequence* outSeqs, + size_t outSeqsSize, const void* src, size_t srcSize); + +/*! ZSTD_mergeBlockDelimiters() : + * Given an array of ZSTD_Sequence, remove all sequences that represent block delimiters/last literals + * by merging them into into the literals of the next sequence. + * + * As such, the final generated result has no explicit representation of block boundaries, + * and the final last literals segment is not represented in the sequences. + * + * The output of this function can be fed into ZSTD_compressSequences() with CCtx + * setting of ZSTD_c_blockDelimiters as ZSTD_sf_noBlockDelimiters + * @return : number of sequences left after merging + */ +ZSTDLIB_STATIC_API size_t ZSTD_mergeBlockDelimiters(ZSTD_Sequence* sequences, size_t seqsSize); + +/*! ZSTD_compressSequences() : + * Compress an array of ZSTD_Sequence, generated from the original source buffer, into dst. + * If a dictionary is included, then the cctx should reference the dict. (see: ZSTD_CCtx_refCDict(), ZSTD_CCtx_loadDictionary(), etc.) + * The entire source is compressed into a single frame. + * + * The compression behavior changes based on cctx params. In particular: + * If ZSTD_c_blockDelimiters == ZSTD_sf_noBlockDelimiters, the array of ZSTD_Sequence is expected to contain + * no block delimiters (defined in ZSTD_Sequence). Block boundaries are roughly determined based on + * the block size derived from the cctx, and sequences may be split. This is the default setting. + * + * If ZSTD_c_blockDelimiters == ZSTD_sf_explicitBlockDelimiters, the array of ZSTD_Sequence is expected to contain + * block delimiters (defined in ZSTD_Sequence). Behavior is undefined if no block delimiters are provided. + * + * If ZSTD_c_validateSequences == 0, this function will blindly accept the sequences provided. Invalid sequences cause undefined + * behavior. If ZSTD_c_validateSequences == 1, then if sequence is invalid (see doc/zstd_compression_format.md for + * specifics regarding offset/matchlength requirements) then the function will bail out and return an error. + * + * In addition to the two adjustable experimental params, there are other important cctx params. + * - ZSTD_c_minMatch MUST be set as less than or equal to the smallest match generated by the match finder. It has a minimum value of ZSTD_MINMATCH_MIN. + * - ZSTD_c_compressionLevel accordingly adjusts the strength of the entropy coder, as it would in typical compression. + * - ZSTD_c_windowLog affects offset validation: this function will return an error at higher debug levels if a provided offset + * is larger than what the spec allows for a given window log and dictionary (if present). See: doc/zstd_compression_format.md + * + * Note: Repcodes are, as of now, always re-calculated within this function, so ZSTD_Sequence::rep is unused. + * Note 2: Once we integrate ability to ingest repcodes, the explicit block delims mode must respect those repcodes exactly, + * and cannot emit an RLE block that disagrees with the repcode history + * @return : final compressed size or a ZSTD error. + */ +ZSTDLIB_STATIC_API size_t ZSTD_compressSequences(ZSTD_CCtx* const cctx, void* dst, size_t dstSize, + const ZSTD_Sequence* inSeqs, size_t inSeqsSize, + const void* src, size_t srcSize); + + +/*! ZSTD_writeSkippableFrame() : + * Generates a zstd skippable frame containing data given by src, and writes it to dst buffer. + * + * Skippable frames begin with a a 4-byte magic number. There are 16 possible choices of magic number, + * ranging from ZSTD_MAGIC_SKIPPABLE_START to ZSTD_MAGIC_SKIPPABLE_START+15. + * As such, the parameter magicVariant controls the exact skippable frame magic number variant used, so + * the magic number used will be ZSTD_MAGIC_SKIPPABLE_START + magicVariant. + * + * Returns an error if destination buffer is not large enough, if the source size is not representable + * with a 4-byte unsigned int, or if the parameter magicVariant is greater than 15 (and therefore invalid). + * + * @return : number of bytes written or a ZSTD error. + */ +ZSTDLIB_STATIC_API size_t ZSTD_writeSkippableFrame(void* dst, size_t dstCapacity, + const void* src, size_t srcSize, unsigned magicVariant); + +/*! ZSTD_readSkippableFrame() : + * Retrieves a zstd skippable frame containing data given by src, and writes it to dst buffer. + * + * The parameter magicVariant will receive the magicVariant that was supplied when the frame was written, + * i.e. magicNumber - ZSTD_MAGIC_SKIPPABLE_START. This can be NULL if the caller is not interested + * in the magicVariant. + * + * Returns an error if destination buffer is not large enough, or if the frame is not skippable. + * + * @return : number of bytes written or a ZSTD error. + */ +ZSTDLIB_API size_t ZSTD_readSkippableFrame(void* dst, size_t dstCapacity, unsigned* magicVariant, + const void* src, size_t srcSize); + +/*! ZSTD_isSkippableFrame() : + * Tells if the content of `buffer` starts with a valid Frame Identifier for a skippable frame. + */ +ZSTDLIB_API unsigned ZSTD_isSkippableFrame(const void* buffer, size_t size); + + + +/*************************************** +* Memory management +***************************************/ + +/*! ZSTD_estimate*() : + * These functions make it possible to estimate memory usage + * of a future {D,C}Ctx, before its creation. + * + * ZSTD_estimateCCtxSize() will provide a memory budget large enough + * for any compression level up to selected one. + * Note : Unlike ZSTD_estimateCStreamSize*(), this estimate + * does not include space for a window buffer. + * Therefore, the estimation is only guaranteed for single-shot compressions, not streaming. + * The estimate will assume the input may be arbitrarily large, + * which is the worst case. + * + * When srcSize can be bound by a known and rather "small" value, + * this fact can be used to provide a tighter estimation + * because the CCtx compression context will need less memory. + * This tighter estimation can be provided by more advanced functions + * ZSTD_estimateCCtxSize_usingCParams(), which can be used in tandem with ZSTD_getCParams(), + * and ZSTD_estimateCCtxSize_usingCCtxParams(), which can be used in tandem with ZSTD_CCtxParams_setParameter(). + * Both can be used to estimate memory using custom compression parameters and arbitrary srcSize limits. + * + * Note 2 : only single-threaded compression is supported. + * ZSTD_estimateCCtxSize_usingCCtxParams() will return an error code if ZSTD_c_nbWorkers is >= 1. + */ +ZSTDLIB_STATIC_API size_t ZSTD_estimateCCtxSize(int compressionLevel); +ZSTDLIB_STATIC_API size_t ZSTD_estimateCCtxSize_usingCParams(ZSTD_compressionParameters cParams); +ZSTDLIB_STATIC_API size_t ZSTD_estimateCCtxSize_usingCCtxParams(const ZSTD_CCtx_params* params); +ZSTDLIB_STATIC_API size_t ZSTD_estimateDCtxSize(void); + +/*! ZSTD_estimateCStreamSize() : + * ZSTD_estimateCStreamSize() will provide a budget large enough for any compression level up to selected one. + * It will also consider src size to be arbitrarily "large", which is worst case. + * If srcSize is known to always be small, ZSTD_estimateCStreamSize_usingCParams() can provide a tighter estimation. + * ZSTD_estimateCStreamSize_usingCParams() can be used in tandem with ZSTD_getCParams() to create cParams from compressionLevel. + * ZSTD_estimateCStreamSize_usingCCtxParams() can be used in tandem with ZSTD_CCtxParams_setParameter(). Only single-threaded compression is supported. This function will return an error code if ZSTD_c_nbWorkers is >= 1. + * Note : CStream size estimation is only correct for single-threaded compression. + * ZSTD_DStream memory budget depends on window Size. + * This information can be passed manually, using ZSTD_estimateDStreamSize, + * or deducted from a valid frame Header, using ZSTD_estimateDStreamSize_fromFrame(); + * Note : if streaming is init with function ZSTD_init?Stream_usingDict(), + * an internal ?Dict will be created, which additional size is not estimated here. + * In this case, get total size by adding ZSTD_estimate?DictSize */ +ZSTDLIB_STATIC_API size_t ZSTD_estimateCStreamSize(int compressionLevel); +ZSTDLIB_STATIC_API size_t ZSTD_estimateCStreamSize_usingCParams(ZSTD_compressionParameters cParams); +ZSTDLIB_STATIC_API size_t ZSTD_estimateCStreamSize_usingCCtxParams(const ZSTD_CCtx_params* params); +ZSTDLIB_STATIC_API size_t ZSTD_estimateDStreamSize(size_t windowSize); +ZSTDLIB_STATIC_API size_t ZSTD_estimateDStreamSize_fromFrame(const void* src, size_t srcSize); + +/*! ZSTD_estimate?DictSize() : + * ZSTD_estimateCDictSize() will bet that src size is relatively "small", and content is copied, like ZSTD_createCDict(). + * ZSTD_estimateCDictSize_advanced() makes it possible to control compression parameters precisely, like ZSTD_createCDict_advanced(). + * Note : dictionaries created by reference (`ZSTD_dlm_byRef`) are logically smaller. + */ +ZSTDLIB_STATIC_API size_t ZSTD_estimateCDictSize(size_t dictSize, int compressionLevel); +ZSTDLIB_STATIC_API size_t ZSTD_estimateCDictSize_advanced(size_t dictSize, ZSTD_compressionParameters cParams, ZSTD_dictLoadMethod_e dictLoadMethod); +ZSTDLIB_STATIC_API size_t ZSTD_estimateDDictSize(size_t dictSize, ZSTD_dictLoadMethod_e dictLoadMethod); + +/*! ZSTD_initStatic*() : + * Initialize an object using a pre-allocated fixed-size buffer. + * workspace: The memory area to emplace the object into. + * Provided pointer *must be 8-bytes aligned*. + * Buffer must outlive object. + * workspaceSize: Use ZSTD_estimate*Size() to determine + * how large workspace must be to support target scenario. + * @return : pointer to object (same address as workspace, just different type), + * or NULL if error (size too small, incorrect alignment, etc.) + * Note : zstd will never resize nor malloc() when using a static buffer. + * If the object requires more memory than available, + * zstd will just error out (typically ZSTD_error_memory_allocation). + * Note 2 : there is no corresponding "free" function. + * Since workspace is allocated externally, it must be freed externally too. + * Note 3 : cParams : use ZSTD_getCParams() to convert a compression level + * into its associated cParams. + * Limitation 1 : currently not compatible with internal dictionary creation, triggered by + * ZSTD_CCtx_loadDictionary(), ZSTD_initCStream_usingDict() or ZSTD_initDStream_usingDict(). + * Limitation 2 : static cctx currently not compatible with multi-threading. + * Limitation 3 : static dctx is incompatible with legacy support. + */ +ZSTDLIB_STATIC_API ZSTD_CCtx* ZSTD_initStaticCCtx(void* workspace, size_t workspaceSize); +ZSTDLIB_STATIC_API ZSTD_CStream* ZSTD_initStaticCStream(void* workspace, size_t workspaceSize); /**< same as ZSTD_initStaticCCtx() */ + +ZSTDLIB_STATIC_API ZSTD_DCtx* ZSTD_initStaticDCtx(void* workspace, size_t workspaceSize); +ZSTDLIB_STATIC_API ZSTD_DStream* ZSTD_initStaticDStream(void* workspace, size_t workspaceSize); /**< same as ZSTD_initStaticDCtx() */ + +ZSTDLIB_STATIC_API const ZSTD_CDict* ZSTD_initStaticCDict( + void* workspace, size_t workspaceSize, + const void* dict, size_t dictSize, + ZSTD_dictLoadMethod_e dictLoadMethod, + ZSTD_dictContentType_e dictContentType, + ZSTD_compressionParameters cParams); + +ZSTDLIB_STATIC_API const ZSTD_DDict* ZSTD_initStaticDDict( + void* workspace, size_t workspaceSize, + const void* dict, size_t dictSize, + ZSTD_dictLoadMethod_e dictLoadMethod, + ZSTD_dictContentType_e dictContentType); + + +/*! Custom memory allocation : + * These prototypes make it possible to pass your own allocation/free functions. + * ZSTD_customMem is provided at creation time, using ZSTD_create*_advanced() variants listed below. + * All allocation/free operations will be completed using these custom variants instead of regular ones. + */ +typedef void* (*ZSTD_allocFunction) (void* opaque, size_t size); +typedef void (*ZSTD_freeFunction) (void* opaque, void* address); +typedef struct { ZSTD_allocFunction customAlloc; ZSTD_freeFunction customFree; void* opaque; } ZSTD_customMem; +static +#ifdef __GNUC__ +__attribute__((__unused__)) +#endif +ZSTD_customMem const ZSTD_defaultCMem = { NULL, NULL, NULL }; /**< this constant defers to stdlib's functions */ + +ZSTDLIB_STATIC_API ZSTD_CCtx* ZSTD_createCCtx_advanced(ZSTD_customMem customMem); +ZSTDLIB_STATIC_API ZSTD_CStream* ZSTD_createCStream_advanced(ZSTD_customMem customMem); +ZSTDLIB_STATIC_API ZSTD_DCtx* ZSTD_createDCtx_advanced(ZSTD_customMem customMem); +ZSTDLIB_STATIC_API ZSTD_DStream* ZSTD_createDStream_advanced(ZSTD_customMem customMem); + +ZSTDLIB_STATIC_API ZSTD_CDict* ZSTD_createCDict_advanced(const void* dict, size_t dictSize, + ZSTD_dictLoadMethod_e dictLoadMethod, + ZSTD_dictContentType_e dictContentType, + ZSTD_compressionParameters cParams, + ZSTD_customMem customMem); + +/*! Thread pool : + * These prototypes make it possible to share a thread pool among multiple compression contexts. + * This can limit resources for applications with multiple threads where each one uses + * a threaded compression mode (via ZSTD_c_nbWorkers parameter). + * ZSTD_createThreadPool creates a new thread pool with a given number of threads. + * Note that the lifetime of such pool must exist while being used. + * ZSTD_CCtx_refThreadPool assigns a thread pool to a context (use NULL argument value + * to use an internal thread pool). + * ZSTD_freeThreadPool frees a thread pool, accepts NULL pointer. + */ +typedef struct POOL_ctx_s ZSTD_threadPool; +ZSTDLIB_STATIC_API ZSTD_threadPool* ZSTD_createThreadPool(size_t numThreads); +ZSTDLIB_STATIC_API void ZSTD_freeThreadPool (ZSTD_threadPool* pool); /* accept NULL pointer */ +ZSTDLIB_STATIC_API size_t ZSTD_CCtx_refThreadPool(ZSTD_CCtx* cctx, ZSTD_threadPool* pool); + + +/* + * This API is temporary and is expected to change or disappear in the future! + */ +ZSTDLIB_STATIC_API ZSTD_CDict* ZSTD_createCDict_advanced2( + const void* dict, size_t dictSize, + ZSTD_dictLoadMethod_e dictLoadMethod, + ZSTD_dictContentType_e dictContentType, + const ZSTD_CCtx_params* cctxParams, + ZSTD_customMem customMem); + +ZSTDLIB_STATIC_API ZSTD_DDict* ZSTD_createDDict_advanced( + const void* dict, size_t dictSize, + ZSTD_dictLoadMethod_e dictLoadMethod, + ZSTD_dictContentType_e dictContentType, + ZSTD_customMem customMem); + + +/*************************************** +* Advanced compression functions +***************************************/ + +/*! ZSTD_createCDict_byReference() : + * Create a digested dictionary for compression + * Dictionary content is just referenced, not duplicated. + * As a consequence, `dictBuffer` **must** outlive CDict, + * and its content must remain unmodified throughout the lifetime of CDict. + * note: equivalent to ZSTD_createCDict_advanced(), with dictLoadMethod==ZSTD_dlm_byRef */ +ZSTDLIB_STATIC_API ZSTD_CDict* ZSTD_createCDict_byReference(const void* dictBuffer, size_t dictSize, int compressionLevel); + +/*! ZSTD_getCParams() : + * @return ZSTD_compressionParameters structure for a selected compression level and estimated srcSize. + * `estimatedSrcSize` value is optional, select 0 if not known */ +ZSTDLIB_STATIC_API ZSTD_compressionParameters ZSTD_getCParams(int compressionLevel, unsigned long long estimatedSrcSize, size_t dictSize); + +/*! ZSTD_getParams() : + * same as ZSTD_getCParams(), but @return a full `ZSTD_parameters` object instead of sub-component `ZSTD_compressionParameters`. + * All fields of `ZSTD_frameParameters` are set to default : contentSize=1, checksum=0, noDictID=0 */ +ZSTDLIB_STATIC_API ZSTD_parameters ZSTD_getParams(int compressionLevel, unsigned long long estimatedSrcSize, size_t dictSize); + +/*! ZSTD_checkCParams() : + * Ensure param values remain within authorized range. + * @return 0 on success, or an error code (can be checked with ZSTD_isError()) */ +ZSTDLIB_STATIC_API size_t ZSTD_checkCParams(ZSTD_compressionParameters params); + +/*! ZSTD_adjustCParams() : + * optimize params for a given `srcSize` and `dictSize`. + * `srcSize` can be unknown, in which case use ZSTD_CONTENTSIZE_UNKNOWN. + * `dictSize` must be `0` when there is no dictionary. + * cPar can be invalid : all parameters will be clamped within valid range in the @return struct. + * This function never fails (wide contract) */ +ZSTDLIB_STATIC_API ZSTD_compressionParameters ZSTD_adjustCParams(ZSTD_compressionParameters cPar, unsigned long long srcSize, size_t dictSize); + +/*! ZSTD_compress_advanced() : + * Note : this function is now DEPRECATED. + * It can be replaced by ZSTD_compress2(), in combination with ZSTD_CCtx_setParameter() and other parameter setters. + * This prototype will generate compilation warnings. */ +ZSTD_DEPRECATED("use ZSTD_compress2") +size_t ZSTD_compress_advanced(ZSTD_CCtx* cctx, + void* dst, size_t dstCapacity, + const void* src, size_t srcSize, + const void* dict,size_t dictSize, + ZSTD_parameters params); + +/*! ZSTD_compress_usingCDict_advanced() : + * Note : this function is now DEPRECATED. + * It can be replaced by ZSTD_compress2(), in combination with ZSTD_CCtx_loadDictionary() and other parameter setters. + * This prototype will generate compilation warnings. */ +ZSTD_DEPRECATED("use ZSTD_compress2 with ZSTD_CCtx_loadDictionary") +size_t ZSTD_compress_usingCDict_advanced(ZSTD_CCtx* cctx, + void* dst, size_t dstCapacity, + const void* src, size_t srcSize, + const ZSTD_CDict* cdict, + ZSTD_frameParameters fParams); + + +/*! ZSTD_CCtx_loadDictionary_byReference() : + * Same as ZSTD_CCtx_loadDictionary(), but dictionary content is referenced, instead of being copied into CCtx. + * It saves some memory, but also requires that `dict` outlives its usage within `cctx` */ +ZSTDLIB_STATIC_API size_t ZSTD_CCtx_loadDictionary_byReference(ZSTD_CCtx* cctx, const void* dict, size_t dictSize); + +/*! ZSTD_CCtx_loadDictionary_advanced() : + * Same as ZSTD_CCtx_loadDictionary(), but gives finer control over + * how to load the dictionary (by copy ? by reference ?) + * and how to interpret it (automatic ? force raw mode ? full mode only ?) */ +ZSTDLIB_STATIC_API size_t ZSTD_CCtx_loadDictionary_advanced(ZSTD_CCtx* cctx, const void* dict, size_t dictSize, ZSTD_dictLoadMethod_e dictLoadMethod, ZSTD_dictContentType_e dictContentType); + +/*! ZSTD_CCtx_refPrefix_advanced() : + * Same as ZSTD_CCtx_refPrefix(), but gives finer control over + * how to interpret prefix content (automatic ? force raw mode (default) ? full mode only ?) */ +ZSTDLIB_STATIC_API size_t ZSTD_CCtx_refPrefix_advanced(ZSTD_CCtx* cctx, const void* prefix, size_t prefixSize, ZSTD_dictContentType_e dictContentType); + +/* === experimental parameters === */ +/* these parameters can be used with ZSTD_setParameter() + * they are not guaranteed to remain supported in the future */ + + /* Enables rsyncable mode, + * which makes compressed files more rsync friendly + * by adding periodic synchronization points to the compressed data. + * The target average block size is ZSTD_c_jobSize / 2. + * It's possible to modify the job size to increase or decrease + * the granularity of the synchronization point. + * Once the jobSize is smaller than the window size, + * it will result in compression ratio degradation. + * NOTE 1: rsyncable mode only works when multithreading is enabled. + * NOTE 2: rsyncable performs poorly in combination with long range mode, + * since it will decrease the effectiveness of synchronization points, + * though mileage may vary. + * NOTE 3: Rsyncable mode limits maximum compression speed to ~400 MB/s. + * If the selected compression level is already running significantly slower, + * the overall speed won't be significantly impacted. + */ + #define ZSTD_c_rsyncable ZSTD_c_experimentalParam1 + +/* Select a compression format. + * The value must be of type ZSTD_format_e. + * See ZSTD_format_e enum definition for details */ +#define ZSTD_c_format ZSTD_c_experimentalParam2 + +/* Force back-reference distances to remain < windowSize, + * even when referencing into Dictionary content (default:0) */ +#define ZSTD_c_forceMaxWindow ZSTD_c_experimentalParam3 + +/* Controls whether the contents of a CDict + * are used in place, or copied into the working context. + * Accepts values from the ZSTD_dictAttachPref_e enum. + * See the comments on that enum for an explanation of the feature. */ +#define ZSTD_c_forceAttachDict ZSTD_c_experimentalParam4 + +/* Controlled with ZSTD_paramSwitch_e enum. + * Default is ZSTD_ps_auto. + * Set to ZSTD_ps_disable to never compress literals. + * Set to ZSTD_ps_enable to always compress literals. (Note: uncompressed literals + * may still be emitted if huffman is not beneficial to use.) + * + * By default, in ZSTD_ps_auto, the library will decide at runtime whether to use + * literals compression based on the compression parameters - specifically, + * negative compression levels do not use literal compression. + */ +#define ZSTD_c_literalCompressionMode ZSTD_c_experimentalParam5 + +/* Tries to fit compressed block size to be around targetCBlockSize. + * No target when targetCBlockSize == 0. + * There is no guarantee on compressed block size (default:0) */ +#define ZSTD_c_targetCBlockSize ZSTD_c_experimentalParam6 + +/* User's best guess of source size. + * Hint is not valid when srcSizeHint == 0. + * There is no guarantee that hint is close to actual source size, + * but compression ratio may regress significantly if guess considerably underestimates */ +#define ZSTD_c_srcSizeHint ZSTD_c_experimentalParam7 + +/* Controls whether the new and experimental "dedicated dictionary search + * structure" can be used. This feature is still rough around the edges, be + * prepared for surprising behavior! + * + * How to use it: + * + * When using a CDict, whether to use this feature or not is controlled at + * CDict creation, and it must be set in a CCtxParams set passed into that + * construction (via ZSTD_createCDict_advanced2()). A compression will then + * use the feature or not based on how the CDict was constructed; the value of + * this param, set in the CCtx, will have no effect. + * + * However, when a dictionary buffer is passed into a CCtx, such as via + * ZSTD_CCtx_loadDictionary(), this param can be set on the CCtx to control + * whether the CDict that is created internally can use the feature or not. + * + * What it does: + * + * Normally, the internal data structures of the CDict are analogous to what + * would be stored in a CCtx after compressing the contents of a dictionary. + * To an approximation, a compression using a dictionary can then use those + * data structures to simply continue what is effectively a streaming + * compression where the simulated compression of the dictionary left off. + * Which is to say, the search structures in the CDict are normally the same + * format as in the CCtx. + * + * It is possible to do better, since the CDict is not like a CCtx: the search + * structures are written once during CDict creation, and then are only read + * after that, while the search structures in the CCtx are both read and + * written as the compression goes along. This means we can choose a search + * structure for the dictionary that is read-optimized. + * + * This feature enables the use of that different structure. + * + * Note that some of the members of the ZSTD_compressionParameters struct have + * different semantics and constraints in the dedicated search structure. It is + * highly recommended that you simply set a compression level in the CCtxParams + * you pass into the CDict creation call, and avoid messing with the cParams + * directly. + * + * Effects: + * + * This will only have any effect when the selected ZSTD_strategy + * implementation supports this feature. Currently, that's limited to + * ZSTD_greedy, ZSTD_lazy, and ZSTD_lazy2. + * + * Note that this means that the CDict tables can no longer be copied into the + * CCtx, so the dict attachment mode ZSTD_dictForceCopy will no longer be + * usable. The dictionary can only be attached or reloaded. + * + * In general, you should expect compression to be faster--sometimes very much + * so--and CDict creation to be slightly slower. Eventually, we will probably + * make this mode the default. + */ +#define ZSTD_c_enableDedicatedDictSearch ZSTD_c_experimentalParam8 + +/* ZSTD_c_stableInBuffer + * Experimental parameter. + * Default is 0 == disabled. Set to 1 to enable. + * + * Tells the compressor that the ZSTD_inBuffer will ALWAYS be the same + * between calls, except for the modifications that zstd makes to pos (the + * caller must not modify pos). This is checked by the compressor, and + * compression will fail if it ever changes. This means the only flush + * mode that makes sense is ZSTD_e_end, so zstd will error if ZSTD_e_end + * is not used. The data in the ZSTD_inBuffer in the range [src, src + pos) + * MUST not be modified during compression or you will get data corruption. + * + * When this flag is enabled zstd won't allocate an input window buffer, + * because the user guarantees it can reference the ZSTD_inBuffer until + * the frame is complete. But, it will still allocate an output buffer + * large enough to fit a block (see ZSTD_c_stableOutBuffer). This will also + * avoid the memcpy() from the input buffer to the input window buffer. + * + * NOTE: ZSTD_compressStream2() will error if ZSTD_e_end is not used. + * That means this flag cannot be used with ZSTD_compressStream(). + * + * NOTE: So long as the ZSTD_inBuffer always points to valid memory, using + * this flag is ALWAYS memory safe, and will never access out-of-bounds + * memory. However, compression WILL fail if you violate the preconditions. + * + * WARNING: The data in the ZSTD_inBuffer in the range [dst, dst + pos) MUST + * not be modified during compression or you will get data corruption. This + * is because zstd needs to reference data in the ZSTD_inBuffer to find + * matches. Normally zstd maintains its own window buffer for this purpose, + * but passing this flag tells zstd to use the user provided buffer. + */ +#define ZSTD_c_stableInBuffer ZSTD_c_experimentalParam9 + +/* ZSTD_c_stableOutBuffer + * Experimental parameter. + * Default is 0 == disabled. Set to 1 to enable. + * + * Tells he compressor that the ZSTD_outBuffer will not be resized between + * calls. Specifically: (out.size - out.pos) will never grow. This gives the + * compressor the freedom to say: If the compressed data doesn't fit in the + * output buffer then return ZSTD_error_dstSizeTooSmall. This allows us to + * always decompress directly into the output buffer, instead of decompressing + * into an internal buffer and copying to the output buffer. + * + * When this flag is enabled zstd won't allocate an output buffer, because + * it can write directly to the ZSTD_outBuffer. It will still allocate the + * input window buffer (see ZSTD_c_stableInBuffer). + * + * Zstd will check that (out.size - out.pos) never grows and return an error + * if it does. While not strictly necessary, this should prevent surprises. + */ +#define ZSTD_c_stableOutBuffer ZSTD_c_experimentalParam10 + +/* ZSTD_c_blockDelimiters + * Default is 0 == ZSTD_sf_noBlockDelimiters. + * + * For use with sequence compression API: ZSTD_compressSequences(). + * + * Designates whether or not the given array of ZSTD_Sequence contains block delimiters + * and last literals, which are defined as sequences with offset == 0 and matchLength == 0. + * See the definition of ZSTD_Sequence for more specifics. + */ +#define ZSTD_c_blockDelimiters ZSTD_c_experimentalParam11 + +/* ZSTD_c_validateSequences + * Default is 0 == disabled. Set to 1 to enable sequence validation. + * + * For use with sequence compression API: ZSTD_compressSequences(). + * Designates whether or not we validate sequences provided to ZSTD_compressSequences() + * during function execution. + * + * Without validation, providing a sequence that does not conform to the zstd spec will cause + * undefined behavior, and may produce a corrupted block. + * + * With validation enabled, a if sequence is invalid (see doc/zstd_compression_format.md for + * specifics regarding offset/matchlength requirements) then the function will bail out and + * return an error. + * + */ +#define ZSTD_c_validateSequences ZSTD_c_experimentalParam12 + +/* ZSTD_c_useBlockSplitter + * Controlled with ZSTD_paramSwitch_e enum. + * Default is ZSTD_ps_auto. + * Set to ZSTD_ps_disable to never use block splitter. + * Set to ZSTD_ps_enable to always use block splitter. + * + * By default, in ZSTD_ps_auto, the library will decide at runtime whether to use + * block splitting based on the compression parameters. + */ +#define ZSTD_c_useBlockSplitter ZSTD_c_experimentalParam13 + +/* ZSTD_c_useRowMatchFinder + * Controlled with ZSTD_paramSwitch_e enum. + * Default is ZSTD_ps_auto. + * Set to ZSTD_ps_disable to never use row-based matchfinder. + * Set to ZSTD_ps_enable to force usage of row-based matchfinder. + * + * By default, in ZSTD_ps_auto, the library will decide at runtime whether to use + * the row-based matchfinder based on support for SIMD instructions and the window log. + * Note that this only pertains to compression strategies: greedy, lazy, and lazy2 + */ +#define ZSTD_c_useRowMatchFinder ZSTD_c_experimentalParam14 + +/* ZSTD_c_deterministicRefPrefix + * Default is 0 == disabled. Set to 1 to enable. + * + * Zstd produces different results for prefix compression when the prefix is + * directly adjacent to the data about to be compressed vs. when it isn't. + * This is because zstd detects that the two buffers are contiguous and it can + * use a more efficient match finding algorithm. However, this produces different + * results than when the two buffers are non-contiguous. This flag forces zstd + * to always load the prefix in non-contiguous mode, even if it happens to be + * adjacent to the data, to guarantee determinism. + * + * If you really care about determinism when using a dictionary or prefix, + * like when doing delta compression, you should select this option. It comes + * at a speed penalty of about ~2.5% if the dictionary and data happened to be + * contiguous, and is free if they weren't contiguous. We don't expect that + * intentionally making the dictionary and data contiguous will be worth the + * cost to memcpy() the data. + */ +#define ZSTD_c_deterministicRefPrefix ZSTD_c_experimentalParam15 + +/*! ZSTD_CCtx_getParameter() : + * Get the requested compression parameter value, selected by enum ZSTD_cParameter, + * and store it into int* value. + * @return : 0, or an error code (which can be tested with ZSTD_isError()). + */ +ZSTDLIB_STATIC_API size_t ZSTD_CCtx_getParameter(const ZSTD_CCtx* cctx, ZSTD_cParameter param, int* value); + + +/*! ZSTD_CCtx_params : + * Quick howto : + * - ZSTD_createCCtxParams() : Create a ZSTD_CCtx_params structure + * - ZSTD_CCtxParams_setParameter() : Push parameters one by one into + * an existing ZSTD_CCtx_params structure. + * This is similar to + * ZSTD_CCtx_setParameter(). + * - ZSTD_CCtx_setParametersUsingCCtxParams() : Apply parameters to + * an existing CCtx. + * These parameters will be applied to + * all subsequent frames. + * - ZSTD_compressStream2() : Do compression using the CCtx. + * - ZSTD_freeCCtxParams() : Free the memory, accept NULL pointer. + * + * This can be used with ZSTD_estimateCCtxSize_advanced_usingCCtxParams() + * for static allocation of CCtx for single-threaded compression. + */ +ZSTDLIB_STATIC_API ZSTD_CCtx_params* ZSTD_createCCtxParams(void); +ZSTDLIB_STATIC_API size_t ZSTD_freeCCtxParams(ZSTD_CCtx_params* params); /* accept NULL pointer */ + +/*! ZSTD_CCtxParams_reset() : + * Reset params to default values. + */ +ZSTDLIB_STATIC_API size_t ZSTD_CCtxParams_reset(ZSTD_CCtx_params* params); + +/*! ZSTD_CCtxParams_init() : + * Initializes the compression parameters of cctxParams according to + * compression level. All other parameters are reset to their default values. + */ +ZSTDLIB_STATIC_API size_t ZSTD_CCtxParams_init(ZSTD_CCtx_params* cctxParams, int compressionLevel); + +/*! ZSTD_CCtxParams_init_advanced() : + * Initializes the compression and frame parameters of cctxParams according to + * params. All other parameters are reset to their default values. + */ +ZSTDLIB_STATIC_API size_t ZSTD_CCtxParams_init_advanced(ZSTD_CCtx_params* cctxParams, ZSTD_parameters params); + +/*! ZSTD_CCtxParams_setParameter() : Requires v1.4.0+ + * Similar to ZSTD_CCtx_setParameter. + * Set one compression parameter, selected by enum ZSTD_cParameter. + * Parameters must be applied to a ZSTD_CCtx using + * ZSTD_CCtx_setParametersUsingCCtxParams(). + * @result : a code representing success or failure (which can be tested with + * ZSTD_isError()). + */ +ZSTDLIB_STATIC_API size_t ZSTD_CCtxParams_setParameter(ZSTD_CCtx_params* params, ZSTD_cParameter param, int value); + +/*! ZSTD_CCtxParams_getParameter() : + * Similar to ZSTD_CCtx_getParameter. + * Get the requested value of one compression parameter, selected by enum ZSTD_cParameter. + * @result : 0, or an error code (which can be tested with ZSTD_isError()). + */ +ZSTDLIB_STATIC_API size_t ZSTD_CCtxParams_getParameter(const ZSTD_CCtx_params* params, ZSTD_cParameter param, int* value); + +/*! ZSTD_CCtx_setParametersUsingCCtxParams() : + * Apply a set of ZSTD_CCtx_params to the compression context. + * This can be done even after compression is started, + * if nbWorkers==0, this will have no impact until a new compression is started. + * if nbWorkers>=1, new parameters will be picked up at next job, + * with a few restrictions (windowLog, pledgedSrcSize, nbWorkers, jobSize, and overlapLog are not updated). + */ +ZSTDLIB_STATIC_API size_t ZSTD_CCtx_setParametersUsingCCtxParams( + ZSTD_CCtx* cctx, const ZSTD_CCtx_params* params); + +/*! ZSTD_compressStream2_simpleArgs() : + * Same as ZSTD_compressStream2(), + * but using only integral types as arguments. + * This variant might be helpful for binders from dynamic languages + * which have troubles handling structures containing memory pointers. + */ +ZSTDLIB_STATIC_API size_t ZSTD_compressStream2_simpleArgs ( + ZSTD_CCtx* cctx, + void* dst, size_t dstCapacity, size_t* dstPos, + const void* src, size_t srcSize, size_t* srcPos, + ZSTD_EndDirective endOp); + + +/*************************************** +* Advanced decompression functions +***************************************/ + +/*! ZSTD_isFrame() : + * Tells if the content of `buffer` starts with a valid Frame Identifier. + * Note : Frame Identifier is 4 bytes. If `size < 4`, @return will always be 0. + * Note 2 : Legacy Frame Identifiers are considered valid only if Legacy Support is enabled. + * Note 3 : Skippable Frame Identifiers are considered valid. */ +ZSTDLIB_STATIC_API unsigned ZSTD_isFrame(const void* buffer, size_t size); + +/*! ZSTD_createDDict_byReference() : + * Create a digested dictionary, ready to start decompression operation without startup delay. + * Dictionary content is referenced, and therefore stays in dictBuffer. + * It is important that dictBuffer outlives DDict, + * it must remain read accessible throughout the lifetime of DDict */ +ZSTDLIB_STATIC_API ZSTD_DDict* ZSTD_createDDict_byReference(const void* dictBuffer, size_t dictSize); + +/*! ZSTD_DCtx_loadDictionary_byReference() : + * Same as ZSTD_DCtx_loadDictionary(), + * but references `dict` content instead of copying it into `dctx`. + * This saves memory if `dict` remains around., + * However, it's imperative that `dict` remains accessible (and unmodified) while being used, so it must outlive decompression. */ +ZSTDLIB_STATIC_API size_t ZSTD_DCtx_loadDictionary_byReference(ZSTD_DCtx* dctx, const void* dict, size_t dictSize); + +/*! ZSTD_DCtx_loadDictionary_advanced() : + * Same as ZSTD_DCtx_loadDictionary(), + * but gives direct control over + * how to load the dictionary (by copy ? by reference ?) + * and how to interpret it (automatic ? force raw mode ? full mode only ?). */ +ZSTDLIB_STATIC_API size_t ZSTD_DCtx_loadDictionary_advanced(ZSTD_DCtx* dctx, const void* dict, size_t dictSize, ZSTD_dictLoadMethod_e dictLoadMethod, ZSTD_dictContentType_e dictContentType); + +/*! ZSTD_DCtx_refPrefix_advanced() : + * Same as ZSTD_DCtx_refPrefix(), but gives finer control over + * how to interpret prefix content (automatic ? force raw mode (default) ? full mode only ?) */ +ZSTDLIB_STATIC_API size_t ZSTD_DCtx_refPrefix_advanced(ZSTD_DCtx* dctx, const void* prefix, size_t prefixSize, ZSTD_dictContentType_e dictContentType); + +/*! ZSTD_DCtx_setMaxWindowSize() : + * Refuses allocating internal buffers for frames requiring a window size larger than provided limit. + * This protects a decoder context from reserving too much memory for itself (potential attack scenario). + * This parameter is only useful in streaming mode, since no internal buffer is allocated in single-pass mode. + * By default, a decompression context accepts all window sizes <= (1 << ZSTD_WINDOWLOG_LIMIT_DEFAULT) + * @return : 0, or an error code (which can be tested using ZSTD_isError()). + */ +ZSTDLIB_STATIC_API size_t ZSTD_DCtx_setMaxWindowSize(ZSTD_DCtx* dctx, size_t maxWindowSize); + +/*! ZSTD_DCtx_getParameter() : + * Get the requested decompression parameter value, selected by enum ZSTD_dParameter, + * and store it into int* value. + * @return : 0, or an error code (which can be tested with ZSTD_isError()). + */ +ZSTDLIB_STATIC_API size_t ZSTD_DCtx_getParameter(ZSTD_DCtx* dctx, ZSTD_dParameter param, int* value); + +/* ZSTD_d_format + * experimental parameter, + * allowing selection between ZSTD_format_e input compression formats + */ +#define ZSTD_d_format ZSTD_d_experimentalParam1 +/* ZSTD_d_stableOutBuffer + * Experimental parameter. + * Default is 0 == disabled. Set to 1 to enable. + * + * Tells the decompressor that the ZSTD_outBuffer will ALWAYS be the same + * between calls, except for the modifications that zstd makes to pos (the + * caller must not modify pos). This is checked by the decompressor, and + * decompression will fail if it ever changes. Therefore the ZSTD_outBuffer + * MUST be large enough to fit the entire decompressed frame. This will be + * checked when the frame content size is known. The data in the ZSTD_outBuffer + * in the range [dst, dst + pos) MUST not be modified during decompression + * or you will get data corruption. + * + * When this flags is enabled zstd won't allocate an output buffer, because + * it can write directly to the ZSTD_outBuffer, but it will still allocate + * an input buffer large enough to fit any compressed block. This will also + * avoid the memcpy() from the internal output buffer to the ZSTD_outBuffer. + * If you need to avoid the input buffer allocation use the buffer-less + * streaming API. + * + * NOTE: So long as the ZSTD_outBuffer always points to valid memory, using + * this flag is ALWAYS memory safe, and will never access out-of-bounds + * memory. However, decompression WILL fail if you violate the preconditions. + * + * WARNING: The data in the ZSTD_outBuffer in the range [dst, dst + pos) MUST + * not be modified during decompression or you will get data corruption. This + * is because zstd needs to reference data in the ZSTD_outBuffer to regenerate + * matches. Normally zstd maintains its own buffer for this purpose, but passing + * this flag tells zstd to use the user provided buffer. + */ +#define ZSTD_d_stableOutBuffer ZSTD_d_experimentalParam2 + +/* ZSTD_d_forceIgnoreChecksum + * Experimental parameter. + * Default is 0 == disabled. Set to 1 to enable + * + * Tells the decompressor to skip checksum validation during decompression, regardless + * of whether checksumming was specified during compression. This offers some + * slight performance benefits, and may be useful for debugging. + * Param has values of type ZSTD_forceIgnoreChecksum_e + */ +#define ZSTD_d_forceIgnoreChecksum ZSTD_d_experimentalParam3 + +/* ZSTD_d_refMultipleDDicts + * Experimental parameter. + * Default is 0 == disabled. Set to 1 to enable + * + * If enabled and dctx is allocated on the heap, then additional memory will be allocated + * to store references to multiple ZSTD_DDict. That is, multiple calls of ZSTD_refDDict() + * using a given ZSTD_DCtx, rather than overwriting the previous DDict reference, will instead + * store all references. At decompression time, the appropriate dictID is selected + * from the set of DDicts based on the dictID in the frame. + * + * Usage is simply calling ZSTD_refDDict() on multiple dict buffers. + * + * Param has values of byte ZSTD_refMultipleDDicts_e + * + * WARNING: Enabling this parameter and calling ZSTD_DCtx_refDDict(), will trigger memory + * allocation for the hash table. ZSTD_freeDCtx() also frees this memory. + * Memory is allocated as per ZSTD_DCtx::customMem. + * + * Although this function allocates memory for the table, the user is still responsible for + * memory management of the underlying ZSTD_DDict* themselves. + */ +#define ZSTD_d_refMultipleDDicts ZSTD_d_experimentalParam4 + + +/*! ZSTD_DCtx_setFormat() : + * This function is REDUNDANT. Prefer ZSTD_DCtx_setParameter(). + * Instruct the decoder context about what kind of data to decode next. + * This instruction is mandatory to decode data without a fully-formed header, + * such ZSTD_f_zstd1_magicless for example. + * @return : 0, or an error code (which can be tested using ZSTD_isError()). */ +ZSTD_DEPRECATED("use ZSTD_DCtx_setParameter() instead") +size_t ZSTD_DCtx_setFormat(ZSTD_DCtx* dctx, ZSTD_format_e format); + +/*! ZSTD_decompressStream_simpleArgs() : + * Same as ZSTD_decompressStream(), + * but using only integral types as arguments. + * This can be helpful for binders from dynamic languages + * which have troubles handling structures containing memory pointers. + */ +ZSTDLIB_STATIC_API size_t ZSTD_decompressStream_simpleArgs ( + ZSTD_DCtx* dctx, + void* dst, size_t dstCapacity, size_t* dstPos, + const void* src, size_t srcSize, size_t* srcPos); + + +/******************************************************************** +* Advanced streaming functions +* Warning : most of these functions are now redundant with the Advanced API. +* Once Advanced API reaches "stable" status, +* redundant functions will be deprecated, and then at some point removed. +********************************************************************/ + +/*===== Advanced Streaming compression functions =====*/ + +/*! ZSTD_initCStream_srcSize() : + * This function is DEPRECATED, and equivalent to: + * ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only); + * ZSTD_CCtx_refCDict(zcs, NULL); // clear the dictionary (if any) + * ZSTD_CCtx_setParameter(zcs, ZSTD_c_compressionLevel, compressionLevel); + * ZSTD_CCtx_setPledgedSrcSize(zcs, pledgedSrcSize); + * + * pledgedSrcSize must be correct. If it is not known at init time, use + * ZSTD_CONTENTSIZE_UNKNOWN. Note that, for compatibility with older programs, + * "0" also disables frame content size field. It may be enabled in the future. + * This prototype will generate compilation warnings. + */ +ZSTD_DEPRECATED("use ZSTD_CCtx_reset, see zstd.h for detailed instructions") +size_t ZSTD_initCStream_srcSize(ZSTD_CStream* zcs, + int compressionLevel, + unsigned long long pledgedSrcSize); + +/*! ZSTD_initCStream_usingDict() : + * This function is DEPRECATED, and is equivalent to: + * ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only); + * ZSTD_CCtx_setParameter(zcs, ZSTD_c_compressionLevel, compressionLevel); + * ZSTD_CCtx_loadDictionary(zcs, dict, dictSize); + * + * Creates of an internal CDict (incompatible with static CCtx), except if + * dict == NULL or dictSize < 8, in which case no dict is used. + * Note: dict is loaded with ZSTD_dct_auto (treated as a full zstd dictionary if + * it begins with ZSTD_MAGIC_DICTIONARY, else as raw content) and ZSTD_dlm_byCopy. + * This prototype will generate compilation warnings. + */ +ZSTD_DEPRECATED("use ZSTD_CCtx_reset, see zstd.h for detailed instructions") +size_t ZSTD_initCStream_usingDict(ZSTD_CStream* zcs, + const void* dict, size_t dictSize, + int compressionLevel); + +/*! ZSTD_initCStream_advanced() : + * This function is DEPRECATED, and is approximately equivalent to: + * ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only); + * // Pseudocode: Set each zstd parameter and leave the rest as-is. + * for ((param, value) : params) { + * ZSTD_CCtx_setParameter(zcs, param, value); + * } + * ZSTD_CCtx_setPledgedSrcSize(zcs, pledgedSrcSize); + * ZSTD_CCtx_loadDictionary(zcs, dict, dictSize); + * + * dict is loaded with ZSTD_dct_auto and ZSTD_dlm_byCopy. + * pledgedSrcSize must be correct. + * If srcSize is not known at init time, use value ZSTD_CONTENTSIZE_UNKNOWN. + * This prototype will generate compilation warnings. + */ +ZSTD_DEPRECATED("use ZSTD_CCtx_reset, see zstd.h for detailed instructions") +size_t ZSTD_initCStream_advanced(ZSTD_CStream* zcs, + const void* dict, size_t dictSize, + ZSTD_parameters params, + unsigned long long pledgedSrcSize); + +/*! ZSTD_initCStream_usingCDict() : + * This function is DEPRECATED, and equivalent to: + * ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only); + * ZSTD_CCtx_refCDict(zcs, cdict); + * + * note : cdict will just be referenced, and must outlive compression session + * This prototype will generate compilation warnings. + */ +ZSTD_DEPRECATED("use ZSTD_CCtx_reset and ZSTD_CCtx_refCDict, see zstd.h for detailed instructions") +size_t ZSTD_initCStream_usingCDict(ZSTD_CStream* zcs, const ZSTD_CDict* cdict); + +/*! ZSTD_initCStream_usingCDict_advanced() : + * This function is DEPRECATED, and is approximately equivalent to: + * ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only); + * // Pseudocode: Set each zstd frame parameter and leave the rest as-is. + * for ((fParam, value) : fParams) { + * ZSTD_CCtx_setParameter(zcs, fParam, value); + * } + * ZSTD_CCtx_setPledgedSrcSize(zcs, pledgedSrcSize); + * ZSTD_CCtx_refCDict(zcs, cdict); + * + * same as ZSTD_initCStream_usingCDict(), with control over frame parameters. + * pledgedSrcSize must be correct. If srcSize is not known at init time, use + * value ZSTD_CONTENTSIZE_UNKNOWN. + * This prototype will generate compilation warnings. + */ +ZSTD_DEPRECATED("use ZSTD_CCtx_reset and ZSTD_CCtx_refCDict, see zstd.h for detailed instructions") +size_t ZSTD_initCStream_usingCDict_advanced(ZSTD_CStream* zcs, + const ZSTD_CDict* cdict, + ZSTD_frameParameters fParams, + unsigned long long pledgedSrcSize); + +/*! ZSTD_resetCStream() : + * This function is DEPRECATED, and is equivalent to: + * ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only); + * ZSTD_CCtx_setPledgedSrcSize(zcs, pledgedSrcSize); + * Note: ZSTD_resetCStream() interprets pledgedSrcSize == 0 as ZSTD_CONTENTSIZE_UNKNOWN, but + * ZSTD_CCtx_setPledgedSrcSize() does not do the same, so ZSTD_CONTENTSIZE_UNKNOWN must be + * explicitly specified. + * + * start a new frame, using same parameters from previous frame. + * This is typically useful to skip dictionary loading stage, since it will re-use it in-place. + * Note that zcs must be init at least once before using ZSTD_resetCStream(). + * If pledgedSrcSize is not known at reset time, use macro ZSTD_CONTENTSIZE_UNKNOWN. + * If pledgedSrcSize > 0, its value must be correct, as it will be written in header, and controlled at the end. + * For the time being, pledgedSrcSize==0 is interpreted as "srcSize unknown" for compatibility with older programs, + * but it will change to mean "empty" in future version, so use macro ZSTD_CONTENTSIZE_UNKNOWN instead. + * @return : 0, or an error code (which can be tested using ZSTD_isError()) + * This prototype will generate compilation warnings. + */ +ZSTD_DEPRECATED("use ZSTD_CCtx_reset, see zstd.h for detailed instructions") +size_t ZSTD_resetCStream(ZSTD_CStream* zcs, unsigned long long pledgedSrcSize); + + +typedef struct { + unsigned long long ingested; /* nb input bytes read and buffered */ + unsigned long long consumed; /* nb input bytes actually compressed */ + unsigned long long produced; /* nb of compressed bytes generated and buffered */ + unsigned long long flushed; /* nb of compressed bytes flushed : not provided; can be tracked from caller side */ + unsigned currentJobID; /* MT only : latest started job nb */ + unsigned nbActiveWorkers; /* MT only : nb of workers actively compressing at probe time */ +} ZSTD_frameProgression; + +/* ZSTD_getFrameProgression() : + * tells how much data has been ingested (read from input) + * consumed (input actually compressed) and produced (output) for current frame. + * Note : (ingested - consumed) is amount of input data buffered internally, not yet compressed. + * Aggregates progression inside active worker threads. + */ +ZSTDLIB_STATIC_API ZSTD_frameProgression ZSTD_getFrameProgression(const ZSTD_CCtx* cctx); + +/*! ZSTD_toFlushNow() : + * Tell how many bytes are ready to be flushed immediately. + * Useful for multithreading scenarios (nbWorkers >= 1). + * Probe the oldest active job, defined as oldest job not yet entirely flushed, + * and check its output buffer. + * @return : amount of data stored in oldest job and ready to be flushed immediately. + * if @return == 0, it means either : + * + there is no active job (could be checked with ZSTD_frameProgression()), or + * + oldest job is still actively compressing data, + * but everything it has produced has also been flushed so far, + * therefore flush speed is limited by production speed of oldest job + * irrespective of the speed of concurrent (and newer) jobs. + */ +ZSTDLIB_STATIC_API size_t ZSTD_toFlushNow(ZSTD_CCtx* cctx); + + +/*===== Advanced Streaming decompression functions =====*/ + +/*! + * This function is deprecated, and is equivalent to: + * + * ZSTD_DCtx_reset(zds, ZSTD_reset_session_only); + * ZSTD_DCtx_loadDictionary(zds, dict, dictSize); + * + * note: no dictionary will be used if dict == NULL or dictSize < 8 + * Note : this prototype will be marked as deprecated and generate compilation warnings on reaching v1.5.x + */ +ZSTDLIB_STATIC_API size_t ZSTD_initDStream_usingDict(ZSTD_DStream* zds, const void* dict, size_t dictSize); + +/*! + * This function is deprecated, and is equivalent to: + * + * ZSTD_DCtx_reset(zds, ZSTD_reset_session_only); + * ZSTD_DCtx_refDDict(zds, ddict); + * + * note : ddict is referenced, it must outlive decompression session + * Note : this prototype will be marked as deprecated and generate compilation warnings on reaching v1.5.x + */ +ZSTDLIB_STATIC_API size_t ZSTD_initDStream_usingDDict(ZSTD_DStream* zds, const ZSTD_DDict* ddict); + +/*! + * This function is deprecated, and is equivalent to: + * + * ZSTD_DCtx_reset(zds, ZSTD_reset_session_only); + * + * re-use decompression parameters from previous init; saves dictionary loading + * Note : this prototype will be marked as deprecated and generate compilation warnings on reaching v1.5.x + */ +ZSTDLIB_STATIC_API size_t ZSTD_resetDStream(ZSTD_DStream* zds); + + +/********************************************************************* +* Buffer-less and synchronous inner streaming functions +* +* This is an advanced API, giving full control over buffer management, for users which need direct control over memory. +* But it's also a complex one, with several restrictions, documented below. +* Prefer normal streaming API for an easier experience. +********************************************************************* */ + +/** + Buffer-less streaming compression (synchronous mode) + + A ZSTD_CCtx object is required to track streaming operations. + Use ZSTD_createCCtx() / ZSTD_freeCCtx() to manage resource. + ZSTD_CCtx object can be re-used multiple times within successive compression operations. + + Start by initializing a context. + Use ZSTD_compressBegin(), or ZSTD_compressBegin_usingDict() for dictionary compression. + It's also possible to duplicate a reference context which has already been initialized, using ZSTD_copyCCtx() + + Then, consume your input using ZSTD_compressContinue(). + There are some important considerations to keep in mind when using this advanced function : + - ZSTD_compressContinue() has no internal buffer. It uses externally provided buffers only. + - Interface is synchronous : input is consumed entirely and produces 1+ compressed blocks. + - Caller must ensure there is enough space in `dst` to store compressed data under worst case scenario. + Worst case evaluation is provided by ZSTD_compressBound(). + ZSTD_compressContinue() doesn't guarantee recover after a failed compression. + - ZSTD_compressContinue() presumes prior input ***is still accessible and unmodified*** (up to maximum distance size, see WindowLog). + It remembers all previous contiguous blocks, plus one separated memory segment (which can itself consists of multiple contiguous blocks) + - ZSTD_compressContinue() detects that prior input has been overwritten when `src` buffer overlaps. + In which case, it will "discard" the relevant memory section from its history. + + Finish a frame with ZSTD_compressEnd(), which will write the last block(s) and optional checksum. + It's possible to use srcSize==0, in which case, it will write a final empty block to end the frame. + Without last block mark, frames are considered unfinished (hence corrupted) by compliant decoders. + + `ZSTD_CCtx` object can be re-used (ZSTD_compressBegin()) to compress again. +*/ + +/*===== Buffer-less streaming compression functions =====*/ +ZSTDLIB_STATIC_API size_t ZSTD_compressBegin(ZSTD_CCtx* cctx, int compressionLevel); +ZSTDLIB_STATIC_API size_t ZSTD_compressBegin_usingDict(ZSTD_CCtx* cctx, const void* dict, size_t dictSize, int compressionLevel); +ZSTDLIB_STATIC_API size_t ZSTD_compressBegin_usingCDict(ZSTD_CCtx* cctx, const ZSTD_CDict* cdict); /**< note: fails if cdict==NULL */ +ZSTDLIB_STATIC_API size_t ZSTD_copyCCtx(ZSTD_CCtx* cctx, const ZSTD_CCtx* preparedCCtx, unsigned long long pledgedSrcSize); /**< note: if pledgedSrcSize is not known, use ZSTD_CONTENTSIZE_UNKNOWN */ + +ZSTDLIB_STATIC_API size_t ZSTD_compressContinue(ZSTD_CCtx* cctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize); +ZSTDLIB_STATIC_API size_t ZSTD_compressEnd(ZSTD_CCtx* cctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize); + +/* The ZSTD_compressBegin_advanced() and ZSTD_compressBegin_usingCDict_advanced() are now DEPRECATED and will generate a compiler warning */ +ZSTD_DEPRECATED("use advanced API to access custom parameters") +size_t ZSTD_compressBegin_advanced(ZSTD_CCtx* cctx, const void* dict, size_t dictSize, ZSTD_parameters params, unsigned long long pledgedSrcSize); /**< pledgedSrcSize : If srcSize is not known at init time, use ZSTD_CONTENTSIZE_UNKNOWN */ +ZSTD_DEPRECATED("use advanced API to access custom parameters") +size_t ZSTD_compressBegin_usingCDict_advanced(ZSTD_CCtx* const cctx, const ZSTD_CDict* const cdict, ZSTD_frameParameters const fParams, unsigned long long const pledgedSrcSize); /* compression parameters are already set within cdict. pledgedSrcSize must be correct. If srcSize is not known, use macro ZSTD_CONTENTSIZE_UNKNOWN */ +/** + Buffer-less streaming decompression (synchronous mode) + + A ZSTD_DCtx object is required to track streaming operations. + Use ZSTD_createDCtx() / ZSTD_freeDCtx() to manage it. + A ZSTD_DCtx object can be re-used multiple times. + + First typical operation is to retrieve frame parameters, using ZSTD_getFrameHeader(). + Frame header is extracted from the beginning of compressed frame, so providing only the frame's beginning is enough. + Data fragment must be large enough to ensure successful decoding. + `ZSTD_frameHeaderSize_max` bytes is guaranteed to always be large enough. + @result : 0 : successful decoding, the `ZSTD_frameHeader` structure is correctly filled. + >0 : `srcSize` is too small, please provide at least @result bytes on next attempt. + errorCode, which can be tested using ZSTD_isError(). + + It fills a ZSTD_frameHeader structure with important information to correctly decode the frame, + such as the dictionary ID, content size, or maximum back-reference distance (`windowSize`). + Note that these values could be wrong, either because of data corruption, or because a 3rd party deliberately spoofs false information. + As a consequence, check that values remain within valid application range. + For example, do not allocate memory blindly, check that `windowSize` is within expectation. + Each application can set its own limits, depending on local restrictions. + For extended interoperability, it is recommended to support `windowSize` of at least 8 MB. + + ZSTD_decompressContinue() needs previous data blocks during decompression, up to `windowSize` bytes. + ZSTD_decompressContinue() is very sensitive to contiguity, + if 2 blocks don't follow each other, make sure that either the compressor breaks contiguity at the same place, + or that previous contiguous segment is large enough to properly handle maximum back-reference distance. + There are multiple ways to guarantee this condition. + + The most memory efficient way is to use a round buffer of sufficient size. + Sufficient size is determined by invoking ZSTD_decodingBufferSize_min(), + which can @return an error code if required value is too large for current system (in 32-bits mode). + In a round buffer methodology, ZSTD_decompressContinue() decompresses each block next to previous one, + up to the moment there is not enough room left in the buffer to guarantee decoding another full block, + which maximum size is provided in `ZSTD_frameHeader` structure, field `blockSizeMax`. + At which point, decoding can resume from the beginning of the buffer. + Note that already decoded data stored in the buffer should be flushed before being overwritten. + + There are alternatives possible, for example using two or more buffers of size `windowSize` each, though they consume more memory. + + Finally, if you control the compression process, you can also ignore all buffer size rules, + as long as the encoder and decoder progress in "lock-step", + aka use exactly the same buffer sizes, break contiguity at the same place, etc. + + Once buffers are setup, start decompression, with ZSTD_decompressBegin(). + If decompression requires a dictionary, use ZSTD_decompressBegin_usingDict() or ZSTD_decompressBegin_usingDDict(). + + Then use ZSTD_nextSrcSizeToDecompress() and ZSTD_decompressContinue() alternatively. + ZSTD_nextSrcSizeToDecompress() tells how many bytes to provide as 'srcSize' to ZSTD_decompressContinue(). + ZSTD_decompressContinue() requires this _exact_ amount of bytes, or it will fail. + + @result of ZSTD_decompressContinue() is the number of bytes regenerated within 'dst' (necessarily <= dstCapacity). + It can be zero : it just means ZSTD_decompressContinue() has decoded some metadata item. + It can also be an error code, which can be tested with ZSTD_isError(). + + A frame is fully decoded when ZSTD_nextSrcSizeToDecompress() returns zero. + Context can then be reset to start a new decompression. + + Note : it's possible to know if next input to present is a header or a block, using ZSTD_nextInputType(). + This information is not required to properly decode a frame. + + == Special case : skippable frames == + + Skippable frames allow integration of user-defined data into a flow of concatenated frames. + Skippable frames will be ignored (skipped) by decompressor. + The format of skippable frames is as follows : + a) Skippable frame ID - 4 Bytes, Little endian format, any value from 0x184D2A50 to 0x184D2A5F + b) Frame Size - 4 Bytes, Little endian format, unsigned 32-bits + c) Frame Content - any content (User Data) of length equal to Frame Size + For skippable frames ZSTD_getFrameHeader() returns zfhPtr->frameType==ZSTD_skippableFrame. + For skippable frames ZSTD_decompressContinue() always returns 0 : it only skips the content. +*/ + +/*===== Buffer-less streaming decompression functions =====*/ +typedef enum { ZSTD_frame, ZSTD_skippableFrame } ZSTD_frameType_e; +typedef struct { + unsigned long long frameContentSize; /* if == ZSTD_CONTENTSIZE_UNKNOWN, it means this field is not available. 0 means "empty" */ + unsigned long long windowSize; /* can be very large, up to <= frameContentSize */ + unsigned blockSizeMax; + ZSTD_frameType_e frameType; /* if == ZSTD_skippableFrame, frameContentSize is the size of skippable content */ + unsigned headerSize; + unsigned dictID; + unsigned checksumFlag; +} ZSTD_frameHeader; + +/*! ZSTD_getFrameHeader() : + * decode Frame Header, or requires larger `srcSize`. + * @return : 0, `zfhPtr` is correctly filled, + * >0, `srcSize` is too small, value is wanted `srcSize` amount, + * or an error code, which can be tested using ZSTD_isError() */ +ZSTDLIB_STATIC_API size_t ZSTD_getFrameHeader(ZSTD_frameHeader* zfhPtr, const void* src, size_t srcSize); /**< doesn't consume input */ +/*! ZSTD_getFrameHeader_advanced() : + * same as ZSTD_getFrameHeader(), + * with added capability to select a format (like ZSTD_f_zstd1_magicless) */ +ZSTDLIB_STATIC_API size_t ZSTD_getFrameHeader_advanced(ZSTD_frameHeader* zfhPtr, const void* src, size_t srcSize, ZSTD_format_e format); +ZSTDLIB_STATIC_API size_t ZSTD_decodingBufferSize_min(unsigned long long windowSize, unsigned long long frameContentSize); /**< when frame content size is not known, pass in frameContentSize == ZSTD_CONTENTSIZE_UNKNOWN */ + +ZSTDLIB_STATIC_API size_t ZSTD_decompressBegin(ZSTD_DCtx* dctx); +ZSTDLIB_STATIC_API size_t ZSTD_decompressBegin_usingDict(ZSTD_DCtx* dctx, const void* dict, size_t dictSize); +ZSTDLIB_STATIC_API size_t ZSTD_decompressBegin_usingDDict(ZSTD_DCtx* dctx, const ZSTD_DDict* ddict); + +ZSTDLIB_STATIC_API size_t ZSTD_nextSrcSizeToDecompress(ZSTD_DCtx* dctx); +ZSTDLIB_STATIC_API size_t ZSTD_decompressContinue(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize); + +/* misc */ +ZSTDLIB_STATIC_API void ZSTD_copyDCtx(ZSTD_DCtx* dctx, const ZSTD_DCtx* preparedDCtx); +typedef enum { ZSTDnit_frameHeader, ZSTDnit_blockHeader, ZSTDnit_block, ZSTDnit_lastBlock, ZSTDnit_checksum, ZSTDnit_skippableFrame } ZSTD_nextInputType_e; +ZSTDLIB_STATIC_API ZSTD_nextInputType_e ZSTD_nextInputType(ZSTD_DCtx* dctx); + + + + +/* ============================ */ +/** Block level API */ +/* ============================ */ + +/*! + Block functions produce and decode raw zstd blocks, without frame metadata. + Frame metadata cost is typically ~12 bytes, which can be non-negligible for very small blocks (< 100 bytes). + But users will have to take in charge needed metadata to regenerate data, such as compressed and content sizes. + + A few rules to respect : + - Compressing and decompressing require a context structure + + Use ZSTD_createCCtx() and ZSTD_createDCtx() + - It is necessary to init context before starting + + compression : any ZSTD_compressBegin*() variant, including with dictionary + + decompression : any ZSTD_decompressBegin*() variant, including with dictionary + + copyCCtx() and copyDCtx() can be used too + - Block size is limited, it must be <= ZSTD_getBlockSize() <= ZSTD_BLOCKSIZE_MAX == 128 KB + + If input is larger than a block size, it's necessary to split input data into multiple blocks + + For inputs larger than a single block, consider using regular ZSTD_compress() instead. + Frame metadata is not that costly, and quickly becomes negligible as source size grows larger than a block. + - When a block is considered not compressible enough, ZSTD_compressBlock() result will be 0 (zero) ! + ===> In which case, nothing is produced into `dst` ! + + User __must__ test for such outcome and deal directly with uncompressed data + + A block cannot be declared incompressible if ZSTD_compressBlock() return value was != 0. + Doing so would mess up with statistics history, leading to potential data corruption. + + ZSTD_decompressBlock() _doesn't accept uncompressed data as input_ !! + + In case of multiple successive blocks, should some of them be uncompressed, + decoder must be informed of their existence in order to follow proper history. + Use ZSTD_insertBlock() for such a case. +*/ + +/*===== Raw zstd block functions =====*/ +ZSTDLIB_STATIC_API size_t ZSTD_getBlockSize (const ZSTD_CCtx* cctx); +ZSTDLIB_STATIC_API size_t ZSTD_compressBlock (ZSTD_CCtx* cctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize); +ZSTDLIB_STATIC_API size_t ZSTD_decompressBlock(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize); +ZSTDLIB_STATIC_API size_t ZSTD_insertBlock (ZSTD_DCtx* dctx, const void* blockStart, size_t blockSize); /**< insert uncompressed block into `dctx` history. Useful for multi-blocks decompression. */ + + +#endif /* ZSTD_H_ZSTD_STATIC_LINKING_ONLY */ + +#if defined (__cplusplus) +} +#endif diff --git a/stage1/zstd/lib/zstd_errors.h b/stage1/zstd/lib/zstd_errors.h new file mode 100644 index 000000000000..fa3686b77243 --- /dev/null +++ b/stage1/zstd/lib/zstd_errors.h @@ -0,0 +1,95 @@ +/* + * Copyright (c) Yann Collet, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under both the BSD-style license (found in the + * LICENSE file in the root directory of this source tree) and the GPLv2 (found + * in the COPYING file in the root directory of this source tree). + * You may select, at your option, one of the above-listed licenses. + */ + +#ifndef ZSTD_ERRORS_H_398273423 +#define ZSTD_ERRORS_H_398273423 + +#if defined (__cplusplus) +extern "C" { +#endif + +/*===== dependency =====*/ +#include /* size_t */ + + +/* ===== ZSTDERRORLIB_API : control library symbols visibility ===== */ +#ifndef ZSTDERRORLIB_VISIBILITY +# if defined(__GNUC__) && (__GNUC__ >= 4) +# define ZSTDERRORLIB_VISIBILITY __attribute__ ((visibility ("default"))) +# else +# define ZSTDERRORLIB_VISIBILITY +# endif +#endif +#if defined(ZSTD_DLL_EXPORT) && (ZSTD_DLL_EXPORT==1) +# define ZSTDERRORLIB_API __declspec(dllexport) ZSTDERRORLIB_VISIBILITY +#elif defined(ZSTD_DLL_IMPORT) && (ZSTD_DLL_IMPORT==1) +# define ZSTDERRORLIB_API __declspec(dllimport) ZSTDERRORLIB_VISIBILITY /* It isn't required but allows to generate better code, saving a function pointer load from the IAT and an indirect jump.*/ +#else +# define ZSTDERRORLIB_API ZSTDERRORLIB_VISIBILITY +#endif + +/*-********************************************* + * Error codes list + *-********************************************* + * Error codes _values_ are pinned down since v1.3.1 only. + * Therefore, don't rely on values if you may link to any version < v1.3.1. + * + * Only values < 100 are considered stable. + * + * note 1 : this API shall be used with static linking only. + * dynamic linking is not yet officially supported. + * note 2 : Prefer relying on the enum than on its value whenever possible + * This is the only supported way to use the error list < v1.3.1 + * note 3 : ZSTD_isError() is always correct, whatever the library version. + **********************************************/ +typedef enum { + ZSTD_error_no_error = 0, + ZSTD_error_GENERIC = 1, + ZSTD_error_prefix_unknown = 10, + ZSTD_error_version_unsupported = 12, + ZSTD_error_frameParameter_unsupported = 14, + ZSTD_error_frameParameter_windowTooLarge = 16, + ZSTD_error_corruption_detected = 20, + ZSTD_error_checksum_wrong = 22, + ZSTD_error_dictionary_corrupted = 30, + ZSTD_error_dictionary_wrong = 32, + ZSTD_error_dictionaryCreation_failed = 34, + ZSTD_error_parameter_unsupported = 40, + ZSTD_error_parameter_outOfBound = 42, + ZSTD_error_tableLog_tooLarge = 44, + ZSTD_error_maxSymbolValue_tooLarge = 46, + ZSTD_error_maxSymbolValue_tooSmall = 48, + ZSTD_error_stage_wrong = 60, + ZSTD_error_init_missing = 62, + ZSTD_error_memory_allocation = 64, + ZSTD_error_workSpace_tooSmall= 66, + ZSTD_error_dstSize_tooSmall = 70, + ZSTD_error_srcSize_wrong = 72, + ZSTD_error_dstBuffer_null = 74, + /* following error codes are __NOT STABLE__, they can be removed or changed in future versions */ + ZSTD_error_frameIndex_tooLarge = 100, + ZSTD_error_seekableIO = 102, + ZSTD_error_dstBuffer_wrong = 104, + ZSTD_error_srcBuffer_wrong = 105, + ZSTD_error_maxCode = 120 /* never EVER use this value directly, it can change in future versions! Use ZSTD_isError() instead */ +} ZSTD_ErrorCode; + +/*! ZSTD_getErrorCode() : + convert a `size_t` function result into a `ZSTD_ErrorCode` enum type, + which can be used to compare with enum list published above */ +ZSTDERRORLIB_API ZSTD_ErrorCode ZSTD_getErrorCode(size_t functionResult); +ZSTDERRORLIB_API const char* ZSTD_getErrorString(ZSTD_ErrorCode code); /**< Same as ZSTD_getErrorName, but using a `ZSTD_ErrorCode` enum argument */ + + +#if defined (__cplusplus) +} +#endif + +#endif /* ZSTD_ERRORS_H_398273423 */ diff --git a/test/link/wasm/archive/build.zig b/test/link/wasm/archive/build.zig index 5ac97c9cef5a..7efa88999ad8 100644 --- a/test/link/wasm/archive/build.zig +++ b/test/link/wasm/archive/build.zig @@ -13,7 +13,6 @@ pub fn build(b: *Builder) void { lib.setBuildMode(mode); lib.setTarget(.{ .cpu_arch = .wasm32, .os_tag = .freestanding }); lib.use_llvm = false; - lib.use_stage1 = false; lib.use_lld = false; lib.strip = false; diff --git a/test/link/wasm/bss/build.zig b/test/link/wasm/bss/build.zig index 0a8d652338c2..c9bc1aa1069a 100644 --- a/test/link/wasm/bss/build.zig +++ b/test/link/wasm/bss/build.zig @@ -11,7 +11,6 @@ pub fn build(b: *Builder) void { lib.setBuildMode(mode); lib.setTarget(.{ .cpu_arch = .wasm32, .os_tag = .freestanding }); lib.use_llvm = false; - lib.use_stage1 = false; lib.use_lld = false; lib.strip = false; // to make sure the bss segment is emitted, we must import memory diff --git a/test/link/wasm/producers/build.zig b/test/link/wasm/producers/build.zig index 0f29c6896836..7557b4fa4144 100644 --- a/test/link/wasm/producers/build.zig +++ b/test/link/wasm/producers/build.zig @@ -12,7 +12,6 @@ pub fn build(b: *Builder) void { lib.setBuildMode(mode); lib.setTarget(.{ .cpu_arch = .wasm32, .os_tag = .freestanding }); lib.use_llvm = false; - lib.use_stage1 = false; lib.use_lld = false; lib.strip = false; lib.install(); diff --git a/test/link/wasm/segments/build.zig b/test/link/wasm/segments/build.zig index 06ca55300fbb..1b2cdf87ab4f 100644 --- a/test/link/wasm/segments/build.zig +++ b/test/link/wasm/segments/build.zig @@ -11,7 +11,6 @@ pub fn build(b: *Builder) void { lib.setBuildMode(mode); lib.setTarget(.{ .cpu_arch = .wasm32, .os_tag = .freestanding }); lib.use_llvm = false; - lib.use_stage1 = false; lib.use_lld = false; lib.strip = false; lib.install(); diff --git a/test/link/wasm/stack_pointer/build.zig b/test/link/wasm/stack_pointer/build.zig index 1f50a60d1989..5b67c3caa3f4 100644 --- a/test/link/wasm/stack_pointer/build.zig +++ b/test/link/wasm/stack_pointer/build.zig @@ -11,7 +11,6 @@ pub fn build(b: *Builder) void { lib.setBuildMode(mode); lib.setTarget(.{ .cpu_arch = .wasm32, .os_tag = .freestanding }); lib.use_llvm = false; - lib.use_stage1 = false; lib.use_lld = false; lib.strip = false; lib.stack_size = std.wasm.page_size * 2; // set an explicit stack size diff --git a/test/link/wasm/type/build.zig b/test/link/wasm/type/build.zig index 2c926eced3e5..fbae6dc741da 100644 --- a/test/link/wasm/type/build.zig +++ b/test/link/wasm/type/build.zig @@ -11,7 +11,6 @@ pub fn build(b: *Builder) void { lib.setBuildMode(mode); lib.setTarget(.{ .cpu_arch = .wasm32, .os_tag = .freestanding }); lib.use_llvm = false; - lib.use_stage1 = false; lib.use_lld = false; lib.strip = false; lib.install(); diff --git a/test/tests.zig b/test/tests.zig index b738de86b0ad..0817a541d953 100644 --- a/test/tests.zig +++ b/test/tests.zig @@ -720,20 +720,18 @@ pub fn addPkgTests( these_tests.addIncludePath("test"); if (test_target.backend) |backend| switch (backend) { .stage1 => { - these_tests.use_stage1 = true; + @panic("stage1 testing requested"); }, .stage2_llvm => { - these_tests.use_stage1 = false; these_tests.use_llvm = true; }, .stage2_c => { - these_tests.use_stage1 = false; these_tests.use_llvm = false; }, else => { - these_tests.use_stage1 = false; these_tests.use_llvm = false; - // TODO: force self-hosted linkers to avoid LLD creeping in until the auto-select mechanism deems them worthy + // TODO: force self-hosted linkers to avoid LLD creeping in + // until the auto-select mechanism deems them worthy these_tests.use_lld = false; }, }; @@ -1355,8 +1353,6 @@ pub fn addCAbiTests(b: *build.Builder, skip_non_native: bool) *build.Step { triple_prefix, })); - test_step.use_stage1 = false; - step.dependOn(&test_step.step); } return step; diff --git a/test/translate_c.zig b/test/translate_c.zig index 690b584d920d..4ecb6835f5a9 100644 --- a/test/translate_c.zig +++ b/test/translate_c.zig @@ -549,27 +549,25 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\}; }); - if (builtin.zig_backend != .stage1) { - cases.add("function prototype translated as optional", - \\typedef void (*fnptr_ty)(void); - \\typedef __attribute__((cdecl)) void (*fnptr_attr_ty)(void); - \\struct foo { - \\ __attribute__((cdecl)) void (*foo)(void); - \\ void (*bar)(void); - \\ fnptr_ty baz; - \\ fnptr_attr_ty qux; - \\}; - , &[_][]const u8{ - \\pub const fnptr_ty = ?*const fn () callconv(.C) void; - \\pub const fnptr_attr_ty = ?*const fn () callconv(.C) void; - \\pub const struct_foo = extern struct { - \\ foo: ?*const fn () callconv(.C) void, - \\ bar: ?*const fn () callconv(.C) void, - \\ baz: fnptr_ty, - \\ qux: fnptr_attr_ty, - \\}; - }); - } + cases.add("function prototype translated as optional", + \\typedef void (*fnptr_ty)(void); + \\typedef __attribute__((cdecl)) void (*fnptr_attr_ty)(void); + \\struct foo { + \\ __attribute__((cdecl)) void (*foo)(void); + \\ void (*bar)(void); + \\ fnptr_ty baz; + \\ fnptr_attr_ty qux; + \\}; + , &[_][]const u8{ + \\pub const fnptr_ty = ?*const fn () callconv(.C) void; + \\pub const fnptr_attr_ty = ?*const fn () callconv(.C) void; + \\pub const struct_foo = extern struct { + \\ foo: ?*const fn () callconv(.C) void, + \\ bar: ?*const fn () callconv(.C) void, + \\ baz: fnptr_ty, + \\ qux: fnptr_attr_ty, + \\}; + }); cases.add("function prototype with parenthesis", \\void (f0) (void *L); @@ -897,22 +895,20 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\pub const baz = c_int; }); - if (builtin.zig_backend != .stage1) { - cases.add("casting pointers to ints and ints to pointers", - \\void foo(void); - \\void bar(void) { - \\ void *func_ptr = foo; - \\ void (*typed_func_ptr)(void) = (void (*)(void)) (unsigned long) func_ptr; - \\} - , &[_][]const u8{ - \\pub extern fn foo() void; - \\pub export fn bar() void { - \\ var func_ptr: ?*anyopaque = @ptrCast(?*anyopaque, &foo); - \\ var typed_func_ptr: ?*const fn () callconv(.C) void = @intToPtr(?*const fn () callconv(.C) void, @intCast(c_ulong, @ptrToInt(func_ptr))); - \\ _ = @TypeOf(typed_func_ptr); - \\} - }); - } + cases.add("casting pointers to ints and ints to pointers", + \\void foo(void); + \\void bar(void) { + \\ void *func_ptr = foo; + \\ void (*typed_func_ptr)(void) = (void (*)(void)) (unsigned long) func_ptr; + \\} + , &[_][]const u8{ + \\pub extern fn foo() void; + \\pub export fn bar() void { + \\ var func_ptr: ?*anyopaque = @ptrCast(?*anyopaque, &foo); + \\ var typed_func_ptr: ?*const fn () callconv(.C) void = @intToPtr(?*const fn () callconv(.C) void, @intCast(c_ulong, @ptrToInt(func_ptr))); + \\ _ = @TypeOf(typed_func_ptr); + \\} + }); cases.add("noreturn attribute", \\void foo(void) __attribute__((noreturn)); @@ -972,21 +968,19 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\} }); - if (builtin.zig_backend != .stage1) { - cases.add("typedef of function in struct field", - \\typedef void lws_callback_function(void); - \\struct Foo { - \\ void (*func)(void); - \\ lws_callback_function *callback_http; - \\}; - , &[_][]const u8{ - \\pub const lws_callback_function = fn () callconv(.C) void; - \\pub const struct_Foo = extern struct { - \\ func: ?*const fn () callconv(.C) void, - \\ callback_http: ?*const lws_callback_function, - \\}; - }); - } + cases.add("typedef of function in struct field", + \\typedef void lws_callback_function(void); + \\struct Foo { + \\ void (*func)(void); + \\ lws_callback_function *callback_http; + \\}; + , &[_][]const u8{ + \\pub const lws_callback_function = fn () callconv(.C) void; + \\pub const struct_Foo = extern struct { + \\ func: ?*const fn () callconv(.C) void, + \\ callback_http: ?*const lws_callback_function, + \\}; + }); cases.add("pointer to struct demoted to opaque due to bit fields", \\struct Foo { @@ -1057,19 +1051,17 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\pub const Foo = struct_Foo; }); - if (builtin.zig_backend != .stage1) { - cases.add("self referential struct with function pointer", - \\struct Foo { - \\ void (*derp)(struct Foo *foo); - \\}; - , &[_][]const u8{ - \\pub const struct_Foo = extern struct { - \\ derp: ?*const fn ([*c]struct_Foo) callconv(.C) void, - \\}; - , - \\pub const Foo = struct_Foo; - }); - } + cases.add("self referential struct with function pointer", + \\struct Foo { + \\ void (*derp)(struct Foo *foo); + \\}; + , &[_][]const u8{ + \\pub const struct_Foo = extern struct { + \\ derp: ?*const fn ([*c]struct_Foo) callconv(.C) void, + \\}; + , + \\pub const Foo = struct_Foo; + }); cases.add("struct prototype used in func", \\struct Foo; @@ -1335,13 +1327,11 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\pub extern fn func(array: [*c]c_int) void; }); - if (builtin.zig_backend != .stage1) { - cases.add("__cdecl doesn't mess up function pointers", - \\void foo(void (__cdecl *fn_ptr)(void)); - , &[_][]const u8{ - \\pub extern fn foo(fn_ptr: ?*const fn () callconv(.C) void) void; - }); - } + cases.add("__cdecl doesn't mess up function pointers", + \\void foo(void (__cdecl *fn_ptr)(void)); + , &[_][]const u8{ + \\pub extern fn foo(fn_ptr: ?*const fn () callconv(.C) void) void; + }); cases.add("void cast", \\void foo() { @@ -1764,15 +1754,13 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\pub extern var my_enum: enum_enum_ty; }); - if (builtin.zig_backend != .stage1) { - cases.add("Parameterless function pointers", - \\typedef void (*fn0)(); - \\typedef void (*fn1)(char); - , &[_][]const u8{ - \\pub const fn0 = ?*const fn (...) callconv(.C) void; - \\pub const fn1 = ?*const fn (u8) callconv(.C) void; - }); - } + cases.add("Parameterless function pointers", + \\typedef void (*fn0)(); + \\typedef void (*fn1)(char); + , &[_][]const u8{ + \\pub const fn0 = ?*const fn (...) callconv(.C) void; + \\pub const fn1 = ?*const fn (u8) callconv(.C) void; + }); cases.addWithTarget("Calling convention", .{ .cpu_arch = .x86, @@ -1972,64 +1960,60 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\pub const SDL_INIT_VIDEO = @as(c_ulonglong, 0x00000020); }); - if (builtin.zig_backend != .stage1) { - cases.add("generate inline func for #define global extern fn", - \\extern void (*fn_ptr)(void); - \\#define foo fn_ptr - \\ - \\extern char (*fn_ptr2)(int, float); - \\#define bar fn_ptr2 - , &[_][]const u8{ - \\pub extern var fn_ptr: ?*const fn () callconv(.C) void; - , - \\pub inline fn foo() void { - \\ return fn_ptr.?(); - \\} - , - \\pub extern var fn_ptr2: ?*const fn (c_int, f32) callconv(.C) u8; - , - \\pub inline fn bar(arg_1: c_int, arg_2: f32) u8 { - \\ return fn_ptr2.?(arg_1, arg_2); - \\} - }); - } + cases.add("generate inline func for #define global extern fn", + \\extern void (*fn_ptr)(void); + \\#define foo fn_ptr + \\ + \\extern char (*fn_ptr2)(int, float); + \\#define bar fn_ptr2 + , &[_][]const u8{ + \\pub extern var fn_ptr: ?*const fn () callconv(.C) void; + , + \\pub inline fn foo() void { + \\ return fn_ptr.?(); + \\} + , + \\pub extern var fn_ptr2: ?*const fn (c_int, f32) callconv(.C) u8; + , + \\pub inline fn bar(arg_1: c_int, arg_2: f32) u8 { + \\ return fn_ptr2.?(arg_1, arg_2); + \\} + }); - if (builtin.zig_backend != .stage1) { - cases.add("macros with field targets", - \\typedef unsigned int GLbitfield; - \\typedef void (*PFNGLCLEARPROC) (GLbitfield mask); - \\typedef void(*OpenGLProc)(void); - \\union OpenGLProcs { - \\ OpenGLProc ptr[1]; - \\ struct { - \\ PFNGLCLEARPROC Clear; - \\ } gl; - \\}; - \\extern union OpenGLProcs glProcs; - \\#define glClearUnion glProcs.gl.Clear - \\#define glClearPFN PFNGLCLEARPROC - , &[_][]const u8{ - \\pub const GLbitfield = c_uint; - \\pub const PFNGLCLEARPROC = ?*const fn (GLbitfield) callconv(.C) void; - \\pub const OpenGLProc = ?*const fn () callconv(.C) void; - \\const struct_unnamed_1 = extern struct { - \\ Clear: PFNGLCLEARPROC, - \\}; - \\pub const union_OpenGLProcs = extern union { - \\ ptr: [1]OpenGLProc, - \\ gl: struct_unnamed_1, - \\}; - \\pub extern var glProcs: union_OpenGLProcs; - , - \\pub const glClearPFN = PFNGLCLEARPROC; - , - \\pub inline fn glClearUnion(arg_2: GLbitfield) void { - \\ return glProcs.gl.Clear.?(arg_2); - \\} - , - \\pub const OpenGLProcs = union_OpenGLProcs; - }); - } + cases.add("macros with field targets", + \\typedef unsigned int GLbitfield; + \\typedef void (*PFNGLCLEARPROC) (GLbitfield mask); + \\typedef void(*OpenGLProc)(void); + \\union OpenGLProcs { + \\ OpenGLProc ptr[1]; + \\ struct { + \\ PFNGLCLEARPROC Clear; + \\ } gl; + \\}; + \\extern union OpenGLProcs glProcs; + \\#define glClearUnion glProcs.gl.Clear + \\#define glClearPFN PFNGLCLEARPROC + , &[_][]const u8{ + \\pub const GLbitfield = c_uint; + \\pub const PFNGLCLEARPROC = ?*const fn (GLbitfield) callconv(.C) void; + \\pub const OpenGLProc = ?*const fn () callconv(.C) void; + \\const struct_unnamed_1 = extern struct { + \\ Clear: PFNGLCLEARPROC, + \\}; + \\pub const union_OpenGLProcs = extern union { + \\ ptr: [1]OpenGLProc, + \\ gl: struct_unnamed_1, + \\}; + \\pub extern var glProcs: union_OpenGLProcs; + , + \\pub const glClearPFN = PFNGLCLEARPROC; + , + \\pub inline fn glClearUnion(arg_2: GLbitfield) void { + \\ return glProcs.gl.Clear.?(arg_2); + \\} + , + \\pub const OpenGLProcs = union_OpenGLProcs; + }); cases.add("macro pointer cast", \\#define NRF_GPIO_BASE 0 @@ -2936,37 +2920,35 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\} }); - if (builtin.zig_backend != .stage1) { - cases.add("deref function pointer", - \\void foo(void) {} - \\int baz(void) { return 0; } - \\void bar(void) { - \\ void(*f)(void) = foo; - \\ int(*b)(void) = baz; - \\ f(); - \\ (*(f))(); - \\ foo(); - \\ b(); - \\ (*(b))(); - \\ baz(); - \\} - , &[_][]const u8{ - \\pub export fn foo() void {} - \\pub export fn baz() c_int { - \\ return 0; - \\} - \\pub export fn bar() void { - \\ var f: ?*const fn () callconv(.C) void = &foo; - \\ var b: ?*const fn () callconv(.C) c_int = &baz; - \\ f.?(); - \\ f.?(); - \\ foo(); - \\ _ = b.?(); - \\ _ = b.?(); - \\ _ = baz(); - \\} - }); - } + cases.add("deref function pointer", + \\void foo(void) {} + \\int baz(void) { return 0; } + \\void bar(void) { + \\ void(*f)(void) = foo; + \\ int(*b)(void) = baz; + \\ f(); + \\ (*(f))(); + \\ foo(); + \\ b(); + \\ (*(b))(); + \\ baz(); + \\} + , &[_][]const u8{ + \\pub export fn foo() void {} + \\pub export fn baz() c_int { + \\ return 0; + \\} + \\pub export fn bar() void { + \\ var f: ?*const fn () callconv(.C) void = &foo; + \\ var b: ?*const fn () callconv(.C) c_int = &baz; + \\ f.?(); + \\ f.?(); + \\ foo(); + \\ _ = b.?(); + \\ _ = b.?(); + \\ _ = baz(); + \\} + }); cases.add("pre increment/decrement", \\void foo(void) { @@ -3241,77 +3223,73 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\} }); - if (builtin.zig_backend != .stage1) { - cases.add("implicit casts", - \\#include - \\ - \\void fn_int(int x); - \\void fn_f32(float x); - \\void fn_f64(double x); - \\void fn_char(char x); - \\void fn_bool(bool x); - \\void fn_ptr(void *x); - \\ - \\void call() { - \\ fn_int(3.0f); - \\ fn_int(3.0); - \\ fn_int('ABCD'); - \\ fn_f32(3); - \\ fn_f64(3); - \\ fn_char('3'); - \\ fn_char('\x1'); - \\ fn_char(0); - \\ fn_f32(3.0f); - \\ fn_f64(3.0); - \\ fn_bool(123); - \\ fn_bool(0); - \\ fn_bool(&fn_int); - \\ fn_int((int)&fn_int); - \\ fn_ptr((void *)42); - \\} - , &[_][]const u8{ - \\pub extern fn fn_int(x: c_int) void; - \\pub extern fn fn_f32(x: f32) void; - \\pub extern fn fn_f64(x: f64) void; - \\pub extern fn fn_char(x: u8) void; - \\pub extern fn fn_bool(x: bool) void; - \\pub extern fn fn_ptr(x: ?*anyopaque) void; - \\pub export fn call() void { - \\ fn_int(@floatToInt(c_int, 3.0)); - \\ fn_int(@floatToInt(c_int, 3.0)); - \\ fn_int(@as(c_int, 1094861636)); - \\ fn_f32(@intToFloat(f32, @as(c_int, 3))); - \\ fn_f64(@intToFloat(f64, @as(c_int, 3))); - \\ fn_char(@bitCast(u8, @truncate(i8, @as(c_int, '3')))); - \\ fn_char(@bitCast(u8, @truncate(i8, @as(c_int, '\x01')))); - \\ fn_char(@bitCast(u8, @truncate(i8, @as(c_int, 0)))); - \\ fn_f32(3.0); - \\ fn_f64(3.0); - \\ fn_bool(@as(c_int, 123) != 0); - \\ fn_bool(@as(c_int, 0) != 0); - \\ fn_bool(@ptrToInt(&fn_int) != 0); - \\ fn_int(@intCast(c_int, @ptrToInt(&fn_int))); - \\ fn_ptr(@intToPtr(?*anyopaque, @as(c_int, 42))); - \\} - }); - } - - if (builtin.zig_backend != .stage1) { - cases.add("function call", - \\static void bar(void) { } - \\void foo(int *(baz)(void)) { - \\ bar(); - \\ baz(); - \\} - , &[_][]const u8{ - \\pub fn bar() callconv(.C) void {} - \\pub export fn foo(arg_baz: ?*const fn () callconv(.C) [*c]c_int) void { - \\ var baz = arg_baz; - \\ bar(); - \\ _ = baz.?(); - \\} - }); - } + cases.add("implicit casts", + \\#include + \\ + \\void fn_int(int x); + \\void fn_f32(float x); + \\void fn_f64(double x); + \\void fn_char(char x); + \\void fn_bool(bool x); + \\void fn_ptr(void *x); + \\ + \\void call() { + \\ fn_int(3.0f); + \\ fn_int(3.0); + \\ fn_int('ABCD'); + \\ fn_f32(3); + \\ fn_f64(3); + \\ fn_char('3'); + \\ fn_char('\x1'); + \\ fn_char(0); + \\ fn_f32(3.0f); + \\ fn_f64(3.0); + \\ fn_bool(123); + \\ fn_bool(0); + \\ fn_bool(&fn_int); + \\ fn_int((int)&fn_int); + \\ fn_ptr((void *)42); + \\} + , &[_][]const u8{ + \\pub extern fn fn_int(x: c_int) void; + \\pub extern fn fn_f32(x: f32) void; + \\pub extern fn fn_f64(x: f64) void; + \\pub extern fn fn_char(x: u8) void; + \\pub extern fn fn_bool(x: bool) void; + \\pub extern fn fn_ptr(x: ?*anyopaque) void; + \\pub export fn call() void { + \\ fn_int(@floatToInt(c_int, 3.0)); + \\ fn_int(@floatToInt(c_int, 3.0)); + \\ fn_int(@as(c_int, 1094861636)); + \\ fn_f32(@intToFloat(f32, @as(c_int, 3))); + \\ fn_f64(@intToFloat(f64, @as(c_int, 3))); + \\ fn_char(@bitCast(u8, @truncate(i8, @as(c_int, '3')))); + \\ fn_char(@bitCast(u8, @truncate(i8, @as(c_int, '\x01')))); + \\ fn_char(@bitCast(u8, @truncate(i8, @as(c_int, 0)))); + \\ fn_f32(3.0); + \\ fn_f64(3.0); + \\ fn_bool(@as(c_int, 123) != 0); + \\ fn_bool(@as(c_int, 0) != 0); + \\ fn_bool(@ptrToInt(&fn_int) != 0); + \\ fn_int(@intCast(c_int, @ptrToInt(&fn_int))); + \\ fn_ptr(@intToPtr(?*anyopaque, @as(c_int, 42))); + \\} + }); + + cases.add("function call", + \\static void bar(void) { } + \\void foo(int *(baz)(void)) { + \\ bar(); + \\ baz(); + \\} + , &[_][]const u8{ + \\pub fn bar() callconv(.C) void {} + \\pub export fn foo(arg_baz: ?*const fn () callconv(.C) [*c]c_int) void { + \\ var baz = arg_baz; + \\ bar(); + \\ _ = baz.?(); + \\} + }); cases.add("macro defines string literal with octal", \\#define FOO "aoeu\023 derp"