Skip to content

Commit a7d217d

Browse files
authored
Merge pull request #7653 from fhahn/aligned-alloc-fix
Fix aligend_alloc handling
2 parents 6d423c4 + b115d61 commit a7d217d

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
@@ -2728,6 +2728,26 @@ static bool isAllocSiteRemovable(Instruction *AI,
27282728
unsigned OtherIndex = (ICI->getOperand(0) == PI) ? 1 : 0;
27292729
if (!isNeverEqualToUnescapedAlloc(ICI->getOperand(OtherIndex), TLI, AI))
27302730
return false;
2731+
2732+
// Do not fold compares to aligned_alloc calls, as they may have to
2733+
// return null in case the required alignment cannot be satisfied,
2734+
// unless we can prove that both alignment and size are valid.
2735+
auto AlignmentAndSizeKnownValid = [](CallBase *CB) {
2736+
// Check if alignment and size of a call to aligned_alloc is valid,
2737+
// that is alignment is a power-of-2 and the size is a multiple of the
2738+
// alignment.
2739+
const APInt *Alignment;
2740+
const APInt *Size;
2741+
return match(CB->getArgOperand(0), m_APInt(Alignment)) &&
2742+
match(CB->getArgOperand(1), m_APInt(Size)) &&
2743+
Alignment->isPowerOf2() && Size->urem(*Alignment).isZero();
2744+
};
2745+
auto *CB = dyn_cast<CallBase>(AI);
2746+
LibFunc TheLibFunc;
2747+
if (CB && TLI.getLibFunc(*CB->getCalledFunction(), TheLibFunc) &&
2748+
TLI.has(TheLibFunc) && TheLibFunc == LibFunc_aligned_alloc &&
2749+
!AlignmentAndSizeKnownValid(CB))
2750+
return false;
27312751
Users.emplace_back(I);
27322752
continue;
27332753
}

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)