1; RUN: llc -mtriple=x86_64-pc-linux-gnu -mattr=+mwaitx -x86-use-base-pointer=true -stackrealign -stack-alignment=32 %s -o - | FileCheck --check-prefix=CHECK --check-prefix=USE_BASE_64 %s 2; RUN: llc -mtriple=x86_64-pc-linux-gnux32 -mattr=+mwaitx -x86-use-base-pointer=true -stackrealign -stack-alignment=32 %s -o - | FileCheck --check-prefix=CHECK --check-prefix=USE_BASE_32 %s 3; RUN: llc -mtriple=x86_64-pc-linux-gnu -mattr=+mwaitx -x86-use-base-pointer=true %s -o - | FileCheck --check-prefix=CHECK --check-prefix=NO_BASE_64 %s 4; RUN: llc -mtriple=x86_64-pc-linux-gnux32 -mattr=+mwaitx -x86-use-base-pointer=true %s -o - | FileCheck --check-prefix=CHECK --check-prefix=NO_BASE_32 %s 5 6; This test checks that we save and restore the base pointer (ebx or rbx) in the 7; presence of the mwaitx intrinsic which requires to use ebx for one of its 8; argument. 9; This function uses a dynamically allocated stack to force the use 10; of a base pointer. 11; After the call to the mwaitx intrinsic we do a volatile store to the 12; dynamically allocated memory which will require the use of the base pointer. 13; The base pointer should therefore be restored straight after the mwaitx 14; instruction. 15 16define void @test_baseptr(i64 %x, i64 %y, i32 %E, i32 %H, i32 %C) nounwind { 17entry: 18 %ptr = alloca i8*, align 8 19 %0 = alloca i8, i64 %x, align 16 20 store i8* %0, i8** %ptr, align 8 21 call void @llvm.x86.mwaitx(i32 %E, i32 %H, i32 %C) 22 %1 = load i8*, i8** %ptr, align 8 23 %arrayidx = getelementptr inbounds i8, i8* %1, i64 %y 24 store volatile i8 42, i8* %arrayidx, align 1 25 ret void 26} 27; CHECK-LABEL: test_baseptr: 28; USE_BASE_64: movq %rsp, %rbx 29; Pass mwaitx first 2 arguments in eax and ecx respectively. 30; USE_BASE_64: movl %ecx, %eax 31; USE_BASE_64: movl %edx, %ecx 32; Save base pointer. 33; USE_BASE_64: movq %rbx, [[SAVE_rbx:%r([8-9]|1[0-5]|di|si)]] 34; Set mwaitx ebx argument. 35; USE_BASE_64: movl %r8d, %ebx 36; USE_BASE_64-NEXT: mwaitx 37; Restore base pointer. 38; USE_BASE_64-NEXT: movq [[SAVE_rbx]], %rbx 39 40; USE_BASE_32: movl %esp, %ebx 41; Pass mwaitx first 2 arguments in eax and ecx respectively. 42; USE_BASE_32: movl %ecx, %eax 43; USE_BASE_32: movl %edx, %ecx 44; Save base pointer. 45; USE_BASE_32: movq %rbx, [[SAVE_rbx:%r(di|si)]] 46; Set mwaitx ebx argument. 47; USE_BASE_32: movl %r8d, %ebx 48; USE_BASE_32-NEXT: mwaitx 49; Restore base pointer. 50; USE_BASE_32-NEXT: movq [[SAVE_rbx]], %rbx 51 52; Pass mwaitx 3 arguments in eax, ecx, ebx 53; NO_BASE_64: movl %r8d, %ebx 54; NO_BASE_64: movl %ecx, %eax 55; NO_BASE_64: movl %edx, %ecx 56; No need to save base pointer. 57; NO_BASE_64-NOT: movq %rbx 58; NO_BASE_64: mwaitx 59; No need to restore base pointer. 60; NO_BASE_64-NOT: movq {{.*}}, %rbx 61; NO_BASE_64-NEXT: {{.+$}} 62 63; Pass mwaitx 3 arguments in eax, ecx, ebx 64; NO_BASE_32: movl %r8d, %ebx 65; NO_BASE_32: movl %ecx, %eax 66; NO_BASE_32: movl %edx, %ecx 67; No need to save base pointer. 68; NO_BASE_32-NOT: movl %ebx 69; NO_BASE_32: mwaitx 70; No need to restore base pointer. 71; NO_BASE_32-NOT: movl {{.*}}, %ebx 72; NO_BASE_32-NEXT: {{.+$}} 73 74; Test of the case where an opaque sp adjustement is introduced by a separate 75; basic block which, combined with stack realignment, requires a base pointer. 76@g = global i32 0, align 8 77 78define void @test_opaque_sp_adjustment(i32 %E, i32 %H, i32 %C, i64 %x) { 79entry: 80 %ptr = alloca i8*, align 8 81 call void @llvm.x86.mwaitx(i32 %E, i32 %H, i32 %C) 82 %g = load i32, i32* @g, align 4 83 %tobool = icmp ne i32 %g, 0 84 br i1 %tobool, label %if.then, label %if.end 85 86if.then: 87 call void asm sideeffect "", "~{rsp},~{esp},~{dirflag},~{fpsr},~{flags}"() 88 br label %if.end 89 90if.end: 91 %ptr2 = load i8*, i8** %ptr, align 8 92 %arrayidx = getelementptr inbounds i8, i8* %ptr2, i64 %x 93 store volatile i8 42, i8* %arrayidx, align 1 94 ret void 95} 96; CHECK-LABEL: test_opaque_sp_adjustment: 97; USE_BASE_64: movq %rsp, %rbx 98; Pass mwaitx first 2 arguments in eax and ecx respectively. 99; USE_BASE_64: movl %esi, %eax 100; USE_BASE_64: movl %edi, %ecx 101; Save base pointer. 102; USE_BASE_64: movq %rbx, [[SAVE_rbx:%r([8-9]|1[0-5]|di|si)]] 103; Set mwaitx ebx argument. 104; USE_BASE_64: movl %edx, %ebx 105; USE_BASE_64-NEXT: mwaitx 106; Restore base pointer. 107; USE_BASE_64-NEXT: movq [[SAVE_rbx]], %rbx 108 109; USE_BASE_32: movl %esp, %ebx 110; Pass mwaitx first 2 arguments in eax and ecx respectively. 111; USE_BASE_32: movl %esi, %eax 112; USE_BASE_32: movl %edi, %ecx 113; Save base pointer. 114; USE_BASE_32: movq %rbx, [[SAVE_rbx:%r(di|si)]] 115; Set mwaitx ebx argument. 116; USE_BASE_32: movl %edx, %ebx 117; USE_BASE_32-NEXT: mwaitx 118; Restore base pointer. 119; USE_BASE_32-NEXT: movq [[SAVE_rbx]], %rbx 120 121; Pass mwaitx 3 arguments in eax, ecx, ebx 122; NO_BASE_64: movl %edx, %ebx 123; NO_BASE_64: movl %esi, %eax 124; NO_BASE_64: movl %edi, %ecx 125; No need to save base pointer. 126; NO_BASE_64-NOT: movq %rbx 127; NO_BASE_64: mwaitx 128; NO_BASE_64-NOT: movq {{.*}}, %rbx 129; NO_BASE_64-NEXT: {{.+$}} 130 131; Pass mwaitx 3 arguments in eax, ecx, ebx 132; NO_BASE_32: movl %edx, %ebx 133; NO_BASE_32: movl %esi, %eax 134; NO_BASE_32: movl %edi, %ecx 135; No need to save base pointer. 136; NO_BASE_32-NOT: movl %ebx 137; NO_BASE_32: mwaitx 138; No need to restore base pointer. 139; NO_BASE_32-NOT: movl {{.*}}, %ebx 140; NO_BASE_32-NEXT: {{.+$}} 141 142; Test of the case where a variable size object is introduced by a separate 143; basic block which, combined with stack realignment, requires a base pointer. 144define void @test_variable_size_object(i32 %E, i32 %H, i32 %C, i64 %x) { 145entry: 146 %ptr = alloca i8*, align 8 147 call void @llvm.x86.mwaitx(i32 %E, i32 %H, i32 %C) 148 %g = load i32, i32* @g, align 4 149 %tobool = icmp ne i32 %g, 0 150 br i1 %tobool, label %if.then, label %if.end 151 152if.then: 153 %i5 = alloca i8, i64 %x, align 16 154 store i8* %i5, i8** %ptr, align 8 155 br label %if.end 156 157if.end: 158 %ptr2 = load i8*, i8** %ptr, align 8 159 %arrayidx = getelementptr inbounds i8, i8* %ptr2, i64 %x 160 store volatile i8 42, i8* %arrayidx, align 1 161 ret void 162} 163 164; CHECK-LABEL: test_variable_size_object: 165; USE_BASE_64: movq %rsp, %rbx 166; Pass mwaitx first 2 arguments in eax and ecx respectively. 167; USE_BASE_64: movl %esi, %eax 168; USE_BASE_64: movl %edi, %ecx 169; Save base pointer. 170; USE_BASE_64: movq %rbx, [[SAVE_rbx:%r([8-9]|1[0-5]|di|si)]] 171; Set mwaitx ebx argument. 172; USE_BASE_64: movl %edx, %ebx 173; USE_BASE_64-NEXT: mwaitx 174; Restore base pointer. 175; USE_BASE_64-NEXT: movq [[SAVE_rbx]], %rbx 176 177; USE_BASE_32: movl %esp, %ebx 178; Pass mwaitx first 2 arguments in eax and ecx respectively. 179; USE_BASE_32: movl %esi, %eax 180; USE_BASE_32: movl %edi, %ecx 181; Save base pointer. 182; USE_BASE_32: movq %rbx, [[SAVE_rbx:%r(di|si)]] 183; Set mwaitx ebx argument. 184; USE_BASE_32: movl %edx, %ebx 185; USE_BASE_32-NEXT: mwaitx 186; Restore base pointer. 187; USE_BASE_32-NEXT: movq [[SAVE_rbx]], %rbx 188 189; Pass mwaitx 3 arguments in eax, ecx, ebx 190; NO_BASE_64: movl %edx, %ebx 191; NO_BASE_64: movl %esi, %eax 192; NO_BASE_64: movl %edi, %ecx 193; No need to save base pointer. 194; NO_BASE_64-NOT: movq %rbx 195; NO_BASE_64: mwaitx 196; NO_BASE_64-NOT: movq {{.*}}, %rbx 197; NO_BASE_64-NEXT: {{.+$}} 198 199; Pass mwaitx 3 arguments in eax, ecx, ebx 200; NO_BASE_32: movl %edx, %ebx 201; NO_BASE_32: movl %esi, %eax 202; NO_BASE_32: movl %edi, %ecx 203; No need to save base pointer. 204; NO_BASE_32-NOT: movl %ebx 205; NO_BASE_32: mwaitx 206; No need to restore base pointer. 207; NO_BASE_32-NOT: movl {{.*}}, %ebx 208; NO_BASE_32-NEXT: {{.+$}} 209 210declare void @llvm.x86.mwaitx(i32, i32, i32) nounwind 211