1; RUN: sed -e 's/SLHATTR/speculative_load_hardening/' %s | llc -verify-machineinstrs -mtriple=aarch64-none-linux-gnu | FileCheck %s --check-prefixes=CHECK,SLH 2; RUN: sed -e 's/SLHATTR//' %s | llc -verify-machineinstrs -mtriple=aarch64-none-linux-gnu | FileCheck %s --check-prefixes=CHECK,NOSLH 3; RUN: sed -e 's/SLHATTR/speculative_load_hardening/' %s | llc -verify-machineinstrs -mtriple=aarch64-none-linux-gnu -global-isel | FileCheck %s --check-prefixes=CHECK,SLH 4; RUN: sed -e 's/SLHATTR//' %s | llc -verify-machineinstrs -mtriple=aarch64-none-linux-gnu -global-isel | FileCheck %s --check-prefixes=CHECK,NOSLH 5; RUN: sed -e 's/SLHATTR/speculative_load_hardening/' %s | llc -verify-machineinstrs -mtriple=aarch64-none-linux-gnu -fast-isel | FileCheck %s --check-prefixes=CHECK,SLH 6; RUN: sed -e 's/SLHATTR//' %s | llc -verify-machineinstrs -mtriple=aarch64-none-linux-gnu -fast-isel | FileCheck %s --check-prefixes=CHECK,NOSLH 7 8define i32 @f(i8* nocapture readonly %p, i32 %i, i32 %N) local_unnamed_addr SLHATTR { 9; CHECK-LABEL: f 10entry: 11; SLH: cmp sp, #0 12; SLH: csetm x16, ne 13; NOSLH-NOT: cmp sp, #0 14; NOSLH-NOT: csetm x16, ne 15 16; SLH: mov [[TMPREG:x[0-9]+]], sp 17; SLH: and [[TMPREG]], [[TMPREG]], x16 18; SLH: mov sp, [[TMPREG]] 19; NOSLH-NOT: mov {{x[0-9]+}}, sp 20; NOSLH-NOT: and [[TMPREG:x[0-9]+]], [[TMPREG]], x16 21; NOSLH-NOT: mov sp, {{x[0-9]+}} 22 %call = tail call i32 @tail_callee(i32 %i) 23; SLH: cmp sp, #0 24; SLH: csetm x16, ne 25; NOSLH-NOT: cmp sp, #0 26; NOSLH-NOT: csetm x16, ne 27 %cmp = icmp slt i32 %call, %N 28 br i1 %cmp, label %if.then, label %return 29; CHECK: b.[[COND:(ge)|(lt)|(ne)|(eq)]] 30 31if.then: ; preds = %entry 32; NOSLH-NOT: csel x16, x16, xzr, {{(lt)|(ge)|(eq)|(ne)}} 33; SLH-DAG: csel x16, x16, xzr, {{(lt)|(ge)|(eq)|(ne)}} 34 %idxprom = sext i32 %i to i64 35 %arrayidx = getelementptr inbounds i8, i8* %p, i64 %idxprom 36 %0 = load i8, i8* %arrayidx, align 1 37; CHECK-DAG: ldrb [[LOADED:w[0-9]+]], 38 %conv = zext i8 %0 to i32 39 br label %return 40 41; SLH-DAG: csel x16, x16, xzr, [[COND]] 42; NOSLH-NOT: csel x16, x16, xzr, [[COND]] 43return: ; preds = %entry, %if.then 44 %retval.0 = phi i32 [ %conv, %if.then ], [ 0, %entry ] 45; SLH: mov [[TMPREG:x[0-9]+]], sp 46; SLH: and [[TMPREG]], [[TMPREG]], x16 47; SLH: mov sp, [[TMPREG]] 48; NOSLH-NOT: mov {{x[0-9]+}}, sp 49; NOSLH-NOT: and [[TMPREG:x[0-9]+]], [[TMPREG]], x16 50; NOSLH-NOT: mov sp, {{x[0-9]+}} 51 ret i32 %retval.0 52} 53 54; Make sure that for a tail call, taint doesn't get put into SP twice. 55define i32 @tail_caller(i32 %a) local_unnamed_addr SLHATTR { 56; CHECK-LABEL: tail_caller: 57; SLH: mov [[TMPREG:x[0-9]+]], sp 58; SLH: and [[TMPREG]], [[TMPREG]], x16 59; SLH: mov sp, [[TMPREG]] 60; NOSLH-NOT: mov {{x[0-9]+}}, sp 61; NOSLH-NOT: and [[TMPREG:x[0-9]+]], [[TMPREG]], x16 62; NOSLH-NOT: mov sp, {{x[0-9]+}} 63; SLH: b tail_callee 64; SLH-NOT: cmp sp, #0 65 %call = tail call i32 @tail_callee(i32 %a) 66 ret i32 %call 67} 68 69declare i32 @tail_callee(i32) local_unnamed_addr 70 71; Verify that no cb(n)z/tb(n)z instructions are produced when implementing 72; SLH 73define i32 @compare_branch_zero(i32, i32) SLHATTR { 74; CHECK-LABEL: compare_branch_zero 75 %3 = icmp eq i32 %0, 0 76 br i1 %3, label %then, label %else 77;SLH-NOT: cb{{n?}}z 78;NOSLH: cb{{n?}}z 79then: 80 %4 = sdiv i32 5, %1 81 ret i32 %4 82else: 83 %5 = sdiv i32 %1, %0 84 ret i32 %5 85} 86 87define i32 @test_branch_zero(i32, i32) SLHATTR { 88; CHECK-LABEL: test_branch_zero 89 %3 = and i32 %0, 16 90 %4 = icmp eq i32 %3, 0 91 br i1 %4, label %then, label %else 92;SLH-NOT: tb{{n?}}z 93;NOSLH: tb{{n?}}z 94then: 95 %5 = sdiv i32 5, %1 96 ret i32 %5 97else: 98 %6 = sdiv i32 %1, %0 99 ret i32 %6 100} 101 102define i32 @landingpad(i32 %l0, i32 %l1) SLHATTR personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) { 103; CHECK-LABEL: landingpad 104entry: 105; SLH: cmp sp, #0 106; SLH: csetm x16, ne 107; NOSLH-NOT: cmp sp, #0 108; NOSLH-NOT: csetm x16, ne 109; CHECK: bl _Z10throwing_fv 110 invoke void @_Z10throwing_fv() 111 to label %exit unwind label %lpad 112; SLH: cmp sp, #0 113; SLH: csetm x16, ne 114 115lpad: 116 %l4 = landingpad { i8*, i32 } 117 catch i8* null 118; SLH: cmp sp, #0 119; SLH: csetm x16, ne 120; NOSLH-NOT: cmp sp, #0 121; NOSLH-NOT: csetm x16, ne 122 %l5 = extractvalue { i8*, i32 } %l4, 0 123 %l6 = tail call i8* @__cxa_begin_catch(i8* %l5) 124 %l7 = icmp sgt i32 %l0, %l1 125 br i1 %l7, label %then, label %else 126; GlobalISel lowers the branch to a b.ne sometimes instead of b.ge as expected.. 127; CHECK: b.[[COND:(le)|(gt)|(ne)|(eq)]] 128 129then: 130; SLH-DAG: csel x16, x16, xzr, [[COND]] 131 %l9 = sdiv i32 %l0, %l1 132 br label %postif 133 134else: 135; SLH-DAG: csel x16, x16, xzr, {{(gt)|(le)|(eq)|(ne)}} 136 %l11 = sdiv i32 %l1, %l0 137 br label %postif 138 139postif: 140 %l13 = phi i32 [ %l9, %then ], [ %l11, %else ] 141 tail call void @__cxa_end_catch() 142 br label %exit 143 144exit: 145 %l15 = phi i32 [ %l13, %postif ], [ 0, %entry ] 146 ret i32 %l15 147} 148 149declare i32 @__gxx_personality_v0(...) 150declare void @_Z10throwing_fv() local_unnamed_addr 151declare i8* @__cxa_begin_catch(i8*) local_unnamed_addr 152declare void @__cxa_end_catch() local_unnamed_addr 153