Skip to content

Commit 357e5e6

Browse files
authored
Merge pull request swiftlang#7654 from fhahn/aligned-alloc-fix-2
Fix aligned_alloc handling.
2 parents fd715c2 + 45b89d1 commit 357e5e6

File tree

2 files changed

+75
-0
lines changed

2 files changed

+75
-0
lines changed

llvm/lib/Transforms/InstCombine/InstructionCombining.cpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2362,6 +2362,26 @@ static bool isAllocSiteRemovable(Instruction *AI,
23622362
unsigned OtherIndex = (ICI->getOperand(0) == PI) ? 1 : 0;
23632363
if (!isNeverEqualToUnescapedAlloc(ICI->getOperand(OtherIndex), TLI, AI))
23642364
return false;
2365+
2366+
// Do not fold compares to aligned_alloc calls, as they may have to
2367+
// return null in case the required alignment cannot be satisfied,
2368+
// unless we can prove that both alignment and size are valid.
2369+
auto AlignmentAndSizeKnownValid = [](CallBase *CB) {
2370+
// Check if alignment and size of a call to aligned_alloc is valid,
2371+
// that is alignment is a power-of-2 and the size is a multiple of the
2372+
// alignment.
2373+
const APInt *Alignment;
2374+
const APInt *Size;
2375+
return match(CB->getArgOperand(0), m_APInt(Alignment)) &&
2376+
match(CB->getArgOperand(1), m_APInt(Size)) &&
2377+
Alignment->isPowerOf2() && Size->urem(*Alignment).isZero();
2378+
};
2379+
auto *CB = dyn_cast<CallBase>(AI);
2380+
LibFunc TheLibFunc;
2381+
if (CB && TLI.getLibFunc(*CB->getCalledFunction(), TheLibFunc) &&
2382+
TLI.has(TheLibFunc) && TheLibFunc == LibFunc_aligned_alloc &&
2383+
!AlignmentAndSizeKnownValid(CB))
2384+
return false;
23652385
Users.emplace_back(I);
23662386
continue;
23672387
}

llvm/test/Transforms/InstCombine/malloc-free.ll

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,64 @@ define i32 @dead_aligned_alloc(i32 %size, i32 %alignment, i8 %value) {
2626
ret i32 0
2727
}
2828

29+
define i1 @aligned_alloc_only_pointe(i32 %size, i32 %alignment, i8 %value) {
30+
; CHECK-LABEL: @aligned_alloc_only_pointe(
31+
; CHECK-NEXT: [[ALIGNED_ALLOCATION:%.*]] = tail call ptr @aligned_alloc(i32 [[ALIGNMENT:%.*]], i32 [[SIZE:%.*]])
32+
; CHECK-NEXT: [[CMP:%.*]] = icmp ne ptr [[ALIGNED_ALLOCATION]], null
33+
; CHECK-NEXT: ret i1 [[CMP]]
34+
;
35+
%aligned_allocation = tail call ptr @aligned_alloc(i32 %alignment, i32 %size)
36+
%cmp = icmp ne ptr %aligned_allocation, null
37+
ret i1 %cmp
38+
}
39+
40+
define i1 @aligned_alloc_pointer_only_used_by_cmp_alignment_and_value_known_ok(i32 %size, i32 %alignment, i8 %value) {
41+
; CHECK-LABEL: @aligned_alloc_pointer_only_used_by_cmp_alignment_and_value_known_ok(
42+
; CHECK-NEXT: ret i1 true
43+
;
44+
%aligned_allocation = tail call ptr @aligned_alloc(i32 8, i32 32)
45+
%cmp = icmp ne ptr %aligned_allocation, null
46+
ret i1 %cmp
47+
}
48+
49+
define i1 @aligned_alloc_pointer_only_used_by_cmp_alignment_no_power_of_2(i32 %size, i32 %alignment, i8 %value) {
50+
; CHECK-LABEL: @aligned_alloc_pointer_only_used_by_cmp_alignment_no_power_of_2(
51+
; CHECK-NEXT: [[ALIGNED_ALLOCATION:%.*]] = tail call dereferenceable_or_null(32) ptr @aligned_alloc(i32 3, i32 32)
52+
; CHECK-NEXT: [[CMP:%.*]] = icmp ne ptr [[ALIGNED_ALLOCATION]], null
53+
; CHECK-NEXT: ret i1 [[CMP]]
54+
;
55+
%aligned_allocation = tail call ptr @aligned_alloc(i32 3, i32 32)
56+
%cmp = icmp ne ptr %aligned_allocation, null
57+
ret i1 %cmp
58+
}
59+
60+
define i1 @aligned_alloc_pointer_only_used_by_cmp_size_not_multiple_of_alignment(i32 %size, i32 %alignment, i8 %value) {
61+
; CHECK-LABEL: @aligned_alloc_pointer_only_used_by_cmp_size_not_multiple_of_alignment(
62+
; CHECK-NEXT: [[ALIGNED_ALLOCATION:%.*]] = tail call dereferenceable_or_null(31) ptr @aligned_alloc(i32 8, i32 31)
63+
; CHECK-NEXT: [[CMP:%.*]] = icmp ne ptr [[ALIGNED_ALLOCATION]], null
64+
; CHECK-NEXT: ret i1 [[CMP]]
65+
;
66+
%aligned_allocation = tail call ptr @aligned_alloc(i32 8, i32 31)
67+
%cmp = icmp ne ptr %aligned_allocation, null
68+
ret i1 %cmp
69+
}
70+
71+
; This test uses a aligned allocation function different to @aligned_alloc,
72+
; and should be treated as having @aligned_alloc's constraints on alignment
73+
; and size operands.
74+
define i1 @other_aligned_allocation_function(i32 %size, i32 %alignment, i8 %value) {
75+
; CHECK-LABEL: @other_aligned_allocation_function(
76+
; CHECK-NEXT: ret i1 true
77+
;
78+
%aligned_allocation = tail call ptr @other_aligned_alloc(i32 %alignment, i32 %size)
79+
%cmp = icmp ne ptr %aligned_allocation, null
80+
ret i1 %cmp
81+
}
82+
2983
declare noalias ptr @calloc(i32, i32) nounwind allockind("alloc,zeroed") allocsize(0,1) "alloc-family"="malloc"
3084
declare noalias ptr @malloc(i32) allockind("alloc,uninitialized") allocsize(0) "alloc-family"="malloc"
3185
declare noalias ptr @aligned_alloc(i32, i32) allockind("alloc,uninitialized,aligned") allocsize(1) "alloc-family"="malloc"
86+
declare noalias ptr @other_aligned_alloc(i32, i32) allockind("alloc,uninitialized,aligned") allocsize(1) "alloc-family"="malloc"
3287
declare void @free(ptr) allockind("free") "alloc-family"="malloc"
3388

3489
define i1 @foo() {

0 commit comments

Comments
 (0)