diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp index d6b62736bdf60..4a7d2e9321c41 100644 --- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp +++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp @@ -22429,6 +22429,21 @@ void RISCVTargetLowering::computeKnownBitsForTargetNode(const SDValue Op, Known.Zero.setBitsFrom(LowBits); break; } + case RISCVISD::CLSW: { + // The upper 32 bits are ignored by the instruction, but ComputeNumSignBits + // doesn't give us a way to ignore them. If there are fewer than 33 sign + // bits in the input consider it as having no redundant sign bits. Otherwise + // the lower bound of the result is NumSignBits-33. The maximum value of the + // the result is 31. + unsigned NumSignBits = DAG.ComputeNumSignBits(Op.getOperand(0), Depth + 1); + unsigned MinRedundantSignBits = NumSignBits < 33 ? 0 : NumSignBits - 33; + // Create a ConstantRange [MinRedundantSignBits, 32) and convert it to + // KnownBits. + ConstantRange Range(APInt(BitWidth, MinRedundantSignBits), + APInt(BitWidth, 32)); + Known = Range.toKnownBits(); + break; + } case RISCVISD::BREV8: case RISCVISD::ORC_B: { // FIXME: This is based on the non-ratified Zbp GREV and GORC where a diff --git a/llvm/test/CodeGen/RISCV/rv64p.ll b/llvm/test/CodeGen/RISCV/rv64p.ll index 931771154f485..21779543ed011 100644 --- a/llvm/test/CodeGen/RISCV/rv64p.ll +++ b/llvm/test/CodeGen/RISCV/rv64p.ll @@ -222,6 +222,70 @@ define i32 @cls_i32_2(i32 %x) { ret i32 %e } +; The result is in the range [1-31], so we don't need an andi after the cls. +define i32 @cls_i32_knownbits(i32 %x) { +; CHECK-LABEL: cls_i32_knownbits: +; CHECK: # %bb.0: +; CHECK-NEXT: clsw a0, a0 +; CHECK-NEXT: ret + %a = ashr i32 %x, 31 + %b = xor i32 %x, %a + %c = call i32 @llvm.ctlz.i32(i32 %b, i1 false) + %d = sub i32 %c, 1 + %e = and i32 %d, 31 + ret i32 %e +} + +; There are at least 16 redundant sign bits so we don't need an ori after the clsw. +define i32 @cls_i32_knownbits_2(i16 signext %x) { +; CHECK-LABEL: cls_i32_knownbits_2: +; CHECK: # %bb.0: +; CHECK-NEXT: clsw a0, a0 +; CHECK-NEXT: ret + %sext = sext i16 %x to i32 + %a = ashr i32 %sext, 31 + %b = xor i32 %sext, %a + %c = call i32 @llvm.ctlz.i32(i32 %b, i1 false) + %d = sub i32 %c, 1 + %e = or i32 %d, 16 + ret i32 %e +} + +; There are at least 24 redundant sign bits so we don't need an ori after the clsw. +define i32 @cls_i32_knownbits_3(i8 signext %x) { +; CHECK-LABEL: cls_i32_knownbits_3: +; CHECK: # %bb.0: +; CHECK-NEXT: clsw a0, a0 +; CHECK-NEXT: ret + %sext = sext i8 %x to i32 + %a = ashr i32 %sext, 31 + %b = xor i32 %sext, %a + %c = call i32 @llvm.ctlz.i32(i32 %b, i1 false) + %d = sub i32 %c, 1 + %e = or i32 %d, 24 + ret i32 %e +} + +; Negative test. We only know there is at least 1 redundant sign bit. We can't +; remove the ori. +define i32 @cls_i32_knownbits_4(i32 signext %x) { +; CHECK-LABEL: cls_i32_knownbits_4: +; CHECK: # %bb.0: +; CHECK-NEXT: slli a0, a0, 33 +; CHECK-NEXT: srai a0, a0, 33 +; CHECK-NEXT: clsw a0, a0 +; CHECK-NEXT: ori a0, a0, 1 +; CHECK-NEXT: ret + %shl = shl i32 %x, 1 + %ashr = ashr i32 %shl, 1 + %a = ashr i32 %ashr, 31 + %b = xor i32 %ashr, %a + %c = call i32 @llvm.ctlz.i32(i32 %b, i1 false) + %d = sub i32 %c, 1 + %e = or i32 %d, 1 + ret i32 %e +} + define i64 @cls_i64(i64 %x) { ; CHECK-LABEL: cls_i64: ; CHECK: # %bb.0: