Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for _Generic #720

Merged
merged 13 commits into from
Sep 11, 2024
Merged
1 change: 1 addition & 0 deletions include/vast/CodeGen/DefaultStmtVisitor.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
2 changes: 2 additions & 0 deletions include/vast/CodeGen/DefaultTypeVisitor.hpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (c) 2022-present, Trail of Bits, Inc.

Check notice on line 1 in include/vast/CodeGen/DefaultTypeVisitor.hpp

View workflow job for this annotation

GitHub Actions / cpp-linter (18, 22.04)

Run clang-format on include/vast/CodeGen/DefaultTypeVisitor.hpp

File include/vast/CodeGen/DefaultTypeVisitor.hpp does not conform to Custom style guidelines. (lines 179)

#pragma once

Expand Down Expand Up @@ -176,4 +176,6 @@

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
84 changes: 79 additions & 5 deletions include/vast/Dialect/HighLevel/HighLevelOps.td
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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
41 changes: 41 additions & 0 deletions lib/vast/CodeGen/DefaultStmtVisitor.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (c) 2022-present, Trail of Bits, Inc.

Check notice on line 1 in lib/vast/CodeGen/DefaultStmtVisitor.cpp

View workflow job for this annotation

GitHub Actions / cpp-linter (18, 22.04)

Run clang-format on lib/vast/CodeGen/DefaultStmtVisitor.cpp

File lib/vast/CodeGen/DefaultStmtVisitor.cpp does not conform to Custom style guidelines. (lines 865, 866, 877, 889, 898)

#include "vast/Util/Warnings.hpp"

Expand Down Expand Up @@ -862,6 +862,47 @@
.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 >()
Expand Down
6 changes: 6 additions & 0 deletions lib/vast/CodeGen/DefaultTypeVisitor.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (c) 2024, Trail of Bits, Inc.

Check notice on line 1 in lib/vast/CodeGen/DefaultTypeVisitor.cpp

View workflow job for this annotation

GitHub Actions / cpp-linter (18, 22.04)

Run clang-format on lib/vast/CodeGen/DefaultTypeVisitor.cpp

File lib/vast/CodeGen/DefaultTypeVisitor.cpp does not conform to Custom style guidelines. (lines 515, 520)

#include "vast/CodeGen/DefaultTypeVisitor.hpp"

Expand Down Expand Up @@ -512,6 +512,12 @@
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
21 changes: 21 additions & 0 deletions lib/vast/Dialect/HighLevel/HighLevelOps.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (c) 2021-present, Trail of Bits, Inc.

Check notice on line 1 in lib/vast/Dialect/HighLevel/HighLevelOps.cpp

View workflow job for this annotation

GitHub Actions / cpp-linter (18, 22.04)

Run clang-format on lib/vast/Dialect/HighLevel/HighLevelOps.cpp

File lib/vast/Dialect/HighLevel/HighLevelOps.cpp does not conform to Custom style guidelines. (lines 876, 880, 881, 886, 887, 890, 891)

#include "vast/Util/Warnings.hpp"

Expand Down Expand Up @@ -869,6 +869,27 @@
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");
}
}

//===----------------------------------------------------------------------===//
Expand Down
39 changes: 39 additions & 0 deletions test/vast/Dialect/HighLevel/generic-expr-a.c
Original file line number Diff line number Diff line change
@@ -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");
}