Index: include/llvm/Analysis/TargetLibraryInfo.def =================================================================== --- include/llvm/Analysis/TargetLibraryInfo.def +++ include/llvm/Analysis/TargetLibraryInfo.def @@ -616,6 +616,9 @@ /// char *ctermid(char *s); TLI_DEFINE_ENUM_INTERNAL(ctermid) TLI_DEFINE_STRING_INTERNAL("ctermid") +/// div_t div(int numerator, int denominator); +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") @@ -928,9 +931,15 @@ /// long double ldexpl(long double x, int n); TLI_DEFINE_ENUM_INTERNAL(ldexpl) TLI_DEFINE_STRING_INTERNAL("ldexpl") +/// ldiv_t ldiv(long numerator, long denominator); +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 numerator, long long denominator); +TLI_DEFINE_ENUM_INTERNAL(lldiv) +TLI_DEFINE_STRING_INTERNAL("lldiv") /// double log(double x); TLI_DEFINE_ENUM_INTERNAL(log) TLI_DEFINE_STRING_INTERNAL("log") Index: include/llvm/Transforms/Utils/SimplifyLibCalls.h =================================================================== --- include/llvm/Transforms/Utils/SimplifyLibCalls.h +++ include/llvm/Transforms/Utils/SimplifyLibCalls.h @@ -198,6 +198,7 @@ Value *optimizeIsAscii(CallInst *CI, IRBuilder<> &B); Value *optimizeToAscii(CallInst *CI, IRBuilder<> &B); Value *optimizeAtoi(CallInst *CI, IRBuilder<> &B); + Value *optimizeDiv(CallInst *CI, IRBuilder<> &B); Value *optimizeStrtol(CallInst *CI, IRBuilder<> &B); // Formatting and IO Library Call Optimizations Index: lib/Analysis/TargetLibraryInfo.cpp =================================================================== --- lib/Analysis/TargetLibraryInfo.cpp +++ lib/Analysis/TargetLibraryInfo.cpp @@ -1286,6 +1286,12 @@ case LibFunc_coshl: case LibFunc_coshl_finite: case LibFunc_cosl: + return (NumParams == 1 && FTy.getReturnType()->isFloatingPointTy() && + FTy.getReturnType() == FTy.getParamType(0)); + case LibFunc_div: + return (NumParams == 2 && FTy.getReturnType()->isIntegerTy() && + FTy.getParamType(0)->isIntegerTy() && + FTy.getParamType(1)->isIntegerTy()); case LibFunc_exp10: case LibFunc_exp10_finite: case LibFunc_exp10f: @@ -1313,6 +1319,11 @@ case LibFunc_floor: case LibFunc_floorf: case LibFunc_floorl: + case LibFunc_ldiv: + case LibFunc_lldiv: + return (NumParams == 2 && FTy.getReturnType()->isAggregateType() && + FTy.getParamType(0)->isIntegerTy() && + FTy.getParamType(1)->isIntegerTy()); case LibFunc_log10: case LibFunc_log10_finite: case LibFunc_log10f: Index: lib/Transforms/Utils/BuildLibCalls.cpp =================================================================== --- lib/Transforms/Utils/BuildLibCalls.cpp +++ lib/Transforms/Utils/BuildLibCalls.cpp @@ -150,6 +150,15 @@ Changed |= setNonLazyBind(F); switch (TheLibFunc) { + case LibFunc_div: + case LibFunc_ldiv: + case LibFunc_lldiv: + Changed |= setDoesNotThrow(F); + Changed |= setDoesNotCapture(F, 0); + Changed |= setOnlyReadsMemory(F, 0); + Changed |= setDoesNotCapture(F, 1); + Changed |= setOnlyReadsMemory(F, 1); + return Changed; case LibFunc_strlen: case LibFunc_wcslen: Changed |= setOnlyReadsMemory(F); Index: lib/Transforms/Utils/SimplifyLibCalls.cpp =================================================================== --- lib/Transforms/Utils/SimplifyLibCalls.cpp +++ lib/Transforms/Utils/SimplifyLibCalls.cpp @@ -1990,6 +1990,16 @@ return convertStrToNumber(CI, Str, 10); } +Value *LibCallSimplifier::optimizeDiv(CallInst *CI, IRBuilder<> &B) { + // TODO handle div + Value *Op0 = CI->getArgOperand(0); + Value *Op1 = CI->getArgOperand(1); + Value *V = B.CreateInsertValue(UndefValue::get(CI->getType()), + B.CreateSDiv(Op0, Op1), 0); + V = B.CreateInsertValue(V, B.CreateSRem(Op0, Op1), 1); + return V; +} + Value *LibCallSimplifier::optimizeStrtol(CallInst *CI, IRBuilder<> &B) { StringRef Str; if (!getConstantStringInfo(CI->getArgOperand(0), Str)) @@ -2780,6 +2790,11 @@ case LibFunc_atol: case LibFunc_atoll: return optimizeAtoi(CI, Builder); + // TODO + // case LibFunc_div: + case LibFunc_ldiv: + case LibFunc_lldiv: + return optimizeDiv(CI, Builder); case LibFunc_strtol: case LibFunc_strtoll: return optimizeStrtol(CI, Builder); Index: test/Transforms/InstCombine/div-call.ll =================================================================== --- test/Transforms/InstCombine/div-call.ll +++ test/Transforms/InstCombine/div-call.ll @@ -0,0 +1,115 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; RUN: opt < %s -instcombine -S | FileCheck %s + +declare i64 @div(i32, i32) +declare { i64, i64 } @ldiv(i64, i64) +declare { i64, i64 } @lldiv(i64, i64) +declare void @use(i64) + +define i64 @div_qout_rem(i32 %x, i32 %y) { +; CHECK-LABEL: @div_qout_rem( +; CHECK-NEXT: [[DIVREM:%.*]] = tail call i64 @div(i32 [[X:%.*]], i32 [[Y:%.*]]) +; CHECK-NEXT: ret i64 [[DIVREM]] +; + %divrem = tail call i64 @div(i32 %x, i32 %y) + ret i64 %divrem +} + +define i64 @div_qout_rem_multiuse(i32 %x, i32 %y) { +; CHECK-LABEL: @div_qout_rem_multiuse( +; CHECK-NEXT: [[DIVREM:%.*]] = tail call i64 @div(i32 [[X:%.*]], i32 [[Y:%.*]]) +; CHECK-NEXT: tail call void @use(i64 [[DIVREM]]) +; CHECK-NEXT: ret i64 [[DIVREM]] +; + %divrem = tail call i64 @div(i32 %x, i32 %y) + tail call void @use(i64 %divrem) + ret i64 %divrem +} + +define i32 @div_qout(i32 %x, i32 %y) { +; CHECK-LABEL: @div_qout( +; CHECK-NEXT: [[DIVREM:%.*]] = tail call i64 @div(i32 [[X:%.*]], i32 [[Y:%.*]]) +; CHECK-NEXT: [[QUOT:%.*]] = trunc i64 [[DIVREM]] to i32 +; CHECK-NEXT: ret i32 [[QUOT]] +; + %divrem = tail call i64 @div(i32 %x, i32 %y) + %quot = trunc i64 %divrem to i32 + ret i32 %quot +} + +define i32 @div_rem(i32 %x, i32 %y) { +; CHECK-LABEL: @div_rem( +; CHECK-NEXT: [[DIVREM:%.*]] = tail call i64 @div(i32 [[X:%.*]], i32 [[Y:%.*]]) +; CHECK-NEXT: [[L:%.*]] = lshr i64 [[DIVREM]], 32 +; CHECK-NEXT: [[REM:%.*]] = trunc i64 [[L]] to i32 +; CHECK-NEXT: ret i32 [[REM]] +; + %divrem = tail call i64 @div(i32 %x, i32 %y) + %l = lshr i64 %divrem, 32 + %rem = trunc i64 %l to i32 + ret i32 %rem +} + +define { i64, i64 } @ldiv_qout_rem(i64 %x, i64 %y) { +; CHECK-LABEL: @ldiv_qout_rem( +; CHECK-NEXT: [[TMP1:%.*]] = sdiv i64 [[X:%.*]], [[Y:%.*]] +; CHECK-NEXT: [[TMP2:%.*]] = insertvalue { i64, i64 } undef, i64 [[TMP1]], 0 +; CHECK-NEXT: [[TMP3:%.*]] = srem i64 [[X]], [[Y]] +; CHECK-NEXT: [[TMP4:%.*]] = insertvalue { i64, i64 } [[TMP2]], i64 [[TMP3]], 1 +; CHECK-NEXT: ret { i64, i64 } [[TMP4]] +; + %divrem = tail call { i64, i64 } @ldiv(i64 %x, i64 %y) + ret { i64, i64 } %divrem +} + +define i64 @ldiv_qout(i64 %x, i64 %y) { +; CHECK-LABEL: @ldiv_qout( +; CHECK-NEXT: [[TMP1:%.*]] = sdiv i64 [[X:%.*]], [[Y:%.*]] +; CHECK-NEXT: ret i64 [[TMP1]] +; + %divrem = tail call { i64, i64 } @ldiv(i64 %x, i64 %y) + %quot = extractvalue { i64, i64 } %divrem, 0 + ret i64 %quot +} + +define i64 @ldiv_rem(i64 %x, i64 %y) { +; CHECK-LABEL: @ldiv_rem( +; CHECK-NEXT: [[TMP1:%.*]] = srem i64 [[X:%.*]], [[Y:%.*]] +; CHECK-NEXT: ret i64 [[TMP1]] +; + %divrem = tail call { i64, i64 } @ldiv(i64 %x, i64 %y) + %rem = extractvalue { i64, i64 } %divrem, 1 + ret i64 %rem +} + +define { i64, i64 } @lldiv_qout_rem(i64 %x, i64 %y) { +; CHECK-LABEL: @lldiv_qout_rem( +; CHECK-NEXT: [[TMP1:%.*]] = sdiv i64 [[X:%.*]], [[Y:%.*]] +; CHECK-NEXT: [[TMP2:%.*]] = insertvalue { i64, i64 } undef, i64 [[TMP1]], 0 +; CHECK-NEXT: [[TMP3:%.*]] = srem i64 [[X]], [[Y]] +; CHECK-NEXT: [[TMP4:%.*]] = insertvalue { i64, i64 } [[TMP2]], i64 [[TMP3]], 1 +; CHECK-NEXT: ret { i64, i64 } [[TMP4]] +; + %divrem = tail call { i64, i64 } @lldiv(i64 %x, i64 %y) + ret { i64, i64 } %divrem +} + +define i64 @lldiv_qout(i64 %x, i64 %y) { +; CHECK-LABEL: @lldiv_qout( +; CHECK-NEXT: [[TMP1:%.*]] = sdiv i64 [[X:%.*]], [[Y:%.*]] +; CHECK-NEXT: ret i64 [[TMP1]] +; + %divrem = tail call { i64, i64 } @lldiv(i64 %x, i64 %y) + %quot = extractvalue { i64, i64 } %divrem, 0 + ret i64 %quot +} + +define i64 @lldiv_rem(i64 %x, i64 %y) { +; CHECK-LABEL: @lldiv_rem( +; CHECK-NEXT: [[TMP1:%.*]] = srem i64 [[X:%.*]], [[Y:%.*]] +; CHECK-NEXT: ret i64 [[TMP1]] +; + %divrem = tail call { i64, i64 } @lldiv(i64 %x, i64 %y) + %rem = extractvalue { i64, i64 } %divrem, 1 + ret i64 %rem +} Index: unittests/Analysis/TargetLibraryInfoTest.cpp =================================================================== --- unittests/Analysis/TargetLibraryInfoTest.cpp +++ unittests/Analysis/TargetLibraryInfoTest.cpp @@ -139,6 +139,7 @@ "declare float @coshf(float)\n" "declare x86_fp80 @coshl(x86_fp80)\n" "declare x86_fp80 @cosl(x86_fp80)\n" + "declare i64 @div(i32, i32)\n" "declare i8* @ctermid(i8*)\n" "declare double @exp(double)\n" "declare double @exp2(double)\n"