From 7da501ceb4f070119999177a1cc85ae5b8517105 Mon Sep 17 00:00:00 2001
From: Keck Jean-Baptiste <jean-baptiste.keck@imag.fr>
Date: Sun, 21 May 2017 01:40:41 +0200
Subject: [PATCH] codegen refactoring

---
 hysop/backend/device/codegen/base/codegen.py  |  38 +-
 .../device/codegen/base/struct_codegen.py     |   2 +-
 .../backend/device/codegen/base/variables.py  | 511 ++++++++++--------
 .../codegen/kernels/directional_remesh.py     |  42 +-
 .../device/opencl/opencl_array_backend.py     |  14 +-
 5 files changed, 333 insertions(+), 274 deletions(-)

diff --git a/hysop/backend/device/codegen/base/codegen.py b/hysop/backend/device/codegen/base/codegen.py
index b548213af..a4b397e59 100644
--- a/hysop/backend/device/codegen/base/codegen.py
+++ b/hysop/backend/device/codegen/base/codegen.py
@@ -120,8 +120,6 @@ class CodeGenerator(object):
             pass
         return self
 
-
-
     def to_file(self,folder,filename):
         dst_file = folder + '/' + filename
         if not os.path.exists(folder):
@@ -186,7 +184,6 @@ class CodeGenerator(object):
         if k>0:
             self.code = self.code[:k]
         return self
-   
 
 
     def _noop(self):
@@ -206,9 +203,9 @@ class CodeGenerator(object):
     def define(self,what,prepend=True):
         code = '#define {}'.format(what)
         self.append(code,simple=True)
-    def include(self,*kargs):
+    def include(self,*args):
         code = []
-        for k in kargs:
+        for k in args:
             code.append('#include {}'.format(k))
         return self.append(code)
 
@@ -252,24 +249,13 @@ class CodeGenerator(object):
         else:
             self.append(code)
 
-    def decl_vars(self,_type,_varnames,_inits=None,comment=None,cv_qualifier=None):
-        if not isinstance(_varnames,list):
-            _varnames = [_varnames]
-        if _inits is not None and not isinstance(_inits,list):
-            _inits = [_inits]
-
-        declvar = ''
-        if cv_qualifier:
-            declvar+=cv_qualifier+' '
-        declvar += '{} '.format(_type)
-        if _inits:
-            declvar += ','.join(['{}={}'.format(v,i) for v,i in zip(_varnames,_inits)])
-        else:
-            declvar += ','.join(_varnames)
-        declvar += ';'
-        if comment is not None:
-            declvar += ' /* {} */'.format(comment)
-        self.append(declvar)
+    def decl_vars(self, *variables):
+        assert len(set(var.base_ctype() for var in variables))==1
+        base= variables[0].base_ctype()
+        svars=[]
+        for var in variables:
+            svars.append(var.declare(multidecl=True))
+        return '{} {};'.format(base, ', '.join(svars))
    
 
     class VarBlock(object):
@@ -354,7 +340,11 @@ class CodeGenerator(object):
             maxlen  = lambda i: max([len(line[i]) for line in self._lines if len(line)>1])
             line_str = ''
             for i in xrange(self._parts_count):
-                line_str+='{:'+str(maxlen(i))+'}'
+                ml = maxlen(i)
+                if ml==0:
+                    line_str+='{}'
+                else:
+                    line_str+='{:'+str(ml)+'}'
             code = []
             for line in self._lines:
                 if len(line)>1:
diff --git a/hysop/backend/device/codegen/base/struct_codegen.py b/hysop/backend/device/codegen/base/struct_codegen.py
index 12f6754de..3a058366b 100644
--- a/hysop/backend/device/codegen/base/struct_codegen.py
+++ b/hysop/backend/device/codegen/base/struct_codegen.py
@@ -59,7 +59,7 @@ class StructCodeGenerator(OpenClCodeGenerator):
                         i+=1
 
     def build_codegen_variable(self,name,**kargs):
-        return CodegenStruct(varname=name, struct=self, **kargs)
+        return CodegenStruct(name=name, struct=self, **kargs)
 
 if __name__ == '__main__':
 
diff --git a/hysop/backend/device/codegen/base/variables.py b/hysop/backend/device/codegen/base/variables.py
index e8f47f9fc..430840bc2 100644
--- a/hysop/backend/device/codegen/base/variables.py
+++ b/hysop/backend/device/codegen/base/variables.py
@@ -1,9 +1,10 @@
     
 from hysop.deps import np, re, copy
+from hysop.tools.types import to_list, check_instance
 import hysop.backend.device.opencl.opencl_types
 
 from hysop.backend.device.codegen.base.utils import VarDict
-from hysop.backend.device.opencl.opencl_types import OpenClTypeGen
+from hysop.backend.device.opencl.opencl_types import TypeGen, OpenClTypeGen
 
 # opencl extras        
 from hysop.backend.device.opencl.opencl_types import cl_type_to_dtype
@@ -35,7 +36,7 @@ _ctype_to_dtype = {
         'half':                   np.float16,
         'float' :                 np.float32,
         'double':                 np.float64,
-        'long doube':             np.longdouble,
+        'long double':            np.longdouble,
 }
 
 
@@ -60,18 +61,77 @@ def register_ctype_dtype(ctype,dtype):
         _ctype_to_dtype[ctype] = dtype
 
 class CodegenVariable(object):
-    def __init__(self,name,ctype,typegen,
-            value=None, svalue=None,
-            const=False, add_impl_const=False,
-            storage=None, nl=None, 
-            ptr=False, restrict=False, volatile=False,
-            init=None,
+    def __init__(self, name, ctype, typegen,
+            storage=None, const=False, volatile=False, 
+            add_impl_const=False, nl=None, 
+            ptr=False, ptr_restrict=None, ptr_volatile=None, ptr_const=None,
+            value=None, svalue=None, init=None,
             symbolic_mode=False,struct_var=None):
+        
+        check_instance(typegen, TypeGen)
+
+        check_instance(name, str)
+        check_instance(ctype, str)
+        check_instance(storage, str, allow_none=True)
+        assert len(name)>0
+        assert len(ctype)>0
+        assert (storage is None) or len(ctype)>0
+        
+        check_instance(const, bool)
+        check_instance(volatile, bool)
+        check_instance(add_impl_const, bool)
+        check_instance(nl, bool, allow_none=True)
+        
+        if const and add_impl_const:
+            msg='Variable {} is const and add_impl_const has been specified!'
+            msg=msg.format(name)
+            raise ValueError(msg)
+
+        self.name     = name
+        self.ctype    = ctype
+        self.typegen  = typegen
+        self.const    = const
+        self.volatile = volatile
+        self.add_impl_const = add_impl_const
+        self.storage = storage
 
-        self.name    = name
-        self.ctype   = ctype
-        self.typegen = typegen
+        self.nl = nl if (nl is not None) else (storage is not None)
+        self.struct_var = struct_var
+        self.symbolic_mode = symbolic_mode
+        
+        # pointer 
+        if isinstance(ptr,bool):
+            is_ptr = ptr
+            ptr_level = int(ptr)
+        else:
+            check_instance(ptr, (int, long))
+            is_ptr = True
+            ptr_level = ptr
+        del ptr
+        
+        if is_ptr:
+            ptr_restrict = to_list(ptr_restrict)
+            ptr_const    = to_list(ptr_const)
+            ptr_volatile = to_list(ptr_volatile)
 
+            _len = max(len(ptr_restrict), len(ptr_const), len(ptr_volatile))
+            assert _len <= ptr_level
+            
+            ptr_restrict = np.asarray(ptr_restrict + [False]*(ptr_level-len(ptr_restrict)))
+            ptr_volatile = np.asarray(ptr_volatile + [False]*(ptr_level-len(ptr_volatile)))
+            ptr_const    = np.asarray(ptr_const    + [False]*(ptr_level-len(ptr_const)))
+        else:
+            assert ptr_restrict is None
+            assert ptr_volatile is None
+            assert ptr_const    is None
+
+        self.is_ptr = is_ptr
+        self.ptr_level = ptr_level
+        self.ptr_restrict = ptr_restrict
+        self.ptr_const = ptr_const
+        self.ptr_volatile = ptr_volatile
+        
+        # value and svalue
         if value is None:
             value = None
         elif np.isscalar(value):
@@ -94,82 +154,129 @@ class CodegenVariable(object):
                 value = value.copy()
         else:
             pass
-
+        
         self.value   = value
         self.svalue  = svalue
-
-        self.storage = storage
-        self.volatile = volatile
-        self.nl = nl if (nl is not None) else (storage is not None)
-        self.ptr = ptr
-        self.struct_var = struct_var
-        self.symbolic_mode = symbolic_mode
         self.init=init
-        
-        const = [const] if isinstance(const,bool) else list(const)
-        add_impl_const = [add_impl_const] if isinstance(add_impl_const,bool) \
-                else list(add_impl_const)
-        restrict = [restrict] if isinstance(restrict,bool) else list(restrict)
-        _len = max(max(len(const),len(add_impl_const)), len(restrict))
-        const = np.asarray(const + (_len-len(const))*[False], dtype=bool)
-        add_impl_const = np.asarray(add_impl_const + (_len-len(add_impl_const))*[False], 
-                dtype=bool)
-        restrict = np.asarray(restrict + (_len-len(restrict))*[False], dtype=bool)
-        if (const.size != add_impl_const.size) or (const.size != restrict.size):
-            raise ValueError('const, add_impl_const, restrict size mismatch!')
-        if not ptr and restrict.any():
-            raise ValueError('Non pointer types cannot be aliased!')
-        if not ptr and (const.size>1 or add_impl_const.size>1):
-            raise ValueError('Non pointer types cannot have multiple const qualifiers!')
-        if not ptr and np.logical_and(const, add_impl_const).any():
-            raise ValueError('Variable {} is const and add_impl_const has been specified!'\
-                    .format(name))
-        #if (struct_var is not None) and (struct_var.const) and (not const[0]):
-            #raise ValueError('Variable {} declared in const struct {} is not const!'.format(name,struct_var.name))
-        self.const          = const
-        self.add_impl_const = add_impl_const
-        self.restrict       = restrict
-
+    
+    def newvar(name, nl=False,
+            storage=None, value=None, svalue=None, init=None,
+            ctype=None, const=None, volatile=None, add_impl_const=None,
+            ptr=None, ptr_restrict=None, ptr_volatile=None, ptr_const=None):
 
-    def full_ctype(self, const=None, impl=False):
+        ctype = self.ctype if (ctype is None) else ctype
         const = self.const if (const is None) else const
-        ctype = self.ctype
+        volatile = self.volatile if (volatile is None) else volatile
+        add_impl_const = self.add_impl_const if (add_impl_const is None) else add_impl_const
+        storage = self.storage if (storage is None) else storage
+
+        if ptr is None:
+            ptr = self.ptr if (ptr is None) else ptr
+            ptr_const    = self.ptr_const    if (ptr_const is None)    else ptr_const
+            ptr_volatile = self.ptr_volatile if (ptr_volatile is None) else ptr_volatile
+            ptr_restrict = self.ptr_restrict if (ptr_restrict is None) else ptr_restrict
+
+        return CodegenVariable(name=name, nl=nl,
+                value=value, svalue=svalue, init=init,
+                ctype=ctype, storage=storage, 
+                const=const, volatile=volatile, 
+                add_impl_const=add_impl_const,
+                ptr=ptr, ptr_restrict=ptr_restrict, 
+                ptr_volatile=ptr_volatile, ptr_const=ptr_const)
+
+    def pointer_alias(self, name, ctype, **kargs):
+        handle = self.newvar(name=name, ctype=ctype, 
+                const=const, volatile=volatile, restrict=restrict,
+                init='({})({})'.format(
+                    handle.full_ctype(disable_ptr_cv_qualifiers=True), self),
+                **kargs)
+        return handle
 
-        if not self.ptr:
-            if const or (impl and self.add_impl_const):
-                const = 'const '
-            else:
-                const = ''
+    def pointer(self, name, ptr_level, 
+            ptr_const=None, ptr_volatile=None, ptr_restrict=None,
+            add_impl_const=False, with_init=True, **kargs):
+        ptr_const    = [False]*ptr_level if (ptr_const is None)    else to_list(ptr_const)
+        ptr_volatile = [False]*ptr_level if (ptr_volatile is None) else to_list(ptr_volatile)
+        ptr_restrict = [False]*ptr_level if (ptr_restrict is None) else to_list(ptr_restrict)
+        assert ptr_level>0
+        assert len(ptr_const)    == ptr_level
+        assert len(ptr_volatile) == ptr_level
+        assert len(ptr_restrict) == ptr_level
+        if self.is_ptr:
+            ptr_level    = self.ptr_level    + ptr_level
+            ptr_const    = self.ptr_const    + ptr_const
+            ptr_volatile = self.ptr_volatile + ptr_volatile
+            ptr_restrict = self.ptr_restrict + ptr_restrict
+        if with_init:
+            init = '&{}'.format(self.name)
         else:
-            const = ' const' if const else ''#' '*6
-            ctype += '{} *'.format(const)
-            if impl and self.add_impl_const:
-                ctype += 'const '
-            const=''
+            init = None
+        return self.newvar(name=name, ptr=ptr_level,
+                ptr_const=ptr_const, ptr_volatile=ptr_volatile, 
+                ptr_restrict=ptr_restrict, init=init,
+                add_impl_const=add_impl_const, **kargs)
+
+
+    def base_ctype(self, storage=None, ctype=None, 
+            const=None, volatile=False,
+            impl=True, align=False):
+        storage  = self.storage  if (storage is None)  else storage
+        ctype    = self.ctype    if (ctype is None)    else ctype
+        volatile = self.volatile if (volatile is None) else volatile
         
-        restrict = 'restrict' if self.restrict else ''
-        storage  = ('volatile ' if self.volatile else '')
-        storage  += (self.storage + ' ') if self.storage else ''
-        return '{storage}{const}{ctype}{restrict}'.format(storage=storage,
-                restrict=restrict,const=const,ctype=ctype)
-    
-    def argument(self,impl,const=None):
-        name    = self.name
-        nl      = '\n' if self.nl else ''
-        return '{} {name}{nl}'.format(self.full_ctype(impl=impl,const=const),name=name,nl=nl)
-
-
-    def alias(self, name, ctype, 
-            const=None, volatile=None, restrict=None):
-        handle = copy.copy(self)
-        handle.ctype = ctype
-        handle.name=name
-        handle.const = const if (const is not None) else handle.const
-        handle.volatile = volatile if (volatile is not None) else handle.volatile
-        handle.restrict = restrict if (restrict is not None) else handle.restrict
-        handle.init='({})({})'.format(handle.full_ctype(), self)
-        return handle
+        if (const is None):
+            const = self.const
+            if impl and (not self.is_ptr) and (not const):
+                const = self.add_impl_const
+
+        base_ctype = '{storage}${ctype}${const}${volatile}'.format(
+                storage='{} '.format(storage) if (storage is not None) else '',
+                const='const ' if const else '',
+                volatile='volatile ' if volatile else '',
+                ctype=ctype+' ')
+        if not align:
+            base_ctype = base_ctype.replace('$','')
+        return base_ctype.strip()
 
+    def full_ctype(self, storage=None, ctype=None, const=None, volatile=False,
+            impl=True, multidecl=False, align=False, cast=False):
+        
+        if multidecl:
+            base_ctype = ''
+        else:
+            base_ctype = self.base_ctype(storage,ctype,const,volatile,impl,align)
+
+        if self.is_ptr:
+            ptrs=[]
+            for i, (c,v,r) in enumerate(zip(self.ptr_const, self.ptr_volatile, self.ptr_restrict)):
+                if i==self.ptr_level-1:
+                    c = c or (impl and self.add_impl_const)
+                ptr=' $*{const}${volatile}${restrict}'.format(
+                    const    = 'const '    if (c and not cast) else '',
+                    volatile = 'volatile ' if (v and not cast) else '',
+                    restrict = 'restrict ' if (r and not cast) else '')
+                ptrs.append(ptr)
+            ptr_ctype = ''.join(ptrs)
+        else:
+            ptr_ctype=''
+
+        full_ctype = '{}{}'.format(base_ctype, ptr_ctype)
+        if not align:
+            full_ctype = full_ctype.replace('$', '')
+        else:
+            full_ctype = full_ctype.replace('$ ', '$')
+
+        return full_ctype.strip()
+    
+    def argument(self,impl,
+            nl=None, name=None,
+            **kargs):
+        name    = self.name if (name is None) else name
+        nl      = self.nl   if (nl is None) else nl
+        return '{} {name}{nl}'.format(
+                self.full_ctype(impl=impl, **kargs),
+                name=name,
+                nl='\n' if self.nl else '')
 
     def is_symbolic(self):
         return (self.value is None) or self.symbolic_mode
@@ -197,7 +304,8 @@ class CodegenVariable(object):
             elif self.value is not None:
                 return self.typegen.dump(self.value)
             else:
-                raise NotImplementedError()
+                msg='value and svalue are not defined.'
+                raise RuntimeError(msg)
 
     def access_prefix(self,access):
         acc = ''
@@ -205,55 +313,15 @@ class CodegenVariable(object):
             acc += self.struct_var.access_prefix(access=True)
         acc += self.name
         if access:
-            acc += '->' if self.ptr else '.'
+            acc += '->' if self.is_ptr else '.'
         return acc
 
-    def declare(self,codegen=None,align=False,
-            const=None,restrict=None,
-            storage=None,init=None):
-        
-        storage = storage if (storage is not None) else self.storage
-        storage = '{} '.format(storage) if (storage is not None) else ''
-        storage = '{}{}'.format('volatile ' if self.volatile else '', storage)
-
-        if const is not None:
-            self.const = np.asarray(self.const,bool)
-            const = (const,)+(False,)*(self.const.size-1) if isinstance(const,bool) else const
-            const = np.asarray(const,dtype=bool)
-            const = np.logical_or(const, self.const)
-        else:
-            const = self.const
+    def declare(self, codegen=None, align=False,
+            multidecl=False, const=None, init=None):
         
-        if restrict is not None:
-            restrict = (restrict,)+(False,)*(self.restrict.size-1) \
-                    if isinstance(restrict,bool) else restrict
-            restrict = np.asarray(restrict,dtype=bool)
-            restrict = np.logical_or(restrict, self.restrict)
-        else:     
-            restrict = self.restrict
+        ctype = self.full_ctype(align=align,multidecl=multidecl,const=const)
         
-        if self.ptr:
-            if hasattr(self, 'sshape'):
-                sshape = self.sshape
-                qualifiers = ['[{}{}{}]'.format(
-                        s,
-                        (' const' if c else ''),
-                        (' restrict' if r else '' ))
-                    for (s,c,r) in zip(sshape,const,restrict)]
-                array_qualifiers = ''.join(qualifiers)
-            else:
-                qualifiers = [('const' if c else '') + (' restrict' if r else '' ) \
-                        for (c,r) in zip(const,restrict)]
-                impl_const = ' const' if self.add_impl_const[0] else ''
-                array_qualifiers = '{} *'.format(impl_const)+' *'.join(qualifiers)
-
-            ctype = '{}{}'.format(self.ctype, array_qualifiers)
-            modifiers = storage
-        else:
-            ctype = self.ctype
-            modifiers = '{}{}'.format(storage,'' if not const else 'const ')
-
-
+        # static array ctype needs to be split
         split = ctype.split('[',1)
         ctype = split[0]
         is_static_array = len(split)==2
@@ -261,14 +329,18 @@ class CodegenVariable(object):
         name = self.name+name_suffix
 
         init = init if (init is not None) else self.init
-        code = '{}{} ${}'.format(modifiers, ctype, name)
+        code = '{} ${}'.format(ctype, name)
+        
         if (init is not None):
             code = '{} $= {}'.format(code,init)
         elif self.known():
             self.force_symbolic(False)
             sval = self.sval()
             code = '{} $= {}'.format(code,sval)
-        code+=';'
+        
+        if not multidecl:
+            code+=';'
+        
         self.force_symbolic() 
         
         if not align:
@@ -277,123 +349,121 @@ class CodegenVariable(object):
             codegen.append(code)
         return code
 
-    def __call__(self):
-        return self.sval()
     def __getitem__(self,ss):
-        if self.ptr:
+        if self.is_ptr:
             return '{}[{}]'.format(self.name,ss)
         elif ss==0:
             return self.__call__()
         else:
             assert self.ptr, '{} is not a pointer!'.format(self.name)
+
     def __repr__(self):
         if self.is_symbolic():
             return '{}({})'.format(self.name,self.ctype)
         else:
             return '{}({},{})'.format(self.name,self.ctype,self.value)
+    
+    def __call__(self):
+        return self.sval()
     def __str__(self):
         return self.sval()
 
 class CodegenArray(CodegenVariable):
     @staticmethod
-    def initialize_rec(name,dim,
-            ctype, typegen, 
-            shape,sshape,value,svalue,
-            const, add_impl_const, restrict,
-            symbolic_mode):
+    def _initialize_rec(name, typegen,
+                    storage, ctype, const, volatile,
+                    shape, sshape, value, svalue, 
+                    ptr_dim, ptr_restrict, ptr_const, ptr_volatile,
+                    symbolic_mode):
        
         if (value is None):
             return value, svalue
             
         s0 = shape[0]
-        if dim==1:
-            _name   = name
-            _value  = value
+
+        if ptr_dim==1:
+            _name  = name
+            _value = value
             if (svalue is not None):
                 _svalue = '{ ' + ', '.join(svalue) + ' }'
         else:
-            _const = const[1:]
-            _add_impl_const= add_impl_const[1:]
-            _restrict=restrict[1:]
             _shape  = shape[1:]
             _sshape = sshape[1:]
             
+            _ptr_dim      = ptr_dim - 1
+            _ptr_const    = ptr_const[:-1]
+            _ptr_restrict = ptr_restrict[:-1]
+            _ptr_volatile = ptr_volatile[:-1]
+            
             _value  = [None]*s0
             _svalue = [None]*s0
             for d in xrange(s0):
-                _name = name+'_{}'.format(d)
-                val, sval = CodegenArray.initialize_rec(_name, 
-                        dim-1, ctype, typegen,
-                        _shape, _sshape, value[d], svalue[d],
-                        _const, _add_impl_const, _restrict,
+                _name   = '{}_{}'.format(name, d)
+                _value  = value[d]
+                _svalue = svalue[d]
+                val, sval = CodegenArray.initialize_rec(_name, typegen,
+                        storage, ctype, const, volatile,
+                        _shape, _sshape, _value, _svalue,
+                        _ptr_dim, _ptr_restrict, _ptr_const, _ptr_volatile,
                         symbolic_mode)
-                var = CodegenArray(name=_name,
-                        ctype=ctype, typegen=typegen,
-                        dim=dim-1, 
-                        shape=_shape, sshape=_sshape, 
-                        value=val, svalue=sval,
-                        symbolic_mode=False, struct_var=None,direct_init=True)
+                var = CodegenArray(name=_name, typegen=typegen,
+                        storage=storage, ctype=ctype, const=const, volatile=volatile,
+                        shape=_shape, sshape=_sshape, value=val, svalue=sval,
+                        dim=_ptr_dim, ptr_const=_ptr_const,
+                        ptr_volatile=_ptr_volatile, ptr_restrict=_ptr_restrict,
+                        add_impl_const=False,
+                        symbolic_mode=False,
+                        struct_var=None,
+                        _direct_init=True)
                 _value[d]  = var
                 _svalue[d] = '\n\t'.join(sval.split('\n'))
-            if svalue is not None:
-                _svalue = '{\n\t'+',\n\t'.join(_svalue)+'\n}'
-            else:
+
+            if svalue is None:
                 _svalue=None
+            else:
+                _svalue = '{\n\t'+',\n\t'.join(_svalue)+'\n}'
         
         return _value, _svalue
 
-    def __init__(self, name, ctype, typegen,
-            dim=1,
+    def __init__(self, name, ctype, typegen, 
+            storage=None, volatile=False, const=False, add_impl_const = False,
+            dim=1, ptr_const=None, ptr_volatile=None, ptr_restrict=None,
             shape=None, sshape=None,
             value=None, svalue=None,
-            const=None, add_impl_const=None, 
-            restrict=None, storage=None,
             symbolic_mode=False, struct_var=None,
-            direct_init=False):
+            _direct_init=False):
+
+        ptr_dim = dim
+        del dim
         
-        if direct_init:
+        if _direct_init:
             _value, _svalue = value, svalue
         else:
-            if const is None:
-                const = (False,)*dim
-            elif const in [True,False]:
-                const = (const,)*dim
-            elif len(const)!= dim:
-                raise ValueError('const dim mismatch!')
-            const = np.asarray(const)
-            
-            if add_impl_const is None:
-                add_impl_const = (False,)*dim
-            elif add_impl_const in [True,False]:
-                add_impl_const = (add_impl_const,)*dim
-            elif len(add_impl_const)!= dim:
-                raise ValueError('add_impl_const dim mismatch!')
-            add_impl_const = np.asarray(add_impl_const)
-
-            if restrict is None:
-                restrict = (False,)*dim
-            elif restrict in [True,False]:
-                restrict = (restrict,)*dim
-            elif len(restrict)!= dim:
-                raise ValueError('restrict dim mismatch!')
-            restrict = np.asarray(restrict)
+            ptr_const    = [] if (ptr_const is None)    else to_list(ptr_const) 
+            ptr_volatile = [] if (ptr_volatile is None) else to_list(ptr_volatile) 
+            ptr_restrict = [] if (ptr_restrict is None) else to_list(ptr_restrict) 
+            ptr_const    += [False]*(ptr_dim-len(ptr_const))
+            ptr_volatile += [False]*(ptr_dim-len(ptr_volatile))
+            ptr_restrict += [False]*(ptr_dim-len(ptr_restrict))
 
             if (value is not None):
                 value = np.asarray(value)
-                if value.ndim != dim:
-                    raise ValueError('value array dim mismatch!')
+                if value.ndim != ptr_dim:
+                    raise ValueError('value array dim mismatch.')
                 if shape is None:
                     shape = value.shape
+                else:
+                    assert value.shape == shape, 'shape mismatch.'
                
             if (svalue is not None):
                 svalue = np.asarray(svalue)
                 if value is None:
                     raise ValueError('value cannot be None when svalue is not None.')
-                if svalue.ndim != dim:
+                if svalue.ndim != ptr_dim:
                     raise ValueError('svalue input array dimension mismatch!')
                 if svalue.shape != value.shape:
                     raise ValueError('Input array shape mismatch between value and svalue.')
-            elif value is not None:
+            elif (value is not None):
                 svalue = np.zeros_like(value,dtype=object)
                 dtype = ctype_to_dtype(ctype)
                 sview = svalue.flat
@@ -401,48 +471,49 @@ class CodegenArray(CodegenVariable):
                     sview[i] = typegen.dump(v)
             
             if (shape is not None):
-                if len(shape)!=dim:
+                if len(shape)!=ptr_dim:
                     raise ValueError('shape dim mismatch!')
             else:
-                shape = (None,)*dim
+                shape = (None,)*ptr_dim
             shape = np.asarray(shape)
             
             if (sshape is None) and (shape[0] != None):
-                sshape = [s.__str__() for s in shape]
+                sshape = [str(s) for s in shape]
             elif (sshape is not None) and len(sshape)!=dim:
                 raise ValueError('sshape dim mismatch!')
             else:
-                sshape = (None,)*dim
+                sshape = (None,)*ptr_dim
             sshape = np.asarray(sshape)
        
-            _value, _svalue = CodegenArray.initialize_rec(name,dim,
-                    ctype, typegen, shape, sshape, value, svalue, 
-                    const, add_impl_const, restrict,
+            _value, _svalue = CodegenArray._initialize_rec(name, typegen, 
+                    storage, ctype, const, volatile,
+                    shape, sshape, value, svalue, 
+                    ptr_dim, ptr_restrict, ptr_const, ptr_volatile,
                     symbolic_mode)
         
-        super(self.__class__, self).__init__(name=name,
-                ctype=ctype, typegen=typegen, 
+        super(CodegenArray, self).__init__(name=name,
+                storage=storage, ctype=ctype, typegen=typegen, 
                 value=_value, svalue=_svalue,
-                const=const, add_impl_const=add_impl_const,
-                ptr=True,restrict=restrict,
-                symbolic_mode=symbolic_mode, struct_var=struct_var,
-                storage=storage)
+                const=const, add_impl_const=add_impl_const, volatile=volatile,
+                ptr=ptr_dim, ptr_restrict=ptr_restrict, ptr_const=ptr_const, ptr_volatile=ptr_volatile,
+                symbolic_mode=symbolic_mode, struct_var=struct_var)
         self.shape = shape
         self.sshape = sshape
 
         
         
 class CodegenVector(CodegenVariable):
-    def __init__(self,name,ctype,dim,typegen,
+    def __init__(self, name, ctype, dim, typegen,
             value=None,svalue=None,
-            const=False, add_impl_const=False,
-            storage=None, nl=None,
-            ptr=False, restrict=False,
+            storage=None, const=False, volatile=False, 
+            ptr=False, ptr_const=None, ptr_volatile=None, ptr_restrict=None,
+            add_impl_const=False, nl=None,
             symbolic_mode=False, struct_var=None,
             init=None):
         super(CodegenVector,self).__init__(name=name,ctype=ctype,value=value,typegen=typegen,
-                const=const, add_impl_const=add_impl_const,
-                storage=storage, nl=nl, ptr=ptr, restrict=restrict,
+                const=const, volatile=volatile, add_impl_const=add_impl_const,
+                storage=storage, nl=nl, 
+                ptr=ptr, ptr_const=ptr_const, ptr_volatile=ptr_volatile, ptr_restrict=ptr_restrict,
                 symbolic_mode=symbolic_mode,struct_var=struct_var,init=init)
 
         self.value = value
@@ -592,14 +663,14 @@ class CodegenVectorClBuiltin(CodegenVector):
         else:
             raise TypeError, 'Invalid key type!'
     
-    def declare(self,codegen=None,align=False,const=None,storage=None,init=None):
+    def declare(self,codegen=None,align=False,const=None,init=None):
         if isinstance(init,int):
             init = ','.join([self.typegen.dump(init) for _ in xrange(self.dim)])
             init = '({})({})'.format(self.ctype,init)
         elif init.__class__ in [list,tuple,np.ndarray]:
             init = ','.join([self.typegen.dump(init[i]) for i in xrange(self.dim)])
             init = '({})({})'.format(self.ctype,init)
-        return super(CodegenVectorClBuiltin,self).declare(codegen=codegen,align=align,const=const,storage=storage,init=init)
+        return super(CodegenVectorClBuiltin,self).declare(codegen=codegen,align=align,const=const,init=init)
 
 class CodegenVectorClBuiltinFunc(CodegenVectorClBuiltin):
     def __init__(self,fname,name,btype,dim,typegen,
@@ -618,34 +689,32 @@ class CodegenVectorClBuiltinFunc(CodegenVectorClBuiltin):
             assert i<self.dim
             return 'get_{}({})'.format(self.fname,i)
 
-    def declare(self,codegen=None,align=False,const=None,storage=None,init=None):
+    def declare(self,codegen=None,align=False,const=None,init=None):
         if init is False:
             init = None
         else:
             init = self.fval() if not self.known() else init
-        return super(CodegenVectorClBuiltinFunc,self).declare(codegen=codegen,align=align,const=const,storage=storage,init=init)
+        return super(CodegenVectorClBuiltinFunc,self).declare(codegen=codegen,align=align,
+                const=const, init=init)
 
 class CodegenStruct(CodegenVariable):
-    def __init__(self,varname,struct,
-                    ptr=False, restrict=False,
-                    const=False, add_impl_const=False,
-                    storage=None, nl=None,
+    def __init__(self, name, struct,
+                    storage=None, const=False, volatile=False,
+                    ptr=False, ptr_const=None, ptr_volatile=None, ptr_restrict=None,
+                    add_impl_const=False, nl=None,
                     symbolic_mode=False,
                     struct_var=None,
                     value=None,
                     var_overrides=None):
 
         super(CodegenStruct,self).__init__(
-                name=varname,
+                name=name,
                 ctype=struct.ctype, 
                 typegen=struct.typegen,
+                storage=storage, const=const, volatile=volatile,
+                ptr=ptr, ptr_const=ptr_const, ptr_volatile=ptr_volatile, ptr_restrict=ptr_restrict,
+                add_impl_const=add_impl_const, nl=nl, 
                 value=value,
-                const=const, 
-                add_impl_const=add_impl_const,
-                storage=storage, 
-                nl=nl, 
-                ptr=ptr,
-                restrict=restrict,
                 symbolic_mode=symbolic_mode, 
                 struct_var=struct_var)
        
diff --git a/hysop/backend/device/codegen/kernels/directional_remesh.py b/hysop/backend/device/codegen/kernels/directional_remesh.py
index 955b449cf..2aee3c016 100644
--- a/hysop/backend/device/codegen/kernels/directional_remesh.py
+++ b/hysop/backend/device/codegen/kernels/directional_remesh.py
@@ -64,8 +64,7 @@ class DirectionalRemeshKernel(KernelCodeGenerator):
         return int(1+math.ceil(scalar_cfl)+remesh_kernel.n/2)
 
     def __init__(self, typegen, work_dim, direction, ftype, 
-                       nparticles, nscalars, sboundary,
-                       is_inplace, 
+                       nparticles, nscalars, sboundary, is_inplace, 
                        scalar_cfl, remesh_kernel,
                        remesh_criteria_eps=None,
                        use_atomics   = False,
@@ -80,19 +79,19 @@ class DirectionalRemeshKernel(KernelCodeGenerator):
         check_instance(sboundary[0],BoundaryCondition)
         check_instance(sboundary[1],BoundaryCondition)
         check_instance(remesh_kernel, RemeshKernel)
-
-        known_vars = known_vars or dict()
-        itype = 'int'
-        vftype = tg.vtype(ftype, nparticles)
-        vitype = tg.vtype(itype, nparticles)
-
+        
         assert sboundary[0] in [BoundaryCondition.PERIODIC, BoundaryCondition.NONE]
         assert sboundary[1] in [BoundaryCondition.PERIODIC, BoundaryCondition.NONE]
         is_periodic = (sboundary[0]==BoundaryCondition.PERIODIC \
                    and sboundary[1]==BoundaryCondition.PERIODIC)
-        
+
+        known_vars = known_vars or dict()
         local_size_known = ('local_size' in known_vars)
 
+        itype = 'int'
+        vftype = tg.vtype(ftype, nparticles)
+        vitype = tg.vtype(itype, nparticles)
+
         name = DirectionalRemeshKernel.codegen_name(work_dim, direction, 
                 remesh_kernel, ftype,
                 nparticles,nscalars, remesh_criteria_eps,
@@ -155,28 +154,28 @@ class DirectionalRemeshKernel(KernelCodeGenerator):
         kargs = ArgDict()
         self.position = OpenClArrayBackend.build_codegen_argument(kargs, name='position', 
                     storage=self._global, ctype=ftype, typegen=typegen,
-                    restrict=True, const=True)
+                    ptr_restrict=True, ptr_const=True)
         if is_inplace:
             self.scalars_in = tuple( 
                     OpenClArrayBackend.build_codegen_argument(kargs, name=' s{}_in'.format(i),
                         storage=self._global, ctype=ftype, typegen=typegen,
-                        restrict=True, const=False) for i in xrange(nscalars))
+                        ptr_restrict=True, ptr_const=False) for i in xrange(nscalars))
             self.scalars_out = self.scalars_in
         else:
             self.scalars_in = tuple( 
                     OpenClArrayBackend.build_codegen_argument(kargs, name='s{}_in'.format(i),
                         storage=self._global, ctype=ftype, typegen=typegen,
-                        restrict=True, const=True) for i in xrange(nscalars))
+                        ptr_restrict=True, ptr_const=True) for i in xrange(nscalars))
             self.scalars_out = tuple( 
                     OpenClArrayBackend.build_codegen_argument(kargs, name='s{}_out'.format(i),
                         storage=self._global, ctype=ftype, typegen=typegen,
-                        restrict=True, const=False) for i in xrange(nscalars))
+                        ptr_restrict=True, ptr_const=False) for i in xrange(nscalars))
         
         if debug_mode:
             kargs['dbg0'] = CodegenVariable(storage=self._global,name='dbg0',ctype=itype,
-                    typegen=typegen, restrict=True,ptr=True,const=False,add_impl_const=True)
+                    typegen=typegen, ptr_restrict=True,ptr=True,const=False,add_impl_const=True)
             kargs['dbg1'] = CodegenVariable(storage=self._global,name='dbg1',ctype=itype,
-                    typegen=typegen, restrict=True,ptr=True,const=False,add_impl_const=True)
+                    typegen=typegen, ptr_restrict=True,ptr=True,const=False,add_impl_const=True)
 
         kargs['position_mesh_info'] = kernel_reqs['MeshInfoStruct'].build_codegen_variable(
                 const=True, name='position_mesh_info')
@@ -187,7 +186,7 @@ class DirectionalRemeshKernel(KernelCodeGenerator):
 
         if not local_size_known:
              kargs['buffer'] = CodegenVariable(storage=self._local, ctype=ftype, 
-                     add_impl_const=True, name='buffer', ptr=True, restrict=True, 
+                     add_impl_const=True, name='buffer', ptr=True, ptr_restrict=True, 
                      typegen=typegen, nl=False)
 
         return kargs
@@ -256,7 +255,7 @@ class DirectionalRemeshKernel(KernelCodeGenerator):
         line_index    = CodegenVariable(name='line_index', ctype=itype, typegen=tg)
         line_offset   = CodegenVariable(name='line_offset', ctype=itype, typegen=tg,const=True)
         line_velocity = CodegenVariable(name='line_velocity', ctype=ftype, ptr=True, 
-                storage='__global', restrict=True, const=True, add_impl_const=True, typegen=tg)
+                storage='__global', ptr_restrict=True, ptr_const=True, const=True, typegen=tg)
         
         position_global_id = CodegenVectorClBuiltin('pos_gid', itype, work_dim, typegen=tg)
         scalars_global_id = tuple(CodegenVectorClBuiltin('S{}_gid'.format(i), 
@@ -283,7 +282,7 @@ class DirectionalRemeshKernel(KernelCodeGenerator):
             buf = self.vars['buffer']
             for i in xrange(nscalars):
                 Si = CodegenVariable(name='S{}'.format(i),ctype=ftype,typegen=tg,
-                            restrict=True, ptr=True, storage=self._local,
+                            ptr_restrict=True, ptr=True, storage=self._local,
                             const=True,
                             init='{} + {}*{}'.format(buf,i,cache_width))
                 cached_scalars.append(Si)
@@ -380,9 +379,10 @@ class DirectionalRemeshKernel(KernelCodeGenerator):
                     sgid.declare(al,align=True)
             s.jumpline()
             
-            with s._align_() as al:
-                for var in cached_scalars:
-                    var.declare(al,align=True);
+            #with s._align_() as al:
+                #for var in cached_scalars:
+                    #var.declare(al,align=True);
+            s.decl_vars(*cached_scalars)
             s.jumpline()
                 
         
diff --git a/hysop/backend/device/opencl/opencl_array_backend.py b/hysop/backend/device/opencl/opencl_array_backend.py
index 3609031bb..d53ee9498 100644
--- a/hysop/backend/device/opencl/opencl_array_backend.py
+++ b/hysop/backend/device/opencl/opencl_array_backend.py
@@ -2985,20 +2985,20 @@ class OpenClArrayBackend(ArrayBackend):
         assert 'add_impl_const' not in kargs
         assert 'init' not in kargs
 
-        args[base] = CodegenVariable(name=base,
-                typegen=typegen, ctype=ctype, ptr=ptr, const=const,
+        args[base] = CodegenVariable(name=base, typegen=typegen, 
+                ctype=ctype, ptr=ptr, const=const,
                 add_impl_const=True, nl=False, **kargs)
 
         args[offset] = CodegenVariable(name=offset,
                 typegen=typegen, ctype=itype,
-                add_impl_const=True,nl=True)
+                add_impl_const=True, nl=True)
         
-        char_alias  = args[base].alias(None, ctype='char', restrict=False, volatile=False).full_ctype()
-        ctype_alias = args[base].alias(None, ctype=ctype,  restrict=False, volatile=False).full_ctype()
+        char_alias  = args[base].full_ctype(ctype='char', cast=True)
+        ctype_alias = args[base].full_ctype(cast=True)
         init = '({})(({})({})+{})'.format(ctype_alias, char_alias, base, offset)
 
-        var = CodegenVariable(name=name,
-                typegen=typegen, ctype=ctype, ptr=ptr, const=const,
+        var = CodegenVariable(name=name, typegen=typegen, 
+                ctype=ctype, ptr=ptr, const=const,
                 add_impl_const=True, nl=False, 
                 init=init, **kargs)
 
-- 
GitLab