Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions devito/ir/support/guards.py
Original file line number Diff line number Diff line change
Expand Up @@ -278,6 +278,14 @@ class Guards(frozendict):
construction of a new object, leaving self intact.
"""

def __init__(self, *args, **kwargs):
mapper = dict(*args, **kwargs)

# A guard that reduces to `true` is pointless, hence never set
mapper = {d: v for d, v in mapper.items() if v != true}

super().__init__(mapper)

def get(self, d, v=true):
return super().get(d, v)

Expand Down
7 changes: 7 additions & 0 deletions devito/passes/iet/languages/C.py
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,13 @@ class CPrinter(BasePrinter, C99CodePrinter):
def _print_ImaginaryUnit(self, expr):
return '_Complex_I'

# C99 has no `true`/`false` without `stdbool.h`, which is never included
def _print_BooleanTrue(self, expr):
return '1'

def _print_BooleanFalse(self, expr):
return '0'

def _print_ListInitializer(self, expr):
li = super()._print_ListInitializer(expr)
if expr.dtype:
Expand Down
31 changes: 31 additions & 0 deletions tests/test_buffering.py
Original file line number Diff line number Diff line change
Expand Up @@ -1203,3 +1203,34 @@ def test_buffering_multi_cond(factor):
# The last sample is on the subsampled grid, hence no extra slot
expected[-2:] = [ntmod - 1, 0]
assert np.allclose(f_all.data[:, 11, 11], expected)


def test_true_condition_single_buffer():
"""
A condition folded to `true` (`time` is nonnegative, so `time >= 0` is
`true`) imposes no guard. Reads of `f` under it and unguarded reads of `f`
must thus share one buffer.
"""
grid = Grid(shape=(4, 4))
time = grid.time_dim
nt = 4

f = TimeFunction(name='f', grid=grid, time_order=0, space_order=0, save=nt)
g = TimeFunction(name='g', grid=grid, time_order=0, space_order=0)
h = TimeFunction(name='h', grid=grid, time_order=0, space_order=0)
for i in range(nt):
f.data[i] = i

ctrue = ConditionalDimension(name='ctrue', parent=time, condition=time >= 0,
relation='strict')

eqs = [Eq(g, g + f, implicit_dims=ctrue), Eq(h, h + 2*f)]

op = Operator(eqs, opt='buffering', name='TrueCondition')

buffers = [i for i in FindSymbols().visit(op.body) if i.is_Array and i._mem_heap]
assert len(buffers) == 1

op.apply(time_m=0, time_M=nt-1)
assert np.allclose(g.data[0], 6.)
assert np.allclose(h.data[0], 12.)
52 changes: 51 additions & 1 deletion tests/test_dimension.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

import numpy as np
import pytest
from sympy import And, Or
from sympy import And, Or, false

from conftest import assert_blocking, assert_structure, opts_tiling, skipif
from devito import ( # noqa
Expand Down Expand Up @@ -2128,6 +2128,56 @@ def test_blocking_w_guard(self):
't,x0_blk0,y0_blk0,x,y,z'],
't,x0_blk0,y0_blk0,x,y,z,z')

def test_false_condition(self):
"""
A condition that SymPy folds to `false` (`time` is nonnegative) must
still be printed as valid C.
"""
grid = Grid(shape=(4, 4))
time = grid.time_dim

condition = time < 0
assert condition is false
ct = ConditionalDimension(name='ct', parent=time, condition=condition)

T = TimeFunction(name='T', grid=grid, time_order=0)
f = TimeFunction(name='f', grid=grid, time_order=0, save=2)

op = Operator([Eq(f, T + 1, implicit_dims=ct), Eq(T, T + 1)],
name='FalseCondition')
op.apply(time_M=1)

assert np.all(f.data[:, 1, 1] == [0, 0])

@pytest.mark.parametrize('relation', [And, Or, 'strict'])
def test_true_never_set(self, relation):
"""
A guard that reduces to `true` is pointless, hence never set. E.g.,
`time >= 0` folds to `true` as `time` is nonnegative.
"""
grid = Grid(shape=(4, 4))
time = grid.time_dim

ct = ConditionalDimension(name='ct', parent=time, condition=time >= 0,
relation=relation)

f = TimeFunction(name='f', grid=grid, time_order=0, save=4)
f1 = TimeFunction(name='f', grid=grid, time_order=0, save=4)

eqn = Eq(f, time + 1, implicit_dims=ct)

op0 = Operator(eqn, opt='noop')
op1 = Operator(eqn)

for op in (op0, op1):
assert not FindNodes(Conditional).visit(op)

op0.apply(time_M=3)
op1.apply(time_M=3, f=f1)

assert np.all(f.data[:, 1, 1] == [1, 2, 3, 4])
assert np.all(f.data == f1.data)


class TestCustomDimension:

Expand Down
Loading