Skip to content

Convert

convert

LLVMTarget dataclass

Bases: Target

Source code in xdsl/backend/llvm/convert.py
220
221
222
223
224
225
226
@dataclass(frozen=True)
class LLVMTarget(Target):
    name = "llvm"

    def emit(self, ctx: Context, module: ModuleOp, output: IO[str]) -> None:
        llvm_module = convert_module(module, fallback_target_triple=None)
        print(llvm_module, file=output)

name = 'llvm' class-attribute instance-attribute

__init__() -> None

emit(ctx: Context, module: ModuleOp, output: IO[str]) -> None

Source code in xdsl/backend/llvm/convert.py
224
225
226
def emit(self, ctx: Context, module: ModuleOp, output: IO[str]) -> None:
    llvm_module = convert_module(module, fallback_target_triple=None)
    print(llvm_module, file=output)

convert_module(module: ModuleOp, *, fallback_target_triple: str | None, data_layout: str = '') -> ir.Module

Convert an xDSL module to an LLVM module.

Parameters:

Name Type Description Default
module ModuleOp

The xDSL module to convert.

required
fallback_target_triple str | None

The target triple to use when the module does not carry an llvm.target_triple attribute. The triple of the resulting module is resolved as follows:

  1. If the module has an llvm.target_triple attribute, its value is always used and fallback_target_triple is ignored.
  2. Otherwise, if fallback_target_triple is not None, it is used as-is.
  3. Otherwise (it is None), the host's default triple, as reported by llvmlite.binding.get_default_triple(), is used.
required
data_layout str

The data layout to set on the resulting module. If empty, no data layout is set.

''

Returns:

Type Description
Module

The corresponding llvmlite IR module.

Raises:

Type Description
LLVMTranslationException

If the llvm.target_triple attribute is present but is not a StringAttr.

NotImplementedError

If the module contains an op that is not a llvm.func or llvm.global.

Source code in xdsl/backend/llvm/convert.py
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
def convert_module(
    module: ModuleOp,
    *,
    fallback_target_triple: str | None,
    data_layout: str = "",
) -> ir.Module:
    """
    Convert an xDSL module to an LLVM module.

    Args:
        module: The xDSL module to convert.
        fallback_target_triple: The target triple to use when the module does not
            carry an ``llvm.target_triple`` attribute. The triple of the resulting
            module is resolved as follows:

            1. If the module has an ``llvm.target_triple`` attribute, its value is
               always used and ``fallback_target_triple`` is ignored.
            2. Otherwise, if ``fallback_target_triple`` is not ``None``, it is used
               as-is.
            3. Otherwise (it is ``None``), the host's default triple, as reported by
               ``llvmlite.binding.get_default_triple()``, is used.
        data_layout: The data layout to set on the resulting module. If empty, no
            data layout is set.

    Returns:
        The corresponding llvmlite IR module.

    Raises:
        LLVMTranslationException: If the ``llvm.target_triple`` attribute is present
            but is not a ``StringAttr``.
        NotImplementedError: If the module contains an op that is not a ``llvm.func`` or ``llvm.global``.
    """
    llvm_module = ir.Module()
    module_triple = module.attributes.get("llvm.target_triple")
    if module_triple is not None:
        if not isinstance(module_triple, StringAttr):
            raise LLVMTranslationException(
                f"Unsupported llvm.target_triple attribute: {module_triple}"
            )
        llvm_module.triple = module_triple.data
    else:
        if fallback_target_triple is None:
            from llvmlite import binding

            fallback_target_triple = binding.get_default_triple()
        llvm_module.triple = fallback_target_triple
    if data_layout:
        llvm_module.data_layout = data_layout

    global_ops: list[llvm.GlobalOp] = []
    func_ops: list[llvm.FuncOp] = []
    for op in module.ops:
        match op:
            case llvm.GlobalOp():
                global_ops.append(op)
            case llvm.FuncOp():
                func_ops.append(op)
            case _:
                raise NotImplementedError(
                    f"Conversion not implemented for op: {op.name}"
                )

    # Convert globals first so that addressof lookups can always find them
    for global_op in global_ops:
        _convert_global(global_op, llvm_module)

    # Declare all functions (enables forward references)
    for op in func_ops:
        _declare_func(op, llvm_module)

    # Generate function bodies
    for func_op in func_ops:
        if func_op.body.blocks:
            _convert_func(func_op, llvm_module)

    return llvm_module