Skip to content

Commit 4773dd5

Browse files
author
Jessica Paquette
committed
[GlobalISel] Add G_SBFX + G_UBFX (bitfield extraction opcodes)
There is a bunch of similar bitfield extraction code throughout *ISelDAGToDAG. E.g, ARMISelDAGToDAG, AArch64ISelDAGToDAG, and AMDGPUISelDAGToDAG all contain code that matches a bitfield extract from an and + right shift. Rather than duplicating code in the same way, this adds two opcodes: - G_UBFX (unsigned bitfield extract) - G_SBFX (signed bitfield extract) They work like this ``` %x = G_UBFX %y, %lsb, %width ``` Where `lsb` and `width` are - The least-significant bit of the extraction - The width of the extraction This will extract `width` bits from `%y`, starting at `lsb`. G_UBFX zero-extends the result, while G_SBFX sign-extends the result. This should allow us to use the combiner to match the bitfield extraction patterns rather than duplicating pattern-matching code in each target. Differential Revision: https://reviews.llvm.org/D98464
1 parent cde203e commit 4773dd5

File tree

7 files changed

+115
-1
lines changed

7 files changed

+115
-1
lines changed

llvm/docs/GlobalISel/GenericOpcode.rst

+33
Original file line numberDiff line numberDiff line change
@@ -233,6 +233,39 @@ Reverse the order of the bits in a scalar.
233233
234234
%1:_(s32) = G_BITREVERSE %0:_(s32)
235235
236+
G_SBFX, G_UBFX
237+
^^^^^^^^^^^^^^
238+
239+
Extract a range of bits from a register.
240+
241+
The source operands are registers as follows:
242+
243+
- Source
244+
- The least-significant bit for the extraction
245+
- The width of the extraction
246+
247+
G_SBFX sign-extends the result, while G_UBFX zero-extends the result.
248+
249+
.. code-block:: none
250+
251+
; Extract 5 bits starting at bit 1 from %x and store them in %a.
252+
; Sign-extend the result.
253+
;
254+
; Example:
255+
; %x = 0...0000[10110]1 ---> %a = 1...111111[10110]
256+
%lsb_one = G_CONSTANT i32 1
257+
%width_five = G_CONSTANT i32 5
258+
%a:_(s32) = G_SBFX %x, %lsb_one, %width_five
259+
260+
; Extract 3 bits starting at bit 2 from %x and store them in %b. Zero-extend
261+
; the result.
262+
;
263+
; Example:
264+
; %x = 1...11111[100]11 ---> %b = 0...00000[100]
265+
%lsb_two = G_CONSTANT i32 2
266+
%width_three = G_CONSTANT i32 3
267+
%b:_(s32) = G_UBFX %x, %lsb_two, %width_three
268+
236269
Integer Operations
237270
-------------------
238271

llvm/include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h

+12
Original file line numberDiff line numberDiff line change
@@ -1831,6 +1831,18 @@ class MachineIRBuilder {
18311831
DstMMO, SrcMMO);
18321832
}
18331833

1834+
/// Build and insert \p Dst = G_SBFX \p Src, \p LSB, \p Width.
1835+
MachineInstrBuilder buildSbfx(const DstOp &Dst, const SrcOp &Src,
1836+
const SrcOp &LSB, const SrcOp &Width) {
1837+
return buildInstr(TargetOpcode::G_SBFX, {Dst}, {Src, LSB, Width});
1838+
}
1839+
1840+
/// Build and insert \p Dst = G_UBFX \p Src, \p LSB, \p Width.
1841+
MachineInstrBuilder buildUbfx(const DstOp &Dst, const SrcOp &Src,
1842+
const SrcOp &LSB, const SrcOp &Width) {
1843+
return buildInstr(TargetOpcode::G_UBFX, {Dst}, {Src, LSB, Width});
1844+
}
1845+
18341846
virtual MachineInstrBuilder buildInstr(unsigned Opc, ArrayRef<DstOp> DstOps,
18351847
ArrayRef<SrcOp> SrcOps,
18361848
Optional<unsigned> Flags = None);

llvm/include/llvm/Support/TargetOpcodes.def

+4-1
Original file line numberDiff line numberDiff line change
@@ -749,10 +749,13 @@ HANDLE_TARGET_OPCODE(G_VECREDUCE_SMIN)
749749
HANDLE_TARGET_OPCODE(G_VECREDUCE_UMAX)
750750
HANDLE_TARGET_OPCODE(G_VECREDUCE_UMIN)
751751

752+
HANDLE_TARGET_OPCODE(G_SBFX)
753+
HANDLE_TARGET_OPCODE(G_UBFX)
754+
752755
/// Marker for the end of the generic opcode.
753756
/// This is used to check if an opcode is in the range of the
754757
/// generic opcodes.
755-
HANDLE_TARGET_OPCODE_MARKER(PRE_ISEL_GENERIC_OPCODE_END, G_VECREDUCE_UMIN)
758+
HANDLE_TARGET_OPCODE_MARKER(PRE_ISEL_GENERIC_OPCODE_END, G_UBFX)
756759

757760
/// BUILTIN_OP_END - This must be the last enum value in this list.
758761
/// The target-specific post-isel opcode values start here.

llvm/include/llvm/Target/GenericOpcodes.td

+18
Original file line numberDiff line numberDiff line change
@@ -1354,6 +1354,24 @@ def G_MEMSET : GenericInstruction {
13541354
let mayStore = true;
13551355
}
13561356

1357+
//------------------------------------------------------------------------------
1358+
// Bitfield extraction.
1359+
//------------------------------------------------------------------------------
1360+
1361+
// Generic signed bitfield extraction.
1362+
def G_SBFX : GenericInstruction {
1363+
let OutOperandList = (outs type0:$dst);
1364+
let InOperandList = (ins type0:$src, type0:$lsb, type0:$width);
1365+
let hasSideEffects = false;
1366+
}
1367+
1368+
// Generic unsigned bitfield extraction.
1369+
def G_UBFX : GenericInstruction {
1370+
let OutOperandList = (outs type0:$dst);
1371+
let InOperandList = (ins type0:$src, type0:$lsb, type0:$width);
1372+
let hasSideEffects = false;
1373+
}
1374+
13571375
//------------------------------------------------------------------------------
13581376
// Optimization hints
13591377
//------------------------------------------------------------------------------

llvm/lib/CodeGen/MachineVerifier.cpp

+11
Original file line numberDiff line numberDiff line change
@@ -1566,6 +1566,17 @@ void MachineVerifier::verifyPreISelGenericInstruction(const MachineInstr *MI) {
15661566
report("Vector reduction requires vector source=", MI);
15671567
break;
15681568
}
1569+
1570+
case TargetOpcode::G_SBFX:
1571+
case TargetOpcode::G_UBFX: {
1572+
LLT DstTy = MRI->getType(MI->getOperand(0).getReg());
1573+
if (DstTy.isVector()) {
1574+
report("Bitfield extraction is not supported on vectors", MI);
1575+
break;
1576+
}
1577+
break;
1578+
}
1579+
15691580
default:
15701581
break;
15711582
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# RUN: not --crash llc -verify-machineinstrs -run-pass none -o /dev/null %s 2>&1 | FileCheck %s
2+
# REQUIRES: aarch64-registered-target
3+
4+
name: test
5+
body: |
6+
bb.0:
7+
%v1:_(<2 x s64>) = G_IMPLICIT_DEF
8+
%v2:_(<2 x s64>) = G_IMPLICIT_DEF
9+
%v3:_(<2 x s64>) = G_IMPLICIT_DEF
10+
11+
; CHECK: *** Bad machine code: Bitfield extraction is not supported on vectors ***
12+
%ubfx_vector:_(<2 x s64>) = G_UBFX %v1, %v2, %v3
13+
; CHECK: *** Bad machine code: Bitfield extraction is not supported on vectors ***
14+
%sbfx_vector:_(<2 x s64>) = G_SBFX %v1, %v2, %v3
15+
...

llvm/unittests/CodeGen/GlobalISel/MachineIRBuilderTest.cpp

+22
Original file line numberDiff line numberDiff line change
@@ -398,3 +398,25 @@ TEST_F(AArch64GISelMITest, BuildAddoSubo) {
398398

399399
EXPECT_TRUE(CheckMachineFunction(*MF, CheckStr)) << *MF;
400400
}
401+
402+
TEST_F(AArch64GISelMITest, BuildBitfieldExtract) {
403+
setUp();
404+
if (!TM)
405+
return;
406+
LLT S64 = LLT::scalar(64);
407+
SmallVector<Register, 4> Copies;
408+
collectCopies(Copies, MF);
409+
410+
auto Ubfx = B.buildUbfx(S64, Copies[0], Copies[1], Copies[2]);
411+
B.buildSbfx(S64, Ubfx, Copies[0], Copies[2]);
412+
413+
const auto *CheckStr = R"(
414+
; CHECK: [[COPY0:%[0-9]+]]:_(s64) = COPY $x0
415+
; CHECK: [[COPY1:%[0-9]+]]:_(s64) = COPY $x1
416+
; CHECK: [[COPY2:%[0-9]+]]:_(s64) = COPY $x2
417+
; CHECK: [[UBFX:%[0-9]+]]:_(s64) = G_UBFX [[COPY0]]:_, [[COPY1]]:_, [[COPY2]]:_
418+
; CHECK: [[SBFX:%[0-9]+]]:_(s64) = G_SBFX [[UBFX]]:_, [[COPY0]]:_, [[COPY2]]:_
419+
)";
420+
421+
EXPECT_TRUE(CheckMachineFunction(*MF, CheckStr)) << *MF;
422+
}

0 commit comments

Comments
 (0)