; RUN: opt < %s -aarch64-stack-tagging -S -o - | FileCheck %s --check-prefixes=CHECK,SSI ; RUN: opt < %s -aarch64-stack-tagging -stack-tagging-use-stack-safety=0 -S -o - | FileCheck %s --check-prefixes=CHECK,NOSSI target datalayout = "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128" target triple = "aarch64--linux-android" declare void @use8(i8*) declare void @use32(i32*) declare void @llvm.lifetime.start.p0i8(i64, i8* nocapture) declare void @llvm.lifetime.end.p0i8(i64, i8* nocapture) define dso_local void @noUse32(i32*) sanitize_memtag { entry: ret void } define void @OneVar() sanitize_memtag { entry: %x = alloca i32, align 4 call void @use32(i32* %x) ret void } ; CHECK-LABEL: define void @OneVar( ; CHECK: [[BASE:%.*]] = call i8* @llvm.aarch64.irg.sp(i64 0) ; CHECK: [[X:%.*]] = alloca { i32, [12 x i8] }, align 16 ; CHECK: [[TX:%.*]] = call { i32, [12 x i8] }* @llvm.aarch64.tagp.{{.*}}({ i32, [12 x i8] }* [[X]], i8* [[BASE]], i64 0) ; CHECK: [[TX8:%.*]] = bitcast { i32, [12 x i8] }* [[TX]] to i8* ; CHECK: call void @llvm.aarch64.settag(i8* [[TX8]], i64 16) ; CHECK: [[GEP32:%.*]] = bitcast { i32, [12 x i8] }* [[TX]] to i32* ; CHECK: call void @use32(i32* [[GEP32]]) ; CHECK: [[GEP8:%.*]] = bitcast { i32, [12 x i8] }* [[X]] to i8* ; CHECK: call void @llvm.aarch64.settag(i8* [[GEP8]], i64 16) ; CHECK: ret void define void @ManyVars() sanitize_memtag { entry: %x1 = alloca i32, align 4 %x2 = alloca i8, align 4 %x3 = alloca i32, i32 11, align 4 %x4 = alloca i32, align 4 call void @use32(i32* %x1) call void @use8(i8* %x2) call void @use32(i32* %x3) ret void } ; CHECK-LABEL: define void @ManyVars( ; CHECK: alloca { i32, [12 x i8] }, align 16 ; CHECK: call { i32, [12 x i8] }* @llvm.aarch64.tagp.{{.*}}({ i32, [12 x i8] }* {{.*}}, i64 0) ; CHECK: call void @llvm.aarch64.settag(i8* {{.*}}, i64 16) ; CHECK: alloca { i8, [15 x i8] }, align 16 ; CHECK: call { i8, [15 x i8] }* @llvm.aarch64.tagp.{{.*}}({ i8, [15 x i8] }* {{.*}}, i64 1) ; CHECK: call void @llvm.aarch64.settag(i8* {{.*}}, i64 16) ; CHECK: alloca { [11 x i32], [4 x i8] }, align 16 ; CHECK: call { [11 x i32], [4 x i8] }* @llvm.aarch64.tagp.{{.*}}({ [11 x i32], [4 x i8] }* {{.*}}, i64 2) ; CHECK: call void @llvm.aarch64.settag(i8* {{.*}}, i64 48) ; SSI: alloca i32, align 4 ; NOSSI: alloca { i32, [12 x i8] }, align 16 ; NOSSI: @llvm.aarch64.tagp. ; NOSSI: call void @llvm.aarch64.settag(i8* {{.*}}, i64 16) ; SSI-NOT: @llvm.aarch64.tagp ; SSI-NOT: @llvm.aarch64.settag ; CHECK: call void @use32( ; CHECK: call void @use8( ; CHECK: call void @use32( ; CHECK: call void @llvm.aarch64.settag(i8* {{.*}}, i64 16) ; CHECK: call void @llvm.aarch64.settag(i8* {{.*}}, i64 16) ; CHECK: call void @llvm.aarch64.settag(i8* {{.*}}, i64 48) ; NOSSI: call void @llvm.aarch64.settag(i8* {{.*}}, i64 16) ; CHECK-NEXT: ret void define void @Scope(i32 %b) sanitize_memtag { entry: %x = alloca i32, align 4 %tobool = icmp eq i32 %b, 0 br i1 %tobool, label %if.end, label %if.then if.then: %0 = bitcast i32* %x to i8* call void @llvm.lifetime.start.p0i8(i64 4, i8* nonnull %0) call void @use8(i8* %0) #3 call void @llvm.lifetime.end.p0i8(i64 4, i8* nonnull %0) br label %if.end if.end: ret void } ; CHECK-LABEL: define void @Scope( ; CHECK: br i1 ; CHECK: call void @llvm.lifetime.start.p0i8( ; CHECK: call void @llvm.aarch64.settag( ; CHECK: call void @use8( ; CHECK: call void @llvm.aarch64.settag( ; CHECK: call void @llvm.lifetime.end.p0i8( ; CHECK: br label ; CHECK: ret void ; Spooked by the multiple lifetime ranges, StackTagging remove all of them and sets tags on entry and exit. define void @BadScope(i32 %b) sanitize_memtag { entry: %x = alloca i32, align 4 %tobool = icmp eq i32 %b, 0 br i1 %tobool, label %if.end, label %if.then if.then: %0 = bitcast i32* %x to i8* call void @llvm.lifetime.start.p0i8(i64 4, i8* nonnull %0) call void @use8(i8* %0) #3 call void @llvm.lifetime.end.p0i8(i64 4, i8* nonnull %0) call void @llvm.lifetime.start.p0i8(i64 4, i8* nonnull %0) call void @use8(i8* %0) #3 call void @llvm.lifetime.end.p0i8(i64 4, i8* nonnull %0) br label %if.end if.end: ret void } ; CHECK-LABEL: define void @BadScope( ; CHECK: call void @llvm.aarch64.settag(i8* {{.*}}, i64 16) ; CHECK: br i1 ; CHECK: call void @use8(i8* ; CHECK-NEXT: call void @use8(i8* ; CHECK: br label ; CHECK: call void @llvm.aarch64.settag(i8* {{.*}}, i64 16) ; CHECK-NEXT: ret void define void @DynamicAllocas(i32 %cnt) sanitize_memtag { entry: %x = alloca i32, i32 %cnt, align 4 br label %l l: %y = alloca i32, align 4 call void @use32(i32* %x) call void @use32(i32* %y) ret void } ; CHECK-LABEL: define void @DynamicAllocas( ; CHECK-NOT: @llvm.aarch64.irg.sp ; CHECK: %x = alloca i32, i32 %cnt, align 4 ; CHECK-NOT: @llvm.aarch64.irg.sp ; CHECK: alloca i32, align 4 ; CHECK-NOT: @llvm.aarch64.irg.sp ; CHECK: ret void ; If we can't trace one of the lifetime markers to a single alloca, fall back ; to poisoning all allocas at the beginning of the function. ; Each alloca must be poisoned only once. define void @UnrecognizedLifetime(i8 %v) sanitize_memtag { entry: %x = alloca i32, align 4 %y = alloca i32, align 4 %z = alloca i32, align 4 %cx = bitcast i32* %x to i8* %cy = bitcast i32* %y to i8* %cz = bitcast i32* %z to i8* %tobool = icmp eq i8 %v, 0 %xy = select i1 %tobool, i32* %x, i32* %y %cxcy = select i1 %tobool, i8* %cx, i8* %cy br label %another_bb another_bb: call void @llvm.lifetime.start.p0i8(i64 4, i8* nonnull %cz) store i32 7, i32* %z call void @noUse32(i32* %z) call void @llvm.lifetime.end.p0i8(i64 4, i8* nonnull %cz) call void @llvm.lifetime.start.p0i8(i64 4, i8* nonnull %cz) store i32 7, i32* %z call void @llvm.lifetime.end.p0i8(i64 4, i8* nonnull %cz) call void @llvm.lifetime.start.p0i8(i64 4, i8* nonnull %cxcy) store i32 8, i32* %xy call void @noUse32(i32* %x) call void @noUse32(i32* %y) call void @llvm.lifetime.end.p0i8(i64 4, i8* nonnull %cxcy) ret void } ; CHECK-LABEL: define void @UnrecognizedLifetime( ; CHECK: call i8* @llvm.aarch64.irg.sp(i64 0) ; CHECK: alloca { i32, [12 x i8] }, align 16 ; CHECK: call { i32, [12 x i8] }* @llvm.aarch64.tagp ; CHECK: call void @llvm.aarch64.settag( ; CHECK: alloca { i32, [12 x i8] }, align 16 ; CHECK: call { i32, [12 x i8] }* @llvm.aarch64.tagp ; CHECK: call void @llvm.aarch64.settag( ; CHECK: alloca { i32, [12 x i8] }, align 16 ; CHECK: call { i32, [12 x i8] }* @llvm.aarch64.tagp ; CHECK: call void @llvm.aarch64.settag( ; CHECK: store i32 ; CHECK: call void @noUse32(i32* ; CHECK: store i32 ; CHECK: store i32 ; CHECK: call void @noUse32(i32* ; CHECK: call void @llvm.aarch64.settag( ; CHECK: call void @llvm.aarch64.settag( ; CHECK: call void @llvm.aarch64.settag( ; CHECK: ret void !0 = !{}