Add string constants.

pull/1/head
Stella Laurenzo 2020-06-07 15:46:28 -07:00
parent 869228e316
commit f3829b1d4f
8 changed files with 164 additions and 92 deletions

View File

@ -21,11 +21,12 @@ namespace Basicpy {
namespace BasicpyTypes { namespace BasicpyTypes {
enum Kind { enum Kind {
// Dialect types. // Dialect types.
UnknownType = TypeRanges::Basicpy, BoolType = TypeRanges::Basicpy,
NoneType,
BoolType,
EllipsisType, EllipsisType,
NoneType,
SlotObjectType, SlotObjectType,
StrType,
UnknownType,
// Dialect attributes. // Dialect attributes.
SingletonAttr, SingletonAttr,
@ -37,28 +38,6 @@ namespace detail {
struct SlotObjectTypeStorage; struct SlotObjectTypeStorage;
} // namespace detail } // namespace detail
/// An unknown type that could be any supported python type.
class UnknownType : public Type::TypeBase<UnknownType, Type> {
public:
using Base::Base;
static bool kindof(unsigned kind) {
return kind == BasicpyTypes::UnknownType;
}
static UnknownType get(MLIRContext *context) {
return Base::get(context, BasicpyTypes::UnknownType);
}
};
/// The type of the Python `None` value.
class NoneType : public Type::TypeBase<NoneType, Type> {
public:
using Base::Base;
static bool kindof(unsigned kind) { return kind == BasicpyTypes::NoneType; }
static NoneType get(MLIRContext *context) {
return Base::get(context, BasicpyTypes::NoneType);
}
};
/// Python 'bool' type (can contain values True or False, corresponding to /// Python 'bool' type (can contain values True or False, corresponding to
/// i1 constants of 0 or 1). /// i1 constants of 0 or 1).
class BoolType : public Type::TypeBase<BoolType, Type> { class BoolType : public Type::TypeBase<BoolType, Type> {
@ -82,6 +61,16 @@ public:
} }
}; };
/// The type of the Python `None` value.
class NoneType : public Type::TypeBase<NoneType, Type> {
public:
using Base::Base;
static bool kindof(unsigned kind) { return kind == BasicpyTypes::NoneType; }
static NoneType get(MLIRContext *context) {
return Base::get(context, BasicpyTypes::NoneType);
}
};
class SlotObjectType : public Type::TypeBase<SlotObjectType, Type, class SlotObjectType : public Type::TypeBase<SlotObjectType, Type,
detail::SlotObjectTypeStorage> { detail::SlotObjectTypeStorage> {
public: public:
@ -101,6 +90,28 @@ public:
} }
}; };
/// The type of the Python `str` values.
class StrType : public Type::TypeBase<StrType, Type> {
public:
using Base::Base;
static bool kindof(unsigned kind) { return kind == BasicpyTypes::StrType; }
static StrType get(MLIRContext *context) {
return Base::get(context, BasicpyTypes::StrType);
}
};
/// An unknown type that could be any supported python type.
class UnknownType : public Type::TypeBase<UnknownType, Type> {
public:
using Base::Base;
static bool kindof(unsigned kind) {
return kind == BasicpyTypes::UnknownType;
}
static UnknownType get(MLIRContext *context) {
return Base::get(context, BasicpyTypes::UnknownType);
}
};
#include "npcomp/Dialect/Basicpy/BasicpyOpsDialect.h.inc" #include "npcomp/Dialect/Basicpy/BasicpyOpsDialect.h.inc"
} // namespace Basicpy } // namespace Basicpy

View File

@ -38,11 +38,19 @@ class Basicpy_Op<string mnemonic, list<OpTrait> traits = []> :
// Dialect types // Dialect types
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
def Basicpy_UnknownType : DialectType<Basicpy_Dialect, def Basicpy_BoolType : DialectType<Basicpy_Dialect,
CPred<"$_self.isa<::mlir::NPCOMP::Basicpy::UnknownType>()">, CPred<"$_self.isa<::mlir::NPCOMP::Basicpy::BoolType>()">, "Bool type">,
"Unknown type"> { BuildableType<"$_builder.getType<::mlir::NPCOMP::Basicpy::BoolType>()"> {
let typeDescription = [{ let typeDescription = [{
An unknown type (for the current phase of processing). Type for 'True' and 'False' values.
}];
}
def Basicpy_EllipsisType : DialectType<Basicpy_Dialect,
CPred<"$_self.isa<::mlir::NPCOMP::Basicpy::EllipsisType>()">, "Ellipsis type">,
BuildableType<"$_builder.getType<::mlir::NPCOMP::Basicpy::EllipsisType>()"> {
let typeDescription = [{
Type of the Python 'Ellipsis' value.
}]; }];
} }
@ -54,14 +62,6 @@ def Basicpy_NoneType : DialectType<Basicpy_Dialect,
}]; }];
} }
def Basicpy_BoolType : DialectType<Basicpy_Dialect,
CPred<"$_self.isa<::mlir::NPCOMP::Basicpy::BoolType>()">, "Bool type">,
BuildableType<"$_builder.getType<::mlir::NPCOMP::Basicpy::BoolType>()"> {
let typeDescription = [{
Type for 'True' and 'False' values.
}];
}
def Basicpy_SlotObjectType : DialectType<Basicpy_Dialect, def Basicpy_SlotObjectType : DialectType<Basicpy_Dialect,
CPred<"$_self.isa<::mlir::NPCOMP::Basicpy::SlotObjectType>()">, CPred<"$_self.isa<::mlir::NPCOMP::Basicpy::SlotObjectType>()">,
"Slot object"> { "Slot object"> {
@ -72,11 +72,19 @@ def Basicpy_SlotObjectType : DialectType<Basicpy_Dialect,
}]; }];
} }
def Basicpy_EllipsisType : DialectType<Basicpy_Dialect, def Basicpy_StrType : DialectType<Basicpy_Dialect,
CPred<"$_self.isa<::mlir::NPCOMP::Basicpy::EllipsisType>()">, "Ellipsis type">, CPred<"$_self.isa<::mlir::NPCOMP::Basicpy::StrType>()">,"String type">,
BuildableType<"$_builder.getType<::mlir::NPCOMP::Basicpy::EllipsisType>()"> { BuildableType<"$_builder.getType<::mlir::NPCOMP::Basicpy::StrType>()"> {
let typeDescription = [{ let typeDescription = [{
Type of the Python 'Ellipsis' value. Represents values of the python 'str' type.
}];
}
def Basicpy_UnknownType : DialectType<Basicpy_Dialect,
CPred<"$_self.isa<::mlir::NPCOMP::Basicpy::UnknownType>()">,
"Unknown type"> {
let typeDescription = [{
An unknown type (for the current phase of processing).
}]; }];
} }

View File

@ -13,27 +13,6 @@ include "BasicpyDialect.td"
include "mlir/Interfaces/SideEffectInterfaces.td" include "mlir/Interfaces/SideEffectInterfaces.td"
include "mlir/IR/SymbolInterfaces.td" include "mlir/IR/SymbolInterfaces.td"
def Basicpy_UnknownCastOp : Basicpy_Op<"unknown_cast", [NoSideEffect]> {
let summary = "Casts to and from the UnknownType";
let arguments = (ins AnyType:$input);
let results = (outs AnyType:$result);
let assemblyFormat = "operands attr-dict `:` type(operands) `->` type(results)";
}
def Basicpy_SingletonOp : Basicpy_Op<"singleton", [
ConstantLike, NoSideEffect]> {
let summary = "Constant value for a singleton type";
let description = [{
Some types only have a single possible value, represented by the
SingletonAttr. This op allows creating constants of these types.
}];
let arguments = (ins);
let results = (outs
Basicpy_SingletonType:$result
);
let assemblyFormat = "attr-dict `:` type($result)";
}
def Basicpy_BoolConstantOp : Basicpy_Op<"bool_constant", [ def Basicpy_BoolConstantOp : Basicpy_Op<"bool_constant", [
ConstantLike, NoSideEffect]> { ConstantLike, NoSideEffect]> {
let summary = "A boolean constant"; let summary = "A boolean constant";
@ -92,4 +71,41 @@ def Basicpy_SlotObjectGetOp : Basicpy_Op<"slot_object_get", [
); );
} }
def Basicpy_StrConstantOp : Basicpy_Op<"str_constant", [
ConstantLike, NoSideEffect]> {
let summary = "Constant string value";
let description = [{
A string value of StrType. The value is represented by a StringAttr
that is UTF-8 encoded.
}];
let arguments = (ins
StrAttr:$value
);
let results = (outs
Basicpy_StrType:$result
);
let assemblyFormat = "$value attr-dict";
}
def Basicpy_SingletonOp : Basicpy_Op<"singleton", [
ConstantLike, NoSideEffect]> {
let summary = "Constant value for a singleton type";
let description = [{
Some types only have a single possible value, represented by the
SingletonAttr. This op allows creating constants of these types.
}];
let arguments = (ins);
let results = (outs
Basicpy_SingletonType:$result
);
let assemblyFormat = "attr-dict `:` type($result)";
}
def Basicpy_UnknownCastOp : Basicpy_Op<"unknown_cast", [NoSideEffect]> {
let summary = "Casts to and from the UnknownType";
let arguments = (ins AnyType:$input);
let results = (outs AnyType:$result);
let assemblyFormat = "operands attr-dict `:` type(operands) `->` type(results)";
}
#endif // NPCOMP_DIALECT_BASICPY_BASICPY_OPS #endif // NPCOMP_DIALECT_BASICPY_BASICPY_OPS

View File

@ -19,7 +19,8 @@ BasicpyDialect::BasicpyDialect(MLIRContext *context)
#define GET_OP_LIST #define GET_OP_LIST
#include "npcomp/Dialect/Basicpy/BasicpyOps.cpp.inc" #include "npcomp/Dialect/Basicpy/BasicpyOps.cpp.inc"
>(); >();
addTypes<EllipsisType, NoneType, BoolType, SlotObjectType, UnknownType>(); addTypes<BoolType, EllipsisType, NoneType, SlotObjectType, StrType,
UnknownType>();
// TODO: Make real ops for everything we need. // TODO: Make real ops for everything we need.
allowUnknownOperations(); allowUnknownOperations();
@ -30,14 +31,12 @@ Type BasicpyDialect::parseType(DialectAsmParser &parser) const {
if (parser.parseKeyword(&keyword)) if (parser.parseKeyword(&keyword))
return Type(); return Type();
if (keyword == "UnknownType")
return UnknownType::get(getContext());
if (keyword == "NoneType")
return NoneType::get(getContext());
if (keyword == "BoolType") if (keyword == "BoolType")
return BoolType::get(getContext()); return BoolType::get(getContext());
if (keyword == "EllipsisType") if (keyword == "EllipsisType")
return EllipsisType::get(getContext()); return EllipsisType::get(getContext());
if (keyword == "NoneType")
return NoneType::get(getContext());
if (keyword == "SlotObject") { if (keyword == "SlotObject") {
StringRef className; StringRef className;
if (parser.parseLess() || parser.parseKeyword(&className)) { if (parser.parseLess() || parser.parseKeyword(&className)) {
@ -56,6 +55,10 @@ Type BasicpyDialect::parseType(DialectAsmParser &parser) const {
return SlotObjectType::get(StringAttr::get(className, getContext()), return SlotObjectType::get(StringAttr::get(className, getContext()),
slotTypes); slotTypes);
} }
if (keyword == "StrType")
return StrType::get(getContext());
if (keyword == "UnknownType")
return UnknownType::get(getContext());
parser.emitError(parser.getNameLoc(), "unknown basicpy type"); parser.emitError(parser.getNameLoc(), "unknown basicpy type");
return Type(); return Type();
@ -63,18 +66,15 @@ Type BasicpyDialect::parseType(DialectAsmParser &parser) const {
void BasicpyDialect::printType(Type type, DialectAsmPrinter &os) const { void BasicpyDialect::printType(Type type, DialectAsmPrinter &os) const {
switch (type.getKind()) { switch (type.getKind()) {
case BasicpyTypes::UnknownType:
os << "UnknownType";
return;
case BasicpyTypes::NoneType:
os << "NoneType";
return;
case BasicpyTypes::BoolType: case BasicpyTypes::BoolType:
os << "BoolType"; os << "BoolType";
return; return;
case BasicpyTypes::EllipsisType: case BasicpyTypes::EllipsisType:
os << "EllipsisType"; os << "EllipsisType";
return; return;
case BasicpyTypes::NoneType:
os << "NoneType";
return;
case BasicpyTypes::SlotObjectType: { case BasicpyTypes::SlotObjectType: {
auto slotObject = type.cast<SlotObjectType>(); auto slotObject = type.cast<SlotObjectType>();
auto slotTypes = slotObject.getSlotTypes(); auto slotTypes = slotObject.getSlotTypes();
@ -86,6 +86,12 @@ void BasicpyDialect::printType(Type type, DialectAsmPrinter &os) const {
os << ">"; os << ">";
return; return;
} }
case BasicpyTypes::StrType:
os << "StrType";
return;
case BasicpyTypes::UnknownType:
os << "UnknownType";
return;
default: default:
llvm_unreachable("unexpected 'basicpy' type kind"); llvm_unreachable("unexpected 'basicpy' type kind");
} }

View File

@ -11,7 +11,7 @@ def import_global(f):
return f return f
# CHECK: func @integer_constants # CHECK-LABEL: func @integer_constants
@import_global @import_global
def integer_constants(): def integer_constants():
# CHECK: %[[A:.*]] = constant 100 : i64 # CHECK: %[[A:.*]] = constant 100 : i64
@ -20,7 +20,7 @@ def integer_constants():
# CHECK: return %[[A_CAST]] # CHECK: return %[[A_CAST]]
return a return a
# CHECK: func @float_constants # CHECK-LABEL: func @float_constants
@import_global @import_global
def float_constants(): def float_constants():
# CHECK: %[[A:.*]] = constant 2.200000e+00 : f64 # CHECK: %[[A:.*]] = constant 2.200000e+00 : f64
@ -29,7 +29,7 @@ def float_constants():
# CHECK: return %[[A_CAST]] # CHECK: return %[[A_CAST]]
return a return a
# CHECK: func @bool_true_constant # CHECK-LABEL: func @bool_true_constant
@import_global @import_global
def bool_true_constant(): def bool_true_constant():
# CHECK: %[[A:.*]] = basicpy.bool_constant 1 # CHECK: %[[A:.*]] = basicpy.bool_constant 1
@ -37,10 +37,27 @@ def bool_true_constant():
a = True a = True
return a return a
# CHECK: func @bool_false_constant # CHECK-LABEL: func @bool_false_constant
@import_global @import_global
def bool_false_constant(): def bool_false_constant():
# CHECK: %[[A:.*]] = basicpy.bool_constant 0 # CHECK: %[[A:.*]] = basicpy.bool_constant 0
# CHECK: basicpy.unknown_cast %[[A]] # CHECK: basicpy.unknown_cast %[[A]]
a = False a = False
return a return a
# CHECK-LABEL: func @string_constant
@import_global
def string_constant():
# CHECK: %[[A:.*]] = basicpy.str_constant "foobar"
# CHECK: basicpy.unknown_cast %[[A]]
a = "foobar"
return a
# CHECK-LABEL: func @joined_string_constant
@import_global
def joined_string_constant():
# CHECK: %[[A:.*]] = basicpy.str_constant "I am still here"
# CHECK: basicpy.unknown_cast %[[A]]
a = "I am" " still here"
return a

View File

@ -167,7 +167,7 @@ class FunctionDefImporter(BaseNodeVisitor):
ir_h = self.fctx.ir_h ir_h = self.fctx.ir_h
expr = ExpressionImporter(self.fctx) expr = ExpressionImporter(self.fctx)
expr.visit(ast_node.value) expr.visit(ast_node.value)
casted = ir_h.basicpy_unknown_cast(ir_h.basicpy_UnknownType, casted = ir_h.basicpy_unknown_cast_op(ir_h.basicpy_UnknownType,
expr.value).result expr.value).result
ir_h.return_op([casted]) ir_h.return_op([casted])
@ -208,6 +208,8 @@ class ExpressionImporter(BaseNodeVisitor):
self.value = ir_h.basicpy_bool_constant_op(False).result self.value = ir_h.basicpy_bool_constant_op(False).result
else: else:
self.fctx.abort("unknown named constant '%r'" % (ast_node.value,)) self.fctx.abort("unknown named constant '%r'" % (ast_node.value,))
elif isinstance(ast_node, ast.Str):
self.value = ir_h.basicpy_str_constant_op(ast_node.s).result
else: else:
self.fctx.abort("unknown constant type %s" % self.fctx.abort("unknown constant type %s" %
(ast_node.__class__.__name__)) (ast_node.__class__.__name__))

View File

@ -47,9 +47,6 @@ class DialectHelper(_BaseDialectHelper):
""" """
def basicpy_unknown_cast(self, result_type, operand):
return self.op("basicpy.unknown_cast", [result_type], [operand])
def basicpy_bool_constant_op(self, value): def basicpy_bool_constant_op(self, value):
c = self.context c = self.context
ival = 1 if value else 0 ival = 1 if value else 0
@ -57,7 +54,7 @@ class DialectHelper(_BaseDialectHelper):
"value": c.integer_attr(self.i1_type, ival) "value": c.integer_attr(self.i1_type, ival)
}) })
return self.op("basicpy.bool_constant", [self.basicpy_BoolType], [], attrs) return self.op("basicpy.bool_constant", [self.basicpy_BoolType], [], attrs)
def basicpy_singleton_op(self, singleton_type): def basicpy_singleton_op(self, singleton_type):
return self.op("basicpy.singleton", [singleton_type], []) return self.op("basicpy.singleton", [singleton_type], [])
@ -70,6 +67,16 @@ class DialectHelper(_BaseDialectHelper):
return self.op("basicpy.slot_object_make", [object_type], slot_values, return self.op("basicpy.slot_object_make", [object_type], slot_values,
attrs) attrs)
def basicpy_str_constant_op(self, value):
c = self.context
attrs = c.dictionary_attr({
"value": c.string_attr(value.encode("utf-8"))
})
return self.op("basicpy.str_constant", [self.basicpy_StrType], [], attrs)
def basicpy_unknown_cast_op(self, result_type, operand):
return self.op("basicpy.unknown_cast", [result_type], [operand])
if __name__ == "__main__": if __name__ == "__main__":
import doctest import doctest

View File

@ -21,16 +21,6 @@ public:
static void bind(py::module m) { static void bind(py::module m) {
py::class_<BasicpyDialectHelper, PyDialectHelper>(m, "BasicpyDialectHelper") py::class_<BasicpyDialectHelper, PyDialectHelper>(m, "BasicpyDialectHelper")
.def(py::init<std::shared_ptr<PyContext>>()) .def(py::init<std::shared_ptr<PyContext>>())
.def_property_readonly("basicpy_UnknownType",
[](BasicpyDialectHelper &self) -> PyType {
return Basicpy::UnknownType::get(
&self.context->context);
})
.def_property_readonly("basicpy_NoneType",
[](BasicpyDialectHelper &self) -> PyType {
return Basicpy::NoneType::get(
&self.context->context);
})
.def_property_readonly("basicpy_BoolType", .def_property_readonly("basicpy_BoolType",
[](BasicpyDialectHelper &self) -> PyType { [](BasicpyDialectHelper &self) -> PyType {
return Basicpy::BoolType::get( return Basicpy::BoolType::get(
@ -41,6 +31,11 @@ public:
return Basicpy::EllipsisType::get( return Basicpy::EllipsisType::get(
&self.context->context); &self.context->context);
}) })
.def_property_readonly("basicpy_NoneType",
[](BasicpyDialectHelper &self) -> PyType {
return Basicpy::NoneType::get(
&self.context->context);
})
.def("basicpy_SlotObject_type", .def("basicpy_SlotObject_type",
[](BasicpyDialectHelper &self, std::string className, [](BasicpyDialectHelper &self, std::string className,
py::args pySlotTypes) -> PyType { py::args pySlotTypes) -> PyType {
@ -53,6 +48,16 @@ public:
return Basicpy::SlotObjectType::get(classNameAttr, slotTypes); return Basicpy::SlotObjectType::get(classNameAttr, slotTypes);
}, },
py::arg("className")) py::arg("className"))
.def_property_readonly("basicpy_StrType",
[](BasicpyDialectHelper &self) -> PyType {
return Basicpy::StrType::get(
&self.context->context);
})
.def_property_readonly("basicpy_UnknownType",
[](BasicpyDialectHelper &self) -> PyType {
return Basicpy::UnknownType::get(
&self.context->context);
})
.def("basicpy_slot_object_get_op", .def("basicpy_slot_object_get_op",
[](BasicpyDialectHelper &self, PyValue slotObject, [](BasicpyDialectHelper &self, PyValue slotObject,
unsigned index) -> PyOperationRef { unsigned index) -> PyOperationRef {