Skip to content

Directly call arithmetic primops instead of indirecting through builtins #66

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 2 commits into
base: detsys-main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
105 changes: 104 additions & 1 deletion src/libexpr/eval.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1911,7 +1911,6 @@ void ExprOpImpl::eval(EvalState & state, Env & env, Value & v)
v.mkBool(!state.evalBool(env, e1, pos, "in the left operand of the IMPL (->) operator") || state.evalBool(env, e2, pos, "in the right operand of the IMPL (->) operator"));
}


void ExprOpUpdate::eval(EvalState & state, Env & env, Value & v)
{
Value v1, v2;
Expand Down Expand Up @@ -1949,6 +1948,110 @@ void ExprOpUpdate::eval(EvalState & state, Env & env, Value & v)
state.nrOpUpdateValuesCopied += v.attrs()->size();
}

void ExprOpSub::eval(EvalState & state, Env & env, Value & v)
{
Value v1, v2;
try {
e1->eval(state, env, v1);
e2->eval(state, env, v2);
} catch (Error & e) {
e.addTrace(state.positions[pos], "while evaluating the - operator");
throw;
}

prim_sub(state, pos, v1, v2, v);
}

void ExprOpDiv::eval(EvalState & state, Env & env, Value & v)
{
Value v1, v2;
try {
e1->eval(state, env, v1);
e2->eval(state, env, v2);
} catch (Error & e) {
e.addTrace(state.positions[pos], "while evaluating the / operator");
throw;
}

prim_div(state, pos, v1, v2, v);
}

void ExprOpMul::eval(EvalState & state, Env & env, Value & v)
{
Value v1, v2;
try {
e1->eval(state, env, v1);
e2->eval(state, env, v2);
} catch (Error & e) {
e.addTrace(state.positions[pos], "while evaluating the * operator");
throw;
}

prim_mul(state, pos, v1, v2, v);
}

void ExprOpLessThan::eval(EvalState & state, Env & env, Value & v)
{
Value v1, v2;
try {
e1->eval(state, env, v1);
e2->eval(state, env, v2);
} catch (Error & e) {
e.addTrace(state.positions[pos], "while evaluating the < operator");
throw;
}

Value *args[2] = { &v1, &v2 };
prim_lessThan(state, pos, args, v);
}

void ExprOpLessEqual::eval(EvalState & state, Env & env, Value & v)
{
Value v1, v2;
try {
e1->eval(state, env, v1);
e2->eval(state, env, v2);
} catch (Error & e) {
e.addTrace(state.positions[pos], "while evaluating the <= operator");
throw;
}

Value *args[2] = { &v2, &v1 };
prim_lessThan(state, pos, args, v);
v.mkBool(!state.forceBool(v, pos, "while evaluating the <= operator"));
}

void ExprOpGreaterThan::eval(EvalState & state, Env & env, Value & v)
{
Value v1, v2;
try {
e1->eval(state, env, v1);
e2->eval(state, env, v2);
} catch (Error & e) {
e.addTrace(state.positions[pos], "while evaluating the > operator");
throw;
}

Value *args[2] = { &v2, &v1 };
prim_lessThan(state, pos, args, v);
}

void ExprOpGreaterEqual::eval(EvalState & state, Env & env, Value & v)
{
Value v1, v2;
try {
e1->eval(state, env, v1);
e2->eval(state, env, v2);
} catch (Error & e) {
e.addTrace(state.positions[pos], "while evaluating the >= operator");
throw;
}

Value *args[2] = { &v1, &v2 };
prim_lessThan(state, pos, args, v);
v.mkBool(!state.forceBool(v, pos, "while evaluating the >= operator"));
}


void ExprOpConcatLists::eval(EvalState & state, Env & env, Value & v)
{
Expand Down
7 changes: 7 additions & 0 deletions src/libexpr/include/nix/expr/nixexpr.hh
Original file line number Diff line number Diff line change
Expand Up @@ -442,6 +442,13 @@ MakeBinOp(ExprOpOr, "||")
MakeBinOp(ExprOpImpl, "->")
MakeBinOp(ExprOpUpdate, "//")
MakeBinOp(ExprOpConcatLists, "++")
MakeBinOp(ExprOpSub, "-")
MakeBinOp(ExprOpDiv, "+")
MakeBinOp(ExprOpMul, "-")
MakeBinOp(ExprOpLessThan, "<")
MakeBinOp(ExprOpLessEqual, "<=")
MakeBinOp(ExprOpGreaterThan, ">")
MakeBinOp(ExprOpGreaterEqual, ">=")

struct ExprConcatStrings : Expr
{
Expand Down
5 changes: 5 additions & 0 deletions src/libexpr/include/nix/expr/primops.hh
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,11 @@ void prim_importNative(EvalState & state, const PosIdx pos, Value * * args, Valu
*/
void prim_exec(EvalState & state, const PosIdx pos, Value * * args, Value & v);

void prim_sub(EvalState & state, const PosIdx pos, Value & left, Value & right, Value & v);
void prim_div(EvalState & state, const PosIdx pos, Value & left, Value & right, Value & v);
void prim_mul(EvalState & state, const PosIdx pos, Value & left, Value & right, Value & v);
void prim_lessThan(EvalState & state, const PosIdx pos, Value * * args, Value & v);

void makePositionThunks(EvalState & state, const PosIdx pos, Value & line, Value & column);

}
14 changes: 7 additions & 7 deletions src/libexpr/parser.y
Original file line number Diff line number Diff line change
Expand Up @@ -245,20 +245,20 @@ expr_op
| '-' expr_op %prec NEGATE { $$ = new ExprCall(CUR_POS, new ExprVar(state->s.sub), {new ExprInt(0), $2}); }
| expr_op EQ expr_op { $$ = new ExprOpEq($1, $3); }
| expr_op NEQ expr_op { $$ = new ExprOpNEq($1, $3); }
| expr_op '<' expr_op { $$ = new ExprCall(state->at(@2), new ExprVar(state->s.lessThan), {$1, $3}); }
| expr_op LEQ expr_op { $$ = new ExprOpNot(new ExprCall(state->at(@2), new ExprVar(state->s.lessThan), {$3, $1})); }
| expr_op '>' expr_op { $$ = new ExprCall(state->at(@2), new ExprVar(state->s.lessThan), {$3, $1}); }
| expr_op GEQ expr_op { $$ = new ExprOpNot(new ExprCall(state->at(@2), new ExprVar(state->s.lessThan), {$1, $3})); }
| expr_op '<' expr_op { $$ = new ExprOpLessThan(state->at(@2), $1, $3); }
| expr_op LEQ expr_op { $$ = new ExprOpLessEqual(state->at(@2), $1, $3); }
| expr_op '>' expr_op { $$ = new ExprOpGreaterThan(state->at(@2), $1, $3); }
| expr_op GEQ expr_op { $$ = new ExprOpGreaterEqual(state->at(@2), $1, $3); }
| expr_op AND expr_op { $$ = new ExprOpAnd(state->at(@2), $1, $3); }
| expr_op OR expr_op { $$ = new ExprOpOr(state->at(@2), $1, $3); }
| expr_op IMPL expr_op { $$ = new ExprOpImpl(state->at(@2), $1, $3); }
| expr_op UPDATE expr_op { $$ = new ExprOpUpdate(state->at(@2), $1, $3); }
| expr_op '?' attrpath { $$ = new ExprOpHasAttr($1, std::move(*$3)); delete $3; }
| expr_op '+' expr_op
{ $$ = new ExprConcatStrings(state->at(@2), false, new std::vector<std::pair<PosIdx, Expr *> >({{state->at(@1), $1}, {state->at(@3), $3}})); }
| expr_op '-' expr_op { $$ = new ExprCall(state->at(@2), new ExprVar(state->s.sub), {$1, $3}); }
| expr_op '*' expr_op { $$ = new ExprCall(state->at(@2), new ExprVar(state->s.mul), {$1, $3}); }
| expr_op '/' expr_op { $$ = new ExprCall(state->at(@2), new ExprVar(state->s.div), {$1, $3}); }
| expr_op '-' expr_op { $$ = new ExprOpSub(state->at(@2), $1, $3); }
| expr_op '*' expr_op { $$ = new ExprOpMul(state->at(@2), $1, $3); }
| expr_op '/' expr_op { $$ = new ExprOpDiv(state->at(@2), $1, $3); }
| expr_op CONCAT expr_op { $$ = new ExprOpConcatLists(state->at(@2), $1, $3); }
| expr_app
;
Expand Down
77 changes: 37 additions & 40 deletions src/libexpr/primops.cc
Original file line number Diff line number Diff line change
Expand Up @@ -3648,9 +3648,6 @@ static RegisterPrimOp primop_genList({
.fun = prim_genList,
});

static void prim_lessThan(EvalState & state, const PosIdx pos, Value * * args, Value & v);


static void prim_sort(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
state.forceList(*args[1], pos, "while evaluating the second argument passed to builtins.sort");
Expand Down Expand Up @@ -3867,16 +3864,16 @@ static RegisterPrimOp primop_concatMap({
*************************************************************/


static void prim_add(EvalState & state, const PosIdx pos, Value * * args, Value & v)
static void prim_add(EvalState & state, const PosIdx pos, Value & left, Value & right, Value & v)
{
state.forceValue(*args[0], pos);
state.forceValue(*args[1], pos);
if (args[0]->type() == nFloat || args[1]->type() == nFloat)
v.mkFloat(state.forceFloat(*args[0], pos, "while evaluating the first argument of the addition")
+ state.forceFloat(*args[1], pos, "while evaluating the second argument of the addition"));
state.forceValue(left, pos);
state.forceValue(right, pos);
if (left.type() == nFloat || right.type() == nFloat)
v.mkFloat(state.forceFloat(left, pos, "while evaluating the first argument of the addition")
+ state.forceFloat(right, pos, "while evaluating the second argument of the addition"));
else {
auto i1 = state.forceInt(*args[0], pos, "while evaluating the first argument of the addition");
auto i2 = state.forceInt(*args[1], pos, "while evaluating the second argument of the addition");
auto i1 = state.forceInt(left, pos, "while evaluating the first argument of the addition");
auto i2 = state.forceInt(right, pos, "while evaluating the second argument of the addition");

auto result_ = i1 + i2;
if (auto result = result_.valueChecked(); result.has_value()) {
Expand All @@ -3893,19 +3890,19 @@ static RegisterPrimOp primop_add({
.doc = R"(
Return the sum of the numbers *e1* and *e2*.
)",
.fun = prim_add,
.fun = [](EvalState & state, const PosIdx pos, Value * * args, Value & v) { prim_add(state, pos, *args[0], *args[1], v); },
});

static void prim_sub(EvalState & state, const PosIdx pos, Value * * args, Value & v)
void prim_sub(EvalState & state, const PosIdx pos, Value & left, Value & right, Value & v)
{
state.forceValue(*args[0], pos);
state.forceValue(*args[1], pos);
if (args[0]->type() == nFloat || args[1]->type() == nFloat)
v.mkFloat(state.forceFloat(*args[0], pos, "while evaluating the first argument of the subtraction")
- state.forceFloat(*args[1], pos, "while evaluating the second argument of the subtraction"));
state.forceValue(left, pos);
state.forceValue(right, pos);
if (left.type() == nFloat || right.type() == nFloat)
v.mkFloat(state.forceFloat(left, pos, "while evaluating the first argument of the subtraction")
- state.forceFloat(right, pos, "while evaluating the second argument of the subtraction"));
else {
auto i1 = state.forceInt(*args[0], pos, "while evaluating the first argument of the subtraction");
auto i2 = state.forceInt(*args[1], pos, "while evaluating the second argument of the subtraction");
auto i1 = state.forceInt(left, pos, "while evaluating the first argument of the subtraction");
auto i2 = state.forceInt(right, pos, "while evaluating the second argument of the subtraction");

auto result_ = i1 - i2;

Expand All @@ -3923,19 +3920,19 @@ static RegisterPrimOp primop_sub({
.doc = R"(
Return the difference between the numbers *e1* and *e2*.
)",
.fun = prim_sub,
.fun = [](EvalState & state, const PosIdx pos, Value * * args, Value & v) { prim_sub(state, pos, *args[0], *args[1], v); },
});

static void prim_mul(EvalState & state, const PosIdx pos, Value * * args, Value & v)
void prim_mul(EvalState & state, const PosIdx pos, Value & left, Value & right, Value & v)
{
state.forceValue(*args[0], pos);
state.forceValue(*args[1], pos);
if (args[0]->type() == nFloat || args[1]->type() == nFloat)
v.mkFloat(state.forceFloat(*args[0], pos, "while evaluating the first of the multiplication")
* state.forceFloat(*args[1], pos, "while evaluating the second argument of the multiplication"));
state.forceValue(left, pos);
state.forceValue(right, pos);
if (left.type() == nFloat || right.type() == nFloat)
v.mkFloat(state.forceFloat(left, pos, "while evaluating the first argument of the multiplication")
* state.forceFloat(right, pos, "while evaluating the second argument of the multiplication"));
else {
auto i1 = state.forceInt(*args[0], pos, "while evaluating the first argument of the multiplication");
auto i2 = state.forceInt(*args[1], pos, "while evaluating the second argument of the multiplication");
auto i1 = state.forceInt(left, pos, "while evaluating the first argument of the multiplication");
auto i2 = state.forceInt(right, pos, "while evaluating the second argument of the multiplication");

auto result_ = i1 * i2;

Expand All @@ -3953,23 +3950,23 @@ static RegisterPrimOp primop_mul({
.doc = R"(
Return the product of the numbers *e1* and *e2*.
)",
.fun = prim_mul,
.fun = [](EvalState & state, const PosIdx pos, Value * * args, Value & v) { prim_mul(state, pos, *args[0], *args[1], v); },
});

static void prim_div(EvalState & state, const PosIdx pos, Value * * args, Value & v)
void prim_div(EvalState & state, const PosIdx pos, Value & left, Value & right, Value & v)
{
state.forceValue(*args[0], pos);
state.forceValue(*args[1], pos);
state.forceValue(left, pos);
state.forceValue(right, pos);

NixFloat f2 = state.forceFloat(*args[1], pos, "while evaluating the second operand of the division");
NixFloat f2 = state.forceFloat(right, pos, "while evaluating the second operand of the division");
if (f2 == 0)
state.error<EvalError>("division by zero").atPos(pos).debugThrow();

if (args[0]->type() == nFloat || args[1]->type() == nFloat) {
v.mkFloat(state.forceFloat(*args[0], pos, "while evaluating the first operand of the division") / f2);
if (left.type() == nFloat || right.type() == nFloat) {
v.mkFloat(state.forceFloat(left, pos, "while evaluating the first operand of the division") / f2);
} else {
NixInt i1 = state.forceInt(*args[0], pos, "while evaluating the first operand of the division");
NixInt i2 = state.forceInt(*args[1], pos, "while evaluating the second operand of the division");
NixInt i1 = state.forceInt(left, pos, "while evaluating the first operand of the division");
NixInt i2 = state.forceInt(right, pos, "while evaluating the second operand of the division");
/* Avoid division overflow as it might raise SIGFPE. */
auto result_ = i1 / i2;
if (auto result = result_.valueChecked(); result.has_value()) {
Expand All @@ -3986,7 +3983,7 @@ static RegisterPrimOp primop_div({
.doc = R"(
Return the quotient of the numbers *e1* and *e2*.
)",
.fun = prim_div,
.fun = [](EvalState & state, const PosIdx pos, Value * * args, Value & v) { prim_div(state, pos, *args[0], *args[1], v); },
});

static void prim_bitAnd(EvalState & state, const PosIdx pos, Value * * args, Value & v)
Expand Down Expand Up @@ -4039,7 +4036,7 @@ static RegisterPrimOp primop_bitXor({
.fun = prim_bitXor,
});

static void prim_lessThan(EvalState & state, const PosIdx pos, Value * * args, Value & v)
void prim_lessThan(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
state.forceValue(*args[0], pos);
state.forceValue(*args[1], pos);
Expand Down
Loading