From 3c48c5a31bb07857bdd77f446edab6f21283e4bc Mon Sep 17 00:00:00 2001 From: Sophia Vorderwuelbecke Date: Wed, 1 Dec 2021 13:51:15 +0000 Subject: [PATCH 01/13] GEM: introduce new nodes in GEM to faciliate locally matrix-free methods. The Solve node can now be specialised into being matrix-explicit or matrix-free. A new node called Action is introduced alongside and is a placeholder node for the local assembly of a 1-form. --- gem/gem.py | 49 ++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 44 insertions(+), 5 deletions(-) diff --git a/gem/gem.py b/gem/gem.py index 57014545..2c82c0ad 100644 --- a/gem/gem.py +++ b/gem/gem.py @@ -33,7 +33,7 @@ 'IndexSum', 'ListTensor', 'Concatenate', 'Delta', 'index_sum', 'partial_indexed', 'reshape', 'view', 'indices', 'as_gem', 'FlexiblyIndexed', - 'Inverse', 'Solve'] + 'Inverse', 'Solve', 'Action'] class NodeMeta(type): @@ -249,9 +249,11 @@ class Variable(Terminal): __slots__ = ('name', 'shape') __front__ = ('name', 'shape') + id = 0 def __init__(self, name, shape): - self.name = name + Variable.id += 1 + self.name = "T%d" % Variable.id if not name else name self.shape = shape @@ -834,17 +836,54 @@ class Solve(Node): Represents the X obtained by solving AX = B. """ - __slots__ = ('children', 'shape') + __slots__ = ('children', 'shape', 'matfree', 'Aonp', 'Aonx', 'name') + __back__ = ('matfree', 'Aonp', 'Aonx', 'name') + id = 0 - def __init__(self, A, B): + def __new__(cls, A, B, matfree=False, Aonp=None, Aonx=None, name=""): # Shape requirements assert B.shape assert len(A.shape) == 2 assert A.shape[0] == A.shape[1] assert A.shape[0] == B.shape[0] + self = super(Solve, cls).__new__(cls) self.children = (A, B) self.shape = A.shape[1:] + B.shape[1:] + self.matfree = matfree + self.Aonp = Aonp + self.Aonx = Aonx + + # When nodes are reconstructed in the GEM optimiser, + # we want them to keep their names which is why + # there is an optional name keyword in this constructor + self.name = name if name else "S%d" % Solve.id + Solve.id += 1 + return self + + +class Action(Node): + __slots__ = ('children', 'shape', 'pick_op', 'name') + __back__ = ('pick_op', 'name') + id = 0 + + def __new__(cls, A, B, pick_op, name=""): + assert B.shape + assert len(A.shape) == 2 + assert A.shape[pick_op] == B.shape[0] + assert pick_op < 2 + + self = super(Action, cls).__new__(cls) + self.children = A, B + self.shape = (A.shape[pick_op ^ 1],) + self.pick_op = pick_op + + # When nodes are reconstructed in the GEM optimiser, + # we want them to keep their names which is why + # there is an optional name keyword in this constructor + self.name = name if name else "A%d" % Action.id + Action.id += 1 + return self def unique(indices): @@ -903,7 +942,7 @@ def strides_of(shape): def decompose_variable_view(expression): """Extract information from a shaped node. Decompose ComponentTensor + FlexiblyIndexed.""" - if (isinstance(expression, (Variable, Inverse, Solve))): + if (isinstance(expression, (Variable, Inverse, Solve, Action))): variable = expression indexes = tuple(Index(extent=extent) for extent in expression.shape) dim2idxs = tuple((0, ((index, 1),)) for index in indexes) From ca6423ad42654b26de73ddfa7d12a2276f97ab63 Mon Sep 17 00:00:00 2001 From: Sophia Vorderwuelbecke Date: Wed, 1 Dec 2021 13:54:09 +0000 Subject: [PATCH 02/13] GEM2Loopy: Translate the matrix-free Solve and the Action node to loopy instructions. --- tsfc/loopy.py | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/tsfc/loopy.py b/tsfc/loopy.py index ae8f93e5..fd3dcec6 100644 --- a/tsfc/loopy.py +++ b/tsfc/loopy.py @@ -350,6 +350,7 @@ def statement_evaluate(leaf, ctx): return [lp.CallInstruction(lhs, rhs, within_inames=ctx.active_inames())] elif isinstance(expr, gem.Solve): + name = "mtf_solve" if expr.matfree else "solve" idx = ctx.pymbolic_multiindex(expr.shape) var = ctx.pymbolic_variable(expr) lhs = (SubArrayRef(idx, p.Subscript(var, idx)),) @@ -359,7 +360,20 @@ def statement_evaluate(leaf, ctx): idx_reads = ctx.pymbolic_multiindex(child.shape) var_reads = ctx.pymbolic_variable(child) reads.append(SubArrayRef(idx_reads, p.Subscript(var_reads, idx_reads))) - rhs = p.Call(p.Variable("solve"), tuple(reads)) + rhs = p.Call(p.Variable(name), tuple(reads)) + + return [lp.CallInstruction(lhs, rhs, within_inames=ctx.active_inames())] + elif isinstance(expr, gem.Action): + idx = ctx.pymbolic_multiindex(expr.shape) + var = ctx.pymbolic_variable(expr) + lhs = (SubArrayRef(idx, p.Subscript(var, idx)),) + + reads = [] + for child in expr.children: + idx_reads = ctx.pymbolic_multiindex(child.shape) + var_reads = ctx.pymbolic_variable(child) + reads.append(SubArrayRef(idx_reads, p.Subscript(var_reads, idx_reads))) + rhs = p.Call(p.Variable("action"), tuple(reads)) return [lp.CallInstruction(lhs, rhs, within_inames=ctx.active_inames())] else: From 5053536745b43aa77fe69c5a5e39c79d87d91421 Mon Sep 17 00:00:00 2001 From: Sophia Vorderwuelbecke Date: Wed, 1 Dec 2021 13:58:10 +0000 Subject: [PATCH 03/13] GEM2Loopy: minor changes, mostly to make more information available to components reusing the infrastructure for the loopy kernel generation. --- tsfc/loopy.py | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/tsfc/loopy.py b/tsfc/loopy.py index fd3dcec6..35cbf886 100644 --- a/tsfc/loopy.py +++ b/tsfc/loopy.py @@ -113,13 +113,14 @@ def assign_dtypes(expressions, scalar_type): class LoopyContext(object): - def __init__(self, target=None): + def __init__(self, kernel_name, target=None): self.indices = {} # indices for declarations and referencing values, from ImperoC self.active_indices = {} # gem index -> pymbolic variable self.index_extent = OrderedDict() # pymbolic variable for indices -> extent self.gem_to_pymbolic = {} # gem node -> pymbolic variable self.name_gen = UniqueNameGenerator() self.target = target + self.kernel_name = kernel_name def fetch_multiindex(self, multiindex): indices = [] @@ -199,7 +200,7 @@ def active_indices(mapping, ctx): def generate(impero_c, args, scalar_type, kernel_name="loopy_kernel", index_names=[], - return_increments=True, log=False): + return_increments=True, return_ctx=False, log=False): """Generates loopy code. :arg impero_c: ImperoC tuple with Impero AST and other data @@ -209,9 +210,10 @@ def generate(impero_c, args, scalar_type, kernel_name="loopy_kernel", index_name :arg index_names: pre-assigned index names :arg return_increments: Does codegen for Return nodes increment the lvalue, or assign? :arg log: bool if the Kernel should be profiled with Log events + :arg return_ctx: Is the ctx returned alongside the generated kernel? :returns: loopy kernel """ - ctx = LoopyContext(target=target) + ctx = LoopyContext(kernel_name, target=target) ctx.indices = impero_c.indices ctx.index_names = defaultdict(lambda: "i", index_names) ctx.epsilon = numpy.finfo(scalar_type).resolution @@ -221,7 +223,7 @@ def generate(impero_c, args, scalar_type, kernel_name="loopy_kernel", index_name # Create arguments data = list(args) for i, (temp, dtype) in enumerate(assign_dtypes(impero_c.temporaries, scalar_type)): - name = "t%d" % i + name = temp.name if hasattr(temp, "name") and temp.shape else "t%d" % i if isinstance(temp, gem.Constant): data.append(lp.TemporaryVariable(name, shape=temp.shape, dtype=dtype, initializer=temp.array, address_space=lp.AddressSpace.LOCAL, read_only=True)) else: @@ -239,14 +241,14 @@ def generate(impero_c, args, scalar_type, kernel_name="loopy_kernel", index_name domains = create_domains(ctx.index_extent.items()) # Create loopy kernel - knl = lp.make_function(domains, instructions, data, name=kernel_name, target=target, - seq_dependencies=True, silenced_warnings=["summing_if_branches_ops"], + knl = lp.make_function(domains, instructions, data, name=kernel_name, target=lp.CTarget(), + seq_dependencies=True, silenced_warnings=["summing_if_branches_ops", "single_writer_after_creation", "unused_inames"], lang_version=(2018, 2), preambles=preamble) # Prevent loopy interchange by loopy knl = lp.prioritize_loops(knl, ",".join(ctx.index_extent.keys())) - return knl, event_name + return (knl, ctx, event_name) if return_ctx else (knl, event_name) def create_domains(indices): @@ -258,7 +260,8 @@ def create_domains(indices): domains = [] for idx, extent in indices: inames = isl.make_zero_and_vars([idx]) - domains.append(((inames[0].le_set(inames[idx])) & (inames[idx].lt_set(inames[0] + extent)))) + domains.append(isl.BasicSet(str(((inames[0].le_set(inames[idx])) & + (inames[idx].lt_set(inames[0] + extent)))))) if not domains: domains = [isl.BasicSet("[] -> {[]}")] From 03b569d34e48dc0072e744519fcaebac506bfb0a Mon Sep 17 00:00:00 2001 From: Sophia Vorderwuelbecke Date: Wed, 1 Dec 2021 14:02:26 +0000 Subject: [PATCH 04/13] UFL2GEM: querying the number of an argument in a form for a form where one of the arguments got replaced by a coefficient does not yield the correct index. This is a workaround for that. --- tsfc/fem.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/tsfc/fem.py b/tsfc/fem.py index 2c5c865c..555a8a93 100644 --- a/tsfc/fem.py +++ b/tsfc/fem.py @@ -608,7 +608,15 @@ def fiat_to_ufl(fiat_dict, order): @translate.register(Argument) def translate_argument(terminal, mt, ctx): - argument_multiindex = ctx.argument_multiindices[terminal.number()] + # The following try except is need due to introducing an optimiser and actions in Slate. + # When action(Transpose(Tensor(form)), AssembledVector(f)) is part of an expression, + # it gets translated into a form where the first argument is replaced by the coefficient f. + # FIXME This is ugly, maybe we can introduce new information on the ctx to make it cleaner. + no = terminal.number() + try: + argument_multiindex = ctx.argument_multiindices[no] + except IndexError: + argument_multiindex = ctx.argument_multiindices[0] sigma = tuple(gem.Index(extent=d) for d in mt.expr.ufl_shape) element = ctx.create_element(terminal.ufl_element(), restriction=mt.restriction) From e4e27f8bd0e9bfaa869ee4ee50ce79b24e54920a Mon Sep 17 00:00:00 2001 From: Sophia Vorderwuelbecke Date: Fri, 18 Mar 2022 14:19:57 +0100 Subject: [PATCH 05/13] Set targets from params --- tsfc/loopy.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tsfc/loopy.py b/tsfc/loopy.py index 35cbf886..38c28d90 100644 --- a/tsfc/loopy.py +++ b/tsfc/loopy.py @@ -241,7 +241,7 @@ def generate(impero_c, args, scalar_type, kernel_name="loopy_kernel", index_name domains = create_domains(ctx.index_extent.items()) # Create loopy kernel - knl = lp.make_function(domains, instructions, data, name=kernel_name, target=lp.CTarget(), + knl = lp.make_function(domains, instructions, data, name=kernel_name, target=target, seq_dependencies=True, silenced_warnings=["summing_if_branches_ops", "single_writer_after_creation", "unused_inames"], lang_version=(2018, 2), preambles=preamble) From 1c4732dfdb99753840499c4f738be78a906d6f5c Mon Sep 17 00:00:00 2001 From: Sophia Vorderwuelbecke Date: Mon, 28 Mar 2022 17:41:45 +0200 Subject: [PATCH 06/13] WIP add stop criterion that is controllable from the outside --- gem/gem.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/gem/gem.py b/gem/gem.py index 2c82c0ad..5d38da85 100644 --- a/gem/gem.py +++ b/gem/gem.py @@ -836,11 +836,11 @@ class Solve(Node): Represents the X obtained by solving AX = B. """ - __slots__ = ('children', 'shape', 'matfree', 'Aonp', 'Aonx', 'name') - __back__ = ('matfree', 'Aonp', 'Aonx', 'name') + __slots__ = ('children', 'shape', 'matfree', 'Aonp', 'Aonx', 'name', 'rtol', 'atol') + __back__ = ('matfree', 'Aonp', 'Aonx', 'name', 'rtol', 'atol') id = 0 - def __new__(cls, A, B, matfree=False, Aonp=None, Aonx=None, name=""): + def __new__(cls, A, B, matfree=False, Aonp=None, Aonx=None, name="", rtol=None, atol=None): # Shape requirements assert B.shape assert len(A.shape) == 2 @@ -853,6 +853,9 @@ def __new__(cls, A, B, matfree=False, Aonp=None, Aonx=None, name=""): self.matfree = matfree self.Aonp = Aonp self.Aonx = Aonx + self.rtol = rtol + self.atol = atol + # When nodes are reconstructed in the GEM optimiser, # we want them to keep their names which is why From bc41ec7b95f6561b395c2fcab2c0e0dff1a91934 Mon Sep 17 00:00:00 2001 From: Sophia Vorderwuelbecke Date: Tue, 29 Mar 2022 02:34:16 +0200 Subject: [PATCH 07/13] WIP make it easier to add extra args to Solves --- gem/gem.py | 34 +++++++++++++++++++++++++--------- tsfc/loopy.py | 2 +- 2 files changed, 26 insertions(+), 10 deletions(-) diff --git a/gem/gem.py b/gem/gem.py index 5d38da85..1f193cd1 100644 --- a/gem/gem.py +++ b/gem/gem.py @@ -18,6 +18,7 @@ from itertools import chain from operator import attrgetter from numbers import Integral, Number +import collections import numpy from numpy import asarray @@ -33,7 +34,15 @@ 'IndexSum', 'ListTensor', 'Concatenate', 'Delta', 'index_sum', 'partial_indexed', 'reshape', 'view', 'indices', 'as_gem', 'FlexiblyIndexed', - 'Inverse', 'Solve', 'Action'] + 'Inverse', 'Solve', 'Action', 'MatfreeSolveContext'] + + +MatfreeSolveContext = collections.namedtuple("MatfreeSolveContext", + ["matfree", + "Aonx", + "Aonp", + "rtol", + "atol"]) class NodeMeta(type): @@ -836,11 +845,14 @@ class Solve(Node): Represents the X obtained by solving AX = B. """ - __slots__ = ('children', 'shape', 'matfree', 'Aonp', 'Aonx', 'name', 'rtol', 'atol') - __back__ = ('matfree', 'Aonp', 'Aonx', 'name', 'rtol', 'atol') + __slots__ = ('children', 'shape', 'name', 'ctx') + __back__ = ('name', 'ctx') + id = 0 + defaults = {"matfree": False, "Aonx": None, "Aonp": None, + "rtol": None, "atol": None} - def __new__(cls, A, B, matfree=False, Aonp=None, Aonx=None, name="", rtol=None, atol=None): + def __new__(cls, A, B, name="", ctx=MatfreeSolveContext(**defaults)): # Shape requirements assert B.shape assert len(A.shape) == 2 @@ -850,11 +862,15 @@ def __new__(cls, A, B, matfree=False, Aonp=None, Aonx=None, name="", rtol=None, self = super(Solve, cls).__new__(cls) self.children = (A, B) self.shape = A.shape[1:] + B.shape[1:] - self.matfree = matfree - self.Aonp = Aonp - self.Aonx = Aonx - self.rtol = rtol - self.atol = atol + + # Values in default args are overwritten if there is a corresponding kwarg + assert (all(k in Solve.defaults for k in ctx), + (f"A key in the optional dict ctx is not valid." + f"All keys have to be one of {Solve.defaults}.")) + # It's not save to make defaults a nested dict + updated_ctx = cls.defaults.copy() + updated_ctx.update(ctx._asdict()) + self.ctx = MatfreeSolveContext(**updated_ctx) # When nodes are reconstructed in the GEM optimiser, diff --git a/tsfc/loopy.py b/tsfc/loopy.py index 38c28d90..60c4c4e4 100644 --- a/tsfc/loopy.py +++ b/tsfc/loopy.py @@ -353,7 +353,7 @@ def statement_evaluate(leaf, ctx): return [lp.CallInstruction(lhs, rhs, within_inames=ctx.active_inames())] elif isinstance(expr, gem.Solve): - name = "mtf_solve" if expr.matfree else "solve" + name = "mtf_solve" if getattr(expr.ctx, "matfree") else "solve" idx = ctx.pymbolic_multiindex(expr.shape) var = ctx.pymbolic_variable(expr) lhs = (SubArrayRef(idx, p.Subscript(var, idx)),) From 040bfbddd7916134c06f7698c73fb4068c65684a Mon Sep 17 00:00:00 2001 From: Sophia Vorderwuelbecke Date: Wed, 30 Mar 2022 12:16:24 +0200 Subject: [PATCH 08/13] WIP make it easier to add extra args to Solves --- gem/gem.py | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/gem/gem.py b/gem/gem.py index 1f193cd1..61bf131f 100644 --- a/gem/gem.py +++ b/gem/gem.py @@ -37,13 +37,14 @@ 'Inverse', 'Solve', 'Action', 'MatfreeSolveContext'] +# Defaults are in the order of items in MatfreeSolveContext MatfreeSolveContext = collections.namedtuple("MatfreeSolveContext", ["matfree", - "Aonx", - "Aonp", - "rtol", - "atol"]) - + "Aonx", + "Aonp", + "rtol", + "atol"]) +DEFAULT_MSC = MatfreeSolveContext(*(False, None, None, "1.e-8", "1.e-50")) class NodeMeta(type): """Metaclass of GEM nodes. @@ -849,10 +850,8 @@ class Solve(Node): __back__ = ('name', 'ctx') id = 0 - defaults = {"matfree": False, "Aonx": None, "Aonp": None, - "rtol": None, "atol": None} - def __new__(cls, A, B, name="", ctx=MatfreeSolveContext(**defaults)): + def __new__(cls, A, B, name="", ctx=DEFAULT_MSC): # Shape requirements assert B.shape assert len(A.shape) == 2 @@ -863,12 +862,11 @@ def __new__(cls, A, B, name="", ctx=MatfreeSolveContext(**defaults)): self.children = (A, B) self.shape = A.shape[1:] + B.shape[1:] + # We use a ctx rather than kwargs because then __slots__ and __back__ are independent + # of the extra arguments passed for the matrix-free, iterative solver # Values in default args are overwritten if there is a corresponding kwarg - assert (all(k in Solve.defaults for k in ctx), - (f"A key in the optional dict ctx is not valid." - f"All keys have to be one of {Solve.defaults}.")) # It's not save to make defaults a nested dict - updated_ctx = cls.defaults.copy() + updated_ctx = DEFAULT_MSC._asdict().copy() updated_ctx.update(ctx._asdict()) self.ctx = MatfreeSolveContext(**updated_ctx) From c65f6de6d3bf9e63bdccf2d3fea01193a0b404c1 Mon Sep 17 00:00:00 2001 From: Sophia Vorderwuelbecke Date: Wed, 15 Dec 2021 10:27:25 +0100 Subject: [PATCH 09/13] GEM: add preconditioning to Solve node --- gem/gem.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/gem/gem.py b/gem/gem.py index 61bf131f..e36dc3d5 100644 --- a/gem/gem.py +++ b/gem/gem.py @@ -42,9 +42,12 @@ ["matfree", "Aonx", "Aonp", + "preconditioner", + "Ponr", + "diag_prec", "rtol", "atol"]) -DEFAULT_MSC = MatfreeSolveContext(*(False, None, None, "1.e-8", "1.e-50")) +DEFAULT_MSC = MatfreeSolveContext(*(False, None, None, None, None, False, "1.e-8", "1.e-50")) class NodeMeta(type): """Metaclass of GEM nodes. From 0201079ea518a73ae75bcd9c2e6a5b4c24f63182 Mon Sep 17 00:00:00 2001 From: Sophia Vorderwuelbecke Date: Thu, 16 Dec 2021 18:11:33 +0100 Subject: [PATCH 10/13] Gem2Loopy: pass preconditioner to matf solve call too --- tsfc/loopy.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tsfc/loopy.py b/tsfc/loopy.py index 60c4c4e4..c8999a1c 100644 --- a/tsfc/loopy.py +++ b/tsfc/loopy.py @@ -359,7 +359,8 @@ def statement_evaluate(leaf, ctx): lhs = (SubArrayRef(idx, p.Subscript(var, idx)),) reads = [] - for child in expr.children: + childs = expr.children+(expr.preconditioner,) if expr.preconditioner else expr.children + for child in childs: idx_reads = ctx.pymbolic_multiindex(child.shape) var_reads = ctx.pymbolic_variable(child) reads.append(SubArrayRef(idx_reads, p.Subscript(var_reads, idx_reads))) From afd6787d6c64160ae9bf3a3c74a54b0da7e11cf5 Mon Sep 17 00:00:00 2001 From: Sophia Vorderwuelbecke Date: Thu, 31 Mar 2022 15:24:09 +0200 Subject: [PATCH 11/13] With preconditioning --- gem/gem.py | 2 +- tsfc/loopy.py | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/gem/gem.py b/gem/gem.py index e36dc3d5..9abd28ee 100644 --- a/gem/gem.py +++ b/gem/gem.py @@ -47,7 +47,7 @@ "diag_prec", "rtol", "atol"]) -DEFAULT_MSC = MatfreeSolveContext(*(False, None, None, None, None, False, "1.e-8", "1.e-50")) +DEFAULT_MSC = MatfreeSolveContext(*(False, None, None, None, None, False, "1.e-12", "1.e-70")) class NodeMeta(type): """Metaclass of GEM nodes. diff --git a/tsfc/loopy.py b/tsfc/loopy.py index c8999a1c..92c6f1bc 100644 --- a/tsfc/loopy.py +++ b/tsfc/loopy.py @@ -359,7 +359,8 @@ def statement_evaluate(leaf, ctx): lhs = (SubArrayRef(idx, p.Subscript(var, idx)),) reads = [] - childs = expr.children+(expr.preconditioner,) if expr.preconditioner else expr.children + prec = getattr(expr.ctx, "preconditioner") + childs = expr.children+(prec,) if prec else expr.children for child in childs: idx_reads = ctx.pymbolic_multiindex(child.shape) var_reads = ctx.pymbolic_variable(child) From 8aff2c4661584086f75ecf832afe87155f715617 Mon Sep 17 00:00:00 2001 From: Sophia Vorderwuelbecke Date: Wed, 27 Apr 2022 16:27:44 +0200 Subject: [PATCH 12/13] Local matf solve: add a maxit argument to control the solver. --- gem/gem.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/gem/gem.py b/gem/gem.py index 9abd28ee..81694426 100644 --- a/gem/gem.py +++ b/gem/gem.py @@ -46,8 +46,9 @@ "Ponr", "diag_prec", "rtol", - "atol"]) -DEFAULT_MSC = MatfreeSolveContext(*(False, None, None, None, None, False, "1.e-12", "1.e-70")) + "atol", + "max_it"]) +DEFAULT_MSC = MatfreeSolveContext(*(False, None, None, None, None, False, "1.e-12", "1.e-70", None)) class NodeMeta(type): """Metaclass of GEM nodes. From cdee089e1d034d7f273cabe4ba6e3396f8e3504e Mon Sep 17 00:00:00 2001 From: Sophia Vorderwuelbecke Date: Mon, 18 Jul 2022 16:35:14 +0200 Subject: [PATCH 13/13] Add insn_count_subgroups_upper_bound warning in all our Loo.py kernel generation functions. --- tsfc/loopy.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tsfc/loopy.py b/tsfc/loopy.py index 92c6f1bc..c6dd2462 100644 --- a/tsfc/loopy.py +++ b/tsfc/loopy.py @@ -242,7 +242,8 @@ def generate(impero_c, args, scalar_type, kernel_name="loopy_kernel", index_name # Create loopy kernel knl = lp.make_function(domains, instructions, data, name=kernel_name, target=target, - seq_dependencies=True, silenced_warnings=["summing_if_branches_ops", "single_writer_after_creation", "unused_inames"], + seq_dependencies=True, silenced_warnings=["summing_if_branches_ops", "single_writer_after_creation", + "unused_inames", "insn_count_subgroups_upper_bound"], lang_version=(2018, 2), preambles=preamble) # Prevent loopy interchange by loopy