https://github.com/Magnushst updated 
https://github.com/llvm/llvm-project/pull/215868

From 4288af13448f6b23ea2e379017a69e168384c06a Mon Sep 17 00:00:00 2001
From: Magnushst <[email protected]>
Date: Thu, 13 Aug 2026 06:57:03 +0200
Subject: [PATCH 1/2] [InstCombine] Add baseline tests for div-family libcalls

---
 clang/test/CodeGen/div-builtins.c             | 50 ++++++++++
 .../Transforms/InstCombine/div-libcalls.ll    | 99 +++++++++++++++++++
 2 files changed, 149 insertions(+)
 create mode 100644 clang/test/CodeGen/div-builtins.c
 create mode 100644 llvm/test/Transforms/InstCombine/div-libcalls.ll

diff --git a/clang/test/CodeGen/div-builtins.c 
b/clang/test/CodeGen/div-builtins.c
new file mode 100644
index 0000000000000..b82db6467bef0
--- /dev/null
+++ b/clang/test/CodeGen/div-builtins.c
@@ -0,0 +1,50 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -O2 -emit-llvm -o - %s | 
FileCheck --check-prefix=OPT %s
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -O2 -emit-llvm \
+// RUN:   -fno-builtin-div -fno-builtin-ldiv -fno-builtin-lldiv -o - %s | \
+// RUN:   FileCheck --check-prefix=DISABLED %s
+
+typedef struct {
+  int quot;
+  int rem;
+} div_t;
+
+typedef struct {
+  long quot;
+  long rem;
+} ldiv_t;
+
+typedef struct {
+  long long quot;
+  long long rem;
+} lldiv_t;
+
+div_t div(int, int);
+ldiv_t ldiv(long, long);
+lldiv_t lldiv(long long, long long);
+
+div_t test_div(int numer, int denom) {
+  return div(numer, denom);
+}
+
+// OPT-LABEL: define{{.*}} i64 @test_div(
+// OPT: call i64 @div(
+// DISABLED-LABEL: define{{.*}} i64 @test_div(
+// DISABLED: call i64 @div(
+
+ldiv_t test_ldiv(long numer, long denom) {
+  return ldiv(numer, denom);
+}
+
+// OPT-LABEL: define{{.*}} { i64, i64 } @test_ldiv(
+// OPT: call { i64, i64 } @ldiv(
+// DISABLED-LABEL: define{{.*}} { i64, i64 } @test_ldiv(
+// DISABLED: call { i64, i64 } @ldiv(
+
+lldiv_t test_lldiv(long long numer, long long denom) {
+  return lldiv(numer, denom);
+}
+
+// OPT-LABEL: define{{.*}} { i64, i64 } @test_lldiv(
+// OPT: call { i64, i64 } @lldiv(
+// DISABLED-LABEL: define{{.*}} { i64, i64 } @test_lldiv(
+// DISABLED: call { i64, i64 } @lldiv(
diff --git a/llvm/test/Transforms/InstCombine/div-libcalls.ll 
b/llvm/test/Transforms/InstCombine/div-libcalls.ll
new file mode 100644
index 0000000000000..7b946ea58c22b
--- /dev/null
+++ b/llvm/test/Transforms/InstCombine/div-libcalls.ll
@@ -0,0 +1,99 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py 
UTC_ARGS: --version 6
+; RUN: opt -S -passes=instcombine -data-layout=e-p:64:64 %s | FileCheck %s 
--check-prefixes=CHECK,LITTLE
+; RUN: opt -S -passes=instcombine -data-layout=E-p:64:64 %s | FileCheck %s 
--check-prefixes=CHECK,BIG
+
+%div_sret = type { i32, i32 }
+
+; The LLVM mangling escape lets one module exercise incompatible ABI forms
+; that all resolve to the same libcall name.
+declare i64 @div(i32, i32)
+declare { i64 } @"\01div"(i32, i32)
+declare { i64, i64 } @ldiv(i64, i64)
+declare void @"\01ldiv"(ptr sret(%div_sret), i32, i32)
+declare [2 x i64] @lldiv(i64, i64)
+declare { i32, i64 } @"\01lldiv"(i64, i64)
+
+define i64 @div_packed(i32 %numer, i32 %denom) {
+; CHECK-LABEL: define i64 @div_packed(
+; CHECK-SAME: i32 [[NUMER:%.*]], i32 [[DENOM:%.*]]) {
+; CHECK-NEXT:    [[RESULT:%.*]] = call i64 @div(i32 [[NUMER]], i32 [[DENOM]])
+; CHECK-NEXT:    ret i64 [[RESULT]]
+;
+  %result = call i64 @div(i32 %numer, i32 %denom)
+  ret i64 %result
+}
+
+define { i64 } @div_packed_wrapper(i32 %numer, i32 %denom) {
+; CHECK-LABEL: define { i64 } @div_packed_wrapper(
+; CHECK-SAME: i32 [[NUMER:%.*]], i32 [[DENOM:%.*]]) {
+; CHECK-NEXT:    [[RESULT:%.*]] = call { i64 } @"\01div"(i32 [[NUMER]], i32 
[[DENOM]])
+; CHECK-NEXT:    ret { i64 } [[RESULT]]
+;
+  %result = call { i64 } @"\01div"(i32 %numer, i32 %denom)
+  ret { i64 } %result
+}
+
+define { i64, i64 } @ldiv_struct(i64 %numer, i64 %denom) {
+; CHECK-LABEL: define { i64, i64 } @ldiv_struct(
+; CHECK-SAME: i64 [[NUMER:%.*]], i64 [[DENOM:%.*]]) {
+; CHECK-NEXT:    [[DIV_REM_INSERT:%.*]] = call { i64, i64 } @ldiv(i64 
[[NUMER]], i64 [[DENOM]])
+; CHECK-NEXT:    ret { i64, i64 } [[DIV_REM_INSERT]]
+;
+  %result = call { i64, i64 } @ldiv(i64 %numer, i64 %denom)
+  ret { i64, i64 } %result
+}
+
+define [2 x i64] @lldiv_array(i64 %numer, i64 %denom) {
+; CHECK-LABEL: define [2 x i64] @lldiv_array(
+; CHECK-SAME: i64 [[NUMER:%.*]], i64 [[DENOM:%.*]]) {
+; CHECK-NEXT:    [[DIV_REM_INSERT:%.*]] = call [2 x i64] @lldiv(i64 [[NUMER]], 
i64 [[DENOM]])
+; CHECK-NEXT:    ret [2 x i64] [[DIV_REM_INSERT]]
+;
+  %result = call [2 x i64] @lldiv(i64 %numer, i64 %denom)
+  ret [2 x i64] %result
+}
+
+define void @ldiv_sret(ptr %result, i32 %numer, i32 %denom) {
+; CHECK-LABEL: define void @ldiv_sret(
+; CHECK-SAME: ptr [[RESULT:%.*]], i32 [[NUMER:%.*]], i32 [[DENOM:%.*]]) {
+; CHECK-NEXT:    call void @"\01ldiv"(ptr sret([[DIV_SRET:%.*]]) [[RESULT]], 
i32 [[NUMER]], i32 [[DENOM]])
+; CHECK-NEXT:    ret void
+;
+  call void @"\01ldiv"(ptr sret(%div_sret) %result, i32 %numer, i32 %denom)
+  ret void
+}
+
+define { i32, i64 } @invalid_lldiv_return(i64 %numer, i64 %denom) {
+; CHECK-LABEL: define { i32, i64 } @invalid_lldiv_return(
+; CHECK-SAME: i64 [[NUMER:%.*]], i64 [[DENOM:%.*]]) {
+; CHECK-NEXT:    [[RESULT:%.*]] = call { i32, i64 } @"\01lldiv"(i64 [[NUMER]], 
i64 [[DENOM]])
+; CHECK-NEXT:    ret { i32, i64 } [[RESULT]]
+;
+  %result = call { i32, i64 } @"\01lldiv"(i64 %numer, i64 %denom)
+  ret { i32, i64 } %result
+}
+
+define i32 @invalid_call_type(i32 %numer, i32 %denom) {
+; CHECK-LABEL: define i32 @invalid_call_type(
+; CHECK-SAME: i32 [[NUMER:%.*]], i32 [[DENOM:%.*]]) {
+; CHECK-NEXT:    [[RESULT:%.*]] = call i32 @div(i32 [[NUMER]], i32 [[DENOM]])
+; CHECK-NEXT:    ret i32 [[RESULT]]
+;
+  %result = call i32 @div(i32 %numer, i32 %denom)
+  ret i32 %result
+}
+
+define i64 @no_builtin(i32 %numer, i32 %denom) {
+; CHECK-LABEL: define i64 @no_builtin(
+; CHECK-SAME: i32 [[NUMER:%.*]], i32 [[DENOM:%.*]]) {
+; CHECK-NEXT:    [[RESULT:%.*]] = call i64 @div(i32 [[NUMER]], i32 [[DENOM]]) 
#[[ATTR0:[0-9]+]]
+; CHECK-NEXT:    ret i64 [[RESULT]]
+;
+  %result = call i64 @div(i32 %numer, i32 %denom) #0
+  ret i64 %result
+}
+
+attributes #0 = { nobuiltin }
+;; NOTE: These prefixes are unused and the list is autogenerated. Do not add 
tests below this line:
+; BIG: {{.*}}
+; LITTLE: {{.*}}

From 871425710ec98acf6f89ca90fd7a5531804e7824 Mon Sep 17 00:00:00 2001
From: Magnushst <[email protected]>
Date: Thu, 13 Aug 2026 06:57:52 +0200
Subject: [PATCH 2/2] [Clang][InstCombine] Recognise div/ldiv/lldiv libcalls

---
 clang/lib/Frontend/CompilerInvocation.cpp     |  8 +-
 clang/test/CodeGen/div-builtins.c             | 12 ++-
 .../llvm/Analysis/TargetLibraryInfo.td        |  9 ++
 .../llvm/Transforms/Utils/SimplifyLibCalls.h  |  1 +
 llvm/lib/Analysis/TargetLibraryInfo.cpp       | 84 ++++++++++++++++++-
 .../lib/Transforms/Utils/SimplifyLibCalls.cpp | 64 ++++++++++++++
 .../Transforms/InstCombine/div-libcalls.ll    | 67 +++++++++++----
 .../tools/llvm-tli-checker/ps4-tli-check.yaml | 11 ++-
 .../Analysis/TargetLibraryInfoTest.cpp        |  3 +
 9 files changed, 236 insertions(+), 23 deletions(-)

diff --git a/clang/lib/Frontend/CompilerInvocation.cpp 
b/clang/lib/Frontend/CompilerInvocation.cpp
index 56b39dc672aa6..652a58a268260 100644
--- a/clang/lib/Frontend/CompilerInvocation.cpp
+++ b/clang/lib/Frontend/CompilerInvocation.cpp
@@ -923,7 +923,13 @@ static void parseAnalyzerConfigs(AnalyzerOptions &AnOpts,
 static void getAllNoBuiltinFuncValues(ArgList &Args,
                                       std::vector<std::string> &Funcs) {
   std::vector<std::string> Values = Args.getAllArgValues(OPT_fno_builtin_);
-  auto BuiltinEnd = llvm::partition(Values, Builtin::Context::isBuiltinFunc);
+  auto IsBuiltinFunc = [](StringRef Name) {
+    // These libcalls have target-specific aggregate return types that cannot 
be
+    // represented by Clang's builtin type encoding.
+    return Builtin::Context::isBuiltinFunc(Name) || Name == "div" ||
+           Name == "ldiv" || Name == "lldiv";
+  };
+  auto BuiltinEnd = llvm::partition(Values, IsBuiltinFunc);
   Funcs.insert(Funcs.end(), Values.begin(), BuiltinEnd);
 }
 
diff --git a/clang/test/CodeGen/div-builtins.c 
b/clang/test/CodeGen/div-builtins.c
index b82db6467bef0..6b7f12e46b05f 100644
--- a/clang/test/CodeGen/div-builtins.c
+++ b/clang/test/CodeGen/div-builtins.c
@@ -27,7 +27,9 @@ div_t test_div(int numer, int denom) {
 }
 
 // OPT-LABEL: define{{.*}} i64 @test_div(
-// OPT: call i64 @div(
+// OPT: sdiv i32
+// OPT: srem i32
+// OPT-NOT: call
 // DISABLED-LABEL: define{{.*}} i64 @test_div(
 // DISABLED: call i64 @div(
 
@@ -36,7 +38,9 @@ ldiv_t test_ldiv(long numer, long denom) {
 }
 
 // OPT-LABEL: define{{.*}} { i64, i64 } @test_ldiv(
-// OPT: call { i64, i64 } @ldiv(
+// OPT: sdiv i64
+// OPT: srem i64
+// OPT-NOT: call
 // DISABLED-LABEL: define{{.*}} { i64, i64 } @test_ldiv(
 // DISABLED: call { i64, i64 } @ldiv(
 
@@ -45,6 +49,8 @@ lldiv_t test_lldiv(long long numer, long long denom) {
 }
 
 // OPT-LABEL: define{{.*}} { i64, i64 } @test_lldiv(
-// OPT: call { i64, i64 } @lldiv(
+// OPT: sdiv i64
+// OPT: srem i64
+// OPT-NOT: call
 // DISABLED-LABEL: define{{.*}} { i64, i64 } @test_lldiv(
 // DISABLED: call { i64, i64 } @lldiv(
diff --git a/llvm/include/llvm/Analysis/TargetLibraryInfo.td 
b/llvm/include/llvm/Analysis/TargetLibraryInfo.td
index 6b17e70b87f55..fd13ca95eabb5 100644
--- a/llvm/include/llvm/Analysis/TargetLibraryInfo.td
+++ b/llvm/include/llvm/Analysis/TargetLibraryInfo.td
@@ -726,6 +726,9 @@ def cosl : TargetLibCall<"cosl", LDbl, [LDbl]>;
 /// char *ctermid(char *s);
 def ctermid : TargetLibCall<"ctermid", Ptr, [Ptr]>;
 
+/// div_t div(int numer, int denom);
+def div : TargetLibCall<"div", ? /* Checked manually. */>;
+
 /// double erf(double x);
 def erf : TargetLibCall<"erf", Dbl, [Dbl]>;
 
@@ -1092,9 +1095,15 @@ def ldexpf : TargetLibCall<"ldexpf", Flt, [Flt, Int]>;
 /// long double ldexpl(long double x, int n);
 def ldexpl : TargetLibCall<"ldexpl", LDbl, [LDbl, Int]>;
 
+/// ldiv_t ldiv(long int numer, long int denom);
+def ldiv : TargetLibCall<"ldiv", ? /* Checked manually. */>;
+
 /// long long int llabs(long long int j);
 def llabs : TargetLibCall<"llabs", LLong, [LLong]>;
 
+/// lldiv_t lldiv(long long int numer, long long int denom);
+def lldiv : TargetLibCall<"lldiv", ? /* Checked manually. */>;
+
 /// double log(double x);
 def log : TargetLibCall<"log", Dbl, [Dbl]>;
 
diff --git a/llvm/include/llvm/Transforms/Utils/SimplifyLibCalls.h 
b/llvm/include/llvm/Transforms/Utils/SimplifyLibCalls.h
index 5bdac325b5659..0a306f12da34d 100644
--- a/llvm/include/llvm/Transforms/Utils/SimplifyLibCalls.h
+++ b/llvm/include/llvm/Transforms/Utils/SimplifyLibCalls.h
@@ -222,6 +222,7 @@ class LibCallSimplifier {
   Value *optimizeFFS(CallInst *CI, IRBuilderBase &B);
   Value *optimizeFls(CallInst *CI, IRBuilderBase &B);
   Value *optimizeAbs(CallInst *CI, IRBuilderBase &B);
+  Value *optimizeDiv(CallInst *CI, IRBuilderBase &B);
   Value *optimizeIsDigit(CallInst *CI, IRBuilderBase &B);
   Value *optimizeIsAscii(CallInst *CI, IRBuilderBase &B);
   Value *optimizeToAscii(CallInst *CI, IRBuilderBase &B);
diff --git a/llvm/lib/Analysis/TargetLibraryInfo.cpp 
b/llvm/lib/Analysis/TargetLibraryInfo.cpp
index 763c04b9b06f7..78f0f38f33502 100644
--- a/llvm/lib/Analysis/TargetLibraryInfo.cpp
+++ b/llvm/lib/Analysis/TargetLibraryInfo.cpp
@@ -1079,12 +1079,82 @@ static bool isValidProtoForSizeReturningNew(const 
FunctionType &FTy, LibFunc F,
   return FTy.getReturnType() == SizedPtrTy;
 }
 
+static bool isValidDivAggregateType(Type *Ty, Type *ElementTy) {
+  if (auto *StructTy = dyn_cast<StructType>(Ty))
+    return StructTy->getNumElements() == 2 &&
+           StructTy->getElementType(0) == ElementTy &&
+           StructTy->getElementType(1) == ElementTy;
+
+  if (auto *ArrayTy = dyn_cast<ArrayType>(Ty))
+    return ArrayTy->getNumElements() == 2 &&
+           ArrayTy->getElementType() == ElementTy;
+
+  return false;
+}
+
+static bool isValidDivReturnType(Type *Ty, Type *ElementTy) {
+  if (auto *IntegerTy = dyn_cast<IntegerType>(Ty))
+    return IntegerTy->getBitWidth() == 2 * ElementTy->getIntegerBitWidth();
+
+  if (auto *StructTy = dyn_cast<StructType>(Ty))
+    if (StructTy->getNumElements() == 1)
+      if (auto *IntegerTy = dyn_cast<IntegerType>(StructTy->getElementType(0)))
+        return IntegerTy->getBitWidth() == 2 * ElementTy->getIntegerBitWidth();
+
+  return isValidDivAggregateType(Ty, ElementTy);
+}
+
+static bool isValidProtoForDiv(const FunctionType &FTy, LibFunc F,
+                               unsigned IntBits) {
+  if (FTy.isFunctionVarArg())
+    return false;
+
+  unsigned ArgOffset = 0;
+  if (FTy.getReturnType()->isVoidTy()) {
+    if (FTy.getNumParams() != 3 || !FTy.getParamType(0)->isPointerTy())
+      return false;
+    ArgOffset = 1;
+  } else if (FTy.getNumParams() != 2) {
+    return false;
+  }
+
+  auto *ElementTy = dyn_cast<IntegerType>(FTy.getParamType(ArgOffset));
+  if (!ElementTy || FTy.getParamType(ArgOffset + 1) != ElementTy)
+    return false;
+
+  FuncArgTypeID ElementTypeID;
+  switch (F) {
+  case LibFunc_div:
+    ElementTypeID = Int;
+    break;
+  case LibFunc_ldiv:
+    ElementTypeID = Long;
+    break;
+  case LibFunc_lldiv:
+    ElementTypeID = LLong;
+    break;
+  default:
+    llvm_unreachable("not a div-family libcall");
+  }
+  if (!matchType(ElementTypeID, ElementTy, IntBits, /*SizeTBits=*/0))
+    return false;
+
+  Type *ReturnTy = FTy.getReturnType();
+  if (ReturnTy->isVoidTy())
+    return true;
+  return isValidDivReturnType(ReturnTy, ElementTy);
+}
+
 bool TargetLibraryInfoImpl::isValidProtoForLibFunc(const FunctionType &FTy,
                                                    LibFunc F,
                                                    const Module &M) const {
   unsigned NumParams = FTy.getNumParams();
 
   switch (F) {
+  case LibFunc_div:
+  case LibFunc_ldiv:
+  case LibFunc_lldiv:
+    return isValidProtoForDiv(FTy, F, getIntSize());
     // Special handling for <complex.h> functions:
   case LibFunc_cabs:
   case LibFunc_cabsf:
@@ -1206,7 +1276,19 @@ bool TargetLibraryInfoImpl::getLibFunc(const Function 
&FDecl,
     return false;
 
   F = FDecl.LibFuncCache;
-  return isValidProtoForLibFunc(*FDecl.getFunctionType(), F, *M);
+  if (!isValidProtoForLibFunc(*FDecl.getFunctionType(), F, *M))
+    return false;
+
+  if ((F == LibFunc_div || F == LibFunc_ldiv || F == LibFunc_lldiv) &&
+      FDecl.getReturnType()->isVoidTy()) {
+    const Argument *SRet = FDecl.getArg(0);
+    if (!SRet->hasStructRetAttr())
+      return false;
+    return isValidDivAggregateType(SRet->getParamStructRetType(),
+                                   FDecl.getFunctionType()->getParamType(1));
+  }
+
+  return true;
 }
 
 bool TargetLibraryInfoImpl::getLibFunc(unsigned int Opcode, Type *Ty,
diff --git a/llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp 
b/llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp
index c0140e431ffb6..680901cd3856a 100644
--- a/llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp
+++ b/llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp
@@ -41,6 +41,7 @@
 #include "llvm/Transforms/Utils/SizeOpts.h"
 
 #include <cmath>
+#include <utility>
 
 using namespace llvm;
 using namespace PatternMatch;
@@ -3282,6 +3283,65 @@ Value *LibCallSimplifier::optimizeAbs(CallInst *CI, 
IRBuilderBase &B) {
   return B.CreateSelect(IsNeg, NegX, X);
 }
 
+static Value *createDivResult(IRBuilderBase &B, const DataLayout &DL,
+                              Type *ResultTy, Value *Quot, Value *Rem) {
+  if (auto *IntegerResultTy = dyn_cast<IntegerType>(ResultTy)) {
+    Value *Low = Quot;
+    Value *High = Rem;
+    if (DL.isBigEndian())
+      std::swap(Low, High);
+
+    Low = B.CreateZExt(Low, IntegerResultTy, "div.low");
+    High = B.CreateZExt(High, IntegerResultTy, "div.high");
+    High = B.CreateShl(High, Quot->getType()->getIntegerBitWidth(),
+                       "div.high.shift");
+    return B.CreateOr(Low, High, "div.result");
+  }
+
+  if (auto *StructResultTy = dyn_cast<StructType>(ResultTy);
+      StructResultTy && StructResultTy->getNumElements() == 1) {
+    Value *Packed =
+        createDivResult(B, DL, StructResultTy->getElementType(0), Quot, Rem);
+    return B.CreateInsertValue(PoisonValue::get(ResultTy), Packed, 0,
+                               "div.result.insert");
+  }
+
+  Value *Result = PoisonValue::get(ResultTy);
+  if (isa<StructType, ArrayType>(ResultTy)) {
+    Result = B.CreateInsertValue(Result, Quot, 0, "div.quot.insert");
+    return B.CreateInsertValue(Result, Rem, 1, "div.rem.insert");
+  }
+
+  llvm_unreachable("unexpected div result type");
+}
+
+Value *LibCallSimplifier::optimizeDiv(CallInst *CI, IRBuilderBase &B) {
+  Function *Callee = CI->getCalledFunction();
+  if (!Callee || CI->getFunctionType() != Callee->getFunctionType())
+    return nullptr;
+
+  bool UsesSRet = CI->getType()->isVoidTy();
+  unsigned ArgOffset = UsesSRet ? 1 : 0;
+  if (UsesSRet) {
+    if (!CI->hasStructRetAttr() ||
+        CI->getParamStructRetType(0) != Callee->getParamStructRetType(0))
+      return nullptr;
+  }
+
+  Value *Numer = CI->getArgOperand(ArgOffset);
+  Value *Denom = CI->getArgOperand(ArgOffset + 1);
+  Value *Quot = B.CreateSDiv(Numer, Denom, "div.quot");
+  Value *Rem = B.CreateSRem(Numer, Denom, "div.rem");
+
+  if (!UsesSRet)
+    return createDivResult(B, DL, CI->getType(), Quot, Rem);
+
+  Type *ResultTy = CI->getParamStructRetType(0);
+  Value *Result = createDivResult(B, DL, ResultTy, Quot, Rem);
+  B.CreateStore(Result, CI->getArgOperand(0));
+  return CI;
+}
+
 Value *LibCallSimplifier::optimizeIsDigit(CallInst *CI, IRBuilderBase &B) {
   // isdigit(c) -> (c-'0') <u 10
   Value *Op = CI->getArgOperand(0);
@@ -4316,6 +4376,10 @@ Value *LibCallSimplifier::optimizeCall(CallInst *CI, 
IRBuilderBase &Builder) {
     case LibFunc_labs:
     case LibFunc_llabs:
       return optimizeAbs(CI, Builder);
+    case LibFunc_div:
+    case LibFunc_ldiv:
+    case LibFunc_lldiv:
+      return optimizeDiv(CI, Builder);
     case LibFunc_isdigit:
       return optimizeIsDigit(CI, Builder);
     case LibFunc_isascii:
diff --git a/llvm/test/Transforms/InstCombine/div-libcalls.ll 
b/llvm/test/Transforms/InstCombine/div-libcalls.ll
index 7b946ea58c22b..71943d49b9218 100644
--- a/llvm/test/Transforms/InstCombine/div-libcalls.ll
+++ b/llvm/test/Transforms/InstCombine/div-libcalls.ll
@@ -14,20 +14,52 @@ declare [2 x i64] @lldiv(i64, i64)
 declare { i32, i64 } @"\01lldiv"(i64, i64)
 
 define i64 @div_packed(i32 %numer, i32 %denom) {
-; CHECK-LABEL: define i64 @div_packed(
-; CHECK-SAME: i32 [[NUMER:%.*]], i32 [[DENOM:%.*]]) {
-; CHECK-NEXT:    [[RESULT:%.*]] = call i64 @div(i32 [[NUMER]], i32 [[DENOM]])
-; CHECK-NEXT:    ret i64 [[RESULT]]
+; LITTLE-LABEL: define i64 @div_packed(
+; LITTLE-SAME: i32 [[NUMER:%.*]], i32 [[DENOM:%.*]]) {
+; LITTLE-NEXT:    [[DIV_QUOT:%.*]] = sdiv i32 [[NUMER]], [[DENOM]]
+; LITTLE-NEXT:    [[DIV_REM:%.*]] = srem i32 [[NUMER]], [[DENOM]]
+; LITTLE-NEXT:    [[DIV_LOW:%.*]] = zext i32 [[DIV_QUOT]] to i64
+; LITTLE-NEXT:    [[DIV_HIGH:%.*]] = zext i32 [[DIV_REM]] to i64
+; LITTLE-NEXT:    [[DIV_HIGH_SHIFT:%.*]] = shl nuw i64 [[DIV_HIGH]], 32
+; LITTLE-NEXT:    [[DIV_RESULT:%.*]] = or disjoint i64 [[DIV_HIGH_SHIFT]], 
[[DIV_LOW]]
+; LITTLE-NEXT:    ret i64 [[DIV_RESULT]]
+;
+; BIG-LABEL: define i64 @div_packed(
+; BIG-SAME: i32 [[NUMER:%.*]], i32 [[DENOM:%.*]]) {
+; BIG-NEXT:    [[DIV_QUOT:%.*]] = sdiv i32 [[NUMER]], [[DENOM]]
+; BIG-NEXT:    [[DIV_REM:%.*]] = srem i32 [[NUMER]], [[DENOM]]
+; BIG-NEXT:    [[DIV_LOW:%.*]] = zext i32 [[DIV_REM]] to i64
+; BIG-NEXT:    [[DIV_HIGH:%.*]] = zext i32 [[DIV_QUOT]] to i64
+; BIG-NEXT:    [[DIV_HIGH_SHIFT:%.*]] = shl nuw i64 [[DIV_HIGH]], 32
+; BIG-NEXT:    [[DIV_RESULT:%.*]] = or disjoint i64 [[DIV_HIGH_SHIFT]], 
[[DIV_LOW]]
+; BIG-NEXT:    ret i64 [[DIV_RESULT]]
 ;
   %result = call i64 @div(i32 %numer, i32 %denom)
   ret i64 %result
 }
 
 define { i64 } @div_packed_wrapper(i32 %numer, i32 %denom) {
-; CHECK-LABEL: define { i64 } @div_packed_wrapper(
-; CHECK-SAME: i32 [[NUMER:%.*]], i32 [[DENOM:%.*]]) {
-; CHECK-NEXT:    [[RESULT:%.*]] = call { i64 } @"\01div"(i32 [[NUMER]], i32 
[[DENOM]])
-; CHECK-NEXT:    ret { i64 } [[RESULT]]
+; LITTLE-LABEL: define { i64 } @div_packed_wrapper(
+; LITTLE-SAME: i32 [[NUMER:%.*]], i32 [[DENOM:%.*]]) {
+; LITTLE-NEXT:    [[DIV_QUOT:%.*]] = sdiv i32 [[NUMER]], [[DENOM]]
+; LITTLE-NEXT:    [[DIV_REM:%.*]] = srem i32 [[NUMER]], [[DENOM]]
+; LITTLE-NEXT:    [[DIV_LOW:%.*]] = zext i32 [[DIV_QUOT]] to i64
+; LITTLE-NEXT:    [[DIV_HIGH:%.*]] = zext i32 [[DIV_REM]] to i64
+; LITTLE-NEXT:    [[DIV_HIGH_SHIFT:%.*]] = shl nuw i64 [[DIV_HIGH]], 32
+; LITTLE-NEXT:    [[DIV_RESULT:%.*]] = or disjoint i64 [[DIV_HIGH_SHIFT]], 
[[DIV_LOW]]
+; LITTLE-NEXT:    [[DIV_RESULT_INSERT:%.*]] = insertvalue { i64 } poison, i64 
[[DIV_RESULT]], 0
+; LITTLE-NEXT:    ret { i64 } [[DIV_RESULT_INSERT]]
+;
+; BIG-LABEL: define { i64 } @div_packed_wrapper(
+; BIG-SAME: i32 [[NUMER:%.*]], i32 [[DENOM:%.*]]) {
+; BIG-NEXT:    [[DIV_QUOT:%.*]] = sdiv i32 [[NUMER]], [[DENOM]]
+; BIG-NEXT:    [[DIV_REM:%.*]] = srem i32 [[NUMER]], [[DENOM]]
+; BIG-NEXT:    [[DIV_LOW:%.*]] = zext i32 [[DIV_REM]] to i64
+; BIG-NEXT:    [[DIV_HIGH:%.*]] = zext i32 [[DIV_QUOT]] to i64
+; BIG-NEXT:    [[DIV_HIGH_SHIFT:%.*]] = shl nuw i64 [[DIV_HIGH]], 32
+; BIG-NEXT:    [[DIV_RESULT:%.*]] = or disjoint i64 [[DIV_HIGH_SHIFT]], 
[[DIV_LOW]]
+; BIG-NEXT:    [[DIV_RESULT_INSERT:%.*]] = insertvalue { i64 } poison, i64 
[[DIV_RESULT]], 0
+; BIG-NEXT:    ret { i64 } [[DIV_RESULT_INSERT]]
 ;
   %result = call { i64 } @"\01div"(i32 %numer, i32 %denom)
   ret { i64 } %result
@@ -36,7 +68,10 @@ define { i64 } @div_packed_wrapper(i32 %numer, i32 %denom) {
 define { i64, i64 } @ldiv_struct(i64 %numer, i64 %denom) {
 ; CHECK-LABEL: define { i64, i64 } @ldiv_struct(
 ; CHECK-SAME: i64 [[NUMER:%.*]], i64 [[DENOM:%.*]]) {
-; CHECK-NEXT:    [[DIV_REM_INSERT:%.*]] = call { i64, i64 } @ldiv(i64 
[[NUMER]], i64 [[DENOM]])
+; CHECK-NEXT:    [[DIV_QUOT:%.*]] = sdiv i64 [[NUMER]], [[DENOM]]
+; CHECK-NEXT:    [[DIV_REM:%.*]] = srem i64 [[NUMER]], [[DENOM]]
+; CHECK-NEXT:    [[DIV_QUOT_INSERT:%.*]] = insertvalue { i64, i64 } poison, 
i64 [[DIV_QUOT]], 0
+; CHECK-NEXT:    [[DIV_REM_INSERT:%.*]] = insertvalue { i64, i64 } 
[[DIV_QUOT_INSERT]], i64 [[DIV_REM]], 1
 ; CHECK-NEXT:    ret { i64, i64 } [[DIV_REM_INSERT]]
 ;
   %result = call { i64, i64 } @ldiv(i64 %numer, i64 %denom)
@@ -46,7 +81,10 @@ define { i64, i64 } @ldiv_struct(i64 %numer, i64 %denom) {
 define [2 x i64] @lldiv_array(i64 %numer, i64 %denom) {
 ; CHECK-LABEL: define [2 x i64] @lldiv_array(
 ; CHECK-SAME: i64 [[NUMER:%.*]], i64 [[DENOM:%.*]]) {
-; CHECK-NEXT:    [[DIV_REM_INSERT:%.*]] = call [2 x i64] @lldiv(i64 [[NUMER]], 
i64 [[DENOM]])
+; CHECK-NEXT:    [[DIV_QUOT:%.*]] = sdiv i64 [[NUMER]], [[DENOM]]
+; CHECK-NEXT:    [[DIV_REM:%.*]] = srem i64 [[NUMER]], [[DENOM]]
+; CHECK-NEXT:    [[DIV_QUOT_INSERT:%.*]] = insertvalue [2 x i64] poison, i64 
[[DIV_QUOT]], 0
+; CHECK-NEXT:    [[DIV_REM_INSERT:%.*]] = insertvalue [2 x i64] 
[[DIV_QUOT_INSERT]], i64 [[DIV_REM]], 1
 ; CHECK-NEXT:    ret [2 x i64] [[DIV_REM_INSERT]]
 ;
   %result = call [2 x i64] @lldiv(i64 %numer, i64 %denom)
@@ -56,7 +94,11 @@ define [2 x i64] @lldiv_array(i64 %numer, i64 %denom) {
 define void @ldiv_sret(ptr %result, i32 %numer, i32 %denom) {
 ; CHECK-LABEL: define void @ldiv_sret(
 ; CHECK-SAME: ptr [[RESULT:%.*]], i32 [[NUMER:%.*]], i32 [[DENOM:%.*]]) {
-; CHECK-NEXT:    call void @"\01ldiv"(ptr sret([[DIV_SRET:%.*]]) [[RESULT]], 
i32 [[NUMER]], i32 [[DENOM]])
+; CHECK-NEXT:    [[DIV_QUOT:%.*]] = sdiv i32 [[NUMER]], [[DENOM]]
+; CHECK-NEXT:    [[DIV_REM:%.*]] = srem i32 [[NUMER]], [[DENOM]]
+; CHECK-NEXT:    store i32 [[DIV_QUOT]], ptr [[RESULT]], align 4
+; CHECK-NEXT:    [[RESULT_REPACK1:%.*]] = getelementptr inbounds nuw i8, ptr 
[[RESULT]], i64 4
+; CHECK-NEXT:    store i32 [[DIV_REM]], ptr [[RESULT_REPACK1]], align 4
 ; CHECK-NEXT:    ret void
 ;
   call void @"\01ldiv"(ptr sret(%div_sret) %result, i32 %numer, i32 %denom)
@@ -94,6 +136,3 @@ define i64 @no_builtin(i32 %numer, i32 %denom) {
 }
 
 attributes #0 = { nobuiltin }
-;; NOTE: These prefixes are unused and the list is autogenerated. Do not add 
tests below this line:
-; BIG: {{.*}}
-; LITTLE: {{.*}}
diff --git a/llvm/test/tools/llvm-tli-checker/ps4-tli-check.yaml 
b/llvm/test/tools/llvm-tli-checker/ps4-tli-check.yaml
index 63520a0b98089..1dc06fdbe76b9 100644
--- a/llvm/test/tools/llvm-tli-checker/ps4-tli-check.yaml
+++ b/llvm/test/tools/llvm-tli-checker/ps4-tli-check.yaml
@@ -32,7 +32,7 @@
 # RUN: FileCheck %s --check-prefix=AVAIL --input-file %t3.txt
 # RUN: FileCheck %s --check-prefix=UNAVAIL --input-file %t3.txt
 #
-# CHECK: << Total TLI yes SDK no:  18
+# CHECK: << Total TLI yes SDK no:  21
 # CHECK: >> Total TLI no  SDK yes: 0
 # CHECK: == Total TLI yes SDK yes: 277
 #
@@ -40,13 +40,16 @@
 # WRONG_DETAIL: >> TLI no  SDK yes: '_ZdaPvj' aka operator delete[](void*, 
unsigned int)
 # WRONG_DETAIL-COUNT-8: << TLI yes SDK no : {{.*}}__hot_cold_t
 # WRONG_DETAIL-COUNT-4: << TLI yes SDK no : '__size_returning_new{{.*}}
+# WRONG_DETAIL: << TLI yes SDK no : 'div'
 # WRONG_DETAIL: << TLI yes SDK no : 'fmaximum_num'
 # WRONG_DETAIL: << TLI yes SDK no : 'fmaximum_numf'
 # WRONG_DETAIL: << TLI yes SDK no : 'fmaximum_numl'
 # WRONG_DETAIL: << TLI yes SDK no : 'fminimum_num'
 # WRONG_DETAIL: << TLI yes SDK no : 'fminimum_numf'
 # WRONG_DETAIL: << TLI yes SDK no : 'fminimum_numl'
-# WRONG_SUMMARY: << Total TLI yes SDK no:  19{{$}}
+# WRONG_DETAIL: << TLI yes SDK no : 'ldiv'
+# WRONG_DETAIL: << TLI yes SDK no : 'lldiv'
+# WRONG_SUMMARY: << Total TLI yes SDK no:  22{{$}}
 # WRONG_SUMMARY: >> Total TLI no  SDK yes: 1{{$}}
 # WRONG_SUMMARY: == Total TLI yes SDK yes: 276
 #
@@ -54,8 +57,8 @@
 ## the exact count first; the two directives should add up to that.
 ## Yes, this means additions to TLI will fail this test, but the argument
 ## to -COUNT can't be an expression.
-# AVAIL: TLI knows 528 symbols, 295 available
-# AVAIL-COUNT-295: {{^}} available
+# AVAIL: TLI knows 531 symbols, 298 available
+# AVAIL-COUNT-298: {{^}} available
 # AVAIL-NOT:       {{^}} available
 # UNAVAIL-COUNT-233: not available
 # UNAVAIL-NOT:       not available
diff --git a/llvm/unittests/Analysis/TargetLibraryInfoTest.cpp 
b/llvm/unittests/Analysis/TargetLibraryInfoTest.cpp
index afeefd36a11e7..7a8a6b34f4df6 100644
--- a/llvm/unittests/Analysis/TargetLibraryInfoTest.cpp
+++ b/llvm/unittests/Analysis/TargetLibraryInfoTest.cpp
@@ -174,6 +174,7 @@ TEST_F(TargetLibraryInfoTest, ValidProto) {
       "declare x86_fp80 @coshl(x86_fp80)\n"
       "declare x86_fp80 @cosl(x86_fp80)\n"
       "declare ptr @ctermid(ptr)\n"
+      "declare i64 @div(i32, i32)\n"
       "declare double @exp(double)\n"
       "declare double @exp2(double)\n"
       "declare float @exp2f(float)\n"
@@ -258,7 +259,9 @@ TEST_F(TargetLibraryInfoTest, ValidProto) {
       "declare double @ldexp(double, i32)\n"
       "declare float @ldexpf(float, i32)\n"
       "declare x86_fp80 @ldexpl(x86_fp80, i32)\n"
+      "declare { i64, i64 } @ldiv(i64, i64)\n"
       "declare i64 @llabs(i64)\n"
+      "declare [2 x i64] @lldiv(i64, i64)\n"
       "declare double @log(double)\n"
       "declare double @log10(double)\n"
       "declare float @log10f(float)\n"

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to