mirror of
https://github.com/revng/revng
synced 2026-06-21 14:07:57 +00:00
afaff540ed
Local variable initializer regions can now have a block argument representing the local variable being initialized.
1227 lines
34 KiB
TableGen
1227 lines
34 KiB
TableGen
//
|
|
// This file is distributed under the MIT License. See LICENSE.md for details.
|
|
//
|
|
|
|
#ifndef MLIR_CLIFT_OPS
|
|
#define MLIR_CLIFT_OPS
|
|
|
|
include "mlir/Interfaces/CallInterfaces.td"
|
|
include "mlir/Interfaces/InferTypeOpInterface.td"
|
|
include "mlir/Interfaces/SideEffectInterfaces.td"
|
|
include "mlir/IR/BuiltinAttributes.td"
|
|
include "mlir/IR/FunctionInterfaces.td"
|
|
include "mlir/IR/RegionKindInterface.td"
|
|
include "mlir/IR/SymbolInterfaces.td"
|
|
|
|
include "revng/Clift/CliftOpInterfaces.td"
|
|
include "revng/Clift/CliftOpTraits.td"
|
|
include "revng/Clift/CliftTypes.td"
|
|
|
|
class Clift_Op<string mnemonic, list<Trait> traits = []>
|
|
: Op<Clift_Dialect,
|
|
mnemonic,
|
|
!listconcat(traits, [NoTerminator])>;
|
|
|
|
//===-------------------------- Type constraints --------------------------===//
|
|
|
|
def Clift_AnyAddressableType
|
|
: Type<CPred<"mlir::isa<clift::AddressableType>($_self)">,
|
|
"value type">;
|
|
|
|
def Clift_AnyObjectType
|
|
: Type<CPred<"clift::unwrapped_isa<clift::ObjectType>($_self)">,
|
|
"object type">;
|
|
|
|
def Clift_AnyValueType
|
|
: Type<CPred<"clift::unwrapped_isa<clift::ValueType>($_self)">,
|
|
"value type">;
|
|
|
|
def Clift_AnyBooleanType
|
|
: Type<CPred<"clift::isBooleanType($_self)">,
|
|
"boolean type">;
|
|
|
|
def Clift_AnyScalarType
|
|
: Type<CPred<"clift::isScalarType($_self)">,
|
|
"scalar type">;
|
|
|
|
def Clift_AnyIntegerType
|
|
: Type<CPred<"clift::unwrapped_isa<clift::IntegralType>($_self)">,
|
|
"integer type">;
|
|
|
|
def Clift_AnyPrimitiveIntegerType
|
|
: Type<CPred<"clift::unwrapped_isa<clift::IntegerType>($_self)">,
|
|
"primitive integer type">;
|
|
|
|
def Clift_AnyPointerType
|
|
: Type<CPred<"clift::unwrapped_isa<clift::PointerType>($_self)">,
|
|
"pointer type">;
|
|
|
|
def Clift_AnyFunctionType
|
|
: Type<CPred<"clift::unwrapped_isa<clift::FunctionType>($_self)">,
|
|
"function type">;
|
|
|
|
def Clift_AnyNonVoidType
|
|
: Type<CPred<"not clift::unwrapped_isa<clift::VoidType>($_self)">,
|
|
"non-void type">;
|
|
|
|
class Clift_AnyNonConstType<Type type>
|
|
: Type<And<[type.predicate,
|
|
CPred<"not clift::isConst($_self)">]>,
|
|
"non-const " # type.summary>;
|
|
|
|
class Clift_AnyModifiableType<Type type>
|
|
: Type<And<[type.predicate,
|
|
CPred<"clift::isModifiableType($_self)">]>,
|
|
"modifiable " # type.summary>;
|
|
|
|
class Clift_AllTypesMatch<list<string> names>
|
|
: AllMatchSameOperatorTrait<names,
|
|
"clift::removeConst($_self.getType())",
|
|
"type (ignoring qualifiers)">;
|
|
|
|
class Clift_AllSizesMatch<list<string> names>
|
|
: AllMatchSameOperatorTrait<names,
|
|
"clift::getObjectSize($_self.getType())",
|
|
"object size">;
|
|
|
|
class Clift_AllPointeeTypesMatch<list<string> names>
|
|
: AllMatchSameOperatorTrait<names,
|
|
"clift::unwrapped_cast<clift::PointerType>($_self.getType()).getPointeeType()",
|
|
"pointee type">;
|
|
|
|
class Clift_UnqualifiedTypeMatches<string qualified, string unqualified>
|
|
: TypesMatchWith<qualified # " type (ignoring qualifiers) matches the " # unqualified # " type",
|
|
qualified,
|
|
unqualified,
|
|
"clift::removeConst($_self)">;
|
|
|
|
class Clift_PointeeTypeMatches<string pointer, string value>
|
|
: TypesMatchWith<pointer # " pointee type matches the " # value # " type",
|
|
pointer,
|
|
value,
|
|
"clift::unwrapped_cast<clift::PointerType>($_self).getPointeeType()">;
|
|
|
|
class Clift_LValueOperand<string name>
|
|
: PredOpTrait<"operand " # name # " is an lvalue expression",
|
|
CPred<"clift::isLvalueExpression($" # name # ")">>;
|
|
|
|
//===---------------------------- Region types ----------------------------===//
|
|
|
|
def Clift_StatementRegion
|
|
: Region<CPred<"clift::impl::verifyStatementRegion($_self)">,
|
|
"Region containing statements">;
|
|
|
|
def Clift_ExpressionRegion
|
|
: Region<CPred<"clift::impl::verifyExpressionRegion($_self, true)">,
|
|
"Region representing an expression">;
|
|
|
|
def Clift_OptionalExpressionRegion
|
|
: Region<CPred<"clift::impl::verifyExpressionRegion($_self, false)">,
|
|
"Optional region representing an expression">;
|
|
|
|
//===------------------------ Top level operations ------------------------===//
|
|
|
|
def Clift_FunctionOp : Clift_Op<"func",
|
|
[Clift_GlobalOpInterface,
|
|
CallableOpInterface,
|
|
FunctionOpInterface,
|
|
AutomaticAllocationScope,
|
|
IsolatedFromAbove]> {
|
|
let arguments = (ins StrAttr:$sym_name,
|
|
TypeAttrOf<Clift_AnyFunctionType>:$type,
|
|
OptionalAttr<DictArrayAttr>:$arg_attrs,
|
|
OptionalAttr<DictArrayAttr>:$res_attrs,
|
|
UnitAttr:$noreturn,
|
|
UnitAttr:$always_inline,
|
|
DefaultValuedStrAttr<StrAttr, "">:$handle);
|
|
|
|
let description = [{
|
|
expression.
|
|
}];
|
|
|
|
let regions = (region Clift_StatementRegion:$body);
|
|
|
|
let builders = [
|
|
OpBuilder<(ins "llvm::StringRef":$Name,
|
|
"clift::FunctionType":$FunctionType)>
|
|
];
|
|
|
|
let hasCustomAssemblyFormat = 1;
|
|
|
|
code extraClassDeclaration = [{
|
|
static mlir::StringAttr getFunctionTypeAttrName(mlir::OperationName Name) {
|
|
return getTypeAttrName(Name);
|
|
}
|
|
|
|
mlir::StringAttr getFunctionTypeAttrName() {
|
|
return getTypeAttrName();
|
|
}
|
|
|
|
mlir::TypeAttr getFunctionTypeAttr() {
|
|
return getTypeAttr();
|
|
}
|
|
|
|
void setFunctionTypeAttr(mlir::TypeAttr Attr) {
|
|
return setTypeAttr(Attr);
|
|
}
|
|
|
|
FunctionType getFunctionType() {
|
|
return clift::unwrapped_cast<FunctionType>(getType());
|
|
}
|
|
|
|
|
|
mlir::Type getReturnType() {
|
|
return getFunctionType().getReturnType();
|
|
}
|
|
|
|
unsigned getArgCount() {
|
|
return getFunctionType().getArgumentTypes().size();
|
|
}
|
|
|
|
|
|
clift::AttrDictView getArgAttrs(unsigned Index) {
|
|
std::optional<mlir::ArrayAttr> Attrs = getArgAttrs();
|
|
mlir::DictionaryAttr DictAttr = Attrs ?
|
|
mlir::cast<mlir::DictionaryAttr>((*Attrs)[Index]) :
|
|
mlir::DictionaryAttr::get(getContext());
|
|
return AttrDictView(DictAttr);
|
|
}
|
|
|
|
clift::AttrDictView getResAttrs(unsigned Index) {
|
|
std::optional<mlir::ArrayAttr> Attrs = getArgAttrs();
|
|
mlir::DictionaryAttr DictAttr = Attrs ?
|
|
mlir::cast<mlir::DictionaryAttr>((*Attrs)[Index]) :
|
|
mlir::DictionaryAttr::get(getContext());
|
|
return AttrDictView(DictAttr);
|
|
}
|
|
|
|
|
|
mlir::Region::BlockListType& getBlocks() {
|
|
return getBody().getBlocks();
|
|
}
|
|
|
|
mlir::Block::args_iterator args_begin() {
|
|
return getBody().front().args_begin();
|
|
}
|
|
|
|
mlir::Block::args_iterator args_end() {
|
|
return getBody().front().args_end();
|
|
}
|
|
|
|
|
|
// Implementation of CallableOpInterface
|
|
|
|
mlir::Region *getCallableRegion() {
|
|
return isExternal() ? nullptr : &getBody();
|
|
}
|
|
|
|
/// Returns the result types of this function.
|
|
llvm::ArrayRef<mlir::Type> getCallableResults() {
|
|
return getResultTypes();
|
|
}
|
|
|
|
|
|
// Implementation of FunctionOpInterface
|
|
|
|
llvm::ArrayRef<mlir::Type> getArgumentTypes();
|
|
llvm::ArrayRef<mlir::Type> getResultTypes();
|
|
|
|
mlir::Type cloneTypeWith(mlir::TypeRange inputs, mlir::TypeRange results);
|
|
}];
|
|
}
|
|
|
|
def Clift_GlobalVariableOp : Clift_Op<"global",
|
|
[Clift_GlobalOpInterface,
|
|
NoRegionArguments,
|
|
IsolatedFromAbove]> {
|
|
let arguments = (ins SymbolNameAttr:$sym_name,
|
|
TypeAttrOf<Clift_AddressableType>:$type,
|
|
DefaultValuedStrAttr<StrAttr, "">:$handle);
|
|
|
|
let description = [{
|
|
global variable
|
|
}];
|
|
|
|
let regions = (region Clift_OptionalExpressionRegion:$initializer);
|
|
|
|
let assemblyFormat = [{
|
|
$sym_name `:` $type (`=` $initializer^)? attr-dict-with-keyword
|
|
}];
|
|
|
|
let hasVerifier = 1;
|
|
}
|
|
|
|
//===----------------------------- Statements -----------------------------===//
|
|
|
|
class Clift_BasicStatementOp<string mnemonic,
|
|
Trait interface,
|
|
list<Trait> traits = []>
|
|
: Clift_Op<mnemonic, !listconcat(traits, [interface])>;
|
|
|
|
class Clift_StatementOp<string mnemonic, list<Trait> traits = []>
|
|
: Clift_BasicStatementOp<mnemonic,
|
|
Clift_StatementOpInterface,
|
|
!listconcat(traits, [NoRegionArguments])>;
|
|
|
|
class Clift_JumpStatementOp<string mnemonic>
|
|
: Clift_BasicStatementOp<mnemonic,
|
|
Clift_JumpStatementOpInterface,
|
|
[NoRegionArguments, Clift_NoFallthrough]>;
|
|
|
|
// Two bit integer used to represent two flags, each indicating the presence of
|
|
// the break and continue label assignments respectively.
|
|
def LoopLabelMaskAttr : TypedUnsignedIntegerAttrBase<UI<2>,
|
|
"uint8_t",
|
|
"Loop label mask">;
|
|
|
|
class Clift_LoopStatementOp<string mnemonic, list<Trait> traits = []>
|
|
: Clift_BasicStatementOp<mnemonic,
|
|
Clift_LoopOpInterface,
|
|
!listconcat(traits, [Clift_AssignsLoopLabels])> {
|
|
|
|
let arguments = (ins LoopLabelMaskAttr:$label_mask,
|
|
Variadic<Clift_LabelType>:$labels);
|
|
|
|
// The generation of default builders for loop operations is skipped to avoid
|
|
// mistakes, as building a valid loop with explicit label mask and operands
|
|
// would be error prone.
|
|
let skipDefaultBuilders = 1;
|
|
|
|
let builders = [
|
|
OpBuilder<(ins CArg<"clift::LoopOpInterface", "{}">:$OtherLoop)>
|
|
];
|
|
}
|
|
|
|
def Clift_MakeLabelOp : Clift_StatementOp<"make_label"> {
|
|
let arguments = (ins DefaultValuedStrAttr<StrAttr, "">:$name,
|
|
DefaultValuedStrAttr<StrAttr, "">:$handle);
|
|
|
|
let results = (outs Clift_LabelType:$result);
|
|
|
|
let assemblyFormat = [{
|
|
attr-dict
|
|
}];
|
|
|
|
let hasCanonicalizeMethod = 1;
|
|
let hasVerifier = 1;
|
|
|
|
let builders = [
|
|
OpBuilder<(ins), [{
|
|
build($_builder,
|
|
$_state,
|
|
clift::LabelType::get($_builder.getContext()));
|
|
}]>
|
|
];
|
|
|
|
let extraClassDeclaration = [{
|
|
[[nodiscard]] LabelAssignmentOpInterface getAssignment();
|
|
}];
|
|
}
|
|
|
|
def Clift_AssignLabelOp
|
|
: Clift_BasicStatementOp<"assign_label",
|
|
Clift_LabelAssignmentOpInterface> {
|
|
|
|
let arguments = (ins Clift_LabelType:$label);
|
|
|
|
let assemblyFormat = [{
|
|
$label attr-dict
|
|
}];
|
|
|
|
let extraClassDeclaration = [{
|
|
[[nodiscard]] MakeLabelOp getLabelOp();
|
|
|
|
unsigned getAssignedLabelCount() {
|
|
return 1;
|
|
}
|
|
|
|
mlir::Value getAssignedLabel(unsigned Index) {
|
|
revng_assert(Index == 0);
|
|
return getLabel();
|
|
}
|
|
}];
|
|
}
|
|
|
|
def Clift_BlockStatementOp
|
|
: Clift_StatementOp<"block", [Clift_StatementRegionOpInterface]> {
|
|
|
|
let regions = (region Clift_StatementRegion:$block);
|
|
|
|
let assemblyFormat = [{
|
|
$block attr-dict-with-keyword
|
|
}];
|
|
|
|
let extraClassDeclaration = [{
|
|
bool isIndirectlyNoFallthrough();
|
|
|
|
unsigned getStatementRegionCount() {
|
|
return 1;
|
|
}
|
|
|
|
mlir::Region &getStatementRegion(unsigned Index) {
|
|
revng_assert(Index == 0);
|
|
return getBlock();
|
|
}
|
|
}];
|
|
}
|
|
|
|
def Clift_BreakToOp : Clift_JumpStatementOp<"break_to"> {
|
|
let arguments = (ins Clift_LabelType:$label);
|
|
|
|
let assemblyFormat = [{
|
|
$label attr-dict
|
|
}];
|
|
|
|
let hasVerifier = 1;
|
|
|
|
let extraClassDeclaration = [{
|
|
[[nodiscard]] MakeLabelOp getLabelOp();
|
|
}];
|
|
}
|
|
|
|
def Clift_ContinueToOp : Clift_JumpStatementOp<"continue_to"> {
|
|
let arguments = (ins Clift_LabelType:$label);
|
|
|
|
let assemblyFormat = [{
|
|
$label attr-dict
|
|
}];
|
|
|
|
let hasVerifier = 1;
|
|
|
|
let extraClassDeclaration = [{
|
|
[[nodiscard]] MakeLabelOp getLabelOp();
|
|
}];
|
|
}
|
|
|
|
def Clift_DoWhileOp : Clift_LoopStatementOp<"do_while", [NoRegionArguments]> {
|
|
let regions = (region Clift_StatementRegion:$body,
|
|
Clift_ExpressionRegion:$condition);
|
|
|
|
let assemblyFormat = [{
|
|
custom<CliftLoopLabels>($label_mask, $labels)
|
|
`body` $body `cond` $condition attr-dict-with-keyword
|
|
}];
|
|
|
|
let hasVerifier = 1;
|
|
|
|
let extraClassDeclaration = [{
|
|
[[nodiscard]] bool isBooleanTestedExpression(mlir::Region &R) {
|
|
return &R == &getCondition();
|
|
}
|
|
|
|
unsigned getStatementRegionCount() {
|
|
return 1;
|
|
}
|
|
|
|
mlir::Region &getStatementRegion(unsigned Index) {
|
|
revng_assert(Index == 0);
|
|
return getBody();
|
|
}
|
|
|
|
unsigned getExpressionRegionCount() {
|
|
return 1;
|
|
}
|
|
|
|
mlir::Region &getExpressionRegion(unsigned Index) {
|
|
revng_assert(Index == 0);
|
|
return getCondition();
|
|
}
|
|
}];
|
|
}
|
|
|
|
def Clift_ExpressionStatementOp
|
|
: Clift_StatementOp<"expr", [Clift_ExpressionRegionOpInterface]> {
|
|
|
|
let regions = (region Clift_OptionalExpressionRegion:$expression);
|
|
|
|
let assemblyFormat = [{
|
|
$expression attr-dict-with-keyword
|
|
}];
|
|
|
|
let extraClassDeclaration = [{
|
|
[[nodiscard]] bool isDiscardedExpression(mlir::Region &R) {
|
|
return true;
|
|
}
|
|
|
|
unsigned getExpressionRegionCount() {
|
|
return 1;
|
|
}
|
|
|
|
mlir::Region &getExpressionRegion(unsigned Index) {
|
|
revng_assert(Index == 0);
|
|
return getExpression();
|
|
}
|
|
}];
|
|
}
|
|
|
|
def Clift_ForOp
|
|
: Clift_LoopStatementOp<"for",
|
|
[DeclareOpInterfaceMethods<Clift_StatementOpInterface,
|
|
["getBlockArgumentVariable"]>]> {
|
|
|
|
let regions = (region Clift_StatementRegion:$initializer,
|
|
Clift_OptionalExpressionRegion:$condition,
|
|
Clift_OptionalExpressionRegion:$expression,
|
|
Clift_StatementRegion:$body);
|
|
|
|
let hasCustomAssemblyFormat = 1;
|
|
let hasVerifier = 1;
|
|
|
|
let extraClassDeclaration = [{
|
|
[[nodiscard]] bool isDiscardedExpression(mlir::Region &R);
|
|
|
|
[[nodiscard]] bool isBooleanTestedExpression(mlir::Region &R) {
|
|
return &R == &getCondition();
|
|
}
|
|
|
|
unsigned getStatementRegionCount() {
|
|
return 1;
|
|
}
|
|
|
|
mlir::Region &getStatementRegion(unsigned Index) {
|
|
revng_assert(Index == 0);
|
|
return getBody();
|
|
}
|
|
|
|
unsigned getExpressionRegionCount();
|
|
mlir::Region &getExpressionRegion(unsigned Index);
|
|
}];
|
|
}
|
|
|
|
def Clift_GotoOp : Clift_JumpStatementOp<"goto"> {
|
|
let arguments = (ins Clift_LabelType:$label);
|
|
|
|
let assemblyFormat = [{
|
|
$label attr-dict
|
|
}];
|
|
|
|
let hasVerifier = 1;
|
|
|
|
let extraClassDeclaration = [{
|
|
[[nodiscard]] MakeLabelOp getLabelOp();
|
|
}];
|
|
}
|
|
|
|
def Clift_IfOp : Clift_BasicStatementOp<"if", Clift_BranchOpInterface> {
|
|
let regions = (region Clift_ExpressionRegion:$condition,
|
|
Clift_StatementRegion:$then,
|
|
Clift_StatementRegion:$else);
|
|
|
|
let assemblyFormat = [{
|
|
$condition `then` $then (`else` $else^)? attr-dict-with-keyword
|
|
}];
|
|
|
|
let hasVerifier = 1;
|
|
|
|
let extraClassDeclaration = [{
|
|
bool isIndirectlyNoFallthrough() const;
|
|
|
|
[[nodiscard]] bool isBooleanTestedExpression(mlir::Region &R) {
|
|
return &R == &getCondition();
|
|
}
|
|
|
|
unsigned getStatementRegionCount() {
|
|
return 2;
|
|
}
|
|
|
|
mlir::Region &getStatementRegion(unsigned Index) {
|
|
revng_assert(Index < 2);
|
|
return Index == 0 ? getThen() : getElse();
|
|
}
|
|
|
|
unsigned getExpressionRegionCount() {
|
|
return 1;
|
|
}
|
|
|
|
mlir::Region &getExpressionRegion(unsigned Index) {
|
|
revng_assert(Index == 0);
|
|
return getCondition();
|
|
}
|
|
}];
|
|
}
|
|
|
|
def Clift_LocalVariableOp
|
|
: Clift_BasicStatementOp<"local",
|
|
Clift_StatementOpInterface,
|
|
[DeclareOpInterfaceMethods<Clift_StatementOpInterface,
|
|
["getBlockArgumentVariable"]>]> {
|
|
|
|
let arguments = (ins DefaultValuedStrAttr<StrAttr, "">:$name,
|
|
DefaultValuedStrAttr<StrAttr, "">:$handle);
|
|
|
|
let results = (outs Clift_AnyObjectType:$result);
|
|
|
|
let regions = (region Clift_OptionalExpressionRegion:$initializer);
|
|
|
|
let hasCustomAssemblyFormat = 1;
|
|
let hasVerifier = 1;
|
|
|
|
let extraClassDeclaration = [{
|
|
mlir::Type getType() {
|
|
return getResult().getType();
|
|
}
|
|
|
|
unsigned getExpressionRegionCount() {
|
|
return 1;
|
|
}
|
|
|
|
mlir::Region &getExpressionRegion(unsigned Index) {
|
|
revng_assert(Index == 0);
|
|
return getInitializer();
|
|
}
|
|
}];
|
|
}
|
|
|
|
def Clift_ReturnOp : Clift_StatementOp<"return", [Clift_NoFallthrough]> {
|
|
|
|
let regions = (region Clift_OptionalExpressionRegion:$result);
|
|
|
|
let assemblyFormat = [{
|
|
$result attr-dict-with-keyword
|
|
}];
|
|
|
|
let extraClassDeclaration = [{
|
|
unsigned getExpressionRegionCount() {
|
|
return 1;
|
|
}
|
|
|
|
mlir::Region &getExpressionRegion(unsigned Index) {
|
|
revng_assert(Index == 0);
|
|
return getResult();
|
|
}
|
|
}];
|
|
|
|
let hasVerifier = 1;
|
|
}
|
|
|
|
def Clift_RequireOp : Clift_StatementOp<"require"> {
|
|
let arguments = (ins AnyType:$local);
|
|
|
|
let assemblyFormat = [{
|
|
$local attr-dict `:` type($local)
|
|
}];
|
|
|
|
let hasVerifier = 1;
|
|
|
|
let extraClassDeclaration = [{
|
|
[[nodiscard]] LocalVariableOp getLocalOp();
|
|
}];
|
|
}
|
|
|
|
def Clift_SwitchOp : Clift_BasicStatementOp<"switch", Clift_BranchOpInterface> {
|
|
let arguments = (ins DenseI64ArrayAttr:$case_values);
|
|
|
|
let regions = (region Clift_ExpressionRegion:$condition,
|
|
Clift_StatementRegion:$default,
|
|
VariadicRegion<Clift_StatementRegion>:$cases);
|
|
|
|
let hasCustomAssemblyFormat = 1;
|
|
let hasVerifier = 1;
|
|
|
|
let builders = [
|
|
OpBuilder<(ins "llvm::ArrayRef<uint64_t>":$case_values)>
|
|
];
|
|
|
|
code extraClassDeclaration = [{
|
|
bool isIndirectlyNoFallthrough() const;
|
|
|
|
[[nodiscard]] mlir::Type getConditionType();
|
|
|
|
[[nodiscard]] mlir::Region &getConditionRegion() {
|
|
return getRegion(0);
|
|
}
|
|
|
|
[[nodiscard]] bool hasDefaultCase() {
|
|
return not getDefaultCaseRegion().empty();
|
|
}
|
|
|
|
[[nodiscard]] mlir::Region &getDefaultCaseRegion() {
|
|
return getRegion(1);
|
|
}
|
|
|
|
[[nodiscard]] unsigned getNumCases() {
|
|
return getNumRegions() - 2;
|
|
}
|
|
|
|
[[nodiscard]] uint64_t getCaseValue(const unsigned index) {
|
|
return static_cast<uint64_t>(getCaseValues()[index]);
|
|
}
|
|
|
|
[[nodiscard]] llvm::MutableArrayRef<mlir::Region> getCaseRegions() {
|
|
return getOperation()->getRegions().drop_front(2);
|
|
}
|
|
|
|
[[nodiscard]] mlir::Region &getCaseRegion(const unsigned index) {
|
|
return getCaseRegions()[index];
|
|
}
|
|
|
|
[[nodiscard]] mlir::Region *findCaseRegion(const uint64_t value);
|
|
|
|
unsigned getStatementRegionCount() {
|
|
return getOperation()->getRegions().size() - 1;
|
|
}
|
|
|
|
mlir::Region &getStatementRegion(unsigned Index) {
|
|
return getOperation()->getRegions()[Index + 1];
|
|
}
|
|
|
|
unsigned getExpressionRegionCount() {
|
|
return 1;
|
|
}
|
|
|
|
mlir::Region &getExpressionRegion(unsigned Index) {
|
|
revng_assert(Index == 0);
|
|
return getCondition();
|
|
}
|
|
}];
|
|
}
|
|
|
|
def Clift_WhileOp : Clift_LoopStatementOp<"while", [NoRegionArguments]> {
|
|
let regions = (region Clift_ExpressionRegion:$condition,
|
|
Clift_StatementRegion:$body);
|
|
|
|
let assemblyFormat = [{
|
|
custom<CliftLoopLabels>($label_mask, $labels)
|
|
`cond` $condition `body` $body attr-dict-with-keyword
|
|
}];
|
|
|
|
let hasVerifier = 1;
|
|
|
|
let extraClassDeclaration = [{
|
|
[[nodiscard]] bool isBooleanTestedExpression(mlir::Region &R) {
|
|
return &R == &getCondition();
|
|
}
|
|
|
|
unsigned getStatementRegionCount() {
|
|
return 1;
|
|
}
|
|
|
|
mlir::Region &getStatementRegion(unsigned Index) {
|
|
revng_assert(Index == 0);
|
|
return getBody();
|
|
}
|
|
|
|
unsigned getExpressionRegionCount() {
|
|
return 1;
|
|
}
|
|
|
|
mlir::Region &getExpressionRegion(unsigned Index) {
|
|
revng_assert(Index == 0);
|
|
return getCondition();
|
|
}
|
|
}];
|
|
}
|
|
|
|
//===----------------------------- Expressions ----------------------------===//
|
|
|
|
class Clift_BasicExpressionOp<string mnemonic,
|
|
Trait interface,
|
|
list<Trait> traits = []>
|
|
: Clift_Op<mnemonic, !listconcat(traits, [interface,
|
|
NoMemoryEffect,
|
|
NoRegionArguments])>;
|
|
|
|
class Clift_ExpressionOp<string mnemonic, list<Trait> traits = []>
|
|
: Clift_BasicExpressionOp<mnemonic, Clift_ExpressionOpInterface, traits>;
|
|
|
|
def Clift_UndefOp : Clift_ExpressionOp<"undef"> {
|
|
let results = (outs Clift_AnyAddressableType:$result);
|
|
|
|
let assemblyFormat = [{
|
|
attr-dict `:` type($result)
|
|
}];
|
|
}
|
|
|
|
def Clift_YieldOp : Clift_Op<"yield", [Clift_ExpressionOpInterface,
|
|
Terminator,
|
|
NoRegionArguments]> {
|
|
|
|
let arguments = (ins Clift_AnyAddressableType:$value);
|
|
|
|
let assemblyFormat = [{
|
|
$value attr-dict `:` type($value)
|
|
}];
|
|
|
|
let extraClassDeclaration = [{
|
|
[[nodiscard]] bool isDiscardedOperand(mlir::OpOperand &Operand);
|
|
[[nodiscard]] bool isBooleanTestedOperand(mlir::OpOperand &Operand);
|
|
}];
|
|
}
|
|
|
|
def Clift_ImmediateOp : Clift_ExpressionOp<"imm"> {
|
|
let arguments = (ins I64Attr:$value);
|
|
|
|
let results = (outs Clift_AnyNonConstType<Clift_AnyIntegerType>:$result);
|
|
|
|
let assemblyFormat = [{
|
|
$value attr-dict `:` type($result)
|
|
}];
|
|
}
|
|
|
|
def Clift_StringOp : Clift_ExpressionOp<"str"> {
|
|
let arguments = (ins StrAttr:$value);
|
|
let results = (outs AnyType:$result);
|
|
|
|
let assemblyFormat = [{
|
|
$value attr-dict `:` type($result)
|
|
}];
|
|
|
|
let hasVerifier = 1;
|
|
}
|
|
|
|
class Clift_UnaryArithmeticOp<string mnemonic>
|
|
: Clift_ExpressionOp<mnemonic,
|
|
[Clift_UnqualifiedTypeMatches<"value", "result">]> {
|
|
|
|
let arguments = (ins Clift_AnyPrimitiveIntegerType:$value);
|
|
let results = (outs Clift_AnyNonConstType<Clift_AnyPrimitiveIntegerType>:$result);
|
|
|
|
let assemblyFormat = [{
|
|
$value attr-dict `:` type($value)
|
|
}];
|
|
}
|
|
|
|
class Clift_BinaryArithmeticOp<string mnemonic, list<Trait> traits = []>
|
|
: Clift_ExpressionOp<mnemonic,
|
|
!listconcat(traits,
|
|
[Clift_AllTypesMatch<["lhs", "rhs", "result"]>])> {
|
|
|
|
let arguments = (ins Clift_AnyPrimitiveIntegerType:$lhs,
|
|
Clift_AnyPrimitiveIntegerType:$rhs);
|
|
|
|
let results = (outs Clift_AnyNonConstType<Clift_AnyPrimitiveIntegerType>:$result);
|
|
|
|
let builders = [
|
|
OpBuilder<(ins "mlir::Value":$Lhs, "mlir::Value":$Rhs), [{
|
|
build($_builder, $_state, Lhs.getType(), Lhs, Rhs);
|
|
}]>
|
|
];
|
|
|
|
let assemblyFormat = [{
|
|
$lhs `,` $rhs attr-dict `:`
|
|
custom<CliftOpTypes>(type($result), type($lhs), type($rhs))
|
|
}];
|
|
}
|
|
|
|
class Clift_PointerArithmeticOp<string mnemonic, list<Trait> traits = []>
|
|
: Clift_ExpressionOp<mnemonic, traits> {
|
|
|
|
let arguments = (ins AnyType:$lhs, AnyType:$rhs);
|
|
let results = (outs Clift_AnyNonConstType<AnyType>:$result);
|
|
|
|
let assemblyFormat = [{
|
|
$lhs `,` $rhs attr-dict `:` `(`
|
|
custom<CliftPointerArithmeticOpTypes>(type($result), type($lhs), type($rhs))
|
|
`)`
|
|
}];
|
|
|
|
let hasVerifier = 1;
|
|
|
|
let extraClassDeclaration = [{
|
|
unsigned getPointerOperandIndex() {
|
|
return clift::impl::getPointerArithmeticPointerOperandIndex(getOperation());
|
|
}
|
|
|
|
mlir::Value getPointer() {
|
|
return getOperation()->getOperand(getPointerOperandIndex());
|
|
}
|
|
|
|
unsigned getOffsetOperandIndex() {
|
|
return clift::impl::getPointerArithmeticOffsetOperandIndex(getOperation());
|
|
}
|
|
|
|
mlir::Value getOffset() {
|
|
return getOperation()->getOperand(getOffsetOperandIndex());
|
|
}
|
|
}];
|
|
}
|
|
|
|
class Clift_BinaryLogicalOp<string mnemonic>
|
|
: Clift_ExpressionOp<mnemonic, [Clift_ReturnsBoolean]> {
|
|
|
|
let arguments = (ins Clift_AnyScalarType:$lhs,
|
|
Clift_AnyScalarType:$rhs);
|
|
|
|
let results = (outs Clift_AnyNonConstType<Clift_AnyBooleanType>:$result);
|
|
|
|
let assemblyFormat = [{
|
|
$lhs `,` $rhs attr-dict `:`
|
|
custom<CliftOpOperandTypes>(type($lhs), type($rhs)) `->` type($result)
|
|
}];
|
|
|
|
let extraClassDeclaration = [{
|
|
[[nodiscard]] bool isBooleanTestedOperand(mlir::OpOperand &Operand) {
|
|
return true;
|
|
}
|
|
}];
|
|
}
|
|
|
|
class Clift_ShiftOp<string mnemonic>
|
|
: Clift_ExpressionOp<mnemonic,
|
|
[Clift_UnqualifiedTypeMatches<"lhs", "result">]> {
|
|
|
|
let arguments = (ins Clift_AnyPrimitiveIntegerType:$lhs,
|
|
Clift_AnyPrimitiveIntegerType:$rhs);
|
|
|
|
let results = (outs Clift_AnyNonConstType<Clift_AnyPrimitiveIntegerType>:$result);
|
|
|
|
let assemblyFormat = [{
|
|
$lhs `,` $rhs attr-dict `:` custom<CliftOpOperandTypes>(type($lhs), type($rhs))
|
|
}];
|
|
}
|
|
|
|
class Clift_ComparisonOp<string mnemonic>
|
|
: Clift_ExpressionOp<mnemonic,
|
|
[Commutative,
|
|
Clift_ReturnsBoolean,
|
|
Clift_AllTypesMatch<["lhs", "rhs"]>]> {
|
|
|
|
let arguments = (ins Clift_AnyScalarType:$lhs,
|
|
Clift_AnyScalarType:$rhs);
|
|
|
|
let results = (outs Clift_AnyNonConstType<Clift_AnyBooleanType>:$result);
|
|
|
|
let assemblyFormat = [{
|
|
$lhs `,` $rhs attr-dict `:`
|
|
custom<CliftOpOperandTypes>(type($lhs), type($rhs)) `->` type($result)
|
|
}];
|
|
}
|
|
|
|
class Clift_UnaryIntegerMutationOp<string mnemonic>
|
|
: Clift_ExpressionOp<mnemonic,
|
|
[AllTypesMatch<["value", "result"]>,
|
|
Clift_LValueOperand<"value">]> {
|
|
|
|
let arguments = (ins Clift_AnyModifiableType<Clift_AnyPrimitiveIntegerType>:$value);
|
|
let results = (outs Clift_AnyPrimitiveIntegerType:$result);
|
|
|
|
let assemblyFormat = [{
|
|
$value attr-dict `:` type($value)
|
|
}];
|
|
|
|
let extraClassDeclaration = [{
|
|
bool isLvalueExpression() {
|
|
return true;
|
|
}
|
|
}];
|
|
}
|
|
|
|
def Clift_NegOp : Clift_UnaryArithmeticOp<"neg">;
|
|
def Clift_AddOp : Clift_BinaryArithmeticOp<"add", [Commutative]>;
|
|
def Clift_SubOp : Clift_BinaryArithmeticOp<"sub">;
|
|
def Clift_MulOp : Clift_BinaryArithmeticOp<"mul", [Commutative]>;
|
|
def Clift_DivOp : Clift_BinaryArithmeticOp<"div">;
|
|
def Clift_RemOp : Clift_BinaryArithmeticOp<"rem">;
|
|
|
|
def Clift_PtrAddOp : Clift_PointerArithmeticOp<"ptr_add", [Commutative]>;
|
|
def Clift_PtrSubOp : Clift_PointerArithmeticOp<"ptr_sub">;
|
|
|
|
def Clift_PtrDiffOp : Clift_ExpressionOp<"ptr_diff"> {
|
|
let arguments = (ins Clift_AnyPointerType:$lhs,
|
|
Clift_AnyPointerType:$rhs);
|
|
|
|
let results = (outs Clift_AnyNonConstType<AnyType>:$result);
|
|
|
|
let assemblyFormat = [{
|
|
$lhs `,` $rhs attr-dict `:`
|
|
custom<CliftOpOperandTypes>(type($lhs), type($rhs)) `->` type($result)
|
|
}];
|
|
|
|
let hasVerifier = 1;
|
|
}
|
|
|
|
def Clift_LogicalNotOp
|
|
: Clift_ExpressionOp<"not", [Clift_ReturnsBoolean]> {
|
|
|
|
let arguments = (ins Clift_AnyIntegerType:$value);
|
|
let results = (outs Clift_AnyNonConstType<Clift_AnyBooleanType>:$result);
|
|
|
|
let assemblyFormat = [{
|
|
$value attr-dict `:` type($value) `->` type($result)
|
|
}];
|
|
|
|
let extraClassDeclaration = [{
|
|
[[nodiscard]] bool isBooleanTestedOperand(mlir::OpOperand &Operand) {
|
|
return true;
|
|
}
|
|
}];
|
|
}
|
|
|
|
def Clift_LogicalAndOp : Clift_BinaryLogicalOp<"and">;
|
|
def Clift_LogicalOrOp : Clift_BinaryLogicalOp<"or">;
|
|
|
|
def Clift_BitwiseNotOp : Clift_UnaryArithmeticOp<"bitnot">;
|
|
def Clift_BitwiseAndOp : Clift_BinaryArithmeticOp<"bitand", [Commutative]>;
|
|
def Clift_BitwiseOrOp : Clift_BinaryArithmeticOp<"bitor", [Commutative]>;
|
|
def Clift_BitwiseXorOp : Clift_BinaryArithmeticOp<"bitxor", [Commutative]>;
|
|
|
|
def Clift_ShiftLeftOp : Clift_ShiftOp<"shl">;
|
|
def Clift_ShiftRightOp : Clift_ShiftOp<"shr">;
|
|
|
|
def Clift_CmpEqOp : Clift_ComparisonOp<"eq">;
|
|
def Clift_CmpNeOp : Clift_ComparisonOp<"ne">;
|
|
def Clift_CmpLtOp : Clift_ComparisonOp<"lt">;
|
|
def Clift_CmpGtOp : Clift_ComparisonOp<"gt">;
|
|
def Clift_CmpLeOp : Clift_ComparisonOp<"le">;
|
|
def Clift_CmpGeOp : Clift_ComparisonOp<"ge">;
|
|
|
|
def Clift_IncrementOp : Clift_UnaryIntegerMutationOp<"inc">;
|
|
def Clift_DecrementOp : Clift_UnaryIntegerMutationOp<"dec">;
|
|
|
|
def Clift_PostIncrementOp : Clift_UnaryIntegerMutationOp<"post_inc">;
|
|
def Clift_PostDecrementOp : Clift_UnaryIntegerMutationOp<"post_dec">;
|
|
|
|
class Clift_CastExpressionOp<string mnemonic, list<Trait> traits = []>
|
|
: Clift_BasicExpressionOp<mnemonic, Clift_CastOpInterface, traits>;
|
|
|
|
def Clift_DecayOp : Clift_CastExpressionOp<"decay"> {
|
|
let arguments = (ins AnyType:$value);
|
|
|
|
let results = (outs Clift_AnyNonConstType<AnyType>:$result);
|
|
|
|
let assemblyFormat = [{
|
|
$value attr-dict `:` type($value) `->` type($result)
|
|
}];
|
|
|
|
let hasVerifier = 1;
|
|
}
|
|
|
|
def Clift_BitCastOp
|
|
: Clift_CastExpressionOp<"bitcast",
|
|
[Clift_AllSizesMatch<["value", "result"]>]> {
|
|
|
|
let arguments = (ins Clift_AnyValueType:$value);
|
|
let results = (outs Clift_AnyNonConstType<Clift_AnyValueType>:$result);
|
|
|
|
let assemblyFormat = [{
|
|
$value attr-dict `:` type($value) `->` type($result)
|
|
}];
|
|
}
|
|
|
|
def Clift_ExtendOp : Clift_CastExpressionOp<"extend"> {
|
|
let arguments = (ins Clift_AnyIntegerType:$value);
|
|
|
|
let results = (outs Clift_AnyNonConstType<Clift_AnyIntegerType>:$result);
|
|
|
|
let assemblyFormat = [{
|
|
$value attr-dict `:` type($value) `->` type($result)
|
|
}];
|
|
|
|
let hasVerifier = 1;
|
|
}
|
|
|
|
def Clift_TruncateOp : Clift_CastExpressionOp<"truncate"> {
|
|
let arguments = (ins Clift_AnyIntegerType:$value);
|
|
|
|
let results = (outs Clift_AnyNonConstType<Clift_AnyIntegerType>:$result);
|
|
|
|
let assemblyFormat = [{
|
|
$value attr-dict `:` type($value) `->` type($result)
|
|
}];
|
|
|
|
let hasVerifier = 1;
|
|
}
|
|
|
|
def Clift_PtrResizeOp
|
|
: Clift_CastExpressionOp<"ptr_resize",
|
|
[Clift_AllPointeeTypesMatch<["value", "result"]>]> {
|
|
|
|
let arguments = (ins Clift_AnyPointerType:$value);
|
|
let results = (outs Clift_AnyNonConstType<Clift_AnyPointerType>:$result);
|
|
|
|
let assemblyFormat = [{
|
|
$value attr-dict `:` type($value) `->` type($result)
|
|
}];
|
|
|
|
let hasVerifier = 1;
|
|
}
|
|
|
|
def Clift_AddressofOp
|
|
: Clift_ExpressionOp<"addressof",
|
|
[Clift_PointeeTypeMatches<"result", "object">,
|
|
Clift_LValueOperand<"object">]> {
|
|
|
|
let arguments = (ins AnyType:$object);
|
|
let results = (outs Clift_AnyNonConstType<Clift_AnyPointerType>:$result);
|
|
|
|
let assemblyFormat = [{
|
|
$object attr-dict `:` type($result)
|
|
}];
|
|
}
|
|
|
|
def Clift_IndirectionOp
|
|
: Clift_ExpressionOp<"indirection",
|
|
[Clift_PointeeTypeMatches<"pointer", "result">]> {
|
|
|
|
let arguments = (ins Clift_AnyPointerType:$pointer);
|
|
let results = (outs Clift_AnyNonVoidType:$result);
|
|
|
|
let assemblyFormat = [{
|
|
$pointer attr-dict `:` type($pointer)
|
|
}];
|
|
|
|
let extraClassDeclaration = [{
|
|
bool isLvalueExpression() {
|
|
return true;
|
|
}
|
|
}];
|
|
}
|
|
|
|
def Clift_AssignOp
|
|
: Clift_ExpressionOp<"assign",
|
|
[AllTypesMatch<["lhs", "result"]>,
|
|
Clift_AllTypesMatch<["lhs", "rhs"]>,
|
|
Clift_LValueOperand<"lhs">]> {
|
|
|
|
let arguments = (ins Clift_AnyModifiableType<Clift_AnyValueType>:$lhs,
|
|
AnyType:$rhs);
|
|
|
|
let results = (outs AnyType:$result);
|
|
|
|
let assemblyFormat = [{
|
|
$lhs `,` $rhs attr-dict `:`
|
|
custom<CliftOpOperandTypes>(type($lhs), type($rhs))
|
|
}];
|
|
|
|
let extraClassDeclaration = [{
|
|
bool isLvalueExpression() {
|
|
return true;
|
|
}
|
|
}];
|
|
}
|
|
|
|
def Clift_AccessOp : Clift_ExpressionOp<"access"> {
|
|
let arguments = (ins AnyType:$value,
|
|
UnitAttr:$indirect,
|
|
I64Attr:$member_index);
|
|
|
|
let results = (outs AnyType:$result);
|
|
|
|
let assemblyFormat = [{
|
|
`<` (`indirect` $indirect^)? $member_index `>` $value attr-dict
|
|
`:` type($value) `->` type($result)
|
|
}];
|
|
|
|
let extraClassDeclaration = [{
|
|
[[nodiscard]] bool isIndirect() {
|
|
return getIndirect();
|
|
}
|
|
|
|
[[nodiscard]] bool isLvalueExpression();
|
|
|
|
[[nodiscard]] clift::ClassType getClassType();
|
|
[[nodiscard]] clift::FieldAttr getFieldAttr();
|
|
}];
|
|
|
|
let hasVerifier = 1;
|
|
}
|
|
|
|
def Clift_SubscriptOp
|
|
: Clift_ExpressionOp<"subscript",
|
|
[Clift_PointeeTypeMatches<"pointer", "result">]> {
|
|
let arguments = (ins AnyType:$pointer,
|
|
Clift_AnyIntegerType:$index);
|
|
|
|
let results = (outs AnyType:$result);
|
|
|
|
let assemblyFormat = [{
|
|
$pointer `,` $index attr-dict `:` `(` type($pointer) `,` type($index) `)`
|
|
}];
|
|
|
|
let extraClassDeclaration = [{
|
|
bool isLvalueExpression() {
|
|
return true;
|
|
}
|
|
}];
|
|
|
|
let hasVerifier = 1;
|
|
}
|
|
|
|
def Clift_CommaOp : Clift_ExpressionOp<"comma",
|
|
[AllTypesMatch<["rhs", "result"]>]> {
|
|
|
|
let arguments = (ins Clift_AnyAddressableType:$lhs,
|
|
Clift_AnyAddressableType:$rhs);
|
|
|
|
let results = (outs AnyType:$result);
|
|
|
|
let assemblyFormat = [{
|
|
$lhs `,` $rhs attr-dict `:` type($lhs) `,` type($rhs)
|
|
}];
|
|
|
|
let extraClassDeclaration = [{
|
|
bool isLvalueExpression() {
|
|
return clift::isLvalueExpression(getRhs());
|
|
}
|
|
|
|
[[nodiscard]] bool isDiscardedOperand(mlir::OpOperand &Operand) {
|
|
return &Operand == &getOperation()->getOpOperand(0);
|
|
}
|
|
}];
|
|
}
|
|
|
|
def Clift_UseOp
|
|
: Clift_ExpressionOp<"use",
|
|
[DeclareOpInterfaceMethods<SymbolUserOpInterface>]> {
|
|
|
|
let arguments = (ins FlatSymbolRefAttr:$symbol_name);
|
|
let results = (outs Clift_AnyAddressableType:$result);
|
|
|
|
let assemblyFormat = [{
|
|
$symbol_name attr-dict `:` type($result)
|
|
}];
|
|
|
|
let extraClassDeclaration = [{
|
|
bool isLvalueExpression() {
|
|
return true;
|
|
}
|
|
}];
|
|
}
|
|
|
|
def Clift_CallOp : Clift_ExpressionOp<"call"> {
|
|
let arguments = (ins AnyType:$function,
|
|
Variadic<AnyType>:$arguments);
|
|
|
|
let results = (outs Clift_AnyNonConstType<AnyType>:$result);
|
|
|
|
let hasCustomAssemblyFormat = 1;
|
|
let hasVerifier = 1;
|
|
|
|
let extraClassDeclaration = [{
|
|
FunctionType getFunctionType();
|
|
}];
|
|
}
|
|
|
|
def Clift_TernaryOp
|
|
: Clift_ExpressionOp<"ternary",
|
|
[Clift_AllTypesMatch<["lhs", "rhs"]>,
|
|
Clift_UnqualifiedTypeMatches<"lhs", "result">]> {
|
|
|
|
let arguments = (ins Clift_AnyScalarType:$condition,
|
|
AnyType:$lhs,
|
|
AnyType:$rhs);
|
|
|
|
let results = (outs Clift_AnyNonConstType<Clift_AnyAddressableType>:$result);
|
|
|
|
let assemblyFormat = [{
|
|
$condition `,` $lhs `,` $rhs attr-dict `:` `(`
|
|
custom<CliftTernaryOpTypes>(type($condition), type($lhs), type($rhs)) `)`
|
|
}];
|
|
|
|
let extraClassDeclaration = [{
|
|
[[nodiscard]] bool isBooleanTestedOperand(mlir::OpOperand &Operand) {
|
|
return &Operand == &getOperation()->getOpOperand(0);
|
|
}
|
|
}];
|
|
}
|
|
|
|
def Clift_AggregateOp : Clift_ExpressionOp<"aggregate"> {
|
|
let arguments = (ins Variadic<AnyType>:$initializers);
|
|
let results = (outs Clift_AnyNonConstType<AnyType>:$result);
|
|
|
|
let hasCustomAssemblyFormat = 1;
|
|
let hasVerifier = 1;
|
|
}
|
|
|
|
#endif
|