diff --git a/include/vast/CodeGen/DefaultStmtVisitor.hpp b/include/vast/CodeGen/DefaultStmtVisitor.hpp index 24f635d1a1..f7e66c6b34 100644 --- a/include/vast/CodeGen/DefaultStmtVisitor.hpp +++ b/include/vast/CodeGen/DefaultStmtVisitor.hpp @@ -244,6 +244,9 @@ namespace vast::cg { // operation VisitParenListExpr(const clang::ParenListExpr *expr) operation VisitStmtExpr(const clang::StmtExpr *expr); + template< typename op_t > + operation mk_type_trait_expr(const clang::TypeTraitExpr *expr); + template< typename op_t > operation mk_type_trait_expr(const clang::UnaryExprOrTypeTraitExpr *expr); @@ -254,6 +257,7 @@ namespace vast::cg { operation mk_trait_expr(const clang::UnaryExprOrTypeTraitExpr *expr); operation VisitUnaryExprOrTypeTraitExpr(const clang::UnaryExprOrTypeTraitExpr *expr); + operation VisitTypeTraitExpr(const clang::TypeTraitExpr *expr); operation VisitVAArgExpr(const clang::VAArgExpr *expr); operation VisitNullStmt(const clang::NullStmt *stmt); operation VisitCXXThisExpr(const clang::CXXThisExpr *expr); @@ -476,6 +480,20 @@ namespace vast::cg { return {}; } + template< typename op_t > + operation default_stmt_visitor::mk_type_trait_expr(const clang::TypeTraitExpr *expr) { + types_t types; + for (auto type_info : expr->getArgs()) { + types.push_back(self.visit(type_info->getType())); + } + return bld.compose< op_t >() + .bind(self.location(expr)) + .bind(self.visit(expr->getType())) + .bind(types) + .bind_always(expr->isValueDependent() ? std::nullopt : std::optional(expr->getValue())) + .freeze(); + } + template< typename op_t > operation default_stmt_visitor::mk_type_trait_expr(const clang::UnaryExprOrTypeTraitExpr *expr) { return bld.compose< op_t >() diff --git a/include/vast/Dialect/HighLevel/HighLevelOps.hpp b/include/vast/Dialect/HighLevel/HighLevelOps.hpp index f4e7d03b27..53162c133d 100644 --- a/include/vast/Dialect/HighLevel/HighLevelOps.hpp +++ b/include/vast/Dialect/HighLevel/HighLevelOps.hpp @@ -20,6 +20,7 @@ VAST_UNRELAX_WARNINGS #include "vast/Dialect/Core/Interfaces/SymbolInterface.hpp" #include "vast/Interfaces/AggregateTypeDefinitionInterface.hpp" +#include "vast/Interfaces/TypeTraitExprInterface.hpp" #include "vast/Interfaces/AST/DeclInterface.hpp" diff --git a/include/vast/Dialect/HighLevel/HighLevelOps.td b/include/vast/Dialect/HighLevel/HighLevelOps.td index d411e46918..dcf56a927a 100644 --- a/include/vast/Dialect/HighLevel/HighLevelOps.td +++ b/include/vast/Dialect/HighLevel/HighLevelOps.td @@ -9,6 +9,7 @@ include "mlir/IR/BuiltinAttributes.td" include "mlir/Interfaces/CastInterfaces.td" include "vast/Interfaces/AggregateTypeDefinitionInterface.td" +include "vast/Interfaces/TypeTraitExprInterface.td" include "vast/Dialect/Core/Interfaces/SymbolInterface.td" include "vast/Dialect/Core/Interfaces/SymbolTableInterface.td" @@ -1379,6 +1380,44 @@ class HighLevel_AlignOfExprOpBase< string mnemonic, list< Trait > traits = [] > def HighLevel_AlignOfExprOp : HighLevel_AlignOfExprOpBase< "alignof.expr" >; def HighLevel_PreferredAlignOfExprOp : HighLevel_AlignOfExprOpBase< "preferred_alignof.expr" >; +class HighLevel_TypeTraitExprOp< string mnemonic, list< Trait > traits = [] > + : HighLevel_Op< mnemonic, !listconcat([Pure, DeclareOpInterfaceMethods], traits) > +{ + let skipDefaultBuilders = 1; + let builders = [ + OpBuilder< (ins + "Type":$resultType, + "llvm::ArrayRef< mlir::Type >":$types, + CArg< "std::optional< bool >", "std::nullopt" >:$result + ), [{ + auto attr_names = getAttributeNames(); + for (auto [type, attr_name] : llvm::zip_first(types, attr_names)) { + $_state.addAttribute(attr_name, mlir::TypeAttr::get(type)); + } + if (result) { + $_state.addAttribute(attr_names.back(), $_builder.getBoolAttr(result.value())); + } + $_state.addTypes(resultType); + }] >, + OpBuilder< (ins + "Type":$resultType, + "clang::ArrayRef< mlir::Type >":$types, + "bool":$result + ), [{ + build($_builder, $_state, resultType, types, std::optional(result)); + }] > + ]; +} + +def HighLevel_BuiltinTypesCompatiblePOp + : HighLevel_TypeTraitExprOp< "builtin_types_compatible_p.type" > + , Arguments<(ins TypeAttr:$Type1, TypeAttr:$Type2, BoolAttr:$compatible)> + , Results<(outs HighLevel_IntegerLikeType:$result)> +{ + let summary = "VAST representation of __builtin_types_compatible_p"; + let assemblyFormat = [{ $Type1`,` $Type2 `compatible` $compatible attr-dict `->` type($result) }]; +} + def HighLevel_OffsetOfNodeAttr : HighLevel_Attr< "OffsetOfNode", "offset_of_node" > { let parameters = (ins diff --git a/include/vast/Interfaces/CMakeLists.txt b/include/vast/Interfaces/CMakeLists.txt index 7bada3b4a4..c334ad41c7 100644 --- a/include/vast/Interfaces/CMakeLists.txt +++ b/include/vast/Interfaces/CMakeLists.txt @@ -1,4 +1,5 @@ add_vast_op_interface(AggregateTypeDefinitionInterface) +add_vast_op_interface(TypeTraitExprInterface) add_vast_attr_interface(TypeQualifiersInterfaces) add_vast_type_interface(AliasTypeInterface) add_vast_type_interface(DefaultDataLayoutTypeInterface) diff --git a/include/vast/Interfaces/TypeTraitExprInterface.hpp b/include/vast/Interfaces/TypeTraitExprInterface.hpp new file mode 100644 index 0000000000..d85577f442 --- /dev/null +++ b/include/vast/Interfaces/TypeTraitExprInterface.hpp @@ -0,0 +1,16 @@ +// Copyright (c) 2024-present, Trail of Bits, Inc. + +#pragma once + +#include "vast/Util/Warnings.hpp" + +VAST_RELAX_WARNINGS +#include +#include +#include +#include +VAST_RELAX_WARNINGS + + +/// Include the generated interface declarations. +#include "vast/Interfaces/TypeTraitExprInterface.h.inc" diff --git a/include/vast/Interfaces/TypeTraitExprInterface.td b/include/vast/Interfaces/TypeTraitExprInterface.td new file mode 100644 index 0000000000..17c0f89640 --- /dev/null +++ b/include/vast/Interfaces/TypeTraitExprInterface.td @@ -0,0 +1,24 @@ +// Copyright (c) 2024-present, Trail of Bits, Inc. + +#ifndef VAST_INTERFACES_TYPE_TRAIT_EXPR_INTERFACE +#define VAST_INTERFACES_TYPE_TRAIT_EXPR_INTERFACE + +include "mlir/IR/OpBase.td" +include "vast/Interfaces/Common.td" + +def TypeTraitExprInterface : VastOpInterface< "TypeTraitExprInterface" > { + let description = [{ + Interface to use type trait expressions uniformly + }]; + + let methods = [ + InterfaceMethod< "Returns type trait arguments.", + "llvm::SmallVector< mlir::Type >", "getArgs", (ins), "" + >, + InterfaceMethod< "Returns trait value, if possible.", + "std::optional< bool >", "getValue", (ins), "" + > + ]; +} + +#endif // VAST_INTERFACES_TYPE_TRAIT_EXPR_INTERFACE diff --git a/lib/vast/CodeGen/DefaultStmtVisitor.cpp b/lib/vast/CodeGen/DefaultStmtVisitor.cpp index 7094e531ff..46a10865e8 100644 --- a/lib/vast/CodeGen/DefaultStmtVisitor.cpp +++ b/lib/vast/CodeGen/DefaultStmtVisitor.cpp @@ -1093,6 +1093,16 @@ namespace vast::cg } } + operation default_stmt_visitor::VisitTypeTraitExpr(const clang::TypeTraitExpr *expr) { + switch (expr->getTrait()) { + case clang::BTT_TypeCompatible: + return mk_type_trait_expr< hl::BuiltinTypesCompatiblePOp >(expr); + default: + return {}; + } + return {}; + } + operation default_stmt_visitor::VisitVAArgExpr(const clang::VAArgExpr *expr) { return bld.compose< hl::VAArgExpr >() .bind(self.location(expr)) diff --git a/lib/vast/Dialect/HighLevel/HighLevelOps.cpp b/lib/vast/Dialect/HighLevel/HighLevelOps.cpp index 29249df4f1..ac3296c312 100644 --- a/lib/vast/Dialect/HighLevel/HighLevelOps.cpp +++ b/lib/vast/Dialect/HighLevel/HighLevelOps.cpp @@ -864,6 +864,17 @@ namespace vast::hl return core::IntegerAttr::get(getType(), apsint(getValue())); } + // + // BuiltinTypesCompatiblePOp + // + types_t BuiltinTypesCompatiblePOp::getArgs() { + return types_t{getType1(), getType2()}; + } + + std::optional< bool > BuiltinTypesCompatiblePOp::getValue() { + return std::optional(getCompatibleAttr().getValue()); + } + } //===----------------------------------------------------------------------===// diff --git a/lib/vast/Interfaces/CMakeLists.txt b/lib/vast/Interfaces/CMakeLists.txt index d0fd2d2819..3d6b3fbd32 100644 --- a/lib/vast/Interfaces/CMakeLists.txt +++ b/lib/vast/Interfaces/CMakeLists.txt @@ -7,6 +7,7 @@ set(VAST_OPTIONAL_SOURCES SymbolTableInterface.cpp SymbolRefInterface.cpp TypeQualifiersInterfaces.cpp + TypeTraitExprInterface.cpp ) add_vast_interface_library(AggregateTypeDefinitionInterface @@ -44,4 +45,8 @@ add_vast_interface_library(TypeQualifiersInterfaces TypeQualifiersInterfaces.cpp ) +add_vast_interface_library(TypeTraitExprInterface + TypeTraitExprInterface.cpp +) + add_subdirectory(AST) diff --git a/lib/vast/Interfaces/TypeTraitExprInterface.cpp b/lib/vast/Interfaces/TypeTraitExprInterface.cpp new file mode 100644 index 0000000000..d56cacd67c --- /dev/null +++ b/lib/vast/Interfaces/TypeTraitExprInterface.cpp @@ -0,0 +1,10 @@ +// Copyright (c) 2024-present, Trail of Bits, Inc. + +#include "vast/Interfaces/TypeTraitExprInterface.hpp" + +//===----------------------------------------------------------------------===// +// Alias Type Interface +//===----------------------------------------------------------------------===// + +/// Include the generated interface. +#include "vast/Interfaces/TypeTraitExprInterface.cpp.inc" diff --git a/test/vast/Dialect/HighLevel/types-compatible-a.c b/test/vast/Dialect/HighLevel/types-compatible-a.c new file mode 100644 index 0000000000..be1bebd1f4 --- /dev/null +++ b/test/vast/Dialect/HighLevel/types-compatible-a.c @@ -0,0 +1,12 @@ +// 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 - + +typedef int INT; +int main() { + // CHECK: hl.builtin_types_compatible_p.type !hl.int, !hl.char compatible false -> !hl.int + __builtin_types_compatible_p(int, char); + // CHECK: hl.builtin_types_compatible_p.type !hl.int, !hl.int compatible true -> !hl.int + __builtin_types_compatible_p(int, int); + // CHECK: hl.builtin_types_compatible_p.type !hl.int, !hl.elaborated> compatible true -> !hl.int + __builtin_types_compatible_p(int, INT); +}