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

Implement ChooseExpr #715

Merged
merged 11 commits into from
Sep 4, 2024
1 change: 1 addition & 0 deletions include/vast/CodeGen/DefaultStmtVisitor.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,7 @@ namespace vast::cg {

operation VisitMemberExpr(const clang::MemberExpr *expr);
operation VisitConditionalOperator(const clang::ConditionalOperator *op);
operation VisitChooseExpr(const clang::ChooseExpr *expr);
operation VisitBinaryConditionalOperator(const clang::BinaryConditionalOperator *op);
operation VisitAddrLabelExpr(const clang::AddrLabelExpr *expr);
operation VisitConstantExpr(const clang::ConstantExpr *expr);
Expand Down
89 changes: 84 additions & 5 deletions include/vast/Dialect/HighLevel/HighLevelCF.td
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ class HighLevel_ControlFlowOp< string mnemonic, list< Trait > traits = [] >
def HighLevel_CondYieldOp
: HighLevel_Op< "cond.yield", [
// TODO(Heno): add ReturnLike trait
Terminator, ParentOneOf<["IfOp", "WhileOp", "ForOp", "DoOp", "CondOp", "BinaryCondOp"]>
Terminator, ParentOneOf<["IfOp", "WhileOp", "ForOp", "DoOp", "CondOp", "ChooseExprOp", "BinaryCondOp"]>
] >
{
let summary = "condition yield operation";
Expand Down Expand Up @@ -130,11 +130,11 @@ def HighLevel_IfOp
let hasCustomAssemblyFormat = 1;
}

def HighLevel_CondOp
: HighLevel_ControlFlowOp< "cond" >
class HighLevel_CondOpBase< string mnemonic, list< Trait > traits = [] >

: HighLevel_ControlFlowOp< mnemonic, traits >
, Results<(outs AnyType:$result)>
{
let summary = "VAST conditional statement";
let description = [{
The operation takes builders of three regions -- condition, true branch and false branch.
Builders, given the location, build a particular region.
Expand Down Expand Up @@ -166,12 +166,91 @@ def HighLevel_CondOp
"builder_callback_ref":$condBuilder,
"builder_callback_ref":$thenBuilder,
"builder_callback_ref":$elseBuilder
)>
), [{
InsertionGuard guard($_builder);
build_region($_builder, $_state, condBuilder);
build_region($_builder, $_state, thenBuilder);
build_region($_builder, $_state, elseBuilder);
$_state.addTypes(type);
}] >
];

let assemblyFormat = [{ attr-dict `:` type(results) $condRegion `?` $thenRegion `:` $elseRegion }];
}

def HighLevel_CondOp : HighLevel_CondOpBase< "cond" > {
Jezurko marked this conversation as resolved.
Show resolved Hide resolved
let summary = "VAST conditional statement";
}

def HighLevel_ChooseExprOp : HighLevel_ControlFlowOp< "choose_expr" >
, Arguments<(ins OptionalAttr< BoolAttr >:$condTrue)>
, Results<(outs AnyType:$result)>
{
let summary = "Representation of GNU __builtin_choose_expr";

let description = [{
The operation takes builders of three regions -- condition, true branch and false branch.
Builders, given the location, build a particular region.

The generic form of the operation is as follows:

hl.cond {
... /* condition region */
hl.cond.yield %cond : !hl.bool
} ? {
... /* true region */
} : {
... /* false region */
}
}];

let regions = (region
Core_CondRegion:$condRegion,
Core_ValueRegion:$thenRegion,
Core_ValueRegion:$elseRegion
);

let skipDefaultBuilders = 1;
let builders = [
OpBuilder<(ins
"Type":$type,
"builder_callback_ref":$condBuilder,
"builder_callback_ref":$thenBuilder,
"builder_callback_ref":$elseBuilder,
CArg<"std::optional< bool >", "std::nullopt">:$condTrue
), [{
InsertionGuard guard($_builder);
build_region($_builder, $_state, condBuilder);
build_region($_builder, $_state, thenBuilder);
build_region($_builder, $_state, elseBuilder);
if (condTrue) {
$_state.addAttribute("condTrue", $_builder.getBoolAttr(condTrue.value()));
}
$_state.addTypes(type);
}] >
];

let extraClassDeclaration = [{
std::optional< bool > isConditionTrue() {
if (auto cond = getCondTrue()) {
return cond.value();
}
return {};
}

bool isConditionDependent() { return (bool) getCondTrueAttr(); }

region_ptr getChosenSubExpr() {
if (auto cond = isConditionTrue()) {
return cond.value() ? &getThenRegion() : &getElseRegion();
}
return {};
}
}];

let assemblyFormat = [{ attr-dict (`cond` $condTrue^)? `:` type(results) $condRegion `?` $thenRegion `:` $elseRegion }];
}

def HighLevel_BinaryCondOp
: HighLevel_Op<
"binary_cond",
Expand Down
12 changes: 12 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 861)

#include "vast/Util/Warnings.hpp"

Expand Down Expand Up @@ -850,6 +850,18 @@
.freeze();
}

operation default_stmt_visitor::VisitChooseExpr(const clang::ChooseExpr *expr) {
return bld.compose< hl::ChooseExprOp >()
.bind(self.location(expr))
// ChooseExpr conserves everything including lvalue-ness
.bind(visit_maybe_lvalue_result_type(expr))
.bind_always(mk_cond_builder(expr->getCond()))
.bind_always(mk_value_builder(expr->getLHS()))
.bind_always(mk_value_builder(expr->getRHS()))
.bind_always(expr->isConditionDependent() ? std::nullopt : std::optional(expr->isConditionTrue()))
.freeze();
}

operation default_stmt_visitor::VisitBinaryConditionalOperator(const clang::BinaryConditionalOperator *op) {
auto common_type = self.visit(op->getCommon()->getType());
return bld.compose< hl::BinaryCondOp >()
Expand Down
13 changes: 1 addition & 12 deletions lib/vast/Dialect/HighLevel/HighLevelOps.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -569,18 +569,6 @@ namespace vast::hl
build_region(bld, st, else_builder);
}

void CondOp::build(
Builder &bld, State &st, Type type,
builder_callback_ref cond,
builder_callback_ref then_builder,
builder_callback_ref else_builder
) {
InsertionGuard guard(bld);
build_region(bld, st, cond);
build_region(bld, st, then_builder);
build_region(bld, st, else_builder);
st.addTypes(type);
}
void BinaryCondOp::build(
Builder &bld, State &st, Type type,
builder_callback_ref common_builder,
Expand Down Expand Up @@ -827,6 +815,7 @@ namespace vast::hl
GRAPH_REGION_OP(LabelStmt);
GRAPH_REGION_OP(BreakOp);
GRAPH_REGION_OP(CondOp);
GRAPH_REGION_OP(ChooseExprOp);
GRAPH_REGION_OP(BinaryCondOp);
GRAPH_REGION_OP(ContinueOp);

Expand Down
27 changes: 27 additions & 0 deletions test/vast/Dialect/HighLevel/choose-expr-a.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// 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 fn() {
int x, y;
// CHECK: hl.choose_expr cond false : !hl.lvalue<!hl.int> {
// CHECK: hl.cond.yield {{%.*}} : !hl.int
// CHECK: hl.value.yield {{%.*}} : !hl.lvalue<!hl.int>
// CHECK: hl.value.yield {{%.*}} : !hl.lvalue<!hl.int>
int z = __builtin_choose_expr(0, x, y);
// CHECK: hl.choose_expr cond true : !hl.lvalue<!hl.int> {
z = __builtin_choose_expr(1, x, y);

// CHECK: hl.choose_expr cond true : !hl.lvalue<!hl.int> {
// CHECK: hl.value.yield {{%.*}} : !hl.lvalue<!hl.int>
// CHECK: hl.value.yield {{%.*}} : !hl.void
z = __builtin_choose_expr(1, x, (void) 0);
// CHECK: hl.choose_expr cond false : !hl.lvalue<!hl.int> {
// CHECK: hl.value.yield {{%.*}} : !hl.void
// CHECK: hl.value.yield {{%.*}} : !hl.lvalue<!hl.int>
z = __builtin_choose_expr(0, (void) 0, x);

// CHECK: hl.choose_expr cond true : !hl.lvalue<!hl.int> {
// CHECK: hl.value.yield {{%.*}} : !hl.lvalue<!hl.int>
// CHECK: hl.value.yield {{%.*}} : !hl.char
z = __builtin_choose_expr(1, x, (char) 0);
}