[ImportVerilog]Support real math functions. (#8192)

Co-authored-by: Fabian Schuiki <fabian@schuiki.ch>
Co-authored-by: chenbo <71652651+chenbo-again@users.noreply.github.com>
This commit is contained in:
Hailong Sun 2025-02-07 15:41:59 +08:00 committed by GitHub
parent 39f7d01261
commit 2b2532506c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 254 additions and 8 deletions

View File

@ -508,6 +508,23 @@ def StringConstantOp : MooreOp<"string_constant", [Pure]> {
let assemblyFormat = "$value attr-dict `:` type($result)";
}
def RealLiteralOp : MooreOp<"real_constant", [Pure]> {
let summary = "Produce a constant real value";
let description = [{
Produces a constant value of real type.
Example:
```mlir
%0 = moore.real_constant 1.23
```
The real type has fixed-point(1.2) and exponent(2.0e10) formats.
See IEEE 1800-2017 § 5.7.2 "Real literal constants".
}];
let arguments = (ins F64Attr:$value);
let results = (outs RealType:$result);
let assemblyFormat = "$value attr-dict `:` type($result)";
}
//===----------------------------------------------------------------------===//
// Casting and Resizing
//===----------------------------------------------------------------------===//
@ -1610,6 +1627,20 @@ def SeverityBIOp : Builtin<"severity"> {
// Math Builtins
//===----------------------------------------------------------------------===//
class RealMathFunc<string mnemonic, list<Trait> traits = []> :
Builtin<mnemonic, traits # [SameOperandsAndResultType]> {
let description = [{
The system real math functions shall accept real value arguments and return
a real result type. Their behavior shall match the equivalent C language
standard math library function indicated.
See IEEE 1800-2017 § 20.8.2 "Real math functions".
}];
let arguments = (ins RealType:$value);
let results = (outs RealType:$result);
let assemblyFormat = "$value attr-dict `:` type($value)";
}
def Clog2BIOp : Builtin<"clog2", [SameOperandsAndResultType]> {
let summary = "Compute ceil(log2(x)) of x";
let description = [{
@ -1628,4 +1659,76 @@ def Clog2BIOp : Builtin<"clog2", [SameOperandsAndResultType]> {
let assemblyFormat = "$value attr-dict `:` type($value)";
}
def LnBIOp : RealMathFunc<"ln"> {
let summary = "Natural logarithm";
}
def Log10BIOp : RealMathFunc<"log10"> {
let summary = "Decimal logarithm";
}
def ExpBIOp : RealMathFunc<"exp"> {
let summary = "Exponential";
}
def SqrtBIOp : RealMathFunc<"sqrt"> {
let summary = "Square root";
}
def FloorBIOp : RealMathFunc<"floor"> {
let summary = "Floor";
}
def CeilBIOp : RealMathFunc<"ceil"> {
let summary = "Ceiling";
}
def SinBIOp : RealMathFunc<"sin"> {
let summary = "Sine";
}
def CosBIOp : RealMathFunc<"cos"> {
let summary = "Cosine";
}
def TanBIOp : RealMathFunc<"tan"> {
let summary = "Tangent";
}
def AsinBIOp : RealMathFunc<"asin"> {
let summary = "Arc-sine";
}
def AcosBIOp : RealMathFunc<"acos"> {
let summary = "Arc-cosine";
}
def AtanBIOp : RealMathFunc<"atan"> {
let summary = "Arc-tangent";
}
def SinhBIOp : RealMathFunc<"sinh"> {
let summary = "Hyperbolic sine";
}
def CoshBIOp : RealMathFunc<"cosh"> {
let summary = "Hyperbolic cosine";
}
def TanhBIOp : RealMathFunc<"tanh"> {
let summary = "Hyperbolic tangent";
}
def AsinhBIOp : RealMathFunc<"asinh"> {
let summary = "Arc-hyperbolic sine";
}
def AcoshBIOp : RealMathFunc<"acosh"> {
let summary = "Arc-hyperbolic cosine";
}
def AtanhBIOp : RealMathFunc<"atanh"> {
let summary = "Arc-hyperbolic tangent";
}
#endif // CIRCT_DIALECT_MOORE_MOOREOPS

View File

@ -751,15 +751,15 @@ struct RvalueExprVisitor {
const auto &subroutine = *info.subroutine;
auto args = expr.arguments();
if (subroutine.name == "$signed" || subroutine.name == "$unsigned")
return context.convertRvalueExpression(*args[0]);
if (subroutine.name == "$clog2") {
auto value = context.convertToSimpleBitVector(
context.convertRvalueExpression(*args[0]));
if (args.size() == 1) {
auto value = context.convertRvalueExpression(*args[0]);
if (!value)
return {};
return builder.create<moore::Clog2BIOp>(loc, value);
auto result = context.convertSystemCallArity1(subroutine, loc, value);
if (failed(result))
return {};
if (*result)
return *result;
}
mlir::emitError(loc) << "unsupported system call `" << subroutine.name
@ -773,6 +773,12 @@ struct RvalueExprVisitor {
return builder.create<moore::StringConstantOp>(loc, type, expr.getValue());
}
/// Handle real literals.
Value visit(const slang::ast::RealLiteral &expr) {
return builder.create<moore::RealLiteralOp>(
loc, builder.getF64FloatAttr(expr.getValue()));
}
/// Handle assignment patterns.
Value visitAssignmentPattern(
const slang::ast::AssignmentPatternExpressionBase &expr,
@ -1310,3 +1316,96 @@ Value Context::materializeConversion(Type type, Value value, bool isSigned,
value = builder.create<moore::ConversionOp>(loc, type, value);
return value;
}
FailureOr<Value>
Context::convertSystemCallArity1(const slang::ast::SystemSubroutine &subroutine,
Location loc, Value value) {
auto systemCallRes =
llvm::StringSwitch<std::function<FailureOr<Value>()>>(subroutine.name)
// Signed and unsigned system functions.
.Case("$signed", [&]() { return value; })
.Case("$unsigned", [&]() { return value; })
// Math functions in SystemVerilog.
.Case("$clog2",
[&]() -> FailureOr<Value> {
value = convertToSimpleBitVector(value);
if (!value)
return failure();
return (Value)builder.create<moore::Clog2BIOp>(loc, value);
})
.Case("$ln",
[&]() -> Value {
return builder.create<moore::LnBIOp>(loc, value);
})
.Case("$log10",
[&]() -> Value {
return builder.create<moore::Log10BIOp>(loc, value);
})
.Case("$sin",
[&]() -> Value {
return builder.create<moore::SinBIOp>(loc, value);
})
.Case("$cos",
[&]() -> Value {
return builder.create<moore::CosBIOp>(loc, value);
})
.Case("$tan",
[&]() -> Value {
return builder.create<moore::TanBIOp>(loc, value);
})
.Case("$exp",
[&]() -> Value {
return builder.create<moore::ExpBIOp>(loc, value);
})
.Case("$sqrt",
[&]() -> Value {
return builder.create<moore::SqrtBIOp>(loc, value);
})
.Case("$floor",
[&]() -> Value {
return builder.create<moore::FloorBIOp>(loc, value);
})
.Case("$ceil",
[&]() -> Value {
return builder.create<moore::CeilBIOp>(loc, value);
})
.Case("$asin",
[&]() -> Value {
return builder.create<moore::AsinBIOp>(loc, value);
})
.Case("$acos",
[&]() -> Value {
return builder.create<moore::AcosBIOp>(loc, value);
})
.Case("$atan",
[&]() -> Value {
return builder.create<moore::AtanBIOp>(loc, value);
})
.Case("$sinh",
[&]() -> Value {
return builder.create<moore::SinhBIOp>(loc, value);
})
.Case("$cosh",
[&]() -> Value {
return builder.create<moore::CoshBIOp>(loc, value);
})
.Case("$tanh",
[&]() -> Value {
return builder.create<moore::TanhBIOp>(loc, value);
})
.Case("$asinh",
[&]() -> Value {
return builder.create<moore::AsinhBIOp>(loc, value);
})
.Case("$acosh",
[&]() -> Value {
return builder.create<moore::AcoshBIOp>(loc, value);
})
.Case("$atanh",
[&]() -> Value {
return builder.create<moore::AtanhBIOp>(loc, value);
})
.Default([&]() -> Value { return {}; });
return systemCallRes();
}

View File

@ -163,6 +163,11 @@ struct Context {
moore::IntFormat defaultFormat = moore::IntFormat::Decimal,
bool appendNewline = false);
/// Convert system function calls only have arity-1.
FailureOr<Value>
convertSystemCallArity1(const slang::ast::SystemSubroutine &subroutine,
Location loc, Value value);
/// Evaluate the constant value of an expression.
slang::ConstantValue evaluateConstant(const slang::ast::Expression &expr);

View File

@ -6,6 +6,7 @@
// UNSUPPORTED: valgrind
function void dummyA(int x); endfunction
function void dummyB(real x); endfunction
// IEEE 1800-2017 § 20.2 "Simulation control system tasks"
// CHECK-LABEL: func.func private @SimulationControlBuiltins(
@ -191,9 +192,47 @@ endfunction
// CHECK-LABEL: func.func private @MathBuiltins(
// CHECK-SAME: [[X:%.+]]: !moore.i32
// CHECK-SAME: [[Y:%.+]]: !moore.l42
function void MathBuiltins(int x, logic [41:0] y);
// CHECK-SAME: [[R:%.+]]: !moore.real
function void MathBuiltins(int x, logic [41:0] y, real r);
// CHECK: moore.builtin.clog2 [[X]] : i32
dummyA($clog2(x));
// CHECK: moore.builtin.clog2 [[Y]] : l42
dummyA($clog2(y));
// CHECK: moore.builtin.ln [[R]] : real
dummyB($ln(r));
// CHECK: moore.builtin.log10 [[R]] : real
dummyB($log10(r));
// CHECK: moore.builtin.exp [[R]] : real
dummyB($exp(r));
// CHECK: moore.builtin.sqrt [[R]] : real
dummyB($sqrt(r));
// CHECK: moore.builtin.floor [[R]] : real
dummyB($floor(r));
// CHECK: moore.builtin.ceil [[R]] : real
dummyB($ceil(r));
// CHECK: moore.builtin.sin [[R]] : real
dummyB($sin(r));
// CHECK: moore.builtin.cos [[R]] : real
dummyB($cos(r));
// CHECK: moore.builtin.tan [[R]] : real
dummyB($tan(r));
// CHECK: moore.builtin.asin [[R]] : real
dummyB($asin(r));
// CHECK: moore.builtin.acos [[R]] : real
dummyB($acos(r));
// CHECK: moore.builtin.atan [[R]] : real
dummyB($atan(r));
// CHECK: moore.builtin.sinh [[R]] : real
dummyB($sinh(r));
// CHECK: moore.builtin.cosh [[R]] : real
dummyB($cosh(r));
// CHECK: moore.builtin.tanh [[R]] : real
dummyB($tanh(r));
// CHECK: moore.builtin.asinh [[R]] : real
dummyB($asinh(r));
// CHECK: moore.builtin.acosh [[R]] : real
dummyB($acosh(r));
// CHECK: moore.builtin.atanh [[R]] : real
dummyB($atanh(r));
endfunction