From 5def7559a6bb6ccae821cf9bb35fb9abc0ea8439 Mon Sep 17 00:00:00 2001 From: eldritch horrors Date: Sun, 28 Sep 2025 00:02:20 +0200 Subject: [PATCH] libexpr: move floats to auxiliary storage floats are used very rarely, and our float support is bad enough to strongly discourage using them on reproducibility grounds alone. we can thus move them to more expensive storage without hurting folks. Change-Id: I1086f612f85e294dd3fae4a2d334e09f52bbe4a8 --- lix/libexpr/eval.cc | 2 ++ lix/libexpr/nixexpr.hh | 17 ++++++++++++-- lix/libexpr/parser/parser-impl1.inc.cc | 2 +- lix/libexpr/value.hh | 32 ++++++++++++++------------ 4 files changed, 35 insertions(+), 18 deletions(-) diff --git a/lix/libexpr/eval.cc b/lix/libexpr/eval.cc index 88231e4b4..202273202 100644 --- a/lix/libexpr/eval.cc +++ b/lix/libexpr/eval.cc @@ -107,6 +107,8 @@ std::string showType(const Value & v) switch (v.auxiliary()->type) { case Value::Acb::tExternal: return v.external()->showType(); + case Value::Acb::tFloat: + return std::string(showType(v.type())); } #pragma GCC diagnostic pop case tThunk: return v.isBlackhole() ? "a black hole" : "a thunk"; diff --git a/lix/libexpr/nixexpr.hh b/lix/libexpr/nixexpr.hh index 54be8ed95..009c5767b 100644 --- a/lix/libexpr/nixexpr.hh +++ b/lix/libexpr/nixexpr.hh @@ -177,14 +177,27 @@ protected: public: ExprLiteral(const PosIdx pos, NewValueAs::integer_t, NixInt n) : Expr(pos) { v.mkInt(n); }; - ExprLiteral(const PosIdx pos, NewValueAs::integer_t, NixInt::Inner n) : Expr(pos) { v.mkInt(n); }; - ExprLiteral(const PosIdx pos, NewValueAs::floating_t, NixFloat nf) : Expr(pos) { v.mkFloat(nf); }; + ExprLiteral(const PosIdx pos, NewValueAs::integer_t, NixInt::Inner n) : Expr(pos) + { + v.mkInt(n); + } Value * maybeThunk(EvalState & state, Env & env) override; JSON toJSON(const SymbolTable & symbols) const override; void eval(EvalState & state, Env & env, Value & v) override; void accept(ExprVisitor & ev, std::unique_ptr & ptr) override { ev.visit(*this, ptr); } }; +struct ExprFloat : ExprLiteral +{ + Value::Float f; + ExprFloat(const PosIdx pos, NewValueAs::floating_t, double f) + : ExprLiteral(pos) + , f{{Value::Acb::tFloat}, f} + { + v = Value(this->f); + } +}; + struct ExprString : ExprLiteral { std::string s; diff --git a/lix/libexpr/parser/parser-impl1.inc.cc b/lix/libexpr/parser/parser-impl1.inc.cc index d698daddb..487b5ff96 100644 --- a/lix/libexpr/parser/parser-impl1.inc.cc +++ b/lix/libexpr/parser/parser-impl1.inc.cc @@ -542,7 +542,7 @@ template<> struct BuildAST { }); } }(); - s.emplaceExpr(ps.at(in), NewValueAs::floating, v); + s.emplaceExpr(ps.at(in), NewValueAs::floating, v); } }; diff --git a/lix/libexpr/value.hh b/lix/libexpr/value.hh index f4d46973d..7bccb785b 100644 --- a/lix/libexpr/value.hh +++ b/lix/libexpr/value.hh @@ -34,7 +34,6 @@ typedef enum { tLambda, tPrimOp, tAuxiliary, - tFloat } InternalType; /** @@ -259,11 +258,13 @@ public: /// Constructs a nix language value of type "float", with the floating /// point value of @ref f. - Value(floating_t, NixFloat f) - : internalType(tFloat) - , _fpoint(f) - , _float_pad(0) - { } + Value(floating_t, NixFloat f) : internalType(tAuxiliary), _aux_pad(0) + { + auto fp = gcAllocType(); + fp->type = Acb::tFloat; + fp->value = f; + _auxiliary = fp; + } /// Constructs a nix language value of type "bool", with the boolean /// value of @ref b. @@ -638,12 +639,17 @@ public: { enum { tExternal, + tFloat, } type; }; struct External : Acb { ExternalValueBase * external; }; + struct Float : Acb + { + NixFloat value; + }; union { @@ -688,10 +694,6 @@ public: const Acb * _auxiliary; uintptr_t _aux_pad; }; - struct { - NixFloat _fpoint; - uintptr_t _float_pad; - }; }; /** @@ -719,8 +721,9 @@ public: switch (_auxiliary->type) { case Acb::tExternal: return nExternal; + case Acb::tFloat: + return nFloat; } - case tFloat: return nFloat; case tThunk: return nThunk; case tApp: @@ -834,9 +837,7 @@ public: inline void mkFloat(NixFloat n) { - clearValue(); - internalType = tFloat; - _fpoint = n; + *this = {NewValueAs::floating, n}; } bool isList() const @@ -954,7 +955,8 @@ public: NixFloat fpoint() const { - return _fpoint; + assert(internalType == tAuxiliary && _auxiliary->type == Acb::tFloat); + return static_cast(_auxiliary)->value; } const Acb * auxiliary() const