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 @@ -649,6 +649,9 @@ /// char *ctermid(char *s); TLI_DEFINE_ENUM_INTERNAL(ctermid) TLI_DEFINE_STRING_INTERNAL("ctermid") +/// div_t div(int, int); +TLI_DEFINE_ENUM_INTERNAL(div) +TLI_DEFINE_STRING_INTERNAL("div") /// int execl(const char *path, const char *arg, ...); TLI_DEFINE_ENUM_INTERNAL(execl) TLI_DEFINE_STRING_INTERNAL("execl") @@ -937,6 +940,9 @@ /// uint16_t htons(uint16_t hostshort); TLI_DEFINE_ENUM_INTERNAL(htons) TLI_DEFINE_STRING_INTERNAL("htons") +/// imaxdiv_t imaxdiv(intmax_t, intmax_t); +TLI_DEFINE_ENUM_INTERNAL(imaxdiv) +TLI_DEFINE_STRING_INTERNAL("imaxdiv") /// int iprintf(const char *format, ...); TLI_DEFINE_ENUM_INTERNAL(iprintf) TLI_DEFINE_STRING_INTERNAL("iprintf") @@ -961,9 +967,15 @@ /// long double ldexpl(long double x, int n); TLI_DEFINE_ENUM_INTERNAL(ldexpl) TLI_DEFINE_STRING_INTERNAL("ldexpl") +/// ldiv_t ldiv(long, long); +TLI_DEFINE_ENUM_INTERNAL(ldiv) +TLI_DEFINE_STRING_INTERNAL("ldiv") /// long long int llabs(long long int j); TLI_DEFINE_ENUM_INTERNAL(llabs) TLI_DEFINE_STRING_INTERNAL("llabs") +/// lldiv_t lldiv(long long, long long); +TLI_DEFINE_ENUM_INTERNAL(lldiv) +TLI_DEFINE_STRING_INTERNAL("lldiv") /// 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 @@ -201,6 +201,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 @@ -1745,6 +1745,14 @@ return (NumParams == 1 && FTy.getReturnType()->isIntegerTy() && FTy.getReturnType() == FTy.getParamType(0)); + case LibFunc_div: + case LibFunc_ldiv: + case LibFunc_lldiv: + case LibFunc_imaxdiv: + // TODO: Check return type to match div_t et al.? + return (NumParams == 2 && FTy.getParamType(0)->isIntegerTy() && + FTy.getParamType(1)->isIntegerTy()); + case LibFunc_cxa_atexit: return (NumParams == 3 && FTy.getReturnType()->isIntegerTy() && FTy.getParamType(0)->isPointerTy() && 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 @@ -2505,6 +2505,48 @@ // Integer Library Call Optimizations //===----------------------------------------------------------------------===// +// Fold the div, ldiv, lldiv, and imaxdiv C standard functions. +Value *LibCallSimplifier::optimizeDiv(CallInst *CI, IRBuilderBase &B) { + ConstantInt *NumC = dyn_cast(CI->getArgOperand(0)); + 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. + StructType *DivTy = dyn_cast(CI->getType()); + return ConstantStruct::get(DivTy, {NumC, NumC}); + } + + ConstantInt *DenC = dyn_cast(CI->getArgOperand(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); + + NumC = ConstantInt::get(NumC->getType(), Res.quot); + DenC = ConstantInt::get(DenC->getType(), Res.rem); + + // Assume div_t members are laid out in order, as: { T quot, rem; }. + StructType *DivTy = dyn_cast(CI->getType()); + return ConstantStruct::get(DivTy, {NumC, DenC}); +} + Value *LibCallSimplifier::optimizeFFS(CallInst *CI, IRBuilderBase &B) { // ffs(x) -> x != 0 ? (i32)llvm.cttz(x)+1 : 0 Value *Op = CI->getArgOperand(0); @@ -3393,6 +3435,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,394 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; RUN: opt < %s -passes=instcombine -S | FileCheck %s + +%struct.ldiv_t = type { i64, i64 } + +declare { i32, i32 } @div(i32, i32) +declare { i64, i64 } @ldiv(i64, i64) +declare { i64, i64 } @lldiv(i64, i64) +declare { i64, i64 } @imaxdiv(i64, i64) + +declare void @sink({ i32, i32 }) +declare void @lsink({ i64, i64 }) + + +; Verify that div calls with constant arguments are correctly folded. + +define void @fold_div() { +; CHECK-LABEL: @fold_div( +; CHECK-NEXT: call void @sink({ i32, i32 } { i32 5, i32 0 }) +; CHECK-NEXT: call void @sink({ i32, i32 } { i32 2, i32 -1 }) +; CHECK-NEXT: call void @sink({ i32, i32 } zeroinitializer) +; CHECK-NEXT: call void @sink({ i32, i32 } zeroinitializer) +; CHECK-NEXT: call void @sink({ i32, i32 } { i32 1, i32 0 }) +; CHECK-NEXT: call void @sink({ i32, i32 } zeroinitializer) +; CHECK-NEXT: call void @sink({ i32, i32 } { i32 0, i32 1 }) +; CHECK-NEXT: call void @sink({ i32, i32 } { i32 2, i32 0 }) +; CHECK-NEXT: call void @sink({ i32, i32 } { i32 3, i32 2 }) +; CHECK-NEXT: call void @lsink({ i32, i32 } { i32 -2147483647, i32 0 }) +; CHECK-NEXT: call void @lsink({ i32, i32 } { i32 1073741824, i32 0 }) +; CHECK-NEXT: ret void +; + ; Fold div(-5, -1) to { 5, 0 }. + %div_m5_m1 = call { i32, i32 } @div(i32 -5, i32 -1) + call void @sink({ i32, i32 } %div_m5_m1) + + ; Fold div(-5, -2) to { 2, -1 }. + %div_m5_m2 = call { i32, i32 } @div(i32 -5, i32 -2) + call void @sink({ i32, i32 } %div_m5_m2) + + ; Fold div(0, -1) to { 0, 0 }. + %div_0_m1 = call { i32, i32 } @div(i32 0, i32 -1) + call void @sink({ i32, i32 } %div_0_m1) + + ; Fold div(0, 1) to { 0, 0 }. + %div_0_1 = call { i32, i32 } @div(i32 0, i32 1) + call void @sink({ i32, i32 } %div_0_1) + + ; Fold div(1, 1) to { 1, 0 }. + %div_1_1 = call { i32, i32 } @div(i32 1, i32 1) + call void @sink({ i32, i32 } %div_1_1) + + ; Fold div(0, 2) to { 0, 0 }. + %div_0_2 = call { i32, i32 } @div(i32 0, i32 2) + call void @sink({ i32, i32 } %div_0_2) + + ; Fold div(1, 2) to { 0, 1 }. + %div_1_2 = call { i32, i32 } @div(i32 1, i32 2) + call void @sink({ i32, i32 } %div_1_2) + + ; Fold div(2, 1) to { 2, 0 }. + %div_2_1 = call { i32, i32 } @div(i32 2, i32 1) + call void @sink({ i32, i32 } %div_2_1) + + ; Fold div(11, 3) to { 3, 2 }. + %div_11_3 = call { i32, i32 } @div(i32 11, i32 3) + call void @sink({ i32, i32 } %div_11_3) + + ; Fold div(INT_MAX, -1) to { INT_MIN, 0 }. + %div_imax_m1 = call { i32, i32 } @div(i32 2147483647, i32 -1) + call void @lsink({ i32, i32 } %div_imax_m1) + + ; Fold div(INT_MIN, -2) to { 1073741824, 0 }. + %div_imin_m2 = call { i32, i32 } @div(i32 -2147483648, i32 -2) + call void @lsink({ i32, i32 } %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 { i32, i32 } @div(i32 1, i32 0) +; CHECK-NEXT: call void @sink({ i32, i32 } [[DIV_0_0]]) +; CHECK-NEXT: [[DIV_IMIN_M1:%.*]] = call { i32, i32 } @div(i32 -2147483648, i32 -1) +; CHECK-NEXT: call void @sink({ i32, i32 } [[DIV_IMIN_M1]]) +; CHECK-NEXT: ret void +; + ; Do not fold div(1, 0) and the library generate SIGFPE. + %div_0_0 = call { i32, i32 } @div(i32 1, i32 0) + call void @sink({ i32, i32 } %div_0_0) + + ; Do not fold div(INT_MIN, -1), + %div_imin_m1 = call { i32, i32 } @div(i32 -2147483648, i32 -1) + call void @sink({ i32, i32 } %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({ i64, i64 } { i64 5, i64 0 }) +; CHECK-NEXT: call void @lsink({ i64, i64 } { i64 2, i64 -1 }) +; CHECK-NEXT: call void @lsink({ i64, i64 } zeroinitializer) +; CHECK-NEXT: call void @lsink({ i64, i64 } zeroinitializer) +; CHECK-NEXT: call void @lsink({ i64, i64 } { i64 1, i64 0 }) +; CHECK-NEXT: call void @lsink({ i64, i64 } zeroinitializer) +; CHECK-NEXT: call void @lsink({ i64, i64 } { i64 0, i64 1 }) +; CHECK-NEXT: call void @lsink({ i64, i64 } { i64 2, i64 0 }) +; CHECK-NEXT: call void @lsink({ i64, i64 } { i64 3, i64 2 }) +; CHECK-NEXT: call void @lsink({ i64, i64 } { i64 2147483648, i64 0 }) +; CHECK-NEXT: call void @lsink({ i64, i64 } { i64 9223372036854775807, i64 0 }) +; CHECK-NEXT: call void @lsink({ i64, i64 } { i64 4611686018427387904, i64 0 }) +; CHECK-NEXT: call void @lsink({ i64, i64 } { i64 -9223372036854775807, i64 0 }) +; CHECK-NEXT: ret void +; + ; Fold div(-5, -1) to { 5, 0 }. + %div_m5_m1 = call { i64, i64 } @ldiv(i64 -5, i64 -1) + call void @lsink({ i64, i64 } %div_m5_m1) + + ; Fold div(-5, -2) to { 2, -1 }. + %div_m5_m2 = call { i64, i64 } @ldiv(i64 -5, i64 -2) + call void @lsink({ i64, i64 } %div_m5_m2) + + ; Fold div(0, -1) to { 0, 0 }. + %div_0_m1 = call { i64, i64 } @ldiv(i64 0, i64 -1) + call void @lsink({ i64, i64 } %div_0_m1) + + ; Fold div(0, 1) to { 0, 0 }. + %div_0_1 = call { i64, i64 } @ldiv(i64 0, i64 1) + call void @lsink({ i64, i64 } %div_0_1) + + ; Fold div(1, 1) to { 1, 0 }. + %div_1_1 = call { i64, i64 } @ldiv(i64 1, i64 1) + call void @lsink({ i64, i64 } %div_1_1) + + ; Fold div(0, 2) to { 0, 0 }. + %div_0_2 = call { i64, i64 } @ldiv(i64 0, i64 2) + call void @lsink({ i64, i64 } %div_0_2) + + ; Fold div(1, 2) to { 0, 1 }. + %div_1_2 = call { i64, i64 } @ldiv(i64 1, i64 2) + call void @lsink({ i64, i64 } %div_1_2) + + ; Fold div(2, 1) to { 2, 0 }. + %div_2_1 = call { i64, i64 } @ldiv(i64 2, i64 1) + call void @lsink({ i64, i64 } %div_2_1) + + ; Fold div(11, 3) to { 3, 2 }. + %div_11_3 = call { i64, i64 } @ldiv(i64 11, i64 3) + call void @lsink({ i64, i64 } %div_11_3) + + ; Fold ldiv(INT_MIN, -1) to { INT_MAX, 0 }. + %div_imin_m1 = call { i64, i64 } @ldiv(i64 -2147483648, i64 -1) + call void @lsink({ i64, i64 } %div_imin_m1) + + ; Fold ldiv(LONG_MIN + 1, -1) to { }. + %div_iminp1_m1 = call { i64, i64 } @ldiv(i64 -9223372036854775807, i64 -1) + call void @lsink({ i64, i64 } %div_iminp1_m1) + + ; Fold ldiv(LONG_MIN, -2) to { 4611686018427387904, 0 }. + %div_imin_m2 = call { i64, i64 } @ldiv(i64 -9223372036854775808, i64 -2) + call void @lsink({ i64, i64 } %div_imin_m2) + + ; Fold ldiv(LONG_MAX, -1) to { LONG_MIN, 0 }. + %div_imax_m1 = call { i64, i64 } @ldiv(i64 9223372036854775807, i64 -1) + call void @lsink({ i64, i64 } %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 { i64, i64 } @ldiv(i64 1, i64 0) +; CHECK-NEXT: call void @lsink({ i64, i64 } [[DIV_0_0]]) +; CHECK-NEXT: [[DIV_IMIN_M1:%.*]] = call { i64, i64 } @ldiv(i64 -9223372036854775808, i64 -1) +; CHECK-NEXT: call void @lsink({ i64, i64 } [[DIV_IMIN_M1]]) +; CHECK-NEXT: ret void +; + ; Do not fold ldiv(1, 0) and the library generate SIGFPE. + %div_0_0 = call { i64, i64 } @ldiv(i64 1, i64 0) + call void @lsink({ i64, i64 } %div_0_0) + + ; Do not fold ldiv(LONG_MIN, -1). + %div_imin_m1 = call { i64, i64 } @ldiv(i64 -9223372036854775808, i64 -1) + call void @lsink({ i64, i64 } %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({ i64, i64 } { i64 5, i64 0 }) +; CHECK-NEXT: call void @lsink({ i64, i64 } { i64 2, i64 -1 }) +; CHECK-NEXT: call void @lsink({ i64, i64 } zeroinitializer) +; CHECK-NEXT: call void @lsink({ i64, i64 } zeroinitializer) +; CHECK-NEXT: call void @lsink({ i64, i64 } { i64 1, i64 0 }) +; CHECK-NEXT: call void @lsink({ i64, i64 } zeroinitializer) +; CHECK-NEXT: call void @lsink({ i64, i64 } { i64 0, i64 1 }) +; CHECK-NEXT: call void @lsink({ i64, i64 } { i64 2, i64 0 }) +; CHECK-NEXT: call void @lsink({ i64, i64 } { i64 3, i64 2 }) +; CHECK-NEXT: call void @lsink({ i64, i64 } { i64 2147483648, i64 0 }) +; CHECK-NEXT: call void @lsink({ i64, i64 } { i64 9223372036854775807, i64 0 }) +; CHECK-NEXT: call void @lsink({ i64, i64 } { i64 4611686018427387904, i64 0 }) +; CHECK-NEXT: call void @lsink({ i64, i64 } { i64 -9223372036854775807, i64 0 }) +; CHECK-NEXT: ret void +; + ; Fold lldiv(-5, -1) to { 5, 0 }. + %div_m5_m1 = call { i64, i64 } @lldiv(i64 -5, i64 -1) + call void @lsink({ i64, i64 } %div_m5_m1) + + ; Fold lldiv(-5, -2) to { 2, -1 }. + %div_m5_m2 = call { i64, i64 } @lldiv(i64 -5, i64 -2) + call void @lsink({ i64, i64 } %div_m5_m2) + + ; Fold lldiv(0, -1) to { 0, 0 }. + %div_0_m1 = call { i64, i64 } @lldiv(i64 0, i64 -1) + call void @lsink({ i64, i64 } %div_0_m1) + + ; Fold lldiv(0, 1) to { 0, 0 }. + %div_0_1 = call { i64, i64 } @lldiv(i64 0, i64 1) + call void @lsink({ i64, i64 } %div_0_1) + + ; Fold lldiv(1, 1) to { 1, 0 }. + %div_1_1 = call { i64, i64 } @lldiv(i64 1, i64 1) + call void @lsink({ i64, i64 } %div_1_1) + + ; Fold lldiv(0, 2) to { 0, 0 }. + %div_0_2 = call { i64, i64 } @lldiv(i64 0, i64 2) + call void @lsink({ i64, i64 } %div_0_2) + + ; Fold lldiv(1, 2) to { 0, 1 }. + %div_1_2 = call { i64, i64 } @lldiv(i64 1, i64 2) + call void @lsink({ i64, i64 } %div_1_2) + + ; Fold lldiv(2, 1) to { 2, 0 }. + %div_2_1 = call { i64, i64 } @lldiv(i64 2, i64 1) + call void @lsink({ i64, i64 } %div_2_1) + + ; Fold lldiv(11, 3) to { 3, 2 }. + %div_11_3 = call { i64, i64 } @lldiv(i64 11, i64 3) + call void @lsink({ i64, i64 } %div_11_3) + + ; Fold lldiv(INT_MIN, -1) to { INT_MAX, 0 }. + %div_imin_m1 = call { i64, i64 } @lldiv(i64 -2147483648, i64 -1) + call void @lsink({ i64, i64 } %div_imin_m1) + + ; Fold lldiv(LLONG_MIN + 1, -1) to { }. + %div_iminp1_m1 = call { i64, i64 } @lldiv(i64 -9223372036854775807, i64 -1) + call void @lsink({ i64, i64 } %div_iminp1_m1) + + ; Fold lldiv(LLONG_MIN, -2) to { 4611686018427387904, 0 }. + %div_imin_m2 = call { i64, i64 } @lldiv(i64 -9223372036854775808, i64 -2) + call void @lsink({ i64, i64 } %div_imin_m2) + + ; Fold lldiv(LLONG_MAX, -1) to { LLONG_MIN, 0 }. + %div_imax_m1 = call { i64, i64 } @lldiv(i64 9223372036854775807, i64 -1) + call void @lsink({ i64, i64 } %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 { i64, i64 } @lldiv(i64 1, i64 0) +; CHECK-NEXT: call void @lsink({ i64, i64 } [[DIV_0_0]]) +; CHECK-NEXT: [[DIV_IMIN_M1:%.*]] = call { i64, i64 } @lldiv(i64 -9223372036854775808, i64 -1) +; CHECK-NEXT: call void @lsink({ i64, i64 } [[DIV_IMIN_M1]]) +; CHECK-NEXT: ret void +; + ; Do not fold lldiv(1, 0) and the library generate SIGFPE. + %div_0_0 = call { i64, i64 } @lldiv(i64 1, i64 0) + call void @lsink({ i64, i64 } %div_0_0) + + ; Do not fold lldiv(LONG_MIN, -1). + %div_imin_m1 = call { i64, i64 } @lldiv(i64 -9223372036854775808, i64 -1) + call void @lsink({ i64, i64 } %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({ i64, i64 } { i64 5, i64 0 }) +; CHECK-NEXT: call void @lsink({ i64, i64 } { i64 2, i64 -1 }) +; CHECK-NEXT: call void @lsink({ i64, i64 } zeroinitializer) +; CHECK-NEXT: call void @lsink({ i64, i64 } zeroinitializer) +; CHECK-NEXT: call void @lsink({ i64, i64 } { i64 1, i64 0 }) +; CHECK-NEXT: call void @lsink({ i64, i64 } zeroinitializer) +; CHECK-NEXT: call void @lsink({ i64, i64 } { i64 0, i64 1 }) +; CHECK-NEXT: call void @lsink({ i64, i64 } { i64 2, i64 0 }) +; CHECK-NEXT: call void @lsink({ i64, i64 } { i64 3, i64 2 }) +; CHECK-NEXT: call void @lsink({ i64, i64 } { i64 2147483648, i64 0 }) +; CHECK-NEXT: call void @lsink({ i64, i64 } { i64 4611686018427387904, i64 0 }) +; CHECK-NEXT: call void @lsink({ i64, i64 } { i64 9223372036854775807, i64 0 }) +; CHECK-NEXT: call void @lsink({ i64, i64 } { i64 -9223372036854775807, i64 0 }) +; CHECK-NEXT: ret void +; + ; Fold imaxdiv(-5, -1) to { 5, 0 }. + %div_m5_m1 = call { i64, i64 } @imaxdiv(i64 -5, i64 -1) + call void @lsink({ i64, i64 } %div_m5_m1) + + ; Fold imaxdiv(-5, -2) to { 2, -1 }. + %div_m5_m2 = call { i64, i64 } @imaxdiv(i64 -5, i64 -2) + call void @lsink({ i64, i64 } %div_m5_m2) + + ; Fold imaxdiv(0, -1) to { 0, 0 }. + %div_0_m1 = call { i64, i64 } @imaxdiv(i64 0, i64 -1) + call void @lsink({ i64, i64 } %div_0_m1) + + ; Fold imaxdiv(0, 1) to { 0, 0 }. + %div_0_1 = call { i64, i64 } @imaxdiv(i64 0, i64 1) + call void @lsink({ i64, i64 } %div_0_1) + + ; Fold imaxdiv(1, 1) to { 1, 0 }. + %div_1_1 = call { i64, i64 } @imaxdiv(i64 1, i64 1) + call void @lsink({ i64, i64 } %div_1_1) + + ; Fold imaxdiv(0, 2) to { 0, 0 }. + %div_0_2 = call { i64, i64 } @imaxdiv(i64 0, i64 2) + call void @lsink({ i64, i64 } %div_0_2) + + ; Fold imaxdiv(1, 2) to { 0, 1 }. + %div_1_2 = call { i64, i64 } @imaxdiv(i64 1, i64 2) + call void @lsink({ i64, i64 } %div_1_2) + + ; Fold imaxdiv(2, 1) to { 2, 0 }. + %div_2_1 = call { i64, i64 } @imaxdiv(i64 2, i64 1) + call void @lsink({ i64, i64 } %div_2_1) + + ; Fold imaxdiv(11, 3) to { 3, 2 }. + %div_11_3 = call { i64, i64 } @imaxdiv(i64 11, i64 3) + call void @lsink({ i64, i64 } %div_11_3) + + ; Fold imaxdiv(INT_MIN, -1) to { INT_MAX, 0 }. + %div_imin_m1 = call { i64, i64 } @imaxdiv(i64 -2147483648, i64 -1) + call void @lsink({ i64, i64 } %div_imin_m1) + + ; Fold imaxdiv(INTMAX_MIN, -2) to { 4611686018427387904, 0 }. + %div_imin_m2 = call { i64, i64 } @imaxdiv(i64 -9223372036854775808, i64 -2) + call void @lsink({ i64, i64 } %div_imin_m2) + + ; Fold imaxdiv(INTMAX_MIN + 1, -1) to { INTMAX_MAX, 0}. + %div_iminp1_m1 = call { i64, i64 } @imaxdiv(i64 -9223372036854775807, i64 -1) + call void @lsink({ i64, i64 } %div_iminp1_m1) + + ; Fold imaxdiv(INTMAX_MAX, -1) to { INTMAX_MIN, 0 }. + %div_imax_m1 = call { i64, i64 } @imaxdiv(i64 9223372036854775807, i64 -1) + call void @lsink({ i64, i64 } %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 { i64, i64 } @imaxdiv(i64 1, i64 0) +; CHECK-NEXT: call void @lsink({ i64, i64 } [[DIV_0_0]]) +; CHECK-NEXT: [[DIV_IMIN_M1:%.*]] = call { i64, i64 } @imaxdiv(i64 -9223372036854775808, i64 -1) +; CHECK-NEXT: call void @lsink({ i64, i64 } [[DIV_IMIN_M1]]) +; CHECK-NEXT: ret void +; + ; Do not fold imaxdiv(1, 0) and the library generate SIGFPE. + %div_0_0 = call { i64, i64 } @imaxdiv(i64 1, i64 0) + call void @lsink({ i64, i64 } %div_0_0) + + ; Do not fold imaxdiv(INTMAX_MIN, -1). + %div_imin_m1 = call { i64, i64 } @imaxdiv(i64 -9223372036854775808, i64 -1) + call void @lsink({ i64, i64 } %div_imin_m1) + + ret void +}