[HW] Verify the expression in a hw.param.value is correct.

This commit is contained in:
Chris Lattner 2021-09-26 18:13:55 -07:00
parent c3b2b46de8
commit f0600f06a3
4 changed files with 45 additions and 12 deletions

View File

@ -74,7 +74,8 @@ def BitcastOp: HWOp<"bitcast", [NoSideEffect]> {
}
def ParamValueOp : HWOp<"param.value",
[FirstAttrDerivedResultType, NoSideEffect]> {
[FirstAttrDerivedResultType, NoSideEffect,
ConstantLike]> {
let summary = [{
Return the value of a parameter expression as an SSA value that may be used
by other ops.
@ -83,4 +84,5 @@ def ParamValueOp : HWOp<"param.value",
let arguments = (ins AnyAttr:$value);
let results = (outs HWValueType:$result);
let assemblyFormat = "custom<ParamValue>($value, type($result)) attr-dict";
let verifier = "return ::verifyParamValueOp(*this);";
}

View File

@ -111,6 +111,10 @@ void setModuleResultNames(Operation *module, ArrayRef<Attribute> names);
/// Return true if the specified operation is a combinational logic op.
bool isCombinational(Operation *op);
/// Return true if the specified attribute tree is made up of nodes that are
/// valid in a parameter expression.
bool isValidParameterExpression(Attribute attr, Operation *module);
/// Check parameter specified by `value` to see if it is valid within the scope
/// of the specified module `module`. If not, emit an error at the location of
/// `usingOp` and return failure, otherwise return success.

View File

@ -40,7 +40,8 @@ enum class Delimiter {
/// Check parameter specified by `value` to see if it is valid within the scope
/// of the specified module `module`. If not, emit an error at the location of
/// `usingOp` and return failure, otherwise return success.
/// `usingOp` and return failure, otherwise return success. If `usingOp` is
/// null, then no diagnostic is generated.
///
/// If `disallowParamRefs` is true, then parameter references are not allowed.
LogicalResult hw::checkParameterInContext(Attribute value, Operation *module,
@ -70,8 +71,9 @@ LogicalResult hw::checkParameterInContext(Attribute value, Operation *module,
// Don't allow references to parameters from the default values of a
// parameter list.
if (disallowParamRefs) {
usingOp->emitOpError("parameter ")
<< nameAttr << " cannot be used as a default value for a parameter";
if (usingOp)
usingOp->emitOpError("parameter ")
<< nameAttr << " cannot be used as a default value for a parameter";
return failure();
}
@ -85,19 +87,31 @@ LogicalResult hw::checkParameterInContext(Attribute value, Operation *module,
if (paramAttr.getType().getValue() == parameterRef.getType())
return success();
auto diag = usingOp->emitOpError("parameter ")
<< nameAttr << " used with type " << parameterRef.getType()
<< "; should have type " << paramAttr.getType().getValue();
diag.attachNote(module->getLoc()) << "module declared here";
if (usingOp) {
auto diag = usingOp->emitOpError("parameter ")
<< nameAttr << " used with type " << parameterRef.getType()
<< "; should have type " << paramAttr.getType().getValue();
diag.attachNote(module->getLoc()) << "module declared here";
}
return failure();
}
auto diag = usingOp->emitOpError("use of unknown parameter ") << nameAttr;
diag.attachNote(module->getLoc()) << "module declared here";
if (usingOp) {
auto diag = usingOp->emitOpError("use of unknown parameter ") << nameAttr;
diag.attachNote(module->getLoc()) << "module declared here";
}
return failure();
}
return usingOp->emitOpError("invalid parameter value ") << value;
if (usingOp)
usingOp->emitOpError("invalid parameter value ") << value;
return failure();
}
/// Return true if the specified attribute tree is made up of nodes that are
/// valid in a parameter expression.
bool hw::isValidParameterExpression(Attribute attr, Operation *module) {
return succeeded(checkParameterInContext(attr, module, nullptr, false));
}
//===----------------------------------------------------------------------===//
@ -180,7 +194,7 @@ OpFoldResult ConstantOp::fold(ArrayRef<Attribute> constants) {
}
//===----------------------------------------------------------------------===//
// ConstantOp
// ParamValueOp
//===----------------------------------------------------------------------===//
static ParseResult parseParamValue(OpAsmParser &p, Attribute &value,
@ -197,6 +211,12 @@ static void printParamValue(OpAsmPrinter &p, Operation *, Attribute value,
p.printAttributeWithoutType(value);
}
static LogicalResult verifyParamValueOp(ParamValueOp op) {
// Check that the attribute expression is valid in this module.
return checkParameterInContext(op.value(),
op->getParentOfType<hw::HWModuleOp>(), op);
}
//===----------------------------------------------------------------------===//
// HWModuleOp
//===----------------------------------------------------------------------===/

View File

@ -269,3 +269,10 @@ hw.module @Use<xx: i41>() {
// expected-error @+1 {{op parameter "p" cannot be used as a default value for a parameter}}
hw.module.extern @p<p: i42 = #hw.param.decl.ref<"p">>() -> ()
// -----
// expected-note @+1 {{module declared here}}
hw.module @Use<xx: i41>() {
// expected-error @+1 {{'hw.param.value' op parameter "xx" used with type 'i40'; should have type 'i41'}}
%0 = hw.param.value i40 = #hw.param.decl.ref<"xx">
}