# Add/sub with carry; widening multiply

I've been playing around with llvm lately and I was wondering something about the bitcode instructions for basic arithmetic. Is there any plan to provide instructions that perform widening multiply, or add with carry? It might be written as:

mulw i32 %lhs %rhs -> i64 ; widening multiply
addc i32 %lhs, i32 %rhs, i1 %c -> i33 ; add with carry

Alternatively, would something like following get reduced to a single multiply and two stores on arch's that support wide multiplies, like x86-32 and ARM?

define void @mulw(i32* hidest, i32* lodest, i32 lhs, i32 rhs) {
%0 = sext i32 %lhs to i64
%1 = sext i32 %rhs to i64
%2 = mul i64 %0 %1
%3 = trunc i64 %2 to i32
%4 = lshr i64 %2, 32
%5 = truc i64 %4 to i32
store i32 %3, i32* %lodest
store i32 %5, i32* %hidest
ret void
}

Another alternative could rely on multiple return values to return both the low and high words and/or carry bit separately.
%0, %1 = subc i32 %lhs, i32 %rhs, i1 %borrow -> i32, i1 ; subtract including borrow, returning result and borrow flag
%0, %1 = adc i32 %lhs, i32 %rhs, i1 %carry -> i32, i1 ; add with carry, returning result and carry

Has anything like this been considered in the past?

Thanks,
-Jonathan Brandmeyer

Jonathan,

I've been playing around with llvm lately and I was wondering something about the bitcode instructions for basic arithmetic. Is there any plan to provide instructions that perform widening multiply, or add with carry? It might be written as:

mulw i32 %lhs %rhs -> i64 ; widening multiply
addc i32 %lhs, i32 %rhs, i1 %c -> i33 ; add with carry

You would need 2 mulw instructions: signed and unsigned. Those
two functions would be useful.

addw can be easily split into several instructions that compute
the result and carry/overflow separately. Than you can add that
carry using plain add. For details, see:
Henry S. Warren: Hacker's Delight, A. Wesley 2002.

Cheers,

This kind of thing is done by the code generators.

Ciao,

Duncan.

I've been playing around with llvm lately and I was wondering something about the bitcode instructions for basic arithmetic. Is there any plan to provide instructions that perform widening multiply, or add with carry?

Nope, there is no need: see below,

Alternatively, would something like following get reduced to a single multiply and two stores on arch's that support wide multiplies, like x86-32 and ARM?

Yes, it already does. Here's a compilable example:

define void @mulw(i32* %hidest, i32* %lodest, i32 %lhs, i32 %rhs) {
entry:
sext i32 %lhs to i64
sext i32 %rhs to i64
mul i64 %0, %1
trunc i64 %2 to i32
lshr i64 %2, 32
trunc i64 %4 to i32
store i32 %3, i32* %lodest
store i32 %5, i32* %hidest
ret void
}

on x86-32, I get one multiply: llvm-as < t.ll | llc -march=x86

_mulw:
movl 12(%esp), %eax
imull 16(%esp)
movl 8(%esp), %ecx
movl %eax, (%ecx)
movl 4(%esp), %eax
movl %edx, (%eax)
ret

ppc32 requires two, because the ISA doesn't have a high and low multiply: llvm-as < t.ll | llc -march=ppc32

_mulw:
mullw r2, r5, r6
mulhw r5, r5, r6
stw r2, 0(r4)
stw r5, 0(r3)
blr

arm only requires one: llvm-as < t.ll | llc -march=arm
_mulw:
smull r3, r2, r2, r3
str r3, [r1]
str r2, [r0]
bx lr

etc.

Right now we support up to i64, but we plan to support beyond i64 to arbitrary sizes in the future. Right now we do have partial (but incomplete) support for i128. For example:

define void @mulw(i128* %lhs, i128* %rhs, i128* %dst) {
entry:
%Res = add i128 %LHS, %RHS
store i128 %Res, i128* %dst
ret void
}

compiles to: llvm-as < t.ll | llc -march=ppc32

_mulw:
lwz r2, 0(r4)
lwz r6, 4(r4)
lwz r7, 8(r4)
lwz r4, 12(r4)
lwz r8, 0(r3)
lwz r9, 4(r3)
lwz r10, 8(r3)
lwz r3, 12(r3)