def gen_readme(opts): print('-- Generating documentation in DOC.md') filename = os.path.join(opts.script_dir, '..', 'DOC.md') if not common.can_create_filename(opts, filename): return with io.open(filename, mode='w', encoding='utf-8') as fout: fout.write('''## NSIMD scalar types Their names follows the following pattern: `Sxx` where - `S` is `i` for signed integers, `u` for unsigned integer and `f` for floatting point number. - `xx` is the number of bits taken to represent the number. Full list of scalar types: ''') for t in common.types: fout.write('- `{}`\n'.format(t)) fout.write(''' ## NSIMD SIMD vector types Their names follows the following pattern: `vSCALAR` where `SCALAR` is a one of scalar type listed above. For example `vi8` means a SIMD vector containing `i8`'s. Full list of SIMD vector types: ''') for t in common.types: fout.write('- `v{}`\n'.format(t)) fout.write(''' ## C/C++ base APIs These come automatically when you include `nsimd/nsimd.h`. You do *not* need to include a header file for having a function. In NSIMD, we call a platform an architecture e.g. Intel, ARM, POWERPC. We call SIMD extension a set of low-level functions and types provided to access a given SIDM extension. Examples include SSE2, SSE42, AVX, ... Here is a list of supported platforms and their corresponding SIMD extensions. ''') platforms = common.get_platforms(opts) for p in platforms: fout.write('- Platform `{}`\n'.format(p)) for s in platforms[p].get_simd_exts(): fout.write(' - `{}`\n'.format(s)) fout.write(''' Each simd extension has its own set of SIMD types and functions. Types follow the following pattern: `nsimd_SIMDEXT_vSCALAR` where - `SIMDEXT` is the SIMD extensions. - `SCALAR` is one of scalar types listed above. There are also logical types associated to each SIMD vector type. These types are used to represent the result of a comparison of SIMD vectors. They are usually bit masks. Their name follow the following pattern: `nsimd_SIMDEXT_vlSCALAR` where - `SIMDEXT` is the SIMD extensions. - `SCALAR` is one of scalar types listed above. Note 1: Platform `cpu` is scalar fallback when no SIMD extension has been specified. Note 2: as all SIMD extensions of all platforms are different there is no need to put the name of the platform in each identifier. Function names follow the following pattern: `nsimd_SIMDEXT_FUNCNAME_SCALAR` where - `SIMDEXT` is the SIMD extensions. - `FUNCNAME` is the name of a function e.g. `add` or `sub`. - `SCALAR` is one of scalar types listed above. ### Generic identifier In C, genericity is achieved using macros. - `vec(SCALAR)` represents the SIMD vector type containing SCALAR elements. SCALAR must be one of scalar types listed above. - `vecl(SCALAR)` represents the SIMD vector of logicals type containing SCALAR elements. SCALAR must be one of scalar types listed above. - `vec_e(SCALAR)` represents the SIMD vector type containing SCALAR elements. SCALAR must be one of scalar types listed above. - `vecl_e(SCALAR)` represents the SIMD vector of logicals type containing SCALAR elements. SCALAR must be one of scalar types listed above. - `vFUNCNAME` is the macro name to access the function FUNCNAME e.g. `vadd`, `vsub`. - `vFUNCNAME_e` is the macro name to access the function FUNCNAME e.g. `vadd_e`, `vsub_e`. In C++98 and C++03, type traits are available. - `nsimd::simd_traits<SCALAR, SIMDEXT>::vector` is the SIMD vector type for platform SIMDEXT containing SCALAR elements. SIMDEXT is one of SIMD extension listed above, SCALAR is one of scalar type listed above. - `nsimd::simd_traits<SCALAR, SIMDEXT>::vectorl` is the SIMD vector of logicals type for platform SIMDEXT containing SCALAR elements. SIMDEXT is one of SIMD extensions listed above, SCALAR is one of scalar type listed above. In C++11 and beyond, type traits are still available but typedefs are also provided. - `nsimd::vector<SCALAR, SIMDEXT>` is a typedef to `nsimd::simd_traits<SCALAR, SIMDEXT>::vector`. - `nsimd::vectorl<SCALAR, SIMDEXT>` is a typedef to `nsimd::simd_traits<SCALAR, SIMDEXT>::vectorl`. Note that all macro and functions available in plain C are still available in C++. ### List of functions available for manipulation of SIMD vectors For each FUNCNAME a C function (also available in C++) named `nsimd_SIMDEXT_FUNCNAME_SCALAR` is available for each SCALAR type unless specified otherwise. For each FUNCNAME, a C macro (also available in C++) named `vFUNCNAME` is available and takes as its last argument a SCALAR type. For each FUNCNAME, a C macro (also available in C++) named `vFUNCNAME_a` is available and takes as its two last argument a SCALAR type and a SIMDEXT. For each FUNCNAME, a C++ function in namespace `nsimd` named `FUNCNAME` is available. It takes as its last argument the SCALAR type and can optionnally take the SIMDEXT as its last last argument. For example, for the addition of two SIMD vectors `a` and `b` here are the possibilities: c = nsimd_add_avx_f32(a, b); // use AVX c = nsimd::add(a, b, f32()); // use detected SIMDEXT c = nsimd::add(a, b, f32(), avx()); // force AVX even if detected SIMDEXT is not AVX c = vadd(a, b, f32); // use detected SIMDEXT c = vadd_e(a, b, f32, avx); // force AVX even if detected SIMDEXT is not AVX Here is a list of available FUNCNAME. ''') for op_name, operator in operators.items(): return_typ = common.get_one_type_generic(operator.params[0], 'SCALAR') func = operator.name args = ', '.join([common.get_one_type_generic(p, 'SCALAR') + \ ' a' + str(count) for count, p in \ enumerate(operator.params[1:])]) fout.write('- `{} {}({});`\n'.format(return_typ, func, args)) if operator.domain and len(operator.params[1:]) > 0: params = operator.params[1:] if len(params) == 1: fout.write(' a0 ∈ {}\n'.format(operator.domain)) else: param = ', '.join(['a' + str(count) for count in \ range(len(params))]) fout.write(' ({}) ∈ {}\n'.format(param, operator.domain)) if len(operator.types) < len(common.types): typs = ', '.join(['{}'.format(t) for t in operator.types]) fout.write(' Only available for {}\n'.format(typs)) fout.write(''' ## C++ advanced API The C++ advanced API is called advanced not because it requires C++11 or above but because it makes use of the particular implementation of ARM SVE by ARM in their compiler. We do not know if GCC (and possibly MSVC in the distant future) will use the same approach. Anyway the current implementation allows us to put SVE SIMD vectors inside some kind of structs that behave like standard structs. If you want to be sure to write portable code do *not* use this API. Two new types are available. - `nsimd::pack<SCALAR, N, SIMDEXT>` represents `N` SIMD vectors containing SCALAR elements of SIMD extension SIMDEXT. You can specify only the first template argument. The second defaults to 1 while the third defaults to the detected SIMDEXT. - `nsimd::packl<SCALAR, N, SIMDEXT>` represents `N` SIMD vectors of logical type containing SCALAR elements of SIMD extension SIMDEXT. You can specify only the first template argument. The second defaults to 1 while the third defaults to the detected SIMDEXT. Use N > 1 when declaring packs to have an unroll of N. This is particularily useful on ARM. Functions that takes packs do not take any other argument unless specified otherwise e.g. the load family of funtions. It is impossible to determine the kind of pack (unroll and SIMDEXT) from the type of a pointer. Therefore in this case, the last argument must be a pack and this same type will then return. Also some functions are available as C++ operators. Here is the list of functions that act on packs. ''') for op_name, operator in operators.items(): return_typ = common.get_one_type_pack(operator.params[0], 1, 'N') func = operator.name args = ', '.join([common.get_one_type_pack(p, 0, 'N') + ' a' + \ str(count) for count, p in \ enumerate(operator.params[1:])]) if 'v' not in operator.params[1:] and 'l' not in operator.params[ 1:]: args = args + ', pack<T, N, SimdExt> const&' if args != '' \ else 'pack<T, N, SimdExt> const&' fout.write('- `{} {}({});`\n'.format(return_typ, func, args)) if operator.domain and len(operator.params[1:]) > 0: params = operator.params[1:] if len(params) == 1: fout.write(' a0 ∈ {}\n'.format(operator.domain)) else: param = ', '.join(['a'+str(count) for count in \ range(len(params))]) fout.write(' ({}) ∈ {}\n'.format(param, operator.domain)) if operator.cxx_operator: fout.write(' Available as {}\n'.format(operator.cxx_operator)) if len(operator.types) < len(common.types): typs = ', '.join(['{}'.format(t) for t in operator.types]) fout.write(' Only available for {}\n'.format(typs))
def gen_doc(opts): sys.stdout.write('-- Generating doc for each functions\n') dirname = os.path.join(opts.script_dir, '..', 'doc') common.mkdir_p(dirname) # Root node first obj = collections.OrderedDict() obj['title'] = 'Root node' obj['sig'] = [] obj['lang'] = '' obj['categories'] = [] obj['desc'] = [] obj['parent'] = '' obj['id'] = '/' obj['type'] = 'root' obj['title'] = 'Root node' filename = os.path.join(dirname, 'root.json') if common.can_create_filename(opts, filename): with io.open(filename, mode='w', encoding='utf-8') as fout: fout.write(json.dumps(obj, ensure_ascii=False)) # Categories first for name, cat in categories.items(): filename = os.path.join(dirname, '{}.json'.format(name)) ## Check if we need to create the file if not common.can_create_filename(opts, filename): continue obj = collections.OrderedDict() obj['title'] = cat.name obj['sig'] = [] obj['lang'] = '' obj['categories'] = [] obj['desc'] = [] obj['parent'] = '/' obj['id'] = '/{}'.format(name) obj['type'] = 'category' obj['title'] = cat.title with io.open(filename, mode='w', encoding='utf-8') as fout: fout.write(json.dumps(obj, ensure_ascii=False)) # APIs for api in ['c_base', 'cxx_base', 'cxx_adv']: filename = os.path.join(dirname, '{}.json'.format(api)) if common.can_create_filename(opts, filename): l = collections.OrderedDict() l['title'] = { 'c_base': 'C API', 'cxx_base': 'C++ base API', 'cxx_adv': 'C++ advanced API' }[api] l['id'] = '/{}'.format(api) l['parent'] = '/' l['sig'] = [] l['type'] = '' l['desc'] = [] l['categories'] = [] l['lang'] = 'C' if api == 'c' else 'C++' with io.open(filename, mode='w', encoding='utf-8') as fout: fout.write(json.dumps(l, ensure_ascii=False)) # Operators (one file per operator otherwise too much files) for op_name, operator in operators.items(): ## Skip non-matching doc if opts.match and not opts.match.match(op_name): continue filename = os.path.join(dirname, '{}.json'.format(op_name)) cats = ['/{}'.format(c.name) for c in operator.categories] withdoc_id = '/{}'.format(op_name) doc_blocks = [] obj = collections.OrderedDict() # All is withdoc'ed with this docblock which has no desc, no sig... obj = collections.OrderedDict() obj['id'] = withdoc_id obj['desc'] = [operator.desc] obj['sig'] = [] obj['parent'] = '/' obj['categories'] = cats obj['type'] = 'function' obj['title'] = operator.full_name obj['lang'] = '' doc_blocks.append(obj) def to_list(var): ret = [var] if type(var) == str or not hasattr(var, '__iter__') \ else list(var) for i in range(0, len(ret)): ret[i] = re.sub('[ \n\t\r]+', ' ', ret[i]) return ret # All base C/C++ functions (for each architecture and type) for api in ['c_base', 'cxx_base']: for simd_ext in common.simds: for typ in operator.types: obj = collections.OrderedDict() obj['id'] = '/{}-{}-{}-{}'.format(op_name, api, simd_ext, typ) obj['desc'] = [] obj['parent'] = '/{}'.format(api) obj['categories'] = cats obj['type'] = 'function' obj['withdoc'] = withdoc_id obj['sig'] = to_list( operator.get_signature(typ, api, simd_ext)) obj['title'] = '' obj['lang'] = common.ext_from_lang(api) doc_blocks.append(obj) # C/C++ base/advanced generic functions for api in ['c_base', 'cxx_base', 'cxx_adv']: obj = collections.OrderedDict() obj['id'] = '/{}-{}'.format(op_name, api) obj['desc'] = [] obj['parent'] = '/{}'.format(api) obj['categories'] = cats obj['type'] = 'function' obj['withdoc'] = withdoc_id obj['sig'] = to_list(operator.get_generic_signature(api) \ if api != 'cxx_adv' else \ operator.get_generic_signature(api).values()) obj['title'] = '' obj['lang'] = common.ext_from_lang(api) doc_blocks.append(obj) # Finally dump JSON with io.open(filename, mode='w', encoding='utf-8') as fout: fout.write(json.dumps(doc_blocks, ensure_ascii=False))
def gen_overview(opts): filename = common.get_markdown_file(opts, 'overview') if not common.can_create_filename(opts, filename): return with common.open_utf8(opts, filename) as fout: fout.write('''# Overview ## NSIMD scalar types Their names follow the following pattern: `Sxx` where - `S` is `i` for signed integers, `u` for unsigned integer or `f` for floatting point number. - `xx` is the number of bits taken to represent the number. Full list of scalar types: ''') for t in common.types: fout.write('- `{}`\n'.format(t)) fout.write(''' ## NSIMD generic SIMD vector types In NSIMD, we call a platform an architecture e.g. Intel, ARM, POWERPC. We call SIMD extension a set of low-level functions and types provided by hardware vendors to access SIMD units. Examples include SSE2, SSE42, AVX, ... When compiling the generic SIMD vector types represents a SIMD register of the target. Examples are a `__m128` for Intel SSE, `__m512` for Intel AVX-512 or `svfloat32_t` for Arm SVE. Their names follow the following pattern: - C base API: `vSCALAR` where `SCALAR` is a one of scalar type listed above. - C advanced API: `nsimd_pack_SCALAR` where `SCALAR` is a one of scalar type listed above. - C++ advanced API: `nsimd::pack<SCALAR>` where `SCALAR` is a one of scalar type listed above. Full list of SIMD vector types: | Base type | C base API | C advanced API | C++ advanced API | |-----------|------------|----------------|------------------| ''') fout.write('\n'.join([ '| `{typ}` | `v{typ}` | `nsimd_pack_{typ}` | `nsimd::pack<{typ}>` |'. \ format(typ=typ) for typ in common.types])) fout.write(''' ## C/C++ base APIs These come automatically when you include `nsimd/nsimd.h`. You do *not* need to include a header file for having a function. Here is a list of supported platforms and their corresponding SIMD extensions. ''') platforms = common.get_platforms(opts) for p in platforms: fout.write('- Platform `{}`\n'.format(p)) for s in platforms[p].get_simd_exts(): fout.write(' - `{}`\n'.format(s)) fout.write(''' Each simd extension has its own set of SIMD types and functions. Types follow the pattern: `nsimd_SIMDEXT_vSCALAR` where - `SIMDEXT` is the SIMD extensions. - `SCALAR` is one of scalar types listed above. There are also logical types associated to each SIMD vector type. These types are used, for example, to represent the result of a comparison of SIMD vectors. They are usually bit masks. Their name follow the pattern: `nsimd_SIMDEXT_vlSCALAR` where - `SIMDEXT` is the SIMD extensions. - `SCALAR` is one of scalar types listed above. Note 1: Platform `cpu` is a 128 bits SIMD emulation fallback when no SIMD extension has been specified or is supported on a given compilation target. Note 2: as all SIMD extensions of all platforms are different there is no need to put the name of the platform in each identifier. Function names follow the pattern: `nsimd_SIMDEXT_FUNCNAME_SCALAR` where - `SIMDEXT` is the SIMD extensions. - `FUNCNAME` is the name of a function e.g. `add` or `sub`. - `SCALAR` is one of scalar types listed above. ### Generic identifier In the base C API, genericity is achieved using macros. - `vec(SCALAR)` is a type to represent a SIMD vector containing SCALAR elements. SCALAR must be one of scalar types listed above. - `vecl(SCALAR)` is a type to represent a SIMD vector of logicals for SCALAR elements. SCALAR must be one of scalar types listed above. - `vec_a(SCALAR, SIMDEXT)` is a type to represent a SIMD vector containing SCALAR elements for the simd extension SIMDEXT. SCALAR must be one of scalar types listed above and SIMDEXT must be a valid SIMD extension. - `vecl_a(SCALAR, SIMDEXT)` is a type to represent a SIMD vector of logicals for SCALAR elements for the simd extension SIMDEXT. SCALAR must be one of scalar types listed above and SIMDEXT must be a valid SIMD extension. - `vFUNCNAME` takes as input the above types to access the operator FUNCNAME e.g. `vadd`, `vsub`. In C++98 and C++03, type traits are available. - `nsimd::simd_traits<SCALAR, SIMDEXT>::vector` is the SIMD vector type for platform SIMDEXT containing SCALAR elements. SIMDEXT is one of SIMD extension listed above, SCALAR is one of scalar type listed above. - `nsimd::simd_traits<SCALAR, SIMDEXT>::vectorl` is the SIMD vector of logicals type for platform SIMDEXT containing SCALAR elements. SIMDEXT is one of SIMD extensions listed above, SCALAR is one of scalar type listed above. In C++11 and beyond, type traits are still available but typedefs are also provided. - `nsimd::vector<SCALAR, SIMDEXT>` is a typedef to `nsimd::simd_traits<SCALAR, SIMDEXT>::vector`. - `nsimd::vectorl<SCALAR, SIMDEXT>` is a typedef to `nsimd::simd_traits<SCALAR, SIMDEXT>::vectorl`. The C++20 API does not bring different types for SIMD registers nor other way to access the other SIMD types. It only brings concepts instead of usual `typename`s. For more informations cf. <concepts.md>. Note that all macro and functions available in plain C are still available in C++. ### List of operators provided by the base APIs In the documentation we use interchangeably the terms "function" and "operator". For each operator FUNCNAME a C function (also available in C++) named `nsimd_SIMDEXT_FUNCNAME_SCALAR` is available for each SCALAR type unless specified otherwise. For each FUNCNAME, a C macro (also available in C++) named `vFUNCNAME` is available and takes as its last argument a SCALAR type. For each FUNCNAME, a C macro (also available in C++) named `vFUNCNAME_a` is available and takes as its two last argument a SCALAR type and a SIMDEXT. For each FUNCNAME, a C++ function in namespace `nsimd` named `FUNCNAME` is available. It takes as its last argument the SCALAR type and can optionnally take the SIMDEXT as its last last argument. For example, for the addition of two SIMD vectors `a` and `b` here are the possibilities: ```c++ c = nsimd_add_avx_f32(a, b); // use AVX c = nsimd::add(a, b, f32()); // use detected SIMDEXT c = nsimd::add(a, b, f32(), avx()); // force AVX even if detected SIMDEXT is not AVX c = vadd(a, b, f32); // use detected SIMDEXT c = vadd_e(a, b, f32, avx); // force AVX even if detected SIMDEXT is not AVX ``` Here is a list of available FUNCNAME. ''') for op_name, operator in operators.items(): return_typ = common.get_one_type_generic(operator.params[0], 'SCALAR') func = operator.name args = ', '.join([common.get_one_type_generic(p, 'SCALAR') + \ ' a' + str(count) for count, p in \ enumerate(operator.params[1:])]) fout.write('- `{} {}({});` \n'.format(return_typ, func, args)) if len(operator.types) < len(common.types): typs = ', '.join(['{}'.format(t) for t in operator.types]) fout.write(' Only available for {}\n'.format(typs)) fout.write(''' ## C advanced API (only available in C11) The C advanced API takes advantage of the C11 `_Generic` keyword to provide function overloading. Unlike the base API described above there is no need to pass as arguments the base type of the SIMD extension. The informations are contained in the types provided by this API. - `nsimd_pack_SCALAR_SIMDEXT` represents a SIMD vectors containing SCALAR elements of SIMD extension SIMDEXT. - `nsimd::packl_SCALAR_SIMDEXT` represents a SIMD vectors of logicals for SCALAR elements of SIMD extension SIMDEXT. There are versions of the above type without SIMDEXT for which the targeted SIMD extension is automatically chosen. - `nsimd_pack_SCALAR` represents a SIMD vectors containing SCALAR elements. - `nsimd::packl_SCALAR` represents a SIMD vectors of logicals for SCALAR elements. Generic types are also available: - `nsimd_pack(SCALAR)` is a type to represent a SIMD vector containing SCALAR elements. SCALAR must be one of scalar types listed above. - `nsimd_packl(SCALAR)` is a type to represent a SIMD vector of logicals for SCALAR elements. SCALAR must be one of scalar types listed above. - `nsimd_pack_a(SCALAR, SIMDEXT)` is a type to represent a SIMD vector containing SCALAR elements for the simd extension SIMDEXT. SCALAR must be one of scalar types listed above and SIMDEXT must be a valid SIMD extension. - `nsimd_packl_a(SCALAR, SIMDEXT)` is a type to represent a SIMD vector of logicals for SCALAR elements for the simd extension SIMDEXT. SCALAR must be one of scalar types listed above and SIMDEXT must be a valid SIMD extension. Finally, operators are follow the naming: `nsimd_FUNCNAME` e.g. `nsimd_add`, `nsimd_sub`. ## C++ advanced API The C++ advanced API is called advanced not because it requires C++11 or above but because it makes use of the particular implementation of ARM SVE by ARM in their compiler. We do not know if GCC (and possibly MSVC in the distant future) will use the same approach. Anyway the current implementation allows us to put SVE SIMD vectors inside some kind of structs that behave like standard structs. If you want to be sure to write portable code do *not* use this API. Two new types are available. - `nsimd::pack<SCALAR, N, SIMDEXT>` represents `N` SIMD vectors containing SCALAR elements of SIMD extension SIMDEXT. You can specify only the first template argument. The second defaults to 1 while the third defaults to the detected SIMDEXT. - `nsimd::packl<SCALAR, N, SIMDEXT>` represents `N` SIMD vectors of logical type containing SCALAR elements of SIMD extension SIMDEXT. You can specify only the first template argument. The second defaults to 1 while the third defaults to the detected SIMDEXT. Use N > 1 when declaring packs to have an unroll of N. This is particularily useful on ARM. Functions that takes packs do not take any other argument unless specified otherwise e.g. the load family of funtions. It is impossible to determine the kind of pack (unroll and SIMDEXT) from the type of a pointer. Therefore in this case, the last argument must be a pack and this same type will then return. Also some functions are available as C++ operators. They follow the naming: `nsimd::FUNCNAME`. ''')
def gen_what_is_wrapped(opts): common.myprint(opts, 'Generating "which intrinsics are wrapped"') build_exe_for_doc(opts) wrapped = 'what_is_wrapped.exe' if platform.system() == 'Windows' \ else 'what_is_wrapped' doc_dir = os.path.join(opts.script_dir, '..', 'doc') full_path_wrapped = os.path.join(doc_dir, wrapped) if not os.path.isfile(full_path_wrapped): common.myprint(opts, '{} not found'.format(wrapped)) return # Content for indexing files created in this function index = '# Intrinsics that are wrapped\n' # Build command line cmd0 = '{} {},{},{},{},{},{}'.format(full_path_wrapped, common.in0, common.in1, common.in2, common.in3, common.in4, common.in5) # For now we only list Intel, Arm and POWERPC intrinsics simd_exts = common.x86_simds + common.arm_simds + common.ppc_simds for p in common.get_platforms(opts): index_simds = '' for simd_ext in opts.platforms_list[p].get_simd_exts(): if simd_ext not in simd_exts: continue md = os.path.join(common.get_markdown_dir(opts), 'wrapped_intrinsics_for_{}.md'.format(simd_ext)) index_simds += '- [{}](wrapped_intrinsics_for_{}.md)\n'. \ format(simd_ext.upper(), simd_ext) ops = [[], [], [], []] for op_name, operator in operators.items(): if operator.src: continue c_src = os.path.join(opts.include_dir, p, simd_ext, '{}.h'.format(op_name)) ops[operator.output_to].append('{} "{}"'. \ format(op_name, c_src)) if not common.can_create_filename(opts, md): continue with common.open_utf8(opts, md) as fout: fout.write('# Intrinsics wrapped for {}\n\n'. \ format(simd_ext.upper())) fout.write('Notations are as follows:\n' '- `T` for trick usually using other intrinsics\n' '- `E` for scalar emulation\n' '- `NOOP` for no operation\n' '- `NA` means the operator does not exist for ' 'the given type\n' '- `intrinsic` for the actual wrapped intrinsic\n' '\n') cmd = '{} {} same {} >> "{}"'.format( cmd0, simd_ext, ' '.join(ops[common.OUTPUT_TO_SAME_TYPE]), md) if os.system(cmd) != 0: common.myprint(opts, 'Unable to generate markdown for ' '"same"') continue cmd = '{} {} same_size {} >> "{}"'.format( cmd0, simd_ext, ' '.join(ops[common.OUTPUT_TO_SAME_SIZE_TYPES]), md) if os.system(cmd) != 0: common.myprint( opts, 'Unable to generate markdown for ' '"same_size"') continue cmd = '{} {} bigger_size {} >> "{}"'.format( cmd0, simd_ext, ' '.join(ops[common.OUTPUT_TO_UP_TYPES]), md) if os.system(cmd) != 0: common.myprint( opts, 'Unable to generate markdown for ' '"bigger_size"') continue cmd = '{} {} lesser_size {} >> "{}"'.format( cmd0, simd_ext, ' '.join(ops[common.OUTPUT_TO_DOWN_TYPES]), md) if os.system(cmd) != 0: common.myprint( opts, 'Unable to generate markdown for ' '"lesser_size"') continue if index_simds != '': index += '\n## Platform {}\n\n'.format(p) index += index_simds md = os.path.join(common.get_markdown_dir(opts), 'wrapped_intrinsics.md') if common.can_create_filename(opts, md): with common.open_utf8(opts, md) as fout: fout.write(index)
def gen_doc(opts): common.myprint(opts, 'Generating doc for each function') # Build tree for api.md api = dict() for _, operator in operators.items(): for c in operator.categories: if c not in api: api[c] = [operator] else: api[c].append(operator) # api.md # filename = os.path.join(opts.script_dir, '..','doc', 'markdown', 'api.md') filename = common.get_markdown_file(opts, 'api') if common.can_create_filename(opts, filename): with common.open_utf8(opts, filename) as fout: fout.write('# General API\n\n') fout.write('- [Memory function](memory.md)\n') fout.write('- [Float16 related functions](fp16.md)\n') fout.write('- [Defines provided by NSIMD](defines.md)\n') fout.write('- [NSIMD pack and related functions](pack.md)\n\n') fout.write('- [NSIMD C++20 concepts](concepts.md)\n\n') fout.write('# SIMD operators\n') for c, ops in api.items(): if len(ops) == 0: continue fout.write('\n## {}\n\n'.format(c.title)) for op in ops: Full_name = op.full_name[0].upper() + op.full_name[1:] fout.write('- [{} ({})](api_{}.md)\n'.format( Full_name, op.name, common.to_filename(op.name))) # helper to get list of function signatures def to_string(var): sigs = [var] if type(var) == str or not hasattr(var, '__iter__') \ else list(var) for i in range(0, len(sigs)): sigs[i] = re.sub('[ \n\t\r]+', ' ', sigs[i]) return '\n'.join(sigs) # Operators (one file per operator) # dirname = os.path.join(opts.script_dir, '..','doc', 'markdown') dirname = common.get_markdown_dir(opts) common.mkdir_p(dirname) for op_name, operator in operators.items(): # Skip non-matching doc if opts.match and not opts.match.match(op_name): continue # filename = os.path.join(dirname, 'api_{}.md'.format(common.to_filename( # operator.name))) filename = common.get_markdown_api_file(opts, operator.name) if not common.can_create_filename(opts, filename): continue Full_name = operator.full_name[0].upper() + operator.full_name[1:] with common.open_utf8(opts, filename) as fout: fout.write('# {}\n\n'.format(Full_name)) fout.write('## Description\n\n') fout.write(operator.desc) fout.write('\n\n## C base API (generic)\n\n') fout.write('```c\n') fout.write(to_string(operator.get_generic_signature('c_base'))) fout.write('\n```\n\n') fout.write('\n\n## C advanced API (generic, requires C11)\n\n') fout.write('```c\n') fout.write(to_string(operator.get_generic_signature('c_adv'))) fout.write('\n```\n\n') fout.write('## C++ base API (generic)\n\n') fout.write('```c++\n') fout.write(to_string(operator.get_generic_signature('cxx_base'))) fout.write('\n```\n\n') fout.write('## C++ advanced API\n\n') fout.write('```c++\n') fout.write(to_string(operator.get_generic_signature('cxx_adv'). \ values())) fout.write('\n```\n\n') fout.write('## C base API (architecture specifics)') for simd_ext in opts.simd: fout.write('\n\n### {}\n\n'.format(simd_ext.upper())) fout.write('```c\n') for typ in operator.types: fout.write(operator.get_signature(typ, 'c_base', simd_ext)) fout.write(';\n') fout.write('```') fout.write('\n\n## C++ base API (architecture specifics)') for simd_ext in opts.simd: fout.write('\n\n### {}\n\n'.format(simd_ext.upper())) fout.write('```c\n') for typ in operator.types: fout.write( operator.get_signature(typ, 'cxx_base', simd_ext)) fout.write(';\n') fout.write('```')
def gen_doc(opts): sys.stdout.write('-- Generating doc for each function\n') # Build tree for api.md api = dict() for _, operator in operators.items(): for c in operator.categories: if c not in api: api[c] = [operator] else: api[c].append(operator) # helper to construct filename for operator # def to_filename(op_name): # valid = string.ascii_letters + string.digits # ret = '' # for c in op_name: # ret += '-' if c not in valid else c # return ret # api.md # filename = os.path.join(opts.script_dir, '..','doc', 'markdown', 'api.md') filename = common.get_markdown_file(opts, 'api') if common.can_create_filename(opts, filename): with common.open_utf8(opts, filename) as fout: fout.write('# API\n') for c, ops in api.items(): if len(ops) == 0: continue fout.write('\n## {}\n\n'.format(c.title)) for op in ops: Full_name = op.full_name[0].upper() + op.full_name[1:] fout.write('- [{} ({})](api_{}.md)\n'.format( Full_name, op.name, common.to_filename(op.name))) # helper to get list of function signatures def to_string(var): sigs = [var] if type(var) == str or not hasattr(var, '__iter__') \ else list(var) for i in range(0, len(sigs)): sigs[i] = re.sub('[ \n\t\r]+', ' ', sigs[i]) return '\n'.join(sigs) # Operators (one file per operator) # dirname = os.path.join(opts.script_dir, '..','doc', 'markdown') dirname = common.get_markdown_dir(opts) common.mkdir_p(dirname) for op_name, operator in operators.items(): # Skip non-matching doc if opts.match and not opts.match.match(op_name): continue # filename = os.path.join(dirname, 'api_{}.md'.format(common.to_filename( # operator.name))) filename = common.get_markdown_api_file(opts, operator.name) if not common.can_create_filename(opts, filename): continue Full_name = operator.full_name[0].upper() + operator.full_name[1:] with common.open_utf8(opts, filename) as fout: fout.write('# {}\n\n'.format(Full_name)) fout.write('## Description\n\n') fout.write(operator.desc) fout.write('\n\n## C base API (generic)\n\n') fout.write('```c\n') fout.write(to_string(operator.get_generic_signature('c_base'))) fout.write('\n```\n\n') fout.write('## C++ base API (generic)\n\n') fout.write('```c++\n') fout.write(to_string(operator.get_generic_signature('cxx_base'))) fout.write('\n```\n\n') fout.write('## C++ advanced API\n\n') fout.write('```c++\n') fout.write(to_string(operator.get_generic_signature('cxx_adv'). \ values())) fout.write('\n```\n\n') fout.write('## C base API (architecture specifics)') for simd_ext in opts.simd: fout.write('\n\n### {}\n\n'.format(simd_ext.upper())) fout.write('```c\n') for typ in operator.types: fout.write(operator.get_signature(typ, 'c_base', simd_ext)) fout.write(';\n') fout.write('```') fout.write('\n\n## C++ base API (architecture specifics)') for simd_ext in opts.simd: fout.write('\n\n### {}\n\n'.format(simd_ext.upper())) fout.write('```c\n') for typ in operator.types: fout.write( operator.get_signature(typ, 'cxx_base', simd_ext)) fout.write(';\n') fout.write('```')