xref: /llvm-project/mlir/lib/Bindings/Python/DialectLLVM.cpp (revision 79d4d165638b7587937fc60431e0865fd73c9334)
1 //===- DialectLLVM.cpp - Pybind module for LLVM dialect API support -------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "mlir-c/Dialect/LLVM.h"
10 #include "mlir-c/IR.h"
11 #include "mlir-c/Support.h"
12 #include "mlir/Bindings/Python/PybindAdaptors.h"
13 #include <string>
14 
15 namespace py = pybind11;
16 using namespace llvm;
17 using namespace mlir;
18 using namespace mlir::python;
19 using namespace mlir::python::adaptors;
20 
21 void populateDialectLLVMSubmodule(const pybind11::module &m) {
22 
23   //===--------------------------------------------------------------------===//
24   // StructType
25   //===--------------------------------------------------------------------===//
26 
27   auto llvmStructType =
28       mlir_type_subclass(m, "StructType", mlirTypeIsALLVMStructType);
29 
30   llvmStructType.def_classmethod(
31       "get_literal",
32       [](py::object cls, const std::vector<MlirType> &elements, bool packed,
33          MlirLocation loc) {
34         CollectDiagnosticsToStringScope scope(mlirLocationGetContext(loc));
35 
36         MlirType type = mlirLLVMStructTypeLiteralGetChecked(
37             loc, elements.size(), elements.data(), packed);
38         if (mlirTypeIsNull(type)) {
39           throw py::value_error(scope.takeMessage());
40         }
41         return cls(type);
42       },
43       "cls"_a, "elements"_a, py::kw_only(), "packed"_a = false,
44       "loc"_a = py::none());
45 
46   llvmStructType.def_classmethod(
47       "get_identified",
48       [](py::object cls, const std::string &name, MlirContext context) {
49         return cls(mlirLLVMStructTypeIdentifiedGet(
50             context, mlirStringRefCreate(name.data(), name.size())));
51       },
52       "cls"_a, "name"_a, py::kw_only(), "context"_a = py::none());
53 
54   llvmStructType.def_classmethod(
55       "get_opaque",
56       [](py::object cls, const std::string &name, MlirContext context) {
57         return cls(mlirLLVMStructTypeOpaqueGet(
58             context, mlirStringRefCreate(name.data(), name.size())));
59       },
60       "cls"_a, "name"_a, "context"_a = py::none());
61 
62   llvmStructType.def(
63       "set_body",
64       [](MlirType self, const std::vector<MlirType> &elements, bool packed) {
65         MlirLogicalResult result = mlirLLVMStructTypeSetBody(
66             self, elements.size(), elements.data(), packed);
67         if (!mlirLogicalResultIsSuccess(result)) {
68           throw py::value_error(
69               "Struct body already set to different content.");
70         }
71       },
72       "elements"_a, py::kw_only(), "packed"_a = false);
73 
74   llvmStructType.def_classmethod(
75       "new_identified",
76       [](py::object cls, const std::string &name,
77          const std::vector<MlirType> &elements, bool packed, MlirContext ctx) {
78         return cls(mlirLLVMStructTypeIdentifiedNewGet(
79             ctx, mlirStringRefCreate(name.data(), name.length()),
80             elements.size(), elements.data(), packed));
81       },
82       "cls"_a, "name"_a, "elements"_a, py::kw_only(), "packed"_a = false,
83       "context"_a = py::none());
84 
85   llvmStructType.def_property_readonly(
86       "name", [](MlirType type) -> std::optional<std::string> {
87         if (mlirLLVMStructTypeIsLiteral(type))
88           return std::nullopt;
89 
90         MlirStringRef stringRef = mlirLLVMStructTypeGetIdentifier(type);
91         return StringRef(stringRef.data, stringRef.length).str();
92       });
93 
94   llvmStructType.def_property_readonly("body", [](MlirType type) -> py::object {
95     // Don't crash in absence of a body.
96     if (mlirLLVMStructTypeIsOpaque(type))
97       return py::none();
98 
99     py::list body;
100     for (intptr_t i = 0, e = mlirLLVMStructTypeGetNumElementTypes(type); i < e;
101          ++i) {
102       body.append(mlirLLVMStructTypeGetElementType(type, i));
103     }
104     return body;
105   });
106 
107   llvmStructType.def_property_readonly(
108       "packed", [](MlirType type) { return mlirLLVMStructTypeIsPacked(type); });
109 
110   llvmStructType.def_property_readonly(
111       "opaque", [](MlirType type) { return mlirLLVMStructTypeIsOpaque(type); });
112 
113   //===--------------------------------------------------------------------===//
114   // PointerType
115   //===--------------------------------------------------------------------===//
116 
117   mlir_type_subclass(m, "PointerType", mlirTypeIsALLVMPointerType)
118       .def_classmethod(
119           "get",
120           [](py::object cls, std::optional<unsigned> addressSpace,
121              MlirContext context) {
122             CollectDiagnosticsToStringScope scope(context);
123             MlirType type = mlirLLVMPointerTypeGet(
124                 context, addressSpace.has_value() ? *addressSpace : 0);
125             if (mlirTypeIsNull(type)) {
126               throw py::value_error(scope.takeMessage());
127             }
128             return cls(type);
129           },
130           "cls"_a, "address_space"_a = py::none(), py::kw_only(),
131           "context"_a = py::none())
132       .def_property_readonly("address_space", [](MlirType type) {
133         return mlirLLVMPointerTypeGetAddressSpace(type);
134       });
135 }
136 
137 PYBIND11_MODULE(_mlirDialectsLLVM, m) {
138   m.doc() = "MLIR LLVM Dialect";
139 
140   populateDialectLLVMSubmodule(m);
141 }
142