| ; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6 | |
| ; NOTE: Test cases for FCMP-FCSEL and CMP/CMN-CSEL code layout optimization | |
| ; RUN: llc < %s -verify-machineinstrs -mtriple=aarch64-apple-darwin -aarch64-code-layout-opt-enable=fcmp-fcsel,cmp-csel | FileCheck %s --check-prefixes=CHECK,ENABLED | |
| ; RUN: llc < %s -verify-machineinstrs -mtriple=aarch64-apple-darwin -mcpu=apple-m4 -aarch64-code-layout-opt-enable=fcmp-fcsel,cmp-csel | FileCheck %s --check-prefixes=CHECK,ENABLED | |
| ; Default for -mcpu=apple-m4 enables both fcmp-fcsel and cmp-csel; expect identical output. | |
| ; RUN: llc < %s -verify-machineinstrs -mtriple=aarch64-apple-darwin -mcpu=apple-m4 | FileCheck %s --check-prefixes=CHECK,ENABLED | |
| ; RUN: llc < %s -verify-machineinstrs -mtriple=aarch64-apple-darwin -mcpu=apple-m4 -aarch64-code-layout-opt-enable=none | FileCheck %s --check-prefixes=CHECK,DISABLED | |
| ; RUN: llc < %s -verify-machineinstrs -mtriple=aarch64-apple-darwin | FileCheck %s --check-prefixes=CHECK,DEFAULT | |
| ; RUN: llc < %s -verify-machineinstrs -mtriple=aarch64-windows-msvc -mcpu=apple-m4 | FileCheck %s --check-prefixes=WINDOWS | |
| ; Test coverage for optimizeForCodeLayout function: | |
| ; * Basic FCMP-FCSEL instruction pair detection and function alignment (single/double precision) | |
| ; * Multiple FCMP-FCSEL pairs in same function (also tests different predicates) | |
| ; * Mixed single and double precision in same function | |
| ; * FCMP with immediate operand (#0.0) is excluded from optimization | |
| ; * Instruction pairs with function calls | |
| ; * Negative tests (no false positives) | |
| ; * Basic CMP-CSEL and CMN-CSEL instruction pair detection and function alignment | |
| ; * CMP/CMN with immediate <=15 qualifies; immediate >15 is excluded | |
| ; * Basic single-precision FCMP-FCSEL instruction pair | |
| define float @test_basic_fcmp_fcsel_single(float %a, float %b, float %c, float %d) { | |
| ; ENABLED-LABEL: test_basic_fcmp_fcsel_single: | |
| ; ENABLED: .p2align 6, , 4 | |
| ; ENABLED-NEXT: ; %bb.0: ; %entry | |
| ; ENABLED-NEXT: fcmp s0, s1 | |
| ; ENABLED-NEXT: fcsel s0, s2, s3, eq | |
| ; ENABLED-NEXT: ret | |
| ; | |
| ; DISABLED-LABEL: test_basic_fcmp_fcsel_single: | |
| ; DISABLED: ; %bb.0: ; %entry | |
| ; DISABLED-NEXT: fcmp s0, s1 | |
| ; DISABLED-NEXT: fcsel s0, s2, s3, eq | |
| ; DISABLED-NEXT: ret | |
| ; | |
| ; DEFAULT-LABEL: test_basic_fcmp_fcsel_single: | |
| ; DEFAULT: ; %bb.0: ; %entry | |
| ; DEFAULT-NEXT: fcmp s0, s1 | |
| ; DEFAULT-NEXT: fcsel s0, s2, s3, eq | |
| ; DEFAULT-NEXT: ret | |
| ; | |
| ; WINDOWS-LABEL: test_basic_fcmp_fcsel_single: | |
| ; WINDOWS: // %bb.0: // %entry | |
| ; WINDOWS-NEXT: fcmp s0, s1 | |
| ; WINDOWS-NEXT: fcsel s0, s2, s3, eq | |
| ; WINDOWS-NEXT: ret | |
| entry: | |
| %cmp = fcmp oeq float %a, %b | |
| %sel = select i1 %cmp, float %c, float %d | |
| ret float %sel | |
| } | |
| ; * Basic double-precision FCMP-FCSEL instruction pair | |
| define double @test_basic_fcmp_fcsel_double(double %a, double %b, double %c, double %d) { | |
| ; ENABLED-LABEL: test_basic_fcmp_fcsel_double: | |
| ; ENABLED: .p2align 6, , 4 | |
| ; ENABLED-NEXT: ; %bb.0: ; %entry | |
| ; ENABLED-NEXT: fcmp d0, d1 | |
| ; ENABLED-NEXT: fcsel d0, d2, d3, eq | |
| ; ENABLED-NEXT: ret | |
| ; | |
| ; DISABLED-LABEL: test_basic_fcmp_fcsel_double: | |
| ; DISABLED: ; %bb.0: ; %entry | |
| ; DISABLED-NEXT: fcmp d0, d1 | |
| ; DISABLED-NEXT: fcsel d0, d2, d3, eq | |
| ; DISABLED-NEXT: ret | |
| ; | |
| ; DEFAULT-LABEL: test_basic_fcmp_fcsel_double: | |
| ; DEFAULT: ; %bb.0: ; %entry | |
| ; DEFAULT-NEXT: fcmp d0, d1 | |
| ; DEFAULT-NEXT: fcsel d0, d2, d3, eq | |
| ; DEFAULT-NEXT: ret | |
| ; | |
| ; WINDOWS-LABEL: test_basic_fcmp_fcsel_double: | |
| ; WINDOWS: // %bb.0: // %entry | |
| ; WINDOWS-NEXT: fcmp d0, d1 | |
| ; WINDOWS-NEXT: fcsel d0, d2, d3, eq | |
| ; WINDOWS-NEXT: ret | |
| entry: | |
| %cmp = fcmp oeq double %a, %b | |
| %sel = select i1 %cmp, double %c, double %d | |
| ret double %sel | |
| } | |
| ; * Multiple FCMP-FCSEL instruction pairs in same function | |
| define float @test_multiple_patterns(float %a, float %b, float %c, float %d, float %e, float %f) { | |
| ; ENABLED-LABEL: test_multiple_patterns: | |
| ; ENABLED: .p2align 6, , 4 | |
| ; ENABLED-NEXT: ; %bb.0: ; %entry | |
| ; ENABLED-NEXT: fcmp s0, s1 | |
| ; ENABLED-NEXT: fcsel s0, s2, s3, eq | |
| ; ENABLED-NEXT: .p2align 6, , 4 | |
| ; ENABLED-NEXT: ; %bb.1: ; %entry | |
| ; ENABLED-NEXT: fcmp s0, s4 | |
| ; ENABLED-NEXT: fcsel s0, s0, s5, gt | |
| ; ENABLED-NEXT: ret | |
| ; | |
| ; DISABLED-LABEL: test_multiple_patterns: | |
| ; DISABLED: ; %bb.0: ; %entry | |
| ; DISABLED-NEXT: fcmp s0, s1 | |
| ; DISABLED-NEXT: fcsel s0, s2, s3, eq | |
| ; DISABLED-NEXT: fcmp s0, s4 | |
| ; DISABLED-NEXT: fcsel s0, s0, s5, gt | |
| ; DISABLED-NEXT: ret | |
| ; | |
| ; DEFAULT-LABEL: test_multiple_patterns: | |
| ; DEFAULT: ; %bb.0: ; %entry | |
| ; DEFAULT-NEXT: fcmp s0, s1 | |
| ; DEFAULT-NEXT: fcsel s0, s2, s3, eq | |
| ; DEFAULT-NEXT: fcmp s0, s4 | |
| ; DEFAULT-NEXT: fcsel s0, s0, s5, gt | |
| ; DEFAULT-NEXT: ret | |
| ; | |
| ; WINDOWS-LABEL: test_multiple_patterns: | |
| ; WINDOWS: // %bb.0: // %entry | |
| ; WINDOWS-NEXT: fcmp s0, s1 | |
| ; WINDOWS-NEXT: fcsel s0, s2, s3, eq | |
| ; WINDOWS-NEXT: fcmp s0, s4 | |
| ; WINDOWS-NEXT: fcsel s0, s0, s5, gt | |
| ; WINDOWS-NEXT: ret | |
| entry: | |
| %cmp1 = fcmp oeq float %a, %b | |
| %sel1 = select i1 %cmp1, float %c, float %d | |
| %cmp2 = fcmp ogt float %sel1, %e | |
| %sel2 = select i1 %cmp2, float %sel1, float %f | |
| ret float %sel2 | |
| } | |
| ; * FCMP with comparison to zero (immediate) - excluded from optimization | |
| ; FCMP #0.0 uses the ri-form opcode which is not in the detection list | |
| define float @test_fcmp_immediate(float %a, float %b) { | |
| ; CHECK-LABEL: test_fcmp_immediate: | |
| ; CHECK: ; %bb.0: ; %entry | |
| ; CHECK-NEXT: fcmp s0, #0.0 | |
| ; CHECK-NEXT: fcsel s0, s0, s1, eq | |
| ; CHECK-NEXT: ret | |
| ; | |
| ; WINDOWS-LABEL: test_fcmp_immediate: | |
| ; WINDOWS: // %bb.0: // %entry | |
| ; WINDOWS-NEXT: fcmp s0, #0.0 | |
| ; WINDOWS-NEXT: fcsel s0, s0, s1, eq | |
| ; WINDOWS-NEXT: ret | |
| entry: | |
| %cmp = fcmp oeq float %a, 0.0 | |
| %sel = select i1 %cmp, float %a, float %b | |
| ret float %sel | |
| } | |
| ; * Mixed single and double precision in same function | |
| define float @test_mixed_precision(float %a, float %b, double %c, double %d) { | |
| ; ENABLED-LABEL: test_mixed_precision: | |
| ; ENABLED: .p2align 6, , 4 | |
| ; ENABLED-NEXT: ; %bb.0: ; %entry | |
| ; ENABLED-NEXT: fcmp s0, s1 | |
| ; ENABLED-NEXT: fcsel s0, s0, s1, gt | |
| ; ENABLED-NEXT: .p2align 6, , 4 | |
| ; ENABLED-NEXT: ; %bb.1: ; %entry | |
| ; ENABLED-NEXT: fcmp d2, d3 | |
| ; ENABLED-NEXT: fcsel d1, d2, d3, mi | |
| ; ENABLED-NEXT: fcvt s1, d1 | |
| ; ENABLED-NEXT: fadd s0, s0, s1 | |
| ; ENABLED-NEXT: ret | |
| ; | |
| ; DISABLED-LABEL: test_mixed_precision: | |
| ; DISABLED: ; %bb.0: ; %entry | |
| ; DISABLED-NEXT: fcmp s0, s1 | |
| ; DISABLED-NEXT: fcsel s0, s0, s1, gt | |
| ; DISABLED-NEXT: fcmp d2, d3 | |
| ; DISABLED-NEXT: fcsel d1, d2, d3, mi | |
| ; DISABLED-NEXT: fcvt s1, d1 | |
| ; DISABLED-NEXT: fadd s0, s0, s1 | |
| ; DISABLED-NEXT: ret | |
| ; | |
| ; DEFAULT-LABEL: test_mixed_precision: | |
| ; DEFAULT: ; %bb.0: ; %entry | |
| ; DEFAULT-NEXT: fcmp s0, s1 | |
| ; DEFAULT-NEXT: fcsel s0, s0, s1, gt | |
| ; DEFAULT-NEXT: fcmp d2, d3 | |
| ; DEFAULT-NEXT: fcsel d1, d2, d3, mi | |
| ; DEFAULT-NEXT: fcvt s1, d1 | |
| ; DEFAULT-NEXT: fadd s0, s0, s1 | |
| ; DEFAULT-NEXT: ret | |
| ; | |
| ; WINDOWS-LABEL: test_mixed_precision: | |
| ; WINDOWS: // %bb.0: // %entry | |
| ; WINDOWS-NEXT: fcmp s0, s1 | |
| ; WINDOWS-NEXT: fcsel s0, s0, s1, gt | |
| ; WINDOWS-NEXT: fcmp d2, d3 | |
| ; WINDOWS-NEXT: fcsel d1, d2, d3, mi | |
| ; WINDOWS-NEXT: fcvt s1, d1 | |
| ; WINDOWS-NEXT: fadd s0, s0, s1 | |
| ; WINDOWS-NEXT: ret | |
| entry: | |
| %cmp_single = fcmp ogt float %a, %b | |
| %sel_single = select i1 %cmp_single, float %a, float %b | |
| %cmp_double = fcmp olt double %c, %d | |
| %sel_double = select i1 %cmp_double, double %c, double %d | |
| %trunc = fptrunc double %sel_double to float | |
| %final = fadd float %sel_single, %trunc | |
| ret float %final | |
| } | |
| ; * FCMP-FCSEL instruction pair with a function call present | |
| declare float @external_func(float) | |
| define float @test_with_function_calls(float %a, float %b, float %c, float %d) { | |
| ; ENABLED-LABEL: test_with_function_calls: | |
| ; ENABLED: ; %bb.0: ; %entry | |
| ; ENABLED-NEXT: stp x29, x30, [sp, #-16]! ; 16-byte Folded Spill | |
| ; ENABLED-NEXT: .cfi_def_cfa_offset 16 | |
| ; ENABLED-NEXT: .cfi_offset w30, -8 | |
| ; ENABLED-NEXT: .cfi_offset w29, -16 | |
| ; ENABLED-NEXT: .p2align 6, , 4 | |
| ; ENABLED-NEXT: ; %bb.1: ; %entry | |
| ; ENABLED-NEXT: fcmp s0, s1 | |
| ; ENABLED-NEXT: fcsel s0, s2, s3, gt | |
| ; ENABLED-NEXT: bl _external_func | |
| ; ENABLED-NEXT: ldp x29, x30, [sp], #16 ; 16-byte Folded Reload | |
| ; ENABLED-NEXT: ret | |
| ; | |
| ; DISABLED-LABEL: test_with_function_calls: | |
| ; DISABLED: ; %bb.0: ; %entry | |
| ; DISABLED-NEXT: stp x29, x30, [sp, #-16]! ; 16-byte Folded Spill | |
| ; DISABLED-NEXT: .cfi_def_cfa_offset 16 | |
| ; DISABLED-NEXT: .cfi_offset w30, -8 | |
| ; DISABLED-NEXT: .cfi_offset w29, -16 | |
| ; DISABLED-NEXT: fcmp s0, s1 | |
| ; DISABLED-NEXT: fcsel s0, s2, s3, gt | |
| ; DISABLED-NEXT: bl _external_func | |
| ; DISABLED-NEXT: ldp x29, x30, [sp], #16 ; 16-byte Folded Reload | |
| ; DISABLED-NEXT: ret | |
| ; | |
| ; DEFAULT-LABEL: test_with_function_calls: | |
| ; DEFAULT: ; %bb.0: ; %entry | |
| ; DEFAULT-NEXT: stp x29, x30, [sp, #-16]! ; 16-byte Folded Spill | |
| ; DEFAULT-NEXT: .cfi_def_cfa_offset 16 | |
| ; DEFAULT-NEXT: .cfi_offset w30, -8 | |
| ; DEFAULT-NEXT: .cfi_offset w29, -16 | |
| ; DEFAULT-NEXT: fcmp s0, s1 | |
| ; DEFAULT-NEXT: fcsel s0, s2, s3, gt | |
| ; DEFAULT-NEXT: bl _external_func | |
| ; DEFAULT-NEXT: ldp x29, x30, [sp], #16 ; 16-byte Folded Reload | |
| ; DEFAULT-NEXT: ret | |
| ; | |
| ; WINDOWS-LABEL: test_with_function_calls: | |
| ; WINDOWS: .seh_proc test_with_function_calls | |
| ; WINDOWS-NEXT: // %bb.0: // %entry | |
| ; WINDOWS-NEXT: str x30, [sp, #-16]! // 8-byte Folded Spill | |
| ; WINDOWS-NEXT: .seh_save_reg_x x30, 16 | |
| ; WINDOWS-NEXT: .seh_endprologue | |
| ; WINDOWS-NEXT: fcmp s0, s1 | |
| ; WINDOWS-NEXT: fcsel s0, s2, s3, gt | |
| ; WINDOWS-NEXT: bl external_func | |
| ; WINDOWS-NEXT: .seh_startepilogue | |
| ; WINDOWS-NEXT: ldr x30, [sp], #16 // 8-byte Folded Reload | |
| ; WINDOWS-NEXT: .seh_save_reg_x x30, 16 | |
| ; WINDOWS-NEXT: .seh_endepilogue | |
| ; WINDOWS-NEXT: ret | |
| ; WINDOWS-NEXT: .seh_endfunclet | |
| ; WINDOWS-NEXT: .seh_endproc | |
| entry: | |
| %cmp = fcmp ogt float %a, %b | |
| %sel = select i1 %cmp, float %c, float %d | |
| %result = call float @external_func(float %sel) | |
| ret float %result | |
| } | |
| ; * Verify no false positives - FCMP without FCSEL | |
| define i32 @test_fcmp_without_fcsel(float %a, float %b) { | |
| ; CHECK-LABEL: test_fcmp_without_fcsel: | |
| ; CHECK: ; %bb.0: ; %entry | |
| ; CHECK-NEXT: fcmp s0, s1 | |
| ; CHECK-NEXT: cset w0, gt | |
| ; CHECK-NEXT: ret | |
| ; | |
| ; WINDOWS-LABEL: test_fcmp_without_fcsel: | |
| ; WINDOWS: // %bb.0: // %entry | |
| ; WINDOWS-NEXT: fcmp s0, s1 | |
| ; WINDOWS-NEXT: cset w0, gt | |
| ; WINDOWS-NEXT: ret | |
| entry: | |
| %cmp = fcmp ogt float %a, %b | |
| %result = zext i1 %cmp to i32 | |
| ret i32 %result | |
| } | |
| ; * Verify no false positives - FCSEL without preceding FCMP | |
| ; CHECK: .globl _test_fcsel_without_fcmp | |
| ; CHECK-NEXT: .p2align 2 | |
| define float @test_fcsel_without_fcmp(i1 %cond, float %a, float %b) { | |
| ; CHECK-LABEL: test_fcsel_without_fcmp: | |
| ; CHECK: ; %bb.0: ; %entry | |
| ; CHECK-NEXT: tst w0, #0x1 | |
| ; CHECK-NEXT: fcsel s0, s0, s1, ne | |
| ; CHECK-NEXT: ret | |
| ; | |
| ; WINDOWS-LABEL: test_fcsel_without_fcmp: | |
| ; WINDOWS: // %bb.0: // %entry | |
| ; WINDOWS-NEXT: tst w0, #0x1 | |
| ; WINDOWS-NEXT: fcsel s0, s0, s1, ne | |
| ; WINDOWS-NEXT: ret | |
| entry: | |
| %result = select i1 %cond, float %a, float %b | |
| ret float %result | |
| } | |
| ;------------------------------------------------------------------------------ | |
| ; CMP/CMN-CSEL tests (cmp-csel flag of -aarch64-code-layout-opt-enable) | |
| ;------------------------------------------------------------------------------ | |
| ; * Basic CMP-CSEL instruction pair (integer register comparison) | |
| define i32 @test_basic_cmp_csel(i32 %a, i32 %b, i32 %c, i32 %d) { | |
| ; ENABLED-LABEL: test_basic_cmp_csel: | |
| ; ENABLED: .p2align 6, , 4 | |
| ; ENABLED-NEXT: ; %bb.0: ; %entry | |
| ; ENABLED-NEXT: cmp w0, w1 | |
| ; ENABLED-NEXT: csel w0, w2, w3, eq | |
| ; ENABLED-NEXT: ret | |
| ; | |
| ; DISABLED-LABEL: test_basic_cmp_csel: | |
| ; DISABLED: ; %bb.0: ; %entry | |
| ; DISABLED-NEXT: cmp w0, w1 | |
| ; DISABLED-NEXT: csel w0, w2, w3, eq | |
| ; DISABLED-NEXT: ret | |
| ; | |
| ; DEFAULT-LABEL: test_basic_cmp_csel: | |
| ; DEFAULT: ; %bb.0: ; %entry | |
| ; DEFAULT-NEXT: cmp w0, w1 | |
| ; DEFAULT-NEXT: csel w0, w2, w3, eq | |
| ; DEFAULT-NEXT: ret | |
| ; | |
| ; WINDOWS-LABEL: test_basic_cmp_csel: | |
| ; WINDOWS: // %bb.0: // %entry | |
| ; WINDOWS-NEXT: cmp w0, w1 | |
| ; WINDOWS-NEXT: csel w0, w2, w3, eq | |
| ; WINDOWS-NEXT: ret | |
| entry: | |
| %cmp = icmp eq i32 %a, %b | |
| %sel = select i1 %cmp, i32 %c, i32 %d | |
| ret i32 %sel | |
| } | |
| ; * CMP-CSEL instruction pair with small immediate (<=15, qualifies for optimization) | |
| define i32 @test_cmp_small_imm_csel(i32 %a, i32 %b, i32 %c) { | |
| ; ENABLED-LABEL: test_cmp_small_imm_csel: | |
| ; ENABLED: .p2align 6, , 4 | |
| ; ENABLED-NEXT: ; %bb.0: ; %entry | |
| ; ENABLED-NEXT: cmp w0, #7 | |
| ; ENABLED-NEXT: csel w0, w1, w2, eq | |
| ; ENABLED-NEXT: ret | |
| ; | |
| ; DISABLED-LABEL: test_cmp_small_imm_csel: | |
| ; DISABLED: ; %bb.0: ; %entry | |
| ; DISABLED-NEXT: cmp w0, #7 | |
| ; DISABLED-NEXT: csel w0, w1, w2, eq | |
| ; DISABLED-NEXT: ret | |
| ; | |
| ; DEFAULT-LABEL: test_cmp_small_imm_csel: | |
| ; DEFAULT: ; %bb.0: ; %entry | |
| ; DEFAULT-NEXT: cmp w0, #7 | |
| ; DEFAULT-NEXT: csel w0, w1, w2, eq | |
| ; DEFAULT-NEXT: ret | |
| ; | |
| ; WINDOWS-LABEL: test_cmp_small_imm_csel: | |
| ; WINDOWS: // %bb.0: // %entry | |
| ; WINDOWS-NEXT: cmp w0, #7 | |
| ; WINDOWS-NEXT: csel w0, w1, w2, eq | |
| ; WINDOWS-NEXT: ret | |
| entry: | |
| %cmp = icmp eq i32 %a, 7 | |
| %sel = select i1 %cmp, i32 %b, i32 %c | |
| ret i32 %sel | |
| } | |
| ; * CMP-CSEL with immediate > 15 - excluded from optimization | |
| define i32 @test_cmp_large_imm_csel(i32 %a, i32 %b, i32 %c) { | |
| ; CHECK-LABEL: test_cmp_large_imm_csel: | |
| ; CHECK: ; %bb.0: ; %entry | |
| ; CHECK-NEXT: cmp w0, #100 | |
| ; CHECK-NEXT: csel w0, w1, w2, eq | |
| ; CHECK-NEXT: ret | |
| ; | |
| ; WINDOWS-LABEL: test_cmp_large_imm_csel: | |
| ; WINDOWS: // %bb.0: // %entry | |
| ; WINDOWS-NEXT: cmp w0, #100 | |
| ; WINDOWS-NEXT: csel w0, w1, w2, eq | |
| ; WINDOWS-NEXT: ret | |
| entry: | |
| %cmp = icmp eq i32 %a, 100 | |
| %sel = select i1 %cmp, i32 %b, i32 %c | |
| ret i32 %sel | |
| } | |
| ; * Basic CMN-CSEL instruction pair (ADDSWrr with WZR destination) | |
| define i32 @test_basic_cmn_csel(i32 %a, i32 %b, i32 %c, i32 %d) { | |
| ; ENABLED-LABEL: test_basic_cmn_csel: | |
| ; ENABLED: .p2align 6, , 4 | |
| ; ENABLED-NEXT: ; %bb.0: ; %entry | |
| ; ENABLED-NEXT: cmn w0, w1 | |
| ; ENABLED-NEXT: csel w0, w2, w3, eq | |
| ; ENABLED-NEXT: ret | |
| ; | |
| ; DISABLED-LABEL: test_basic_cmn_csel: | |
| ; DISABLED: ; %bb.0: ; %entry | |
| ; DISABLED-NEXT: cmn w0, w1 | |
| ; DISABLED-NEXT: csel w0, w2, w3, eq | |
| ; DISABLED-NEXT: ret | |
| ; | |
| ; DEFAULT-LABEL: test_basic_cmn_csel: | |
| ; DEFAULT: ; %bb.0: ; %entry | |
| ; DEFAULT-NEXT: cmn w0, w1 | |
| ; DEFAULT-NEXT: csel w0, w2, w3, eq | |
| ; DEFAULT-NEXT: ret | |
| ; | |
| ; WINDOWS-LABEL: test_basic_cmn_csel: | |
| ; WINDOWS: // %bb.0: // %entry | |
| ; WINDOWS-NEXT: cmn w0, w1 | |
| ; WINDOWS-NEXT: csel w0, w2, w3, eq | |
| ; WINDOWS-NEXT: ret | |
| entry: | |
| %sum = add i32 %a, %b | |
| %cmp = icmp eq i32 %sum, 0 | |
| %sel = select i1 %cmp, i32 %c, i32 %d | |
| ret i32 %sel | |
| } | |
| define i32 @test_subtarget_m4(i32 %a, i32 %b, i32 %c) "target-cpu"="apple-m4" { | |
| ; ENABLED-LABEL: test_subtarget_m4: | |
| ; ENABLED: .p2align 6, , 4 | |
| ; ENABLED-NEXT: ; %bb.0: ; %entry | |
| ; ENABLED-NEXT: cmn w0, #7 | |
| ; ENABLED-NEXT: csel w0, w1, w2, eq | |
| ; ENABLED-NEXT: ret | |
| ; | |
| ; DISABLED-LABEL: test_subtarget_m4: | |
| ; DISABLED: ; %bb.0: ; %entry | |
| ; DISABLED-NEXT: cmn w0, #7 | |
| ; DISABLED-NEXT: csel w0, w1, w2, eq | |
| ; DISABLED-NEXT: ret | |
| ; | |
| ; DEFAULT-LABEL: test_subtarget_m4: | |
| ; DEFAULT: .p2align 6, , 4 | |
| ; DEFAULT-NEXT: ; %bb.0: ; %entry | |
| ; DEFAULT-NEXT: cmn w0, #7 | |
| ; DEFAULT-NEXT: csel w0, w1, w2, eq | |
| ; DEFAULT-NEXT: ret | |
| ; | |
| ; WINDOWS-LABEL: test_subtarget_m4: | |
| ; WINDOWS: // %bb.0: // %entry | |
| ; WINDOWS-NEXT: cmn w0, #7 | |
| ; WINDOWS-NEXT: csel w0, w1, w2, eq | |
| ; WINDOWS-NEXT: ret | |
| entry: | |
| %cmp = icmp eq i32 %a, -7 | |
| %sel = select i1 %cmp, i32 %b, i32 %c | |
| ret i32 %sel | |
| } | |
| ; * CMN-CSEL instruction pair with small immediate (ADDSWri imm=7, qualifies) | |
| define i32 @test_cmn_small_imm_csel(i32 %a, i32 %b, i32 %c) { | |
| ; ENABLED-LABEL: test_cmn_small_imm_csel: | |
| ; ENABLED: .p2align 6, , 4 | |
| ; ENABLED-NEXT: ; %bb.0: ; %entry | |
| ; ENABLED-NEXT: cmn w0, #7 | |
| ; ENABLED-NEXT: csel w0, w1, w2, eq | |
| ; ENABLED-NEXT: ret | |
| ; | |
| ; DISABLED-LABEL: test_cmn_small_imm_csel: | |
| ; DISABLED: ; %bb.0: ; %entry | |
| ; DISABLED-NEXT: cmn w0, #7 | |
| ; DISABLED-NEXT: csel w0, w1, w2, eq | |
| ; DISABLED-NEXT: ret | |
| ; | |
| ; DEFAULT-LABEL: test_cmn_small_imm_csel: | |
| ; DEFAULT: ; %bb.0: ; %entry | |
| ; DEFAULT-NEXT: cmn w0, #7 | |
| ; DEFAULT-NEXT: csel w0, w1, w2, eq | |
| ; DEFAULT-NEXT: ret | |
| ; | |
| ; WINDOWS-LABEL: test_cmn_small_imm_csel: | |
| ; WINDOWS: // %bb.0: // %entry | |
| ; WINDOWS-NEXT: cmn w0, #7 | |
| ; WINDOWS-NEXT: csel w0, w1, w2, eq | |
| ; WINDOWS-NEXT: ret | |
| entry: | |
| %cmp = icmp eq i32 %a, -7 | |
| %sel = select i1 %cmp, i32 %b, i32 %c | |
| ret i32 %sel | |
| } | |
| ; * CMP without CSEL - no false positive | |
| define i32 @test_cmp_without_csel(i32 %a, i32 %b) { | |
| ; CHECK-LABEL: test_cmp_without_csel: | |
| ; CHECK: ; %bb.0: ; %entry | |
| ; CHECK-NEXT: cmp w0, w1 | |
| ; CHECK-NEXT: cset w0, eq | |
| ; CHECK-NEXT: ret | |
| ; | |
| ; WINDOWS-LABEL: test_cmp_without_csel: | |
| ; WINDOWS: // %bb.0: // %entry | |
| ; WINDOWS-NEXT: cmp w0, w1 | |
| ; WINDOWS-NEXT: cset w0, eq | |
| ; WINDOWS-NEXT: ret | |
| entry: | |
| %cmp = icmp eq i32 %a, %b | |
| %result = zext i1 %cmp to i32 | |
| ret i32 %result | |
| } |