388 lines · plain
1; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --no_x86_scrub_sp --version 22; RUN: llc -mtriple=i686-unknown-unknown < %s | FileCheck %s3; RUN: llc -mtriple=i686-unknown-unknown -O0 < %s | FileCheck %s -check-prefix=CHECK04 5%struct.interrupt_frame = type { i32, i32, i32, i32, i32 }6 7@sink_address = global ptr null8@sink_i32 = global i32 09 10 11; Spills eax, putting original esp at +4.12; Stack is dyamically realigned to 16 bytes, and then reloaded to ebp - 413; With no error code, the stack is not incremented by 4 bytes before returning14define x86_intrcc void @test_isr_no_ecode(ptr byval(%struct.interrupt_frame) %frame) nounwind {15; CHECK-LABEL: test_isr_no_ecode:16; CHECK: # %bb.0:17; CHECK-NEXT: pushl %ebp18; CHECK-NEXT: movl %esp, %ebp19; CHECK-NEXT: pushl %eax20; CHECK-NEXT: andl $-16, %esp21; CHECK-NEXT: cld22; CHECK-NEXT: movl 12(%ebp), %eax23; CHECK-NEXT: #APP24; CHECK-NEXT: #NO_APP25; CHECK-NEXT: leal -4(%ebp), %esp26; CHECK-NEXT: popl %eax27; CHECK-NEXT: popl %ebp28; CHECK-NEXT: iretl29;30; CHECK0-LABEL: test_isr_no_ecode:31; CHECK0: # %bb.0:32; CHECK0-NEXT: pushl %ebp33; CHECK0-NEXT: movl %esp, %ebp34; CHECK0-NEXT: pushl %eax35; CHECK0-NEXT: andl $-16, %esp36; CHECK0-NEXT: cld37; CHECK0-NEXT: leal 4(%ebp), %eax38; CHECK0-NEXT: movl 8(%eax), %eax39; CHECK0-NEXT: #APP40; CHECK0-NEXT: #NO_APP41; CHECK0-NEXT: leal -4(%ebp), %esp42; CHECK0-NEXT: popl %eax43; CHECK0-NEXT: popl %ebp44; CHECK0-NEXT: iretl45; CHECK-NEXT; movl %esp, %ebp46 %pflags = getelementptr inbounds %struct.interrupt_frame, ptr %frame, i32 0, i32 247 %flags = load i32, ptr %pflags, align 448 call void asm sideeffect "", "r"(i32 %flags)49 ret void50}51 52; Spills eax and ecx, putting original esp at +8.53; Stack is dynamically realigned to 16 bytes, and then reloaded to ebp - 854; Error code is popped from the stack with an increment of 4 before returning55define x86_intrcc void @test_isr_ecode(ptr byval(%struct.interrupt_frame) %frame, i32 %ecode) nounwind {56; CHECK-LABEL: test_isr_ecode:57; CHECK: # %bb.0:58; CHECK-NEXT: pushl %ebp59; CHECK-NEXT: movl %esp, %ebp60; CHECK-NEXT: pushl %ecx61; CHECK-NEXT: pushl %eax62; CHECK-NEXT: andl $-16, %esp63; CHECK-NEXT: cld64; CHECK-NEXT: movl 4(%ebp), %eax65; CHECK-NEXT: movl 16(%ebp), %ecx66; CHECK-NEXT: #APP67; CHECK-NEXT: #NO_APP68; CHECK-NEXT: leal -8(%ebp), %esp69; CHECK-NEXT: popl %eax70; CHECK-NEXT: popl %ecx71; CHECK-NEXT: popl %ebp72; CHECK-NEXT: addl $4, %esp73; CHECK-NEXT: iretl74;75; CHECK0-LABEL: test_isr_ecode:76; CHECK0: # %bb.0:77; CHECK0-NEXT: pushl %ebp78; CHECK0-NEXT: movl %esp, %ebp79; CHECK0-NEXT: pushl %ecx80; CHECK0-NEXT: pushl %eax81; CHECK0-NEXT: andl $-16, %esp82; CHECK0-NEXT: cld83; CHECK0-NEXT: movl 4(%ebp), %ecx84; CHECK0-NEXT: leal 8(%ebp), %eax85; CHECK0-NEXT: movl 8(%eax), %eax86; CHECK0-NEXT: #APP87; CHECK0-NEXT: #NO_APP88; CHECK0-NEXT: leal -8(%ebp), %esp89; CHECK0-NEXT: popl %eax90; CHECK0-NEXT: popl %ecx91; CHECK0-NEXT: popl %ebp92; CHECK0-NEXT: addl $4, %esp93; CHECK0-NEXT: iretl94 %pflags = getelementptr inbounds %struct.interrupt_frame, ptr %frame, i32 0, i32 295 %flags = load i32, ptr %pflags, align 496 call x86_fastcallcc void asm sideeffect "", "r,r"(i32 %flags, i32 %ecode)97 ret void98}99 100; All clobbered registers must be saved101define x86_intrcc void @test_isr_clobbers(ptr byval(%struct.interrupt_frame) %frame, i32 %ecode) nounwind {102; CHECK-LABEL: test_isr_clobbers:103; CHECK: # %bb.0:104; CHECK-NEXT: pushl %ebp105; CHECK-NEXT: movl %esp, %ebp106; CHECK-NEXT: pushl %ecx107; CHECK-NEXT: pushl %ebx108; CHECK-NEXT: pushl %eax109; CHECK-NEXT: andl $-16, %esp110; CHECK-NEXT: cld111; CHECK-NEXT: pushl %ebp112; CHECK-NEXT: #APP113; CHECK-NEXT: #NO_APP114; CHECK-NEXT: popl %ebp115; CHECK-NEXT: leal -12(%ebp), %esp116; CHECK-NEXT: popl %eax117; CHECK-NEXT: popl %ebx118; CHECK-NEXT: popl %ecx119; CHECK-NEXT: popl %ebp120; CHECK-NEXT: addl $4, %esp121; CHECK-NEXT: iretl122;123; CHECK0-LABEL: test_isr_clobbers:124; CHECK0: # %bb.0:125; CHECK0-NEXT: pushl %ebp126; CHECK0-NEXT: movl %esp, %ebp127; CHECK0-NEXT: pushl %ecx128; CHECK0-NEXT: pushl %ebx129; CHECK0-NEXT: pushl %eax130; CHECK0-NEXT: andl $-16, %esp131; CHECK0-NEXT: cld132; CHECK0-NEXT: pushl %ebp133; CHECK0-NEXT: #APP134; CHECK0-NEXT: #NO_APP135; CHECK0-NEXT: popl %ebp136; CHECK0-NEXT: leal -12(%ebp), %esp137; CHECK0-NEXT: popl %eax138; CHECK0-NEXT: popl %ebx139; CHECK0-NEXT: popl %ecx140; CHECK0-NEXT: popl %ebp141; CHECK0-NEXT: addl $4, %esp142; CHECK0-NEXT: iretl143 call void asm sideeffect "", "~{eax},~{ebx},~{ecx},~{ebp}"()144 ret void145}146 147@f80 = common global x86_fp80 0xK00000000000000000000, align 4148 149; Test that the presence of x87 does not crash the FP stackifier150define x86_intrcc void @test_isr_x87(ptr byval(%struct.interrupt_frame) %frame) nounwind {151; CHECK-LABEL: test_isr_x87:152; CHECK: # %bb.0: # %entry153; CHECK-NEXT: pushl %ebp154; CHECK-NEXT: movl %esp, %ebp155; CHECK-NEXT: andl $-16, %esp156; CHECK-NEXT: fldt f80157; CHECK-NEXT: fld1158; CHECK-NEXT: faddp %st, %st(1)159; CHECK-NEXT: fstpt f80160; CHECK-NEXT: movl %ebp, %esp161; CHECK-NEXT: popl %ebp162; CHECK-NEXT: iretl163;164; CHECK0-LABEL: test_isr_x87:165; CHECK0: # %bb.0: # %entry166; CHECK0-NEXT: pushl %ebp167; CHECK0-NEXT: movl %esp, %ebp168; CHECK0-NEXT: andl $-16, %esp169; CHECK0-NEXT: fldt f80170; CHECK0-NEXT: fld1171; CHECK0-NEXT: faddp %st, %st(1)172; CHECK0-NEXT: fstpt f80173; CHECK0-NEXT: movl %ebp, %esp174; CHECK0-NEXT: popl %ebp175; CHECK0-NEXT: iretl176entry:177 %ld = load x86_fp80, ptr @f80, align 4178 %add = fadd x86_fp80 %ld, 0xK3FFF8000000000000000179 store x86_fp80 %add, ptr @f80, align 4180 ret void181}182 183; Use the interrupt_frame pointer to check the offsets.184; No return address, arguments start at EBP+4.185define dso_local x86_intrcc void @test_fp_1(ptr byval(%struct.interrupt_frame) %p) #0 {186; CHECK-LABEL: test_fp_1:187; CHECK: # %bb.0: # %entry188; CHECK-NEXT: pushl %ebp189; CHECK-NEXT: movl %esp, %ebp190; CHECK-NEXT: pushl %ecx191; CHECK-NEXT: pushl %eax192; CHECK-NEXT: andl $-16, %esp193; CHECK-NEXT: leal 20(%ebp), %eax194; CHECK-NEXT: leal 4(%ebp), %ecx195; CHECK-NEXT: movl %ecx, sink_address196; CHECK-NEXT: movl %eax, sink_address197; CHECK-NEXT: leal -8(%ebp), %esp198; CHECK-NEXT: popl %eax199; CHECK-NEXT: popl %ecx200; CHECK-NEXT: popl %ebp201; CHECK-NEXT: iretl202;203; CHECK0-LABEL: test_fp_1:204; CHECK0: # %bb.0: # %entry205; CHECK0-NEXT: pushl %ebp206; CHECK0-NEXT: movl %esp, %ebp207; CHECK0-NEXT: pushl %ecx208; CHECK0-NEXT: pushl %eax209; CHECK0-NEXT: andl $-16, %esp210; CHECK0-NEXT: leal 4(%ebp), %ecx211; CHECK0-NEXT: movl %ecx, %eax212; CHECK0-NEXT: addl $16, %eax213; CHECK0-NEXT: movl %ecx, sink_address214; CHECK0-NEXT: movl %eax, sink_address215; CHECK0-NEXT: leal -8(%ebp), %esp216; CHECK0-NEXT: popl %eax217; CHECK0-NEXT: popl %ecx218; CHECK0-NEXT: popl %ebp219; CHECK0-NEXT: iretl220entry:221 %arrayidx2 = getelementptr inbounds %struct.interrupt_frame, ptr %p, i32 0, i32 4222 store volatile ptr %p, ptr @sink_address223 store volatile ptr %arrayidx2, ptr @sink_address224 ret void225}226 227; The error code is between EBP and the interrupt_frame.228define dso_local x86_intrcc void @test_fp_2(ptr byval(%struct.interrupt_frame) %p, i32 %err) #0 {229; CHECK-LABEL: test_fp_2:230; CHECK: # %bb.0: # %entry231; CHECK-NEXT: pushl %ebp232; CHECK-NEXT: movl %esp, %ebp233; CHECK-NEXT: pushl %edx234; CHECK-NEXT: pushl %ecx235; CHECK-NEXT: pushl %eax236; CHECK-NEXT: andl $-16, %esp237; CHECK-NEXT: movl 4(%ebp), %eax238; CHECK-NEXT: leal 24(%ebp), %ecx239; CHECK-NEXT: leal 8(%ebp), %edx240; CHECK-NEXT: movl %edx, sink_address241; CHECK-NEXT: movl %ecx, sink_address242; CHECK-NEXT: movl %eax, sink_i32243; CHECK-NEXT: leal -12(%ebp), %esp244; CHECK-NEXT: popl %eax245; CHECK-NEXT: popl %ecx246; CHECK-NEXT: popl %edx247; CHECK-NEXT: popl %ebp248; CHECK-NEXT: addl $4, %esp249; CHECK-NEXT: iretl250;251; CHECK0-LABEL: test_fp_2:252; CHECK0: # %bb.0: # %entry253; CHECK0-NEXT: pushl %ebp254; CHECK0-NEXT: movl %esp, %ebp255; CHECK0-NEXT: pushl %edx256; CHECK0-NEXT: pushl %ecx257; CHECK0-NEXT: pushl %eax258; CHECK0-NEXT: andl $-16, %esp259; CHECK0-NEXT: movl 4(%ebp), %eax260; CHECK0-NEXT: leal 8(%ebp), %edx261; CHECK0-NEXT: movl %edx, %ecx262; CHECK0-NEXT: addl $16, %ecx263; CHECK0-NEXT: movl %edx, sink_address264; CHECK0-NEXT: movl %ecx, sink_address265; CHECK0-NEXT: movl %eax, sink_i32266; CHECK0-NEXT: leal -12(%ebp), %esp267; CHECK0-NEXT: popl %eax268; CHECK0-NEXT: popl %ecx269; CHECK0-NEXT: popl %edx270; CHECK0-NEXT: popl %ebp271; CHECK0-NEXT: addl $4, %esp272; CHECK0-NEXT: iretl273entry:274 %arrayidx2 = getelementptr inbounds %struct.interrupt_frame, ptr %p, i32 0, i32 4275 store volatile ptr %p, ptr @sink_address276 store volatile ptr %arrayidx2, ptr @sink_address277 store volatile i32 %err, ptr @sink_i32278 ret void279}280 281; Test argument copy elision when copied to a local alloca.282define x86_intrcc void @test_copy_elide(ptr byval(%struct.interrupt_frame) %frame, i32 %err) #0 {283; CHECK-LABEL: test_copy_elide:284; CHECK: # %bb.0: # %entry285; CHECK-NEXT: pushl %ebp286; CHECK-NEXT: movl %esp, %ebp287; CHECK-NEXT: pushl %eax288; CHECK-NEXT: andl $-16, %esp289; CHECK-NEXT: leal 4(%ebp), %eax290; CHECK-NEXT: movl %eax, sink_address291; CHECK-NEXT: leal -4(%ebp), %esp292; CHECK-NEXT: popl %eax293; CHECK-NEXT: popl %ebp294; CHECK-NEXT: addl $4, %esp295; CHECK-NEXT: iretl296;297; CHECK0-LABEL: test_copy_elide:298; CHECK0: # %bb.0: # %entry299; CHECK0-NEXT: pushl %ebp300; CHECK0-NEXT: movl %esp, %ebp301; CHECK0-NEXT: pushl %eax302; CHECK0-NEXT: andl $-16, %esp303; CHECK0-NEXT: movl 4(%ebp), %eax304; CHECK0-NEXT: leal 4(%ebp), %eax305; CHECK0-NEXT: movl %eax, sink_address306; CHECK0-NEXT: leal -4(%ebp), %esp307; CHECK0-NEXT: popl %eax308; CHECK0-NEXT: popl %ebp309; CHECK0-NEXT: addl $4, %esp310; CHECK0-NEXT: iretl311entry:312 %err.addr = alloca i32, align 4313 store i32 %err, ptr %err.addr, align 4314 store volatile ptr %err.addr, ptr @sink_address315 ret void316}317 318; Disabling dynamic realignment with attributes should work319define x86_intrcc void @test_isr_no_realign(ptr byval(%struct.interrupt_frame) %frame) #1 {320; CHECK-LABEL: test_isr_no_realign:321; CHECK: # %bb.0:322; CHECK-NEXT: pushl %eax323; CHECK-NEXT: cld324; CHECK-NEXT: movl 12(%esp), %eax325; CHECK-NEXT: #APP326; CHECK-NEXT: #NO_APP327; CHECK-NEXT: popl %eax328; CHECK-NEXT: iretl329;330; CHECK0-LABEL: test_isr_no_realign:331; CHECK0: # %bb.0:332; CHECK0-NEXT: pushl %eax333; CHECK0-NEXT: cld334; CHECK0-NEXT: leal 4(%esp), %eax335; CHECK0-NEXT: movl 8(%eax), %eax336; CHECK0-NEXT: #APP337; CHECK0-NEXT: #NO_APP338; CHECK0-NEXT: popl %eax339; CHECK0-NEXT: iretl340 %pflags = getelementptr inbounds %struct.interrupt_frame, ptr %frame, i32 0, i32 2341 %flags = load i32, ptr %pflags, align 4342 call void asm sideeffect "", "r"(i32 %flags)343 ret void344}345 346; The stackrealign attribute should work, and the function's alignment347; should be respected over the default 16-byte alignment required by the calling348; convention.349define x86_intrcc void @test_isr_realign(ptr byval(%struct.interrupt_frame) %frame, i32 %ecode) #2 {350; CHECK-LABEL: test_isr_realign:351; CHECK: # %bb.0:352; CHECK-NEXT: pushl %ebp353; CHECK-NEXT: movl %esp, %ebp354; CHECK-NEXT: pushl %eax355; CHECK-NEXT: andl $-32, %esp356; CHECK-NEXT: subl $32, %esp357; CHECK-NEXT: movl 4(%ebp), %eax358; CHECK-NEXT: movl %eax, (%esp)359; CHECK-NEXT: leal -4(%ebp), %esp360; CHECK-NEXT: popl %eax361; CHECK-NEXT: popl %ebp362; CHECK-NEXT: addl $4, %esp363; CHECK-NEXT: iretl364;365; CHECK0-LABEL: test_isr_realign:366; CHECK0: # %bb.0:367; CHECK0-NEXT: pushl %ebp368; CHECK0-NEXT: movl %esp, %ebp369; CHECK0-NEXT: pushl %eax370; CHECK0-NEXT: andl $-32, %esp371; CHECK0-NEXT: subl $32, %esp372; CHECK0-NEXT: movl 4(%ebp), %eax373; CHECK0-NEXT: movl %eax, (%esp)374; CHECK0-NEXT: leal -4(%ebp), %esp375; CHECK0-NEXT: popl %eax376; CHECK0-NEXT: popl %ebp377; CHECK0-NEXT: addl $4, %esp378; CHECK0-NEXT: iretl379 %ecode.stack = alloca i32, align 32380 store i32 %ecode, ptr %ecode.stack381 ret void382}383 384 385attributes #0 = { nounwind "frame-pointer"="all" }386attributes #1 = { nounwind "no-realign-stack" }387attributes #2 = { nounwind "stackrealign" }388