diff --git a/llvm/docs/GlobalISel/GenericOpcode.rst b/llvm/docs/GlobalISel/GenericOpcode.rst --- a/llvm/docs/GlobalISel/GenericOpcode.rst +++ b/llvm/docs/GlobalISel/GenericOpcode.rst @@ -280,6 +280,34 @@ %width_three = G_CONSTANT i32 3 %b:_(s32) = G_UBFX %x, %lsb_two, %width_three +G_BFI +^^^^^ +Insert a range of bits into a register. + +The source operands are registers as follows: + +- Source: existing value +- Value: the actual bits that will be inserted +- Position: the starting bit position where the value will be inserted +- Width: the bit-width of the value to be inserted + +The position (pos) and width operands are in the range: + +:: + + 0 <= pos < pos + width <= source bitwidth, where all values are unsigned + +.. code-block:: none + + ; Insert the value 0x5, with bit-width 8, starting at bit position 1 + ; + ; Example: + ; %src = 0..0111..001000011 ------> %a = 0..0111..000001011 + %val = G_CONSTANT i32 5 + %pos_one = G_CONSTANT i32 1 + %width_eight = G_CONSTANT i32 8 + %a:_(s32) = G_BFI %src, %val, %pos_one, %width_eight + Integer Operations ------------------- diff --git a/llvm/include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h b/llvm/include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h --- a/llvm/include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h +++ b/llvm/include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h @@ -1856,6 +1856,13 @@ return buildInstr(TargetOpcode::G_UBFX, {Dst}, {Src, LSB, Width}); } + /// Build and insert \p Dst = G_BFI \p Src, \p LSB, \p Width. + MachineInstrBuilder buildBfi(const DstOp &Dst, const SrcOp &Src, + const SrcOp &Val, const SrcOp &Pos, + const SrcOp &Width) { + return buildInstr(TargetOpcode::G_BFI, {Dst}, {Src, Val, Pos, Width}); + } + /// Build and insert \p Dst = G_ROTR \p Src, \p Amt MachineInstrBuilder buildRotateRight(const DstOp &Dst, const SrcOp &Src, const SrcOp &Amt) { diff --git a/llvm/include/llvm/Support/TargetOpcodes.def b/llvm/include/llvm/Support/TargetOpcodes.def --- a/llvm/include/llvm/Support/TargetOpcodes.def +++ b/llvm/include/llvm/Support/TargetOpcodes.def @@ -772,6 +772,8 @@ HANDLE_TARGET_OPCODE(G_SBFX) HANDLE_TARGET_OPCODE(G_UBFX) +HANDLE_TARGET_OPCODE(G_BFI) + /// Marker for the end of the generic opcode. /// This is used to check if an opcode is in the range of the /// generic opcodes. diff --git a/llvm/include/llvm/Target/GenericOpcodes.td b/llvm/include/llvm/Target/GenericOpcodes.td --- a/llvm/include/llvm/Target/GenericOpcodes.td +++ b/llvm/include/llvm/Target/GenericOpcodes.td @@ -1415,6 +1415,18 @@ let hasSideEffects = false; } +//------------------------------------------------------------------------------ +// Bitfield insertion. +//------------------------------------------------------------------------------ + +// Generic bitfield insertion. The operands are in the range +// 0 <= pos < pos + width <= src bitwidth, where all values are unsigned. +def G_BFI : GenericInstruction { + let OutOperandList = (outs type0:$dst); + let InOperandList = (ins type0:$src, type0:$val, type1:$pos, type1:$width); + let hasSideEffects = false; +} + //------------------------------------------------------------------------------ // Optimization hints //------------------------------------------------------------------------------ diff --git a/llvm/lib/CodeGen/MachineVerifier.cpp b/llvm/lib/CodeGen/MachineVerifier.cpp --- a/llvm/lib/CodeGen/MachineVerifier.cpp +++ b/llvm/lib/CodeGen/MachineVerifier.cpp @@ -1611,6 +1611,14 @@ } break; } + case TargetOpcode::G_BFI: { + LLT DstTy = MRI->getType(MI->getOperand(0).getReg()); + if (DstTy.isVector()) { + report("Bitfield insertion is not supported on vectors", MI); + break; + } + break; + } case TargetOpcode::G_ROTR: case TargetOpcode::G_ROTL: { LLT Src1Ty = MRI->getType(MI->getOperand(1).getReg()); diff --git a/llvm/test/MachineVerifier/test_g_bfi.mir b/llvm/test/MachineVerifier/test_g_bfi.mir new file mode 100644 --- /dev/null +++ b/llvm/test/MachineVerifier/test_g_bfi.mir @@ -0,0 +1,14 @@ +# RUN: not --crash llc -march=arm64 -verify-machineinstrs -run-pass none -o /dev/null %s 2>&1 | FileCheck %s +# REQUIRES: aarch64-registered-target + +name: test +body: | + bb.0: + %v1:_(<2 x s64>) = G_IMPLICIT_DEF + %v2:_(<2 x s64>) = G_IMPLICIT_DEF + %v3:_(<2 x s64>) = G_IMPLICIT_DEF + %v4:_(<2 x s64>) = G_IMPLICIT_DEF + + ; CHECK: *** Bad machine code: Bitfield insertion is not supported on vectors *** + %bfi_vector:_(<2 x s64>) = G_BFI %v1, %v2, %v3, %v4 +... diff --git a/llvm/unittests/CodeGen/GlobalISel/MachineIRBuilderTest.cpp b/llvm/unittests/CodeGen/GlobalISel/MachineIRBuilderTest.cpp --- a/llvm/unittests/CodeGen/GlobalISel/MachineIRBuilderTest.cpp +++ b/llvm/unittests/CodeGen/GlobalISel/MachineIRBuilderTest.cpp @@ -420,3 +420,27 @@ EXPECT_TRUE(CheckMachineFunction(*MF, CheckStr)) << *MF; } + +TEST_F(AArch64GISelMITest, BuildBitfieldInsert) { + StringRef MIRString = R"( + %3:_(s64) = COPY $x4 + )"; + setUp(MIRString.rtrim(' ')); + if (!TM) + return; + LLT S64 = LLT::scalar(64); + SmallVector Copies; + collectCopies(Copies, MF); + + B.buildBfi(S64, Copies[0], Copies[1], Copies[2], Copies[3]); + + const auto *CheckStr = R"( + ; CHECK: [[COPY0:%[0-9]+]]:_(s64) = COPY $x0 + ; CHECK: [[COPY1:%[0-9]+]]:_(s64) = COPY $x1 + ; CHECK: [[COPY2:%[0-9]+]]:_(s64) = COPY $x2 + ; CHECK: [[COPY3:%[0-9]+]]:_(s64) = COPY $x4 + ; CHECK: [[UBFX:%[0-9]+]]:_(s64) = G_BFI [[COPY0]]:_, [[COPY1]]:_, [[COPY2]]:_(s64), [[COPY3]]:_ + )"; + + EXPECT_TRUE(CheckMachineFunction(*MF, CheckStr)) << *MF; +}