Functions for low-level arithmetic

I was wondering if there were any way to get access to the the sorts of assembly instructions like unsigned multiply of UInt64 * UInt64 producing UInt128 (for 64-bit platforms), or UInt32 * UInt32 producing UInt64 (for 32-bit platforms),
or UInt64 * UInt64 + UInt64 producing UInt128 (which also cannot cause an overflow).

These sorts of instructions are very useful for writing basic arithmetic packages efficiently, without having to resort to assembly language.

http://llvm.org/docs/LangRef.html#add-instruction

I’m looking for multiplication, not plain addition, although for addition, you really want to be able to have
i64 + i64 -> i64, carry bit, and i64 + i64 + carry -> i64, carry

From the LLVM documentation, it seems that they don’t support the low level instructions, which surprises me a bit:
“If a full product (e.g. i32 * i32 → i64) is needed, the operands should be sign-extended or zero-extended as appropriate to the width of the full product.”

Also, I was asking about if these operations were accessible from Julia - I don’t know how you’d go about inserting LLVM IR into a Julia program.

http://docs.julialang.org/en/stable/stdlib/c/#llvm-interface

Thanks, but that doesn’t seem to help, since the low-level instructions I’m looking for don’t seem to be present in the LLVM IR.

The mul instruction in LLVM LLVM Language Reference Manual — LLVM 18.0.0git documentation has the following note:

If a full product (e.g. i32 * i32 → i64) is needed, the operands should be sign-extended or zero-extended as appropriate to the width of the full product.

So the first thing to test is if the intel llvm backend correctly detects this pattern:

%a = zext i32 %0 to i64;
%b = zext i32 %0 to i64;
%res = mul i64 %a, %b;
ret i64 %res;

If the backend does not correctly detect the pattern you can either fix that in LLVM or use inline assembly in the LLVM IR LLVM Language Reference Manual — LLVM 18.0.0git documentation.

3 Likes