1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py 2; RUN: opt -passes=instcombine,lower-constant-intrinsics -S < %s | FileCheck %s 3 4target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" 5target triple = "x86_64-unknown-linux-gnu" 6 7declare dso_local i32 @posix_memalign(ptr noundef, i64 noundef, i64 noundef) 8declare i64 @llvm.objectsize.i64.p0(ptr, i1 immarg, i1 immarg, i1 immarg) 9 10; Check posix_memalign call with proper handlig of return value 11define dso_local i64 @check_posix_memalign(i32 noundef %n) local_unnamed_addr { 12; CHECK-LABEL: @check_posix_memalign( 13; CHECK-NEXT: entry: 14; CHECK-NEXT: [[OBJ:%.*]] = alloca ptr, align 8 15; CHECK-NEXT: [[CALL:%.*]] = call i32 @posix_memalign(ptr noundef nonnull [[OBJ]], i64 noundef 8, i64 noundef 10) 16; CHECK-NEXT: [[TOBOOL_NOT:%.*]] = icmp eq i32 [[CALL]], 0 17; CHECK-NEXT: br i1 [[TOBOOL_NOT]], label [[COND_FALSE:%.*]], label [[EXIT:%.*]] 18; CHECK: cond.false: 19; CHECK-NEXT: br label [[EXIT]] 20; CHECK: exit: 21; CHECK-NEXT: [[COND:%.*]] = phi i64 [ -2, [[ENTRY:%.*]] ], [ 10, [[COND_FALSE]] ] 22; CHECK-NEXT: ret i64 [[COND]] 23; 24entry: 25 %obj = alloca ptr 26 %call = call i32 @posix_memalign(ptr noundef %obj, i64 noundef 8, i64 noundef 10) 27 %tobool = icmp ne i32 %call, 0 28 br i1 %tobool, label %exit, label %cond.false 29 30cond.false: 31 %val = load ptr, ptr %obj 32 %objsize = call i64 @llvm.objectsize.i64.p0(ptr %val, i1 false, i1 true, i1 false) 33 br label %exit 34 35exit: 36 %cond = phi i64 [ -2, %entry ], [ %objsize, %cond.false ] 37 ret i64 %cond 38 39} 40 41 42; Same test case as above but with idiomatic NULL initialization 43define dso_local i64 @check_posix_memalign_null() { 44; CHECK-LABEL: @check_posix_memalign_null( 45; CHECK-NEXT: entry: 46; CHECK-NEXT: [[OBJ:%.*]] = alloca ptr, align 8 47; CHECK-NEXT: store ptr null, ptr [[OBJ]], align 8 48; CHECK-NEXT: [[CALL:%.*]] = call i32 @posix_memalign(ptr noundef nonnull [[OBJ]], i64 noundef 8, i64 noundef 10) 49; CHECK-NEXT: [[TOBOOL_NOT:%.*]] = icmp eq i32 [[CALL]], 0 50; CHECK-NEXT: br i1 [[TOBOOL_NOT]], label [[COND_FALSE:%.*]], label [[EXIT:%.*]] 51; CHECK: cond.false: 52; CHECK-NEXT: br label [[EXIT]] 53; CHECK: exit: 54; CHECK-NEXT: [[COND:%.*]] = phi i64 [ -2, [[ENTRY:%.*]] ], [ 10, [[COND_FALSE]] ] 55; CHECK-NEXT: ret i64 [[COND]] 56; 57entry: 58 %obj = alloca ptr 59 store ptr null, ptr %obj 60 %call = call i32 @posix_memalign(ptr noundef %obj, i64 noundef 8, i64 noundef 10) 61 %tobool = icmp ne i32 %call, 0 62 br i1 %tobool, label %exit, label %cond.false 63 64cond.false: 65 %val = load ptr, ptr %obj 66 %objsize = call i64 @llvm.objectsize.i64.p0(ptr %val, i1 false, i1 true, i1 false) 67 br label %exit 68 69exit: 70 %cond = phi i64 [ -2, %entry ], [ %objsize, %cond.false ] 71 ret i64 %cond 72} 73 74; Using argument storage instead of local storage for the allocated pointer. 75define dso_local i64 @check_posix_memalign_arg(ptr noalias noundef %obj) { 76; CHECK-LABEL: @check_posix_memalign_arg( 77; CHECK-NEXT: entry: 78; CHECK-NEXT: [[CALL:%.*]] = call i32 @posix_memalign(ptr noundef [[OBJ:%.*]], i64 noundef 8, i64 noundef 10) 79; CHECK-NEXT: [[TOBOOL_NOT:%.*]] = icmp eq i32 [[CALL]], 0 80; CHECK-NEXT: br i1 [[TOBOOL_NOT]], label [[COND_FALSE:%.*]], label [[EXIT:%.*]] 81; CHECK: cond.false: 82; CHECK-NEXT: br label [[EXIT]] 83; CHECK: exit: 84; CHECK-NEXT: [[COND:%.*]] = phi i64 [ -2, [[ENTRY:%.*]] ], [ 10, [[COND_FALSE]] ] 85; CHECK-NEXT: ret i64 [[COND]] 86; 87entry: 88 %call = call i32 @posix_memalign(ptr noundef %obj, i64 noundef 8, i64 noundef 10) 89 %tobool = icmp ne i32 %call, 0 90 br i1 %tobool, label %exit, label %cond.false 91 92cond.false: 93 %val = load ptr, ptr %obj 94 %objsize = call i64 @llvm.objectsize.i64.p0(ptr %val, i1 false, i1 true, i1 false) 95 br label %exit 96 97exit: 98 %cond = phi i64 [ -2, %entry ], [ %objsize, %cond.false ] 99 ret i64 %cond 100 101} 102 103; posix_memalign can fail, in that case no object_size can be guessed. 104define dso_local i64 @check_posix_memalign_unchecked() { 105; CHECK-LABEL: @check_posix_memalign_unchecked( 106; CHECK-NEXT: entry: 107; CHECK-NEXT: [[OBJ:%.*]] = alloca ptr, align 8 108; CHECK-NEXT: [[CALL:%.*]] = call i32 @posix_memalign(ptr noundef nonnull [[OBJ]], i64 noundef 8, i64 noundef 10) 109; CHECK-NEXT: [[VAL:%.*]] = load ptr, ptr [[OBJ]], align 8 110; CHECK-NEXT: ret i64 -1 111; 112entry: 113 %obj = alloca ptr 114 %call = call i32 @posix_memalign(ptr noundef %obj, i64 noundef 8, i64 noundef 10) 115 %val = load ptr, ptr %obj 116 %objsize = call i64 @llvm.objectsize.i64.p0(ptr %val, i1 false, i1 true, i1 false) 117 ret i64 %objsize 118} 119 120; Checks that bo upon posix_memalign failure behaves correctly 121define dso_local i64 @check_posix_memalign_inverted_cond() { 122; CHECK-LABEL: @check_posix_memalign_inverted_cond( 123; CHECK-NEXT: entry: 124; CHECK-NEXT: [[OBJ:%.*]] = alloca ptr, align 8 125; CHECK-NEXT: store ptr null, ptr [[OBJ]], align 8 126; CHECK-NEXT: [[CALL:%.*]] = call i32 @posix_memalign(ptr noundef nonnull [[OBJ]], i64 noundef 8, i64 noundef 10) 127; CHECK-NEXT: [[TOBOOL:%.*]] = icmp eq i32 [[CALL]], 0 128; CHECK-NEXT: br i1 [[TOBOOL]], label [[EXIT:%.*]], label [[COND_FALSE:%.*]] 129; CHECK: cond.false: 130; CHECK-NEXT: [[VAL:%.*]] = load ptr, ptr [[OBJ]], align 8 131; CHECK-NEXT: br label [[EXIT]] 132; CHECK: exit: 133; CHECK-NEXT: [[COND:%.*]] = phi i64 [ -2, [[ENTRY:%.*]] ], [ -1, [[COND_FALSE]] ] 134; CHECK-NEXT: ret i64 [[COND]] 135; 136entry: 137 %obj = alloca ptr 138 store ptr null, ptr %obj 139 %call = call i32 @posix_memalign(ptr noundef %obj, i64 noundef 8, i64 noundef 10) 140 %tobool = icmp eq i32 %call, 0 141 br i1 %tobool, label %exit, label %cond.false 142 143cond.false: 144 %val = load ptr, ptr %obj 145 %objsize = call i64 @llvm.objectsize.i64.p0(ptr %val, i1 false, i1 true, i1 false) 146 br label %exit 147 148exit: 149 %cond = phi i64 [ -2, %entry ], [ %objsize, %cond.false ] 150 ret i64 %cond 151} 152 153; Check posix_memalign call with a runtime condition check 154define dso_local i64 @check_posix_memalign_runtime_cond(i32 noundef %n) local_unnamed_addr { 155; CHECK-LABEL: @check_posix_memalign_runtime_cond( 156; CHECK-NEXT: entry: 157; CHECK-NEXT: [[OBJ:%.*]] = alloca ptr, align 8 158; CHECK-NEXT: [[CALL:%.*]] = call i32 @posix_memalign(ptr noundef nonnull [[OBJ]], i64 noundef 8, i64 noundef 10) 159; CHECK-NEXT: [[TOBOOL_NOT:%.*]] = icmp eq i32 [[CALL]], [[N:%.*]] 160; CHECK-NEXT: br i1 [[TOBOOL_NOT]], label [[COND_FALSE:%.*]], label [[EXIT:%.*]] 161; CHECK: cond.false: 162; CHECK-NEXT: [[VAL:%.*]] = load ptr, ptr [[OBJ]], align 8 163; CHECK-NEXT: br label [[EXIT]] 164; CHECK: exit: 165; CHECK-NEXT: [[COND:%.*]] = phi i64 [ -2, [[ENTRY:%.*]] ], [ -1, [[COND_FALSE]] ] 166; CHECK-NEXT: ret i64 [[COND]] 167; 168entry: 169 %obj = alloca ptr 170 %call = call i32 @posix_memalign(ptr noundef %obj, i64 noundef 8, i64 noundef 10) 171 %tobool = icmp ne i32 %call, %n 172 br i1 %tobool, label %exit, label %cond.false 173 174cond.false: 175 %val = load ptr, ptr %obj 176 %objsize = call i64 @llvm.objectsize.i64.p0(ptr %val, i1 false, i1 true, i1 false) 177 br label %exit 178 179exit: 180 %cond = phi i64 [ -2, %entry ], [ %objsize, %cond.false ] 181 ret i64 %cond 182 183} 184 185; Check posix_memalign call with two different paths leading to the same alloc. 186define dso_local i64 @check_posix_memalign_diamond() local_unnamed_addr { 187; CHECK-LABEL: @check_posix_memalign_diamond( 188; CHECK-NEXT: entry: 189; CHECK-NEXT: [[OBJ:%.*]] = alloca ptr, align 8 190; CHECK-NEXT: [[CALL:%.*]] = call i32 @posix_memalign(ptr noundef nonnull [[OBJ]], i64 noundef 8, i64 noundef 10) 191; CHECK-NEXT: [[TOBOOL_NOT:%.*]] = icmp eq i32 [[CALL]], 0 192; CHECK-NEXT: br i1 [[TOBOOL_NOT]], label [[COND_FALSE:%.*]], label [[COND_TRUE:%.*]] 193; CHECK: cond.true: 194; CHECK-NEXT: br label [[EXIT:%.*]] 195; CHECK: cond.false: 196; CHECK-NEXT: br label [[EXIT]] 197; CHECK: exit: 198; CHECK-NEXT: [[COND:%.*]] = phi i64 [ -2, [[COND_TRUE]] ], [ 10, [[COND_FALSE]] ] 199; CHECK-NEXT: ret i64 [[COND]] 200; 201entry: 202 %obj = alloca ptr 203 %call = call i32 @posix_memalign(ptr noundef %obj, i64 noundef 8, i64 noundef 10) 204 %tobool = icmp ne i32 %call, 0 205 br i1 %tobool, label %cond.true, label %cond.false 206 207cond.true: 208 br label %exit 209 210cond.false: 211 %val = load ptr, ptr %obj 212 %objsize = call i64 @llvm.objectsize.i64.p0(ptr %val, i1 false, i1 true, i1 false) 213 br label %exit 214 215exit: 216 %cond = phi i64 [ -2, %cond.true ], [ %objsize, %cond.false ] 217 ret i64 %cond 218 219} 220