mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2025-01-31 12:41:49 +01:00
Introduce support for lib function aligned_alloc in TLI / memory builtins
Aligned_alloc is a standard lib function and has been in glibc since 2.16 and in the C11 standard. It has semantics similar to malloc/calloc for several analyses/transforms. This patch introduces aligned_alloc in target library info and memory builtins. Subsequent ones will make other passes aware and fix https://bugs.llvm.org/show_bug.cgi?id=44062 This change will also be useful to LLVM generators that need to allocate buffers of vector elements larger than 16 bytes (for eg. 256-bit ones), element boundary alignment for which is not typically provided by glibc malloc. Signed-off-by: Uday Bondhugula <uday@polymagelabs.com> Differential Revision: https://reviews.llvm.org/D76970
This commit is contained in:
parent
d0c820ef49
commit
336d326470
@ -75,6 +75,14 @@ bool isMallocLikeFn(const Value *V,
|
||||
function_ref<const TargetLibraryInfo &(Function &)> GetTLI,
|
||||
bool LookThroughBitCast = false);
|
||||
|
||||
/// Tests if a value is a call or invoke to a library function that
|
||||
/// allocates uninitialized memory with alignment (such as aligned_alloc).
|
||||
bool isAlignedAllocLikeFn(const Value *V, const TargetLibraryInfo *TLI,
|
||||
bool LookThroughBitCast = false);
|
||||
bool isAlignedAllocLikeFn(
|
||||
const Value *V, function_ref<const TargetLibraryInfo &(Function &)> GetTLI,
|
||||
bool LookThroughBitCast = false);
|
||||
|
||||
/// Tests if a value is a call or invoke to a library function that
|
||||
/// allocates zero-filled memory (such as calloc).
|
||||
bool isCallocLikeFn(const Value *V, const TargetLibraryInfo *TLI,
|
||||
|
@ -481,6 +481,9 @@ TLI_DEFINE_STRING_INTERNAL("acoshl")
|
||||
/// long double acosl(long double x);
|
||||
TLI_DEFINE_ENUM_INTERNAL(acosl)
|
||||
TLI_DEFINE_STRING_INTERNAL("acosl")
|
||||
/// void *aligned_alloc(size_t alignment, size_t size);
|
||||
TLI_DEFINE_ENUM_INTERNAL(aligned_alloc)
|
||||
TLI_DEFINE_STRING_INTERNAL("aligned_alloc")
|
||||
/// double asin(double x);
|
||||
TLI_DEFINE_ENUM_INTERNAL(asin)
|
||||
TLI_DEFINE_STRING_INTERNAL("asin")
|
||||
|
@ -960,7 +960,7 @@ ModRefInfo BasicAAResult::getModRefInfo(const CallBase *Call,
|
||||
}
|
||||
}
|
||||
|
||||
// If the call is to malloc or calloc, we can assume that it doesn't
|
||||
// If the call is malloc/calloc like, we can assume that it doesn't
|
||||
// modify any IR visible value. This is only valid because we assume these
|
||||
// routines do not read values visible in the IR. TODO: Consider special
|
||||
// casing realloc and strdup routines which access only their arguments as
|
||||
|
@ -52,11 +52,12 @@ using namespace llvm;
|
||||
enum AllocType : uint8_t {
|
||||
OpNewLike = 1<<0, // allocates; never returns null
|
||||
MallocLike = 1<<1 | OpNewLike, // allocates; may return null
|
||||
CallocLike = 1<<2, // allocates + bzero
|
||||
ReallocLike = 1<<3, // reallocates
|
||||
StrDupLike = 1<<4,
|
||||
MallocOrCallocLike = MallocLike | CallocLike,
|
||||
AllocLike = MallocLike | CallocLike | StrDupLike,
|
||||
AlignedAllocLike = 1<<2, // allocates with alignment; may return null
|
||||
CallocLike = 1<<3, // allocates + bzero
|
||||
ReallocLike = 1<<4, // reallocates
|
||||
StrDupLike = 1<<5,
|
||||
MallocOrCallocLike = MallocLike | CallocLike | AlignedAllocLike,
|
||||
AllocLike = MallocOrCallocLike | StrDupLike,
|
||||
AnyAlloc = AllocLike | ReallocLike
|
||||
};
|
||||
|
||||
@ -100,6 +101,7 @@ static const std::pair<LibFunc, AllocFnsTy> AllocationFnData[] = {
|
||||
{LibFunc_msvc_new_array_int_nothrow, {MallocLike, 2, 0, -1}}, // new[](unsigned int, nothrow)
|
||||
{LibFunc_msvc_new_array_longlong, {OpNewLike, 1, 0, -1}}, // new[](unsigned long long)
|
||||
{LibFunc_msvc_new_array_longlong_nothrow, {MallocLike, 2, 0, -1}}, // new[](unsigned long long, nothrow)
|
||||
{LibFunc_aligned_alloc, {AlignedAllocLike, 2, 1, -1}},
|
||||
{LibFunc_calloc, {CallocLike, 2, 0, 1}},
|
||||
{LibFunc_realloc, {ReallocLike, 2, 1, -1}},
|
||||
{LibFunc_reallocf, {ReallocLike, 2, 1, -1}},
|
||||
@ -265,6 +267,20 @@ bool llvm::isMallocLikeFn(
|
||||
.hasValue();
|
||||
}
|
||||
|
||||
/// Tests if a value is a call or invoke to a library function that
|
||||
/// allocates uninitialized memory with alignment (such as aligned_alloc).
|
||||
bool llvm::isAlignedAllocLikeFn(const Value *V, const TargetLibraryInfo *TLI,
|
||||
bool LookThroughBitCast) {
|
||||
return getAllocationData(V, AlignedAllocLike, TLI, LookThroughBitCast)
|
||||
.hasValue();
|
||||
}
|
||||
bool llvm::isAlignedAllocLikeFn(
|
||||
const Value *V, function_ref<const TargetLibraryInfo &(Function &)> GetTLI,
|
||||
bool LookThroughBitCast) {
|
||||
return getAllocationData(V, AlignedAllocLike, GetTLI, LookThroughBitCast)
|
||||
.hasValue();
|
||||
}
|
||||
|
||||
/// Tests if a value is a call or invoke to a library function that
|
||||
/// allocates zero-filled memory (such as calloc).
|
||||
bool llvm::isCallocLikeFn(const Value *V, const TargetLibraryInfo *TLI,
|
||||
|
@ -901,6 +901,8 @@ bool TargetLibraryInfoImpl::isValidProtoForLibFunc(const FunctionType &FTy,
|
||||
FTy.getParamType(1)->isPointerTy());
|
||||
case LibFunc_write:
|
||||
return (NumParams == 3 && FTy.getParamType(1)->isPointerTy());
|
||||
case LibFunc_aligned_alloc:
|
||||
return (NumParams == 2 && FTy.getReturnType()->isPointerTy());
|
||||
case LibFunc_bcopy:
|
||||
case LibFunc_bcmp:
|
||||
return (NumParams == 3 && FTy.getParamType(0)->isPointerTy() &&
|
||||
|
@ -378,6 +378,10 @@ bool llvm::inferLibFuncAttributes(Function &F, const TargetLibraryInfo &TLI) {
|
||||
Changed |= setDoesNotCapture(F, 1);
|
||||
Changed |= setOnlyReadsMemory(F, 1);
|
||||
return Changed;
|
||||
case LibFunc_aligned_alloc:
|
||||
Changed |= setDoesNotThrow(F);
|
||||
Changed |= setRetDoesNotAlias(F);
|
||||
return Changed;
|
||||
case LibFunc_bcopy:
|
||||
Changed |= setDoesNotThrow(F);
|
||||
Changed |= setDoesNotCapture(F, 0);
|
||||
|
@ -259,6 +259,8 @@ define i32 addrspace(1)* @test13_addrspacecast() {
|
||||
|
||||
declare noalias i8* @malloc(i32)
|
||||
declare noalias i8* @calloc(i32, i32)
|
||||
declare noalias i8* @aligned_alloc(i32, i32)
|
||||
declare void @free(i8*)
|
||||
|
||||
|
||||
define void @test14(i32* %Q) {
|
||||
@ -272,6 +274,17 @@ define void @test14(i32* %Q) {
|
||||
|
||||
}
|
||||
|
||||
; Dead store on an aligned_alloc: should know that %M doesn't alias with %A.
|
||||
define i32 @test14a(i8* %M, i8 %value) {
|
||||
; CHECK-LABEL: @test14a(
|
||||
; CHECK-NOT: store
|
||||
; CHECK: ret i32 0
|
||||
;
|
||||
%A = tail call i8* @aligned_alloc(i32 32, i32 1024)
|
||||
store i8 %value, i8* %A
|
||||
tail call void @free(i8* %A)
|
||||
ret i32 0
|
||||
}
|
||||
|
||||
; PR8701
|
||||
|
||||
|
@ -96,6 +96,7 @@ TEST_F(TargetLibraryInfoTest, ValidProto) {
|
||||
"declare float @acoshf(float)\n"
|
||||
"declare x86_fp80 @acoshl(x86_fp80)\n"
|
||||
"declare x86_fp80 @acosl(x86_fp80)\n"
|
||||
"declare i8* @aligned_alloc(i64, i64)\n"
|
||||
"declare double @asin(double)\n"
|
||||
"declare float @asinf(float)\n"
|
||||
"declare double @asinh(double)\n"
|
||||
|
Loading…
x
Reference in New Issue
Block a user