diff --git a/petra/__init__.py b/petra/__init__.py index b52f710c..fc3f4cd4 100644 --- a/petra/__init__.py +++ b/petra/__init__.py @@ -17,6 +17,7 @@ from .truth import And, Eq, Gt, Gte, Lt, Lte, Neq, Not, Or from .type import ( Bool_t, + Void_t, Float32_t, Float64_t, Int8_t, diff --git a/petra/call.py b/petra/call.py index 4a0a6f59..c688778f 100644 --- a/petra/call.py +++ b/petra/call.py @@ -20,10 +20,11 @@ class Call(Expr): A function call expression. """ - def __init__(self, name: str, args: List[Expr]): + def __init__(self, name: str, args: List[Expr], attributes: Optional[Tuple[str, ...]] = None): self.name = name self.args = args self.t: Union[Tuple[()], Optional[Type]] = None + self.attributes = attributes self.validate() def get_type(self) -> Type: @@ -63,7 +64,9 @@ def typecheck(self, ctx: TypeContext) -> None: def codegen(self, builder: ir.IRBuilder, ctx: CodegenContext) -> ir.Value: def codegen_arg(arg: Expr) -> ir.Value: return arg.codegen(builder, ctx) - args = tuple(map(codegen_arg, self.args)) func = ctx.funcs[self.name] - return builder.call(func, args) + output = builder.call(func, args) + if self.attributes is not None : + output.addParamAttr(self.attributes) + return output diff --git a/petra/function.py b/petra/function.py index 543cccd6..1673ec4f 100644 --- a/petra/function.py +++ b/petra/function.py @@ -5,7 +5,7 @@ import re from llvmlite import ir -from typing import Dict, List, Tuple +from typing import Dict, List, Tuple, Optional from .block import Block from .codegen import CodegenContext @@ -28,11 +28,13 @@ def __init__( t_out: Ftypeout, block: Block, functypes: Dict[str, Tuple[Ftypein, Ftypeout]], + attributes: Optional[Tuple[Tuple[str, ...], ...]] = None, ): self.name = name self.args = args self.t_out = t_out self.block = block + self.attributes = attributes self.validate() # Initial typecontext should contain arguments ctx = TypeContext(functypes, t_out) @@ -62,13 +64,19 @@ def typecheck(self, ctx: TypeContext) -> None: self.block.typecheck(ctx) def codegen(self, module: ir.Module, funcs: Dict[str, ir.Function]) -> None: + block = funcs[self.name].append_basic_block(name="start") builder = ir.IRBuilder(block) ctx = CodegenContext(funcs) - # Treat function arguments as variables declared at the beginning. for i, arg in enumerate(self.args): var = builder.alloca(arg.get_type().llvm_type(), name=arg.unique_name()) + if self.attributes is not None and i < len(self.attributes) and self.attributes[i] is not None: + x: ir.Argument = funcs[self.name].args[i] + for a in self.attributes[i]: + x.add_attribute(a) # FIXME: I'm not sure why I can't get this to type check builder.store(funcs[self.name].args[i], var) # type: ignore ctx.vars[arg] = var self.block.codegen(builder, ctx) + + diff --git a/petra/program.py b/petra/program.py index d5be3a27..c286cf0c 100644 --- a/petra/program.py +++ b/petra/program.py @@ -4,7 +4,7 @@ from __future__ import annotations # necessary to avoid forward declarations from llvmlite import ir, binding -from typing import Dict, List, Tuple +from typing import Dict, List, Tuple, Optional from .block import Block from .codegen import convert_func_type @@ -18,24 +18,51 @@ class Program(object): A Petra program. Petra programs can be codegen'ed to LLVM. """ - llvm_initialized: bool = False - def __init__(self, name: str): self.module = ir.Module(name=name) self.functypes: Dict[str, Tuple[Ftypein, Ftypeout]] = dict() self.funcs: Dict[str, ir.Function] = dict() + binding.initialize() + binding.initialize_native_target() + binding.initialize_native_asmprinter() + target: binding.Target = binding.Target.from_default_triple() + self.target_machine: binding.TargetMachine = target.create_target_machine() - def add_func_decl(self, name: str, t_in: Ftypein, t_out: Ftypeout) -> Program: + def add_func_decl( + self, + name: str, + t_in: Ftypein, + t_out: Ftypeout, + attributes: Optional[Tuple[Tuple[str, ...], ...]] = None, + func_attributes: Optional[Tuple[str, ...]] = None, + ) -> Program: if name in self.functypes: raise Exception("Function %s already exists in program." % name) self.functypes[name] = (t_in, t_out) self.funcs[name] = ir.Function( self.module, convert_func_type(t_in, t_out), name ) + if attributes is not None: + for i in range(len(attributes)): + if attributes[i] is None: + continue + x: ir.Argument = self.funcs[name].args[i] + for a in attributes[i]: + x.add_attribute(a) + if func_attributes is not None: + for a in func_attributes: + if a is not None: + self.funcs[name].attributes.add(a) return self def add_func( - self, name: str, args: Tuple[Symbol, ...], t_out: Ftypeout, block: Block, + self, + name: str, + args: Tuple[Symbol, ...], + t_out: Ftypeout, + block: Block, + attributes: Optional[Tuple[Tuple[str, ...], ...]] = None, + func_attributes: Optional[Tuple[str, ...]] = None, ) -> Program: if name in self.functypes: raise Exception("Function %s already exists in program." % name) @@ -44,7 +71,11 @@ def add_func( self.funcs[name] = ir.Function( self.module, convert_func_type(t_in, t_out), name ) - func = Function(name, args, t_out, block, self.functypes) + func = Function(name, args, t_out, block, self.functypes, attributes) + if func_attributes is not None: + for a in func_attributes: + if a is not None: + self.funcs[name].attributes.add(a) func.codegen(self.module, self.funcs) return self @@ -52,32 +83,20 @@ def to_llvm(self) -> str: return str(self.module) def save_object(self, filename: str) -> None: - if not self.llvm_initialized: - self.llvm_initialized = True - binding.initialize() - binding.initialize_native_target() - binding.initialize_native_asmprinter() - # FIXME: Not sure why MyPy can't type check this, maybe a bug - target = binding.Target.from_default_triple() # type: ignore - target_machine = target.create_target_machine() backing_mod = binding.parse_assembly(self.to_llvm()) with open(filename, "wb") as f: - f.write(target_machine.emit_object(backing_mod)) + f.write(self.target_machine.emit_object(backing_mod)) def compile(self) -> binding.ExecutionEngine: - if not self.llvm_initialized: - self.llvm_initialized = True - binding.initialize() - binding.initialize_native_target() - binding.initialize_native_asmprinter() - # FIXME: Not sure why MyPy can't type check this, maybe a bug - target = binding.Target.from_default_triple() # type: ignore - target_machine = target.create_target_machine() + print(self.to_llvm()) backing_mod = binding.parse_assembly(self.to_llvm()) - engine = binding.create_mcjit_compiler(backing_mod, target_machine) + engine = binding.create_mcjit_compiler(backing_mod, self.target_machine) engine.finalize_object() engine.run_static_constructors() return engine + def get_target_machine(self) -> binding.TargetMachine: + return self.target_machine + def load_library(self, filename: str) -> None: - binding.load_library_permanently(filename) + binding.load_library_permanently(filename) \ No newline at end of file diff --git a/petra/type.py b/petra/type.py index 33048927..ef65d18a 100644 --- a/petra/type.py +++ b/petra/type.py @@ -1,158 +1,181 @@ -""" -This file defines Petra types. -""" - -from abc import ABC, abstractmethod -from llvmlite import ir -from typing import Generic, Optional, Tuple, TypeVar, Union, List, Dict - -from .validate import ValidateError - - -class Type(object): - """ - A type. - """ - - def __init__(self, name: str): - self.name = name - - def __str__(self) -> str: - return self.name - - def llvm_type(self) -> ir.Type: - """ - Return the LLVM type of the given type. - """ - assert False, "unimplemented" - - -_T = TypeVar("_T") - - -class ValueType(Type, Generic[_T]): - def validate(self, value: _T) -> None: - """ - Validate values of the type. - """ - assert False, "unimplemented" - - -class IntType(ValueType[int]): - """ - An integer type. - """ - - def __init__(self, bits: int): - super().__init__("Int%d_t" % bits) - self.bits = bits - - def validate(self, value: int) -> None: - exp = self.bits - 1 - if not (-(1 << exp) <= value < (1 << exp)): - raise ValidateError( - "Int%d_t value not in the range [-2**%d, 2**%d)." - % (self.bits, exp, exp) - ) - - def llvm_type(self) -> ir.Type: - return ir.IntType(self.bits) - - -class FloatType(ValueType[float]): - """ - A floating point type. - """ - - def __init__(self, bits: int, name: Optional[str] = None): - if bits not in (32, 64): - raise ValidateError("Float bits must be 32 or 64") - super().__init__(name or "Float%d_t" % bits) - self.bits = bits - - def validate(self, value: float) -> None: - pass - - def llvm_type(self) -> ir.Type: - if self.bits == 32: - return ir.FloatType() - elif self.bits == 64: - return ir.DoubleType() - else: - assert False - - -class BoolType(ValueType[bool]): - """ - A boolean type. - """ - - def __init__(self) -> None: - super().__init__("Bool_t") - - def validate(self, value: bool) -> None: - pass - - def llvm_type(self) -> ir.Type: - return ir.IntType(1) - - -class PointerType(Type): - """ - A pointer type. - """ - - def __init__(self, pointee: Type) -> None: - super().__init__("PointerType(%s)" % pointee) - self.pointee = pointee - - def llvm_type(self) -> ir.Type: - return ir.PointerType(self.pointee.llvm_type()) - - -class StructType(Type): - """ - A struct type. - """ - - def __init__(self, elements: Dict[str, Type]) -> None: - super().__init__("StructType(%s)" % elements) - self.elements = tuple(elements.values()) - llvm_elements = [t.llvm_type() for t in elements.values()] - self.struct_type = ir.LiteralStructType(llvm_elements) - self.name_to_index: Dict[str, int] = {} - for i, name in enumerate(elements.keys()): - self.name_to_index[name] = i - - def llvm_type(self) -> ir.Type: - return self.struct_type - - -class ArrayType(Type): - """ - An array type. - """ - - def __init__(self, element: Type, length: int) -> None: - super().__init__("ArrayType(%s, %s)" % (element, length)) - self.element = element - self.length = length - self.array_type = ir.ArrayType(self.element.llvm_type(), self.length) - - def llvm_type(self) -> ir.Type: - return self.array_type - - -# Type aliases for functions. -Ftypein = Tuple[Type, ...] -Ftypeout = Union[Tuple[()], Type] - -Int8_t = IntType(8) -Int16_t = IntType(16) -Int32_t = IntType(32) -Int64_t = IntType(64) - -Float32_t = FloatType(32) -Float64_t = FloatType(64) - -Bool_t = BoolType() +""" +This file defines Petra types. +""" + +from abc import ABC, abstractmethod +from llvmlite import ir +from typing import Generic, Optional, Tuple, TypeVar, Union, List, Dict + +from .validate import ValidateError + + +class Type(object): + """ + A type. + """ + + def __init__(self, name: str): + self.name = name + + def __str__(self) -> str: + return self.name + + def llvm_type(self) -> ir.Type: + """ + Return the LLVM type of the given type. + """ + assert False, "unimplemented" + + +_T = TypeVar("_T") + + +class ValueType(Type, Generic[_T]): + def validate(self, value: _T) -> None: + """ + Validate values of the type. + """ + assert False, "unimplemented" + + +class IntType(ValueType[int]): + """ + An integer type. + """ + + def __init__(self, bits: int): + super().__init__("Int%d_t" % bits) + self.bits = bits + + def validate(self, value: int) -> None: + exp = self.bits - 1 + if not (-(1 << exp) <= value < (1 << exp)): + raise ValidateError( + "Int%d_t value not in the range [-2**%d, 2**%d)." + % (self.bits, exp, exp) + ) + + def llvm_type(self) -> ir.Type: + return ir.IntType(self.bits) + + +class FloatType(ValueType[float]): + """ + A floating point type. + """ + + def __init__(self, bits: int, name: Optional[str] = None): + if bits not in (32, 64): + raise ValidateError("Float bits must be 32 or 64") + super().__init__(name or "Float%d_t" % bits) + self.bits = bits + + def validate(self, value: float) -> None: + pass + + def llvm_type(self) -> ir.Type: + if self.bits == 32: + return ir.FloatType() + elif self.bits == 64: + return ir.DoubleType() + else: + assert False + + +class BoolType(ValueType[bool]): + """ + A boolean type. + """ + + def __init__(self) -> None: + super().__init__("Bool_t") + + def validate(self, value: bool) -> None: + pass + + def llvm_type(self) -> ir.Type: + return ir.IntType(1) + + +class VoidType(Type): + """ + A void type. + """ + + def __init__(self) -> None: + super().__init__("Void_t") + + def validate(self, value: None) -> None: + pass + + def llvm_type(self) -> ir.Type: + # return ir.VoidType() + return ir.IntType(8) + + +# equality to ckeck if the types are the same __eq__ +class PointerType(Type): + """ + A pointer type. + """ + + def __init__(self, pointee: Type) -> None: + super().__init__("PointerType(%s)" % pointee) + self.pointee = pointee + + def __eq__(self, other: object) -> bool: + if not isinstance(other, PointerType): + return False + return (self.pointee == other.pointee) + + def llvm_type(self) -> ir.Type: + return ir.PointerType(self.pointee.llvm_type()) + + +class StructType(Type): + """ + A struct type. + """ + + def __init__(self, elements: Dict[str, Type]) -> None: + super().__init__("StructType(%s)" % elements) + self.elements = tuple(elements.values()) + llvm_elements = [t.llvm_type() for t in elements.values()] + self.struct_type = ir.LiteralStructType(llvm_elements) + self.name_to_index: Dict[str, int] = {} + for i, name in enumerate(elements.keys()): + self.name_to_index[name] = i + + def llvm_type(self) -> ir.Type: + return self.struct_type + + +class ArrayType(Type): + """ + An array type. + """ + + def __init__(self, element: Type, length: int) -> None: + super().__init__("ArrayType(%s, %s)" % (element, length)) + self.element = element + self.length = length + self.array_type = ir.ArrayType(self.element.llvm_type(), self.length) + + def llvm_type(self) -> ir.Type: + return self.array_type + + +# Type aliases for functions. +Ftypein = Tuple[Type, ...] +Ftypeout = Union[Tuple[()], Type] + +Int8_t = IntType(8) +Int16_t = IntType(16) +Int32_t = IntType(32) +Int64_t = IntType(64) + +Float32_t = FloatType(32) +Float64_t = FloatType(64) + +Bool_t = BoolType() +Void_t = VoidType() \ No newline at end of file diff --git a/run_tests.sh b/run_tests.sh index ca47e26e..f50e6696 100755 --- a/run_tests.sh +++ b/run_tests.sh @@ -2,4 +2,6 @@ set -e +export LD_LIBRARY_PATH=$PWD/tests + python3 -m unittest discover -v tests diff --git a/stubs/llvmlite/ir/instructions.pyi b/stubs/llvmlite/ir/instructions.pyi index 95700c41..0ab5f96a 100644 --- a/stubs/llvmlite/ir/instructions.pyi +++ b/stubs/llvmlite/ir/instructions.pyi @@ -62,6 +62,7 @@ class CallInstr(Instruction): @property def called_function(self): ... def descr(self, buf: Any) -> None: ... + def addParamAttr(self, attributes:Tuple[str, ...]) -> None: ... class InvokeInstr(CallInstr): opname: str = ... diff --git a/stubs/llvmlite/ir/values.pyi b/stubs/llvmlite/ir/values.pyi index 99e3632d..0999d9fa 100644 --- a/stubs/llvmlite/ir/values.pyi +++ b/stubs/llvmlite/ir/values.pyi @@ -127,7 +127,7 @@ class Function(GlobalValue, _HasMetadata): ftype: Any = ... scope: Any = ... blocks: List[Block] = ... - attributes: Any = ... + attributes: ir.FunctionAttributesr = ... args: Tuple[Argument, ...] = ... return_value: Any = ... calling_convention: str = ... @@ -148,7 +148,7 @@ class Function(GlobalValue, _HasMetadata): def is_declaration(self): ... class ArgumentAttributes(AttributeSet): - def __init__(self, args: Any = ...) -> None: ... + def __init__(self, args: Tuple[Argument, ...] = ...) -> None: ... @property def align(self): ... @align.setter @@ -163,10 +163,10 @@ class ArgumentAttributes(AttributeSet): def dereferenceable_or_null(self, val: Any) -> None: ... class _BaseArgument(NamedValue): - parent: Any = ... - attributes: Any = ... - def __init__(self, parent: Any, typ: Any, name: str = ...) -> None: ... - def add_attribute(self, attr: Any) -> None: ... + parent: Argument = ... + attributes: str = ... + def __init__(self, parent: Argument, typ: Value, name: str = ...) -> None: ... + def add_attribute(self, attr: str) -> None: ... class Argument(_BaseArgument): ... class ReturnValue(_BaseArgument): ... diff --git a/tests/Makefile b/tests/Makefile new file mode 100644 index 00000000..3b34dc00 --- /dev/null +++ b/tests/Makefile @@ -0,0 +1,22 @@ +BIN := libtest_struct.so +FILENAME := test_structs.c.o +LDFLAGS += -shared +CFLAGS += -fPIC + +.SUFFIXES: # disable builtin rules (results in cyclic dependency on .py) + +.PHONY: all +all: $(BIN) + +%.c.o: %.c + $(CC) $(CFLAGS) $^ -c -o $@ + +$(BIN): $(FILENAME) + $(CC) $(CFLAGS) $^ $(LDFLAGS) -o $@ + +.PHONY: clean +clean: + rm -f $(BIN) *.o + + +## need to run "export LD_LIBRARY_PATH=$PWD/tests" \ No newline at end of file diff --git a/tests/libtest_struct.so b/tests/libtest_struct.so new file mode 100755 index 00000000..9abcfeaa Binary files /dev/null and b/tests/libtest_struct.so differ diff --git a/tests/proj_functor.c b/tests/proj_functor.c new file mode 100644 index 00000000..2548aac2 --- /dev/null +++ b/tests/proj_functor.c @@ -0,0 +1,28 @@ +#define LEGION_ENABLE_C_BINDINGS +#include "legion.h" +​ +// for x in D: +// my_task(p[x + 1]) +legion_logical_region_t my_projection_functor( + legion_runtime_t runtime, + legion_logical_partition_t parent, // p // struct + legion_domain_point_t point, // x + legion_domain_t domain) // D +{ + // legion_point_1d_t is a struct + // legion_point_1d_t.x is an array + // legion_logical_partition_t is an array + // legion_domain_point_t is a struct + // legion_domain_t is an array + // legion_runtime_t is a struct // opaque + // return type: legion_logical_region_t is a struct + legion_point_1d_t point1d = legion_domain_point_get_point_1d(point); + // int 64 + coord_t x = point1d.x[0]; + coord_t x_plus_1 = x + 1; + legion_point_1d_t point1d_x_plus_1; + point1d_x_plus_1.x[0] = x_plus_1; + legion_domain_point_t domain_point_x_plus_1 = legion_domain_point_from_point_1d(point1d_x_plus_1); + legion_logical_region_t result = legion_logical_partition_get_logical_subregion_by_color_domain_point(runtime, parent, domain_point_x_plus_1); + return result; +} \ No newline at end of file diff --git a/tests/test_proj_functor.py b/tests/test_proj_functor.py new file mode 100644 index 00000000..337a8cf1 --- /dev/null +++ b/tests/test_proj_functor.py @@ -0,0 +1,181 @@ +from typing import cast, Callable + +import subprocess +import petra as pt +import unittest + +from ctypes import CFUNCTYPE, c_int32 + +program = pt.Program("module") + +# Global variables +LEGION_MAX_DIM = 2 +MAX_DOMAIN_DIM = 2 * LEGION_MAX_DIM +DIM = 1 + +# Define types: +legion_region_tree_id_t = pt.Int32_t # unsigned int +legion_index_partition_id_t = pt.Int32_t # unsigned int +legion_index_tree_id_t = pt.Int32_t # unsigned int +legion_type_tag_t = pt.Int32_t # unsigned int +legion_field_space_id_t = pt.Int32_t # unsigned int +coord_t = pt.Int64_t # long long +legion_index_space_id_t = pt.Int32_t # unsigned int +realm_id_t = pt.Int64_t # unsigned long long + +# Add void type in Types +legion_runtime_t = pt.StructType({"impl": pt.PointerType(pt.Int64_t)}) + +legion_index_partition_t = pt.StructType( + { + "id": legion_index_partition_id_t, + "tid": legion_index_tree_id_t, + "type_tag": legion_type_tag_t, + } +) + +legion_field_space_t = pt.StructType({"id": legion_field_space_id_t}) + +legion_logical_partition_t = pt.StructType( + { + "tree_id": legion_region_tree_id_t, + "index_partition": legion_index_partition_t, + "field_space": legion_field_space_t, + } +) + +legion_domain_point_t = pt.StructType( # dim is an int #change from 32 to 64? + {"dim": pt.Int32_t, "point_data": pt.ArrayType(coord_t, LEGION_MAX_DIM)} +) + +legion_domain_t = pt.StructType( + { + "is_id": realm_id_t, + "dim": pt.Int32_t, + "rect_data": pt.ArrayType(coord_t, MAX_DOMAIN_DIM), + } +) + +legion_point_1d_array = pt.ArrayType(coord_t, DIM) + +legion_point_1d_t = pt.StructType({"x": legion_point_1d_array}) + +legion_index_space_t = pt.StructType( + { + "id": legion_index_space_id_t, + "tid": legion_index_tree_id_t, + "type_tag": legion_type_tag_t, + } +) + +legion_logical_region_t = pt.StructType( + { + "tree_id": legion_region_tree_id_t, + "index_space": legion_index_space_t, + "field_space": legion_field_space_t, + } +) + +# Define functions: +# these functions take pointers +#everything is a ptr except runtime +program.add_func_decl( + "legion_domain_point_get_point_1d", (legion_domain_point_t,), legion_point_1d_t, attributes=("byval",) +) +program.add_func_decl( + "legion_domain_point_from_point_1d", (legion_point_1d_t,), legion_domain_point_t, attributes=("byval",) +) +program.add_func_decl( + "legion_logical_partition_get_logical_subregion_by_color_domain_point", + (legion_runtime_t, legion_logical_partition_t, legion_domain_point_t,), + legion_logical_region_t, + attributes=("byval", "byval", "byval"), +) + +# Define variables: +runtime = pt.Symbol(legion_runtime_t, "runtime_ptr") +parent_ptr = pt.Symbol(pt.PointerType(legion_logical_partition_t), "parent_ptr") +point_ptr = pt.Symbol(pt.PointerType(legion_domain_point_t), "point_ptr") +domain_ptr = pt.Symbol(pt.PointerType(legion_domain_t), "domain_ptr") +point1d = pt.Symbol(legion_point_1d_t, "point1d") +point1d_x = pt.Symbol(legion_point_1d_array, "point1d_x") +x = pt.Symbol(coord_t, "x") +x_plus_1 = pt.Symbol(coord_t, "x_plus_1") +point1d_x_plus_1 = pt.Symbol(legion_point_1d_t, "point1d_x_plus_1") +domain_point_x_plus_1 = pt.Symbol(legion_domain_point_t, "domain_point_x_plus_1") +result = pt.Symbol(legion_logical_region_t, "result") +point1d_x_plus_1_x = pt.Symbol(pt.ArrayType(coord_t, DIM), "point1d_x_plus_1_x") + +program.add_func( + "proj_functor", + (runtime_ptr, parent_ptr, point_ptr, domain_ptr,), + legion_logical_region_t, + pt.Block( + [ + pt.DefineVar( + point1d, pt.Call("legion_domain_point_get_point_1d", [pt.Deref(pt.Var(point_ptr))]) + ), + pt.DefineVar(point1d_x, pt.GetElement(pt.Var(point1d), name="x"),), + pt.DefineVar(x, pt.GetElement(pt.Var(point1d_x), idx=0)), + pt.DefineVar(x_plus_1, pt.Add(pt.Var(x), pt.Int64(1))), + pt.DefineVar(point1d_x_plus_1_x), + pt.Assign( + pt.Var(point1d_x_plus_1_x), + pt.SetElement(pt.Var(point1d_x_plus_1_x), pt.Var(x_plus_1), 0), + ), + pt.DefineVar(point1d_x_plus_1), + pt.Assign( + pt.Var(point1d_x_plus_1), + pt.SetElement( + pt.Var(point1d_x_plus_1), pt.Var(point1d_x_plus_1_x), name="x" + ), + ), + pt.DefineVar( + domain_point_x_plus_1, + pt.Call( + "legion_domain_point_from_point_1d", [pt.Var(point1d_x_plus_1)] + ), + ), + pt.DefineVar( + result, + pt.Call( + "legion_logical_partition_get_logical_subregion_by_color_domain_point", + [pt.Var(runtime), pt.Deref(pt.Var(parent_ptr)), pt.Var(domain_point_x_plus_1)], + ), + ), + pt.Return(pt.Var(result)), + ] + ), + attributes=("byval", "byval", "byval", "byval"), +) + + +class ProjectionFunctor(unittest.TestCase): + def setUp(self) -> None: + program.load_library("libtest_proj_functor.so") + self.engine = program.compile() + + proj_functor = self.engine.get_function_address("proj_functor") + self.proj_functor = cast(Callable[[], int], CFUNCTYPE(c_int32)(proj_functor)) + + # self.proj_functor = cast( + # Callable[ + # [ + # legion_runtime_t, + # legion_logical_partition_t, + # legion_domain_point_t, + # legion_domain_t, + # ], + # legion_logical_region_t, + # ], + # CFUNCTYPE( + # legion_runtime_t, + # legion_logical_partition_t, + # legion_domain_point_t, + # legion_domain_t, + # legion_logical_region_t, + # )(proj_functor) + # ) + + def test_proj_functor(self) -> None: + self.assertEqual(self.proj_functor(), 0) diff --git a/tests/test_structs.c b/tests/test_structs.c new file mode 100644 index 00000000..74652ddf --- /dev/null +++ b/tests/test_structs.c @@ -0,0 +1,26 @@ +#include + +struct my_struct +{ + int a, b, c; +}; + +//given a struct with elements all one digit ints, return the ints right next to each other (3 digit int) +int test_struct_input(struct my_struct x){ + return x.a * 100 + x.b * 10 + x.c; +} + +//given 3 ints put them in the struct my_struct and return that +struct my_struct test_struct_output(int a, int b, int c){ + struct my_struct output; + output.a = a; + output.b = b; + output.c = c; + return output; +} + +int main(){ + struct my_struct x = {4, 4, 4}; + printf("%d\n", test_struct_input(x)); + printf("%d\n", test_struct_input(test_struct_output(5, 5, 5))); +} diff --git a/tests/test_structs.py b/tests/test_structs.py index 5870f926..230ad5ae 100644 --- a/tests/test_structs.py +++ b/tests/test_structs.py @@ -1,57 +1,87 @@ -from typing import cast, Callable - -import subprocess -import petra as pt -import unittest - -from ctypes import CFUNCTYPE, c_int32 - -program = pt.Program("module") - -My_Struct = pt.StructType({"a": pt.Int32_t, "b": pt.Int32_t, "c": pt.Int32_t}) -struct_var = pt.Symbol(My_Struct, "struct_var") - -program.add_func( - "struct_set_get_field", - (), - pt.Int32_t, - pt.Block( - [ - pt.DefineVar(struct_var), - pt.Assign( - pt.Var(struct_var), - pt.SetElement(pt.Var(struct_var), pt.Int32(1), name="a"), - ), - pt.Assign( - pt.Var(struct_var), - pt.SetElement(pt.Var(struct_var), pt.Int32(2), idx=1), - ), - pt.Assign( - pt.Var(struct_var), - pt.SetElement(pt.Var(struct_var), pt.Int32(3), name="c"), - ), - pt.Return( - pt.Add( - pt.GetElement(pt.Var(struct_var), name="b"), - pt.Add( - pt.GetElement(pt.Var(struct_var), idx=2), - pt.GetElement(pt.Var(struct_var), name="a"), - ), - ) - ), - ] - ), -) - - -class StructsTestCase(unittest.TestCase): - def setUp(self) -> None: - self.engine = program.compile() - - struct_set_get_field = self.engine.get_function_address("struct_set_get_field") - self.struct_set_get_field = cast( - Callable[[], int], CFUNCTYPE(c_int32)(struct_set_get_field) - ) - - def test_struct_set_get_field(self) -> None: - self.assertEqual(self.struct_set_get_field(), 6) +# from typing import cast, Callable + +# import subprocess +# import petra as pt +# import unittest + +# from ctypes import CFUNCTYPE, c_int32, c_int64 + +# program = pt.Program("module") + +# My_Struct = pt.StructType({"a": pt.Int64_t, "b": pt.Int64_t, "c": pt.Int64_t}) +# struct_var = pt.Symbol(My_Struct, "struct_var") + +# # int test_struct_input(struct my_struct x) +# program.add_func_decl("test_struct_input", (My_Struct,), pt.Int64_t) + +# # struct my_struct test_struct_output(int a, int b, int c) +# program.add_func_decl( +# "test_struct_output", (pt.Int64_t, pt.Int64_t, pt.Int64_t), My_Struct +# ) + +# program.add_func( +# "struct_in_out", +# (), +# pt.Int64_t, +# pt.Block( +# [ +# pt.DefineVar( +# struct_var, +# pt.Call("test_struct_output", [pt.Int64(1), pt.Int64(2), pt.Int64(3)]), +# ), +# pt.Return(pt.Call("test_struct_input", [pt.Var(struct_var)])), +# ] +# ), +# ) + +# program.add_func( +# "struct_set_get_field", +# (), +# pt.Int64_t, +# pt.Block( +# [ +# pt.DefineVar(struct_var), +# pt.Assign( +# pt.Var(struct_var), +# pt.SetElement(pt.Var(struct_var), pt.Int64(1), name="a"), +# ), +# pt.Assign( +# pt.Var(struct_var), +# pt.SetElement(pt.Var(struct_var), pt.Int64(2), idx=1), +# ), +# pt.Assign( +# pt.Var(struct_var), +# pt.SetElement(pt.Var(struct_var), pt.Int64(3), name="c"), +# ), +# pt.Return( +# pt.Add( +# pt.GetElement(pt.Var(struct_var), name="b"), +# pt.Add( +# pt.GetElement(pt.Var(struct_var), idx=2), +# pt.GetElement(pt.Var(struct_var), name="a"), +# ), +# ) +# ), +# ] +# ), +# ) + + +# class StructsTestCase(unittest.TestCase): +# def setUp(self) -> None: +# program.load_library("libtest_struct.so") +# self.engine = program.compile() + +# struct_in_out = self.engine.get_function_address("struct_in_out") +# self.struct_in_out = cast(Callable[[], int], CFUNCTYPE(c_int64)(struct_in_out)) + +# struct_set_get_field = self.engine.get_function_address("struct_set_get_field") +# self.struct_set_get_field = cast( +# Callable[[], int], CFUNCTYPE(c_int64)(struct_set_get_field) +# ) + +# def test_struct_in_out(self) -> None: +# self.assertEqual(self.struct_in_out(), 123) + +# def test_struct_set_get_field(self) -> None: +# self.assertEqual(self.struct_set_get_field(), 6)