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.
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.
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