[llvm] intrinsic to generate a bfi instruction (PR #79672)

via llvm-commits llvm-commits at lists.llvm.org
Fri Jan 26 18:44:12 PST 2024


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-llvm-ir

Author: Rama Malladi (RamaMalladiAWS)

<details>
<summary>Changes</summary>

BFI: Bit Field Insert copies any number of low order bits from a
register into the same number of adjacent bits at any position
in the destination register.

This PR generates the BFI instruction by implementing an intrinsic
function that can be invoked from the LLVM-IR.


---
Full diff: https://github.com/llvm/llvm-project/pull/79672.diff


4 Files Affected:

- (modified) llvm/include/llvm/IR/IntrinsicsAArch64.td (+3) 
- (modified) llvm/lib/Target/AArch64/AArch64ISelDAGToDAG.cpp (+13) 
- (modified) llvm/lib/Target/AArch64/AArch64InstrInfo.td (+8) 
- (added) llvm/test/CodeGen/AArch64/bfi-64-intrinsic.ll (+25) 


``````````diff
diff --git a/llvm/include/llvm/IR/IntrinsicsAArch64.td b/llvm/include/llvm/IR/IntrinsicsAArch64.td
index 921e5b95ae03e8..9eb5154c95138f 100644
--- a/llvm/include/llvm/IR/IntrinsicsAArch64.td
+++ b/llvm/include/llvm/IR/IntrinsicsAArch64.td
@@ -855,6 +855,9 @@ def int_aarch64_crc32x  : DefaultAttrsIntrinsic<[llvm_i32_ty], [llvm_i32_ty, llv
     [IntrNoMem]>;
 def int_aarch64_crc32cx : DefaultAttrsIntrinsic<[llvm_i32_ty], [llvm_i32_ty, llvm_i64_ty],
     [IntrNoMem]>;
+def int_aarch64_bfi : DefaultAttrsIntrinsic<
+    [llvm_anyint_ty], [llvm_anyint_ty, llvm_anyint_ty, llvm_anyint_ty, llvm_anyint_ty],
+    [IntrNoMem, ImmArg<ArgIndex<2>>, ImmArg<ArgIndex<3>>]>;
 }
 
 //===----------------------------------------------------------------------===//
diff --git a/llvm/lib/Target/AArch64/AArch64ISelDAGToDAG.cpp b/llvm/lib/Target/AArch64/AArch64ISelDAGToDAG.cpp
index 163ed520a8a677..1fe3f95d54d131 100644
--- a/llvm/lib/Target/AArch64/AArch64ISelDAGToDAG.cpp
+++ b/llvm/lib/Target/AArch64/AArch64ISelDAGToDAG.cpp
@@ -5230,6 +5230,19 @@ void AArch64DAGToDAGISel::Select(SDNode *Node) {
     switch (IntNo) {
     default:
       break;
+    case Intrinsic::aarch64_bfi: {
+      SDLoc DL(Node);
+      auto lsb = cast<ConstantSDNode>(Node->getOperand(3))->getZExtValue();
+      auto width = cast<ConstantSDNode>(Node->getOperand(4))->getZExtValue();
+      auto ImmR = (VT.getSizeInBits() - lsb) % VT.getSizeInBits();
+      auto ImmS = width - 1;
+      SDValue Ops[] = {Node->getOperand(1), Node->getOperand(2),
+                       CurDAG->getConstant(ImmR, DL, VT),
+                       CurDAG->getConstant(ImmS, DL, VT)};
+      unsigned Opc = (VT == MVT::i32) ? AArch64::BFMWri : AArch64::BFMXri;
+      CurDAG->SelectNodeTo(Node, Opc, VT, Ops);
+      return;
+    }
     case Intrinsic::aarch64_tagp:
       SelectTagP(Node);
       return;
diff --git a/llvm/lib/Target/AArch64/AArch64InstrInfo.td b/llvm/lib/Target/AArch64/AArch64InstrInfo.td
index 03baa7497615e3..afa911abad7982 100644
--- a/llvm/lib/Target/AArch64/AArch64InstrInfo.td
+++ b/llvm/lib/Target/AArch64/AArch64InstrInfo.td
@@ -2558,6 +2558,14 @@ def : Pat<(rotr GPR32:$Rn, (i64 imm0_31:$imm)),
 def : Pat<(rotr GPR64:$Rn, (i64 imm0_63:$imm)),
           (EXTRXrri GPR64:$Rn, GPR64:$Rn, imm0_63:$imm)>;
 
+def SDT_AArch64BFI_32bit : SDTypeProfile<1, 2, [SDTCisVT<0, i32>, SDTCisVT<1, i32>,
+                                                    SDTCisVT<2, i32>]>;
+def SDT_AArch64BFI_64bit : SDTypeProfile<1, 2, [SDTCisVT<0, i64>, SDTCisVT<1, i64>,
+                                                    SDTCisVT<2, i64>]>;
+
+def aarch64_bfiw  : SDNode<"AArch64::BFMWri",  SDT_AArch64BFI_32bit>;
+def aarch64_bfix  : SDNode<"AArch64::BFMXri",  SDT_AArch64BFI_64bit>;
+
 //===----------------------------------------------------------------------===//
 // Other bitfield immediate instructions.
 //===----------------------------------------------------------------------===//
diff --git a/llvm/test/CodeGen/AArch64/bfi-64-intrinsic.ll b/llvm/test/CodeGen/AArch64/bfi-64-intrinsic.ll
new file mode 100644
index 00000000000000..11ecde6b6fab20
--- /dev/null
+++ b/llvm/test/CodeGen/AArch64/bfi-64-intrinsic.ll
@@ -0,0 +1,25 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
+; RUN: llc -mtriple=aarch64-none-linux-gnu %s -o - 2>&1 | FileCheck %s --check-prefixes=CHECK,CHECK-GI
+
+define i32 @f32(i32 %A, i32 %B) nounwind {
+; CHECK-LABEL: f32:
+; CHECK-GI:      // %bb.0:
+; CHECK-GI-NEXT: bfi w0, w1, #4, #2
+; CHECK-GI-NEXT: ret
+entry:
+  %tmp32 = call i32 @llvm.aarch64.bfi.i32(i32 %A, i32 %B, i32 4, i32 2)
+  ret i32 %tmp32
+}
+
+define i64 @f64(i64 %A, i64 %B) nounwind {
+; CHECK-LABEL: f64:
+; CHECK-GI:      // %bb.0:
+; CHECK-GI-NEXT: bfi x0, x1, #23, #8
+; CHECK-GI-NEXT: ret
+entry:
+  %tmp64 = call i64 @llvm.aarch64.bfi.i64(i64 %A, i64 %B, i64 23, i64 8)
+  ret i64 %tmp64
+}
+
+declare i32 @llvm.aarch64.bfi.i32(i32, i32, i32, i32)
+declare i64 @llvm.aarch64.bfi.i64(i64, i64, i64, i64)

``````````

</details>


https://github.com/llvm/llvm-project/pull/79672


More information about the llvm-commits mailing list