diff --git a/llvm/lib/Target/ARM/ARMTargetTransformInfo.cpp b/llvm/lib/Target/ARM/ARMTargetTransformInfo.cpp index 932ec2d46daf..aaec3107aece 100644 --- a/llvm/lib/Target/ARM/ARMTargetTransformInfo.cpp +++ b/llvm/lib/Target/ARM/ARMTargetTransformInfo.cpp @@ -47,6 +47,21 @@ int ARMTTIImpl::getIntImmCost(const APInt &Imm, Type *Ty) { return 3; } +int ARMTTIImpl::getIntImmCost(unsigned Opcode, unsigned Idx, const APInt &Imm, + Type *Ty) { + // Division by a constant can be turned into multiplication, but only if we + // know it's constant. So it's not so much that the immediate is cheap (it's + // not), but that the alternative is worse. + // FIXME: this is probably unneeded with GlobalISel. + if ((Opcode == Instruction::SDiv || Opcode == Instruction::UDiv || + Opcode == Instruction::SRem || Opcode == Instruction::URem) && + Idx == 1) + return 0; + + return getIntImmCost(Imm, Ty); +} + + int ARMTTIImpl::getCastInstrCost(unsigned Opcode, Type *Dst, Type *Src) { int ISD = TLI->InstructionOpcodeToISD(Opcode); assert(ISD && "Invalid opcode"); diff --git a/llvm/lib/Target/ARM/ARMTargetTransformInfo.h b/llvm/lib/Target/ARM/ARMTargetTransformInfo.h index 0fe964f36de4..e07174eb40be 100644 --- a/llvm/lib/Target/ARM/ARMTargetTransformInfo.h +++ b/llvm/lib/Target/ARM/ARMTargetTransformInfo.h @@ -64,9 +64,7 @@ public: using BaseT::getIntImmCost; int getIntImmCost(const APInt &Imm, Type *Ty); - int getIntImmCost(unsigned Opcode, unsigned Idx, const APInt &Imm, Type *Ty) { - return getIntImmCost(Imm, Ty); - } + int getIntImmCost(unsigned Opcode, unsigned Idx, const APInt &Imm, Type *Ty); /// @} diff --git a/llvm/test/Transforms/ConstantHoisting/ARM/bad-cases.ll b/llvm/test/Transforms/ConstantHoisting/ARM/bad-cases.ll index 3602eb9f3fd2..8fa78e3d69b4 100644 --- a/llvm/test/Transforms/ConstantHoisting/ARM/bad-cases.ll +++ b/llvm/test/Transforms/ConstantHoisting/ARM/bad-cases.ll @@ -45,3 +45,48 @@ bb2: default: ret void } + +; We don't want to convert constant divides because the benefit from converting +; them to a mul in the backend is larget than constant materialization savings. +define void @signed_const_division(i32 %in1, i32 %in2, i32* %addr) { +; CHECK-LABEL: @signed_const_division +; CHECK: %res1 = sdiv i32 %l1, 1000000000 +; CHECK: %res2 = srem i32 %l2, 1000000000 +entry: + br label %loop + +loop: + %l1 = phi i32 [%res1, %loop], [%in1, %entry] + %l2 = phi i32 [%res2, %loop], [%in2, %entry] + %res1 = sdiv i32 %l1, 1000000000 + store volatile i32 %res1, i32* %addr + %res2 = srem i32 %l2, 1000000000 + store volatile i32 %res2, i32* %addr + %again = icmp eq i32 %res1, %res2 + br i1 %again, label %loop, label %end + +end: + ret void +} + +define void @unsigned_const_division(i32 %in1, i32 %in2, i32* %addr) { +; CHECK-LABEL: @unsigned_const_division +; CHECK: %res1 = udiv i32 %l1, 1000000000 +; CHECK: %res2 = urem i32 %l2, 1000000000 + +entry: + br label %loop + +loop: + %l1 = phi i32 [%res1, %loop], [%in1, %entry] + %l2 = phi i32 [%res2, %loop], [%in2, %entry] + %res1 = udiv i32 %l1, 1000000000 + store volatile i32 %res1, i32* %addr + %res2 = urem i32 %l2, 1000000000 + store volatile i32 %res2, i32* %addr + %again = icmp eq i32 %res1, %res2 + br i1 %again, label %loop, label %end + +end: + ret void +}