From 869228e316fb5bfb85b2224eb4ef012b2387aa1f Mon Sep 17 00:00:00 2001 From: Stella Laurenzo Date: Sun, 7 Jun 2020 15:15:19 -0700 Subject: [PATCH] Add bool constants. --- .../npcomp/Dialect/Basicpy/BasicpyDialect.h | 12 ++++++++++ .../npcomp/Dialect/Basicpy/BasicpyDialect.td | 24 ++++++++++++------- include/npcomp/Dialect/Basicpy/BasicpyOps.td | 14 +++++++++++ lib/Dialect/Basicpy/BasicpyDialect.cpp | 7 +++++- pytest/Compiler/constants.py | 17 +++++++++++++ pytest/lit.cfg.py | 2 +- python/npcomp/compiler/frontend.py | 12 ++++++++-- python/npcomp/compiler/logging.py | 5 +++- python/npcomp/dialect/Basicpy.py | 8 +++++++ python_native/NpcompDialect.cpp | 5 ++++ 10 files changed, 93 insertions(+), 13 deletions(-) diff --git a/include/npcomp/Dialect/Basicpy/BasicpyDialect.h b/include/npcomp/Dialect/Basicpy/BasicpyDialect.h index 6991438da..16a78a6ac 100644 --- a/include/npcomp/Dialect/Basicpy/BasicpyDialect.h +++ b/include/npcomp/Dialect/Basicpy/BasicpyDialect.h @@ -23,6 +23,7 @@ enum Kind { // Dialect types. UnknownType = TypeRanges::Basicpy, NoneType, + BoolType, EllipsisType, SlotObjectType, @@ -58,6 +59,17 @@ public: } }; +/// Python 'bool' type (can contain values True or False, corresponding to +/// i1 constants of 0 or 1). +class BoolType : public Type::TypeBase { +public: + using Base::Base; + static bool kindof(unsigned kind) { return kind == BasicpyTypes::BoolType; } + static BoolType get(MLIRContext *context) { + return Base::get(context, BasicpyTypes::BoolType); + } +}; + /// The type of the Python `Ellipsis` value. class EllipsisType : public Type::TypeBase { public: diff --git a/include/npcomp/Dialect/Basicpy/BasicpyDialect.td b/include/npcomp/Dialect/Basicpy/BasicpyDialect.td index eaa45694d..be0255834 100644 --- a/include/npcomp/Dialect/Basicpy/BasicpyDialect.td +++ b/include/npcomp/Dialect/Basicpy/BasicpyDialect.td @@ -46,6 +46,22 @@ def Basicpy_UnknownType : DialectType()">, "None type">, + BuildableType<"$_builder.getType<::mlir::NPCOMP::Basicpy::NoneType>()"> { + let typeDescription = [{ + Type of the Python 'None' value. + }]; +} + +def Basicpy_BoolType : DialectType()">, "Bool type">, + BuildableType<"$_builder.getType<::mlir::NPCOMP::Basicpy::BoolType>()"> { + let typeDescription = [{ + Type for 'True' and 'False' values. + }]; +} + def Basicpy_SlotObjectType : DialectType()">, "Slot object"> { @@ -56,14 +72,6 @@ def Basicpy_SlotObjectType : DialectType()">, "None type">, - BuildableType<"$_builder.getType<::mlir::NPCOMP::Basicpy::NoneType>()"> { - let typeDescription = [{ - Type of the Python 'None' value. - }]; -} - def Basicpy_EllipsisType : DialectType()">, "Ellipsis type">, BuildableType<"$_builder.getType<::mlir::NPCOMP::Basicpy::EllipsisType>()"> { diff --git a/include/npcomp/Dialect/Basicpy/BasicpyOps.td b/include/npcomp/Dialect/Basicpy/BasicpyOps.td index 2f80ccbaa..33232f005 100644 --- a/include/npcomp/Dialect/Basicpy/BasicpyOps.td +++ b/include/npcomp/Dialect/Basicpy/BasicpyOps.td @@ -34,6 +34,20 @@ def Basicpy_SingletonOp : Basicpy_Op<"singleton", [ let assemblyFormat = "attr-dict `:` type($result)"; } +def Basicpy_BoolConstantOp : Basicpy_Op<"bool_constant", [ + ConstantLike, NoSideEffect]> { + let summary = "A boolean constant"; + let description = [{ + A constant of type !basicpy.BoolType that can take either an i1 value + of 0 (False) or 1 (True). + }]; + let arguments = (ins I1Attr:$value); + let results = (outs + Basicpy_BoolType:$result + ); + let assemblyFormat = "$value attr-dict"; +} + def Basicpy_SlotObjectMakeOp : Basicpy_Op<"slot_object_make", [ NoSideEffect]> { let summary = "Creates an instance of a SlotObject type"; diff --git a/lib/Dialect/Basicpy/BasicpyDialect.cpp b/lib/Dialect/Basicpy/BasicpyDialect.cpp index 7f2e2d97c..8bbcbffa4 100644 --- a/lib/Dialect/Basicpy/BasicpyDialect.cpp +++ b/lib/Dialect/Basicpy/BasicpyDialect.cpp @@ -19,7 +19,7 @@ BasicpyDialect::BasicpyDialect(MLIRContext *context) #define GET_OP_LIST #include "npcomp/Dialect/Basicpy/BasicpyOps.cpp.inc" >(); - addTypes(); + addTypes(); // TODO: Make real ops for everything we need. allowUnknownOperations(); @@ -34,6 +34,8 @@ Type BasicpyDialect::parseType(DialectAsmParser &parser) const { 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 == "SlotObject") { @@ -67,6 +69,9 @@ void BasicpyDialect::printType(Type type, DialectAsmPrinter &os) const { case BasicpyTypes::NoneType: os << "NoneType"; return; + case BasicpyTypes::BoolType: + os << "BoolType"; + return; case BasicpyTypes::EllipsisType: os << "EllipsisType"; return; diff --git a/pytest/Compiler/constants.py b/pytest/Compiler/constants.py index b292f2e8a..706871a87 100644 --- a/pytest/Compiler/constants.py +++ b/pytest/Compiler/constants.py @@ -8,6 +8,7 @@ def import_global(f): fe.import_global_function(f) print("// -----") print(fe.ir_module.to_asm()) + return f # CHECK: func @integer_constants @@ -27,3 +28,19 @@ def float_constants(): # CHECK: %[[A_CAST:.*]] = basicpy.unknown_cast %[[A]] : f64 -> !basicpy.UnknownType # CHECK: return %[[A_CAST]] return a + +# CHECK: func @bool_true_constant +@import_global +def bool_true_constant(): + # CHECK: %[[A:.*]] = basicpy.bool_constant 1 + # CHECK: basicpy.unknown_cast %[[A]] + a = True + return a + +# CHECK: 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 diff --git a/pytest/lit.cfg.py b/pytest/lit.cfg.py index 5858213b7..dc7386d43 100644 --- a/pytest/lit.cfg.py +++ b/pytest/lit.cfg.py @@ -35,7 +35,7 @@ config.substitutions.append(('%shlibext', config.llvm_shlib_ext)) config.substitutions.append(('%PYTHON', config.python_executable)) llvm_config.with_system_environment( - ['HOME', 'INCLUDE', 'LIB', 'TMP', 'TEMP']) + ['HOME', 'INCLUDE', 'LIB', 'NPCOMP_DEBUG', 'TMP', 'TEMP']) llvm_config.use_default_substitutions() diff --git a/python/npcomp/compiler/frontend.py b/python/npcomp/compiler/frontend.py index 03c2facbb..1410477fd 100644 --- a/python/npcomp/compiler/frontend.py +++ b/python/npcomp/compiler/frontend.py @@ -64,7 +64,8 @@ class ImportFrontend: # Define the function. # TODO: Much more needs to be done here (arg/result mapping, etc) - logging.debug("Importing global function {}:\n{}", ast_fd.name, + logging.debug(":::::::") + logging.debug("::: Importing global function {}:\n{}", ast_fd.name, ast.dump(ast_fd, include_attributes=True)) h.builder.set_file_line_col(filename_ident, ast_fd.lineno, ast_fd.col_offset) @@ -181,7 +182,7 @@ class ExpressionImporter(BaseNodeVisitor): def visit(self, node): super().visit(node) assert self.value, ("ExpressionImporter did not assign a value (%r)" % - (node,)) + (ast.dump(node),)) def visit_Constant(self, ast_node): ir_c = self.fctx.ir_c @@ -200,6 +201,13 @@ class ExpressionImporter(BaseNodeVisitor): else: self.fctx.abort("unsupported numeric constant type: %r" % (nval,)) self.value = ir_h.constant_op(ir_type, ir_attr).result + elif isinstance(ast_node, ast.NameConstant): + if ast_node.value is True: + self.value = ir_h.basicpy_bool_constant_op(True).result + elif ast_node.value is False: + self.value = ir_h.basicpy_bool_constant_op(False).result + else: + self.fctx.abort("unknown named constant '%r'" % (ast_node.value,)) else: self.fctx.abort("unknown constant type %s" % (ast_node.__class__.__name__)) diff --git a/python/npcomp/compiler/logging.py b/python/npcomp/compiler/logging.py index b115d3e22..282ca7337 100644 --- a/python/npcomp/compiler/logging.py +++ b/python/npcomp/compiler/logging.py @@ -2,10 +2,13 @@ # See https://llvm.org/LICENSE.txt for license information. # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +import os import string import sys -_ENABLED = False +__all__ = ["debug"] + +_ENABLED = "NPCOMP_DEBUG" in os.environ _formatter = string.Formatter() diff --git a/python/npcomp/dialect/Basicpy.py b/python/npcomp/dialect/Basicpy.py index eae2d3678..0bd93e460 100644 --- a/python/npcomp/dialect/Basicpy.py +++ b/python/npcomp/dialect/Basicpy.py @@ -50,6 +50,14 @@ 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 + attrs = c.dictionary_attr({ + "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], []) diff --git a/python_native/NpcompDialect.cpp b/python_native/NpcompDialect.cpp index 6acf08af8..22d678f75 100644 --- a/python_native/NpcompDialect.cpp +++ b/python_native/NpcompDialect.cpp @@ -31,6 +31,11 @@ public: return Basicpy::NoneType::get( &self.context->context); }) + .def_property_readonly("basicpy_BoolType", + [](BasicpyDialectHelper &self) -> PyType { + return Basicpy::BoolType::get( + &self.context->context); + }) .def_property_readonly("basicpy_EllipsisType", [](BasicpyDialectHelper &self) -> PyType { return Basicpy::EllipsisType::get(