diff --git a/.github/workflows/root-ci.yml b/.github/workflows/root-ci.yml index e7149cfe9c9f8..dcbc630df6520 100644 --- a/.github/workflows/root-ci.yml +++ b/.github/workflows/root-ci.yml @@ -402,7 +402,7 @@ jobs: - image: alma9 is_special: true property: march_native - overrides: ["CMAKE_BUILD_TYPE=RelWithDebInfo", "CMAKE_CXX_FLAGS=-march=native", "CMAKE_C_FLAGS=-march=native", "builtin_zlib=ON", "builtin_zstd=ON", "CMAKE_CXX_STANDARD=20"] + overrides: ["CMAKE_BUILD_TYPE=RelWithDebInfo", "CMAKE_CXX_FLAGS=-march=native", "CMAKE_C_FLAGS=-march=native", "builtin_zlib=ON", "builtin_zstd=ON", "CMAKE_CXX_STANDARD=20", "builtin_vc=ON", "builtin_veccore=ON", "vc=ON", "veccore=ON"] - image: alma10 is_special: true property: arm64 diff --git a/hist/hist/src/TFormula.cxx b/hist/hist/src/TFormula.cxx index 8244759b007e2..11cfbb2746e2a 100644 --- a/hist/hist/src/TFormula.cxx +++ b/hist/hist/src/TFormula.cxx @@ -49,6 +49,22 @@ std::string doubleToString(double val) return ss.str(); } +// In the interpreter, we must match the SIMD width used by compiled ROOT. +// ROOT::Double_v aliases the best available native SIMD type, which may differ +// between compiled and interpreted contexts (e.g. with -march=native). +// Therefore, we explicitly select the fixed-size SIMD type corresponding to +// the native SIMD width used in compiled ROOT. +std::string vectorizedArgType() +{ +#ifdef VECCORE_ENABLE_VC + auto n = ROOT::Double_v::size(); + return "Vc::fixed_size_simd"; +#else + // For other possible VecCore backends, we assume using the same type is fine. + return "ROOT::Double_v"; +#endif +} + } // namespace /** \class TFormula TFormula.h "inc/TFormula.h" @@ -815,7 +831,7 @@ prepareMethod(bool HasParameters, bool HasVariables, const char* FuncName, TString prototypeArguments = ""; if (HasVariables || HasParameters) { if (IsVectorized) - prototypeArguments.Append("ROOT::Double_v const*"); + prototypeArguments.Append(vectorizedArgType() + " const*"); else prototypeArguments.Append("Double_t const*"); } @@ -2387,7 +2403,7 @@ void TFormula::ProcessFormula(TString &formula) if (fVectorized) inputFormulaVecFlag += " (vectorized)"; - TString argType = fVectorized ? "ROOT::Double_v" : "Double_t"; + TString argType = fVectorized ? vectorizedArgType() : "Double_t"; // valid input formula - try to put into Cling (in case of no variables but only parameter we need to add the standard signature) TString argumentsPrototype = TString::Format("%s%s%s", ( (hasVariables || hasParameters) ? (argType + " const *x").Data() : ""), diff --git a/math/experimental/genvectorx/inc/MathX/GenVectorX/DisplacementVector3D.h b/math/experimental/genvectorx/inc/MathX/GenVectorX/DisplacementVector3D.h index 12cf0afb1e8e9..3ac9b709571ff 100644 --- a/math/experimental/genvectorx/inc/MathX/GenVectorX/DisplacementVector3D.h +++ b/math/experimental/genvectorx/inc/MathX/GenVectorX/DisplacementVector3D.h @@ -344,7 +344,7 @@ class DisplacementVector3D { DisplacementVector3D Unit() const { SCALAR tot = R(); - tot(tot == SCALAR(0)) = SCALAR(1); + where(tot == SCALAR(0), tot) = SCALAR(1); return DisplacementVector3D(*this) / tot; } @@ -681,7 +681,7 @@ operator<<(std::basic_ostream &os, DisplacementVector3D { if (os) { os << "{ "; - for (std::size_t i = 0; i < PositionVector3D::Scalar::Size; ++i) { + for (std::size_t i = 0; i < PositionVector3D::Scalar::size(); ++i) { os << "(" << v.x()[i] << "," << v.y()[i] << "," << v.z()[i] << ") "; } os << "}"; diff --git a/math/experimental/genvectorx/inc/MathX/GenVectorX/Plane3D.h b/math/experimental/genvectorx/inc/MathX/GenVectorX/Plane3D.h index 64b8f671b5608..199841746b3b3 100644 --- a/math/experimental/genvectorx/inc/MathX/GenVectorX/Plane3D.h +++ b/math/experimental/genvectorx/inc/MathX/GenVectorX/Plane3D.h @@ -242,8 +242,8 @@ class Plane3D { // what to do if s = 0 ? const auto m = (s == SCALAR(0)); // set zero entries to 1 in the vector to avoid /0 later on - s(m) = SCALAR(1); - fD(m) = SCALAR(0); + where(m, s) = SCALAR(1); + where(m, fD) = SCALAR(0); const SCALAR w = SCALAR(1) / s; fA *= w; fB *= w; diff --git a/math/experimental/genvectorx/inc/MathX/GenVectorX/PositionVector3D.h b/math/experimental/genvectorx/inc/MathX/GenVectorX/PositionVector3D.h index 4649b669be158..23a8e3e93bb5d 100644 --- a/math/experimental/genvectorx/inc/MathX/GenVectorX/PositionVector3D.h +++ b/math/experimental/genvectorx/inc/MathX/GenVectorX/PositionVector3D.h @@ -646,7 +646,7 @@ operator<<(std::basic_ostream &os, PositionVector3D cons { if (os) { os << "{ "; - for (std::size_t i = 0; i < PositionVector3D::Scalar::Size; ++i) { + for (std::size_t i = 0; i < PositionVector3D::Scalar::size(); ++i) { os << "(" << v.x()[i] << "," << v.y()[i] << "," << v.z()[i] << ") "; } os << "}"; diff --git a/math/experimental/genvectorx/inc/MathX/GenVectorX/Transform3D.h b/math/experimental/genvectorx/inc/MathX/GenVectorX/Transform3D.h index cbb3c281902fa..29cd5962b8fa0 100644 --- a/math/experimental/genvectorx/inc/MathX/GenVectorX/Transform3D.h +++ b/math/experimental/genvectorx/inc/MathX/GenVectorX/Transform3D.h @@ -859,7 +859,7 @@ class Transform3D { const auto detZmask = (det == T(0)); if (any_of(detZmask)) { std::cerr << "Transform3D::inverse error: zero determinant" << std::endl; - det(detZmask) = T(1); + where(detZmask, det) = T(1); } det = T(1) / det; detxx *= det; @@ -873,15 +873,15 @@ class Transform3D { T detzz = (fM[kXX] * fM[kYY] - fM[kXY] * fM[kYX]) * det; // Set det=0 cases to 0 if (any_of(detZmask)) { - detxx(detZmask) = T(0); - detxy(detZmask) = T(0); - detxz(detZmask) = T(0); - detyx(detZmask) = T(0); - detyy(detZmask) = T(0); - detyz(detZmask) = T(0); - detzx(detZmask) = T(0); - detzy(detZmask) = T(0); - detzz(detZmask) = T(0); + where(detZmask, detxx) = T(0); + where(detZmask, detxy) = T(0); + where(detZmask, detxz) = T(0); + where(detZmask, detyx) = T(0); + where(detZmask, detyy) = T(0); + where(detZmask, detyz) = T(0); + where(detZmask, detzx) = T(0); + where(detZmask, detzy) = T(0); + where(detZmask, detzz) = T(0); } // set final components SetComponents(detxx, -detyx, detzx, -detxx * fM[kDX] + detyx * fM[kDY] - detzx * fM[kDZ], -detxy, detyy, -detzy, diff --git a/math/genvector/inc/Math/GenVector/DisplacementVector3D.h b/math/genvector/inc/Math/GenVector/DisplacementVector3D.h index 04ec163b3c35c..1568ca14cb6b9 100644 --- a/math/genvector/inc/Math/GenVector/DisplacementVector3D.h +++ b/math/genvector/inc/Math/GenVector/DisplacementVector3D.h @@ -345,7 +345,7 @@ namespace ROOT { DisplacementVector3D Unit() const { SCALAR tot = R(); - tot(tot == SCALAR(0)) = SCALAR(1); + where(tot == SCALAR(0), tot) = SCALAR(1); return DisplacementVector3D(*this) / tot; } @@ -660,7 +660,7 @@ namespace ROOT { { if (os) { os << "{ "; - for (std::size_t i = 0; i < PositionVector3D::Scalar::Size; ++i) { + for (std::size_t i = 0; i < PositionVector3D::Scalar::size(); ++i) { os << "(" << v.x()[i] << "," << v.y()[i] << "," << v.z()[i] << ") "; } os << "}"; diff --git a/math/genvector/inc/Math/GenVector/Plane3D.h b/math/genvector/inc/Math/GenVector/Plane3D.h index 3dfd0de1453d2..cb46c32ac8a9e 100644 --- a/math/genvector/inc/Math/GenVector/Plane3D.h +++ b/math/genvector/inc/Math/GenVector/Plane3D.h @@ -244,8 +244,8 @@ class Plane3D { // what to do if s = 0 ? const auto m = (s == SCALAR(0)); // set zero entries to 1 in the vector to avoid /0 later on - s(m) = SCALAR(1); - fD(m) = SCALAR(0); + where(m, s) = SCALAR(1); + where(m, fD) = SCALAR(0); const SCALAR w = SCALAR(1) / s; fA *= w; fB *= w; diff --git a/math/genvector/inc/Math/GenVector/PositionVector3D.h b/math/genvector/inc/Math/GenVector/PositionVector3D.h index fc4b4bd5c70ea..7f61671145aae 100644 --- a/math/genvector/inc/Math/GenVector/PositionVector3D.h +++ b/math/genvector/inc/Math/GenVector/PositionVector3D.h @@ -616,7 +616,7 @@ namespace ROOT { { if (os) { os << "{ "; - for (std::size_t i = 0; i < PositionVector3D::Scalar::Size; ++i) { + for (std::size_t i = 0; i < PositionVector3D::Scalar::size(); ++i) { os << "(" << v.x()[i] << "," << v.y()[i] << "," << v.z()[i] << ") "; } os << "}"; diff --git a/math/genvector/inc/Math/GenVector/Transform3D.h b/math/genvector/inc/Math/GenVector/Transform3D.h index 3c90667691462..7582cda6b82b0 100644 --- a/math/genvector/inc/Math/GenVector/Transform3D.h +++ b/math/genvector/inc/Math/GenVector/Transform3D.h @@ -838,7 +838,7 @@ class Transform3D { const auto detZmask = (det == T(0)); if (any_of(detZmask)) { std::cerr << "Transform3D::inverse error: zero determinant" << std::endl; - det(detZmask) = T(1); + where(detZmask, det) = T(1); } det = T(1) / det; detxx *= det; @@ -852,15 +852,15 @@ class Transform3D { T detzz = (fM[kXX] * fM[kYY] - fM[kXY] * fM[kYX]) * det; // Set det=0 cases to 0 if (any_of(detZmask)) { - detxx(detZmask) = T(0); - detxy(detZmask) = T(0); - detxz(detZmask) = T(0); - detyx(detZmask) = T(0); - detyy(detZmask) = T(0); - detyz(detZmask) = T(0); - detzx(detZmask) = T(0); - detzy(detZmask) = T(0); - detzz(detZmask) = T(0); + where(detZmask, detxx) = T(0); + where(detZmask, detxy) = T(0); + where(detZmask, detxz) = T(0); + where(detZmask, detyx) = T(0); + where(detZmask, detyy) = T(0); + where(detZmask, detyz) = T(0); + where(detZmask, detzx) = T(0); + where(detZmask, detzy) = T(0); + where(detZmask, detzz) = T(0); } // set final components SetComponents(detxx, -detyx, detzx, -detxx * fM[kDX] + detyx * fM[kDY] - detzx * fM[kDZ], -detxy, detyy, -detzy, @@ -984,18 +984,18 @@ class Transform3D { void SetIdentity(const typename SCALAR::mask_type m) { // set identity ( identity rotation and zero translation) - fM[kXX](m) = T(1); - fM[kXY](m) = T(0); - fM[kXZ](m) = T(0); - fM[kDX](m) = T(0); - fM[kYX](m) = T(0); - fM[kYY](m) = T(1); - fM[kYZ](m) = T(0); - fM[kDY](m) = T(0); - fM[kZX](m) = T(0); - fM[kZY](m) = T(0); - fM[kZZ](m) = T(1); - fM[kDZ](m) = T(0); + where(m, fM[kXX]) = T(1); + where(m, fM[kXY]) = T(0); + where(m, fM[kXZ]) = T(0); + where(m, fM[kDX]) = T(0); + where(m, fM[kYX]) = T(0); + where(m, fM[kYY]) = T(1); + where(m, fM[kYZ]) = T(0); + where(m, fM[kDY]) = T(0); + where(m, fM[kZX]) = T(0); + where(m, fM[kZY]) = T(0); + where(m, fM[kZZ]) = T(1); + where(m, fM[kDZ]) = T(0); } private: diff --git a/test/TFormulaVecTests.h b/test/TFormulaVecTests.h index 2f6e499d3877f..365d3e9e384ac 100644 --- a/test/TFormulaVecTests.h +++ b/test/TFormulaVecTests.h @@ -93,25 +93,40 @@ bool testVecFormula() { bool ok = true; + // Note that we have to disable several tests when using the Vc backend + // because of linker errors. This is because Vc is always built as a static + // library, and linked in MathCore, but the interpreter cannot lookup + // missing symbols for Vc math functions if the formula requires them and + // they are not already linked into MathCore by chance. + // See also: + // https://its.cern.ch/jira/browse/ROOT-10614 + // https://github.com/root-project/root/pull/20769 + ok &= testVec1D("3+[0]",constant_function, 3.333); ok &= testVec1D("3",constant_function, 3.333); +#ifndef R__HAS_VC ok &= testVec1D("sin(x)",std::sin,1); ok &= testVec1D("cos(x)",std::cos,1); +#endif ok &= testVec1D("exp(x)",std::exp,1); ok &= testVec1D("log(x)",std::log,2); ok &= testVec1D("log10(x)",TMath::Log10,2); +#ifndef R__HAS_VC ok &= testVec1D("tan(x)",std::tan,1); - //ok &= testVec1D("sinh(x)",std::sinh,1); - //ok &= testVec1D("cosh(x)",std::cosh,1); - //ok &= testVec1D("tanh(x)",std::tanh,1); + ok &= testVec1D("sinh(x)",std::sinh,1); + ok &= testVec1D("cosh(x)",std::cosh,1); + ok &= testVec1D("tanh(x)",std::tanh,1); ok &= testVec1D("asin(x)",std::asin,.1); ok &= testVec1D("acos(x)",std::acos,.1); +#endif ok &= testVec1D("atan(x)",std::atan,.1); ok &= testVec1D("sqrt(x)",std::sqrt,2); ok &= testVec1D("abs(x)",std::abs,-1); ok &= testVec2D("pow(x,y)",std::pow,2,3); +#ifndef R__HAS_VC ok &= testVec2D("min(x,y)",TMath::Min,2,3); ok &= testVec2D("max(x,y)",TMath::Max,2,3); +#endif ok &= testVec2D("atan2(x,y)",TMath::ATan2,2,3); return ok;