[AArch64] Fix miscompile of sdiv-by-power-of-2.

When the constant divisor was larger than 32bits, then the optimized code
generated for the AArch64 backend would emit the wrong code, because the shift
was defined as a shift of a 32bit constant '(1<<Lg2(divisor))' and we would
loose the upper 32bits.

This fixes rdar://problem/18678801.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@219934 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Juergen Ributzka 2014-10-16 16:41:15 +00:00
parent 3b72ec5083
commit c40dab2069
3 changed files with 17 additions and 5 deletions

View File

@ -4515,9 +4515,8 @@ bool AArch64FastISel::selectSDiv(const Instruction *I) {
return true;
}
unsigned Pow2MinusOne = (1 << Lg2) - 1;
unsigned AddReg = emitAddSub_ri(/*UseAdd=*/true, VT, Src0Reg,
/*IsKill=*/false, Pow2MinusOne);
int64_t Pow2MinusOne = (1ULL << Lg2) - 1;
unsigned AddReg = emitAdd_ri_(VT, Src0Reg, /*IsKill=*/false, Pow2MinusOne);
if (!AddReg)
return false;

View File

@ -6822,7 +6822,7 @@ AArch64TargetLowering::BuildSDIVPow2(SDNode *N, const APInt &Divisor,
SDValue N0 = N->getOperand(0);
unsigned Lg2 = Divisor.countTrailingZeros();
SDValue Zero = DAG.getConstant(0, VT);
SDValue Pow2MinusOne = DAG.getConstant((1 << Lg2) - 1, VT);
SDValue Pow2MinusOne = DAG.getConstant((1ULL << Lg2) - 1, VT);
// Add (N0 < 0) ? Pow2 - 1 : 0;
SDValue CCVal;

View File

@ -1,4 +1,5 @@
; RUN: llc -mtriple=arm64-linux-gnu -o - %s | FileCheck %s
; RUN: llc -mtriple=arm64-linux-gnu -fast-isel=0 -verify-machineinstrs < %s | FileCheck %s
; RUN: llc -mtriple=arm64-linux-gnu -fast-isel=1 -verify-machineinstrs < %s | FileCheck %s
define i32 @test1(i32 %x) {
; CHECK-LABEL: test1
@ -59,3 +60,15 @@ define i64 @test6(i64 %x) {
%div = sdiv i64 %x, 64
ret i64 %div
}
define i64 @test7(i64 %x) {
; CHECK-LABEL: test7
; CHECK: orr [[REG:x[0-9]+]], xzr, #0xffffffffffff
; CHECK: add x8, x0, [[REG]]
; CHECK: cmp x0, #0
; CHECK: csel x8, x8, x0, lt
; CHECK: asr x0, x8, #48
%div = sdiv i64 %x, 281474976710656
ret i64 %div
}