diff --git a/CMakeLists.txt b/CMakeLists.txt index ebc045af..0c7e47c9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -408,6 +408,42 @@ if (DEFINED __RAPTOR_VERIFICARLOMCA_LIB_PATH) target_compile_definitions(verificarlo_int INTERFACE __RAPTOR_VERIFICARLOMCA_INT_MODE) endif() endif() + +if (DEFINED __RAPTOR_MCALITE_SOURCE_DIR) + if (NOT __RAPTOR_MCALITE_SOURCE_DIR MATCHES "MCAlite") + message(SEND_ERROR "__RAPTOR_MCALITE_SOURCE_DIR ${__RAPTOR_MCALITE_SOURCE_DIR} does not include the expected lib name") + elseif (NOT EXISTS "${__RAPTOR_MCALITE_SOURCE_DIR}") + message(SEND_ERROR "__RAPTOR_MCALITE_SOURCE_DIR ${__RAPTOR_MCALITE_SOURCE_DIR} does not exists") + elseif(NOT EXISTS "${__RAPTOR_MCALITE_SOURCE_DIR}/mca.h") + message(SEND_ERROR "MCAlite header file ${__RAPTOR_MCALITE_SOURCE_DIR}/mca.h does not exists") + elseif(NOT EXISTS "${__RAPTOR_MCALITE_SOURCE_DIR}/mca.c") + message(SEND_ERROR "MCAlite source file ${__RAPTOR_MCALITE_SOURCE_DIR}/mca.c does not exists") + else() + add_library(mcalite OBJECT "${__RAPTOR_MCALITE_SOURCE_DIR}/mca.h" "${__RAPTOR_MCALITE_SOURCE_DIR}/mca.c") + target_include_directories(mcalite PUBLIC ${__RAPTOR_MCALITE_SOURCE_DIR}) + target_compile_definitions(mcalite PUBLIC __RAPTOR_MCALITE_MODE) + endif() +elseif (DEFINED __RAPTOR_MCALITE_HEADER_PATH) + if (NOT __RAPTOR_MCALITE_HEADER_PATH MATCHES "mca.h") + message(SEND_ERROR "__RAPTOR_MCALITE_HEADER_PATH ${__RAPTOR_MCALITE_HEADER_PATH} does not include the expected header name") + elseif (NOT EXISTS "${__RAPTOR_MCALITE_HEADER_PATH}") + message(SEND_ERROR "__RAPTOR_MCALITE_HEADER_PATH ${__RAPTOR_MCALITE_HEADER_PATH} does not exists") + elseif (NOT DEFINED __RAPTOR_MCALITE_LIB_PATH) + message(SEND_ERROR "__RAPTOR_MCALITE_LIB_PATH not defined, this is required for tests") + elseif (NOT __RAPTOR_MCALITE_LIB_PATH MATCHES "libmcalite.so") + message(SEND_ERROR "__RAPTOR_MCALITE_LIB_PATH ${__RAPTOR_MCALITE_LIB_PATH} does not include the expected library name") + elseif (NOT EXISTS "${__RAPTOR_MCALITE_LIB_PATH}") + message(SEND_ERROR "__RAPTOR_MCALITE_LIB_PATH ${__RAPTOR_MCALITE_LIB_PATH} does not exists") + else() + get_filename_component(__RAPTOR_MCALITE_SOURCE_DIR "${__RAPTOR_MCALITE_HEADER_PATH}" DIRECTORY) + add_library(mcalite INTERFACE "${__RAPTOR_MCALITE_HEADER_PATH}") + target_include_directories(mcalite INTERFACE ${__RAPTOR_MCALITE_SOURCE_DIR}) + target_compile_definitions(mcalite INTERFACE __RAPTOR_MCALITE_MODE) + endif() +elseif (DEFINED __RAPTOR_MCALITE_LIB_PATH) + message(SEND_ERROR "__RAPTOR_MCALITE_LIB_PATH defined but __RAPTOR_MCALITE_HEADER_PATH not defined, the header is required to build the RAPTOR runtime") +endif() + add_subdirectory(runtime) add_subdirectory(test) add_subdirectory(wrappers) diff --git a/pass/CMakeLists.txt b/pass/CMakeLists.txt index 2f7c97c2..93e9a819 100644 --- a/pass/CMakeLists.txt +++ b/pass/CMakeLists.txt @@ -26,6 +26,9 @@ set(CMAKE_CXX_STANDARD_REQUIRED ON) if (DEFINED __RAPTOR_VERIFICARLOMCA_LIB_PATH) add_compile_definitions(__RAPTOR_HAS_VERIFICARLOMCA) endif() +if (DEFINED __RAPTOR_MCALITE_SOURCE_DIR) + add_compile_definitions(__RAPTOR_HAS_MCALITE) +endif() # on windows `PLUGIN_TOOL` doesn't link against LLVM.dll if ((WIN32 OR CYGWIN) AND LLVM_LINK_LLVM_DYLIB) diff --git a/pass/RaptorLogic.cpp b/pass/RaptorLogic.cpp index 0ee30050..9b47498f 100644 --- a/pass/RaptorLogic.cpp +++ b/pass/RaptorLogic.cpp @@ -439,7 +439,8 @@ class TruncateGenerator : public llvm::InstVisitor, } }; if (TC.isToFPRT()) { - if (Mode == TruncOpMode || Mode == TruncOpMCAVerificarloMode) { + if (Mode == TruncOpMode || Mode == TruncOpMCAVerificarloMode || + Mode == TruncOpMCAMCAliteMode) { if (TC.NeedTruncChange || TC.NeedNewScratch) AllocScratch(); if (!TC.NeedNewScratch) { @@ -471,6 +472,7 @@ class TruncateGenerator : public llvm::InstVisitor, case TruncOpMode: case TruncOpFullModuleMode: case TruncOpMCAVerificarloMode: + case TruncOpMCAMCAliteMode: EmitWarning( "UnhandledTrunc", I, "Operation not handled - it will be executed in the original way.", @@ -502,6 +504,7 @@ class TruncateGenerator : public llvm::InstVisitor, case TruncOpMode: case TruncOpFullModuleMode: case TruncOpMCAVerificarloMode: + case TruncOpMCAMCAliteMode: return floatValTruncate(B, v, TC); } llvm_unreachable("Unknown trunc mode"); @@ -514,6 +517,7 @@ class TruncateGenerator : public llvm::InstVisitor, case TruncOpMode: case TruncOpFullModuleMode: case TruncOpMCAVerificarloMode: + case TruncOpMCAMCAliteMode: return floatValExpand(B, v, TC); } llvm_unreachable("Unknown trunc mode"); @@ -576,6 +580,7 @@ class TruncateGenerator : public llvm::InstVisitor, case TruncOpMode: case TruncOpFullModuleMode: case TruncOpMCAVerificarloMode: + case TruncOpMCAMCAliteMode: return; } } @@ -620,6 +625,7 @@ class TruncateGenerator : public llvm::InstVisitor, case TruncOpMode: case TruncOpFullModuleMode: case TruncOpMCAVerificarloMode: + case TruncOpMCAMCAliteMode: return; } } @@ -643,6 +649,7 @@ class TruncateGenerator : public llvm::InstVisitor, case TruncOpMode: case TruncOpFullModuleMode: case TruncOpMCAVerificarloMode: + case TruncOpMCAMCAliteMode: return; } llvm_unreachable(""); @@ -680,6 +687,17 @@ class TruncateGenerator : public llvm::InstVisitor, return; } + if (Mode == TruncOpMCAMCAliteMode) { + // MCAlite only performs fadd, fsub, fmul and fdiv binary operations + switch (BO.getOpcode()) { + case BinaryOperator::FAdd: + case BinaryOperator::FSub: + case BinaryOperator::FMul: + case BinaryOperator::FDiv: + break; + default: return; break; + } + } auto newI = getNewFromOriginal(&BO); IRBuilder<> B(newI); auto newLHS = truncate(B, getNewFromOriginal(oldLHS)); @@ -719,6 +737,9 @@ class TruncateGenerator : public llvm::InstVisitor, bool handleIntrinsic(llvm::CallBase &CI, Intrinsic::ID ID) { if (isDbgInfoIntrinsic(ID)) return true; + + // MCAlite do not support intrinsics + if (Mode == TruncOpMCAMCAliteMode) { return true; } auto newI = cast(getNewFromOriginal(&CI)); IRBuilder<> B(newI); @@ -783,6 +804,7 @@ class TruncateGenerator : public llvm::InstVisitor, case TruncOpMode: case TruncOpFullModuleMode: case TruncOpMCAVerificarloMode: + case TruncOpMCAMCAliteMode: break; default: llvm_unreachable("Unknown trunc mode"); @@ -816,6 +838,7 @@ class TruncateGenerator : public llvm::InstVisitor, case TruncOpMode: case TruncOpFullModuleMode: case TruncOpMCAVerificarloMode: + case TruncOpMCAMCAliteMode: break; default: llvm_unreachable("Unknown trunc mode"); @@ -865,6 +888,7 @@ class TruncateGenerator : public llvm::InstVisitor, case TruncMemMode: case TruncOpMode: case TruncOpMCAVerificarloMode: + case TruncOpMCAMCAliteMode: EmitWarning("FPNoFollow", CI, "Will not follow FP through this indirect call.", CI); break; @@ -883,6 +907,7 @@ class TruncateGenerator : public llvm::InstVisitor, break; case TruncOpMode: case TruncOpMCAVerificarloMode: + case TruncOpMCAMCAliteMode: EmitWarning("FPNoFollow", CI, "Will not truncate flops in this function call as the " "definition is not available.", @@ -933,14 +958,15 @@ class TruncateGenerator : public llvm::InstVisitor, IRBuilder<> BuilderZ(newCall); if (Mode != TruncOpMode && Mode != TruncMemMode && - Mode != TruncOpMCAVerificarloMode) + Mode != TruncOpMCAVerificarloMode && Mode != TruncOpMCAMCAliteMode) return; RequestContext ctx(&CI, &BuilderZ); auto FTTs = getFunctionToTruncate(CI); auto NeedDirectCall = [&](auto FTT) { return scratch && (Mode == TruncOpMode || - Mode == TruncOpMCAVerificarloMode) && + Mode == TruncOpMCAVerificarloMode || + Mode == TruncOpMCAMCAliteMode) && isa(&CI) && !FTT.isCallbackFunc(); }; @@ -1010,6 +1036,7 @@ class TruncateGenerator : public llvm::InstVisitor, case TruncOpMode: case TruncOpFullModuleMode: case TruncOpMCAVerificarloMode: + case TruncOpMCAMCAliteMode: break; default: llvm_unreachable("Unknown trunc mode"); diff --git a/pass/RaptorLogic.h b/pass/RaptorLogic.h index c6c3a1cc..414ee3ea 100644 --- a/pass/RaptorLogic.h +++ b/pass/RaptorLogic.h @@ -87,6 +87,7 @@ namespace MCAType { enum MCAType { NoMCAType, VerificarloMCA, + MCAlite, NumMCAType }; static constexpr int shift = 4; @@ -98,6 +99,7 @@ enum TruncateMode { TruncOpFullModuleMode = 0b0110, TruncOpMCAVerificarloMode = TruncOpMode + (MCAType::VerificarloMCA << MCAType::shift), + TruncOpMCAMCAliteMode = TruncOpMode + (MCAType::MCAlite << MCAType::shift), }; [[maybe_unused]] static const char *truncateModeStr(TruncateMode mode) { switch (mode) { @@ -109,6 +111,8 @@ enum TruncateMode { return "op_full_module"; case TruncOpMCAVerificarloMode: return "op_mca_verificarlo"; + case TruncOpMCAMCAliteMode: + return "op_mca_mcalite"; } llvm_unreachable("Invalid truncation mode"); } @@ -124,6 +128,8 @@ namespace MCAType { switch (Mode) { case TruncOpMCAVerificarloMode: return {TruncOpMode, VerificarloMCA}; break; + case TruncOpMCAMCAliteMode: + return {TruncOpMode, MCAlite}; break; default: return {Mode, NoMCAType}; break; } @@ -133,6 +139,9 @@ namespace MCAType { switch(mcaType) { #ifdef __RAPTOR_HAS_VERIFICARLOMCA case VerificarloMCA: return VerificarloMCA; break; +#endif +#ifdef __RAPTOR_HAS_MCALITE + case MCAlite: return MCAlite; break; #endif default: return NoMCAType; break; } @@ -142,6 +151,7 @@ namespace MCAType { switch(mcaType) { case NoMCAType: return ""; break; case VerificarloMCA: return "verificarlo"; break; + case MCAlite: return "mcalite"; break; default: return "invalid"; break; } } @@ -156,6 +166,7 @@ namespace MCAType { assert(!isMCA(Mode)); switch (Mode + (mcaType << shift)) { case TruncOpMCAVerificarloMode: + case TruncOpMCAMCAliteMode: return true; break; default: return false; break; diff --git a/runtime/CMakeLists.txt b/runtime/CMakeLists.txt index 12601533..9566dc3d 100644 --- a/runtime/CMakeLists.txt +++ b/runtime/CMakeLists.txt @@ -53,6 +53,10 @@ if (DEFINED __RAPTOR_VERIFICARLOMCA_INT_LIB_PATH) target_link_libraries(Raptor-RT-${LLVM_VERSION_MAJOR} PRIVATE verificarlo_int) endif() +if (DEFINED __RAPTOR_MCALITE_SOURCE_DIR) + target_link_libraries(Raptor-RT-${LLVM_VERSION_MAJOR} PRIVATE mcalite) +endif() + install( DIRECTORY ${RAPTOR_PUBLIC_INCLUDE_DIR} DESTINATION include diff --git a/runtime/include/private/raptor/Common.h b/runtime/include/private/raptor/Common.h index a7df3395..ac2a3bba 100644 --- a/runtime/include/private/raptor/Common.h +++ b/runtime/include/private/raptor/Common.h @@ -36,6 +36,17 @@ typedef struct __raptor_fp { // #endif } __raptor_fp; +// Should match definition in pass/RaptorLogic.h +namespace MCAType { + enum MCAType { + NoMCAType, + VerificarloMCA, + MCAlite, + NumMCAType + }; + static constexpr int shift = 4; +}; + static inline bool __raptor_fprt_is_mem_mode(int64_t mode) { return mode & 0b0001; } @@ -48,6 +59,11 @@ static inline bool __raptor_fprt_is_full_module_op_mode(int64_t mode) { static inline bool __raptor_fprt_is_mca_mode(int64_t mode) { return mode & 0b011110000; } +static inline bool __raptor_fprt_mca_type_is(int64_t mode, + MCAType::MCAType mcaType) +{ + return (mode & 0b011110000) == (mcaType << MCAType::shift); +} __RAPTOR_MPFR_DECL_ATTRIBUTES void raptor_fprt_gc_dump_status(); diff --git a/runtime/ir/Mpfr.cpp b/runtime/ir/Mpfr.cpp index 30ba26a9..645c58bc 100644 --- a/runtime/ir/Mpfr.cpp +++ b/runtime/ir/Mpfr.cpp @@ -87,15 +87,73 @@ #define __RAPTOR_USE_MCA true #define __RAPTOR_MCA_CONCAT(prefix, FROM_TY) __raptor_mca_##prefix##FROM_TY + #define __RAPTOR_MCA_STRINGIFY(x) #x #define __RAPTOR_MCA_INEXACT(FROM_TY, a, loc, rnd_mode, isOutbound) \ __RAPTOR_MCA_CONCAT(inexact_, FROM_TY)(a, \ __RAPTOR_MCA_CONCAT(get_virtural_prec_, FROM_TY)(a, loc), rnd_mode, \ isOutbound); + + #ifdef __RAPTOR_MCALITE_MODE + #define __RAPTOR_MCA_BYPASS_MPFR true + #include + #define __RAPTOR_MCA_OP_FUNC_DECL(RET_TYPE, OP_NAME, FROM_TYPE, ...) \ + __RAPTOR_MPFR_ATTRIBUTES \ + RET_TYPE __RAPTOR_MCA_CONCAT(OP_NAME##_, FROM_TYPE)(__VA_ARGS__); + #define __RAPTOR_MCA_OP_FUNC_IF(OP_TYPE, OP_TYPE_REF, LLVM_OP_NAME, \ + LLVM_OP_NAME_REF, FUNC_NAME, FROM_TYPE,...)\ + if constexpr((__RAPTOR_MCA_STRINGIFY(OP_TYPE) == OP_TYPE_REF && \ + __RAPTOR_MCA_STRINGIFY(LLVM_OP_NAME) == LLVM_OP_NAME_REF) \ + ) { return __RAPTOR_MCA_CONCAT(FUNC_NAME##_, FROM_TYPE)(__VA_ARGS__); } + #define __RAPTOR_MCA_BYPASS_MPFR_UNARY(FROM_TYPE, OP_TYPE, LLVM_OP_NAME, \ + LLVM_TYPE, ...) \ + do { \ + using namespace std::literals::string_view_literals; \ + __RAPTOR_MCA_OP_FUNC_IF(OP_TYPE, "unaryop"sv, LLVM_OP_NAME, "fneg"sv, \ + neg, FROM_TYPE, __VA_ARGS__); \ + } while (0) + #define __RAPTOR_MCA_BYPASS_MPFR_BINARY(FROM_TYPE, OP_TYPE, LLVM_OP_NAME, \ + LLVM_TYPE, ...) \ + do { \ + using namespace std::literals::string_view_literals; \ + __RAPTOR_MCA_OP_FUNC_IF(OP_TYPE, "binop"sv, LLVM_OP_NAME, "fadd"sv, \ + add, FROM_TYPE, __VA_ARGS__); \ + __RAPTOR_MCA_OP_FUNC_IF(OP_TYPE, "binop"sv, LLVM_OP_NAME, "fsub"sv, \ + sub, FROM_TYPE, __VA_ARGS__); \ + __RAPTOR_MCA_OP_FUNC_IF(OP_TYPE, "binop"sv, LLVM_OP_NAME, "fmul"sv, \ + mul, FROM_TYPE, __VA_ARGS__); \ + __RAPTOR_MCA_OP_FUNC_IF(OP_TYPE, "binop"sv, LLVM_OP_NAME, "fdiv"sv, \ + div, FROM_TYPE, __VA_ARGS__); \ + } while (0) + #define __RAPTOR_MCA_BYPASS_MPFR_ERR(prefix, OP_TYPE, LLVM_OP_NAME) \ + fprintf(stderr, "%s %s %s\n", #prefix, #OP_TYPE, #LLVM_OP_NAME); abort(); + + #define RAPTOR_FLOAT_TYPE(CPP_TY, FROM_TY) \ + __RAPTOR_MCA_OP_FUNC_DECL(CPP_TY, neg, FROM_TY, CPP_TY x, \ + const char * loc) \ + __RAPTOR_MCA_OP_FUNC_DECL(CPP_TY, add, FROM_TY, CPP_TY x, CPP_TY y, \ + const char * loc) \ + __RAPTOR_MCA_OP_FUNC_DECL(CPP_TY, sub, FROM_TY, CPP_TY x, CPP_TY y, \ + const char * loc) \ + __RAPTOR_MCA_OP_FUNC_DECL(CPP_TY, mul, FROM_TY, CPP_TY x, CPP_TY y, \ + const char * loc) \ + __RAPTOR_MCA_OP_FUNC_DECL(CPP_TY, div, FROM_TY, CPP_TY x, CPP_TY y, \ + const char * loc) + #include "raptor/FloatTypes.def" + #endif #else #define __RAPTOR_USE_MCA false #define __RAPTOR_MCA_INEXACT(FROM_TY, a, loc, rnd_mode, isOutbound) #endif +#ifndef __RAPTOR_MCA_BYPASS_MPFR + #define __RAPTOR_MCA_BYPASS_MPFR false + #define __RAPTOR_MCA_BYPASS_MPFR_UNARY(FROM_TYPE, OP_TYPE, LLVM_OP_NAME, \ + LLVM_TYPE, ...) + #define __RAPTOR_MCA_BYPASS_MPFR_BINARY(FROM_TYPE, OP_TYPE, LLVM_OP_NAME, \ + LLVM_TYPE, ...) + #define __RAPTOR_MCA_BYPASS_MPFR_ERR(prefix, OP_TYPE, LLVM_OP_NAME) +#endif + __RAPTOR_MPFR_ATTRIBUTES void __raptor_fprt_trunc_change(int64_t is_push, int64_t to_e, int64_t to_m, int64_t mode, const char *loc, void *scratch) { @@ -559,6 +617,12 @@ void raptor_fprt_op_clear(); ARG1 a, int64_t exponent, int64_t significand, int64_t mode, \ const char *loc, mpfr_t *scratch) { \ if (__raptor_fprt_is_op_mode(mode)) { \ + if constexpr(__RAPTOR_MCA_BYPASS_MPFR) { \ + if (__raptor_fprt_mca_type_is(mode, MCAType::MCAlite)) { \ + __RAPTOR_MCA_BYPASS_MPFR_ERR("Unsupported MCAlite op", OP_TYPE, \ + LLVM_OP_NAME); \ + } \ + } \ mpfr_set_##MPFR_SET_ARG1(scratch[0], a, ROUNDING_MODE); \ RET c = mpfr_get_si(scratch[0], ROUNDING_MODE); \ return c; \ @@ -575,6 +639,14 @@ void raptor_fprt_op_clear(); ARG1 a, int64_t exponent, int64_t significand, int64_t mode, \ const char *loc, mpfr_t *scratch) { \ if (__raptor_fprt_is_op_mode(mode)) { \ + if constexpr(__RAPTOR_MCA_BYPASS_MPFR) { \ + if (__raptor_fprt_mca_type_is(mode, MCAType::MCAlite)) { \ + __RAPTOR_MCA_BYPASS_MPFR_UNARY(FROM_TYPE, OP_TYPE, LLVM_OP_NAME,, a, \ + loc); \ + __RAPTOR_MCA_BYPASS_MPFR_ERR("Unsupported MCAlite op", OP_TYPE, \ + LLVM_OP_NAME); \ + } \ + } \ __raptor_fprt_trunc_count(exponent, significand, mode, loc, scratch); \ mpfr_set_##MPFR_SET_ARG1(scratch[0], a, ROUNDING_MODE); \ if constexpr (__RAPTOR_USE_MCA) { \ @@ -617,6 +689,12 @@ void raptor_fprt_op_clear(); ARG1 a, ARG2 b, int64_t exponent, int64_t significand, int64_t mode, \ const char *loc, mpfr_t *scratch) { \ if (__raptor_fprt_is_op_mode(mode)) { \ + if constexpr(__RAPTOR_MCA_BYPASS_MPFR) { \ + if (__raptor_fprt_mca_type_is(mode, MCAType::MCAlite)) { \ + __RAPTOR_MCA_BYPASS_MPFR_ERR("Unsupported MCAlite op", OP_TYPE, \ + LLVM_OP_NAME); \ + } \ + } \ __raptor_fprt_trunc_count(exponent, significand, mode, loc, scratch); \ mpfr_set_##MPFR_SET_ARG1(scratch[0], a, ROUNDING_MODE); \ if constexpr (__RAPTOR_USE_MCA) { \ @@ -657,6 +735,14 @@ void raptor_fprt_op_clear(); ARG1 a, ARG2 b, int64_t exponent, int64_t significand, int64_t mode, \ const char *loc, mpfr_t *scratch) { \ if (__raptor_fprt_is_op_mode(mode)) { \ + if constexpr(__RAPTOR_MCA_BYPASS_MPFR) { \ + if (__raptor_fprt_mca_type_is(mode, MCAType::MCAlite)) { \ + __RAPTOR_MCA_BYPASS_MPFR_BINARY(FROM_TYPE, OP_TYPE, LLVM_OP_NAME,, a,\ + b, loc); \ + __RAPTOR_MCA_BYPASS_MPFR_ERR("Unsupported MCAlite op", OP_TYPE, \ + LLVM_OP_NAME); \ + } \ + } \ __raptor_fprt_trunc_count(exponent, significand, mode, loc, scratch); \ mpfr_set_##MPFR_SET_ARG1(scratch[0], a, ROUNDING_MODE); \ mpfr_set_##MPFR_SET_ARG2(scratch[1], b, ROUNDING_MODE); \ @@ -704,6 +790,12 @@ void raptor_fprt_op_clear(); TYPE a, TYPE b, TYPE c, int64_t exponent, int64_t significand, \ int64_t mode, const char *loc, mpfr_t *scratch) { \ if (__raptor_fprt_is_op_mode(mode)) { \ + if constexpr(__RAPTOR_MCA_BYPASS_MPFR) { \ + if (__raptor_fprt_mca_type_is(mode, MCAType::MCAlite)) { \ + __RAPTOR_MCA_BYPASS_MPFR_ERR("Unsupported MCAlite op", OP_TYPE, \ + LLVM_OP_NAME); \ + } \ + } \ __raptor_fprt_trunc_count(exponent, significand, mode, loc, scratch); \ mpfr_set_##MPFR_TYPE(scratch[0], a, ROUNDING_MODE); \ mpfr_set_##MPFR_TYPE(scratch[1], b, ROUNDING_MODE); \ @@ -761,6 +853,12 @@ void raptor_fprt_op_clear(); TYPE a, TYPE b, int64_t exponent, int64_t significand, int64_t mode, \ const char *loc, mpfr_t *scratch) { \ if (__raptor_fprt_is_op_mode(mode)) { \ + if constexpr(__RAPTOR_MCA_BYPASS_MPFR) { \ + if (__raptor_fprt_mca_type_is(mode, MCAType::MCAlite)) { \ + __RAPTOR_MCA_BYPASS_MPFR_ERR("Unsupported MCAlite op", OP_TYPE, \ + LLVM_OP_NAME); \ + } \ + } \ __raptor_fprt_trunc_count(exponent, significand, mode, loc, scratch); \ mpfr_set_##MPFR_GET(scratch[0], a, ROUNDING_MODE); \ mpfr_set_##MPFR_GET(scratch[1], b, ROUNDING_MODE); \ diff --git a/runtime/obj/MonteCarloArithmetic.cpp b/runtime/obj/MonteCarloArithmetic.cpp index 83072f4f..51febf11 100644 --- a/runtime/obj/MonteCarloArithmetic.cpp +++ b/runtime/obj/MonteCarloArithmetic.cpp @@ -477,12 +477,200 @@ #endif // defined(__RAPTOR_VERIFICARLOMCA_QUAD_MODE) || // defined(__RAPTOR_VERIFICARLOMCA_INT_MODE) +#ifdef __RAPTOR_MCALITE_MODE + #define __RAPTOR_USE_MCALITE true + #include + #include + #include + #include + #include + namespace { + enum mcalite_mode { // Comment copied from mca.h + RR, /* Random Rounding (RR): round(inexact(x op y)). */ + PB, /* Precision Bounding (PB): round(inexact(x) op inexact(y)). */ + FULL /* Full MCA: round(inexact(inexact(x) op inexact(y))). */ + }; + std::atomic rng_stream; + struct mcalite_accumulate_stats { + double mu = 0; + double variance = 0; + double sigma = 0; + double s = 0; + void accumulate_stats(double in_mu, double in_sigma) { + mu += in_mu; + variance += (in_sigma * in_sigma); + } + void calculate() { + sigma = std::sqrt(variance); + if (variance == 0.0) { + s = INFINITY; + } else if (mu == 0.0) { + s = -INFINITY; + } else { + s = -std::log2(sigma / std::fabs(mu)); + } + } + std::string str() { + std::stringstream ss; + ss << "mu = " << mu << ", sigma = " << sigma << ", s = " << s; + return ss.str(); + } + }; + struct mcalite_context_t { + uint64_t rng_seed = 42; + int t = 24; // virtual precision + size_t ntrials = 5; // Number of repetition per operation + mcalite_mode mode = mcalite_mode::PB; + bool quiet = false; + std::vector results; + mca_stats stats; + std::map acc_stats; + mca_rng rng; + void print_stats(mca_stats * in) { + std::cout << "mu = " << in->mu << ", sigma = " << in->sigma; + std::cout << ", s = " << in->s << std::endl; + } + int calc_stats(const char *loc) { + int err = mca_compute_stats(results.data(), ntrials, &stats); + if (!quiet) { + std::cout << "MCAlite stats at " << loc << ": "; + print_stats(&stats); + } + acc_stats[loc].accumulate_stats(stats.mu, stats.sigma); + return err; + } + void parse_env() { + // Get the seed, t, ntrials and mode from env var. + char *env_val = getenv("MCA_SEED"); + if (env_val != nullptr) { + std::string env_str(env_val); + rng_seed = std::stoul(env_str); + } + env_val = getenv("MCA_T"); + if (env_val != nullptr) { + std::string env_str(env_val); + t = std::stoi(env_str); + } + env_val = getenv("MCA_NTRIALS"); + if (env_val != nullptr) { + std::string env_str(env_val); + ntrials = std::stoul(env_str); + } + env_val = getenv("MCA_MODE"); + if (env_val != nullptr) { + std::string env_str(env_val); + if (env_str == "RR") { mode = mcalite_mode::RR; } + else if (env_str == "PB") { mode = mcalite_mode::PB; } + else if (env_str == "FULL") { mode = mcalite_mode::FULL; } + else { + std::cerr << "Error: invalid MCA_MODE value " << env_str; + std::cerr << ", valid MCA_MODE options are RR, PB and FULL."; + std::cerr << std::endl; + abort(); + } + } + env_val = getenv("MCA_QUIET"); + if (env_val != nullptr) { + quiet = true; + } + } + std::string mode_str() { + std::string str = "FULL"; + switch(mode) { + case mcalite_mode::RR: str = "RR"; break; + case mcalite_mode::PB: str = "PB"; break; + default: break; // mcalite_mode::FULL + } + return str; + } + void print() { + std::cout << "rng_seed = " << rng_seed << ", t = " << t << ", "; + std::cout << "ntrials = " << ntrials << ", mode = " << mode_str(); + } + mcalite_context_t() { + parse_env(); + results.resize(ntrials); + auto stream_id = rng_stream++; + mca_rng_seed(&rng, rng_seed, stream_id); + if (!quiet) { + print(); std::cout << ", rng_stream " << stream_id << std::endl; + } + } + ~mcalite_context_t() { + for (auto acc_stat : acc_stats) { + acc_stat.second.calculate(); + std::cout << "MCAlite accumulated stats at " << acc_stat.first; + std::cout << ": " << acc_stat.second.str() << std::endl; + } + } + }; + thread_local mcalite_context_t mcalite_context; + } + #define __RAPTOR_MCALITE_OP_FUNC_SIGNATURE(CPP_TY, OP, FROM_TY, ...) \ + CPP_TY __raptor_mca_##OP##_##FROM_TY(__VA_ARGS__) + #define __RAPTOR_MCALITE_CALL(OP, MODE, ...) \ + mca_##OP##_##MODE(__VA_ARGS__, mcalite_context.t, mcalite_context.ntrials, \ + &(mcalite_context.rng), mcalite_context.results.data()) + #define __RAPTOR_MCALITE_OP_FUNC_BODY(OP, ...) \ + { \ + int err = 0; \ + switch (mcalite_context.mode) { \ + case mcalite_mode::RR: \ + err = __RAPTOR_MCALITE_CALL(OP, rr, __VA_ARGS__); \ + break; \ + case mcalite_mode::PB: \ + err = __RAPTOR_MCALITE_CALL(OP, pb, __VA_ARGS__); \ + break; \ + case mcalite_mode::FULL: \ + err = __RAPTOR_MCALITE_CALL(OP, full, __VA_ARGS__); \ + break; \ + default: err = -1; break; \ + } \ + if (err == 0 && mcalite_context.ntrials > 1) { \ + err = mcalite_context.calc_stats(loc); \ + } \ + if (err != 0) { \ + std::cerr << "Error in mode " << mcalite_context.mode; \ + std::cerr << " with op " << #OP << " at " << loc << std::endl; \ + abort(); \ + } \ + return mcalite_context.results[0]; \ + } + #define __RAPTOR_MCALITE_BINARY_OP(OP, FROM_TY, CPP_TY) \ + __RAPTOR_MPFR_ATTRIBUTES \ + __RAPTOR_MCALITE_OP_FUNC_SIGNATURE(CPP_TY, OP, FROM_TY, CPP_TY x, CPP_TY y,\ + const char * loc) \ + __RAPTOR_MCALITE_OP_FUNC_BODY(OP, x, y) + #define __RAPTOR_MCALITE_UNARY_OP(OP, FROM_TY, CPP_TY) \ + __RAPTOR_MPFR_ATTRIBUTES \ + __RAPTOR_MCALITE_OP_FUNC_SIGNATURE(CPP_TY, OP, FROM_TY, CPP_TY x, \ + const char * loc) \ + __RAPTOR_MCALITE_OP_FUNC_BODY(OP, x) + + #define RAPTOR_FLOAT_TYPE(CPP_TY, FROM_TY) \ + __RAPTOR_MCALITE_BINARY_OP(add, FROM_TY, CPP_TY) \ + __RAPTOR_MCALITE_BINARY_OP(sub, FROM_TY, CPP_TY) \ + __RAPTOR_MCALITE_BINARY_OP(mul, FROM_TY, CPP_TY) \ + __RAPTOR_MCALITE_BINARY_OP(div, FROM_TY, CPP_TY) \ + __RAPTOR_MCALITE_UNARY_OP(neg, FROM_TY, CPP_TY) + #include "raptor/FloatTypes.def" + + #define __RAPTOR_MCALITE_get_virtual_prec \ + do { return mcalite_context.t; } while(0) + +#else + #define __RAPTOR_USE_MCALITE false + #define __RAPTOR_MCALITE_get_virtual_prec +#endif // __RAPTOR_USE_MCALITE + #define RAPTOR_FLOAT_TYPE(CPP_TY, FROM_TY) \ __RAPTOR_MPFR_ATTRIBUTES \ unsigned int __raptor_mca_get_virtural_prec_##FROM_TY(mpfr_t a, \ const char *loc) { \ if constexpr (__RAPTOR_USE_VERIFICARLOMCA) { \ __RAPTOR_VERIFICARLOMCA_get_virtual_prec(CPP_TY); \ + } else if constexpr (__RAPTOR_USE_MCALITE) { \ + __RAPTOR_MCALITE_get_virtual_prec; \ } else { \ std::cerr << "__raptor_mca_get_virtural_prec_" << #FROM_TY; \ std::cerr << " is not implemented." << std::endl; \ diff --git a/test/lit.site.cfg.py.in b/test/lit.site.cfg.py.in index 75e4c5d5..abb6f3ba 100644 --- a/test/lit.site.cfg.py.in +++ b/test/lit.site.cfg.py.in @@ -118,6 +118,17 @@ if verificarlomca_lib_path != "": link = "-L@RAPTOR_BINARY_DIR@/runtime/ -lstdc++ -lmpfr -lRaptor-RT-" + config.llvm_ver + verificarlomca_link_options + +mcalite_lib_path = "@__RAPTOR_MCALITE_LIB_PATH@" +if mcalite_lib_path != "": + mcalite_lib_dir = "/".join(mcalite_lib_path.split("/")[:-1]) + mcalite_lib_name = mcalite_lib_path.split("/")[-1].split(".")[0][3:] + link = link + " -L" + mcalite_lib_dir + " -l" + mcalite_lib_name + " -Wl,-rpath=" + mcalite_lib_dir + +mcalite_src_dir = "@__RAPTOR_MCALITE_SOURCE_DIR@" +if mcalite_src_dir != "": + link = link + " -lm" + config.substitutions.append(('%linkRaptorRT', link)) link = "-L@RAPTOR_BINARY_DIR@/runtime/ -lstdc++ -lmpfr -lRaptor-RT-" + config.llvm_ver