diff --git a/include/vast/CodeGen/DefaultStmtVisitor.hpp b/include/vast/CodeGen/DefaultStmtVisitor.hpp index f7e66c6b34..d199d5fc09 100644 --- a/include/vast/CodeGen/DefaultStmtVisitor.hpp +++ b/include/vast/CodeGen/DefaultStmtVisitor.hpp @@ -197,6 +197,7 @@ namespace vast::cg { operation VisitMemberExpr(const clang::MemberExpr *expr); operation VisitConditionalOperator(const clang::ConditionalOperator *op); operation VisitChooseExpr(const clang::ChooseExpr *expr); + operation VisitGenericSelectionExpr(const clang::GenericSelectionExpr *expr); operation VisitBinaryConditionalOperator(const clang::BinaryConditionalOperator *op); operation VisitAddrLabelExpr(const clang::AddrLabelExpr *expr); operation VisitConstantExpr(const clang::ConstantExpr *expr); diff --git a/include/vast/CodeGen/DefaultTypeVisitor.hpp b/include/vast/CodeGen/DefaultTypeVisitor.hpp index 3a1b7952ee..135fe1b01a 100644 --- a/include/vast/CodeGen/DefaultTypeVisitor.hpp +++ b/include/vast/CodeGen/DefaultTypeVisitor.hpp @@ -176,4 +176,6 @@ namespace vast::cg { mlir_type visit_as_lvalue_type(scoped_visitor_view visitor, mcontext_t &mctx, clang_qual_type ty); + mlir_type visit_as_maybe_lvalue_type(scoped_visitor_view visitor, mcontext_t &mctx, clang_qual_type ty); + } // namespace vast::cg diff --git a/include/vast/Dialect/HighLevel/HighLevelOps.td b/include/vast/Dialect/HighLevel/HighLevelOps.td index 3573854cba..f51a624ce6 100644 --- a/include/vast/Dialect/HighLevel/HighLevelOps.td +++ b/include/vast/Dialect/HighLevel/HighLevelOps.td @@ -1638,11 +1638,10 @@ def HighLevel_StaticAssertDecl let skipDefaultBuilders = 1; let builders = [ OpBuilder< (ins - "bool":$failed, - CArg< "builder_callback_ref" >:$assertBuilder, - CArg< "maybe_builder_callback_ref", "std::nullopt" >:$messageBuilder - ), - [{ + "bool":$failed, + CArg< "builder_callback_ref" >:$assertBuilder, + CArg< "maybe_builder_callback_ref", "std::nullopt" >:$messageBuilder + ), [{ $_state.addAttribute("failed", $_builder.getBoolAttr(failed)); InsertionGuard guard($_builder); @@ -1676,4 +1675,79 @@ def HighLevel_AttributedStmt let assemblyFormat = [{ attr-dict `:` $body }]; } +def HighLevel_GenericAssocExpr + : HighLevel_Op< "generic_asoc" > + , Arguments< (ins OptionalAttr< TypeAttr >:$matchType) > + , Results< (outs AnyType:$result) > +{ + let summary = "Op representing single case of _Generic expression."; + let regions = (region AnyRegion:$body); + + let skipDefaultBuilders = 1; + let builders = [ + OpBuilder< (ins + "Type":$type, + CArg< "builder_callback_ref" >:$bodyBuilder, + CArg< "mlir::Type", "mlir::Type()" >:$matchType + ), [{ + $_state.addTypes(type); + InsertionGuard guard($_builder); + if (matchType) { + $_state.addAttribute("matchType", mlir::TypeAttr::get(matchType)); + } + build_region($_builder, $_state, bodyBuilder); + }] > + ]; + + let assemblyFormat = [{ attr-dict (`match` $matchType^)? `:` $body `->` type($result) }]; +} + +def HighLevel_GenericSelectionExpr + : HighLevel_Op< "generic_expr", [NoTerminator] > + , Arguments< (ins OptionalAttr< TypeAttr >:$controlType, OptionalAttr< IndexAttr >:$selected) > + , Results< (outs AnyType:$result) > +{ + let summary = "C11 _Generic expression."; + let regions = (region AnyRegion:$control, AnyRegion:$body); + + let skipDefaultBuilders = 1; + let builders = [ + OpBuilder< (ins + "Type":$type, + CArg< "builder_callback_ref" >:$controlBuilder, + CArg< "builder_callback_ref" >:$bodyBuilder, + CArg< "std::optional< unsigned >", "std::nullopt" >:$selected + ), [{ + $_state.addTypes(type); + InsertionGuard guard($_builder); + if (selected) + $_state.addAttribute("selected", $_builder.getIndexAttr(selected.value())); + build_region($_builder, $_state, controlBuilder); + build_region($_builder, $_state, bodyBuilder); + }] >, + OpBuilder< (ins + "Type":$type, + "mlir::Type":$controlType, + CArg< "builder_callback_ref" >:$bodyBuilder, + CArg< "std::optional< unsigned >", "std::nullopt" >:$selected + ), [{ + $_state.addTypes(type); + InsertionGuard guard($_builder); + $_state.addAttribute("controlType", mlir::TypeAttr::get(controlType)); + if (selected) + $_state.addAttribute("selected", $_builder.getIndexAttr(selected.value())); + $_state.addRegion(); + build_region($_builder, $_state, bodyBuilder); + }] > + ]; + + let extraClassDeclaration = [{ + std::optional< mlir::Region *> getResultRegion(); + bool isExprPredicate(); + bool isTypePredicate(); + }]; + + let assemblyFormat = [{ attr-dict `match` (`region` `:` $control^)? (`type` `:` $controlType^)? $body `->` type($result)}]; +} + #endif // VAST_DIALECT_HIGHLEVEL_IR_HIGHLEVELOPS diff --git a/lib/vast/CodeGen/DefaultStmtVisitor.cpp b/lib/vast/CodeGen/DefaultStmtVisitor.cpp index 46a10865e8..92ab936de2 100644 --- a/lib/vast/CodeGen/DefaultStmtVisitor.cpp +++ b/lib/vast/CodeGen/DefaultStmtVisitor.cpp @@ -862,6 +862,47 @@ namespace vast::cg .freeze(); } + operation default_stmt_visitor::VisitGenericSelectionExpr(const clang::GenericSelectionExpr *expr) { + auto mk_assoc = [&] (const clang::GenericSelectionExpr::ConstAssociation &assoc) -> operation { + auto assoc_type = assoc.getType(); + auto assoc_expr = assoc.getAssociationExpr(); + auto type = assoc_type.isNull() ? mlir::Type() : self.visit(assoc_type); + return bld.compose< hl::GenericAssocExpr >() + .bind(self.location(expr)) + .bind(visit_as_maybe_lvalue_type(self, mctx, assoc_expr->getType())) + .bind(mk_value_builder(assoc_expr)) + .bind_if_valid(type) + .freeze(); + }; + auto mk_body = [&] (auto &state, auto loc) { + for (const auto &assoc : expr->associations()) { + mk_assoc(assoc); + } + }; + + if (expr->isExprPredicate()) { + return bld.compose< hl::GenericSelectionExpr >() + .bind(self.location(expr)) + .bind(visit_maybe_lvalue_result_type(expr)) + .bind(mk_type_yield_builder(expr->getControllingExpr())) + .bind(mk_body) + .bind_always(expr->isValueDependent() ? std::nullopt : std::optional(expr->getResultIndex())) + .freeze(); + } + if (expr->isTypePredicate()) { + return bld.compose< hl::GenericSelectionExpr >() + .bind(self.location(expr)) + .bind(visit_maybe_lvalue_result_type(expr)) + .bind(self.visit(expr->getControllingType()->getType())) + .bind(mk_body) + .bind_always(expr->isValueDependent() ? std::nullopt : std::optional(expr->getResultIndex())) + .freeze(); + } + VAST_REPORT("Generic expr didn't match any predicate type. Is it valid?"); + expr->dump(); + return {}; + } + operation default_stmt_visitor::VisitBinaryConditionalOperator(const clang::BinaryConditionalOperator *op) { auto common_type = self.visit(op->getCommon()->getType()); return bld.compose< hl::BinaryCondOp >() diff --git a/lib/vast/CodeGen/DefaultTypeVisitor.cpp b/lib/vast/CodeGen/DefaultTypeVisitor.cpp index 57fefdbdae..b784b30c42 100644 --- a/lib/vast/CodeGen/DefaultTypeVisitor.cpp +++ b/lib/vast/CodeGen/DefaultTypeVisitor.cpp @@ -512,6 +512,12 @@ namespace vast::cg { return hl::LValueType::get(&mctx, element_type); } + mlir_type visit_as_maybe_lvalue_type(scoped_visitor_view visitor, mcontext_t &mctx, clang_qual_type ty) { + if (ty->isLValueReferenceType()) { + return visit_as_lvalue_type(visitor, mctx, ty); + } + return visitor.visit(ty); + } } // namespace vast::hl diff --git a/lib/vast/Dialect/HighLevel/HighLevelOps.cpp b/lib/vast/Dialect/HighLevel/HighLevelOps.cpp index 9902de3007..2cc99c1333 100644 --- a/lib/vast/Dialect/HighLevel/HighLevelOps.cpp +++ b/lib/vast/Dialect/HighLevel/HighLevelOps.cpp @@ -869,6 +869,27 @@ namespace vast::hl return std::optional(getCompatibleAttr().getValue()); } + // + // GenericSelectionExpr + // + + std::optional< region_t *> GenericSelectionExpr::getResultRegion() { + if (auto selected = getSelected()) { + auto op_it = getBody().op_begin(); + std::advance(op_it, selected.value().getZExtValue()); + if (auto assoc = mlir::dyn_cast< hl::GenericAssocExpr >(*op_it)) + return { &assoc.getBody() }; + } + return std::nullopt; + } + + bool GenericSelectionExpr::isExprPredicate() { + return !getControl().empty(); + } + + bool GenericSelectionExpr::isTypePredicate() { + return (*this)->hasAttr("matchType"); + } } //===----------------------------------------------------------------------===// diff --git a/test/vast/Dialect/HighLevel/generic-expr-a.c b/test/vast/Dialect/HighLevel/generic-expr-a.c new file mode 100644 index 0000000000..b5bf23c199 --- /dev/null +++ b/test/vast/Dialect/HighLevel/generic-expr-a.c @@ -0,0 +1,39 @@ +// RUN: %vast-cc1 -vast-emit-mlir=hl %s -o - | %file-check %s +// RUN: %vast-cc1 -vast-emit-mlir=hl %s -o %t && %vast-opt %t | diff -B %t - +// +void foo() { + // character literal in C matches int + // CHECK: hl.generic_expr {selected = 1 : index} match region : { + // CHECK: hl.type.yield {{%[0-9]+}} : !hl.int + // CHECK: hl.generic_asoc match !hl.char + // CHECK: hl.value.yield + // CHECK: hl.generic_asoc match !hl.int + // CHECK: hl.value.yield + // CHECK: hl.generic_asoc : { + // CHECK: hl.value.yield + int x = _Generic('x', char: "2", int: 1, default: 3); + // CHECK: hl.generic_expr {selected = 1 : index} match type : !hl.int { + // CHECK: hl.generic_asoc match !hl.char + // CHECK: hl.value.yield + // CHECK: hl.generic_asoc match !hl.int + // CHECK: hl.value.yield + // CHECK: hl.generic_asoc : { + // CHECK: hl.value.yield + x = _Generic(int, char: "2", int: 1, default: 3); + // CHECK: hl.generic_expr {selected = 2 : index} match type : !hl.float { + // CHECK: hl.generic_asoc match !hl.char + // CHECK: hl.value.yield + // CHECK: hl.generic_asoc match !hl.int + // CHECK: hl.value.yield + // CHECK: hl.generic_asoc : { + // CHECK: hl.value.yield + x = _Generic(float, char: "2", int: 1, default: 3); + // CHECK: hl.generic_expr {selected = 1 : index} match type : !hl.float { + // CHECK: hl.generic_asoc match !hl.int + // CHECK: hl.value.yield + // CHECK: hl.generic_asoc : { + // CHECK: hl.value.yield + // CHECK: hl.generic_asoc match !hl.char + // CHECK: hl.value.yield + x = _Generic(float, int: 1, default: 3, char: "2"); +}