Index: lib/Target/PowerPC/PPCInstrInfo.td =================================================================== --- lib/Target/PowerPC/PPCInstrInfo.td +++ lib/Target/PowerPC/PPCInstrInfo.td @@ -3158,6 +3158,28 @@ (EXTRACT_SUBREG (rfrag8 $s1), sub_32)>; } +multiclass ExtSetCCPat2 { + def : Pat<(i32 (zext (i1 (pfrag i32:$s1, i32:$s2, cc)))), + (rfrag $s1, $s2)>; + def : Pat<(i64 (zext (i1 (pfrag i64:$s1, i64:$s2, cc)))), + (rfrag8 $s1, $s2)>; + def : Pat<(i64 (zext (i1 (pfrag i32:$s1, i32:$s2, cc)))), + (INSERT_SUBREG (i64 (IMPLICIT_DEF)), (rfrag $s1, $s2), sub_32)>; + def : Pat<(i32 (zext (i1 (pfrag i64:$s1, i64:$s2, cc)))), + (EXTRACT_SUBREG (rfrag8 $s1, $s2), sub_32)>; + } + +// Instead of using rlwinm Rx,Ry,32-n,n,31, the more clever way rlwinm Rx,Ry, +// 32-n,31,31 are used to extract just one bit. Similar thing for rldicl. +defm : ExtSetCCPat2, + OutPatFrag<(ops node:$in1, node:$in2), + (RLWINM (CNTLZW (SUBF $in1, $in2)), 27, 31, 31)>, + OutPatFrag<(ops node:$in1, node:$in2), + (RLDICL (CNTLZD (SUBF8 $in1, $in2)), 58, 63)> >; + // Note that we do all inversions below with i(32|64)not, instead of using // (xori x, 1) because on the A2 nor has single-cycle latency while xori // has 2-cycle latency. @@ -3242,6 +3264,16 @@ OutPatFrag<(ops node:$in), (RLDICL $in, 1, 63)> >; +// This happens frequently because instruction selection will convert +// SETLE 0 to SETLT 1. +defm : ExtSetCCPat, + OutPatFrag<(ops node:$in), + (RLWINM (ORC $in, (NEG $in)), 1, 31, 31)>, + OutPatFrag<(ops node:$in), + (RLDICL (ORC8 $in, (NEG8 $in)), 1, 63)> >; + // An extended SETCC with shift amount. multiclass ExtSetCCShiftPat { Index: test/CodeGen/PowerPC/expand-isel.ll =================================================================== --- test/CodeGen/PowerPC/expand-isel.ll +++ test/CodeGen/PowerPC/expand-isel.ll @@ -212,11 +212,9 @@ ret i32 %retval.0 ; CHECK-LABEL: @testComplexISEL -; CHECK: bc 12, 2, [[TRUE:.LBB[0-9]+]] -; CHECK-NEXT: b [[SUCCESSOR:.LBB[0-9]+]] -; CHECK-NEXT: [[TRUE]] -; CHECK-NEXT: addi r3, r12, 0 -; CHECK-NEXT: [[SUCCESSOR]] +; CHECK: sub [[REG1:r[0-9]+]], r4, r3 +; CHECK-NEXT: cntlzd [[REG2:r[0-9]+]], [[REG1]] +; CHECK-NEXT: rldicl [[REG3:r[0-9]+]], [[REG2]], 58, 63 ; CHECK-NEXT: clrldi r3, r3, 32 ; CHECK-NEXT: blr } Index: test/CodeGen/PowerPC/expand-setcc.ll =================================================================== --- /dev/null +++ test/CodeGen/PowerPC/expand-setcc.ll @@ -0,0 +1,303 @@ +; RUN: llc -verify-machineinstrs -mtriple=powerpc64le-unknown-linux-gnu -O2 -ppc-asm-full-reg-names -mcpu=pwr8 < %s | FileCheck %s +; RUN: llc -verify-machineinstrs -mtriple=powerpc64-unknown-linux-gnu -O2 -ppc-asm-full-reg-names -mcpu=pwr8 < %s | FileCheck %s + +; Function Attrs: norecurse nounwind readnone +define zeroext i1 @setcc_eq_i8(i8 signext %v0, i8 signext %v1) { +entry: + %cmp = icmp eq i8 %v0, %v1 + ret i1 %cmp + +; CHECK-LABEL: @setcc_eq_i8 +; CHECK: subf [[REG1:r[0-9]+]], r3, r4 +; CHECK-NEXT: cntlzw [[REG2:r[0-9]+]], [[REG1]] +; CHECK-NEXT: rlwinm [[REG3:r[0-9]+]], [[REG2]], 27, 31, 31 +; CHECK-NEXT: blr +} + +; Function Attrs: norecurse nounwind readnone +define zeroext i1 @setcc_eq_i16(i16 signext %v0, i16 signext %v1) { +entry: + %cmp = icmp eq i16 %v0, %v1 + ret i1 %cmp + +; CHECK-LABEL: @setcc_eq_i16 +; CHECK: subf [[REG1:r[0-9]+]], r3, r4 +; CHECK-NEXT: cntlzw [[REG2:r[0-9]+]], [[REG1]] +; CHECK-NEXT: rlwinm [[REG3:r[0-9]+]], [[REG2]], 27, 31, 31 +; CHECK-NEXT: blr +} + +; Function Attrs: norecurse nounwind readnone +define zeroext i1 @setcc_eq_i32(i32 signext %v0, i32 signext %v1) { +entry: + %cmp = icmp eq i32 %v0, %v1 + ret i1 %cmp + +; CHECK-LABEL: @setcc_eq_i32 +; CHECK: subf [[REG1:r[0-9]+]], r3, r4 +; CHECK-NEXT: cntlzw [[REG2:r[0-9]+]], [[REG1]] +; CHECK-NEXT: rlwinm [[REG3:r[0-9]+]], [[REG2]], 27, 31, 31 +; CHECK-NEXT: blr +} + +; Function Attrs: norecurse nounwind readnone +define zeroext i1 @setcc_eq_i64(i64 signext %v0, i64 signext %v1) { +entry: + %cmp = icmp eq i64 %v0, %v1 + ret i1 %cmp + +; CHECK-LABEL: @setcc_eq_i64 +; CHECK: sub [[REG1:r[0-9]+]], r4, r3 +; CHECK-NEXT: cntlzd [[REG2:r[0-9]+]], [[REG1]] +; CHECK-NEXT: rldicl [[REG3:r[0-9]+]], [[REG2]], 58, 63 +; CHECK-NEXT: blr +} + +; Function Attrs: norecurse nounwind readnone +define zeroext i1 @setcc_eq0_i8(i8 signext %v0) { +entry: + %cmp = icmp eq i8 %v0, 0 + ret i1 %cmp + +; CHECK-LABEL: @setcc_eq0_i8 +; CHECK: cntlzw [[REG1:r[0-9]+]], r3 +; CHECK-NEXT: rlwinm [[REG2:r[0-9]+]], [[REG1]], 27, 31, 31 +; CHECK-NEXT: blr +} + +; Function Attrs: norecurse nounwind readnone +define zeroext i1 @setcc_eq0_i16(i16 signext %v0) { +entry: + %cmp = icmp eq i16 %v0, 0 + ret i1 %cmp + +; CHECK-LABEL: @setcc_eq0_i16 +; CHECK: cntlzw [[REG1:r[0-9]+]], r3 +; CHECK-NEXT: rlwinm [[REG2:r[0-9]+]], [[REG1]], 27, 31, 31 +; CHECK-NEXT: blr +} + +; Function Attrs: norecurse nounwind readnone +define zeroext i1 @setcc_eq0_i32(i32 signext %v0) { +entry: + %cmp = icmp eq i32 %v0, 0 + ret i1 %cmp + +; CHECK-LABEL: @setcc_eq0_i32 +; CHECK: cntlzw [[REG1:r[0-9]+]], r3 +; CHECK-NEXT: rlwinm [[REG2:r[0-9]+]], [[REG1]], 27, 31, 31 +; CHECK-NEXT: blr +} + +; Function Attrs: norecurse nounwind readnone +define zeroext i1 @setcc_eq0_i64(i64 signext %v0) { +entry: + %cmp = icmp eq i64 %v0, 0 + ret i1 %cmp + +; CHECK-LABEL: @setcc_eq0_i64 +; CHECK: cntlzd [[REG1:r[0-9]+]], r3 +; CHECK-NEXT: rldicl [[REG2:r[0-9]+]], [[REG1]], 58, 63 +; CHECK-NEXT: blr +} +; Function Attrs: norecurse nounwind readnone +define zeroext i1 @setcc_ges0_i8(i8 signext %v0) { +entry: + %cmp = icmp sge i8 %v0, 0 + ret i1 %cmp + +; CHECK-LABEL: @setcc_ges0_i8 +; CHECK: nor [[REG1:r[0-9]+]], r3 +; CHECK-NEXT: srwi [[REG2:r[0-9]+]], [[REG1]], 31 +; CHECK-NEXT: blr +} + +; Function Attrs: norecurse nounwind readnone +define zeroext i1 @setcc_ges0_i16(i16 signext %v0) { +entry: + %cmp = icmp sge i16 %v0, 0 + ret i1 %cmp + +; CHECK-LABEL: @setcc_ges0_i16 +; CHECK: nor [[REG1:r[0-9]+]], r3 +; CHECK-NEXT: srwi [[REG2:r[0-9]+]], [[REG1]], 31 +; CHECK-NEXT: blr +} + +; Function Attrs: norecurse nounwind readnone +define zeroext i1 @setcc_ges0_i32(i32 signext %v0) { +entry: + %cmp = icmp sge i32 %v0, 0 + ret i1 %cmp + +; CHECK-LABEL: @setcc_ges0_i32 + +; TO DO: note the CHECK-CWG here is for future work. +; CHECK-CWG: srwi [[REG1:r[0-9]+]], r3, 31 +; CHECK-CWG-NEXT: xori [[REG2:r[0-9]+]], [[REG1]], 1 +; CHECK-CWG-NEXT: blr + +; CHECK: nor [[REG1:r[0-9]+]], r3 +; CHECK-NEXT: srwi [[REG2:r[0-9]+]], [[REG1]], 31 +; CHECK-NEXT: blr +} + +; Function Attrs: norecurse nounwind readnone +define zeroext i1 @setcc_ges0_i64(i64 signext %v0) { +entry: + %cmp = icmp sge i64 %v0, 0 + ret i1 %cmp + +; CHECK-LABEL: @setcc_ges0_i64 +; CHECK: rldicl [[REG1:r[0-9]+]], r3, 1, 63 +; CHECK-NEXT: xori [[REG2:r[0-9]+]], [[REG1]], 1 +; CHECK-NEXT: blr +} + +; Function Attrs: norecurse nounwind readnone +define zeroext i1 @setcc_gts0_i8(i8 signext %v0) { +entry: + %cmp = icmp sgt i8 %v0, 0 + ret i1 %cmp + +; CHECK-LABEL: @setcc_gts0_i8 +; CHECK: neg [[REG1:r[0-9]+]], r3 +; CHECK-NEXT: andc [[REG2:r[0-9]+]], [[REG1]], r3 +; CHECK-NEXT: srwi [[REG3:r[0-9]+]], [[REG2]], 31 +; CHECK-NEXT: blr +} + +; Function Attrs: norecurse nounwind readnone +define zeroext i1 @setcc_gts0_i16(i16 signext %v0) { +entry: + %cmp = icmp sgt i16 %v0, 0 + ret i1 %cmp + +; CHECK-LABEL: @setcc_gts0_i16 +; CHECK: neg [[REG1:r[0-9]+]], r3 +; CHECK-NEXT: andc [[REG2:r[0-9]+]], [[REG1]], r3 +; CHECK-NEXT: srwi [[REG3:r[0-9]+]], [[REG2]], 31 +; CHECK-NEXT: blr +} + +; Function Attrs: norecurse nounwind readnone +define zeroext i1 @setcc_gts0_i32(i32 signext %v0) { +entry: + %cmp = icmp sgt i32 %v0, 0 + ret i1 %cmp + +; CHECK-LABEL: @setcc_gts0_i32 +; CHECK: neg [[REG1:r[0-9]+]], r3 +; CHECK-NEXT: andc [[REG2:r[0-9]+]], [[REG1]], r3 +; CHECK-NEXT: srwi [[REG3:r[0-9]+]], [[REG2]], 31 +; CHECK-NEXT: blr +} + +; Function Attrs: norecurse nounwind readnone +define zeroext i1 @setcc_gts0_i64(i64 signext %v0) { +entry: + %cmp = icmp sgt i64 %v0, 0 + ret i1 %cmp + +; CHECK-LABEL: @setcc_gts0_i64 +; CHECK: neg [[REG1:r[0-9]+]], r3 +; CHECK-NEXT: andc [[REG2:r[0-9]+]], [[REG1]], r3 +; CHECK-NEXT: rldicl [[REG3:r[0-9]+]], [[REG2]], 1, 63 +; CHECK-NEXT: blr +} + +; Function Attrs: norecurse nounwind readnone +define zeroext i1 @setcc_les0_i8(i8 signext %v0) { +entry: + %cmp = icmp sle i8 %v0, 0 + ret i1 %cmp + +; CHECK-LABEL: @setcc_les0_i8 +; CHECK: neg [[REG1:r[0-9]+]], r3 +; CHECK-NEXT: orc [[REG2:r[0-9]+]], r3, [[REG1]] +; CHECK-NEXT: srwi [[REG3:r[0-9]+]], [[REG2]], 31 +; CHECK-NEXT: blr +} + +; Function Attrs: norecurse nounwind readnone +define zeroext i1 @setcc_les0_i16(i16 signext %v0) { +entry: + %cmp = icmp sle i16 %v0, 0 + ret i1 %cmp + +; CHECK-LABEL: @setcc_les0_i16 +; CHECK: neg [[REG1:r[0-9]+]], r3 +; CHECK-NEXT: orc [[REG2:r[0-9]+]], r3, [[REG1]] +; CHECK-NEXT: srwi [[REG3:r[0-9]+]], [[REG2]], 31 +; CHECK-NEXT: blr +} + +; Function Attrs: norecurse nounwind readnone +define zeroext i1 @setcc_les0_i32(i32 signext %v0) { +entry: + %cmp = icmp sle i32 %v0, 0 + ret i1 %cmp + +; CHECK-LABEL: @setcc_les0_i32 +; CHECK: neg [[REG1:r[0-9]+]], r3 +; CHECK-NEXT: orc [[REG2:r[0-9]+]], r3, [[REG1]] +; CHECK-NEXT: srwi [[REG3:r[0-9]+]], [[REG2]], 31 +; CHECK-NEXT: blr +} + +; Function Attrs: norecurse nounwind readnone +define zeroext i1 @setcc_les0_i64(i64 signext %v0) { +entry: + %cmp = icmp sle i64 %v0, 0 + ret i1 %cmp + +; CHECK-LABEL: @setcc_les0_i64 +; CHECK: neg [[REG1:r[0-9]+]], r3 +; CHECK-NEXT: orc [[REG2:r[0-9]+]], r3, [[REG1]] +; CHECK-NEXT: rldicl [[REG3:r[0-9]+]], [[REG2]], 1, 63 +; CHECK-NEXT: blr +} + +; Function Attrs: norecurse nounwind readnone +define zeroext i1 @setcc_lts0_i8(i8 signext %v0) { +entry: + %cmp = icmp slt i8 %v0, 0 + ret i1 %cmp + +; CHECK-LABEL: @setcc_lts0_i8 +; CHECK: srwi [[REG1:r[0-9]+]], r3, 31 +; CHECK-NEXT: blr +} + +; Function Attrs: norecurse nounwind readnone +define zeroext i1 @setcc_lts0_i16(i16 signext %v0) { +entry: + %cmp = icmp slt i16 %v0, 0 + ret i1 %cmp + +; CHECK-LABEL: @setcc_lts0_i16 +; CHECK: srwi [[REG1:r[0-9]+]], r3, 31 +; CHECK-NEXT: blr +} + +; Function Attrs: norecurse nounwind readnone +define zeroext i1 @setcc_lts0_i32(i32 signext %v0) { +entry: + %cmp = icmp slt i32 %v0, 0 + ret i1 %cmp + +; CHECK-LABEL: @setcc_lts0_i32 +; CHECK: srwi [[REG1:r[0-9]+]], r3, 31 +; CHECK-NEXT: blr +} + +; Function Attrs: norecurse nounwind readnone +define zeroext i1 @setcc_lts0_i64(i64 signext %v0) { +entry: + %cmp = icmp slt i64 %v0, 0 + ret i1 %cmp + +; CHECK-LABEL: @setcc_lts0_i64 +; CHECK: rldicl [[REG1:r[0-9]+]], r3, 1, 63 +; CHECK-NEXT: blr +}