diff --git a/llvm/include/llvm/Analysis/TargetLibraryInfo.def b/llvm/include/llvm/Analysis/TargetLibraryInfo.def --- a/llvm/include/llvm/Analysis/TargetLibraryInfo.def +++ b/llvm/include/llvm/Analysis/TargetLibraryInfo.def @@ -1024,6 +1024,11 @@ TLI_DEFINE_STRING_INTERNAL("ctermid") TLI_DEFINE_SIG_INTERNAL(Ptr, Ptr) +/// div_t div(int, int); +TLI_DEFINE_ENUM_INTERNAL(div) +TLI_DEFINE_STRING_INTERNAL("div") +TLI_DEFINE_SIG_INTERNAL(/* Checked manually. */) + /// int execl(const char *path, const char *arg, ...); TLI_DEFINE_ENUM_INTERNAL(execl) TLI_DEFINE_STRING_INTERNAL("execl") @@ -1507,6 +1512,11 @@ TLI_DEFINE_STRING_INTERNAL("htons") TLI_DEFINE_SIG_INTERNAL(Int16, Int16) +/// imaxdiv_t imaxdiv(intmax_t, intmax_t); +TLI_DEFINE_ENUM_INTERNAL(imaxdiv) +TLI_DEFINE_STRING_INTERNAL("imaxdiv") +TLI_DEFINE_SIG_INTERNAL(/* Checked manually. */) + /// int iprintf(const char *format, ...); TLI_DEFINE_ENUM_INTERNAL(iprintf) TLI_DEFINE_STRING_INTERNAL("iprintf") @@ -1547,11 +1557,21 @@ TLI_DEFINE_STRING_INTERNAL("ldexpl") TLI_DEFINE_SIG_INTERNAL(LDbl, LDbl, Int) +/// ldiv_t ldiv(long, long); +TLI_DEFINE_ENUM_INTERNAL(ldiv) +TLI_DEFINE_STRING_INTERNAL("ldiv") +TLI_DEFINE_SIG_INTERNAL(/* Checked manually. */) + /// long long int llabs(long long int j); TLI_DEFINE_ENUM_INTERNAL(llabs) TLI_DEFINE_STRING_INTERNAL("llabs") TLI_DEFINE_SIG_INTERNAL(LLong, LLong) +/// lldiv_t lldiv(long long, long long); +TLI_DEFINE_ENUM_INTERNAL(lldiv) +TLI_DEFINE_STRING_INTERNAL("lldiv") +TLI_DEFINE_SIG_INTERNAL(/* Checked manually. */) + /// double log(double x); TLI_DEFINE_ENUM_INTERNAL(log) TLI_DEFINE_STRING_INTERNAL("log") diff --git a/llvm/include/llvm/Transforms/Utils/SimplifyLibCalls.h b/llvm/include/llvm/Transforms/Utils/SimplifyLibCalls.h --- a/llvm/include/llvm/Transforms/Utils/SimplifyLibCalls.h +++ b/llvm/include/llvm/Transforms/Utils/SimplifyLibCalls.h @@ -202,6 +202,7 @@ IRBuilderBase &B); // Integer Library Call Optimizations + Value *optimizeDiv(CallInst *CI, IRBuilderBase &B); Value *optimizeFFS(CallInst *CI, IRBuilderBase &B); Value *optimizeFls(CallInst *CI, IRBuilderBase &B); Value *optimizeAbs(CallInst *CI, IRBuilderBase &B); diff --git a/llvm/lib/Analysis/TargetLibraryInfo.cpp b/llvm/lib/Analysis/TargetLibraryInfo.cpp --- a/llvm/lib/Analysis/TargetLibraryInfo.cpp +++ b/llvm/lib/Analysis/TargetLibraryInfo.cpp @@ -996,6 +996,67 @@ llvm_unreachable("Invalid type"); } +// Return true if FTy is a valid internal prototype corresponding to +// function F of the C div family (div, ldiv, lldiv, and imaxdiv). +static bool isValidProtoForDivFunc(const FunctionType &FTy, LibFunc F, + const Module &M) { + unsigned NumParams = FTy.getNumParams(); + Type *RetTy = FTy.getReturnType(); + + if (NumParams == 3) { + // Return true if the void function takes three arguments where + // the first one is a pointer to the return type and the remaining + // two are integers with the same precision. + if (!RetTy->isVoidTy()) + return false; + + Type *ParamTy = FTy.getParamType(0); + if (!ParamTy->isPointerTy()) + return false; + + ParamTy = FTy.getParamType(1); + return ParamTy->isIntegerTy() && ParamTy == FTy.getParamType(2); + } + + if (NumParams != 2) + return false; + + Type *ParamTy = FTy.getParamType(0); + if (!ParamTy->isIntegerTy() || ParamTy != FTy.getParamType(1)) + // Fail if both arguments don't have the same integer type. + return false; + + unsigned ParamBits = ParamTy->getIntegerBitWidth(); + + if (RetTy->isIntegerTy()) + // Return true if the return type is an integer twice the precision + // of the argument type(s). E.g., div on x86_64. + return RetTy->getIntegerBitWidth() == 2 * ParamBits; + + if (auto *Ty = dyn_cast(RetTy)) { + // Return true if the return type is a two-element array with the same + // precision as the argument type(s). E.g., div on riscv32 or ldiv on + // riscv64. + return (Ty->getNumElements() == 2 && + Ty->getElementType()->isIntegerTy(ParamBits)); + } + + if (auto *Ty = dyn_cast(RetTy)) { + if (Ty->getNumElements() == 1) { + // Return true if the return type is a struct with a single member + // twice the precision of the argument type(s). E.g., div on mips64. + Type *ElTy = Ty->getTypeAtIndex(0U); + return ElTy->getIntegerBitWidth() == 2 * ParamBits; + } + + return (Ty->getNumElements() == 2 && + Ty->getElementType(0) == ParamTy && + Ty->getElementType(1) == ParamTy); + } + + return false; +} + bool TargetLibraryInfoImpl::isValidProtoForLibFunc(const FunctionType &FTy, LibFunc F, const Module &M) const { @@ -1022,6 +1083,13 @@ return false; } + // Special handling for the internal form of the {,imax,l,ll}div functions. + case LibFunc_div: + case LibFunc_ldiv: + case LibFunc_lldiv: + case LibFunc_imaxdiv: + return isValidProtoForDivFunc(FTy, F, M); + // Special handling for the sincospi functions that return either // a struct or vector: case LibFunc_sincospi_stret: diff --git a/llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp b/llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp --- a/llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp +++ b/llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp @@ -2632,6 +2632,116 @@ // Integer Library Call Optimizations //===----------------------------------------------------------------------===// +// Helper to create the return value or sequence for the div functions. +// The result can be returned either as an integer, struct, or stored +// into consecutive members of the struct pointed to by the first "sret" +// argument, depending on the calling convention. +static Value *createDivRetVal(CallInst *CI, uint64_t Quot, uint64_t Rem, + IRBuilderBase &B) { + Type *RetTy = CI->getType(); + bool VoidRet = RetTy->isVoidTy(); + + Type *ArgTy = CI->getOperand(VoidRet ? 1 : 0)->getType(); + unsigned ArgBits = ArgTy->getIntegerBitWidth(); + + if (RetTy->isIntegerTy(2 * ArgBits)) { + uint64_t Res; + if (CI->getModule()->getDataLayout().isBigEndian()) + Res = Rem << ArgBits | Quot; + else + Res = Quot << ArgBits | Rem; + + return ConstantInt::get(RetTy, Res); + } + + Constant *QuotC = ConstantInt::get(ArgTy, Quot); + Constant *RemC = ConstantInt::get(ArgTy, Rem); + + if (VoidRet) { + // As a paranoia check verify the function is declared to return its + // value through the object pointed by the first argumenmt. + Function *Callee = CI->getCalledFunction(); + if (!Callee->hasStructRetAttr()) + return nullptr; + + // Store the result in consecutive members of the returned struct, + // assuming they are laid out in the usual order: { T quot, rem; }. + RetTy = Callee->getParamStructRetType(0); + StructType *StructTy = dyn_cast(RetTy); + Value *RetPtr = CI->getOperand(0); + Value *RetVal = ConstantStruct::get(StructTy, {QuotC, RemC}); + return B.CreateStore(RetVal, RetPtr); + } + + if (auto *ArrayTy = dyn_cast(RetTy)) { + if (ArrayTy->getNumElements() != 2) + return nullptr; + return ConstantArray::get(ArrayTy, {QuotC, RemC}); + } + + if (auto *StructTy = dyn_cast(RetTy)) { + unsigned NElts = StructTy->getNumElements(); + if (NElts == 1) { + uint64_t Res; + if (CI->getModule()->getDataLayout().isBigEndian()) + Res = Rem << ArgBits | Quot; + else + Res = Quot << ArgBits | Rem; + + Type *ElTy = StructTy->getTypeAtIndex(0U); + Constant *ResC = ConstantInt::get(ElTy, Res); + return ConstantStruct::get(StructTy, {ResC}); + } + + if (NElts != 2) + return nullptr; + + // Assume div_t members are laid out in order: { T quot, rem; }. + return ConstantStruct::get(StructTy, {QuotC, RemC}); + } + + if (isa(RetTy)) + return ConstantVector::get({QuotC, RemC}); + + return nullptr; +} + +// Fold the div, ldiv, lldiv, and imaxdiv C standard functions. +Value *LibCallSimplifier::optimizeDiv(CallInst *CI, IRBuilderBase &B) { + Value *Arg0 = CI->getArgOperand(0); + int Arg0Idx = Arg0->getType()->isPointerTy(); + ConstantInt *NumC = dyn_cast(CI->getArgOperand(Arg0Idx)); + if (!NumC) + // TODO: fold div(X, 1) to { X, 0 } for any X. + return nullptr; + + if (NumC->isZero()) + // Fold div(0, X) to { 0, 0 } for any X. + return createDivRetVal(CI, 0, 0, B); + + ConstantInt *DenC = dyn_cast(CI->getArgOperand(Arg0Idx + 1)); + if (!DenC) + // Bail if the denumerator is not known. + return nullptr; + + if (DenC->isZero()) + // Bail if the denumerator is zero (the result is undefined). + return nullptr; + + int64_t INum = NumC->getSExtValue(); + int64_t IDen = DenC->getSExtValue(); + + unsigned NBits = NumC->getType()->getPrimitiveSizeInBits(); + if (INum == minIntN(NBits) && IDen == -1) + // Bail if the result is not representable. + return nullptr; + + // Assume no integer type has a greater precision than 64 bits. + assert(NBits <= 64); + lldiv_t Res = lldiv(INum, IDen); + return createDivRetVal(CI, Res.quot, Res.rem, B); +} + Value *LibCallSimplifier::optimizeFFS(CallInst *CI, IRBuilderBase &B) { // All variants of ffs return int which need not be 32 bits wide. // ffs{,l,ll}(x) -> x != 0 ? (int)llvm.cttz(x)+1 : 0 @@ -3599,6 +3709,11 @@ if (Value *V = optimizeFloatingPointLibCall(CI, Func, Builder)) return V; switch (Func) { + case LibFunc_div: + case LibFunc_ldiv: + case LibFunc_lldiv: + case LibFunc_imaxdiv: + return optimizeDiv(CI, Builder); case LibFunc_ffs: case LibFunc_ffsl: case LibFunc_ffsll: diff --git a/llvm/test/Transforms/InstCombine/div-1.ll b/llvm/test/Transforms/InstCombine/div-1.ll new file mode 100644 --- /dev/null +++ b/llvm/test/Transforms/InstCombine/div-1.ll @@ -0,0 +1,405 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; RUN: opt < %s -data-layout=E -passes=instcombine -S | FileCheck %s +; RUN: opt < %s -data-layout=e -passes=instcombine -S | FileCheck %s +; +; Verify that calls to the div functions declared to return a struct are +; folded when appropriate. The output must be the same in both big and +; little endian data models. + +%div_t = type { i32, i32 } +%ldiv_t = type { i64, i64 } +%lldiv_t = type { i64, i64 } +%imaxdiv_t = type { i64, i64 } + +; The following declarations are used on the 32-bit targets arc and nvptx. +declare %div_t @div(i32, i32) +declare %ldiv_t @ldiv(i64, i64) + +; On sparcv9 ldiv also returns a struct. +declare %lldiv_t @lldiv(i64, i64) +declare %imaxdiv_t @imaxdiv(i64, i64) + +declare void @sink(%div_t) +declare void @lsink(%ldiv_t) + + +; Verify that div calls with constant arguments are correctly folded. + +define void @fold_div() { +; CHECK-LABEL: @fold_div( +; CHECK-NEXT: call void @sink([[DIV_T:%.*]] { i32 5, i32 0 }) +; CHECK-NEXT: call void @sink([[DIV_T]] { i32 2, i32 -1 }) +; CHECK-NEXT: call void @sink([[DIV_T]] zeroinitializer) +; CHECK-NEXT: call void @sink([[DIV_T]] zeroinitializer) +; CHECK-NEXT: call void @sink([[DIV_T]] { i32 1, i32 0 }) +; CHECK-NEXT: call void @sink([[DIV_T]] zeroinitializer) +; CHECK-NEXT: call void @sink([[DIV_T]] { i32 0, i32 1 }) +; CHECK-NEXT: call void @sink([[DIV_T]] { i32 2, i32 0 }) +; CHECK-NEXT: call void @sink([[DIV_T]] { i32 3, i32 2 }) +; CHECK-NEXT: call void @lsink([[DIV_T]] { i32 -2147483647, i32 0 }) +; CHECK-NEXT: call void @lsink([[DIV_T]] { i32 1073741824, i32 0 }) +; CHECK-NEXT: ret void +; + ; Fold div(-5, -1) to { 5, 0 }. + %div_m5_m1 = call %div_t @div(i32 -5, i32 -1) + call void @sink(%div_t %div_m5_m1) + + ; Fold div(-5, -2) to { 2, -1 }. + %div_m5_m2 = call %div_t @div(i32 -5, i32 -2) + call void @sink(%div_t %div_m5_m2) + + ; Fold div(0, -1) to { 0, 0 }. + %div_0_m1 = call %div_t @div(i32 0, i32 -1) + call void @sink(%div_t %div_0_m1) + + ; Fold div(0, 1) to { 0, 0 }. + %div_0_1 = call %div_t @div(i32 0, i32 1) + call void @sink(%div_t %div_0_1) + + ; Fold div(1, 1) to { 1, 0 }. + %div_1_1 = call %div_t @div(i32 1, i32 1) + call void @sink(%div_t %div_1_1) + + ; Fold div(0, 2) to { 0, 0 }. + %div_0_2 = call %div_t @div(i32 0, i32 2) + call void @sink(%div_t %div_0_2) + + ; Fold div(1, 2) to { 0, 1 }. + %div_1_2 = call %div_t @div(i32 1, i32 2) + call void @sink(%div_t %div_1_2) + + ; Fold div(2, 1) to { 2, 0 }. + %div_2_1 = call %div_t @div(i32 2, i32 1) + call void @sink(%div_t %div_2_1) + + ; Fold div(11, 3) to { 3, 2 }. + %div_11_3 = call %div_t @div(i32 11, i32 3) + call void @sink(%div_t %div_11_3) + + ; Fold div(INT_MAX, -1) to { INT_MIN, 0 }. + %div_imax_m1 = call %div_t @div(i32 2147483647, i32 -1) + call void @lsink(%div_t %div_imax_m1) + + ; Fold div(INT_MIN, -2) to { 1073741824, 0 }. + %div_imin_m2 = call %div_t @div(i32 -2147483648, i32 -2) + call void @lsink(%div_t %div_imin_m2) + + ret void +} + + +; Verify that erroneous div calls don't abort (although they could +; be folded to avoid the undefined behavior at runtime they're not). + +define void @call_div() { +; CHECK-LABEL: @call_div( +; CHECK-NEXT: [[DIV_0_0:%.*]] = call [[DIV_T:%.*]] @div(i32 1, i32 0) +; CHECK-NEXT: call void @sink([[DIV_T]] [[DIV_0_0]]) +; CHECK-NEXT: [[DIV_IMIN_M1:%.*]] = call [[DIV_T]] @div(i32 -2147483648, i32 -1) +; CHECK-NEXT: call void @sink([[DIV_T]] [[DIV_IMIN_M1]]) +; CHECK-NEXT: ret void +; + ; Do not fold div(1, 0) and the library generate SIGFPE. + %div_0_0 = call %div_t @div(i32 1, i32 0) + call void @sink(%div_t %div_0_0) + + ; Do not fold div(INT_MIN, -1), + %div_imin_m1 = call %div_t @div(i32 -2147483648, i32 -1) + call void @sink(%div_t %div_imin_m1) + + ret void +} + + +; Verify that ldiv calls with constant arguments are correctly folded. + +define void @fold_ldiv() { +; CHECK-LABEL: @fold_ldiv( +; CHECK-NEXT: call void @lsink([[LDIV_T:%.*]] { i64 5, i64 0 }) +; CHECK-NEXT: call void @lsink([[LDIV_T]] { i64 2, i64 -1 }) +; CHECK-NEXT: call void @lsink([[LDIV_T]] zeroinitializer) +; CHECK-NEXT: call void @lsink([[LDIV_T]] zeroinitializer) +; CHECK-NEXT: call void @lsink([[LDIV_T]] { i64 1, i64 0 }) +; CHECK-NEXT: call void @lsink([[LDIV_T]] zeroinitializer) +; CHECK-NEXT: call void @lsink([[LDIV_T]] { i64 0, i64 1 }) +; CHECK-NEXT: call void @lsink([[LDIV_T]] { i64 2, i64 0 }) +; CHECK-NEXT: call void @lsink([[LDIV_T]] { i64 3, i64 2 }) +; CHECK-NEXT: call void @lsink([[LDIV_T]] { i64 2147483648, i64 0 }) +; CHECK-NEXT: call void @lsink([[LDIV_T]] { i64 9223372036854775807, i64 0 }) +; CHECK-NEXT: call void @lsink([[LDIV_T]] { i64 4611686018427387904, i64 0 }) +; CHECK-NEXT: call void @lsink([[LDIV_T]] { i64 -9223372036854775807, i64 0 }) +; CHECK-NEXT: ret void +; + ; Fold div(-5, -1) to { 5, 0 }. + %div_m5_m1 = call %ldiv_t @ldiv(i64 -5, i64 -1) + call void @lsink(%ldiv_t %div_m5_m1) + + ; Fold div(-5, -2) to { 2, -1 }. + %div_m5_m2 = call %ldiv_t @ldiv(i64 -5, i64 -2) + call void @lsink(%ldiv_t %div_m5_m2) + + ; Fold div(0, -1) to { 0, 0 }. + %div_0_m1 = call %ldiv_t @ldiv(i64 0, i64 -1) + call void @lsink(%ldiv_t %div_0_m1) + + ; Fold div(0, 1) to { 0, 0 }. + %div_0_1 = call %ldiv_t @ldiv(i64 0, i64 1) + call void @lsink(%ldiv_t %div_0_1) + + ; Fold div(1, 1) to { 1, 0 }. + %div_1_1 = call %ldiv_t @ldiv(i64 1, i64 1) + call void @lsink(%ldiv_t %div_1_1) + + ; Fold div(0, 2) to { 0, 0 }. + %div_0_2 = call %ldiv_t @ldiv(i64 0, i64 2) + call void @lsink(%ldiv_t %div_0_2) + + ; Fold div(1, 2) to { 0, 1 }. + %div_1_2 = call %ldiv_t @ldiv(i64 1, i64 2) + call void @lsink(%ldiv_t %div_1_2) + + ; Fold div(2, 1) to { 2, 0 }. + %div_2_1 = call %ldiv_t @ldiv(i64 2, i64 1) + call void @lsink(%ldiv_t %div_2_1) + + ; Fold div(11, 3) to { 3, 2 }. + %div_11_3 = call %ldiv_t @ldiv(i64 11, i64 3) + call void @lsink(%ldiv_t %div_11_3) + + ; Fold ldiv(INT_MIN, -1) to { INT_MAX, 0 }. + %div_imin_m1 = call %ldiv_t @ldiv(i64 -2147483648, i64 -1) + call void @lsink(%ldiv_t %div_imin_m1) + + ; Fold ldiv(LONG_MIN + 1, -1) to { }. + %div_iminp1_m1 = call %ldiv_t @ldiv(i64 -9223372036854775807, i64 -1) + call void @lsink(%ldiv_t %div_iminp1_m1) + + ; Fold ldiv(LONG_MIN, -2) to { 4611686018427387904, 0 }. + %div_imin_m2 = call %ldiv_t @ldiv(i64 -9223372036854775808, i64 -2) + call void @lsink(%ldiv_t %div_imin_m2) + + ; Fold ldiv(LONG_MAX, -1) to { LONG_MIN, 0 }. + %div_imax_m1 = call %ldiv_t @ldiv(i64 9223372036854775807, i64 -1) + call void @lsink(%ldiv_t %div_imax_m1) + + ret void +} + + +; Verify that erroneous ldiv calls don't abort (although they could +; be folded to avoid the undefined behavior at runtime they're not). + +define void @call_ldiv() { +; CHECK-LABEL: @call_ldiv( +; CHECK-NEXT: [[DIV_0_0:%.*]] = call [[LDIV_T:%.*]] @ldiv(i64 1, i64 0) +; CHECK-NEXT: call void @lsink([[LDIV_T]] [[DIV_0_0]]) +; CHECK-NEXT: [[DIV_IMIN_M1:%.*]] = call [[LDIV_T]] @ldiv(i64 -9223372036854775808, i64 -1) +; CHECK-NEXT: call void @lsink([[LDIV_T]] [[DIV_IMIN_M1]]) +; CHECK-NEXT: ret void +; + ; Do not fold ldiv(1, 0) and the library generate SIGFPE. + %div_0_0 = call %ldiv_t @ldiv(i64 1, i64 0) + call void @lsink(%ldiv_t %div_0_0) + + ; Do not fold ldiv(LONG_MIN, -1). + %div_imin_m1 = call %ldiv_t @ldiv(i64 -9223372036854775808, i64 -1) + call void @lsink(%ldiv_t %div_imin_m1) + + ret void +} + + +; Verify that lldiv calls with constant arguments are correctly folded. + +define void @fold_lldiv() { +; CHECK-LABEL: @fold_lldiv( +; CHECK-NEXT: call void @lsink([[LLDIV_T:%.*]] { i64 5, i64 0 }) +; CHECK-NEXT: call void @lsink([[LLDIV_T]] { i64 2, i64 -1 }) +; CHECK-NEXT: call void @lsink([[LLDIV_T]] zeroinitializer) +; CHECK-NEXT: call void @lsink([[LLDIV_T]] zeroinitializer) +; CHECK-NEXT: call void @lsink([[LLDIV_T]] { i64 1, i64 0 }) +; CHECK-NEXT: call void @lsink([[LLDIV_T]] zeroinitializer) +; CHECK-NEXT: call void @lsink([[LLDIV_T]] { i64 0, i64 1 }) +; CHECK-NEXT: call void @lsink([[LLDIV_T]] { i64 2, i64 0 }) +; CHECK-NEXT: call void @lsink([[LLDIV_T]] { i64 3, i64 2 }) +; CHECK-NEXT: call void @lsink([[LLDIV_T]] { i64 2147483648, i64 0 }) +; CHECK-NEXT: call void @lsink([[LLDIV_T]] { i64 9223372036854775807, i64 0 }) +; CHECK-NEXT: call void @lsink([[LLDIV_T]] { i64 4611686018427387904, i64 0 }) +; CHECK-NEXT: call void @lsink([[LLDIV_T]] { i64 -9223372036854775807, i64 0 }) +; CHECK-NEXT: ret void +; + ; Fold lldiv(-5, -1) to { 5, 0 }. + %div_m5_m1 = call %lldiv_t @lldiv(i64 -5, i64 -1) + call void @lsink(%lldiv_t %div_m5_m1) + + ; Fold lldiv(-5, -2) to { 2, -1 }. + %div_m5_m2 = call %lldiv_t @lldiv(i64 -5, i64 -2) + call void @lsink(%lldiv_t %div_m5_m2) + + ; Fold lldiv(0, -1) to { 0, 0 }. + %div_0_m1 = call %lldiv_t @lldiv(i64 0, i64 -1) + call void @lsink(%lldiv_t %div_0_m1) + + ; Fold lldiv(0, 1) to { 0, 0 }. + %div_0_1 = call %lldiv_t @lldiv(i64 0, i64 1) + call void @lsink(%lldiv_t %div_0_1) + + ; Fold lldiv(1, 1) to { 1, 0 }. + %div_1_1 = call %lldiv_t @lldiv(i64 1, i64 1) + call void @lsink(%lldiv_t %div_1_1) + + ; Fold lldiv(0, 2) to { 0, 0 }. + %div_0_2 = call %lldiv_t @lldiv(i64 0, i64 2) + call void @lsink(%lldiv_t %div_0_2) + + ; Fold lldiv(1, 2) to { 0, 1 }. + %div_1_2 = call %lldiv_t @lldiv(i64 1, i64 2) + call void @lsink(%lldiv_t %div_1_2) + + ; Fold lldiv(2, 1) to { 2, 0 }. + %div_2_1 = call %lldiv_t @lldiv(i64 2, i64 1) + call void @lsink(%lldiv_t %div_2_1) + + ; Fold lldiv(11, 3) to { 3, 2 }. + %div_11_3 = call %lldiv_t @lldiv(i64 11, i64 3) + call void @lsink(%lldiv_t %div_11_3) + + ; Fold lldiv(INT_MIN, -1) to { INT_MAX, 0 }. + %div_imin_m1 = call %lldiv_t @lldiv(i64 -2147483648, i64 -1) + call void @lsink(%lldiv_t %div_imin_m1) + + ; Fold lldiv(LLONG_MIN + 1, -1) to { }. + %div_iminp1_m1 = call %lldiv_t @lldiv(i64 -9223372036854775807, i64 -1) + call void @lsink(%lldiv_t %div_iminp1_m1) + + ; Fold lldiv(LLONG_MIN, -2) to { 4611686018427387904, 0 }. + %div_imin_m2 = call %lldiv_t @lldiv(i64 -9223372036854775808, i64 -2) + call void @lsink(%lldiv_t %div_imin_m2) + + ; Fold lldiv(LLONG_MAX, -1) to { LLONG_MIN, 0 }. + %div_imax_m1 = call %lldiv_t @lldiv(i64 9223372036854775807, i64 -1) + call void @lsink(%lldiv_t %div_imax_m1) + + ret void +} + + +; Verify that erroneous lldiv calls don't abort (although they could +; be folded to avoid the undefined behavior at runtime they're not). + +define void @call_lldiv() { +; CHECK-LABEL: @call_lldiv( +; CHECK-NEXT: [[DIV_0_0:%.*]] = call [[LLDIV_T:%.*]] @lldiv(i64 1, i64 0) +; CHECK-NEXT: call void @lsink([[LLDIV_T]] [[DIV_0_0]]) +; CHECK-NEXT: [[DIV_IMIN_M1:%.*]] = call [[LLDIV_T]] @lldiv(i64 -9223372036854775808, i64 -1) +; CHECK-NEXT: call void @lsink([[LLDIV_T]] [[DIV_IMIN_M1]]) +; CHECK-NEXT: ret void +; + ; Do not fold lldiv(1, 0) and the library generate SIGFPE. + %div_0_0 = call %lldiv_t @lldiv(i64 1, i64 0) + call void @lsink(%lldiv_t %div_0_0) + + ; Do not fold lldiv(LONG_MIN, -1). + %div_imin_m1 = call %lldiv_t @lldiv(i64 -9223372036854775808, i64 -1) + call void @lsink(%lldiv_t %div_imin_m1) + + ret void +} + + +; Verify that imaxdiv calls with constant arguments are correctly folded. + +define void @fold_imaxdiv() { +; CHECK-LABEL: @fold_imaxdiv( +; CHECK-NEXT: call void @lsink([[IMAXDIV_T:%.*]] { i64 5, i64 0 }) +; CHECK-NEXT: call void @lsink([[IMAXDIV_T]] { i64 2, i64 -1 }) +; CHECK-NEXT: call void @lsink([[IMAXDIV_T]] zeroinitializer) +; CHECK-NEXT: call void @lsink([[IMAXDIV_T]] zeroinitializer) +; CHECK-NEXT: call void @lsink([[IMAXDIV_T]] { i64 1, i64 0 }) +; CHECK-NEXT: call void @lsink([[IMAXDIV_T]] zeroinitializer) +; CHECK-NEXT: call void @lsink([[IMAXDIV_T]] { i64 0, i64 1 }) +; CHECK-NEXT: call void @lsink([[IMAXDIV_T]] { i64 2, i64 0 }) +; CHECK-NEXT: call void @lsink([[IMAXDIV_T]] { i64 3, i64 2 }) +; CHECK-NEXT: call void @lsink([[IMAXDIV_T]] { i64 2147483648, i64 0 }) +; CHECK-NEXT: call void @lsink([[IMAXDIV_T]] { i64 4611686018427387904, i64 0 }) +; CHECK-NEXT: call void @lsink([[IMAXDIV_T]] { i64 9223372036854775807, i64 0 }) +; CHECK-NEXT: call void @lsink([[IMAXDIV_T]] { i64 -9223372036854775807, i64 0 }) +; CHECK-NEXT: ret void +; + ; Fold imaxdiv(-5, -1) to { 5, 0 }. + %div_m5_m1 = call %imaxdiv_t @imaxdiv(i64 -5, i64 -1) + call void @lsink(%imaxdiv_t %div_m5_m1) + + ; Fold imaxdiv(-5, -2) to { 2, -1 }. + %div_m5_m2 = call %imaxdiv_t @imaxdiv(i64 -5, i64 -2) + call void @lsink(%imaxdiv_t %div_m5_m2) + + ; Fold imaxdiv(0, -1) to { 0, 0 }. + %div_0_m1 = call %imaxdiv_t @imaxdiv(i64 0, i64 -1) + call void @lsink(%imaxdiv_t %div_0_m1) + + ; Fold imaxdiv(0, 1) to { 0, 0 }. + %div_0_1 = call %imaxdiv_t @imaxdiv(i64 0, i64 1) + call void @lsink(%imaxdiv_t %div_0_1) + + ; Fold imaxdiv(1, 1) to { 1, 0 }. + %div_1_1 = call %imaxdiv_t @imaxdiv(i64 1, i64 1) + call void @lsink(%imaxdiv_t %div_1_1) + + ; Fold imaxdiv(0, 2) to { 0, 0 }. + %div_0_2 = call %imaxdiv_t @imaxdiv(i64 0, i64 2) + call void @lsink(%imaxdiv_t %div_0_2) + + ; Fold imaxdiv(1, 2) to { 0, 1 }. + %div_1_2 = call %imaxdiv_t @imaxdiv(i64 1, i64 2) + call void @lsink(%imaxdiv_t %div_1_2) + + ; Fold imaxdiv(2, 1) to { 2, 0 }. + %div_2_1 = call %imaxdiv_t @imaxdiv(i64 2, i64 1) + call void @lsink(%imaxdiv_t %div_2_1) + + ; Fold imaxdiv(11, 3) to { 3, 2 }. + %div_11_3 = call %imaxdiv_t @imaxdiv(i64 11, i64 3) + call void @lsink(%imaxdiv_t %div_11_3) + + ; Fold imaxdiv(INT_MIN, -1) to { INT_MAX, 0 }. + %div_imin_m1 = call %imaxdiv_t @imaxdiv(i64 -2147483648, i64 -1) + call void @lsink(%imaxdiv_t %div_imin_m1) + + ; Fold imaxdiv(INTMAX_MIN, -2) to { 4611686018427387904, 0 }. + %div_imin_m2 = call %imaxdiv_t @imaxdiv(i64 -9223372036854775808, i64 -2) + call void @lsink(%imaxdiv_t %div_imin_m2) + + ; Fold imaxdiv(INTMAX_MIN + 1, -1) to { INTMAX_MAX, 0}. + %div_iminp1_m1 = call %imaxdiv_t @imaxdiv(i64 -9223372036854775807, i64 -1) + call void @lsink(%imaxdiv_t %div_iminp1_m1) + + ; Fold imaxdiv(INTMAX_MAX, -1) to { INTMAX_MIN, 0 }. + %div_imax_m1 = call %imaxdiv_t @imaxdiv(i64 9223372036854775807, i64 -1) + call void @lsink(%imaxdiv_t %div_imax_m1) + + ret void +} + + +; Verify that erroneous imaxdiv calls don't abort (although they could +; be folded to avoid the undefined behavior at runtime, they're not). + +define void @call_imaxdiv() { +; CHECK-LABEL: @call_imaxdiv( +; CHECK-NEXT: [[DIV_0_0:%.*]] = call [[IMAXDIV_T:%.*]] @imaxdiv(i64 1, i64 0) +; CHECK-NEXT: call void @lsink([[IMAXDIV_T]] [[DIV_0_0]]) +; CHECK-NEXT: [[DIV_IMIN_M1:%.*]] = call [[IMAXDIV_T]] @imaxdiv(i64 -9223372036854775808, i64 -1) +; CHECK-NEXT: call void @lsink([[IMAXDIV_T]] [[DIV_IMIN_M1]]) +; CHECK-NEXT: ret void +; + ; Do not fold imaxdiv(1, 0) and the library generate SIGFPE. + %div_0_0 = call %imaxdiv_t @imaxdiv(i64 1, i64 0) + call void @lsink(%imaxdiv_t %div_0_0) + + ; Do not fold imaxdiv(INTMAX_MIN, -1). + %div_imin_m1 = call %imaxdiv_t @imaxdiv(i64 -9223372036854775808, i64 -1) + call void @lsink(%imaxdiv_t %div_imin_m1) + + ret void +} diff --git a/llvm/test/Transforms/InstCombine/div-2.ll b/llvm/test/Transforms/InstCombine/div-2.ll new file mode 100644 --- /dev/null +++ b/llvm/test/Transforms/InstCombine/div-2.ll @@ -0,0 +1,630 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; RUN: opt < %s -data-layout=E -passes=instcombine -S | FileCheck %s +; RUN: opt < %s -data-layout=e -passes=instcombine -S | FileCheck %s +; +; Verify that calls to the div functions declared to return a struct through +; the object pointed to by the first argument are folded when appropriate. +; The output must be the same in both big and little endian data models. + +%div_t = type { i32, i32 } +%ldiv_t = type { i64, i64 } +%lldiv_t = type { i64, i64 } +%imaxdiv_t = type { i64, i64 } + +; The following declarations are emitted on 32-bit targets such as arm, +; i386, mips, or sparc. +declare void @div(%div_t* sret(%div_t), i32, i32) +declare void @ldiv(%ldiv_t* sret(%ldiv_t), i64, i64) +declare void @lldiv(%lldiv_t* sret(%lldiv_t), i64, i64) +declare void @imaxdiv(%imaxdiv_t* sret(%imaxdiv_t), i64, i64) + +declare void @sink(%div_t*) +declare void @lsink(%ldiv_t*) +declare void @llsink(%lldiv_t*) +declare void @imaxsink(%imaxdiv_t*) + + +; Verify that div calls with constant arguments are correctly folded. + +define void @fold_div() { +; CHECK-LABEL: @fold_div( +; CHECK-NEXT: [[PDIV:%.*]] = alloca [[DIV_T:%.*]], align 8 +; CHECK-NEXT: [[PDIV_REPACK:%.*]] = getelementptr inbounds [[DIV_T]], %div_t* [[PDIV]], i64 0, i32 0 +; CHECK-NEXT: store i32 5, i32* [[PDIV_REPACK]], align 8 +; CHECK-NEXT: [[PDIV_REPACK1:%.*]] = getelementptr inbounds [[DIV_T]], %div_t* [[PDIV]], i64 0, i32 1 +; CHECK-NEXT: store i32 0, i32* [[PDIV_REPACK1]], align 4 +; CHECK-NEXT: call void @sink(%div_t* nonnull [[PDIV]]) +; CHECK-NEXT: [[PDIV_REPACK2:%.*]] = getelementptr inbounds [[DIV_T]], %div_t* [[PDIV]], i64 0, i32 0 +; CHECK-NEXT: store i32 2, i32* [[PDIV_REPACK2]], align 8 +; CHECK-NEXT: [[PDIV_REPACK3:%.*]] = getelementptr inbounds [[DIV_T]], %div_t* [[PDIV]], i64 0, i32 1 +; CHECK-NEXT: store i32 -1, i32* [[PDIV_REPACK3]], align 4 +; CHECK-NEXT: call void @sink(%div_t* nonnull [[PDIV]]) +; CHECK-NEXT: [[PDIV_REPACK4:%.*]] = getelementptr inbounds [[DIV_T]], %div_t* [[PDIV]], i64 0, i32 0 +; CHECK-NEXT: store i32 0, i32* [[PDIV_REPACK4]], align 8 +; CHECK-NEXT: [[PDIV_REPACK5:%.*]] = getelementptr inbounds [[DIV_T]], %div_t* [[PDIV]], i64 0, i32 1 +; CHECK-NEXT: store i32 0, i32* [[PDIV_REPACK5]], align 4 +; CHECK-NEXT: call void @sink(%div_t* nonnull [[PDIV]]) +; CHECK-NEXT: [[PDIV_REPACK6:%.*]] = getelementptr inbounds [[DIV_T]], %div_t* [[PDIV]], i64 0, i32 0 +; CHECK-NEXT: store i32 0, i32* [[PDIV_REPACK6]], align 8 +; CHECK-NEXT: [[PDIV_REPACK7:%.*]] = getelementptr inbounds [[DIV_T]], %div_t* [[PDIV]], i64 0, i32 1 +; CHECK-NEXT: store i32 0, i32* [[PDIV_REPACK7]], align 4 +; CHECK-NEXT: call void @sink(%div_t* nonnull [[PDIV]]) +; CHECK-NEXT: [[PDIV_REPACK8:%.*]] = getelementptr inbounds [[DIV_T]], %div_t* [[PDIV]], i64 0, i32 0 +; CHECK-NEXT: store i32 1, i32* [[PDIV_REPACK8]], align 8 +; CHECK-NEXT: [[PDIV_REPACK9:%.*]] = getelementptr inbounds [[DIV_T]], %div_t* [[PDIV]], i64 0, i32 1 +; CHECK-NEXT: store i32 0, i32* [[PDIV_REPACK9]], align 4 +; CHECK-NEXT: call void @sink(%div_t* nonnull [[PDIV]]) +; CHECK-NEXT: [[PDIV_REPACK10:%.*]] = getelementptr inbounds [[DIV_T]], %div_t* [[PDIV]], i64 0, i32 0 +; CHECK-NEXT: store i32 0, i32* [[PDIV_REPACK10]], align 8 +; CHECK-NEXT: [[PDIV_REPACK11:%.*]] = getelementptr inbounds [[DIV_T]], %div_t* [[PDIV]], i64 0, i32 1 +; CHECK-NEXT: store i32 0, i32* [[PDIV_REPACK11]], align 4 +; CHECK-NEXT: call void @sink(%div_t* nonnull [[PDIV]]) +; CHECK-NEXT: [[PDIV_REPACK12:%.*]] = getelementptr inbounds [[DIV_T]], %div_t* [[PDIV]], i64 0, i32 0 +; CHECK-NEXT: store i32 0, i32* [[PDIV_REPACK12]], align 8 +; CHECK-NEXT: [[PDIV_REPACK13:%.*]] = getelementptr inbounds [[DIV_T]], %div_t* [[PDIV]], i64 0, i32 1 +; CHECK-NEXT: store i32 1, i32* [[PDIV_REPACK13]], align 4 +; CHECK-NEXT: call void @sink(%div_t* nonnull [[PDIV]]) +; CHECK-NEXT: [[PDIV_REPACK14:%.*]] = getelementptr inbounds [[DIV_T]], %div_t* [[PDIV]], i64 0, i32 0 +; CHECK-NEXT: store i32 2, i32* [[PDIV_REPACK14]], align 8 +; CHECK-NEXT: [[PDIV_REPACK15:%.*]] = getelementptr inbounds [[DIV_T]], %div_t* [[PDIV]], i64 0, i32 1 +; CHECK-NEXT: store i32 0, i32* [[PDIV_REPACK15]], align 4 +; CHECK-NEXT: call void @sink(%div_t* nonnull [[PDIV]]) +; CHECK-NEXT: [[PDIV_REPACK16:%.*]] = getelementptr inbounds [[DIV_T]], %div_t* [[PDIV]], i64 0, i32 0 +; CHECK-NEXT: store i32 3, i32* [[PDIV_REPACK16]], align 8 +; CHECK-NEXT: [[PDIV_REPACK17:%.*]] = getelementptr inbounds [[DIV_T]], %div_t* [[PDIV]], i64 0, i32 1 +; CHECK-NEXT: store i32 2, i32* [[PDIV_REPACK17]], align 4 +; CHECK-NEXT: call void @sink(%div_t* nonnull [[PDIV]]) +; CHECK-NEXT: [[PDIV_REPACK18:%.*]] = getelementptr inbounds [[DIV_T]], %div_t* [[PDIV]], i64 0, i32 0 +; CHECK-NEXT: store i32 -2147483647, i32* [[PDIV_REPACK18]], align 8 +; CHECK-NEXT: [[PDIV_REPACK19:%.*]] = getelementptr inbounds [[DIV_T]], %div_t* [[PDIV]], i64 0, i32 1 +; CHECK-NEXT: store i32 0, i32* [[PDIV_REPACK19]], align 4 +; CHECK-NEXT: call void @sink(%div_t* nonnull [[PDIV]]) +; CHECK-NEXT: [[PDIV_REPACK20:%.*]] = getelementptr inbounds [[DIV_T]], %div_t* [[PDIV]], i64 0, i32 0 +; CHECK-NEXT: store i32 1073741824, i32* [[PDIV_REPACK20]], align 8 +; CHECK-NEXT: [[PDIV_REPACK21:%.*]] = getelementptr inbounds [[DIV_T]], %div_t* [[PDIV]], i64 0, i32 1 +; CHECK-NEXT: store i32 0, i32* [[PDIV_REPACK21]], align 4 +; CHECK-NEXT: call void @sink(%div_t* nonnull [[PDIV]]) +; CHECK-NEXT: ret void +; + %pdiv = alloca %div_t + + ; Fold div(-5, -1) to { 5, 0 }. + call void @div(%div_t* %pdiv, i32 -5, i32 -1) + call void @sink(%div_t* %pdiv) + + ; Fold div(-5, -2) to { 2, -1 }. + call void @div(%div_t* %pdiv, i32 -5, i32 -2) + call void @sink(%div_t* %pdiv) + + ; Fold div(0, -1) to { 0, 0 }. + call void @div(%div_t* %pdiv, i32 0, i32 -1) + call void @sink(%div_t* %pdiv) + + ; Fold div(0, 1) to { 0, 0 }. + call void @div(%div_t* %pdiv, i32 0, i32 1) + call void @sink(%div_t* %pdiv) + + ; Fold div(1, 1) to { 1, 0 }. + call void @div(%div_t* %pdiv, i32 1, i32 1) + call void @sink(%div_t* %pdiv) + + ; Fold div(0, 2) to { 0, 0 }. + call void @div(%div_t* %pdiv, i32 0, i32 2) + call void @sink(%div_t* %pdiv) + + ; Fold div(1, 2) to { 0, 1 }. + call void @div(%div_t* %pdiv, i32 1, i32 2) + call void @sink(%div_t* %pdiv) + + ; Fold div(2, 1) to { 2, 0 }. + call void @div(%div_t* %pdiv, i32 2, i32 1) + call void @sink(%div_t* %pdiv) + + ; Fold div(11, 3) to { 3, 2 }. + call void @div(%div_t* %pdiv, i32 11, i32 3) + call void @sink(%div_t* %pdiv) + + ; Fold div(INT_MAX, -1) to { INT_MIN, 0 }. + call void @div(%div_t* %pdiv, i32 2147483647, i32 -1) + call void @sink(%div_t* %pdiv) + + ; Fold div(INT_MIN, -2) to { 1073741824, 0 }. + call void @div(%div_t* %pdiv, i32 -2147483648, i32 -2) + call void @sink(%div_t* %pdiv) + + ret void +} + + +; Verify that erroneous div calls don't abort (although they could +; be folded to avoid the undefined behavior at runtime they're not). + +define void @call_div() { +; CHECK-LABEL: @call_div( +; CHECK-NEXT: [[PDIV:%.*]] = alloca [[DIV_T:%.*]], align 8 +; CHECK-NEXT: call void @div(%div_t* nonnull [[PDIV]], i32 1, i32 0) +; CHECK-NEXT: call void @sink(%div_t* nonnull [[PDIV]]) +; CHECK-NEXT: call void @div(%div_t* nonnull [[PDIV]], i32 -2147483648, i32 -1) +; CHECK-NEXT: call void @sink(%div_t* nonnull [[PDIV]]) +; CHECK-NEXT: ret void +; + %pdiv = alloca %div_t + + ; Do not fold div(1, 0) and the library generate SIGFPE. + call void @div(%div_t* %pdiv, i32 1, i32 0) + call void @sink(%div_t* %pdiv) + + ; Do not fold div(INT_MIN, -1), + call void @div(%div_t* %pdiv, i32 -2147483648, i32 -1) + call void @sink(%div_t* %pdiv) + + ret void +} + + +; Verify that ldiv calls with constant arguments are correctly folded. + +define void @fold_ldiv() { +; CHECK-LABEL: @fold_ldiv( +; CHECK-NEXT: [[PDIV:%.*]] = alloca [[LDIV_T:%.*]], align 8 +; CHECK-NEXT: [[PDIV_REPACK:%.*]] = getelementptr inbounds [[LDIV_T]], %ldiv_t* [[PDIV]], i64 0, i32 0 +; CHECK-NEXT: store i64 5, i64* [[PDIV_REPACK]], align 8 +; CHECK-NEXT: [[PDIV_REPACK1:%.*]] = getelementptr inbounds [[LDIV_T]], %ldiv_t* [[PDIV]], i64 0, i32 1 +; CHECK-NEXT: store i64 0, i64* [[PDIV_REPACK1]], align 8 +; CHECK-NEXT: call void @lsink(%ldiv_t* nonnull [[PDIV]]) +; CHECK-NEXT: [[PDIV_REPACK2:%.*]] = getelementptr inbounds [[LDIV_T]], %ldiv_t* [[PDIV]], i64 0, i32 0 +; CHECK-NEXT: store i64 2, i64* [[PDIV_REPACK2]], align 8 +; CHECK-NEXT: [[PDIV_REPACK3:%.*]] = getelementptr inbounds [[LDIV_T]], %ldiv_t* [[PDIV]], i64 0, i32 1 +; CHECK-NEXT: store i64 -1, i64* [[PDIV_REPACK3]], align 8 +; CHECK-NEXT: call void @lsink(%ldiv_t* nonnull [[PDIV]]) +; CHECK-NEXT: [[PDIV_REPACK4:%.*]] = getelementptr inbounds [[LDIV_T]], %ldiv_t* [[PDIV]], i64 0, i32 0 +; CHECK-NEXT: store i64 0, i64* [[PDIV_REPACK4]], align 8 +; CHECK-NEXT: [[PDIV_REPACK5:%.*]] = getelementptr inbounds [[LDIV_T]], %ldiv_t* [[PDIV]], i64 0, i32 1 +; CHECK-NEXT: store i64 0, i64* [[PDIV_REPACK5]], align 8 +; CHECK-NEXT: call void @lsink(%ldiv_t* nonnull [[PDIV]]) +; CHECK-NEXT: [[PDIV_REPACK6:%.*]] = getelementptr inbounds [[LDIV_T]], %ldiv_t* [[PDIV]], i64 0, i32 0 +; CHECK-NEXT: store i64 0, i64* [[PDIV_REPACK6]], align 8 +; CHECK-NEXT: [[PDIV_REPACK7:%.*]] = getelementptr inbounds [[LDIV_T]], %ldiv_t* [[PDIV]], i64 0, i32 1 +; CHECK-NEXT: store i64 0, i64* [[PDIV_REPACK7]], align 8 +; CHECK-NEXT: call void @lsink(%ldiv_t* nonnull [[PDIV]]) +; CHECK-NEXT: [[PDIV_REPACK8:%.*]] = getelementptr inbounds [[LDIV_T]], %ldiv_t* [[PDIV]], i64 0, i32 0 +; CHECK-NEXT: store i64 1, i64* [[PDIV_REPACK8]], align 8 +; CHECK-NEXT: [[PDIV_REPACK9:%.*]] = getelementptr inbounds [[LDIV_T]], %ldiv_t* [[PDIV]], i64 0, i32 1 +; CHECK-NEXT: store i64 0, i64* [[PDIV_REPACK9]], align 8 +; CHECK-NEXT: call void @lsink(%ldiv_t* nonnull [[PDIV]]) +; CHECK-NEXT: [[PDIV_REPACK10:%.*]] = getelementptr inbounds [[LDIV_T]], %ldiv_t* [[PDIV]], i64 0, i32 0 +; CHECK-NEXT: store i64 0, i64* [[PDIV_REPACK10]], align 8 +; CHECK-NEXT: [[PDIV_REPACK11:%.*]] = getelementptr inbounds [[LDIV_T]], %ldiv_t* [[PDIV]], i64 0, i32 1 +; CHECK-NEXT: store i64 0, i64* [[PDIV_REPACK11]], align 8 +; CHECK-NEXT: call void @lsink(%ldiv_t* nonnull [[PDIV]]) +; CHECK-NEXT: [[PDIV_REPACK12:%.*]] = getelementptr inbounds [[LDIV_T]], %ldiv_t* [[PDIV]], i64 0, i32 0 +; CHECK-NEXT: store i64 0, i64* [[PDIV_REPACK12]], align 8 +; CHECK-NEXT: [[PDIV_REPACK13:%.*]] = getelementptr inbounds [[LDIV_T]], %ldiv_t* [[PDIV]], i64 0, i32 1 +; CHECK-NEXT: store i64 1, i64* [[PDIV_REPACK13]], align 8 +; CHECK-NEXT: call void @lsink(%ldiv_t* nonnull [[PDIV]]) +; CHECK-NEXT: [[PDIV_REPACK14:%.*]] = getelementptr inbounds [[LDIV_T]], %ldiv_t* [[PDIV]], i64 0, i32 0 +; CHECK-NEXT: store i64 2, i64* [[PDIV_REPACK14]], align 8 +; CHECK-NEXT: [[PDIV_REPACK15:%.*]] = getelementptr inbounds [[LDIV_T]], %ldiv_t* [[PDIV]], i64 0, i32 1 +; CHECK-NEXT: store i64 0, i64* [[PDIV_REPACK15]], align 8 +; CHECK-NEXT: call void @lsink(%ldiv_t* nonnull [[PDIV]]) +; CHECK-NEXT: [[PDIV_REPACK16:%.*]] = getelementptr inbounds [[LDIV_T]], %ldiv_t* [[PDIV]], i64 0, i32 0 +; CHECK-NEXT: store i64 3, i64* [[PDIV_REPACK16]], align 8 +; CHECK-NEXT: [[PDIV_REPACK17:%.*]] = getelementptr inbounds [[LDIV_T]], %ldiv_t* [[PDIV]], i64 0, i32 1 +; CHECK-NEXT: store i64 2, i64* [[PDIV_REPACK17]], align 8 +; CHECK-NEXT: call void @lsink(%ldiv_t* nonnull [[PDIV]]) +; CHECK-NEXT: [[PDIV_REPACK18:%.*]] = getelementptr inbounds [[LDIV_T]], %ldiv_t* [[PDIV]], i64 0, i32 0 +; CHECK-NEXT: store i64 2147483648, i64* [[PDIV_REPACK18]], align 8 +; CHECK-NEXT: [[PDIV_REPACK19:%.*]] = getelementptr inbounds [[LDIV_T]], %ldiv_t* [[PDIV]], i64 0, i32 1 +; CHECK-NEXT: store i64 0, i64* [[PDIV_REPACK19]], align 8 +; CHECK-NEXT: call void @lsink(%ldiv_t* nonnull [[PDIV]]) +; CHECK-NEXT: [[PDIV_REPACK20:%.*]] = getelementptr inbounds [[LDIV_T]], %ldiv_t* [[PDIV]], i64 0, i32 0 +; CHECK-NEXT: store i64 9223372036854775807, i64* [[PDIV_REPACK20]], align 8 +; CHECK-NEXT: [[PDIV_REPACK21:%.*]] = getelementptr inbounds [[LDIV_T]], %ldiv_t* [[PDIV]], i64 0, i32 1 +; CHECK-NEXT: store i64 0, i64* [[PDIV_REPACK21]], align 8 +; CHECK-NEXT: call void @lsink(%ldiv_t* nonnull [[PDIV]]) +; CHECK-NEXT: [[PDIV_REPACK22:%.*]] = getelementptr inbounds [[LDIV_T]], %ldiv_t* [[PDIV]], i64 0, i32 0 +; CHECK-NEXT: store i64 4611686018427387904, i64* [[PDIV_REPACK22]], align 8 +; CHECK-NEXT: [[PDIV_REPACK23:%.*]] = getelementptr inbounds [[LDIV_T]], %ldiv_t* [[PDIV]], i64 0, i32 1 +; CHECK-NEXT: store i64 0, i64* [[PDIV_REPACK23]], align 8 +; CHECK-NEXT: call void @lsink(%ldiv_t* nonnull [[PDIV]]) +; CHECK-NEXT: [[PDIV_REPACK24:%.*]] = getelementptr inbounds [[LDIV_T]], %ldiv_t* [[PDIV]], i64 0, i32 0 +; CHECK-NEXT: store i64 -9223372036854775807, i64* [[PDIV_REPACK24]], align 8 +; CHECK-NEXT: [[PDIV_REPACK25:%.*]] = getelementptr inbounds [[LDIV_T]], %ldiv_t* [[PDIV]], i64 0, i32 1 +; CHECK-NEXT: store i64 0, i64* [[PDIV_REPACK25]], align 8 +; CHECK-NEXT: call void @lsink(%ldiv_t* nonnull [[PDIV]]) +; CHECK-NEXT: ret void +; + %pdiv = alloca %ldiv_t + + ; Fold ldiv(-5, -1) to { 5, 0 }. + call void @ldiv(%ldiv_t* %pdiv, i64 -5, i64 -1) + call void @lsink(%ldiv_t* %pdiv) + + ; Fold ldiv(-5, -2) to { 2, -1 }. + call void @ldiv(%ldiv_t* %pdiv, i64 -5, i64 -2) + call void @lsink(%ldiv_t* %pdiv) + + ; Fold ldiv(0, -1) to { 0, 0 }. + call void @ldiv(%ldiv_t* %pdiv, i64 0, i64 -1) + call void @lsink(%ldiv_t* %pdiv) + + ; Fold ldiv(0, 1) to { 0, 0 }. + call void @ldiv(%ldiv_t* %pdiv, i64 0, i64 1) + call void @lsink(%ldiv_t* %pdiv) + + ; Fold ldiv(1, 1) to { 1, 0 }. + call void @ldiv(%ldiv_t* %pdiv, i64 1, i64 1) + call void @lsink(%ldiv_t* %pdiv) + + ; Fold ldiv(0, 2) to { 0, 0 }. + call void @ldiv(%ldiv_t* %pdiv, i64 0, i64 2) + call void @lsink(%ldiv_t* %pdiv) + + ; Fold ldiv(1, 2) to { 0, 1 }. + call void @ldiv(%ldiv_t* %pdiv, i64 1, i64 2) + call void @lsink(%ldiv_t* %pdiv) + + ; Fold ldiv(2, 1) to { 2, 0 }. + call void @ldiv(%ldiv_t* %pdiv, i64 2, i64 1) + call void @lsink(%ldiv_t* %pdiv) + + ; Fold ldiv(11, 3) to { 3, 2 }. + call void @ldiv(%ldiv_t* %pdiv, i64 11, i64 3) + call void @lsink(%ldiv_t* %pdiv) + + ; Fold ldiv(INT_MIN, -1) to { INT_MAX, 0 }. + call void @ldiv(%ldiv_t* %pdiv, i64 -2147483648, i64 -1) + call void @lsink(%ldiv_t* %pdiv) + + ; Fold ldiv(LONG_MIN + 1, -1) to { }. + call void @ldiv(%ldiv_t* %pdiv, i64 -9223372036854775807, i64 -1) + call void @lsink(%ldiv_t* %pdiv) + + ; Fold ldiv(LONG_MIN, -2) to { 4611686018427387904, 0 }. + call void @ldiv(%ldiv_t* %pdiv, i64 -9223372036854775808, i64 -2) + call void @lsink(%ldiv_t* %pdiv) + + ; Fold ldiv(LONG_MAX, -1) to { LONG_MIN, 0 }. + call void @ldiv(%ldiv_t* %pdiv, i64 9223372036854775807, i64 -1) + call void @lsink(%ldiv_t* %pdiv) + + ret void +} + + +; Verify that erroneous ldiv calls don't abort (although they could +; be folded to avoid the undefined behavior at runtime they're not). + +define void @call_ldiv() { +; CHECK-LABEL: @call_ldiv( +; CHECK-NEXT: [[PDIV:%.*]] = alloca [[LDIV_T:%.*]], align 8 +; CHECK-NEXT: call void @ldiv(%ldiv_t* nonnull [[PDIV]], i64 1, i64 0) +; CHECK-NEXT: call void @lsink(%ldiv_t* nonnull [[PDIV]]) +; CHECK-NEXT: call void @ldiv(%ldiv_t* nonnull [[PDIV]], i64 -9223372036854775808, i64 -1) +; CHECK-NEXT: call void @lsink(%ldiv_t* nonnull [[PDIV]]) +; CHECK-NEXT: ret void +; + %pdiv = alloca %ldiv_t + + ; Do not fold ldiv(1, 0) and the library generate SIGFPE. + call void @ldiv(%ldiv_t* %pdiv, i64 1, i64 0) + call void @lsink(%ldiv_t* %pdiv) + + ; Do not fold ldiv(LONG_MIN, -1). + call void @ldiv(%ldiv_t* %pdiv, i64 -9223372036854775808, i64 -1) + call void @lsink(%ldiv_t* %pdiv) + + ret void +} + + +; Verify that lldiv calls with constant arguments are correctly folded. + +define void @fold_lldiv() { +; CHECK-LABEL: @fold_lldiv( +; CHECK-NEXT: [[PDIV:%.*]] = alloca [[LLDIV_T:%.*]], align 8 +; CHECK-NEXT: [[PDIV_REPACK:%.*]] = getelementptr inbounds [[LLDIV_T]], %lldiv_t* [[PDIV]], i64 0, i32 0 +; CHECK-NEXT: store i64 5, i64* [[PDIV_REPACK]], align 8 +; CHECK-NEXT: [[PDIV_REPACK1:%.*]] = getelementptr inbounds [[LLDIV_T]], %lldiv_t* [[PDIV]], i64 0, i32 1 +; CHECK-NEXT: store i64 0, i64* [[PDIV_REPACK1]], align 8 +; CHECK-NEXT: call void @llsink(%lldiv_t* nonnull [[PDIV]]) +; CHECK-NEXT: [[PDIV_REPACK2:%.*]] = getelementptr inbounds [[LLDIV_T]], %lldiv_t* [[PDIV]], i64 0, i32 0 +; CHECK-NEXT: store i64 2, i64* [[PDIV_REPACK2]], align 8 +; CHECK-NEXT: [[PDIV_REPACK3:%.*]] = getelementptr inbounds [[LLDIV_T]], %lldiv_t* [[PDIV]], i64 0, i32 1 +; CHECK-NEXT: store i64 -1, i64* [[PDIV_REPACK3]], align 8 +; CHECK-NEXT: call void @llsink(%lldiv_t* nonnull [[PDIV]]) +; CHECK-NEXT: [[PDIV_REPACK4:%.*]] = getelementptr inbounds [[LLDIV_T]], %lldiv_t* [[PDIV]], i64 0, i32 0 +; CHECK-NEXT: store i64 0, i64* [[PDIV_REPACK4]], align 8 +; CHECK-NEXT: [[PDIV_REPACK5:%.*]] = getelementptr inbounds [[LLDIV_T]], %lldiv_t* [[PDIV]], i64 0, i32 1 +; CHECK-NEXT: store i64 0, i64* [[PDIV_REPACK5]], align 8 +; CHECK-NEXT: call void @llsink(%lldiv_t* nonnull [[PDIV]]) +; CHECK-NEXT: [[PDIV_REPACK6:%.*]] = getelementptr inbounds [[LLDIV_T]], %lldiv_t* [[PDIV]], i64 0, i32 0 +; CHECK-NEXT: store i64 0, i64* [[PDIV_REPACK6]], align 8 +; CHECK-NEXT: [[PDIV_REPACK7:%.*]] = getelementptr inbounds [[LLDIV_T]], %lldiv_t* [[PDIV]], i64 0, i32 1 +; CHECK-NEXT: store i64 0, i64* [[PDIV_REPACK7]], align 8 +; CHECK-NEXT: call void @llsink(%lldiv_t* nonnull [[PDIV]]) +; CHECK-NEXT: [[PDIV_REPACK8:%.*]] = getelementptr inbounds [[LLDIV_T]], %lldiv_t* [[PDIV]], i64 0, i32 0 +; CHECK-NEXT: store i64 1, i64* [[PDIV_REPACK8]], align 8 +; CHECK-NEXT: [[PDIV_REPACK9:%.*]] = getelementptr inbounds [[LLDIV_T]], %lldiv_t* [[PDIV]], i64 0, i32 1 +; CHECK-NEXT: store i64 0, i64* [[PDIV_REPACK9]], align 8 +; CHECK-NEXT: call void @llsink(%lldiv_t* nonnull [[PDIV]]) +; CHECK-NEXT: [[PDIV_REPACK10:%.*]] = getelementptr inbounds [[LLDIV_T]], %lldiv_t* [[PDIV]], i64 0, i32 0 +; CHECK-NEXT: store i64 0, i64* [[PDIV_REPACK10]], align 8 +; CHECK-NEXT: [[PDIV_REPACK11:%.*]] = getelementptr inbounds [[LLDIV_T]], %lldiv_t* [[PDIV]], i64 0, i32 1 +; CHECK-NEXT: store i64 0, i64* [[PDIV_REPACK11]], align 8 +; CHECK-NEXT: call void @llsink(%lldiv_t* nonnull [[PDIV]]) +; CHECK-NEXT: [[PDIV_REPACK12:%.*]] = getelementptr inbounds [[LLDIV_T]], %lldiv_t* [[PDIV]], i64 0, i32 0 +; CHECK-NEXT: store i64 0, i64* [[PDIV_REPACK12]], align 8 +; CHECK-NEXT: [[PDIV_REPACK13:%.*]] = getelementptr inbounds [[LLDIV_T]], %lldiv_t* [[PDIV]], i64 0, i32 1 +; CHECK-NEXT: store i64 1, i64* [[PDIV_REPACK13]], align 8 +; CHECK-NEXT: call void @llsink(%lldiv_t* nonnull [[PDIV]]) +; CHECK-NEXT: [[PDIV_REPACK14:%.*]] = getelementptr inbounds [[LLDIV_T]], %lldiv_t* [[PDIV]], i64 0, i32 0 +; CHECK-NEXT: store i64 2, i64* [[PDIV_REPACK14]], align 8 +; CHECK-NEXT: [[PDIV_REPACK15:%.*]] = getelementptr inbounds [[LLDIV_T]], %lldiv_t* [[PDIV]], i64 0, i32 1 +; CHECK-NEXT: store i64 0, i64* [[PDIV_REPACK15]], align 8 +; CHECK-NEXT: call void @llsink(%lldiv_t* nonnull [[PDIV]]) +; CHECK-NEXT: [[PDIV_REPACK16:%.*]] = getelementptr inbounds [[LLDIV_T]], %lldiv_t* [[PDIV]], i64 0, i32 0 +; CHECK-NEXT: store i64 3, i64* [[PDIV_REPACK16]], align 8 +; CHECK-NEXT: [[PDIV_REPACK17:%.*]] = getelementptr inbounds [[LLDIV_T]], %lldiv_t* [[PDIV]], i64 0, i32 1 +; CHECK-NEXT: store i64 2, i64* [[PDIV_REPACK17]], align 8 +; CHECK-NEXT: call void @llsink(%lldiv_t* nonnull [[PDIV]]) +; CHECK-NEXT: [[PDIV_REPACK18:%.*]] = getelementptr inbounds [[LLDIV_T]], %lldiv_t* [[PDIV]], i64 0, i32 0 +; CHECK-NEXT: store i64 2147483648, i64* [[PDIV_REPACK18]], align 8 +; CHECK-NEXT: [[PDIV_REPACK19:%.*]] = getelementptr inbounds [[LLDIV_T]], %lldiv_t* [[PDIV]], i64 0, i32 1 +; CHECK-NEXT: store i64 0, i64* [[PDIV_REPACK19]], align 8 +; CHECK-NEXT: call void @llsink(%lldiv_t* nonnull [[PDIV]]) +; CHECK-NEXT: [[PDIV_REPACK20:%.*]] = getelementptr inbounds [[LLDIV_T]], %lldiv_t* [[PDIV]], i64 0, i32 0 +; CHECK-NEXT: store i64 9223372036854775807, i64* [[PDIV_REPACK20]], align 8 +; CHECK-NEXT: [[PDIV_REPACK21:%.*]] = getelementptr inbounds [[LLDIV_T]], %lldiv_t* [[PDIV]], i64 0, i32 1 +; CHECK-NEXT: store i64 0, i64* [[PDIV_REPACK21]], align 8 +; CHECK-NEXT: call void @llsink(%lldiv_t* nonnull [[PDIV]]) +; CHECK-NEXT: [[PDIV_REPACK22:%.*]] = getelementptr inbounds [[LLDIV_T]], %lldiv_t* [[PDIV]], i64 0, i32 0 +; CHECK-NEXT: store i64 4611686018427387904, i64* [[PDIV_REPACK22]], align 8 +; CHECK-NEXT: [[PDIV_REPACK23:%.*]] = getelementptr inbounds [[LLDIV_T]], %lldiv_t* [[PDIV]], i64 0, i32 1 +; CHECK-NEXT: store i64 0, i64* [[PDIV_REPACK23]], align 8 +; CHECK-NEXT: call void @llsink(%lldiv_t* nonnull [[PDIV]]) +; CHECK-NEXT: [[PDIV_REPACK24:%.*]] = getelementptr inbounds [[LLDIV_T]], %lldiv_t* [[PDIV]], i64 0, i32 0 +; CHECK-NEXT: store i64 -9223372036854775807, i64* [[PDIV_REPACK24]], align 8 +; CHECK-NEXT: [[PDIV_REPACK25:%.*]] = getelementptr inbounds [[LLDIV_T]], %lldiv_t* [[PDIV]], i64 0, i32 1 +; CHECK-NEXT: store i64 0, i64* [[PDIV_REPACK25]], align 8 +; CHECK-NEXT: call void @llsink(%lldiv_t* nonnull [[PDIV]]) +; CHECK-NEXT: ret void +; + %pdiv = alloca %lldiv_t + + ; Fold lldiv(-5, -1) to { 5, 0 }. + call void @lldiv(%lldiv_t* %pdiv, i64 -5, i64 -1) + call void @llsink(%lldiv_t* %pdiv) + + ; Fold lldiv(-5, -2) to { 2, -1 }. + call void @lldiv(%lldiv_t* %pdiv, i64 -5, i64 -2) + call void @llsink(%lldiv_t* %pdiv) + + ; Fold lldiv(0, -1) to { 0, 0 }. + call void @lldiv(%lldiv_t* %pdiv, i64 0, i64 -1) + call void @llsink(%lldiv_t* %pdiv) + + ; Fold lldiv(0, 1) to { 0, 0 }. + call void @lldiv(%lldiv_t* %pdiv, i64 0, i64 1) + call void @llsink(%lldiv_t* %pdiv) + + ; Fold lldiv(1, 1) to { 1, 0 }. + call void @lldiv(%lldiv_t* %pdiv, i64 1, i64 1) + call void @llsink(%lldiv_t* %pdiv) + + ; Fold lldiv(0, 2) to { 0, 0 }. + call void @lldiv(%lldiv_t* %pdiv, i64 0, i64 2) + call void @llsink(%lldiv_t* %pdiv) + + ; Fold lldiv(1, 2) to { 0, 1 }. + call void @lldiv(%lldiv_t* %pdiv, i64 1, i64 2) + call void @llsink(%lldiv_t* %pdiv) + + ; Fold lldiv(2, 1) to { 2, 0 }. + call void @lldiv(%lldiv_t* %pdiv, i64 2, i64 1) + call void @llsink(%lldiv_t* %pdiv) + + ; Fold lldiv(11, 3) to { 3, 2 }. + call void @lldiv(%lldiv_t* %pdiv, i64 11, i64 3) + call void @llsink(%lldiv_t* %pdiv) + + ; Fold lldiv(INT_MIN, -1) to { INT_MAX, 0 }. + call void @lldiv(%lldiv_t* %pdiv, i64 -2147483648, i64 -1) + call void @llsink(%lldiv_t* %pdiv) + + ; Fold lldiv(LLONG_MIN + 1, -1) to { }. + call void @lldiv(%lldiv_t* %pdiv, i64 -9223372036854775807, i64 -1) + call void @llsink(%lldiv_t* %pdiv) + + ; Fold lldiv(LLONG_MIN, -2) to { 4611686018427387904, 0 }. + call void @lldiv(%lldiv_t* %pdiv, i64 -9223372036854775808, i64 -2) + call void @llsink(%lldiv_t* %pdiv) + + ; Fold lldiv(LLONG_MAX, -1) to { LLONG_MIN, 0 }. + call void @lldiv(%lldiv_t* %pdiv, i64 9223372036854775807, i64 -1) + call void @llsink(%lldiv_t* %pdiv) + + ret void +} + + +; Verify that erroneous lldiv calls don't abort (although they could +; be folded to avoid the undefined behavior at runtime they're not). + +define void @call_lldiv() { +; CHECK-LABEL: @call_lldiv( +; CHECK-NEXT: [[PDIV:%.*]] = alloca [[LLDIV_T:%.*]], align 8 +; CHECK-NEXT: call void @lldiv(%lldiv_t* nonnull [[PDIV]], i64 1, i64 0) +; CHECK-NEXT: call void @llsink(%lldiv_t* nonnull [[PDIV]]) +; CHECK-NEXT: call void @lldiv(%lldiv_t* nonnull [[PDIV]], i64 -9223372036854775808, i64 -1) +; CHECK-NEXT: call void @llsink(%lldiv_t* nonnull [[PDIV]]) +; CHECK-NEXT: ret void +; + %pdiv = alloca %lldiv_t + + ; Do not fold lldiv(1, 0) and the library generate SIGFPE. + call void @lldiv(%lldiv_t* %pdiv, i64 1, i64 0) + call void @llsink(%lldiv_t* %pdiv) + + ; Do not fold lldiv(LONG_MIN, -1). + call void @lldiv(%lldiv_t* %pdiv, i64 -9223372036854775808, i64 -1) + call void @llsink(%lldiv_t* %pdiv) + + ret void +} + + +; Verify that imaxdiv calls with constant arguments are correctly folded. + +define void @fold_imaxdiv() { +; CHECK-LABEL: @fold_imaxdiv( +; CHECK-NEXT: [[PDIV:%.*]] = alloca [[IMAXDIV_T:%.*]], align 8 +; CHECK-NEXT: [[PDIV_REPACK:%.*]] = getelementptr inbounds [[IMAXDIV_T]], %imaxdiv_t* [[PDIV]], i64 0, i32 0 +; CHECK-NEXT: store i64 5, i64* [[PDIV_REPACK]], align 8 +; CHECK-NEXT: [[PDIV_REPACK1:%.*]] = getelementptr inbounds [[IMAXDIV_T]], %imaxdiv_t* [[PDIV]], i64 0, i32 1 +; CHECK-NEXT: store i64 0, i64* [[PDIV_REPACK1]], align 8 +; CHECK-NEXT: call void @imaxsink(%imaxdiv_t* nonnull [[PDIV]]) +; CHECK-NEXT: [[PDIV_REPACK2:%.*]] = getelementptr inbounds [[IMAXDIV_T]], %imaxdiv_t* [[PDIV]], i64 0, i32 0 +; CHECK-NEXT: store i64 2, i64* [[PDIV_REPACK2]], align 8 +; CHECK-NEXT: [[PDIV_REPACK3:%.*]] = getelementptr inbounds [[IMAXDIV_T]], %imaxdiv_t* [[PDIV]], i64 0, i32 1 +; CHECK-NEXT: store i64 -1, i64* [[PDIV_REPACK3]], align 8 +; CHECK-NEXT: call void @imaxsink(%imaxdiv_t* nonnull [[PDIV]]) +; CHECK-NEXT: [[PDIV_REPACK4:%.*]] = getelementptr inbounds [[IMAXDIV_T]], %imaxdiv_t* [[PDIV]], i64 0, i32 0 +; CHECK-NEXT: store i64 0, i64* [[PDIV_REPACK4]], align 8 +; CHECK-NEXT: [[PDIV_REPACK5:%.*]] = getelementptr inbounds [[IMAXDIV_T]], %imaxdiv_t* [[PDIV]], i64 0, i32 1 +; CHECK-NEXT: store i64 0, i64* [[PDIV_REPACK5]], align 8 +; CHECK-NEXT: call void @imaxsink(%imaxdiv_t* nonnull [[PDIV]]) +; CHECK-NEXT: [[PDIV_REPACK6:%.*]] = getelementptr inbounds [[IMAXDIV_T]], %imaxdiv_t* [[PDIV]], i64 0, i32 0 +; CHECK-NEXT: store i64 0, i64* [[PDIV_REPACK6]], align 8 +; CHECK-NEXT: [[PDIV_REPACK7:%.*]] = getelementptr inbounds [[IMAXDIV_T]], %imaxdiv_t* [[PDIV]], i64 0, i32 1 +; CHECK-NEXT: store i64 0, i64* [[PDIV_REPACK7]], align 8 +; CHECK-NEXT: call void @imaxsink(%imaxdiv_t* nonnull [[PDIV]]) +; CHECK-NEXT: [[PDIV_REPACK8:%.*]] = getelementptr inbounds [[IMAXDIV_T]], %imaxdiv_t* [[PDIV]], i64 0, i32 0 +; CHECK-NEXT: store i64 1, i64* [[PDIV_REPACK8]], align 8 +; CHECK-NEXT: [[PDIV_REPACK9:%.*]] = getelementptr inbounds [[IMAXDIV_T]], %imaxdiv_t* [[PDIV]], i64 0, i32 1 +; CHECK-NEXT: store i64 0, i64* [[PDIV_REPACK9]], align 8 +; CHECK-NEXT: call void @imaxsink(%imaxdiv_t* nonnull [[PDIV]]) +; CHECK-NEXT: [[PDIV_REPACK10:%.*]] = getelementptr inbounds [[IMAXDIV_T]], %imaxdiv_t* [[PDIV]], i64 0, i32 0 +; CHECK-NEXT: store i64 0, i64* [[PDIV_REPACK10]], align 8 +; CHECK-NEXT: [[PDIV_REPACK11:%.*]] = getelementptr inbounds [[IMAXDIV_T]], %imaxdiv_t* [[PDIV]], i64 0, i32 1 +; CHECK-NEXT: store i64 0, i64* [[PDIV_REPACK11]], align 8 +; CHECK-NEXT: call void @imaxsink(%imaxdiv_t* nonnull [[PDIV]]) +; CHECK-NEXT: [[PDIV_REPACK12:%.*]] = getelementptr inbounds [[IMAXDIV_T]], %imaxdiv_t* [[PDIV]], i64 0, i32 0 +; CHECK-NEXT: store i64 0, i64* [[PDIV_REPACK12]], align 8 +; CHECK-NEXT: [[PDIV_REPACK13:%.*]] = getelementptr inbounds [[IMAXDIV_T]], %imaxdiv_t* [[PDIV]], i64 0, i32 1 +; CHECK-NEXT: store i64 1, i64* [[PDIV_REPACK13]], align 8 +; CHECK-NEXT: call void @imaxsink(%imaxdiv_t* nonnull [[PDIV]]) +; CHECK-NEXT: [[PDIV_REPACK14:%.*]] = getelementptr inbounds [[IMAXDIV_T]], %imaxdiv_t* [[PDIV]], i64 0, i32 0 +; CHECK-NEXT: store i64 2, i64* [[PDIV_REPACK14]], align 8 +; CHECK-NEXT: [[PDIV_REPACK15:%.*]] = getelementptr inbounds [[IMAXDIV_T]], %imaxdiv_t* [[PDIV]], i64 0, i32 1 +; CHECK-NEXT: store i64 0, i64* [[PDIV_REPACK15]], align 8 +; CHECK-NEXT: call void @imaxsink(%imaxdiv_t* nonnull [[PDIV]]) +; CHECK-NEXT: [[PDIV_REPACK16:%.*]] = getelementptr inbounds [[IMAXDIV_T]], %imaxdiv_t* [[PDIV]], i64 0, i32 0 +; CHECK-NEXT: store i64 3, i64* [[PDIV_REPACK16]], align 8 +; CHECK-NEXT: [[PDIV_REPACK17:%.*]] = getelementptr inbounds [[IMAXDIV_T]], %imaxdiv_t* [[PDIV]], i64 0, i32 1 +; CHECK-NEXT: store i64 2, i64* [[PDIV_REPACK17]], align 8 +; CHECK-NEXT: call void @imaxsink(%imaxdiv_t* nonnull [[PDIV]]) +; CHECK-NEXT: [[PDIV_REPACK18:%.*]] = getelementptr inbounds [[IMAXDIV_T]], %imaxdiv_t* [[PDIV]], i64 0, i32 0 +; CHECK-NEXT: store i64 2147483648, i64* [[PDIV_REPACK18]], align 8 +; CHECK-NEXT: [[PDIV_REPACK19:%.*]] = getelementptr inbounds [[IMAXDIV_T]], %imaxdiv_t* [[PDIV]], i64 0, i32 1 +; CHECK-NEXT: store i64 0, i64* [[PDIV_REPACK19]], align 8 +; CHECK-NEXT: call void @imaxsink(%imaxdiv_t* nonnull [[PDIV]]) +; CHECK-NEXT: [[PDIV_REPACK20:%.*]] = getelementptr inbounds [[IMAXDIV_T]], %imaxdiv_t* [[PDIV]], i64 0, i32 0 +; CHECK-NEXT: store i64 4611686018427387904, i64* [[PDIV_REPACK20]], align 8 +; CHECK-NEXT: [[PDIV_REPACK21:%.*]] = getelementptr inbounds [[IMAXDIV_T]], %imaxdiv_t* [[PDIV]], i64 0, i32 1 +; CHECK-NEXT: store i64 0, i64* [[PDIV_REPACK21]], align 8 +; CHECK-NEXT: call void @imaxsink(%imaxdiv_t* nonnull [[PDIV]]) +; CHECK-NEXT: [[PDIV_REPACK22:%.*]] = getelementptr inbounds [[IMAXDIV_T]], %imaxdiv_t* [[PDIV]], i64 0, i32 0 +; CHECK-NEXT: store i64 9223372036854775807, i64* [[PDIV_REPACK22]], align 8 +; CHECK-NEXT: [[PDIV_REPACK23:%.*]] = getelementptr inbounds [[IMAXDIV_T]], %imaxdiv_t* [[PDIV]], i64 0, i32 1 +; CHECK-NEXT: store i64 0, i64* [[PDIV_REPACK23]], align 8 +; CHECK-NEXT: call void @imaxsink(%imaxdiv_t* nonnull [[PDIV]]) +; CHECK-NEXT: [[PDIV_REPACK24:%.*]] = getelementptr inbounds [[IMAXDIV_T]], %imaxdiv_t* [[PDIV]], i64 0, i32 0 +; CHECK-NEXT: store i64 -9223372036854775807, i64* [[PDIV_REPACK24]], align 8 +; CHECK-NEXT: [[PDIV_REPACK25:%.*]] = getelementptr inbounds [[IMAXDIV_T]], %imaxdiv_t* [[PDIV]], i64 0, i32 1 +; CHECK-NEXT: store i64 0, i64* [[PDIV_REPACK25]], align 8 +; CHECK-NEXT: call void @imaxsink(%imaxdiv_t* nonnull [[PDIV]]) +; CHECK-NEXT: ret void +; + %pdiv = alloca %imaxdiv_t + + ; Fold imaxdiv(-5, -1) to { 5, 0 }. + call void @imaxdiv(%imaxdiv_t* %pdiv, i64 -5, i64 -1) + call void @imaxsink(%imaxdiv_t* %pdiv) + + ; Fold imaxdiv(-5, -2) to { 2, -1 }. + call void @imaxdiv(%imaxdiv_t* %pdiv, i64 -5, i64 -2) + call void @imaxsink(%imaxdiv_t* %pdiv) + + ; Fold imaxdiv(0, -1) to { 0, 0 }. + call void @imaxdiv(%imaxdiv_t* %pdiv, i64 0, i64 -1) + call void @imaxsink(%imaxdiv_t* %pdiv) + + ; Fold imaxdiv(0, 1) to { 0, 0 }. + call void @imaxdiv(%imaxdiv_t* %pdiv, i64 0, i64 1) + call void @imaxsink(%imaxdiv_t* %pdiv) + + ; Fold imaxdiv(1, 1) to { 1, 0 }. + call void @imaxdiv(%imaxdiv_t* %pdiv, i64 1, i64 1) + call void @imaxsink(%imaxdiv_t* %pdiv) + + ; Fold imaxdiv(0, 2) to { 0, 0 }. + call void @imaxdiv(%imaxdiv_t* %pdiv, i64 0, i64 2) + call void @imaxsink(%imaxdiv_t* %pdiv) + + ; Fold imaxdiv(1, 2) to { 0, 1 }. + call void @imaxdiv(%imaxdiv_t* %pdiv, i64 1, i64 2) + call void @imaxsink(%imaxdiv_t* %pdiv) + + ; Fold imaxdiv(2, 1) to { 2, 0 }. + call void @imaxdiv(%imaxdiv_t* %pdiv, i64 2, i64 1) + call void @imaxsink(%imaxdiv_t* %pdiv) + + ; Fold imaxdiv(11, 3) to { 3, 2 }. + call void @imaxdiv(%imaxdiv_t* %pdiv, i64 11, i64 3) + call void @imaxsink(%imaxdiv_t* %pdiv) + + ; Fold imaxdiv(INT_MIN, -1) to { INT_MAX, 0 }. + call void @imaxdiv(%imaxdiv_t* %pdiv, i64 -2147483648, i64 -1) + call void @imaxsink(%imaxdiv_t* %pdiv) + + ; Fold imaxdiv(INTMAX_MIN, -2) to { 4611686018427387904, 0 }. + call void @imaxdiv(%imaxdiv_t* %pdiv, i64 -9223372036854775808, i64 -2) + call void @imaxsink(%imaxdiv_t* %pdiv) + + ; Fold imaxdiv(INTMAX_MIN + 1, -1) to { INTMAX_MAX, 0}. + call void @imaxdiv(%imaxdiv_t* %pdiv, i64 -9223372036854775807, i64 -1) + call void @imaxsink(%imaxdiv_t* %pdiv) + + ; Fold imaxdiv(INTMAX_MAX, -1) to { INTMAX_MIN, 0 }. + call void @imaxdiv(%imaxdiv_t* %pdiv, i64 9223372036854775807, i64 -1) + call void @imaxsink(%imaxdiv_t* %pdiv) + + ret void +} + + +; Verify that erroneous imaxdiv calls don't abort (although they could +; be folded to avoid the undefined behavior at runtime, they're not). + +define void @call_imaxdiv() { +; CHECK-LABEL: @call_imaxdiv( +; CHECK-NEXT: [[PDIV:%.*]] = alloca [[IMAXDIV_T:%.*]], align 8 +; CHECK-NEXT: call void @imaxdiv(%imaxdiv_t* nonnull [[PDIV]], i64 1, i64 0) +; CHECK-NEXT: call void @imaxsink(%imaxdiv_t* nonnull [[PDIV]]) +; CHECK-NEXT: call void @imaxdiv(%imaxdiv_t* nonnull [[PDIV]], i64 -9223372036854775808, i64 -1) +; CHECK-NEXT: call void @imaxsink(%imaxdiv_t* nonnull [[PDIV]]) +; CHECK-NEXT: ret void +; + %pdiv = alloca %imaxdiv_t + + ; Do not fold imaxdiv(1, 0) and the library generate SIGFPE. + call void @imaxdiv(%imaxdiv_t* %pdiv, i64 1, i64 0) + call void @imaxsink(%imaxdiv_t* %pdiv) + + ; Do not fold imaxdiv(INTMAX_MIN, -1). + call void @imaxdiv(%imaxdiv_t* %pdiv, i64 -9223372036854775808, i64 -1) + call void @imaxsink(%imaxdiv_t* %pdiv) + + ret void +} diff --git a/llvm/test/Transforms/InstCombine/div-3.ll b/llvm/test/Transforms/InstCombine/div-3.ll new file mode 100644 --- /dev/null +++ b/llvm/test/Transforms/InstCombine/div-3.ll @@ -0,0 +1,414 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; RUN: opt < %s -data-layout=E -passes=instcombine -S | FileCheck %s --check-prefixes=CHECK,BE +; RUN: opt < %s -data-layout=e -passes=instcombine -S | FileCheck %s --check-prefixes=CHECK,LE +; +; Verify that calls to the div functions declared to return an integer +; twice the precision of the arguments are folded when appropriate. + +; The following declarations are emitted on aarch64, ppc, ppc64le, riscv64, +; sparcv9, and x86_64. +declare i64 @div(i32, i32); + +; No supported target defines these but they are handled just the same. +declare i128 @ldiv(i64, i64) +declare i128 @lldiv(i64, i64) +declare i128 @imaxdiv(i64, i64) + +declare void @sink64(i64) +declare void @sink128(i128) + + +; Verify that div calls with constant arguments are correctly folded. + +define void @fold_div() { +; BE-LABEL: @fold_div( +; BE-NEXT: call void @sink64(i64 5) +; BE-NEXT: call void @sink64(i64 -4294967294) +; BE-NEXT: call void @sink64(i64 0) +; BE-NEXT: call void @sink64(i64 0) +; BE-NEXT: call void @sink64(i64 1) +; BE-NEXT: call void @sink64(i64 0) +; BE-NEXT: call void @sink64(i64 4294967296) +; BE-NEXT: call void @sink64(i64 2) +; BE-NEXT: call void @sink64(i64 8589934595) +; BE-NEXT: call void @sink128(i64 -2147483647) +; BE-NEXT: call void @sink128(i64 1073741824) +; BE-NEXT: ret void +; +; LE-LABEL: @fold_div( +; LE-NEXT: call void @sink64(i64 21474836480) +; LE-NEXT: call void @sink64(i64 -1) +; LE-NEXT: call void @sink64(i64 0) +; LE-NEXT: call void @sink64(i64 0) +; LE-NEXT: call void @sink64(i64 4294967296) +; LE-NEXT: call void @sink64(i64 0) +; LE-NEXT: call void @sink64(i64 1) +; LE-NEXT: call void @sink64(i64 8589934592) +; LE-NEXT: call void @sink64(i64 12884901890) +; LE-NEXT: call void @sink128(i64 -9223372032559808512) +; LE-NEXT: call void @sink128(i64 4611686018427387904) +; LE-NEXT: ret void +; + ; Fold div(-5, -1) to { 5, 0 }. + %div_m5_m1 = call i64 @div(i32 -5, i32 -1) + call void @sink64(i64 %div_m5_m1) + + ; Fold div(-5, -2) to { 2, -1 }. + %div_m5_m2 = call i64 @div(i32 -5, i32 -2) + call void @sink64(i64 %div_m5_m2) + + ; Fold div(0, -1) to { 0, 0 }. + %div_0_m1 = call i64 @div(i32 0, i32 -1) + call void @sink64(i64 %div_0_m1) + + ; Fold div(0, 1) to { 0, 0 }. + %div_0_1 = call i64 @div(i32 0, i32 1) + call void @sink64(i64 %div_0_1) + + ; Fold div(1, 1) to { 1, 0 }. + %div_1_1 = call i64 @div(i32 1, i32 1) + call void @sink64(i64 %div_1_1) + + ; Fold div(0, 2) to { 0, 0 }. + %div_0_2 = call i64 @div(i32 0, i32 2) + call void @sink64(i64 %div_0_2) + + ; Fold div(1, 2) to { 0, 1 }. + %div_1_2 = call i64 @div(i32 1, i32 2) + call void @sink64(i64 %div_1_2) + + ; Fold div(2, 1) to { 2, 0 }. + %div_2_1 = call i64 @div(i32 2, i32 1) + call void @sink64(i64 %div_2_1) + + ; Fold div(11, 3) to { 3, 2 }. + %div_11_3 = call i64 @div(i32 11, i32 3) + call void @sink64(i64 %div_11_3) + + ; Fold div(INT_MAX, -1) to { INT_MIN, 0 }. + %div_imax_m1 = call i64 @div(i32 2147483647, i32 -1) + call void @sink128(i64 %div_imax_m1) + + ; Fold div(INT_MIN, -2) to { 1073741824, 0 }. + %div_imin_m2 = call i64 @div(i32 -2147483648, i32 -2) + call void @sink128(i64 %div_imin_m2) + + ret void +} + + +; Verify that erroneous div calls don't abort (although they could +; be folded to avoid the undefined behavior at runtime they're not). + +define void @call_div() { +; CHECK-LABEL: @call_div( +; CHECK-NEXT: [[DIV_0_0:%.*]] = call i64 @div(i32 1, i32 0) +; CHECK-NEXT: call void @sink64(i64 [[DIV_0_0]]) +; CHECK-NEXT: [[DIV_IMIN_M1:%.*]] = call i64 @div(i32 -2147483648, i32 -1) +; CHECK-NEXT: call void @sink64(i64 [[DIV_IMIN_M1]]) +; CHECK-NEXT: ret void +; + ; Do not fold div(1, 0) and the library generate SIGFPE. + %div_0_0 = call i64 @div(i32 1, i32 0) + call void @sink64(i64 %div_0_0) + + ; Do not fold div(INT_MIN, -1), + %div_imin_m1 = call i64 @div(i32 -2147483648, i32 -1) + call void @sink64(i64 %div_imin_m1) + + ret void +} + + +; Verify that ldiv calls with constant arguments are correctly folded. + +define void @fold_ldiv() { +; CHECK-LABEL: @fold_ldiv( +; CHECK-NEXT: call void @sink128(i128 5) +; CHECK-NEXT: call void @sink128(i128 18446744073709551615) +; CHECK-NEXT: call void @sink128(i128 0) +; CHECK-NEXT: call void @sink128(i128 0) +; CHECK-NEXT: call void @sink128(i128 1) +; CHECK-NEXT: call void @sink128(i128 0) +; CHECK-NEXT: call void @sink128(i128 1) +; CHECK-NEXT: call void @sink128(i128 2) +; CHECK-NEXT: call void @sink128(i128 3) +; CHECK-NEXT: call void @sink128(i128 2147483648) +; CHECK-NEXT: call void @sink128(i128 9223372036854775807) +; CHECK-NEXT: call void @sink128(i128 4611686018427387904) +; CHECK-NEXT: call void @sink128(i128 9223372036854775809) +; CHECK-NEXT: ret void +; + ; Fold div(-5, -1) to { 5, 0 }. + %div_m5_m1 = call i128 @ldiv(i64 -5, i64 -1) + call void @sink128(i128 %div_m5_m1) + + ; Fold div(-5, -2) to { 2, -1 }. + %div_m5_m2 = call i128 @ldiv(i64 -5, i64 -2) + call void @sink128(i128 %div_m5_m2) + + ; Fold div(0, -1) to { 0, 0 }. + %div_0_m1 = call i128 @ldiv(i64 0, i64 -1) + call void @sink128(i128 %div_0_m1) + + ; Fold div(0, 1) to { 0, 0 }. + %div_0_1 = call i128 @ldiv(i64 0, i64 1) + call void @sink128(i128 %div_0_1) + + ; Fold div(1, 1) to { 1, 0 }. + %div_1_1 = call i128 @ldiv(i64 1, i64 1) + call void @sink128(i128 %div_1_1) + + ; Fold div(0, 2) to { 0, 0 }. + %div_0_2 = call i128 @ldiv(i64 0, i64 2) + call void @sink128(i128 %div_0_2) + + ; Fold div(1, 2) to { 0, 1 }. + %div_1_2 = call i128 @ldiv(i64 1, i64 2) + call void @sink128(i128 %div_1_2) + + ; Fold div(2, 1) to { 2, 0 }. + %div_2_1 = call i128 @ldiv(i64 2, i64 1) + call void @sink128(i128 %div_2_1) + + ; Fold div(11, 3) to { 3, 2 }. + %div_11_3 = call i128 @ldiv(i64 11, i64 3) + call void @sink128(i128 %div_11_3) + + ; Fold ldiv(INT_MIN, -1) to { INT_MAX, 0 }. + %div_imin_m1 = call i128 @ldiv(i64 -2147483648, i64 -1) + call void @sink128(i128 %div_imin_m1) + + ; Fold ldiv(LONG_MIN + 1, -1) to { }. + %div_iminp1_m1 = call i128 @ldiv(i64 -9223372036854775807, i64 -1) + call void @sink128(i128 %div_iminp1_m1) + + ; Fold ldiv(LONG_MIN, -2) to { 4611686018427387904, 0 }. + %div_imin_m2 = call i128 @ldiv(i64 -9223372036854775808, i64 -2) + call void @sink128(i128 %div_imin_m2) + + ; Fold ldiv(LONG_MAX, -1) to { LONG_MIN, 0 }. + %div_imax_m1 = call i128 @ldiv(i64 9223372036854775807, i64 -1) + call void @sink128(i128 %div_imax_m1) + + ret void +} + + +; Verify that erroneous ldiv calls don't abort (although they could +; be folded to avoid the undefined behavior at runtime they're not). + +define void @call_ldiv() { +; CHECK-LABEL: @call_ldiv( +; CHECK-NEXT: [[DIV_0_0:%.*]] = call i128 @ldiv(i64 1, i64 0) +; CHECK-NEXT: call void @sink128(i128 [[DIV_0_0]]) +; CHECK-NEXT: [[DIV_IMIN_M1:%.*]] = call i128 @ldiv(i64 -9223372036854775808, i64 -1) +; CHECK-NEXT: call void @sink128(i128 [[DIV_IMIN_M1]]) +; CHECK-NEXT: ret void +; + ; Do not fold ldiv(1, 0) and the library generate SIGFPE. + %div_0_0 = call i128 @ldiv(i64 1, i64 0) + call void @sink128(i128 %div_0_0) + + ; Do not fold ldiv(LONG_MIN, -1). + %div_imin_m1 = call i128 @ldiv(i64 -9223372036854775808, i64 -1) + call void @sink128(i128 %div_imin_m1) + + ret void +} + + +; Verify that lldiv calls with constant arguments are correctly folded. + +define void @fold_lldiv() { +; CHECK-LABEL: @fold_lldiv( +; CHECK-NEXT: call void @sink128(i128 5) +; CHECK-NEXT: call void @sink128(i128 18446744073709551615) +; CHECK-NEXT: call void @sink128(i128 0) +; CHECK-NEXT: call void @sink128(i128 0) +; CHECK-NEXT: call void @sink128(i128 1) +; CHECK-NEXT: call void @sink128(i128 0) +; CHECK-NEXT: call void @sink128(i128 1) +; CHECK-NEXT: call void @sink128(i128 2) +; CHECK-NEXT: call void @sink128(i128 3) +; CHECK-NEXT: call void @sink128(i128 2147483648) +; CHECK-NEXT: call void @sink128(i128 9223372036854775807) +; CHECK-NEXT: call void @sink128(i128 4611686018427387904) +; CHECK-NEXT: call void @sink128(i128 9223372036854775809) +; CHECK-NEXT: ret void +; + ; Fold lldiv(-5, -1) to { 5, 0 }. + %div_m5_m1 = call i128 @lldiv(i64 -5, i64 -1) + call void @sink128(i128 %div_m5_m1) + + ; Fold lldiv(-5, -2) to { 2, -1 }. + %div_m5_m2 = call i128 @lldiv(i64 -5, i64 -2) + call void @sink128(i128 %div_m5_m2) + + ; Fold lldiv(0, -1) to { 0, 0 }. + %div_0_m1 = call i128 @lldiv(i64 0, i64 -1) + call void @sink128(i128 %div_0_m1) + + ; Fold lldiv(0, 1) to { 0, 0 }. + %div_0_1 = call i128 @lldiv(i64 0, i64 1) + call void @sink128(i128 %div_0_1) + + ; Fold lldiv(1, 1) to { 1, 0 }. + %div_1_1 = call i128 @lldiv(i64 1, i64 1) + call void @sink128(i128 %div_1_1) + + ; Fold lldiv(0, 2) to { 0, 0 }. + %div_0_2 = call i128 @lldiv(i64 0, i64 2) + call void @sink128(i128 %div_0_2) + + ; Fold lldiv(1, 2) to { 0, 1 }. + %div_1_2 = call i128 @lldiv(i64 1, i64 2) + call void @sink128(i128 %div_1_2) + + ; Fold lldiv(2, 1) to { 2, 0 }. + %div_2_1 = call i128 @lldiv(i64 2, i64 1) + call void @sink128(i128 %div_2_1) + + ; Fold lldiv(11, 3) to { 3, 2 }. + %div_11_3 = call i128 @lldiv(i64 11, i64 3) + call void @sink128(i128 %div_11_3) + + ; Fold lldiv(INT_MIN, -1) to { INT_MAX, 0 }. + %div_imin_m1 = call i128 @lldiv(i64 -2147483648, i64 -1) + call void @sink128(i128 %div_imin_m1) + + ; Fold lldiv(LLONG_MIN + 1, -1) to { }. + %div_iminp1_m1 = call i128 @lldiv(i64 -9223372036854775807, i64 -1) + call void @sink128(i128 %div_iminp1_m1) + + ; Fold lldiv(LLONG_MIN, -2) to { 4611686018427387904, 0 }. + %div_imin_m2 = call i128 @lldiv(i64 -9223372036854775808, i64 -2) + call void @sink128(i128 %div_imin_m2) + + ; Fold lldiv(LLONG_MAX, -1) to { LLONG_MIN, 0 }. + %div_imax_m1 = call i128 @lldiv(i64 9223372036854775807, i64 -1) + call void @sink128(i128 %div_imax_m1) + + ret void +} + + +; Verify that erroneous lldiv calls don't abort (although they could +; be folded to avoid the undefined behavior at runtime they're not). + +define void @call_lldiv() { +; CHECK-LABEL: @call_lldiv( +; CHECK-NEXT: [[DIV_0_0:%.*]] = call i128 @lldiv(i64 1, i64 0) +; CHECK-NEXT: call void @sink128(i128 [[DIV_0_0]]) +; CHECK-NEXT: [[DIV_IMIN_M1:%.*]] = call i128 @lldiv(i64 -9223372036854775808, i64 -1) +; CHECK-NEXT: call void @sink128(i128 [[DIV_IMIN_M1]]) +; CHECK-NEXT: ret void +; + ; Do not fold lldiv(1, 0) and the library generate SIGFPE. + %div_0_0 = call i128 @lldiv(i64 1, i64 0) + call void @sink128(i128 %div_0_0) + + ; Do not fold lldiv(LONG_MIN, -1). + %div_imin_m1 = call i128 @lldiv(i64 -9223372036854775808, i64 -1) + call void @sink128(i128 %div_imin_m1) + + ret void +} + + +; Verify that imaxdiv calls with constant arguments are correctly folded. + +define void @fold_imaxdiv() { +; CHECK-LABEL: @fold_imaxdiv( +; CHECK-NEXT: call void @sink128(i128 5) +; CHECK-NEXT: call void @sink128(i128 18446744073709551615) +; CHECK-NEXT: call void @sink128(i128 0) +; CHECK-NEXT: call void @sink128(i128 0) +; CHECK-NEXT: call void @sink128(i128 1) +; CHECK-NEXT: call void @sink128(i128 0) +; CHECK-NEXT: call void @sink128(i128 1) +; CHECK-NEXT: call void @sink128(i128 2) +; CHECK-NEXT: call void @sink128(i128 3) +; CHECK-NEXT: call void @sink128(i128 2147483648) +; CHECK-NEXT: call void @sink128(i128 4611686018427387904) +; CHECK-NEXT: call void @sink128(i128 9223372036854775807) +; CHECK-NEXT: call void @sink128(i128 9223372036854775809) +; CHECK-NEXT: ret void +; + ; Fold imaxdiv(-5, -1) to { 5, 0 }. + %div_m5_m1 = call i128 @imaxdiv(i64 -5, i64 -1) + call void @sink128(i128 %div_m5_m1) + + ; Fold imaxdiv(-5, -2) to { 2, -1 }. + %div_m5_m2 = call i128 @imaxdiv(i64 -5, i64 -2) + call void @sink128(i128 %div_m5_m2) + + ; Fold imaxdiv(0, -1) to { 0, 0 }. + %div_0_m1 = call i128 @imaxdiv(i64 0, i64 -1) + call void @sink128(i128 %div_0_m1) + + ; Fold imaxdiv(0, 1) to { 0, 0 }. + %div_0_1 = call i128 @imaxdiv(i64 0, i64 1) + call void @sink128(i128 %div_0_1) + + ; Fold imaxdiv(1, 1) to { 1, 0 }. + %div_1_1 = call i128 @imaxdiv(i64 1, i64 1) + call void @sink128(i128 %div_1_1) + + ; Fold imaxdiv(0, 2) to { 0, 0 }. + %div_0_2 = call i128 @imaxdiv(i64 0, i64 2) + call void @sink128(i128 %div_0_2) + + ; Fold imaxdiv(1, 2) to { 0, 1 }. + %div_1_2 = call i128 @imaxdiv(i64 1, i64 2) + call void @sink128(i128 %div_1_2) + + ; Fold imaxdiv(2, 1) to { 2, 0 }. + %div_2_1 = call i128 @imaxdiv(i64 2, i64 1) + call void @sink128(i128 %div_2_1) + + ; Fold imaxdiv(11, 3) to { 3, 2 }. + %div_11_3 = call i128 @imaxdiv(i64 11, i64 3) + call void @sink128(i128 %div_11_3) + + ; Fold imaxdiv(INT_MIN, -1) to { INT_MAX, 0 }. + %div_imin_m1 = call i128 @imaxdiv(i64 -2147483648, i64 -1) + call void @sink128(i128 %div_imin_m1) + + ; Fold imaxdiv(INTMAX_MIN, -2) to { 4611686018427387904, 0 }. + %div_imin_m2 = call i128 @imaxdiv(i64 -9223372036854775808, i64 -2) + call void @sink128(i128 %div_imin_m2) + + ; Fold imaxdiv(INTMAX_MIN + 1, -1) to { INTMAX_MAX, 0}. + %div_iminp1_m1 = call i128 @imaxdiv(i64 -9223372036854775807, i64 -1) + call void @sink128(i128 %div_iminp1_m1) + + ; Fold imaxdiv(INTMAX_MAX, -1) to { INTMAX_MIN, 0 }. + %div_imax_m1 = call i128 @imaxdiv(i64 9223372036854775807, i64 -1) + call void @sink128(i128 %div_imax_m1) + + ret void +} + + +; Verify that erroneous imaxdiv calls don't abort (although they could +; be folded to avoid the undefined behavior at runtime, they're not). + +define void @call_imaxdiv() { +; CHECK-LABEL: @call_imaxdiv( +; CHECK-NEXT: [[DIV_0_0:%.*]] = call i128 @imaxdiv(i64 1, i64 0) +; CHECK-NEXT: call void @sink128(i128 [[DIV_0_0]]) +; CHECK-NEXT: [[DIV_IMIN_M1:%.*]] = call i128 @imaxdiv(i64 -9223372036854775808, i64 -1) +; CHECK-NEXT: call void @sink128(i128 [[DIV_IMIN_M1]]) +; CHECK-NEXT: ret void +; + ; Do not fold imaxdiv(1, 0) and the library generate SIGFPE. + %div_0_0 = call i128 @imaxdiv(i64 1, i64 0) + call void @sink128(i128 %div_0_0) + + ; Do not fold imaxdiv(INTMAX_MIN, -1). + %div_imin_m1 = call i128 @imaxdiv(i64 -9223372036854775808, i64 -1) + call void @sink128(i128 %div_imin_m1) + + ret void +} diff --git a/llvm/test/Transforms/InstCombine/div-4.ll b/llvm/test/Transforms/InstCombine/div-4.ll new file mode 100644 --- /dev/null +++ b/llvm/test/Transforms/InstCombine/div-4.ll @@ -0,0 +1,419 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; RUN: opt < %s -data-layout=E -passes=instcombine -S | FileCheck %s --check-prefixes=CHECK,BE +; RUN: opt < %s -data-layout=e -passes=instcombine -S | FileCheck %s --check-prefixes=CHECK,LE +; +; Verify that calls to the div functions declared to return a struct with +; a single member twice the precision of the argument(s) are folded when +; appropriate. + +%div_t = type { i64 } +%ldiv_t = type { i128 } +%lldiv_t = type { i128 } +%imaxdiv_t = type { i128 } + +; The following declarations are emitted for div on mips64. +declare %div_t @div(i32, i32) + +; No supported target defines these but they are handled just the same. +declare %ldiv_t @ldiv(i64, i64) +declare %lldiv_t @lldiv(i64, i64) +declare %imaxdiv_t @imaxdiv(i64, i64) + +declare void @sink(%div_t) +declare void @lsink(%ldiv_t) + + +; Verify that div calls with constant arguments are correctly folded. + +define void @fold_div() { +; BE-LABEL: @fold_div( +; BE-NEXT: call void @sink([[DIV_T:%.*]] { i64 5 }) +; BE-NEXT: call void @sink([[DIV_T]] { i64 -4294967294 }) +; BE-NEXT: call void @sink([[DIV_T]] zeroinitializer) +; BE-NEXT: call void @sink([[DIV_T]] zeroinitializer) +; BE-NEXT: call void @sink([[DIV_T]] { i64 1 }) +; BE-NEXT: call void @sink([[DIV_T]] zeroinitializer) +; BE-NEXT: call void @sink([[DIV_T]] { i64 4294967296 }) +; BE-NEXT: call void @sink([[DIV_T]] { i64 2 }) +; BE-NEXT: call void @sink([[DIV_T]] { i64 8589934595 }) +; BE-NEXT: call void @lsink([[DIV_T]] { i64 -2147483647 }) +; BE-NEXT: call void @lsink([[DIV_T]] { i64 1073741824 }) +; BE-NEXT: ret void +; +; LE-LABEL: @fold_div( +; LE-NEXT: call void @sink([[DIV_T:%.*]] { i64 21474836480 }) +; LE-NEXT: call void @sink([[DIV_T]] { i64 -1 }) +; LE-NEXT: call void @sink([[DIV_T]] zeroinitializer) +; LE-NEXT: call void @sink([[DIV_T]] zeroinitializer) +; LE-NEXT: call void @sink([[DIV_T]] { i64 4294967296 }) +; LE-NEXT: call void @sink([[DIV_T]] zeroinitializer) +; LE-NEXT: call void @sink([[DIV_T]] { i64 1 }) +; LE-NEXT: call void @sink([[DIV_T]] { i64 8589934592 }) +; LE-NEXT: call void @sink([[DIV_T]] { i64 12884901890 }) +; LE-NEXT: call void @lsink([[DIV_T]] { i64 -9223372032559808512 }) +; LE-NEXT: call void @lsink([[DIV_T]] { i64 4611686018427387904 }) +; LE-NEXT: ret void +; + ; Fold div(-5, -1) to { 5, 0 }. + %div_m5_m1 = call %div_t @div(i32 -5, i32 -1) + call void @sink(%div_t %div_m5_m1) + + ; Fold div(-5, -2) to { 2, -1 }. + %div_m5_m2 = call %div_t @div(i32 -5, i32 -2) + call void @sink(%div_t %div_m5_m2) + + ; Fold div(0, -1) to { 0, 0 }. + %div_0_m1 = call %div_t @div(i32 0, i32 -1) + call void @sink(%div_t %div_0_m1) + + ; Fold div(0, 1) to { 0, 0 }. + %div_0_1 = call %div_t @div(i32 0, i32 1) + call void @sink(%div_t %div_0_1) + + ; Fold div(1, 1) to { 1, 0 }. + %div_1_1 = call %div_t @div(i32 1, i32 1) + call void @sink(%div_t %div_1_1) + + ; Fold div(0, 2) to { 0, 0 }. + %div_0_2 = call %div_t @div(i32 0, i32 2) + call void @sink(%div_t %div_0_2) + + ; Fold div(1, 2) to { 0, 1 }. + %div_1_2 = call %div_t @div(i32 1, i32 2) + call void @sink(%div_t %div_1_2) + + ; Fold div(2, 1) to { 2, 0 }. + %div_2_1 = call %div_t @div(i32 2, i32 1) + call void @sink(%div_t %div_2_1) + + ; Fold div(11, 3) to { 3, 2 }. + %div_11_3 = call %div_t @div(i32 11, i32 3) + call void @sink(%div_t %div_11_3) + + ; Fold div(INT_MAX, -1) to { INT_MIN, 0 }. + %div_imax_m1 = call %div_t @div(i32 2147483647, i32 -1) + call void @lsink(%div_t %div_imax_m1) + + ; Fold div(INT_MIN, -2) to { 1073741824, 0 }. + %div_imin_m2 = call %div_t @div(i32 -2147483648, i32 -2) + call void @lsink(%div_t %div_imin_m2) + + ret void +} + + +; Verify that erroneous div calls don't abort (although they could +; be folded to avoid the undefined behavior at runtime they're not). + +define void @call_div() { +; CHECK-LABEL: @call_div( +; CHECK-NEXT: [[DIV_0_0:%.*]] = call [[DIV_T:%.*]] @div(i32 1, i32 0) +; CHECK-NEXT: call void @sink([[DIV_T]] [[DIV_0_0]]) +; CHECK-NEXT: [[DIV_IMIN_M1:%.*]] = call [[DIV_T]] @div(i32 -2147483648, i32 -1) +; CHECK-NEXT: call void @sink([[DIV_T]] [[DIV_IMIN_M1]]) +; CHECK-NEXT: ret void +; + ; Do not fold div(1, 0) and the library generate SIGFPE. + %div_0_0 = call %div_t @div(i32 1, i32 0) + call void @sink(%div_t %div_0_0) + + ; Do not fold div(INT_MIN, -1), + %div_imin_m1 = call %div_t @div(i32 -2147483648, i32 -1) + call void @sink(%div_t %div_imin_m1) + + ret void +} + + +; Verify that ldiv calls with constant arguments are correctly folded. + +define void @fold_ldiv() { +; CHECK-LABEL: @fold_ldiv( +; CHECK-NEXT: call void @lsink([[LDIV_T:%.*]] { i128 5 }) +; CHECK-NEXT: call void @lsink([[LDIV_T]] { i128 18446744073709551615 }) +; CHECK-NEXT: call void @lsink([[LDIV_T]] zeroinitializer) +; CHECK-NEXT: call void @lsink([[LDIV_T]] zeroinitializer) +; CHECK-NEXT: call void @lsink([[LDIV_T]] { i128 1 }) +; CHECK-NEXT: call void @lsink([[LDIV_T]] zeroinitializer) +; CHECK-NEXT: call void @lsink([[LDIV_T]] { i128 1 }) +; CHECK-NEXT: call void @lsink([[LDIV_T]] { i128 2 }) +; CHECK-NEXT: call void @lsink([[LDIV_T]] { i128 3 }) +; CHECK-NEXT: call void @lsink([[LDIV_T]] { i128 2147483648 }) +; CHECK-NEXT: call void @lsink([[LDIV_T]] { i128 9223372036854775807 }) +; CHECK-NEXT: call void @lsink([[LDIV_T]] { i128 4611686018427387904 }) +; CHECK-NEXT: call void @lsink([[LDIV_T]] { i128 9223372036854775809 }) +; CHECK-NEXT: ret void +; + ; Fold div(-5, -1) to { 5, 0 }. + %div_m5_m1 = call %ldiv_t @ldiv(i64 -5, i64 -1) + call void @lsink(%ldiv_t %div_m5_m1) + + ; Fold div(-5, -2) to { 2, -1 }. + %div_m5_m2 = call %ldiv_t @ldiv(i64 -5, i64 -2) + call void @lsink(%ldiv_t %div_m5_m2) + + ; Fold div(0, -1) to { 0, 0 }. + %div_0_m1 = call %ldiv_t @ldiv(i64 0, i64 -1) + call void @lsink(%ldiv_t %div_0_m1) + + ; Fold div(0, 1) to { 0, 0 }. + %div_0_1 = call %ldiv_t @ldiv(i64 0, i64 1) + call void @lsink(%ldiv_t %div_0_1) + + ; Fold div(1, 1) to { 1, 0 }. + %div_1_1 = call %ldiv_t @ldiv(i64 1, i64 1) + call void @lsink(%ldiv_t %div_1_1) + + ; Fold div(0, 2) to { 0, 0 }. + %div_0_2 = call %ldiv_t @ldiv(i64 0, i64 2) + call void @lsink(%ldiv_t %div_0_2) + + ; Fold div(1, 2) to { 0, 1 }. + %div_1_2 = call %ldiv_t @ldiv(i64 1, i64 2) + call void @lsink(%ldiv_t %div_1_2) + + ; Fold div(2, 1) to { 2, 0 }. + %div_2_1 = call %ldiv_t @ldiv(i64 2, i64 1) + call void @lsink(%ldiv_t %div_2_1) + + ; Fold div(11, 3) to { 3, 2 }. + %div_11_3 = call %ldiv_t @ldiv(i64 11, i64 3) + call void @lsink(%ldiv_t %div_11_3) + + ; Fold ldiv(INT_MIN, -1) to { INT_MAX, 0 }. + %div_imin_m1 = call %ldiv_t @ldiv(i64 -2147483648, i64 -1) + call void @lsink(%ldiv_t %div_imin_m1) + + ; Fold ldiv(LONG_MIN + 1, -1) to { }. + %div_iminp1_m1 = call %ldiv_t @ldiv(i64 -9223372036854775807, i64 -1) + call void @lsink(%ldiv_t %div_iminp1_m1) + + ; Fold ldiv(LONG_MIN, -2) to { 4611686018427387904, 0 }. + %div_imin_m2 = call %ldiv_t @ldiv(i64 -9223372036854775808, i64 -2) + call void @lsink(%ldiv_t %div_imin_m2) + + ; Fold ldiv(LONG_MAX, -1) to { LONG_MIN, 0 }. + %div_imax_m1 = call %ldiv_t @ldiv(i64 9223372036854775807, i64 -1) + call void @lsink(%ldiv_t %div_imax_m1) + + ret void +} + + +; Verify that erroneous ldiv calls don't abort (although they could +; be folded to avoid the undefined behavior at runtime they're not). + +define void @call_ldiv() { +; CHECK-LABEL: @call_ldiv( +; CHECK-NEXT: [[DIV_0_0:%.*]] = call [[LDIV_T:%.*]] @ldiv(i64 1, i64 0) +; CHECK-NEXT: call void @lsink([[LDIV_T]] [[DIV_0_0]]) +; CHECK-NEXT: [[DIV_IMIN_M1:%.*]] = call [[LDIV_T]] @ldiv(i64 -9223372036854775808, i64 -1) +; CHECK-NEXT: call void @lsink([[LDIV_T]] [[DIV_IMIN_M1]]) +; CHECK-NEXT: ret void +; + ; Do not fold ldiv(1, 0) and the library generate SIGFPE. + %div_0_0 = call %ldiv_t @ldiv(i64 1, i64 0) + call void @lsink(%ldiv_t %div_0_0) + + ; Do not fold ldiv(LONG_MIN, -1). + %div_imin_m1 = call %ldiv_t @ldiv(i64 -9223372036854775808, i64 -1) + call void @lsink(%ldiv_t %div_imin_m1) + + ret void +} + + +; Verify that lldiv calls with constant arguments are correctly folded. + +define void @fold_lldiv() { +; CHECK-LABEL: @fold_lldiv( +; CHECK-NEXT: call void @lsink([[LLDIV_T:%.*]] { i128 5 }) +; CHECK-NEXT: call void @lsink([[LLDIV_T]] { i128 18446744073709551615 }) +; CHECK-NEXT: call void @lsink([[LLDIV_T]] zeroinitializer) +; CHECK-NEXT: call void @lsink([[LLDIV_T]] zeroinitializer) +; CHECK-NEXT: call void @lsink([[LLDIV_T]] { i128 1 }) +; CHECK-NEXT: call void @lsink([[LLDIV_T]] zeroinitializer) +; CHECK-NEXT: call void @lsink([[LLDIV_T]] { i128 1 }) +; CHECK-NEXT: call void @lsink([[LLDIV_T]] { i128 2 }) +; CHECK-NEXT: call void @lsink([[LLDIV_T]] { i128 3 }) +; CHECK-NEXT: call void @lsink([[LLDIV_T]] { i128 2147483648 }) +; CHECK-NEXT: call void @lsink([[LLDIV_T]] { i128 9223372036854775807 }) +; CHECK-NEXT: call void @lsink([[LLDIV_T]] { i128 4611686018427387904 }) +; CHECK-NEXT: call void @lsink([[LLDIV_T]] { i128 9223372036854775809 }) +; CHECK-NEXT: ret void +; + ; Fold lldiv(-5, -1) to { 5, 0 }. + %div_m5_m1 = call %lldiv_t @lldiv(i64 -5, i64 -1) + call void @lsink(%lldiv_t %div_m5_m1) + + ; Fold lldiv(-5, -2) to { 2, -1 }. + %div_m5_m2 = call %lldiv_t @lldiv(i64 -5, i64 -2) + call void @lsink(%lldiv_t %div_m5_m2) + + ; Fold lldiv(0, -1) to { 0, 0 }. + %div_0_m1 = call %lldiv_t @lldiv(i64 0, i64 -1) + call void @lsink(%lldiv_t %div_0_m1) + + ; Fold lldiv(0, 1) to { 0, 0 }. + %div_0_1 = call %lldiv_t @lldiv(i64 0, i64 1) + call void @lsink(%lldiv_t %div_0_1) + + ; Fold lldiv(1, 1) to { 1, 0 }. + %div_1_1 = call %lldiv_t @lldiv(i64 1, i64 1) + call void @lsink(%lldiv_t %div_1_1) + + ; Fold lldiv(0, 2) to { 0, 0 }. + %div_0_2 = call %lldiv_t @lldiv(i64 0, i64 2) + call void @lsink(%lldiv_t %div_0_2) + + ; Fold lldiv(1, 2) to { 0, 1 }. + %div_1_2 = call %lldiv_t @lldiv(i64 1, i64 2) + call void @lsink(%lldiv_t %div_1_2) + + ; Fold lldiv(2, 1) to { 2, 0 }. + %div_2_1 = call %lldiv_t @lldiv(i64 2, i64 1) + call void @lsink(%lldiv_t %div_2_1) + + ; Fold lldiv(11, 3) to { 3, 2 }. + %div_11_3 = call %lldiv_t @lldiv(i64 11, i64 3) + call void @lsink(%lldiv_t %div_11_3) + + ; Fold lldiv(INT_MIN, -1) to { INT_MAX, 0 }. + %div_imin_m1 = call %lldiv_t @lldiv(i64 -2147483648, i64 -1) + call void @lsink(%lldiv_t %div_imin_m1) + + ; Fold lldiv(LLONG_MIN + 1, -1) to { }. + %div_iminp1_m1 = call %lldiv_t @lldiv(i64 -9223372036854775807, i64 -1) + call void @lsink(%lldiv_t %div_iminp1_m1) + + ; Fold lldiv(LLONG_MIN, -2) to { 4611686018427387904, 0 }. + %div_imin_m2 = call %lldiv_t @lldiv(i64 -9223372036854775808, i64 -2) + call void @lsink(%lldiv_t %div_imin_m2) + + ; Fold lldiv(LLONG_MAX, -1) to { LLONG_MIN, 0 }. + %div_imax_m1 = call %lldiv_t @lldiv(i64 9223372036854775807, i64 -1) + call void @lsink(%lldiv_t %div_imax_m1) + + ret void +} + + +; Verify that erroneous lldiv calls don't abort (although they could +; be folded to avoid the undefined behavior at runtime they're not). + +define void @call_lldiv() { +; CHECK-LABEL: @call_lldiv( +; CHECK-NEXT: [[DIV_0_0:%.*]] = call [[LLDIV_T:%.*]] @lldiv(i64 1, i64 0) +; CHECK-NEXT: call void @lsink([[LLDIV_T]] [[DIV_0_0]]) +; CHECK-NEXT: [[DIV_IMIN_M1:%.*]] = call [[LLDIV_T]] @lldiv(i64 -9223372036854775808, i64 -1) +; CHECK-NEXT: call void @lsink([[LLDIV_T]] [[DIV_IMIN_M1]]) +; CHECK-NEXT: ret void +; + ; Do not fold lldiv(1, 0) and the library generate SIGFPE. + %div_0_0 = call %lldiv_t @lldiv(i64 1, i64 0) + call void @lsink(%lldiv_t %div_0_0) + + ; Do not fold lldiv(LONG_MIN, -1). + %div_imin_m1 = call %lldiv_t @lldiv(i64 -9223372036854775808, i64 -1) + call void @lsink(%lldiv_t %div_imin_m1) + + ret void +} + + +; Verify that imaxdiv calls with constant arguments are correctly folded. + +define void @fold_imaxdiv() { +; CHECK-LABEL: @fold_imaxdiv( +; CHECK-NEXT: call void @lsink([[IMAXDIV_T:%.*]] { i128 5 }) +; CHECK-NEXT: call void @lsink([[IMAXDIV_T]] { i128 18446744073709551615 }) +; CHECK-NEXT: call void @lsink([[IMAXDIV_T]] zeroinitializer) +; CHECK-NEXT: call void @lsink([[IMAXDIV_T]] zeroinitializer) +; CHECK-NEXT: call void @lsink([[IMAXDIV_T]] { i128 1 }) +; CHECK-NEXT: call void @lsink([[IMAXDIV_T]] zeroinitializer) +; CHECK-NEXT: call void @lsink([[IMAXDIV_T]] { i128 1 }) +; CHECK-NEXT: call void @lsink([[IMAXDIV_T]] { i128 2 }) +; CHECK-NEXT: call void @lsink([[IMAXDIV_T]] { i128 3 }) +; CHECK-NEXT: call void @lsink([[IMAXDIV_T]] { i128 2147483648 }) +; CHECK-NEXT: call void @lsink([[IMAXDIV_T]] { i128 4611686018427387904 }) +; CHECK-NEXT: call void @lsink([[IMAXDIV_T]] { i128 9223372036854775807 }) +; CHECK-NEXT: call void @lsink([[IMAXDIV_T]] { i128 9223372036854775809 }) +; CHECK-NEXT: ret void +; + ; Fold imaxdiv(-5, -1) to { 5, 0 }. + %div_m5_m1 = call %imaxdiv_t @imaxdiv(i64 -5, i64 -1) + call void @lsink(%imaxdiv_t %div_m5_m1) + + ; Fold imaxdiv(-5, -2) to { 2, -1 }. + %div_m5_m2 = call %imaxdiv_t @imaxdiv(i64 -5, i64 -2) + call void @lsink(%imaxdiv_t %div_m5_m2) + + ; Fold imaxdiv(0, -1) to { 0, 0 }. + %div_0_m1 = call %imaxdiv_t @imaxdiv(i64 0, i64 -1) + call void @lsink(%imaxdiv_t %div_0_m1) + + ; Fold imaxdiv(0, 1) to { 0, 0 }. + %div_0_1 = call %imaxdiv_t @imaxdiv(i64 0, i64 1) + call void @lsink(%imaxdiv_t %div_0_1) + + ; Fold imaxdiv(1, 1) to { 1, 0 }. + %div_1_1 = call %imaxdiv_t @imaxdiv(i64 1, i64 1) + call void @lsink(%imaxdiv_t %div_1_1) + + ; Fold imaxdiv(0, 2) to { 0, 0 }. + %div_0_2 = call %imaxdiv_t @imaxdiv(i64 0, i64 2) + call void @lsink(%imaxdiv_t %div_0_2) + + ; Fold imaxdiv(1, 2) to { 0, 1 }. + %div_1_2 = call %imaxdiv_t @imaxdiv(i64 1, i64 2) + call void @lsink(%imaxdiv_t %div_1_2) + + ; Fold imaxdiv(2, 1) to { 2, 0 }. + %div_2_1 = call %imaxdiv_t @imaxdiv(i64 2, i64 1) + call void @lsink(%imaxdiv_t %div_2_1) + + ; Fold imaxdiv(11, 3) to { 3, 2 }. + %div_11_3 = call %imaxdiv_t @imaxdiv(i64 11, i64 3) + call void @lsink(%imaxdiv_t %div_11_3) + + ; Fold imaxdiv(INT_MIN, -1) to { INT_MAX, 0 }. + %div_imin_m1 = call %imaxdiv_t @imaxdiv(i64 -2147483648, i64 -1) + call void @lsink(%imaxdiv_t %div_imin_m1) + + ; Fold imaxdiv(INTMAX_MIN, -2) to { 4611686018427387904, 0 }. + %div_imin_m2 = call %imaxdiv_t @imaxdiv(i64 -9223372036854775808, i64 -2) + call void @lsink(%imaxdiv_t %div_imin_m2) + + ; Fold imaxdiv(INTMAX_MIN + 1, -1) to { INTMAX_MAX, 0}. + %div_iminp1_m1 = call %imaxdiv_t @imaxdiv(i64 -9223372036854775807, i64 -1) + call void @lsink(%imaxdiv_t %div_iminp1_m1) + + ; Fold imaxdiv(INTMAX_MAX, -1) to { INTMAX_MIN, 0 }. + %div_imax_m1 = call %imaxdiv_t @imaxdiv(i64 9223372036854775807, i64 -1) + call void @lsink(%imaxdiv_t %div_imax_m1) + + ret void +} + + +; Verify that erroneous imaxdiv calls don't abort (although they could +; be folded to avoid the undefined behavior at runtime, they're not). + +define void @call_imaxdiv() { +; CHECK-LABEL: @call_imaxdiv( +; CHECK-NEXT: [[DIV_0_0:%.*]] = call [[IMAXDIV_T:%.*]] @imaxdiv(i64 1, i64 0) +; CHECK-NEXT: call void @lsink([[IMAXDIV_T]] [[DIV_0_0]]) +; CHECK-NEXT: [[DIV_IMIN_M1:%.*]] = call [[IMAXDIV_T]] @imaxdiv(i64 -9223372036854775808, i64 -1) +; CHECK-NEXT: call void @lsink([[IMAXDIV_T]] [[DIV_IMIN_M1]]) +; CHECK-NEXT: ret void +; + ; Do not fold imaxdiv(1, 0) and the library generate SIGFPE. + %div_0_0 = call %imaxdiv_t @imaxdiv(i64 1, i64 0) + call void @lsink(%imaxdiv_t %div_0_0) + + ; Do not fold imaxdiv(INTMAX_MIN, -1). + %div_imin_m1 = call %imaxdiv_t @imaxdiv(i64 -9223372036854775808, i64 -1) + call void @lsink(%imaxdiv_t %div_imin_m1) + + ret void +} diff --git a/llvm/unittests/Analysis/TargetLibraryInfoTest.cpp b/llvm/unittests/Analysis/TargetLibraryInfoTest.cpp --- a/llvm/unittests/Analysis/TargetLibraryInfoTest.cpp +++ b/llvm/unittests/Analysis/TargetLibraryInfoTest.cpp @@ -592,7 +592,17 @@ // These functions are OpenMP Offloading allocation / free routines "declare i8* @__kmpc_alloc_shared(i64)\n" - "declare void @__kmpc_free_shared(i8*, i64)\n"); + "declare void @__kmpc_free_shared(i8*, i64)\n" + + // The div functions (their internal signature depends on the target). + "%div_t = type { i32, i32 }\n" + "declare %div_t @div(i32, i32)\n" + "%ldiv_t = type { i64, i64 }\n" + "declare %ldiv_t @ldiv(i64, i64)\n" + "%lldiv_t = type { i64, i64 }\n" + "declare %lldiv_t @lldiv(i64, i64)\n" + "%imaxdiv_t = type { i64, i64 }\n" + "declare %imaxdiv_t @imaxdiv(i64, i64)\n"); for (unsigned FI = 0; FI != LibFunc::NumLibFuncs; ++FI) { LibFunc LF = (LibFunc)FI;