| ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py |
| ; RUN: opt -passes=instcombine,lower-constant-intrinsics -S < %s | FileCheck %s |
| |
| target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" |
| target triple = "x86_64-unknown-linux-gnu" |
| |
| declare dso_local i32 @posix_memalign(ptr noundef, i64 noundef, i64 noundef) |
| declare i64 @llvm.objectsize.i64.p0(ptr, i1 immarg, i1 immarg, i1 immarg) |
| |
| ; Check posix_memalign call with proper handlig of return value |
| define dso_local i64 @check_posix_memalign(i32 noundef %n) local_unnamed_addr { |
| ; CHECK-LABEL: @check_posix_memalign( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: [[OBJ:%.*]] = alloca ptr, align 8 |
| ; CHECK-NEXT: [[CALL:%.*]] = call i32 @posix_memalign(ptr noundef nonnull [[OBJ]], i64 noundef 8, i64 noundef 10) |
| ; CHECK-NEXT: [[TOBOOL_NOT:%.*]] = icmp eq i32 [[CALL]], 0 |
| ; CHECK-NEXT: br i1 [[TOBOOL_NOT]], label [[COND_FALSE:%.*]], label [[EXIT:%.*]] |
| ; CHECK: cond.false: |
| ; CHECK-NEXT: br label [[EXIT]] |
| ; CHECK: exit: |
| ; CHECK-NEXT: [[COND:%.*]] = phi i64 [ -2, [[ENTRY:%.*]] ], [ 10, [[COND_FALSE]] ] |
| ; CHECK-NEXT: ret i64 [[COND]] |
| ; |
| entry: |
| %obj = alloca ptr |
| %call = call i32 @posix_memalign(ptr noundef %obj, i64 noundef 8, i64 noundef 10) |
| %tobool = icmp ne i32 %call, 0 |
| br i1 %tobool, label %exit, label %cond.false |
| |
| cond.false: |
| %val = load ptr, ptr %obj |
| %objsize = call i64 @llvm.objectsize.i64.p0(ptr %val, i1 false, i1 true, i1 false) |
| br label %exit |
| |
| exit: |
| %cond = phi i64 [ -2, %entry ], [ %objsize, %cond.false ] |
| ret i64 %cond |
| |
| } |
| |
| |
| ; Same test case as above but with idiomatic NULL initialization |
| define dso_local i64 @check_posix_memalign_null() { |
| ; CHECK-LABEL: @check_posix_memalign_null( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: [[OBJ:%.*]] = alloca ptr, align 8 |
| ; CHECK-NEXT: store ptr null, ptr [[OBJ]], align 8 |
| ; CHECK-NEXT: [[CALL:%.*]] = call i32 @posix_memalign(ptr noundef nonnull [[OBJ]], i64 noundef 8, i64 noundef 10) |
| ; CHECK-NEXT: [[TOBOOL_NOT:%.*]] = icmp eq i32 [[CALL]], 0 |
| ; CHECK-NEXT: br i1 [[TOBOOL_NOT]], label [[COND_FALSE:%.*]], label [[EXIT:%.*]] |
| ; CHECK: cond.false: |
| ; CHECK-NEXT: br label [[EXIT]] |
| ; CHECK: exit: |
| ; CHECK-NEXT: [[COND:%.*]] = phi i64 [ -2, [[ENTRY:%.*]] ], [ 10, [[COND_FALSE]] ] |
| ; CHECK-NEXT: ret i64 [[COND]] |
| ; |
| entry: |
| %obj = alloca ptr |
| store ptr null, ptr %obj |
| %call = call i32 @posix_memalign(ptr noundef %obj, i64 noundef 8, i64 noundef 10) |
| %tobool = icmp ne i32 %call, 0 |
| br i1 %tobool, label %exit, label %cond.false |
| |
| cond.false: |
| %val = load ptr, ptr %obj |
| %objsize = call i64 @llvm.objectsize.i64.p0(ptr %val, i1 false, i1 true, i1 false) |
| br label %exit |
| |
| exit: |
| %cond = phi i64 [ -2, %entry ], [ %objsize, %cond.false ] |
| ret i64 %cond |
| } |
| |
| ; Using argument storage instead of local storage for the allocated pointer. |
| define dso_local i64 @check_posix_memalign_arg(ptr noalias noundef %obj) { |
| ; CHECK-LABEL: @check_posix_memalign_arg( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: [[CALL:%.*]] = call i32 @posix_memalign(ptr noundef [[OBJ:%.*]], i64 noundef 8, i64 noundef 10) |
| ; CHECK-NEXT: [[TOBOOL_NOT:%.*]] = icmp eq i32 [[CALL]], 0 |
| ; CHECK-NEXT: br i1 [[TOBOOL_NOT]], label [[COND_FALSE:%.*]], label [[EXIT:%.*]] |
| ; CHECK: cond.false: |
| ; CHECK-NEXT: br label [[EXIT]] |
| ; CHECK: exit: |
| ; CHECK-NEXT: [[COND:%.*]] = phi i64 [ -2, [[ENTRY:%.*]] ], [ 10, [[COND_FALSE]] ] |
| ; CHECK-NEXT: ret i64 [[COND]] |
| ; |
| entry: |
| %call = call i32 @posix_memalign(ptr noundef %obj, i64 noundef 8, i64 noundef 10) |
| %tobool = icmp ne i32 %call, 0 |
| br i1 %tobool, label %exit, label %cond.false |
| |
| cond.false: |
| %val = load ptr, ptr %obj |
| %objsize = call i64 @llvm.objectsize.i64.p0(ptr %val, i1 false, i1 true, i1 false) |
| br label %exit |
| |
| exit: |
| %cond = phi i64 [ -2, %entry ], [ %objsize, %cond.false ] |
| ret i64 %cond |
| |
| } |
| |
| ; posix_memalign can fail, in that case no object_size can be guessed. |
| define dso_local i64 @check_posix_memalign_unchecked() { |
| ; CHECK-LABEL: @check_posix_memalign_unchecked( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: [[OBJ:%.*]] = alloca ptr, align 8 |
| ; CHECK-NEXT: [[CALL:%.*]] = call i32 @posix_memalign(ptr noundef nonnull [[OBJ]], i64 noundef 8, i64 noundef 10) |
| ; CHECK-NEXT: [[VAL:%.*]] = load ptr, ptr [[OBJ]], align 8 |
| ; CHECK-NEXT: ret i64 -1 |
| ; |
| entry: |
| %obj = alloca ptr |
| %call = call i32 @posix_memalign(ptr noundef %obj, i64 noundef 8, i64 noundef 10) |
| %val = load ptr, ptr %obj |
| %objsize = call i64 @llvm.objectsize.i64.p0(ptr %val, i1 false, i1 true, i1 false) |
| ret i64 %objsize |
| } |
| |
| ; Checks that bo upon posix_memalign failure behaves correctly |
| define dso_local i64 @check_posix_memalign_inverted_cond() { |
| ; CHECK-LABEL: @check_posix_memalign_inverted_cond( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: [[OBJ:%.*]] = alloca ptr, align 8 |
| ; CHECK-NEXT: store ptr null, ptr [[OBJ]], align 8 |
| ; CHECK-NEXT: [[CALL:%.*]] = call i32 @posix_memalign(ptr noundef nonnull [[OBJ]], i64 noundef 8, i64 noundef 10) |
| ; CHECK-NEXT: [[TOBOOL:%.*]] = icmp eq i32 [[CALL]], 0 |
| ; CHECK-NEXT: br i1 [[TOBOOL]], label [[EXIT:%.*]], label [[COND_FALSE:%.*]] |
| ; CHECK: cond.false: |
| ; CHECK-NEXT: [[VAL:%.*]] = load ptr, ptr [[OBJ]], align 8 |
| ; CHECK-NEXT: br label [[EXIT]] |
| ; CHECK: exit: |
| ; CHECK-NEXT: [[COND:%.*]] = phi i64 [ -2, [[ENTRY:%.*]] ], [ -1, [[COND_FALSE]] ] |
| ; CHECK-NEXT: ret i64 [[COND]] |
| ; |
| entry: |
| %obj = alloca ptr |
| store ptr null, ptr %obj |
| %call = call i32 @posix_memalign(ptr noundef %obj, i64 noundef 8, i64 noundef 10) |
| %tobool = icmp eq i32 %call, 0 |
| br i1 %tobool, label %exit, label %cond.false |
| |
| cond.false: |
| %val = load ptr, ptr %obj |
| %objsize = call i64 @llvm.objectsize.i64.p0(ptr %val, i1 false, i1 true, i1 false) |
| br label %exit |
| |
| exit: |
| %cond = phi i64 [ -2, %entry ], [ %objsize, %cond.false ] |
| ret i64 %cond |
| } |
| |
| ; Check posix_memalign call with a runtime condition check |
| define dso_local i64 @check_posix_memalign_runtime_cond(i32 noundef %n) local_unnamed_addr { |
| ; CHECK-LABEL: @check_posix_memalign_runtime_cond( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: [[OBJ:%.*]] = alloca ptr, align 8 |
| ; CHECK-NEXT: [[CALL:%.*]] = call i32 @posix_memalign(ptr noundef nonnull [[OBJ]], i64 noundef 8, i64 noundef 10) |
| ; CHECK-NEXT: [[TOBOOL_NOT:%.*]] = icmp eq i32 [[CALL]], [[N:%.*]] |
| ; CHECK-NEXT: br i1 [[TOBOOL_NOT]], label [[COND_FALSE:%.*]], label [[EXIT:%.*]] |
| ; CHECK: cond.false: |
| ; CHECK-NEXT: [[VAL:%.*]] = load ptr, ptr [[OBJ]], align 8 |
| ; CHECK-NEXT: br label [[EXIT]] |
| ; CHECK: exit: |
| ; CHECK-NEXT: [[COND:%.*]] = phi i64 [ -2, [[ENTRY:%.*]] ], [ -1, [[COND_FALSE]] ] |
| ; CHECK-NEXT: ret i64 [[COND]] |
| ; |
| entry: |
| %obj = alloca ptr |
| %call = call i32 @posix_memalign(ptr noundef %obj, i64 noundef 8, i64 noundef 10) |
| %tobool = icmp ne i32 %call, %n |
| br i1 %tobool, label %exit, label %cond.false |
| |
| cond.false: |
| %val = load ptr, ptr %obj |
| %objsize = call i64 @llvm.objectsize.i64.p0(ptr %val, i1 false, i1 true, i1 false) |
| br label %exit |
| |
| exit: |
| %cond = phi i64 [ -2, %entry ], [ %objsize, %cond.false ] |
| ret i64 %cond |
| |
| } |
| |
| ; Check posix_memalign call with two different paths leading to the same alloc. |
| define dso_local i64 @check_posix_memalign_diamond() local_unnamed_addr { |
| ; CHECK-LABEL: @check_posix_memalign_diamond( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: [[OBJ:%.*]] = alloca ptr, align 8 |
| ; CHECK-NEXT: [[CALL:%.*]] = call i32 @posix_memalign(ptr noundef nonnull [[OBJ]], i64 noundef 8, i64 noundef 10) |
| ; CHECK-NEXT: [[TOBOOL_NOT:%.*]] = icmp eq i32 [[CALL]], 0 |
| ; CHECK-NEXT: br i1 [[TOBOOL_NOT]], label [[COND_FALSE:%.*]], label [[COND_TRUE:%.*]] |
| ; CHECK: cond.true: |
| ; CHECK-NEXT: br label [[EXIT:%.*]] |
| ; CHECK: cond.false: |
| ; CHECK-NEXT: br label [[EXIT]] |
| ; CHECK: exit: |
| ; CHECK-NEXT: [[COND:%.*]] = phi i64 [ -2, [[COND_TRUE]] ], [ 10, [[COND_FALSE]] ] |
| ; CHECK-NEXT: ret i64 [[COND]] |
| ; |
| entry: |
| %obj = alloca ptr |
| %call = call i32 @posix_memalign(ptr noundef %obj, i64 noundef 8, i64 noundef 10) |
| %tobool = icmp ne i32 %call, 0 |
| br i1 %tobool, label %cond.true, label %cond.false |
| |
| cond.true: |
| br label %exit |
| |
| cond.false: |
| %val = load ptr, ptr %obj |
| %objsize = call i64 @llvm.objectsize.i64.p0(ptr %val, i1 false, i1 true, i1 false) |
| br label %exit |
| |
| exit: |
| %cond = phi i64 [ -2, %cond.true ], [ %objsize, %cond.false ] |
| ret i64 %cond |
| |
| } |