From cc7052343e5e955d4e2f48885c06360f9003390a Mon Sep 17 00:00:00 2001 From: Bob Wilson Date: Fri, 15 Nov 2013 19:09:27 +0000 Subject: [PATCH] Avoid illegal integer promotion in fastisel Stop folding constant adds into GEP when the type size doesn't match. Otherwise, the adds' operands are effectively being promoted, changing the conditions of an overflow. Results are different when: sext(a) + sext(b) != sext(a + b) Problem originally found on x86-64, but also fixed issues with ARM and PPC, which used similar code. Patch by Duncan Exon Smith! git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@194840 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/llvm/CodeGen/FastISel.h | 9 +++++ lib/CodeGen/SelectionDAG/FastISel.cpp | 15 ++++++++ lib/Target/ARM/ARMFastISel.cpp | 9 +---- lib/Target/PowerPC/PPCFastISel.cpp | 9 +---- lib/Target/X86/X86FastISel.cpp | 9 +---- .../ARM/fastisel-gep-promote-before-add.ll | 18 +++++++++ .../fastisel-gep-promote-before-add.ll | 17 +++++++++ .../X86/fastisel-gep-promote-before-add.ll | 37 +++++++++++++++++++ 8 files changed, 102 insertions(+), 21 deletions(-) create mode 100644 test/CodeGen/ARM/fastisel-gep-promote-before-add.ll create mode 100644 test/CodeGen/PowerPC/fastisel-gep-promote-before-add.ll create mode 100644 test/CodeGen/X86/fastisel-gep-promote-before-add.ll diff --git a/include/llvm/CodeGen/FastISel.h b/include/llvm/CodeGen/FastISel.h index 00634745347..1e0ef6b545e 100644 --- a/include/llvm/CodeGen/FastISel.h +++ b/include/llvm/CodeGen/FastISel.h @@ -358,6 +358,15 @@ protected: return 0; } + /// \brief Check if \c Add is an add that can be safely folded into \c GEP. + /// + /// \c Add can be folded into \c GEP if: + /// - \c Add is an add, + /// - \c Add's size matches \c GEP's, + /// - \c Add is in the same basic block as \c GEP, and + /// - \c Add has a constant operand. + bool canFoldAddIntoGEP(const User *GEP, const Value *Add); + private: bool SelectBinaryOp(const User *I, unsigned ISDOpcode); diff --git a/lib/CodeGen/SelectionDAG/FastISel.cpp b/lib/CodeGen/SelectionDAG/FastISel.cpp index fb798c1f09b..a6f746140dd 100644 --- a/lib/CodeGen/SelectionDAG/FastISel.cpp +++ b/lib/CodeGen/SelectionDAG/FastISel.cpp @@ -1571,4 +1571,19 @@ bool FastISel::tryToFoldLoad(const LoadInst *LI, const Instruction *FoldInst) { return tryToFoldLoadIntoMI(User, RI.getOperandNo(), LI); } +bool FastISel::canFoldAddIntoGEP(const User *GEP, const Value *Add) { + // Must be an add. + if (!isa(Add)) + return false; + // Type size needs to match. + if (TD.getTypeSizeInBits(GEP->getType()) != + TD.getTypeSizeInBits(Add->getType())) + return false; + // Must be in the same basic block. + if (isa(Add) && + FuncInfo.MBBMap[cast(Add)->getParent()] != FuncInfo.MBB) + return false; + // Must have a constant operand. + return isa(cast(Add)->getOperand(1)); +} diff --git a/lib/Target/ARM/ARMFastISel.cpp b/lib/Target/ARM/ARMFastISel.cpp index f3a74c7109e..a4004f32db3 100644 --- a/lib/Target/ARM/ARMFastISel.cpp +++ b/lib/Target/ARM/ARMFastISel.cpp @@ -900,13 +900,8 @@ bool ARMFastISel::ARMComputeAddress(const Value *Obj, Address &Addr) { TmpOffset += CI->getSExtValue() * S; break; } - if (isa(Op) && - (!isa(Op) || - FuncInfo.MBBMap[cast(Op)->getParent()] - == FuncInfo.MBB) && - isa(cast(Op)->getOperand(1))) { - // An add (in the same block) with a constant operand. Fold the - // constant. + if (canFoldAddIntoGEP(U, Op)) { + // A compatible add with a constant operand. Fold the constant. ConstantInt *CI = cast(cast(Op)->getOperand(1)); TmpOffset += CI->getSExtValue() * S; diff --git a/lib/Target/PowerPC/PPCFastISel.cpp b/lib/Target/PowerPC/PPCFastISel.cpp index 4f8e6c1a101..09117e7ded4 100644 --- a/lib/Target/PowerPC/PPCFastISel.cpp +++ b/lib/Target/PowerPC/PPCFastISel.cpp @@ -336,13 +336,8 @@ bool PPCFastISel::PPCComputeAddress(const Value *Obj, Address &Addr) { TmpOffset += CI->getSExtValue() * S; break; } - if (isa(Op) && - (!isa(Op) || - FuncInfo.MBBMap[cast(Op)->getParent()] - == FuncInfo.MBB) && - isa(cast(Op)->getOperand(1))) { - // An add (in the same block) with a constant operand. Fold the - // constant. + if (canFoldAddIntoGEP(U, Op)) { + // A compatible add with a constant operand. Fold the constant. ConstantInt *CI = cast(cast(Op)->getOperand(1)); TmpOffset += CI->getSExtValue() * S; diff --git a/lib/Target/X86/X86FastISel.cpp b/lib/Target/X86/X86FastISel.cpp index 928dea91b4f..97f96ab72c2 100644 --- a/lib/Target/X86/X86FastISel.cpp +++ b/lib/Target/X86/X86FastISel.cpp @@ -561,13 +561,8 @@ redo_gep: Disp += CI->getSExtValue() * S; break; } - if (isa(Op) && - (!isa(Op) || - FuncInfo.MBBMap[cast(Op)->getParent()] - == FuncInfo.MBB) && - isa(cast(Op)->getOperand(1))) { - // An add (in the same block) with a constant operand. Fold the - // constant. + if (canFoldAddIntoGEP(U, Op)) { + // A compatible add with a constant operand. Fold the constant. ConstantInt *CI = cast(cast(Op)->getOperand(1)); Disp += CI->getSExtValue() * S; diff --git a/test/CodeGen/ARM/fastisel-gep-promote-before-add.ll b/test/CodeGen/ARM/fastisel-gep-promote-before-add.ll new file mode 100644 index 00000000000..a32ab6d0931 --- /dev/null +++ b/test/CodeGen/ARM/fastisel-gep-promote-before-add.ll @@ -0,0 +1,18 @@ +; fastisel should not fold add with non-pointer bitwidth +; sext(a) + sext(b) != sext(a + b) +; RUN: llc -mtriple=armv7-apple-ios %s -O0 -o - | FileCheck %s + +define zeroext i8 @gep_promotion(i8* %ptr) nounwind uwtable ssp { +entry: + %ptr.addr = alloca i8*, align 8 + %add = add i8 64, 64 ; 0x40 + 0x40 + %0 = load i8** %ptr.addr, align 8 + + ; CHECK-LABEL: _gep_promotion: + ; CHECK: ldrb {{r[0-9]+}}, {{\[r[0-9]+\]}} + %arrayidx = getelementptr inbounds i8* %0, i8 %add + + %1 = load i8* %arrayidx, align 1 + ret i8 %1 +} + diff --git a/test/CodeGen/PowerPC/fastisel-gep-promote-before-add.ll b/test/CodeGen/PowerPC/fastisel-gep-promote-before-add.ll new file mode 100644 index 00000000000..4bcacf00974 --- /dev/null +++ b/test/CodeGen/PowerPC/fastisel-gep-promote-before-add.ll @@ -0,0 +1,17 @@ +; fastisel should not fold add with non-pointer bitwidth +; sext(a) + sext(b) != sext(a + b) +; RUN: llc -mtriple=powerpc64-unknown-freebsd10.0 %s -O0 -o - | FileCheck %s + +define zeroext i8 @gep_promotion(i8* %ptr) nounwind uwtable ssp { +entry: + %ptr.addr = alloca i8*, align 8 + %add = add i8 64, 64 ; 0x40 + 0x40 + %0 = load i8** %ptr.addr, align 8 + + ; CHECK-LABEL: gep_promotion: + ; CHECK: lbz {{[0-9]+}}, 0({{.*}}) + %arrayidx = getelementptr inbounds i8* %0, i8 %add + + %1 = load i8* %arrayidx, align 1 + ret i8 %1 +} diff --git a/test/CodeGen/X86/fastisel-gep-promote-before-add.ll b/test/CodeGen/X86/fastisel-gep-promote-before-add.ll new file mode 100644 index 00000000000..f87a34c4abd --- /dev/null +++ b/test/CodeGen/X86/fastisel-gep-promote-before-add.ll @@ -0,0 +1,37 @@ +; fastisel should not fold add with non-pointer bitwidth +; sext(a) + sext(b) != sext(a + b) +; RUN: llc -mtriple=x86_64-apple-darwin %s -O0 -o - | FileCheck %s + +define zeroext i8 @gep_promotion(i8* %ptr) nounwind uwtable ssp { +entry: + %ptr.addr = alloca i8*, align 8 + %add = add i8 64, 64 ; 0x40 + 0x40 + %0 = load i8** %ptr.addr, align 8 + + ; CHECK-LABEL: _gep_promotion: + ; CHECK: movzbl ({{.*}}) + %arrayidx = getelementptr inbounds i8* %0, i8 %add + + %1 = load i8* %arrayidx, align 1 + ret i8 %1 +} + +define zeroext i8 @gep_promotion_nonconst(i8 %i, i8* %ptr) nounwind uwtable ssp { +entry: + %i.addr = alloca i8, align 4 + %ptr.addr = alloca i8*, align 8 + store i8 %i, i8* %i.addr, align 4 + store i8* %ptr, i8** %ptr.addr, align 8 + %0 = load i8* %i.addr, align 4 + ; CHECK-LABEL: _gep_promotion_nonconst: + ; CHECK: movzbl ({{.*}}) + %xor = xor i8 %0, -128 ; %0 ^ 0x80 + %add = add i8 %xor, -127 ; %xor + 0x81 + %1 = load i8** %ptr.addr, align 8 + + %arrayidx = getelementptr inbounds i8* %1, i8 %add + + %2 = load i8* %arrayidx, align 1 + ret i8 %2 +} +