Ufunc codegen refactor

Big refactor in the code-generation for numpy ufuncs. Note: this is not about vectorize, but about code generated when a numpy ufunc is found in a jitted function.

Basically removed lots of duplicated code. Also isolated the portions of code that handle iteration over operands from the code inner function that is applied for each element.

The iteration portion is now a single function that supports any input arity (although a single output is currently supported). The inner operation is defined by a "kernel", that is just a class that handles that kernel specific.

The idea is preventing details of a given operation to add complex configuration to a common function handling all the ufuncs (look at the old code for generating binary-ufuncs and how division added lots of complexity).

This should ease the addition of support for new ufuncs, specially those that differ in logic quite a bit from the currently supported ones (logical operators come to mind).
They are not. That's not a problem as the helper is either used for an argument (read only) or as an output (write only). For read only, it is simpler to keep the value around. Ideally, the alloca would be only needed if a store is actually done, but performing the alloca  in store_data is not possible (or too complex) as the active basic block is likely to have changed.

The use of a stack variable for the output to implement store_data is there to make things easier, as otherwise reading the result value would involve phi nodes and make everything a bit more complex. The optimizer seems to handle really well that kind of stores as well.