69 tables, origin, ArrayRef<ArrayRef<Type>> {funcType.getInputs(), funcType.getResults()}
77static LogicalResult verifyArgOrResNameAttrs(
78 ArrayAttr attrs, StringRef ownAttrName, StringRef crossAttrName, StringRef ownLabel,
84 llvm::DenseSet<StringAttr> seenNames;
85 for (
auto [i, attr] : llvm::enumerate(attrs)) {
86 auto dictAttr = llvm::dyn_cast<DictionaryAttr>(attr);
90 if (dictAttr.contains(crossAttrName)) {
91 return emitFn().append(
92 '\'', crossAttrName,
"' is only valid on function ", crossLabel,
"s but found on ",
96 Attribute nameAttr = dictAttr.get(ownAttrName);
100 auto name = llvm::dyn_cast<StringAttr>(nameAttr);
102 return emitFn().append(
103 '\'', ownAttrName,
"' on ", ownLabel,
' ', i,
" must be a string attribute"
106 if (!llvm::isa<NoneType>(name.getType())) {
107 return emitFn().append(
108 '\'', ownAttrName,
"' on ", ownLabel,
' ', i,
" must not have an explicit type"
111 if (name.getValue().empty()) {
112 return emitFn().append(
'\'', ownAttrName,
"' on ", ownLabel,
' ', i,
" must not be empty");
114 if (!seenNames.insert(name).second) {
115 return emitFn().append(
116 "duplicate '", ownAttrName,
"' value \"", name.getValue(),
"\" on ", ownLabel,
' ', i
123static std::optional<StringAttr>
124getFunctionNameAttrAtIndex(ArrayAttr attrs,
unsigned index, StringRef attrName) {
125 if (!attrs || index >= attrs.size()) {
128 if (
auto dictAttr = llvm::dyn_cast<DictionaryAttr>(attrs[index])) {
129 if (
auto nameAttr = llvm::dyn_cast_if_present<StringAttr>(dictAttr.get(attrName))) {
142 Location location, StringRef name, FunctionType type, ArrayRef<NamedAttribute> attrs
148 Location location, StringRef name, FunctionType type, Operation::dialect_attr_range attrs
150 SmallVector<NamedAttribute, 8> attrRef(attrs);
151 return create(location, name, type, llvm::ArrayRef(attrRef));
155 Location location, StringRef name, FunctionType type, ArrayRef<NamedAttribute> attrs,
156 ArrayRef<DictionaryAttr> argAttrs
158 FuncDefOp func =
create(location, name, type, attrs);
159 func.setAllArgAttrs(argAttrs);
164 OpBuilder &builder, OperationState &state, StringRef name, FunctionType type,
165 ArrayRef<NamedAttribute> attrs, ArrayRef<DictionaryAttr> argAttrs
167 state.addAttribute(SymbolTable::getSymbolAttrName(), builder.getStringAttr(name));
169 state.attributes.append(attrs.begin(), attrs.end());
172 if (argAttrs.empty()) {
175 assert(type.getNumInputs() == argAttrs.size());
176 call_interface_impl::addArgAndResultAttrs(
183 auto buildFuncType = [](Builder &builder, ArrayRef<Type> argTypes, ArrayRef<Type> results,
184 function_interface_impl::VariadicFlag,
185 std::string &) {
return builder.getFunctionType(argTypes, results); };
187 return function_interface_impl::parseFunctionOp(
194 function_interface_impl::printFunctionOp(
204 llvm::MapVector<StringAttr, Attribute> newAttrMap;
205 for (
const auto &attr : dest->getAttrs()) {
206 newAttrMap.insert({attr.getName(), attr.getValue()});
208 for (
const auto &attr : (*this)->getAttrs()) {
209 newAttrMap.insert({attr.getName(), attr.getValue()});
213 llvm::to_vector(llvm::map_range(newAttrMap, [](std::pair<StringAttr, Attribute> attrPair) {
214 return NamedAttribute(attrPair.first, attrPair.second);
216 dest->setAttrs(DictionaryAttr::get(getContext(), newAttrs));
229 FuncDefOp newFunc = llvm::cast<FuncDefOp>(getOperation()->cloneWithoutRegions());
237 unsigned oldNumArgs = oldType.getNumInputs();
238 SmallVector<Type, 4> newInputs;
239 newInputs.reserve(oldNumArgs);
240 for (
unsigned i = 0; i != oldNumArgs; ++i) {
241 if (!mapper.contains(getArgument(i))) {
242 newInputs.push_back(oldType.getInput(i));
248 if (newInputs.size() != oldNumArgs) {
249 newFunc.setType(FunctionType::get(oldType.getContext(), newInputs, oldType.getResults()));
251 if (ArrayAttr argAttrs = getAllArgAttrs()) {
252 SmallVector<Attribute> newArgAttrs;
253 newArgAttrs.reserve(newInputs.size());
254 for (
unsigned i = 0; i != oldNumArgs; ++i) {
255 if (!mapper.contains(getArgument(i))) {
256 newArgAttrs.push_back(argAttrs[i]);
259 newFunc.setAllArgAttrs(newArgAttrs);
271 return clone(mapper);
276 getOperation()->setAttr(AllowConstraintAttr::name, UnitAttr::get(getContext()));
278 getOperation()->removeAttr(AllowConstraintAttr::name);
284 getOperation()->setAttr(AllowWitnessAttr::name, UnitAttr::get(getContext()));
286 getOperation()->removeAttr(AllowWitnessAttr::name);
292 getOperation()->setAttr(AllowNonNativeFieldOpsAttr::name, UnitAttr::get(getContext()));
294 getOperation()->removeAttr(AllowNonNativeFieldOpsAttr::name);
300 getOperation()->setAttr(AllowVerifOpsAttr::name, UnitAttr::get(getContext()));
302 getOperation()->removeAttr(AllowVerifOpsAttr::name);
307 if (index < this->getNumArguments()) {
308 DictionaryAttr res = function_interface_impl::getArgAttrDict(*
this, index);
309 return res ? res.contains(PublicAttr::name) :
false;
323 assert(index < getNumArguments() &&
"argument index out of range");
338 assert(index < getNumResults() &&
"result index out of range");
350 return emitErrorFunc() <<
'\'' <<
ARG_NAME_ATTR_NAME <<
"' is only valid on function arguments";
353 return emitErrorFunc() <<
'\'' <<
RES_NAME_ATTR_NAME <<
"' is only valid on function results";
356 if (failed(verifyArgOrResNameAttrs(
363 if (failed(verifyArgOrResNameAttrs(
375 for (Type t : type.getInputs()) {
380 return emitErrorFunc().append(
381 "\"@", getName(),
"\" parameters cannot contain affine map attributes but found ", t
385 for (Type t : type.getResults()) {
393 WalkResult res = this->walk<WalkOrder::PreOrder>([
this](ModuleOp nestedMod) {
395 "cannot be nested within '", getOperation()->getName(),
"' operations"
397 return WalkResult::interrupt();
399 if (res.wasInterrupted()) {
411 llvm::ArrayRef<Type> resTypes = funcType.getResults();
413 if (resTypes.size() != 1) {
414 return origin.emitOpError().append(
418 if (failed(
checkSelfType(tables, parent, resTypes.front(), origin,
"return"))) {
429verifyFuncTypeProduct(
FuncDefOp &origin, SymbolTableCollection &tables, StructDefOp &parent) {
431 return verifyFuncTypeCompute(origin, tables, parent);
435verifyFuncTypeConstrain(
FuncDefOp &origin, SymbolTableCollection &tables, StructDefOp &parent) {
438 if (funcType.getResults().size() != 0) {
439 return origin.emitOpError() <<
"\"@" <<
FUNC_NAME_CONSTRAIN <<
"\" must have no return type";
443 llvm::ArrayRef<Type> inputTypes = funcType.getInputs();
444 if (inputTypes.size() < 1) {
446 <<
"\" must have at least one input type";
448 if (failed(
checkSelfType(tables, parent, inputTypes.front(), origin,
"first input"))) {
466 return verifyFuncTypeCompute(*
this, tables, parentStructOpt);
468 return verifyFuncTypeConstrain(*
this, tables, parentStructOpt);
470 return verifyFuncTypeProduct(*
this, tables, parentStructOpt);
483static Value getSelfValueFromWitnessGen(
FuncDefOp funcDefOp, Twine name) {
485 Region &body = funcDefOp.
getBody();
486 ensure(!body.empty(), name +
"() function body must not be empty");
489 Operation *terminator = body.back().getTerminator();
490 ensure(terminator, name +
"() function must have a terminator op");
491 auto retOp = llvm::dyn_cast<ReturnOp>(terminator);
494 << terminator->getName() <<
"'\n";
495 ensure(
false, name +
"() function must end with ReturnOp");
497 return retOp.getOperands().front();
504 return getSelfValueFromWitnessGen(*
this,
"compute");
509 return getSelfValueFromWitnessGen(*
this,
"product");
514 return getArguments().front();
527 auto function = getParentOp<FuncDefOp>();
530 const auto results =
function.getFunctionType().getResults();
531 if (getNumOperands() != results.size()) {
532 return emitOpError(
"has ") << getNumOperands() <<
" operands, but enclosing function (@"
533 <<
function.getName() <<
") returns " << results.size();
536 for (
unsigned i = 0, e = results.size(); i != e; ++i) {
537 if (!
typesUnify(getOperand(i).getType(), results[i])) {
538 return emitError() <<
"type of return operand " << i <<
" (" << getOperand(i).getType()
539 <<
") doesn't match function result type (" << results[i] <<
')'
540 <<
" in function @" <<
function.getName();
554 auto &prop = state.getOrAddProperties<
Properties>();
555 if (failed(reader.readAttribute(prop.callee)) ||
556 failed(reader.readAttribute(prop.mapOpGroupSizes)) ||
557 failed(reader.readOptionalAttribute(prop.numDimsPerMap))) {
561 if (reader.getBytecodeVersion() < 6) {
562 auto &propStorage = prop.operandSegmentSizes;
563 DenseI32ArrayAttr attr;
564 if (failed(reader.readAttribute(attr))) {
567 if (attr.size() >
static_cast<int64_t
>(
sizeof(propStorage) /
sizeof(int32_t))) {
568 return reader.emitError(
"size mismatch for operand/result_segment_size");
570 llvm::copy(ArrayRef<int32_t>(attr), propStorage.begin());
575 if (succeeded(versionOpt)) {
577 if (ver.majorVersion >= 2) {
578 if (failed(reader.readOptionalAttribute(prop.templateParams))) {
584 if (reader.getBytecodeVersion() >= 6) {
585 return reader.readSparseArray(MutableArrayRef(prop.operandSegmentSizes));
592 auto &prop = getProperties();
593 writer.writeAttribute(prop.callee);
594 writer.writeAttribute(prop.mapOpGroupSizes);
595 writer.writeOptionalAttribute(prop.numDimsPerMap);
597 if (writer.getBytecodeVersion() < 6) {
598 auto &propStorage = prop.operandSegmentSizes;
599 writer.writeAttribute(DenseI32ArrayAttr::get(this->getContext(), propStorage));
602 writer.writeOptionalAttribute(prop.templateParams);
604 auto &propStorage = prop.operandSegmentSizes;
605 if (writer.getBytecodeVersion() >= 6) {
606 writer.writeSparseArray(ArrayRef(propStorage));
611 OpBuilder &odsBuilder, OperationState &odsState, TypeRange resultTypes, SymbolRefAttr callee,
612 ValueRange argOperands, ArrayRef<Attribute> templateParams
614 odsState.addTypes(resultTypes);
615 odsState.addOperands(argOperands);
619 props.setCallee(callee);
624 OpBuilder &odsBuilder, OperationState &odsState, TypeRange resultTypes, SymbolRefAttr callee,
625 ArrayRef<ValueRange> mapOperands, DenseI32ArrayAttr numDimsPerMap, ValueRange argOperands,
626 ArrayRef<Attribute> templateParams
628 odsState.addTypes(resultTypes);
629 odsState.addOperands(argOperands);
631 odsBuilder, odsState, mapOperands, numDimsPerMap,
634 props.setCallee(callee);
640struct CallOpVerifier {
641 CallOpVerifier(
CallOp *c,
FunctionKind tgtFuncKind) : callOp(c), tgtKind(tgtFuncKind) {}
642 CallOpVerifier(CallOp *c, StringRef tgtName) : CallOpVerifier(c,
fnNameToKind(tgtName)) {}
643 virtual ~CallOpVerifier() =
default;
645 LogicalResult verify() {
648 LogicalResult aggregateResult = success();
649 if (failed(verifyTargetAttributes())) {
650 aggregateResult = failure();
652 if (failed(verifyInputs())) {
653 aggregateResult = failure();
655 if (failed(verifyOutputs())) {
656 aggregateResult = failure();
658 if (failed(verifyTemplateParams())) {
659 aggregateResult = failure();
661 if (failed(verifyAffineMapParams())) {
662 aggregateResult = failure();
664 return aggregateResult;
671 virtual LogicalResult verifyTargetAttributes() = 0;
672 virtual LogicalResult verifyInputs() = 0;
673 virtual LogicalResult verifyOutputs() = 0;
674 virtual LogicalResult verifyTemplateParams() = 0;
675 virtual LogicalResult verifyAffineMapParams() = 0;
678 LogicalResult verifyTargetAttributesMatch(FuncDefOp target) {
679 LogicalResult aggregateRes = success();
680 if (FuncDefOp caller = (*callOp)->getParentOfType<FuncDefOp>()) {
681 auto emitAttrErr = [&](StringLiteral attrName) {
682 aggregateRes = callOp->emitOpError()
683 <<
"target '@" << target.getName() <<
"' has '" << attrName
684 <<
"' attribute, which is not specified by the caller '@" << caller.getName()
689 emitAttrErr(AllowConstraintAttr::name);
692 emitAttrErr(AllowWitnessAttr::name);
695 emitAttrErr(AllowNonNativeFieldOpsAttr::name);
701 LogicalResult verifyNoTemplateInstantiations() {
704 return callOp->emitOpError().append(
705 "can only have template instantiations when targeting a templated free function"
711 LogicalResult verifyNoAffineMapInstantiations() {
714 return callOp->emitOpError().append(
715 "can only have affine map instantiations when targeting a \"@",
FUNC_NAME_COMPUTE,
721 assert(callOp->getMapOperands().empty());
726struct KnownTargetVerifier :
public CallOpVerifier {
727 KnownTargetVerifier(CallOp *c, SymbolLookupResult<FuncDefOp> &&tgtRes)
728 : CallOpVerifier(c, tgtRes.get().getSymName()), shared(c, tgtRes) {}
730 LogicalResult verifyTargetAttributes()
override {
731 return CallOpVerifier::verifyTargetAttributesMatch(shared.getTarget());
734 LogicalResult verifyInputs()
override {
735 return shared.verifyTypesMatch(
736 callOp->
getArgOperands().getTypes(), shared.getTargetType().getInputs(),
"operand"
740 LogicalResult verifyOutputs()
override {
741 return shared.verifyTypesMatch(
742 callOp->getResultTypes(), shared.getTargetType().getResults(),
"result"
746 LogicalResult verifyTemplateParams()
override {
747 Operation *tgtOp = shared.getTarget().getOperation();
750 return verifyNoTemplateInstantiations();
752 return shared.verifyTemplateInstantiation(tgtOpParent);
755 return verifyNoTemplateInstantiations();
759 LogicalResult verifyAffineMapParams()
override {
761 isInStruct(shared.getTarget().getOperation())) {
767 if (ArrayAttr params = retTy.getParams()) {
769 SmallVector<AffineMapAttr> mapAttrs;
770 for (Attribute a : params) {
771 if (AffineMapAttr m = dyn_cast<AffineMapAttr>(a)) {
772 mapAttrs.push_back(m);
783 return verifyNoAffineMapInstantiations();
788 llzk::KnownTargetVerifier<CallOp, FuncDefOp> shared;
793LogicalResult checkSelfTypeUnknownTarget(
794 StringAttr expectedParamName, Type actualType,
CallOp *origin,
const char *aspect
796 if (!llvm::isa<TypeVarType>(actualType) ||
797 llvm::cast<TypeVarType>(actualType).getRefName() != expectedParamName) {
803 return origin->emitOpError().append(
804 "target \"@", origin->
getCallee().getLeafReference().getValue(),
"\" expected ", aspect,
805 " type '!",
TypeVarType::name,
"<@", expectedParamName.getValue(),
">' but found ",
821struct UnknownTargetVerifier :
public CallOpVerifier {
822 UnknownTargetVerifier(CallOp *c,
FunctionKind tgtFuncKind, SymbolRefAttr callee)
823 : CallOpVerifier(c, tgtFuncKind), calleeAttr(callee) {
830 LogicalResult verifyTargetAttributes()
override {
833 LogicalResult aggregateRes = success();
834 if (FuncDefOp caller = (*callOp)->getParentOfType<FuncDefOp>()) {
835 auto emitAttrErr = [&](StringLiteral attrName) {
836 aggregateRes = callOp->emitOpError()
837 <<
"target '" << calleeAttr <<
"' has '" << attrName
838 <<
"' attribute, which is not specified by the caller '@" << caller.getName()
844 if (!caller.hasAllowConstraintAttr()) {
845 emitAttrErr(AllowConstraintAttr::name);
849 if (!caller.hasAllowWitnessAttr()) {
850 emitAttrErr(AllowWitnessAttr::name);
854 if (!caller.hasAllowWitnessAttr()) {
855 emitAttrErr(AllowWitnessAttr::name);
857 if (!caller.hasAllowConstraintAttr()) {
858 emitAttrErr(AllowConstraintAttr::name);
868 LogicalResult verifyInputs()
override {
874 Operation::operand_type_range inputTypes = callOp->
getArgOperands().getTypes();
875 if (inputTypes.size() < 1) {
877 return callOp->emitOpError()
880 return checkSelfTypeUnknownTarget(
881 calleeAttr.getRootReference(), inputTypes.front(), callOp,
"first input"
887 LogicalResult verifyOutputs()
override {
891 Operation::result_type_range resTypes = callOp->getResultTypes();
892 if (resTypes.size() != 1) {
894 return callOp->emitOpError().append(
898 return checkSelfTypeUnknownTarget(
899 calleeAttr.getRootReference(), resTypes.front(), callOp,
"return"
903 if (callOp->getNumResults() != 0) {
905 return callOp->emitOpError()
912 LogicalResult verifyTemplateParams()
override {
914 return verifyNoTemplateInstantiations();
917 LogicalResult verifyAffineMapParams()
override {
922 return verifyNoAffineMapInstantiations();
928 SymbolRefAttr calleeAttr;
942 return emitOpError(
"requires a 'callee' symbol reference attribute");
947 if (calleeAttr.getNestedReferences().size() == 1) {
949 if (parent.hasConstNamed<
TemplateParamOp>(calleeAttr.getRootReference())) {
952 return UnknownTargetVerifier(
this, tgtKind, calleeAttr).verify();
954 return this->emitError(
"expected parameterized callee to target a struct function")
966 if (failed(tgtOpt)) {
968 << calleeAttr <<
'"';
970 return KnownTargetVerifier(
this, std::move(*tgtOpt)).verify();
975bool calleeIsStructFunctionImpl(
976 const char *funcName, SymbolRefAttr callee, llvm::function_ref<
StructType()> getType
978 if (callee.getLeafReference() == funcName) {
1012 return getResults().front();
1017 return getResults().front();
1038 Operation *thisOp = this->getOperation();
1040 assert(succeeded(root));
1063 FailureOr<SymbolLookupResult<FuncDefOp>> res =
1065 if (failed(res) || res->isManaged()) {
1073 SymbolTableCollection tables;