Index: llvm/docs/GlobalISel/GenericOpcode.rst =================================================================== --- llvm/docs/GlobalISel/GenericOpcode.rst +++ llvm/docs/GlobalISel/GenericOpcode.rst @@ -233,6 +233,39 @@ %1:_(s32) = G_BITREVERSE %0:_(s32) +G_SBFX, G_UBFX +^^^^^^^^^^^^^^ + +Extract a range of bits from a register. + +The range is defined using two immediates. + +- The first immediate is the least-significant bit (LSB). +- The second immediate is the width of the extraction. + +G_SBFX sign-extends the result, while G_UBFX zero-extends the result. + +Given a scalar of width W + +- The LSB must be in the range [0, W]. +- The width of the extraction must be in the range [1, W-LSB]. + +.. code-block:: none + + ; Extract 5 bits starting at bit 1 from %x and store them in %a. + ; Sign-extend the result. + ; + ; Example: + ; %x = 0...0000[10110]1 ---> %a = 1...111111[10110] + %a:_(s32) = G_SBFX %x, 1, 5 + + ; Extract 3 bits starting at bit 2 from %x and store them in %b. Zero-extend + ; the result. + ; + ; Example: + ; %x = 1...11111[100]11 ---> %b = 0...00000[100] + %b:_(s32) = G_UBFX %x, 2, 3 + Integer Operations ------------------- Index: llvm/include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h =================================================================== --- llvm/include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h +++ llvm/include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h @@ -1810,6 +1810,15 @@ MachineInstrBuilder buildVecReduceUMin(const DstOp &Dst, const SrcOp &Src) { return buildInstr(TargetOpcode::G_VECREDUCE_UMIN, {Dst}, {Src}); } + + /// Build and insert \p Dst = G_SBFX \p Src, \p LSB, \p Width. + MachineInstrBuilder buildSbfx(const DstOp &Dst, const SrcOp &Src, + uint64_t LSB, uint64_t Width); + + /// Build and insert \p Dst = G_UBFX \p Src, \p LSB, \p Width. + MachineInstrBuilder buildUbfx(const DstOp &Dst, const SrcOp &Src, + uint64_t LSB, uint64_t Width); + virtual MachineInstrBuilder buildInstr(unsigned Opc, ArrayRef DstOps, ArrayRef SrcOps, Optional Flags = None); Index: llvm/include/llvm/Support/TargetOpcodes.def =================================================================== --- llvm/include/llvm/Support/TargetOpcodes.def +++ llvm/include/llvm/Support/TargetOpcodes.def @@ -743,10 +743,13 @@ HANDLE_TARGET_OPCODE(G_VECREDUCE_UMAX) HANDLE_TARGET_OPCODE(G_VECREDUCE_UMIN) +HANDLE_TARGET_OPCODE(G_SBFX) +HANDLE_TARGET_OPCODE(G_UBFX) + /// Marker for the end of the generic opcode. /// This is used to check if an opcode is in the range of the /// generic opcodes. -HANDLE_TARGET_OPCODE_MARKER(PRE_ISEL_GENERIC_OPCODE_END, G_VECREDUCE_UMIN) +HANDLE_TARGET_OPCODE_MARKER(PRE_ISEL_GENERIC_OPCODE_END, G_UBFX) /// BUILTIN_OP_END - This must be the last enum value in this list. /// The target-specific post-isel opcode values start here. Index: llvm/include/llvm/Target/GenericOpcodes.td =================================================================== --- llvm/include/llvm/Target/GenericOpcodes.td +++ llvm/include/llvm/Target/GenericOpcodes.td @@ -1338,6 +1338,24 @@ let mayStore = true; } +//------------------------------------------------------------------------------ +// Bitfield extraction. +//------------------------------------------------------------------------------ + +// Generic signed bitfield extraction. +def G_SBFX : GenericInstruction { + let OutOperandList = (outs type0:$dst); + let InOperandList = (ins type0:$src, unknown:$lsb, unknown:$width); + let hasSideEffects = false; +} + +// Generic unsigned bitfield extraction. +def G_UBFX : GenericInstruction { + let OutOperandList = (outs type0:$dst); + let InOperandList = (ins type0:$src, unknown:$lsb, unknown:$width); + let hasSideEffects = false; +} + //------------------------------------------------------------------------------ // Optimization hints //------------------------------------------------------------------------------ Index: llvm/lib/CodeGen/GlobalISel/MachineIRBuilder.cpp =================================================================== --- llvm/lib/CodeGen/GlobalISel/MachineIRBuilder.cpp +++ llvm/lib/CodeGen/GlobalISel/MachineIRBuilder.cpp @@ -948,6 +948,22 @@ return buildInstr(TargetOpcode::G_BLOCK_ADDR).addDef(Res).addBlockAddress(BA); } +MachineInstrBuilder MachineIRBuilder::buildSbfx(const DstOp &Dst, + const SrcOp &Src, uint64_t LSB, + uint64_t Width) { + return buildInstr(TargetOpcode::G_SBFX, {Dst}, {Src}) + .addImm(LSB) + .addImm(Width); +} + +MachineInstrBuilder MachineIRBuilder::buildUbfx(const DstOp &Dst, + const SrcOp &Src, uint64_t LSB, + uint64_t Width) { + return buildInstr(TargetOpcode::G_UBFX, {Dst}, {Src}) + .addImm(LSB) + .addImm(Width); +} + void MachineIRBuilder::validateTruncExt(const LLT DstTy, const LLT SrcTy, bool IsExtend) { #ifndef NDEBUG Index: llvm/lib/CodeGen/MachineVerifier.cpp =================================================================== --- llvm/lib/CodeGen/MachineVerifier.cpp +++ llvm/lib/CodeGen/MachineVerifier.cpp @@ -1566,6 +1566,33 @@ report("Vector reduction requires vector source=", MI); break; } + + case TargetOpcode::G_SBFX: + case TargetOpcode::G_UBFX: { + LLT DstTy = MRI->getType(MI->getOperand(0).getReg()); + if (DstTy.isVector()) { + report("Bitfield extraction is not supported on vectors", MI); + break; + } + + uint64_t DstSize = DstTy.getSizeInBits(); + int64_t LSB = MI->getOperand(2).getImm(); + int64_t MaxLSB = DstSize - 1; + if (LSB < 0 || LSB > MaxLSB) { + report("LSB (operand 2) must be in [0, " + Twine(MaxLSB) + "]", MI); + break; + } + + int64_t Width = MI->getOperand(3).getImm(); + uint64_t MaxWidth = DstSize - LSB; + if (Width < 1 || static_cast(Width) > MaxWidth) { + report("Width (operand 3) must be in [1, " + Twine(MaxWidth) + "]", + MI); + break; + } + break; + } + default: break; } Index: llvm/test/MachineVerifier/test_g_sbfx.mir =================================================================== --- /dev/null +++ llvm/test/MachineVerifier/test_g_sbfx.mir @@ -0,0 +1,31 @@ +# RUN: not --crash llc -verify-machineinstrs -run-pass none -o /dev/null %s 2>&1 | FileCheck %s +# REQUIRES: aarch64-registered-target + +name: test +body: | + bb.0: + %v2s64:_(<2 x s64>) = G_IMPLICIT_DEF + %s64:_(s64) = G_IMPLICIT_DEF + %s32:_(s32) = G_IMPLICIT_DEF + + ; CHECK: *** Bad machine code: Bitfield extraction is not supported on vectors *** + %vector_ty:_(<2 x s64>) = G_SBFX %v2s64, 0, 3 + + ; CHECK: *** Bad machine code: LSB (operand 2) must be in [0, 63] *** + %lsb_too_small:_(s64) = G_SBFX %s64, -1, 2 + + ; CHECK: Bad machine code: LSB (operand 2) must be in [0, 63] *** + %lsb_too_large:_(s64) = G_SBFX %s64, 64, 2 + + ; CHECK: Bad machine code: Width (operand 3) must be in [1, 63] *** + %width_too_small:_(s64) = G_SBFX %s64, 1, 0 + + ; CHECK: Bad machine code: Width (operand 3) must be in [1, 64] *** + %width_too_large_1:_(s64) = G_SBFX %s64, 0, 65 + + ; CHECK: *** Bad machine code: Width (operand 3) must be in [1, 63] *** + %width_too_large_2:_(s64) = G_SBFX %s64, 1, 64 + + ; CHECK: *** Bad machine code: Width (operand 3) must be in [1, 27] *** + %width_too_large_s32:_(s32) = G_SBFX %s32, 5, 28 +... Index: llvm/test/MachineVerifier/test_g_ubfx.mir =================================================================== --- /dev/null +++ llvm/test/MachineVerifier/test_g_ubfx.mir @@ -0,0 +1,31 @@ +# RUN: not --crash llc -verify-machineinstrs -run-pass none -o /dev/null %s 2>&1 | FileCheck %s +# REQUIRES: aarch64-registered-target + +name: test +body: | + bb.0: + %v2s64:_(<2 x s64>) = G_IMPLICIT_DEF + %s64:_(s64) = G_IMPLICIT_DEF + %s32:_(s32) = G_IMPLICIT_DEF + + ; CHECK: *** Bad machine code: Bitfield extraction is not supported on vectors *** + %vector_ty:_(<2 x s64>) = G_UBFX %v2s64, 0, 3 + + ; CHECK: *** Bad machine code: LSB (operand 2) must be in [0, 63] *** + %lsb_too_small:_(s64) = G_UBFX %s64, -1, 2 + + ; CHECK: Bad machine code: LSB (operand 2) must be in [0, 63] *** + %lsb_too_large:_(s64) = G_UBFX %s64, 64, 2 + + ; CHECK: Bad machine code: Width (operand 3) must be in [1, 63] *** + %width_too_small:_(s64) = G_UBFX %s64, 1, 0 + + ; CHECK: Bad machine code: Width (operand 3) must be in [1, 64] *** + %width_too_large_1:_(s64) = G_UBFX %s64, 0, 65 + + ; CHECK: *** Bad machine code: Width (operand 3) must be in [1, 63] *** + %width_too_large_2:_(s64) = G_UBFX %s64, 1, 64 + + ; CHECK: *** Bad machine code: Width (operand 3) must be in [1, 27] *** + %width_too_large_s32:_(s32) = G_UBFX %s32, 5, 28 +...