| ; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py |
| ; RUN: llc < %s -mtriple=x86_64-unknown-unknown -mattr=+adx,+ndd | FileCheck %s --check-prefixes=CHECK,NDD |
| ; RUN: llc < %s -mtriple=x86_64-unknown-unknown -mattr=+adx | FileCheck %s --check-prefixes=CHECK,ADX |
| ; RUN: llc < %s -mtriple=x86_64-unknown-unknown -mattr=-adx | FileCheck %s --check-prefixes=CHECK,NOADX |
| |
| define i32 @adox_test_i32(i32 %a, i32 %b, i8 %c, i8 %d) { |
| ; NDD-LABEL: adox_test_i32: |
| ; NDD: # %bb.0: |
| ; NDD-NEXT: cmpb %cl, %dl |
| ; NDD-NEXT: adoxl %esi, %edi, %eax |
| ; NDD-NEXT: retq |
| ; |
| ; ADX-LABEL: adox_test_i32: |
| ; ADX: # %bb.0: |
| ; ADX-NEXT: movl %edi, %eax |
| ; ADX-NEXT: cmpb %cl, %dl |
| ; ADX-NEXT: adoxl %esi, %eax |
| ; ADX-NEXT: retq |
| ; |
| ; NOADX-LABEL: adox_test_i32: |
| ; NOADX: # %bb.0: |
| ; NOADX-NEXT: # kill: def $esi killed $esi def $rsi |
| ; NOADX-NEXT: # kill: def $edi killed $edi def $rdi |
| ; NOADX-NEXT: xorl %eax, %eax |
| ; NOADX-NEXT: cmpb %cl, %dl |
| ; NOADX-NEXT: seto %al |
| ; NOADX-NEXT: addl %edi, %eax |
| ; NOADX-NEXT: addl %esi, %eax |
| ; NOADX-NEXT: retq |
| %ssub = call { i8, i1 } @llvm.ssub.with.overflow.i8(i8 %c, i8 %d) |
| %ov = extractvalue { i8, i1 } %ssub, 1 |
| %ov.ext = zext i1 %ov to i32 |
| %sum = add i32 %a, %b |
| %res = add i32 %sum, %ov.ext |
| ret i32 %res |
| } |
| |
| define i64 @adox_test_i64(i64 %a, i64 %b, i8 %c, i8 %d) { |
| ; NDD-LABEL: adox_test_i64: |
| ; NDD: # %bb.0: |
| ; NDD-NEXT: cmpb %cl, %dl |
| ; NDD-NEXT: adoxq %rsi, %rdi, %rax |
| ; NDD-NEXT: retq |
| ; |
| ; ADX-LABEL: adox_test_i64: |
| ; ADX: # %bb.0: |
| ; ADX-NEXT: movq %rdi, %rax |
| ; ADX-NEXT: cmpb %cl, %dl |
| ; ADX-NEXT: adoxq %rsi, %rax |
| ; ADX-NEXT: retq |
| ; |
| ; NOADX-LABEL: adox_test_i64: |
| ; NOADX: # %bb.0: |
| ; NOADX-NEXT: xorl %eax, %eax |
| ; NOADX-NEXT: cmpb %cl, %dl |
| ; NOADX-NEXT: seto %al |
| ; NOADX-NEXT: addq %rdi, %rax |
| ; NOADX-NEXT: addq %rsi, %rax |
| ; NOADX-NEXT: retq |
| %ssub = call { i8, i1 } @llvm.ssub.with.overflow.i8(i8 %c, i8 %d) |
| %ov = extractvalue { i8, i1 } %ssub, 1 |
| %ov.ext = zext i1 %ov to i64 |
| %sum = add i64 %a, %b |
| %res = add i64 %sum, %ov.ext |
| ret i64 %res |
| } |
| |
| declare { i8, i1 } @llvm.ssub.with.overflow.i8(i8, i8) |
| |
| define i32 @adox_test_i32_mem(i32 %a, ptr %b_ptr, i8 %c, i8 %d) { |
| ; NDD-LABEL: adox_test_i32_mem: |
| ; NDD: # %bb.0: |
| ; NDD-NEXT: cmpb %cl, %dl |
| ; NDD-NEXT: adoxl (%rsi), %edi, %eax |
| ; NDD-NEXT: retq |
| ; |
| ; ADX-LABEL: adox_test_i32_mem: |
| ; ADX: # %bb.0: |
| ; ADX-NEXT: movl %edi, %eax |
| ; ADX-NEXT: cmpb %cl, %dl |
| ; ADX-NEXT: adoxl (%rsi), %eax |
| ; ADX-NEXT: retq |
| ; |
| ; NOADX-LABEL: adox_test_i32_mem: |
| ; NOADX: # %bb.0: |
| ; NOADX-NEXT: xorl %eax, %eax |
| ; NOADX-NEXT: cmpb %cl, %dl |
| ; NOADX-NEXT: seto %al |
| ; NOADX-NEXT: addl (%rsi), %edi |
| ; NOADX-NEXT: addl %edi, %eax |
| ; NOADX-NEXT: retq |
| %b = load i32, ptr %b_ptr |
| %ssub = call { i8, i1 } @llvm.ssub.with.overflow.i8(i8 %c, i8 %d) |
| %ov = extractvalue { i8, i1 } %ssub, 1 |
| %ov.ext = zext i1 %ov to i32 |
| %add = add i32 %a, %b |
| %add2 = add i32 %add, %ov.ext |
| ret i32 %add2 |
| } |
| |
| define i64 @adox_test_i64_mem(i64 %a, ptr %b_ptr, i8 %c, i8 %d) { |
| ; NDD-LABEL: adox_test_i64_mem: |
| ; NDD: # %bb.0: |
| ; NDD-NEXT: cmpb %cl, %dl |
| ; NDD-NEXT: adoxq (%rsi), %rdi, %rax |
| ; NDD-NEXT: retq |
| ; |
| ; ADX-LABEL: adox_test_i64_mem: |
| ; ADX: # %bb.0: |
| ; ADX-NEXT: movq %rdi, %rax |
| ; ADX-NEXT: cmpb %cl, %dl |
| ; ADX-NEXT: adoxq (%rsi), %rax |
| ; ADX-NEXT: retq |
| ; |
| ; NOADX-LABEL: adox_test_i64_mem: |
| ; NOADX: # %bb.0: |
| ; NOADX-NEXT: xorl %eax, %eax |
| ; NOADX-NEXT: cmpb %cl, %dl |
| ; NOADX-NEXT: seto %al |
| ; NOADX-NEXT: addq (%rsi), %rdi |
| ; NOADX-NEXT: addq %rdi, %rax |
| ; NOADX-NEXT: retq |
| %b = load i64, ptr %b_ptr |
| %ssub = call { i8, i1 } @llvm.ssub.with.overflow.i8(i8 %c, i8 %d) |
| %ov = extractvalue { i8, i1 } %ssub, 1 |
| %ov.ext = zext i1 %ov to i64 |
| %add = add i64 %a, %b |
| %add2 = add i64 %add, %ov.ext |
| ret i64 %add2 |
| } |
| |
| define i32 @adox_test_sadd_i32(i32 %a, i32 %b, i8 %c, i8 %d) { |
| ; NDD-LABEL: adox_test_sadd_i32: |
| ; NDD: # %bb.0: |
| ; NDD-NEXT: addb %cl, %dl, %al |
| ; NDD-NEXT: adoxl %esi, %edi, %eax |
| ; NDD-NEXT: retq |
| ; |
| ; ADX-LABEL: adox_test_sadd_i32: |
| ; ADX: # %bb.0: |
| ; ADX-NEXT: movl %edi, %eax |
| ; ADX-NEXT: addb %cl, %dl |
| ; ADX-NEXT: adoxl %esi, %eax |
| ; ADX-NEXT: retq |
| ; |
| ; NOADX-LABEL: adox_test_sadd_i32: |
| ; NOADX: # %bb.0: |
| ; NOADX-NEXT: # kill: def $esi killed $esi def $rsi |
| ; NOADX-NEXT: # kill: def $edi killed $edi def $rdi |
| ; NOADX-NEXT: xorl %eax, %eax |
| ; NOADX-NEXT: addb %cl, %dl |
| ; NOADX-NEXT: seto %al |
| ; NOADX-NEXT: addl %edi, %eax |
| ; NOADX-NEXT: addl %esi, %eax |
| ; NOADX-NEXT: retq |
| %sadd = call { i8, i1 } @llvm.sadd.with.overflow.i8(i8 %c, i8 %d) |
| %ov = extractvalue { i8, i1 } %sadd, 1 |
| %ov.ext = zext i1 %ov to i32 |
| %add = add i32 %a, %b |
| %add2 = add i32 %add, %ov.ext |
| ret i32 %add2 |
| } |
| |
| declare { i8, i1 } @llvm.sadd.with.overflow.i8(i8, i8) |
| |
| define i16 @adox_test_i16(i16 %a, i16 %b, i8 %c, i8 %d) { |
| ; NDD-LABEL: adox_test_i16: |
| ; NDD: # %bb.0: |
| ; NDD-NEXT: cmpb %cl, %dl |
| ; NDD-NEXT: adoxl %esi, %edi, %eax |
| ; NDD-NEXT: # kill: def $ax killed $ax killed $eax |
| ; NDD-NEXT: retq |
| ; |
| ; ADX-LABEL: adox_test_i16: |
| ; ADX: # %bb.0: |
| ; ADX-NEXT: movl %edi, %eax |
| ; ADX-NEXT: cmpb %cl, %dl |
| ; ADX-NEXT: adoxl %esi, %eax |
| ; ADX-NEXT: # kill: def $ax killed $ax killed $eax |
| ; ADX-NEXT: retq |
| ; |
| ; NOADX-LABEL: adox_test_i16: |
| ; NOADX: # %bb.0: |
| ; NOADX-NEXT: # kill: def $esi killed $esi def $rsi |
| ; NOADX-NEXT: # kill: def $edi killed $edi def $rdi |
| ; NOADX-NEXT: xorl %eax, %eax |
| ; NOADX-NEXT: cmpb %cl, %dl |
| ; NOADX-NEXT: seto %al |
| ; NOADX-NEXT: addl %edi, %eax |
| ; NOADX-NEXT: addl %esi, %eax |
| ; NOADX-NEXT: # kill: def $ax killed $ax killed $eax |
| ; NOADX-NEXT: retq |
| %ssub = call { i8, i1 } @llvm.ssub.with.overflow.i8(i8 %c, i8 %d) |
| %ov = extractvalue { i8, i1 } %ssub, 1 |
| %ov.ext = zext i1 %ov to i16 |
| %sum = add i16 %a, %b |
| %res = add i16 %sum, %ov.ext |
| ret i16 %res |
| } |
| |
| define i8 @adox_test_i8(i8 %a, i8 %b, i8 %c, i8 %d) { |
| ; NDD-LABEL: adox_test_i8: |
| ; NDD: # %bb.0: |
| ; NDD-NEXT: cmpb %cl, %dl |
| ; NDD-NEXT: adoxl %esi, %edi, %eax |
| ; NDD-NEXT: # kill: def $al killed $al killed $eax |
| ; NDD-NEXT: retq |
| ; |
| ; ADX-LABEL: adox_test_i8: |
| ; ADX: # %bb.0: |
| ; ADX-NEXT: movl %edi, %eax |
| ; ADX-NEXT: cmpb %cl, %dl |
| ; ADX-NEXT: adoxl %esi, %eax |
| ; ADX-NEXT: # kill: def $al killed $al killed $eax |
| ; ADX-NEXT: retq |
| ; |
| ; NOADX-LABEL: adox_test_i8: |
| ; NOADX: # %bb.0: |
| ; NOADX-NEXT: # kill: def $esi killed $esi def $rsi |
| ; NOADX-NEXT: # kill: def $edi killed $edi def $rdi |
| ; NOADX-NEXT: cmpb %cl, %dl |
| ; NOADX-NEXT: seto %cl |
| ; NOADX-NEXT: leal (%rdi,%rsi), %eax |
| ; NOADX-NEXT: addb %cl, %al |
| ; NOADX-NEXT: # kill: def $al killed $al killed $eax |
| ; NOADX-NEXT: retq |
| %ssub = call { i8, i1 } @llvm.ssub.with.overflow.i8(i8 %c, i8 %d) |
| %ov = extractvalue { i8, i1 } %ssub, 1 |
| %ov.ext = zext i1 %ov to i8 |
| %sum = add i8 %a, %b |
| %res = add i8 %sum, %ov.ext |
| ret i8 %res |
| } |
| |
| define i32 @adox_test_sub_i32(i32 %a, i32 %b, i8 %c, i8 %d) { |
| ; NDD-LABEL: adox_test_sub_i32: |
| ; NDD: # %bb.0: |
| ; NDD-NEXT: xorl %eax, %eax |
| ; NDD-NEXT: cmpb %cl, %dl |
| ; NDD-NEXT: seto %al |
| ; NDD-NEXT: subl %esi, %edi |
| ; NDD-NEXT: subl %eax, %edi, %eax |
| ; NDD-NEXT: retq |
| ; |
| ; ADX-LABEL: adox_test_sub_i32: |
| ; ADX: # %bb.0: |
| ; ADX-NEXT: movl %edi, %eax |
| ; ADX-NEXT: xorl %edi, %edi |
| ; ADX-NEXT: cmpb %cl, %dl |
| ; ADX-NEXT: seto %dil |
| ; ADX-NEXT: subl %esi, %eax |
| ; ADX-NEXT: subl %edi, %eax |
| ; ADX-NEXT: retq |
| ; |
| ; NOADX-LABEL: adox_test_sub_i32: |
| ; NOADX: # %bb.0: |
| ; NOADX-NEXT: movl %edi, %eax |
| ; NOADX-NEXT: xorl %edi, %edi |
| ; NOADX-NEXT: cmpb %cl, %dl |
| ; NOADX-NEXT: seto %dil |
| ; NOADX-NEXT: subl %esi, %eax |
| ; NOADX-NEXT: subl %edi, %eax |
| ; NOADX-NEXT: retq |
| %ssub = call { i8, i1 } @llvm.ssub.with.overflow.i8(i8 %c, i8 %d) |
| %ov = extractvalue { i8, i1 } %ssub, 1 |
| %ov.ext = zext i1 %ov to i32 |
| %sum = sub i32 %a, %b |
| %res = sub i32 %sum, %ov.ext |
| ret i32 %res |
| } |
| |
| ; Negative test: ADOX modifies OF but does not modify ZF. |
| ; When the result of the addition is checked for equality with zero (using ZF), |
| ; we cannot optimize the addition into an ADOX instruction because the branch |
| ; would read an incorrect/stale ZF value. The compiler must fall back to a |
| ; standard ADD which sets ZF correctly. |
| define i32 @adox_test_zf(i32 %a, i32 %b, i32 %s) { |
| ; NDD-LABEL: adox_test_zf: |
| ; NDD: # %bb.0: |
| ; NDD-NEXT: xorl %eax, %eax |
| ; NDD-NEXT: addl %edi, %esi |
| ; NDD-NEXT: seto %al |
| ; NDD-NEXT: addl %edx, %eax |
| ; NDD-NEXT: je .LBB8_1 |
| ; NDD-NEXT: # %bb.2: # %nonzero |
| ; NDD-NEXT: movl $222, %eax |
| ; NDD-NEXT: retq |
| ; NDD-NEXT: .LBB8_1: # %iszero |
| ; NDD-NEXT: movl $111, %eax |
| ; NDD-NEXT: retq |
| ; |
| ; ADX-LABEL: adox_test_zf: |
| ; ADX: # %bb.0: |
| ; ADX-NEXT: xorl %eax, %eax |
| ; ADX-NEXT: addl %esi, %edi |
| ; ADX-NEXT: seto %al |
| ; ADX-NEXT: addl %edx, %eax |
| ; ADX-NEXT: je .LBB8_1 |
| ; ADX-NEXT: # %bb.2: # %nonzero |
| ; ADX-NEXT: movl $222, %eax |
| ; ADX-NEXT: retq |
| ; ADX-NEXT: .LBB8_1: # %iszero |
| ; ADX-NEXT: movl $111, %eax |
| ; ADX-NEXT: retq |
| ; |
| ; NOADX-LABEL: adox_test_zf: |
| ; NOADX: # %bb.0: |
| ; NOADX-NEXT: xorl %eax, %eax |
| ; NOADX-NEXT: addl %esi, %edi |
| ; NOADX-NEXT: seto %al |
| ; NOADX-NEXT: addl %edx, %eax |
| ; NOADX-NEXT: je .LBB8_1 |
| ; NOADX-NEXT: # %bb.2: # %nonzero |
| ; NOADX-NEXT: movl $222, %eax |
| ; NOADX-NEXT: retq |
| ; NOADX-NEXT: .LBB8_1: # %iszero |
| ; NOADX-NEXT: movl $111, %eax |
| ; NOADX-NEXT: retq |
| %o = call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 %a, i32 %b) |
| %ov = extractvalue { i32, i1 } %o, 1 |
| %ov.ext = zext i1 %ov to i32 |
| %n = add i32 %s, %ov.ext |
| %z = icmp eq i32 %n, 0 |
| br i1 %z, label %iszero, label %nonzero |
| |
| iszero: |
| ret i32 111 |
| |
| nonzero: |
| ret i32 222 |
| } |
| |
| ;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line: |
| ; CHECK: {{.*}} |