Support power expressions with constant exponent in constraints (#7073)

This commit is contained in:
Kamil Danecki 2026-02-16 12:01:24 +01:00 committed by GitHub
parent 7c1b348b41
commit 821eacebea
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 115 additions and 5 deletions

View File

@ -136,6 +136,7 @@ Julie Schwartz
Julien Margetts
Justin Thiel
Kaleb Barrett
Kamil Danecki
Kamil Rakoczy
Kanad Kanhere
Kefa Chen

View File

@ -1354,6 +1354,49 @@ class ConstraintExprVisitor final : public VNVisitor {
VL_DO_DANGLING(nodep->deleteTree(), nodep);
iterate(resultp);
}
void handlePow(AstNodeBiop* nodep) {
if (AstConst* const exponentp = VN_CAST(nodep->rhsp(), Const)) {
FileLine* const fl = nodep->fileline();
AstNodeExpr* const basep = nodep->lhsp();
V3Number numOne{nodep, basep->width(), 1};
AstNodeExpr* powerp = new AstConst{fl, numOne};
const bool baseSigned = VN_IS(nodep, PowSS) || VN_IS(nodep, PowSU);
const int32_t exponent = baseSigned ? exponentp->toSInt() : exponentp->toUInt();
if (exponent > 0) {
for (int32_t i = 0; i < exponent; i++) {
if (baseSigned) {
powerp = new AstMulS{fl, powerp, basep->cloneTreePure(false)};
} else {
powerp = new AstMul{fl, powerp, basep->cloneTreePure(false)};
}
powerp->user1(true);
}
} else if (exponent < 0) {
// Limit chain of divisions to max 2, because operations are on integers.
// Two divisions are needed to preserve the sign.
if (baseSigned) {
powerp = new AstDivS{fl, powerp, basep->cloneTreePure(false)};
powerp->user1(true);
powerp = new AstDivS{fl, powerp, basep->cloneTreePure(false)};
powerp->user1(true);
} else {
powerp = new AstDiv{fl, powerp, basep->cloneTreePure(false)};
powerp->user1(true);
}
}
nodep->replaceWith(powerp);
VL_DO_DANGLING(nodep->deleteTree(), nodep);
iterate(powerp);
} else {
nodep->v3warn(
CONSTRAINTIGN,
"Unsupported: Power (**) expression with non-constant exponent in constraint");
}
}
void visit(AstPow* nodep) override { handlePow(nodep); }
void visit(AstPowSS* nodep) override { handlePow(nodep); }
void visit(AstPowSU* nodep) override { handlePow(nodep); }
void visit(AstPowUS* nodep) override { handlePow(nodep); }
void visit(AstNodeBiop* nodep) override {
if (editFormat(nodep)) return;
editSMT(nodep, nodep->lhsp(), nodep->rhsp());

View File

@ -0,0 +1,6 @@
%Warning-CONSTRAINTIGN: t/t_constraint_non_const_exp_pow_unsup.v:11:26: Unsupported: Power (**) expression with non-constant exponent in constraint
11 | constraint c_power { x ** y < 10000; }
| ^~
... For warning description see https://verilator.org/warn/CONSTRAINTIGN?v=latest
... Use "/* verilator lint_off CONSTRAINTIGN */" and lint_on around source to disable this message.
%Error: Exiting due to

View File

@ -0,0 +1,16 @@
#!/usr/bin/env python3
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# This program is free software; you can redistribute it and/or modify it
# under the terms of either the GNU Lesser General Public License Version 3
# or the Perl Artistic License Version 2.0.
# SPDX-FileCopyrightText: 2024 Wilson Snyder
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
import vltest_bootstrap
test.scenarios('vlt')
test.lint(fails=True, expect_filename=test.golden_filename)
test.passes()

View File

@ -0,0 +1,23 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed under the Creative Commons Public Domain.
// SPDX-FileCopyrightText: 2026 Antmicro
// SPDX-License-Identifier: CC0-1.0
class Packet;
rand int x;
rand int y;
constraint c_power { x ** y < 10000; }
endclass
module t;
Packet p;
initial begin
p = new;
void'(p.randomize());
$finish;
end
endmodule

View File

@ -8,9 +8,14 @@ class Packet;
rand int x;
rand int y;
rand int z;
rand int w;
rand int v;
rand int u;
rand bit [31:0] b;
rand bit [31:0] c;
rand bit [31:0] d;
rand bit [31:0] e;
rand bit [31:0] f;
rand bit tiny;
rand bit zero;
rand bit one;
@ -32,6 +37,16 @@ class Packet;
z < 0;
z > -4;
}
constraint c_power { e ** 32'h5 < 10000; }
constraint c_power_ss { w ** 5 < 10000; }
constraint c_power_us { f ** 5 < 10000; }
constraint c_power_su { v ** 32'h5 < 10000; }
constraint c_power_many { u ** 2 ** 3 < 1000; u > 2; u < 10; }
// check for negative values in constant
constraint c_power_neg_exp { v ** 4'shf == 0; }
constraint c_power_u_neg_exp { f ** 4'shf == 0; }
constraint c_power_zero_exp { v ** 0 == 1; }
constraint c_power_u_zero_exp { f ** 0 == 1; }
constraint impl { tiny == 1 -> x != 10; }
constraint concat { {c, b} != 'h1111; }
constraint unary { !(-~c == 'h22); }
@ -91,6 +106,11 @@ module t;
if (p.x * 9 == p.b * 3) $stop;
if (p.y != 2) $stop;
if (p.z != -2) $stop;
if (p.w ** 5 >= 10000) $stop;
if (p.e ** 32'h5 >= 10000) $stop;
if (p.v ** 32'h5 >= 10000) $stop;
if (p.f ** 5 >= 10000) $stop;
if (p.u != 3) $stop;
if (p.tiny && p.x == 10) $stop;
if ({p.c, p.b} == 'h1111) $stop;
if (-~p.c == 'h22) $stop;

View File

@ -1,5 +1,6 @@
%Error-UNSUPPORTED: t/t_constraint_unsup.v:9:27: Unsupported expression inside constraint
9 | constraint cons { m_one ** 2 > 0; }
| ^~
%Error-UNSUPPORTED: t/t_constraint_unsup.v:9:29: Unsupported expression inside constraint
: ... note: In instance 't'
9 | constraint cons { x + 1.0 > 0.0; }
| ^
... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest
%Error: Exiting due to

View File

@ -5,8 +5,8 @@
// SPDX-License-Identifier: CC0-1.0
class Packet;
rand int m_one;
constraint cons { m_one ** 2 > 0; }
rand real x;
constraint cons { x + 1.0 > 0.0; }
endclass
module t;