[GlobalISel] Add G_ASSERT_ZEXT
This adds a generic opcode which communicates that a type has already been
zero-extended from a narrower type.
This is intended to be similar to AssertZext in SelectionDAG.
For example,
```
%x_was_extended:_(s64) = G_ASSERT_ZEXT %x, 16
```
Signifies that the top 48 bits of %x are known to be 0.
This is useful in cases like this:
```
define i1 @zeroext_param(i8 zeroext %x) {
%cmp = icmp ult i8 %x, -20
ret i1 %cmp
}
```
In AArch64, `%x` must use a 32-bit register, which is then truncated to a 8-bit
value.
If we know that `%x` is already zero-ed out in the relevant high bits, we can
avoid the truncate.
Currently, in GISel, this looks like this:
```
_zeroext_param:
and w8, w0, #0xff ; We don't actually need this!
cmp w8, #236
cset w0, lo
ret
```
While SDAG does not produce the truncation, since it knows that it's
unnecessary:
```
_zeroext_param:
cmp w0, #236
cset w0, lo
ret
```
This patch
- Adds G_ASSERT_ZEXT
- Adds MIRBuilder support for it
- Adds MachineVerifier support for it
- Documents it
It also puts G_ASSERT_ZEXT into its own class of "hint instruction." (There
should be a G_ASSERT_SEXT in the future, maybe a G_ASSERT_ALIGN as well.)
This allows us to skip over hints in the legalizer etc. These can then later
be selected like COPY instructions or removed.
Differential Revision: https://reviews.llvm.org/D95564
2021-01-27 21:09:05 +01:00
|
|
|
# REQUIRES: aarch64-registered-target
|
|
|
|
# RUN: not --crash llc -verify-machineinstrs -mtriple aarch64 -run-pass none -o /dev/null %s 2>&1 | FileCheck %s
|
|
|
|
|
|
|
|
name: test
|
|
|
|
body: |
|
|
|
|
bb.0:
|
|
|
|
liveins: $x0, $w0
|
|
|
|
%0:_(s64) = COPY $x0
|
|
|
|
%1:_(<4 x s16>) = COPY $x0
|
|
|
|
%2:_(s32) = COPY $w0
|
|
|
|
|
|
|
|
; CHECK: *** Bad machine code: G_ASSERT_ZEXT expects an immediate operand #2 ***
|
|
|
|
; CHECK: instruction: %assert_zext_1:_(s64) = G_ASSERT_ZEXT
|
|
|
|
%assert_zext_1:_(s64) = G_ASSERT_ZEXT %0, %0
|
|
|
|
|
|
|
|
; CHECK: *** Bad machine code: G_ASSERT_ZEXT expects an immediate operand #2 ***
|
|
|
|
; CHECK: instruction: %assert_zext_2:_(s64) = G_ASSERT_ZEXT
|
|
|
|
%assert_zext_2:_(s64) = G_ASSERT_ZEXT %0, i8 8
|
|
|
|
|
|
|
|
; CHECK: *** Bad machine code: Type mismatch in generic instruction ***
|
|
|
|
; CHECK: instruction: %assert_zext_3:_(<2 x s32>) = G_ASSERT_ZEXT
|
|
|
|
%assert_zext_3:_(<2 x s32>) = G_ASSERT_ZEXT %0, 8
|
|
|
|
|
2021-02-12 12:29:13 +01:00
|
|
|
; CHECK: *** Bad machine code: Type mismatch in generic instruction ***
|
[GlobalISel] Add G_ASSERT_ZEXT
This adds a generic opcode which communicates that a type has already been
zero-extended from a narrower type.
This is intended to be similar to AssertZext in SelectionDAG.
For example,
```
%x_was_extended:_(s64) = G_ASSERT_ZEXT %x, 16
```
Signifies that the top 48 bits of %x are known to be 0.
This is useful in cases like this:
```
define i1 @zeroext_param(i8 zeroext %x) {
%cmp = icmp ult i8 %x, -20
ret i1 %cmp
}
```
In AArch64, `%x` must use a 32-bit register, which is then truncated to a 8-bit
value.
If we know that `%x` is already zero-ed out in the relevant high bits, we can
avoid the truncate.
Currently, in GISel, this looks like this:
```
_zeroext_param:
and w8, w0, #0xff ; We don't actually need this!
cmp w8, #236
cset w0, lo
ret
```
While SDAG does not produce the truncation, since it knows that it's
unnecessary:
```
_zeroext_param:
cmp w0, #236
cset w0, lo
ret
```
This patch
- Adds G_ASSERT_ZEXT
- Adds MIRBuilder support for it
- Adds MachineVerifier support for it
- Documents it
It also puts G_ASSERT_ZEXT into its own class of "hint instruction." (There
should be a G_ASSERT_SEXT in the future, maybe a G_ASSERT_ALIGN as well.)
This allows us to skip over hints in the legalizer etc. These can then later
be selected like COPY instructions or removed.
Differential Revision: https://reviews.llvm.org/D95564
2021-01-27 21:09:05 +01:00
|
|
|
; CHECK: instruction: %assert_zext_4:_(<2 x s32>) = G_ASSERT_ZEXT
|
|
|
|
%assert_zext_4:_(<2 x s32>) = G_ASSERT_ZEXT %1, 8
|
|
|
|
|
|
|
|
; CHECK: *** Bad machine code: G_ASSERT_ZEXT size must be >= 1 ***
|
|
|
|
; CHECK: instruction: %assert_zext_5:_(s64) = G_ASSERT_ZEXT
|
|
|
|
%assert_zext_5:_(s64) = G_ASSERT_ZEXT %0, 0
|
|
|
|
|
|
|
|
; CHECK: *** Bad machine code: G_ASSERT_ZEXT size must be less than source bit width ***
|
|
|
|
; CHECK: instruction: %assert_zext_6:_(s64) = G_ASSERT_ZEXT
|
|
|
|
%assert_zext_6:_(s64) = G_ASSERT_ZEXT %0, 128
|
|
|
|
|
|
|
|
; CHECK: *** Bad machine code: Type mismatch in generic instruction ***
|
|
|
|
; CHECK: instruction: %assert_zext_7:_(s64) = G_ASSERT_ZEXT %2:_, 8
|
|
|
|
%assert_zext_7:_(s64) = G_ASSERT_ZEXT %2, 8
|
|
|
|
|
|
|
|
; CHECK: *** Bad machine code: Generic instruction cannot have physical register ***
|
|
|
|
; CHECK: instruction: %assert_zext_8:_(s64) = G_ASSERT_ZEXT $x0, 8
|
|
|
|
%assert_zext_8:_(s64) = G_ASSERT_ZEXT $x0, 8
|