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 {
enum Kind {
// Dialect types.
UnknownType = TypeRanges::Basicpy,
NoneType,
BoolType,
BoolType = TypeRanges::Basicpy,
EllipsisType,
NoneType,
SlotObjectType,
StrType,
UnknownType,
// Dialect attributes.
SingletonAttr,
@ -37,28 +38,6 @@ namespace detail {
struct SlotObjectTypeStorage;
} // 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
/// i1 constants of 0 or 1).
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,
detail::SlotObjectTypeStorage> {
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"
} // namespace Basicpy

View File

@ -38,11 +38,19 @@ class Basicpy_Op<string mnemonic, list<OpTrait> traits = []> :
// Dialect types
//===----------------------------------------------------------------------===//
def Basicpy_UnknownType : DialectType<Basicpy_Dialect,
CPred<"$_self.isa<::mlir::NPCOMP::Basicpy::UnknownType>()">,
"Unknown type"> {
def Basicpy_BoolType : DialectType<Basicpy_Dialect,
CPred<"$_self.isa<::mlir::NPCOMP::Basicpy::BoolType>()">, "Bool type">,
BuildableType<"$_builder.getType<::mlir::NPCOMP::Basicpy::BoolType>()"> {
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,
CPred<"$_self.isa<::mlir::NPCOMP::Basicpy::SlotObjectType>()">,
"Slot object"> {
@ -72,11 +72,19 @@ def Basicpy_SlotObjectType : DialectType<Basicpy_Dialect,
}];
}
def Basicpy_EllipsisType : DialectType<Basicpy_Dialect,
CPred<"$_self.isa<::mlir::NPCOMP::Basicpy::EllipsisType>()">, "Ellipsis type">,
BuildableType<"$_builder.getType<::mlir::NPCOMP::Basicpy::EllipsisType>()"> {
def Basicpy_StrType : DialectType<Basicpy_Dialect,
CPred<"$_self.isa<::mlir::NPCOMP::Basicpy::StrType>()">,"String type">,
BuildableType<"$_builder.getType<::mlir::NPCOMP::Basicpy::StrType>()"> {
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/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", [
ConstantLike, NoSideEffect]> {
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

View File

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

View File

@ -11,7 +11,7 @@ def import_global(f):
return f
# CHECK: func @integer_constants
# CHECK-LABEL: func @integer_constants
@import_global
def integer_constants():
# CHECK: %[[A:.*]] = constant 100 : i64
@ -20,7 +20,7 @@ def integer_constants():
# CHECK: return %[[A_CAST]]
return a
# CHECK: func @float_constants
# CHECK-LABEL: func @float_constants
@import_global
def float_constants():
# CHECK: %[[A:.*]] = constant 2.200000e+00 : f64
@ -29,7 +29,7 @@ def float_constants():
# CHECK: return %[[A_CAST]]
return a
# CHECK: func @bool_true_constant
# CHECK-LABEL: func @bool_true_constant
@import_global
def bool_true_constant():
# CHECK: %[[A:.*]] = basicpy.bool_constant 1
@ -37,10 +37,27 @@ def bool_true_constant():
a = True
return a
# CHECK: func @bool_false_constant
# CHECK-LABEL: func @bool_false_constant
@import_global
def bool_false_constant():
# CHECK: %[[A:.*]] = basicpy.bool_constant 0
# CHECK: basicpy.unknown_cast %[[A]]
a = False
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
expr = ExpressionImporter(self.fctx)
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
ir_h.return_op([casted])
@ -208,6 +208,8 @@ class ExpressionImporter(BaseNodeVisitor):
self.value = ir_h.basicpy_bool_constant_op(False).result
else:
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:
self.fctx.abort("unknown constant type %s" %
(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):
c = self.context
ival = 1 if value else 0
@ -57,7 +54,7 @@ class DialectHelper(_BaseDialectHelper):
"value": c.integer_attr(self.i1_type, ival)
})
return self.op("basicpy.bool_constant", [self.basicpy_BoolType], [], attrs)
def basicpy_singleton_op(self, 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,
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__":
import doctest

View File

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