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
