[GISel] computeKnownBits - add CTLS handling - #178063
Conversation
|
@llvm/pr-subscribers-llvm-globalisel @llvm/pr-subscribers-backend-risc-v Author: Gergo Stomfai (stomfaig) ChangesCloses llvm/llvm-project#174370 Full diff: https://github.com/llvm/llvm-project/pull/178063.diff 4 Files Affected:
diff --git a/llvm/lib/CodeGen/GlobalISel/GISelValueTracking.cpp b/llvm/lib/CodeGen/GlobalISel/GISelValueTracking.cpp
index 34692f0b4c4ee..014e0efcaed2d 100644
--- a/llvm/lib/CodeGen/GlobalISel/GISelValueTracking.cpp
+++ b/llvm/lib/CodeGen/GlobalISel/GISelValueTracking.cpp
@@ -681,6 +681,15 @@ void GISelValueTracking::computeKnownBitsImpl(Register R, KnownBits &Known,
Known.Zero.setBitsFrom(LowBits);
break;
}
+ case TargetOpcode::G_CTLS: {
+ unsigned MinRedundantSignBits =
+ computeNumSignBits(MI.getOperand(0).getReg(), Depth + 1) - 1;
+
+ ConstantRange Range(APInt(BitWidth, MinRedundantSignBits),
+ APInt(BitWidth, BitWidth));
+ Known = Range.toKnownBits();
+ break;
+ }
case TargetOpcode::G_EXTRACT_VECTOR_ELT: {
GExtractVectorElement &Extract = cast<GExtractVectorElement>(MI);
Register InVec = Extract.getVectorReg();
diff --git a/llvm/test/CodeGen/AArch64/arm64-clrsb.ll b/llvm/test/CodeGen/AArch64/arm64-clrsb.ll
index 4597c6178e2ba..2f4b0ac3653a0 100644
--- a/llvm/test/CodeGen/AArch64/arm64-clrsb.ll
+++ b/llvm/test/CodeGen/AArch64/arm64-clrsb.ll
@@ -91,6 +91,137 @@ entry:
ret i64 %0
}
-;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line:
-; CHECK-GI: {{.*}}
-; CHECK-SD: {{.*}}
+define i8 @cls_i8(i8 %x) {
+; CHECK-LABEL: cls_i8:
+; CHECK: ; %bb.0:
+; CHECK-NEXT: sxtb w8, w0
+; CHECK-NEXT: cls w8, w8
+; CHECK-NEXT: sub w0, w8, #24
+; CHECK-NEXT: ret
+
+ %a = ashr i8 %x, 7
+ %b = xor i8 %x, %a
+ %c = call i8 @llvm.ctlz.i8(i8 %b, i1 false)
+ %d = sub i8 %c, 1
+ ret i8 %d
+}
+
+; 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: cls w0, w0
+; 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 cls.
+define i32 @cls_i32_knownbits_2(i16 signext %x) {
+; CHECK-LABEL: cls_i32_knownbits_2:
+; CHECK: ; %bb.0:
+; CHECK-NEXT: cls w0, w0
+; 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
+}
+
+; Check that the range max in ctls cls knownbits
+; is not set to 32
+define i64 @cls_i64_not_32(i64 %x) {
+; CHECK-SD-LABEL: cls_i64_not_32:
+; CHECK-SD: ; %bb.0:
+; CHECK-SD-NEXT: asr x8, x0, #16
+; CHECK-SD-NEXT: cls x8, x8
+; CHECK-SD-NEXT: orr x0, x8, #0x10
+; CHECK-SD-NEXT: ret
+;
+; CHECK-GI-LABEL: cls_i64_not_32:
+; CHECK-GI: ; %bb.0:
+; CHECK-GI-NEXT: asr x8, x0, #63
+; CHECK-GI-NEXT: eor x8, x8, x0, asr #16
+; CHECK-GI-NEXT: lsl x8, x8, #1
+; CHECK-GI-NEXT: orr x8, x8, #0x1
+; CHECK-GI-NEXT: clz x8, x8
+; CHECK-GI-NEXT: orr x0, x8, #0x10
+; CHECK-GI-NEXT: ret
+ %val = ashr i64 %x, 16
+ %a = ashr i64 %val, 63
+ %b = xor i64 %val, %a
+ %c = shl i64 %b, 1
+ %d = or i64 %c, 1
+ %e = call i64 @llvm.ctlz.i64(i64 %d, i1 true)
+ %f = or i64 %e, 16
+ ret i64 %f
+}
+
+; 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: cls w0, w0
+; 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: sbfx w8, w0, #0, #31
+; CHECK-NEXT: cls w8, w8
+; CHECK-NEXT: orr w0, w8, #0x1
+; 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
+ }
+
+; Negative test. Check that the number of sign bits is not
+; overestimated. If it is, the orr disappears.
+define i32 @cls_i32_knownbits_no_overestimate(i32 signext %x) {
+; CHECK-SD-LABEL: cls_i32_knownbits_no_overestimate:
+; CHECK-SD: ; %bb.0:
+; CHECK-SD-NEXT: asr w8, w0, #15
+; CHECK-SD-NEXT: cls w8, w8
+; CHECK-SD-NEXT: orr w0, w8, #0x10
+; CHECK-SD-NEXT: ret
+;
+; CHECK-GI-LABEL: cls_i32_knownbits_no_overestimate:
+; CHECK-GI: ; %bb.0:
+; CHECK-GI-NEXT: asr w8, w0, #31
+; CHECK-GI-NEXT: eor w8, w8, w0, asr #15
+; CHECK-GI-NEXT: clz w8, w8
+; CHECK-GI-NEXT: sub w8, w8, #1
+; CHECK-GI-NEXT: orr w0, w8, #0x10
+; CHECK-GI-NEXT: ret
+ %ashr = ashr i32 %x, 15
+ %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, 16
+ ret i32 %e
+ }
+
diff --git a/llvm/test/CodeGen/RISCV/GlobalISel/rv32p.ll b/llvm/test/CodeGen/RISCV/GlobalISel/rv32p.ll
index 3f403fd8cb9e5..5708077fcefb1 100644
--- a/llvm/test/CodeGen/RISCV/GlobalISel/rv32p.ll
+++ b/llvm/test/CodeGen/RISCV/GlobalISel/rv32p.ll
@@ -139,3 +139,88 @@ define i64 @cls_i64_2(i64 %x) {
%e = call i64 @llvm.ctlz.i64(i64 %d, i1 true)
ret i64 %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: cls 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: cls 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: cls 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, 1
+; CHECK-NEXT: srai a0, a0, 1
+; CHECK-NEXT: cls 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
+ }
+
+; Negative test. Check that the number of sign bits is not
+; overestimated. If it is, the ori disappears.
+define i32 @cls_i32_knownbits_no_overestimate(i32 signext %x) {
+; CHECK-LABEL: cls_i32_knownbits_no_overestimate:
+; CHECK: # %bb.0:
+; CHECK-NEXT: srai a1, a0, 15
+; CHECK-NEXT: srai a0, a0, 31
+; CHECK-NEXT: xor a0, a1, a0
+; CHECK-NEXT: clz a0, a0
+; CHECK-NEXT: addi a0, a0, -1
+; CHECK-NEXT: ori a0, a0, 16
+; CHECK-NEXT: ret
+ %ashr = ashr i32 %x, 15
+ %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, 16
+ ret i32 %e
+ }
diff --git a/llvm/test/CodeGen/RISCV/GlobalISel/rv64p.ll b/llvm/test/CodeGen/RISCV/GlobalISel/rv64p.ll
index 5faf1079a7804..fa32f3ed39c92 100644
--- a/llvm/test/CodeGen/RISCV/GlobalISel/rv64p.ll
+++ b/llvm/test/CodeGen/RISCV/GlobalISel/rv64p.ll
@@ -112,3 +112,26 @@ define i64 @cls_i64_2(i64 %x) {
%e = call i64 @llvm.ctlz.i64(i64 %d, i1 true)
ret i64 %e
}
+
+; Check that the range max in ctls cls knownbits
+; is not set to 32. If it is, then ori disappears.
+define i64 @cls_i64_not_32(i64 %x) {
+; CHECK-LABEL: cls_i64_not_32:
+; CHECK: # %bb.0:
+; CHECK-NEXT: srai a1, a0, 16
+; CHECK-NEXT: srai a0, a0, 63
+; CHECK-NEXT: xor a0, a1, a0
+; CHECK-NEXT: slli a0, a0, 1
+; CHECK-NEXT: ori a0, a0, 1
+; CHECK-NEXT: clz a0, a0
+; CHECK-NEXT: ori a0, a0, 16
+; CHECK-NEXT: ret
+ %val = ashr i64 %x, 16
+ %a = ashr i64 %val, 63
+ %b = xor i64 %val, %a
+ %c = shl i64 %b, 1
+ %d = or i64 %c, 1
+ %e = call i64 @llvm.ctlz.i64(i64 %d, i1 true)
+ %f = or i64 %e, 16
+ ret i64 %f
+}
|
|
@llvm/pr-subscribers-backend-aarch64 Author: Gergo Stomfai (stomfaig) ChangesCloses llvm/llvm-project#174370 Full diff: https://github.com/llvm/llvm-project/pull/178063.diff 4 Files Affected:
diff --git a/llvm/lib/CodeGen/GlobalISel/GISelValueTracking.cpp b/llvm/lib/CodeGen/GlobalISel/GISelValueTracking.cpp
index 34692f0b4c4ee..014e0efcaed2d 100644
--- a/llvm/lib/CodeGen/GlobalISel/GISelValueTracking.cpp
+++ b/llvm/lib/CodeGen/GlobalISel/GISelValueTracking.cpp
@@ -681,6 +681,15 @@ void GISelValueTracking::computeKnownBitsImpl(Register R, KnownBits &Known,
Known.Zero.setBitsFrom(LowBits);
break;
}
+ case TargetOpcode::G_CTLS: {
+ unsigned MinRedundantSignBits =
+ computeNumSignBits(MI.getOperand(0).getReg(), Depth + 1) - 1;
+
+ ConstantRange Range(APInt(BitWidth, MinRedundantSignBits),
+ APInt(BitWidth, BitWidth));
+ Known = Range.toKnownBits();
+ break;
+ }
case TargetOpcode::G_EXTRACT_VECTOR_ELT: {
GExtractVectorElement &Extract = cast<GExtractVectorElement>(MI);
Register InVec = Extract.getVectorReg();
diff --git a/llvm/test/CodeGen/AArch64/arm64-clrsb.ll b/llvm/test/CodeGen/AArch64/arm64-clrsb.ll
index 4597c6178e2ba..2f4b0ac3653a0 100644
--- a/llvm/test/CodeGen/AArch64/arm64-clrsb.ll
+++ b/llvm/test/CodeGen/AArch64/arm64-clrsb.ll
@@ -91,6 +91,137 @@ entry:
ret i64 %0
}
-;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line:
-; CHECK-GI: {{.*}}
-; CHECK-SD: {{.*}}
+define i8 @cls_i8(i8 %x) {
+; CHECK-LABEL: cls_i8:
+; CHECK: ; %bb.0:
+; CHECK-NEXT: sxtb w8, w0
+; CHECK-NEXT: cls w8, w8
+; CHECK-NEXT: sub w0, w8, #24
+; CHECK-NEXT: ret
+
+ %a = ashr i8 %x, 7
+ %b = xor i8 %x, %a
+ %c = call i8 @llvm.ctlz.i8(i8 %b, i1 false)
+ %d = sub i8 %c, 1
+ ret i8 %d
+}
+
+; 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: cls w0, w0
+; 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 cls.
+define i32 @cls_i32_knownbits_2(i16 signext %x) {
+; CHECK-LABEL: cls_i32_knownbits_2:
+; CHECK: ; %bb.0:
+; CHECK-NEXT: cls w0, w0
+; 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
+}
+
+; Check that the range max in ctls cls knownbits
+; is not set to 32
+define i64 @cls_i64_not_32(i64 %x) {
+; CHECK-SD-LABEL: cls_i64_not_32:
+; CHECK-SD: ; %bb.0:
+; CHECK-SD-NEXT: asr x8, x0, #16
+; CHECK-SD-NEXT: cls x8, x8
+; CHECK-SD-NEXT: orr x0, x8, #0x10
+; CHECK-SD-NEXT: ret
+;
+; CHECK-GI-LABEL: cls_i64_not_32:
+; CHECK-GI: ; %bb.0:
+; CHECK-GI-NEXT: asr x8, x0, #63
+; CHECK-GI-NEXT: eor x8, x8, x0, asr #16
+; CHECK-GI-NEXT: lsl x8, x8, #1
+; CHECK-GI-NEXT: orr x8, x8, #0x1
+; CHECK-GI-NEXT: clz x8, x8
+; CHECK-GI-NEXT: orr x0, x8, #0x10
+; CHECK-GI-NEXT: ret
+ %val = ashr i64 %x, 16
+ %a = ashr i64 %val, 63
+ %b = xor i64 %val, %a
+ %c = shl i64 %b, 1
+ %d = or i64 %c, 1
+ %e = call i64 @llvm.ctlz.i64(i64 %d, i1 true)
+ %f = or i64 %e, 16
+ ret i64 %f
+}
+
+; 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: cls w0, w0
+; 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: sbfx w8, w0, #0, #31
+; CHECK-NEXT: cls w8, w8
+; CHECK-NEXT: orr w0, w8, #0x1
+; 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
+ }
+
+; Negative test. Check that the number of sign bits is not
+; overestimated. If it is, the orr disappears.
+define i32 @cls_i32_knownbits_no_overestimate(i32 signext %x) {
+; CHECK-SD-LABEL: cls_i32_knownbits_no_overestimate:
+; CHECK-SD: ; %bb.0:
+; CHECK-SD-NEXT: asr w8, w0, #15
+; CHECK-SD-NEXT: cls w8, w8
+; CHECK-SD-NEXT: orr w0, w8, #0x10
+; CHECK-SD-NEXT: ret
+;
+; CHECK-GI-LABEL: cls_i32_knownbits_no_overestimate:
+; CHECK-GI: ; %bb.0:
+; CHECK-GI-NEXT: asr w8, w0, #31
+; CHECK-GI-NEXT: eor w8, w8, w0, asr #15
+; CHECK-GI-NEXT: clz w8, w8
+; CHECK-GI-NEXT: sub w8, w8, #1
+; CHECK-GI-NEXT: orr w0, w8, #0x10
+; CHECK-GI-NEXT: ret
+ %ashr = ashr i32 %x, 15
+ %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, 16
+ ret i32 %e
+ }
+
diff --git a/llvm/test/CodeGen/RISCV/GlobalISel/rv32p.ll b/llvm/test/CodeGen/RISCV/GlobalISel/rv32p.ll
index 3f403fd8cb9e5..5708077fcefb1 100644
--- a/llvm/test/CodeGen/RISCV/GlobalISel/rv32p.ll
+++ b/llvm/test/CodeGen/RISCV/GlobalISel/rv32p.ll
@@ -139,3 +139,88 @@ define i64 @cls_i64_2(i64 %x) {
%e = call i64 @llvm.ctlz.i64(i64 %d, i1 true)
ret i64 %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: cls 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: cls 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: cls 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, 1
+; CHECK-NEXT: srai a0, a0, 1
+; CHECK-NEXT: cls 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
+ }
+
+; Negative test. Check that the number of sign bits is not
+; overestimated. If it is, the ori disappears.
+define i32 @cls_i32_knownbits_no_overestimate(i32 signext %x) {
+; CHECK-LABEL: cls_i32_knownbits_no_overestimate:
+; CHECK: # %bb.0:
+; CHECK-NEXT: srai a1, a0, 15
+; CHECK-NEXT: srai a0, a0, 31
+; CHECK-NEXT: xor a0, a1, a0
+; CHECK-NEXT: clz a0, a0
+; CHECK-NEXT: addi a0, a0, -1
+; CHECK-NEXT: ori a0, a0, 16
+; CHECK-NEXT: ret
+ %ashr = ashr i32 %x, 15
+ %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, 16
+ ret i32 %e
+ }
diff --git a/llvm/test/CodeGen/RISCV/GlobalISel/rv64p.ll b/llvm/test/CodeGen/RISCV/GlobalISel/rv64p.ll
index 5faf1079a7804..fa32f3ed39c92 100644
--- a/llvm/test/CodeGen/RISCV/GlobalISel/rv64p.ll
+++ b/llvm/test/CodeGen/RISCV/GlobalISel/rv64p.ll
@@ -112,3 +112,26 @@ define i64 @cls_i64_2(i64 %x) {
%e = call i64 @llvm.ctlz.i64(i64 %d, i1 true)
ret i64 %e
}
+
+; Check that the range max in ctls cls knownbits
+; is not set to 32. If it is, then ori disappears.
+define i64 @cls_i64_not_32(i64 %x) {
+; CHECK-LABEL: cls_i64_not_32:
+; CHECK: # %bb.0:
+; CHECK-NEXT: srai a1, a0, 16
+; CHECK-NEXT: srai a0, a0, 63
+; CHECK-NEXT: xor a0, a1, a0
+; CHECK-NEXT: slli a0, a0, 1
+; CHECK-NEXT: ori a0, a0, 1
+; CHECK-NEXT: clz a0, a0
+; CHECK-NEXT: ori a0, a0, 16
+; CHECK-NEXT: ret
+ %val = ashr i64 %x, 16
+ %a = ashr i64 %val, 63
+ %b = xor i64 %val, %a
+ %c = shl i64 %b, 1
+ %d = or i64 %c, 1
+ %e = call i64 @llvm.ctlz.i64(i64 %d, i1 true)
+ %f = or i64 %e, 16
+ ret i64 %f
+}
|
|
Can you add some direct tests, as in for example llvm/test/CodeGen/AArch64/GlobalISel/knownbits-sub.mir? |
arsenm
left a comment
There was a problem hiding this comment.
Can you add a test with vectors
|
@arsenm, Do you mean on mir level, or in ll tests too? |
2bf729b to
94ab16b
Compare
| KnownBits SrcOpKnown; | ||
| auto Reg = MI.getOperand(1).getReg(); | ||
|
|
||
| computeKnownBitsImpl(Reg, SrcOpKnown, DemandedElts, Depth + 1); |
There was a problem hiding this comment.
Why is this more accurate than using computeNumSignBits like you had before? Doesn't computeNumSignBits use computeKnownBits as a fallback?
There was a problem hiding this comment.
The main point is that having SrcOpKnown we can decide if the value is constant. Because if it is, then we know it's ctls exactly.
But if I only use computeNumSignBits, then I would have to excavate the constantness information again, so likely would need to have a computeKnownBitsImpl anyway.
There was a problem hiding this comment.
If all the input bits are known, then I hope the input would be constant folded elsewhere. If that's the case, then we should be able to add a combine that constant folds ctls without needing computeKnownBits to do it.
Not using computeNumSignBits prevents us from being able to determine sign bits if the input is a G_SEXT or G_SEXT_INREG. In those cases we know the number of sign bits but not the exact value.
There was a problem hiding this comment.
I see. I was wondering why the G_SEXT and G_SEXT_INREG was not working properly. Thanks for pointing this out.
🪟 Windows x64 Test Results
✅ The build succeeded and all tests passed. |
🐧 Linux x64 Test Results
✅ The build succeeded and all tests passed. |
|
Looks like there's some constant folding for G_CTLZ/G_CTTZ in CSEMIRBuilder::buildInstr. G_CTLS should probably be added there in another PR.. |
| ;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line: | ||
| ; CHECK-GI: {{.*}} | ||
| ; CHECK-SD: {{.*}} | ||
| define i8 @cls_i8(i8 %x) { |
There was a problem hiding this comment.
Can we add a gisel RUN line to llvm/test/CodeGen/AArch64/cls.ll instead of copy and pasting the tests here?
There was a problem hiding this comment.
Oh. You already did that. So are these tests duplicated?
There was a problem hiding this comment.
Yes, they are duplicates apart from the mtriple. Will remove.
| auto Reg = MI.getOperand(1).getReg(); | ||
| unsigned MinRedundantSignBits = computeNumSignBits(Reg, Depth + 1) - 1; | ||
|
|
||
| unsigned MaxUpperRedundantSignBits = MRI.getType(Reg).getScalarSizeInBits(); |
There was a problem hiding this comment.
Can this be different to BitWidth? Does GISel allow mismatching src/dst types?
There was a problem hiding this comment.
Sorry, I am not sure if you mean it should allow, or if they should be the same?
There was a problem hiding this comment.
The source and dest types should not be assumed to match. G_CTLS is defined with 2 type indexes
There was a problem hiding this comment.
In that case, I believe that this mr is ready?
Closes #174370