Closed
Description
For this function (which is essentially *(ptr << 2)
) llvm generates the following assembly:
define noundef i32 @shift_read2(ptr noundef nonnull %packed) unnamed_addr #1 personality ptr @rust_eh_personality {
start:
%n.i.i = ptrtoint ptr %packed to i64
%offset.i.i.i = mul i64 %n.i.i, 3
%0 = getelementptr i8, ptr %packed, i64 %offset.i.i.i
%1 = icmp ne ptr %0, null
tail call void @llvm.assume(i1 %1)
%2 = load i32, ptr %0, align 4 ; , !noundef !10
ret i32 %2
}
shift_read2: # @shift_read2
lea rax, [rdi + 2*rdi]
mov eax, dword ptr [rdi + rax]
ret
This looks suboptimal, since a single instruction can be generated instead:
shift_read2: # @shift_read2
mov eax, dword ptr [4*rdi]
ret
Moreover if you change the function slightly (replace 3 by 7 which is equivalent to replacing *(ptr << 2)
by *(ptr << 3)
) the generated assembly is better:
define noundef i32 @shift_read3(ptr noundef nonnull %packed) unnamed_addr #1 personality ptr @rust_eh_personality {
start:
%n.i.i = ptrtoint ptr %packed to i64
%offset.i.i.i = mul i64 %n.i.i, 7
%0 = getelementptr i8, ptr %packed, i64 %offset.i.i.i
%1 = icmp ne ptr %0, null
tail call void @llvm.assume(i1 %1)
%2 = load i32, ptr %0, align 4 ; , !noundef !10
ret i32 %2
}
shift_read3: # @shift_read3
mov eax, dword ptr [8*rdi]
ret