:+1::tada: First off, thanks for taking the time to contribute! :tada::+1:
The following is a set of guidelines for contributing to SSE2NEON, hosted on GitHub. These are mostly guidelines, not rules. Use your best judgment, and feel free to propose changes to this document in a pull request.
This project uses GitHub Issues to track ongoing development, discuss project plans, and keep track of bugs. Be sure to search for existing issues before you create another one.
Visit our Issues page on GitHub to search and submit.
The new intrinsic conversion should be added in the sse2neon.h
file, and it should be placed in the correct classification with the alphabetical order. The classification can be referenced from Intel Intrinsics Guide.
Classification: SSE
, SSE2
, SSE3
, SSSE3
, SSE4.1
, SSE4.2
We welcome all contributions from corporate, acaddemic and individual developers. However, there are a number of fundamental ground rules that you must adhere to in order to participate. These rules are outlined as follows:
Software requirement: clang-format version 12 or later.
Use the command $ clang-format -i *.[ch]
to enforce a consistent coding style.
There are some general rules.
foo
and Foo
. Similarly, avoid foobar
and foo_bar
. The potential for confusion is considerable.l
, 1
and I
look quite similar. A variable named l
is particularly bad because it looks so much like the constant 1
.In general, global names (including enums) should have a common prefix (SSE2NEON_
for macros and enum constants; _sse2neon_
for functions) identifying the module that they belong with. Globals may alternatively be grouped in a global structure. Typedeffed names often have _t
appended to their name.
Avoid using names that might conflict with other names used in standard libraries. There may be more library code included in some systems than you need. Your program could also be extended in the future.
This coding style is a variation of the K&R style. Some general principles: honor tradition, but accept progress; be consistent; embrace the latest C standards; embrace modern compilers, their static analysis capabilities and sanitizers.
Use 4 spaces rather than tabs.
All lines should generally be within 80 characters. Wrap long lines. There are some good reasons behind this:
Multi-line comments shall have the opening and closing characters in a separate line, with the lines containing the content prefixed by a space and the *
characters for alignment, e.g.,
Use multi-line comments for more elaborative descriptions or before more significant logical block of code.
Single-line comments shall be written in C89 style:
Leave two spaces between the statement and the inline comment.
Use one space after the conditional or loop keyword, no spaces around their brackets, and one space before the opening curly bracket.
Functions (their declarations or calls), sizeof
operator or similar macros shall not have a space after their name/keyword or around the brackets, e.g.,
Use brackets to avoid ambiguity and with operators such as sizeof
, but otherwise avoid redundant or excessive brackets.
Declarations shall be on the same line, e.g.,
Typedef structures rather than pointers. Note that structures can be kept opaque if they are not dereferenced outside the translation unit where they are defined. Pointers can be typedefed only if there is a very compelling reason.
New types may be suffixed with _t
. Structure name, when used within the translation unit, may be omitted, e.g.:
Embrace C99 structure initialization where reasonable, e.g.,
Embrace C99 array initialization, especially for the state machines, e.g.,
Try to make the control flow easy to follow. Avoid long convoluted logic expressions; try to split them where possible (into inline functions, separate if-statements, etc).
The control structure keyword and the expression in the brackets should be separated by a single space. The opening curly bracket shall be in the same line, also separated by a single space. Example:
Do not add inner spaces around the brackets. There should be one space after the semicolon when for
has expressions:
Avoid:
Consider:
However, do not make logic more convoluted.
if
statementsCurly brackets and spacing follow the K&R style:
Simple and succinct one-line if-statements may omit curly brackets:
However, do prefer curly brackets with multi-line or more complex statements. If one branch uses curly brackets, then all other branches shall use the curly brackets too.
Wrap long conditions to the if-statement indentation adding extra 4 spaces:
else
Avoid:
Consider:
switch
statementsSwitch statements should have the case
blocks at the same indentation level, e.g.:
If the case bock does not break, then it is strongly recommended to add a comment containing "fallthrough" to indicate it. Modern compilers can also be configured to require such comment (see gcc -Wimplicit-fallthrough
).
The opening and closing curly brackets shall also be in the separate lines (K&R style).
Do not use old style K&R style C definitions.
Objects are often "simulated" by the C programmers with a struct
and its "public API". To enforce the information hiding principle, it is a good idea to define the structure in the source file (translation unit) and provide only the declaration in the header. For example, obj.c
:
With an example obj.h
:
Such structuring will prevent direct access of the obj_t
members outside the obj.c
source file. The implementation (of such "class" or "module") may be large and abstracted within separate source files. In such case, consider separating structures and "methods" into separate headers (think of different visibility), for example obj_impl.h
(private) and obj.h
(public).
Consider crypto_impl.h
:
And crypto.h
(public API):
Use unsigned
for general iterators; use size_t
for general sizes; use ssize_t
to return a size which may include an error. Of course, consider possible overflows.
Avoid using uint8_t
or uint16_t
or other sub-word types for general iterators and similar cases, unless programming for micro-controllers or other constrained environments.
C has rather peculiar type promotion rules and unnecessary use of sub-word types might contribute to a bug once in a while.
Do not assume x86 or little-endian architecture. Use endian conversion functions for operating the on-disk and on-the-wire structures or other cases where it is appropriate.
long
or unsigned long
. Use int64_t
or uint64_t
for the 8-byte integers.char
is signed; for example, on Arm it is unsigned.Use:
Do not use:
Do not assume unaligned access is safe. It is not safe on Arm, POWER, and various other architectures. Moreover, even on x86 unaligned access is slower.
Unless programming for micro-controllers or exotic CPU architectures, focus on the common denominator of the modern CPU architectures, avoiding the very maximum portability which can make the code unnecessarily cumbersome.
Some examples:
sizeof(int) == 4
since it is the case on all modern mainstream architectures. PDP-11 era is long gone.1U
instead of UINT32_C(1)
or (uint32_t) 1
is also fine.NULL
is matching (uintptr_t) 0
and it is fair to memset()
structures with zero. Non-zero NULL
is for retro computing.