forked from llvm-mirror/llvm
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
One half of the shifts obviously needed conditional selection based on whether the shift amount is more than 32-bits, but leaving the other half as the natural shift isn't acceptable either: it's undefined behaviour to shift a 32-bit value by more than 31. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@287149 91177308-0d34-0410-b5e6-96231b3b80d8
- Loading branch information
1 parent
4146fdb
commit 9769d9a
Showing
2 changed files
with
90 additions
and
17 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
; RUN: llc -mtriple=arm-eabi %s -o - | FileCheck %s | ||
|
||
define i64 @test_shl(i64 %val, i64 %amt) { | ||
; CHECK-LABEL: test_shl: | ||
; First calculate the hi part when the shift amount is small enough that it | ||
; contains components from both halves. It'll be returned in r1 so that's a | ||
; reasonable place for it to end up. | ||
; CHECK: rsb [[REVERSE_SHIFT:.*]], r2, #32 | ||
; CHECK: lsr [[TMP:.*]], r0, [[REVERSE_SHIFT]] | ||
; CHECK: orr r1, [[TMP]], r1, lsl r2 | ||
|
||
; Check whether the shift was in fact small (< 32 bits). | ||
; CHECK: sub [[EXTRA_SHIFT:.*]], r2, #32 | ||
; CHECK: cmp [[EXTRA_SHIFT]], #0 | ||
|
||
; If not, the high part of the answer is just the low part shifted by the | ||
; excess. | ||
; CHECK: lslge r1, r0, [[EXTRA_SHIFT]] | ||
|
||
; The low part is either a direct shift (1st inst) or 0. We can reuse the same | ||
; NZCV. | ||
; CHECK: lsl r0, r0, r2 | ||
; CHECK: movge r0, #0 | ||
|
||
%res = shl i64 %val, %amt | ||
ret i64 %res | ||
} | ||
|
||
; Explanation for lshr is pretty much the reverse of shl. | ||
define i64 @test_lshr(i64 %val, i64 %amt) { | ||
; CHECK-LABEL: test_lshr: | ||
; CHECK: lsr r0, r0, r2 | ||
; CHECK: rsb [[REVERSE_SHIFT:.*]], r2, #32 | ||
; CHECK: orr r0, r0, r1, lsl [[REVERSE_SHIFT]] | ||
; CHECK: sub [[EXTRA_SHIFT:.*]], r2, #32 | ||
; CHECK: cmp [[EXTRA_SHIFT]], #0 | ||
; CHECK: lsrge r0, r1, [[EXTRA_SHIFT]] | ||
; CHECK: lsr r1, r1, r2 | ||
; CHECK: movge r1, #0 | ||
%res = lshr i64 %val, %amt | ||
ret i64 %res | ||
} | ||
|
||
; One minor difference for ashr: the high bits must be "hi >> 31" if the shift | ||
; amount is large to get the right sign bit. | ||
define i64 @test_ashr(i64 %val, i64 %amt) { | ||
; CHECK-LABEL: test_ashr: | ||
; CHECK: sub [[EXTRA_SHIFT:.*]], r2, #32 | ||
; CHECK: asr [[HI_TMP:.*]], r1, r2 | ||
; CHECK: lsr r0, r0, r2 | ||
; CHECK: rsb [[REVERSE_SHIFT:.*]], r2, #32 | ||
; CHECK: cmp [[EXTRA_SHIFT]], #0 | ||
; CHECK: orr r0, r0, r1, lsl [[REVERSE_SHIFT]] | ||
; CHECK: asrge [[HI_TMP]], r1, #31 | ||
; CHECK: asrge r0, r1, [[EXTRA_SHIFT]] | ||
; CHECK: mov r1, [[HI_TMP]] | ||
%res = ashr i64 %val, %amt | ||
ret i64 %res | ||
} |