351 lines · plain
1; RUN: llc -mtriple=i686-unknown-linux-gnu -mattr=+cmov %s -o - | FileCheck %s --check-prefix=CHECK322; RUN: llc -mtriple=x86_64-unknown-linux-gnu -mattr=+cmov %s -o - | FileCheck %s --check-prefix=CHECK643; RUN: llc -mtriple=x86_64-pc-win32 -mattr=+cmov %s -o - | FileCheck %s --check-prefix=CHECKWIN644 5; RUN: llc -mtriple=i686-unknown-linux-gnu -mattr=+cmov %s -o /dev/null \6; RUN: -print-after postrapseudos -filter-print-funcs pr26023 2>&1 \7; RUN: | FileCheck %s --check-prefix=OPERAND328; RUN: llc -mtriple=x86_64-unknown-linux-gnu -mattr=+cmov %s -o /dev/null \9; RUN: -print-after postrapseudos -filter-print-funcs one64_minsize 2>&1 \10; RUN: | FileCheck %s --check-prefix=OPERAND6411 12define i32 @one32_nooptsize() {13entry:14 ret i32 115 16; When not optimizing for size, use mov.17; CHECK32-LABEL: one32_nooptsize:18; CHECK32: movl $1, %eax19; CHECK32-NEXT: retl20; CHECK64-LABEL: one32_nooptsize:21; CHECK64: movl $1, %eax22; CHECK64-NEXT: retq23}24 25define i32 @one32() optsize {26entry:27 ret i32 128 29; CHECK32-LABEL: one32:30; CHECK32: xorl %eax, %eax31; CHECK32-NEXT: incl %eax32; CHECK32-NEXT: retl33 34; FIXME: Figure out the best approach in 64-bit mode.35; CHECK64-LABEL: one32:36; CHECK64: movl $1, %eax37; CHECK64-NEXT: retq38}39 40define i32 @one32_pgso() !prof !14 {41entry:42 ret i32 143 44; CHECK32-LABEL: one32_pgso:45; CHECK32: xorl %eax, %eax46; CHECK32-NEXT: incl %eax47; CHECK32-NEXT: retl48 49; FIXME: Figure out the best approach in 64-bit mode.50; CHECK64-LABEL: one32_pgso:51; CHECK64: movl $1, %eax52; CHECK64-NEXT: retq53}54 55define i32 @one32_minsize() minsize {56entry:57 ret i32 158 59; On 32-bit, xor-inc is preferred over push-pop.60; CHECK32-LABEL: one32_minsize:61; CHECK32: xorl %eax, %eax62; CHECK32-NEXT: incl %eax63; CHECK32-NEXT: retl64 65; On 64-bit we don't do xor-inc yet, so push-pop it is. Note that we have to66; pop into a 64-bit register even when we just need 32 bits.67; CHECK64-LABEL: one32_minsize:68; CHECK64: pushq $169; CHECK64: .cfi_adjust_cfa_offset 870; CHECK64: popq %rax71; CHECK64: .cfi_adjust_cfa_offset -872; CHECK64-NEXT: retq73 74; On Win64 we can't adjust the stack unless there's a frame pointer.75; CHECKWIN64-LABEL: one32_minsize:76; CHECKWIN64: movl $1, %eax77; CHECKWIN64-NEXT: retq78}79 80define i32 @pr26023() minsize {81entry:82 %x = alloca [120 x i8]83 call void asm sideeffect "", "imr,~{memory},~{dirflag},~{fpsr},~{flags}"(ptr %x)84 %arrayidx = getelementptr inbounds [120 x i8], ptr %x, i64 0, i64 11985 store volatile i8 -2, ptr %arrayidx86 call void asm sideeffect "", "r,~{dirflag},~{fpsr},~{flags}"(i32 5)87 %0 = load volatile i8, ptr %arrayidx88 %conv = sext i8 %0 to i3289 ret i32 %conv90 91; The function writes to the redzone, so push/pop cannot be used.92; CHECK64-LABEL: pr26023:93; CHECK64: movl $5, %ecx94; CHECK64: retq95 96; 32-bit X86 doesn't have a redzone.97; CHECK32-LABEL: pr26023:98; CHECK32: pushl $599; CHECK32: popl %ecx100; CHECK32: retl101 102; Check push/pop have implicit def/use of $esp103; OPERAND32: PUSH32i 5, implicit-def $esp, implicit $esp104; OPERAND32-NEXT: CFI_INSTRUCTION adjust_cfa_offset 4105; OPERAND32-NEXT: renamable $ecx = POP32r implicit-def $esp, implicit $esp106; OPERAND32-NEXT: CFI_INSTRUCTION adjust_cfa_offset -4107}108 109 110define i64 @one64_minsize() minsize {111entry:112 ret i64 1113; On 64-bit we don't do xor-inc yet, so push-pop it is.114; CHECK64-LABEL: one64_minsize:115; CHECK64: pushq $1116; CHECK64: .cfi_adjust_cfa_offset 8117; CHECK64: popq %rax118; CHECK64: .cfi_adjust_cfa_offset -8119; CHECK64-NEXT: retq120 121; On Win64 we can't adjust the stack unless there's a frame pointer.122; CHECKWIN64-LABEL: one64_minsize:123; CHECKWIN64: movl $1, %eax124; CHECKWIN64-NEXT: retq125 126; Check push/pop have implicit def/use of $rsp127; OPERAND64: PUSH64i32 1, implicit-def $rsp, implicit $rsp128; OPERAND64-NEXT: CFI_INSTRUCTION adjust_cfa_offset 8129; OPERAND64-NEXT: $rax = POP64r implicit-def $rsp, implicit $rsp130; OPERAND64-NEXT: CFI_INSTRUCTION adjust_cfa_offset -8131; OPERAND64-NEXT: RET 0, $rax132}133 134define i32 @minus_one32() optsize {135entry:136 ret i32 -1137 138; CHECK32-LABEL: minus_one32:139; CHECK32: xorl %eax, %eax140; CHECK32-NEXT: decl %eax141; CHECK32-NEXT: retl142}143 144define i32 @minus_one32_pgso() !prof !14 {145entry:146 ret i32 -1147 148; CHECK32-LABEL: minus_one32_pgso:149; CHECK32: xorl %eax, %eax150; CHECK32-NEXT: decl %eax151; CHECK32-NEXT: retl152}153 154define i32 @minus_one32_minsize() minsize {155entry:156 ret i32 -1157 158; xor-dec is preferred over push-pop.159; CHECK32-LABEL: minus_one32_minsize:160; CHECK32: xorl %eax, %eax161; CHECK32-NEXT: decl %eax162; CHECK32-NEXT: retl163}164 165define i16 @one16() optsize {166entry:167 ret i16 1168 169; CHECK32-LABEL: one16:170; CHECK32: xorl %eax, %eax171; CHECK32-NEXT: incl %eax172; CHECK32-NEXT: # kill173; CHECK32-NEXT: retl174}175 176define i16 @minus_one16() optsize {177entry:178 ret i16 -1179 180; CHECK32-LABEL: minus_one16:181; CHECK32: xorl %eax, %eax182; CHECK32-NEXT: decl %eax183; CHECK32-NEXT: # kill184; CHECK32-NEXT: retl185}186 187define i16 @one16_pgso() !prof !14 {188entry:189 ret i16 1190 191; CHECK32-LABEL: one16_pgso:192; CHECK32: xorl %eax, %eax193; CHECK32-NEXT: incl %eax194; CHECK32-NEXT: # kill195; CHECK32-NEXT: retl196}197 198define i16 @minus_one16_pgso() !prof !14 {199entry:200 ret i16 -1201 202; CHECK32-LABEL: minus_one16_pgso:203; CHECK32: xorl %eax, %eax204; CHECK32-NEXT: decl %eax205; CHECK32-NEXT: # kill206; CHECK32-NEXT: retl207}208 209define i32 @minus_five32() minsize {210entry:211 ret i32 -5212 213; CHECK32-LABEL: minus_five32:214; CHECK32: pushl $-5215; CHECK32: popl %eax216; CHECK32: retl217}218 219define i64 @minus_five64() minsize {220entry:221 ret i64 -5222 223; CHECK64-LABEL: minus_five64:224; CHECK64: pushq $-5225; CHECK64: .cfi_adjust_cfa_offset 8226; CHECK64: popq %rax227; CHECK64: .cfi_adjust_cfa_offset -8228; CHECK64: retq229}230 231define i32 @rematerialize_minus_one() optsize {232entry:233 ; Materialize -1 (thiscall forces it into %ecx).234 tail call x86_thiscallcc void @f(i32 -1)235 236 ; Clobber all registers except %esp, leaving nowhere to store the -1 besides237 ; spilling it to the stack.238 tail call void asm sideeffect "", "~{eax},~{ebx},~{ecx},~{edx},~{edi},~{esi},~{ebp},~{dirflag},~{fpsr},~{flags}"()239 240 ; -1 should be re-materialized here instead of getting spilled above.241 ret i32 -1242 243; CHECK32-LABEL: rematerialize_minus_one244; CHECK32: xorl %ecx, %ecx245; CHECK32-NEXT: decl %ecx246; CHECK32: calll247; CHECK32: xorl %eax, %eax248; CHECK32-NEXT: decl %eax249; CHECK32-NOT: %eax250; CHECK32: retl251}252 253define i32 @rematerialize_minus_one_eflags(i32 %x) optsize {254entry:255 ; Materialize -1 (thiscall forces it into %ecx).256 tail call x86_thiscallcc void @f(i32 -1)257 258 ; Clobber all registers except %esp, leaving nowhere to store the -1 besides259 ; spilling it to the stack.260 tail call void asm sideeffect "", "~{eax},~{ebx},~{ecx},~{edx},~{edi},~{esi},~{ebp},~{dirflag},~{fpsr},~{flags}"()261 262 ; Define eflags.263 %a = icmp ne i32 %x, 123264 %b = zext i1 %a to i32265 ; Cause -1 to be rematerialized right in front of the cmov, which needs eflags.266 ; It must therefore not use the xor-dec lowering.267 %c = select i1 %a, i32 %b, i32 -1268 ret i32 %c269 270; CHECK32-LABEL: rematerialize_minus_one_eflags271; CHECK32: xorl %ecx, %ecx272; CHECK32-NEXT: decl %ecx273; CHECK32: calll274; CHECK32: cmpl275; CHECK32: setne276; CHECK32-NOT: xorl277; CHECK32: movl $-1278; CHECK32: cmov279; CHECK32: retl280}281 282define i32 @rematerialize_minus_one_pgso() !prof !14 {283entry:284 ; Materialize -1 (thiscall forces it into %ecx).285 tail call x86_thiscallcc void @f(i32 -1)286 287 ; Clobber all registers except %esp, leaving nowhere to store the -1 besides288 ; spilling it to the stack.289 tail call void asm sideeffect "", "~{eax},~{ebx},~{ecx},~{edx},~{edi},~{esi},~{ebp},~{dirflag},~{fpsr},~{flags}"()290 291 ; -1 should be re-materialized here instead of getting spilled above.292 ret i32 -1293 294; CHECK32-LABEL: rematerialize_minus_one_pgso295; CHECK32: xorl %ecx, %ecx296; CHECK32-NEXT: decl %ecx297; CHECK32: calll298; CHECK32: xorl %eax, %eax299; CHECK32-NEXT: decl %eax300; CHECK32-NOT: %eax301; CHECK32: retl302}303 304define i32 @rematerialize_minus_one_eflags_pgso(i32 %x) !prof !14 {305entry:306 ; Materialize -1 (thiscall forces it into %ecx).307 tail call x86_thiscallcc void @f(i32 -1)308 309 ; Clobber all registers except %esp, leaving nowhere to store the -1 besides310 ; spilling it to the stack.311 tail call void asm sideeffect "", "~{eax},~{ebx},~{ecx},~{edx},~{edi},~{esi},~{ebp},~{dirflag},~{fpsr},~{flags}"()312 313 ; Define eflags.314 %a = icmp ne i32 %x, 123315 %b = zext i1 %a to i32316 ; Cause -1 to be rematerialized right in front of the cmov, which needs eflags.317 ; It must therefore not use the xor-dec lowering.318 %c = select i1 %a, i32 %b, i32 -1319 ret i32 %c320 321; CHECK32-LABEL: rematerialize_minus_one_eflags_pgso322; CHECK32: xorl %ecx, %ecx323; CHECK32-NEXT: decl %ecx324; CHECK32: calll325; CHECK32: cmpl326; CHECK32: setne327; CHECK32-NOT: xorl328; CHECK32: movl $-1329; CHECK32: cmov330; CHECK32: retl331}332 333declare x86_thiscallcc void @f(i32)334 335!llvm.module.flags = !{!0}336!0 = !{i32 1, !"ProfileSummary", !1}337!1 = !{!2, !3, !4, !5, !6, !7, !8, !9}338!2 = !{!"ProfileFormat", !"InstrProf"}339!3 = !{!"TotalCount", i64 10000}340!4 = !{!"MaxCount", i64 10}341!5 = !{!"MaxInternalCount", i64 1}342!6 = !{!"MaxFunctionCount", i64 1000}343!7 = !{!"NumCounts", i64 3}344!8 = !{!"NumFunctions", i64 3}345!9 = !{!"DetailedSummary", !10}346!10 = !{!11, !12, !13}347!11 = !{i32 10000, i64 100, i32 1}348!12 = !{i32 999000, i64 100, i32 1}349!13 = !{i32 999999, i64 1, i32 2}350!14 = !{!"function_entry_count", i64 0}351