Skip to content

[Hexagon] Handle Call Operand vxi1 in Hexagon without HVX Enabled #136546

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

pkarveti
Copy link
Contributor

@pkarveti pkarveti commented Apr 21, 2025

This commit updates the Hexagon backend to handle vxi1 call operands
Without HVX enabled. It ensures compatibility for vector types of sizes
4, 8, 16, 32, 64, and 128 x i1 when HVX is not enabled.

This commit updates the Hexagon backend to handle
vxi1 call operands Without HVX enabled. It ensures compatibility for
vector types of sizes 4, 8, 16, 32, 64, and 128 x i1
when HVX is not enabled.

Change-Id: Iddecb58b7e2884cc7b3b35569c0768e203979e95
@llvmbot
Copy link
Member

llvmbot commented Apr 21, 2025

@llvm/pr-subscribers-backend-hexagon

Author: None (pkarveti)

Changes

This commit updates the Hexagon backend to handle
vxi1 call operands Without HVX enabled. It ensures compatibility for vector types of sizes 4, 8, 16, 32, 64, and 128 x i1 when HVX is not enabled.


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

6 Files Affected:

  • (modified) llvm/lib/Target/Hexagon/HexagonISelLowering.cpp (+77)
  • (modified) llvm/lib/Target/Hexagon/HexagonISelLowering.h (+12)
  • (modified) llvm/test/CodeGen/Hexagon/calloperand-v128i1.ll (+21-9)
  • (modified) llvm/test/CodeGen/Hexagon/calloperand-v16i1.ll (+15-8)
  • (modified) llvm/test/CodeGen/Hexagon/calloperand-v32i1.ll (+6)
  • (modified) llvm/test/CodeGen/Hexagon/calloperand-v64i1.ll (+7)
diff --git a/llvm/lib/Target/Hexagon/HexagonISelLowering.cpp b/llvm/lib/Target/Hexagon/HexagonISelLowering.cpp
index 4c479ac41be12..dca8aaaf66422 100644
--- a/llvm/lib/Target/Hexagon/HexagonISelLowering.cpp
+++ b/llvm/lib/Target/Hexagon/HexagonISelLowering.cpp
@@ -155,7 +155,84 @@ static bool CC_SkipOdd(unsigned &ValNo, MVT &ValVT, MVT &LocVT,
 }
 
 #include "HexagonGenCallingConv.inc"
+unsigned HexagonTargetLowering::getVectorTypeBreakdownForCallingConv(
+    LLVMContext &Context, CallingConv::ID CC, EVT VT, EVT &IntermediateVT,
+    unsigned &NumIntermediates, MVT &RegisterVT) const {
+
+  RegisterVT = MVT::v8i8;
+  IntermediateVT = MVT::v8i1;
+  // Split vectors of type vXi1 into (X/8) vectors of type v8i1,
+  // where X is divisible by 8.
+  if (!Subtarget.useHVXOps()) {
+    switch (VT.getSimpleVT().SimpleTy) {
+    case MVT::v16i1:
+      NumIntermediates = 2;
+      return 2;
+    case MVT::v32i1:
+      NumIntermediates = 4;
+      return 4;
+    case MVT::v64i1:
+      NumIntermediates = 8;
+      return 8;
+    case MVT::v128i1:
+      NumIntermediates = 16;
+      return 16;
+    default:
+      break;
+    }
+  }
+  // Split v128i1 vectors into 2 v64i1 vectors in HVX 64-byte mode.
+  if (VT == MVT::v128i1 && Subtarget.useHVX64BOps()) {
+    RegisterVT = MVT::v64i8;
+    IntermediateVT = MVT::v64i1;
+    NumIntermediates = 2;
+    return 2;
+  }
+  return TargetLowering::getVectorTypeBreakdownForCallingConv(
+      Context, CC, VT, IntermediateVT, NumIntermediates, RegisterVT);
+}
+std::pair<MVT, unsigned>
+HexagonTargetLowering::handleMaskRegisterForCallingConv(
+    unsigned NumElts, CallingConv::ID CC, const HexagonSubtarget &Subtarget,
+    EVT VT) const {
+
+  unsigned NumIntermediates = 1;
+  ElementCount EC = VT.getVectorElementCount();
+  // For vectors of type vXi1, where X is divisible by 8,
+  // use Double registers when HVX is not enabled.
+  if (VT.getVectorNumElements() >= 16 && !Subtarget.useHVXOps() &&
+      isPowerOf2_32(EC.getKnownMinValue())) {
+    while (EC.getKnownMinValue() > 8) {
+      EC = EC.divideCoefficientBy(2);
+
+      NumIntermediates <<= 1;
+    }
+    return {MVT::v8i8, NumIntermediates};
+  }
+  // Split v128i1 vectors into 2 v64i1 vectors in HVX 64-byte mode.
+  if (VT == MVT::v128i1 && Subtarget.useHVX64BOps()) {
+    return {MVT::v64i8, 2};
+  }
+  return {MVT::INVALID_SIMPLE_VALUE_TYPE, 0};
+}
+
+MVT HexagonTargetLowering::getRegisterTypeForCallingConv(LLVMContext &Context,
+                                                         CallingConv::ID CC,
+                                                         EVT VT) const {
+  if (VT.isVector()) {
+    if (VT.getVectorElementType() == MVT::i1) {
+      unsigned NumElts = VT.getVectorNumElements();
 
+      MVT RegisterVT;
+      unsigned NumRegisters;
+      std::tie(RegisterVT, NumRegisters) =
+          handleMaskRegisterForCallingConv(NumElts, CC, Subtarget, VT);
+      if (RegisterVT != MVT::INVALID_SIMPLE_VALUE_TYPE)
+        return RegisterVT;
+    }
+  }
+  return TargetLowering::getRegisterTypeForCallingConv(Context, CC, VT);
+}
 
 SDValue
 HexagonTargetLowering::LowerINTRINSIC_WO_CHAIN(SDValue Op, SelectionDAG &DAG)
diff --git a/llvm/lib/Target/Hexagon/HexagonISelLowering.h b/llvm/lib/Target/Hexagon/HexagonISelLowering.h
index 4df88b3a8abd7..8270498b70061 100644
--- a/llvm/lib/Target/Hexagon/HexagonISelLowering.h
+++ b/llvm/lib/Target/Hexagon/HexagonISelLowering.h
@@ -183,6 +183,10 @@ class HexagonTargetLowering : public TargetLowering {
                           SelectionDAG &DAG) const override;
 
   const char *getTargetNodeName(unsigned Opcode) const override;
+  std::pair<MVT, unsigned>
+  handleMaskRegisterForCallingConv(unsigned NumElts, CallingConv::ID CC,
+                                   const HexagonSubtarget &Subtarget,
+                                   EVT VT) const;
 
   SDValue LowerBUILD_VECTOR(SDValue Op, SelectionDAG &DAG) const;
   SDValue LowerCONCAT_VECTORS(SDValue Op, SelectionDAG &DAG) const;
@@ -263,6 +267,14 @@ class HexagonTargetLowering : public TargetLowering {
   Register getRegisterByName(const char* RegName, LLT VT,
                              const MachineFunction &MF) const override;
 
+  unsigned getVectorTypeBreakdownForCallingConv(LLVMContext &Context,
+                                                CallingConv::ID CC, EVT VT,
+                                                EVT &IntermediateVT,
+                                                unsigned &NumIntermediates,
+                                                MVT &RegisterVT) const override;
+
+  MVT getRegisterTypeForCallingConv(LLVMContext &Context, CallingConv::ID CC,
+                                    EVT VT) const override;
   /// If a physical register, this returns the register that receives the
   /// exception address on entry to an EH pad.
   Register
diff --git a/llvm/test/CodeGen/Hexagon/calloperand-v128i1.ll b/llvm/test/CodeGen/Hexagon/calloperand-v128i1.ll
index ddac8c1cd8279..9d323b455449e 100644
--- a/llvm/test/CodeGen/Hexagon/calloperand-v128i1.ll
+++ b/llvm/test/CodeGen/Hexagon/calloperand-v128i1.ll
@@ -1,10 +1,20 @@
-;RUN: llc -mtriple=hexagon -mattr=+hvxv79,+hvx-length128b < %s -o - | FileCheck %s
+;RUN: llc -mtriple=hexagon  < %s -o - | FileCheck %s --check-prefix=CHECK
+;RUN: llc -mtriple=hexagon -mattr=+hvxv79,+hvx-length64b < %s -o - | FileCheck %s --check-prefixes=CHECK-64,CHECK-64-128
+;RUN: llc -mtriple=hexagon -mattr=+hvxv79,+hvx-length128b < %s -o - | FileCheck %s --check-prefixes=CHECK-128,CHECK-64-128
 
 ; CHECK-LABEL: compare_vectors
-; CHECK: [[REG1:(q[0-9]+)]] = vcmp.eq(v{{[0-9]+}}.b,v{{[0-9]+}}.b)
-; CHECK: [[REG2:(r[0-9]+)]] = #-1
-; CHECK: v0 = vand([[REG1]],[[REG2]])
-
+; CHECK: [[REG8:(r[0-9]+):[0-9]]] = CONST64(#72340172838076673)
+; CHECK: r{{[0-9]+}}:{{[0-9]+}} = and(r{{[0-9]+}}:{{[0-9]+}},[[REG8]])
+; CHECK: r{{[0-9]+}}:{{[0-9]+}} = and(r{{[0-9]+}}:{{[0-9]+}},[[REG8]])
+; CHECK: r{{[0-9]+}}:{{[0-9]+}} = and(r{{[0-9]+}}:{{[0-9]+}},[[REG8]])
+; CHECK-128: [[REG1:(q[0-9]+)]] = vcmp.eq(v{{[0-9]+}}.b,v{{[0-9]+}}.b)
+; CHECK-128: [[REG2:(r[0-9]+)]] = #-1
+; CHECK-128: v0 = vand([[REG1]],[[REG2]])
+; CHECK-64: [[REG5:(q[0-9]+)]] = vcmp.eq(v{{[0-9]+}}.b,v{{[0-9]+}}.b)
+; CHECK-64: [[REG6:(q[0-9]+)]] = vcmp.eq(v{{[0-9]+}}.b,v{{[0-9]+}}.b)
+; CHECK-64: [[REG7:(r[0-9]+)]] = #-1
+; CHECK-64: v0 = vand([[REG5]],[[REG7]])
+; CHECK-64: v1 = vand([[REG6]],[[REG7]])
 define void @compare_vectors(<128 x i8> %a, <128 x i8> %b) {
 entry:
   %result = icmp eq <128 x i8> %a, %b
@@ -13,11 +23,13 @@ entry:
 }
 
 ; CHECK-LABEL: f.1:
-; CHECK: [[REG3:(q[0-9]+)]] = vand(v0,r{{[0-9]+}})
-; CHECK: [[REG4:(v[0-9]+)]] = vand([[REG3]],r{{[0-9]+}})
-; CHECK: r{{[0-9]+}} = vextract([[REG4]],r{{[0-9]+}})
+; CHECK: [[REG9:(r[0-9]+)]] = and([[REG9]],##16843009)
+; CHECK: [[REG10:(r[0-9]+)]] = and([[REG10]],##16843009)
+; CHECK-64-128: [[REG3:(q[0-9]+)]] = vand(v0,r{{[0-9]+}})
+; CHECK-64-128: [[REG4:(v[0-9]+)]] = vand([[REG3]],r{{[0-9]+}})
+; CHECK-64-128: r{{[0-9]+}} = vextract([[REG4]],r{{[0-9]+}})
 
-define i32 @f.1(<128 x i1> %vec) {
+define i32 @f.1(<128 x i1> %vec){
   %element = extractelement <128 x i1> %vec, i32 6
   %is_true = icmp eq i1 %element, true
   br i1 %is_true, label %if_true, label %if_false
diff --git a/llvm/test/CodeGen/Hexagon/calloperand-v16i1.ll b/llvm/test/CodeGen/Hexagon/calloperand-v16i1.ll
index bbb2697246df1..6cf1a3fca70b7 100644
--- a/llvm/test/CodeGen/Hexagon/calloperand-v16i1.ll
+++ b/llvm/test/CodeGen/Hexagon/calloperand-v16i1.ll
@@ -1,10 +1,15 @@
-;RUN: llc -mtriple=hexagon -mattr=+hvxv79,+hvx-length64b < %s -o - | FileCheck %s --check-prefix=CHECK
-;RUN: llc -mtriple=hexagon -mattr=+hvxv79,+hvx-length128b < %s -o - | FileCheck %s --check-prefix=CHECK
+;RUN: llc -mtriple=hexagon  < %s -o - | FileCheck %s --check-prefix=CHECK
+;RUN: llc -mtriple=hexagon -mattr=+hvxv79,+hvx-length64b < %s -o - | FileCheck %s --check-prefix=CHECK-HVX
+;RUN: llc -mtriple=hexagon -mattr=+hvxv79,+hvx-length128b < %s -o - | FileCheck %s --check-prefix=CHECK-HVX
 
 ; CHECK-LABEL: compare_vectors
-; CHECK: [[REG1:(q[0-9]+)]] = vcmp.eq(v{{[0-9]+}}.w,v{{[0-9]+}}.w)
-; CHECK: [[REG2:(r[0-9]+)]] = #-1
-; CHECK: v0  = vand([[REG1]],[[REG2]])
+; CHECK: [[REG5:(r[0-9]+):[0-9]]] = CONST64(#72340172838076673)
+; CHECK: r{{[0-9]+}}:{{[0-9]+}} = and(r{{[0-9]+}}:{{[0-9]+}},[[REG5]])
+; CHECK: r{{[0-9]+}}:{{[0-9]+}} = and(r{{[0-9]+}}:{{[0-9]+}},[[REG5]])
+
+; CHECK-HVX: [[REG1:(q[0-9]+)]] = vcmp.eq(v{{[0-9]+}}.w,v{{[0-9]+}}.w)
+; CHECK-HVX: [[REG2:(r[0-9]+)]] = #-1
+; CHECK-HVX: v0  = vand([[REG1]],[[REG2]])
 
 define void @compare_vectors(<16 x i32> %a, <16 x i32> %b) {
 entry:
@@ -14,9 +19,11 @@ entry:
 }
 
 ; CHECK-LABEL: f.1:
-; CHECK: [[REG3:(q[0-9]+)]] = vand(v0,r{{[0-9]+}})
-; CHECK: [[REG4:(v[0-9]+)]] = vand([[REG3]],r{{[0-9]+}})
-; CHECK: r{{[0-9]+}} = vextract([[REG4]],r{{[0-9]+}})
+; CHECK: [[REG3:(r[0-9]+)]] = and([[REG3]],##16843009)
+; CHECK: [[REG4:(r[0-9]+)]] = and([[REG4]],##16843009)
+; CHECK-HVX: [[REG3:(q[0-9]+)]] = vand(v0,r{{[0-9]+}})
+; CHECK-HVX: [[REG4:(v[0-9]+)]] = vand([[REG3]],r{{[0-9]+}})
+; CHECK-HVX: r{{[0-9]+}} = vextract([[REG4]],r{{[0-9]+}})
 
 define i32 @f.1(<16 x i1> %vec) {
   %element = extractelement <16 x i1> %vec, i32 6
diff --git a/llvm/test/CodeGen/Hexagon/calloperand-v32i1.ll b/llvm/test/CodeGen/Hexagon/calloperand-v32i1.ll
index a73478728d910..c43ad70b94100 100644
--- a/llvm/test/CodeGen/Hexagon/calloperand-v32i1.ll
+++ b/llvm/test/CodeGen/Hexagon/calloperand-v32i1.ll
@@ -1,7 +1,11 @@
+; RUN: llc -mtriple=hexagon  < %s -o - | FileCheck %s --check-prefix=CHECK
 ; RUN: llc -mtriple=hexagon -mattr=+hvxv79,+hvx-length64b < %s -o - | FileCheck %s --check-prefix=CHECK-64
 ; RUN: llc -mtriple=hexagon -mattr=+hvxv79,+hvx-length128b < %s -o - | FileCheck %s --check-prefix=CHECK-128
 
 ; CHECK-LABEL: compare_vectors
+; CHECK: [[REG8:(r[0-9]+):[0-9]]] = CONST64(#72340172838076673)
+; CHECK: r{{[0-9]+}}:{{[0-9]+}} = and(r{{[0-9]+}}:{{[0-9]+}},[[REG8]])
+; CHECK: r{{[0-9]+}}:{{[0-9]+}} = and(r{{[0-9]+}}:{{[0-9]+}},[[REG8]])
 ; CHECK-64: [[REG1:(q[0-9]+)]] = vcmp.eq(v{{[0-9]+}}.h,v{{[0-9]+}}.h)
 ; CHECK-64: [[REG2:(r[0-9]+)]] = #-1
 ; CHECK-64: v0 = vand([[REG1]],[[REG2]])
@@ -21,6 +25,8 @@ entry:
 }
 
 ; CHECK-LABEL: f.1:
+; CHECK: [[REG9:(r[0-9]+)]] = and([[REG9]],##16843009)
+; CHECK: [[REG10:(r[0-9]+)]] = and([[REG10]],##16843009)
 ; CHECK-64: [[REG3:(q[0-9]+)]] = vand(v0,r{{[0-9]+}})
 ; CHECK-64: [[REG4:(v[0-9]+)]] = vand([[REG3]],r{{[0-9]+}})
 ; CHECK-64: r{{[0-9]+}} = vextract([[REG4]],r{{[0-9]+}})
diff --git a/llvm/test/CodeGen/Hexagon/calloperand-v64i1.ll b/llvm/test/CodeGen/Hexagon/calloperand-v64i1.ll
index 7cc562085a7e6..90a2da14f1971 100644
--- a/llvm/test/CodeGen/Hexagon/calloperand-v64i1.ll
+++ b/llvm/test/CodeGen/Hexagon/calloperand-v64i1.ll
@@ -1,7 +1,12 @@
+; RUN: llc -mtriple=hexagon  < %s -o - | FileCheck %s --check-prefix=CHECK
 ; RUN: llc -mtriple=hexagon -mattr=+hvxv79,+hvx-length64b < %s -o - | FileCheck %s --check-prefix=CHECK-64
 ; RUN: llc -mtriple=hexagon -mattr=+hvxv79,+hvx-length128b < %s -o - | FileCheck %s --check-prefix=CHECK-128
 
 ; CHECK-LABEL: compare_vectors
+; CHECK: [[REG8:(r[0-9]+):[0-9]]] = CONST64(#72340172838076673)
+; CHECK: r{{[0-9]+}}:{{[0-9]+}} = and(r{{[0-9]+}}:{{[0-9]+}},[[REG8]])
+; CHECK: r{{[0-9]+}}:{{[0-9]+}} = and(r{{[0-9]+}}:{{[0-9]+}},[[REG8]])
+; CHECK: r{{[0-9]+}}:{{[0-9]+}} = and(r{{[0-9]+}}:{{[0-9]+}},[[REG8]])
 ; CHECK-64: [[REG1:(q[0-9]+)]] = vcmp.eq(v{{[0-9]+}}.b,v{{[0-9]+}}.b)
 ; CHECK-64: [[REG2:(r[0-9]+)]] = #-1
 ; CHECK-64: v0 = vand([[REG1]],[[REG2]])
@@ -21,6 +26,8 @@ entry:
 }
 
 ; CHECK-LABEL: f.1:
+; CHECK: [[REG9:(r[0-9]+)]] = and([[REG9]],##16843009)
+; CHECK: [[REG10:(r[0-9]+)]] = and([[REG10]],##16843009)
 ; CHECK-64: [[REG3:(q[0-9]+)]] = vand(v0,r{{[0-9]+}})
 ; CHECK-64: [[REG4:(v[0-9]+)]] = vand([[REG3]],r{{[0-9]+}})
 ; CHECK-64: r{{[0-9]+}} = vextract([[REG4]],r{{[0-9]+}})

Comment on lines +203 to +209
if (VT.getVectorNumElements() >= 16 && !Subtarget.useHVXOps() &&
isPowerOf2_32(EC.getKnownMinValue())) {
while (EC.getKnownMinValue() > 8) {
EC = EC.divideCoefficientBy(2);

NumIntermediates <<= 1;
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we don't need the loop here. Simplify to:

std::pair<MVT, unsigned>
HexagonTargetLowering::handleMaskRegisterForCallingConv(
    const HexagonSubtarget &Subtarget, EVT VT) const {
  assert(VT.getVectorElementType() == MVT::i1)
  
  // For vectors of type vXi1, where X is power of 2 greater than 8,
  // use Double registers when HVX is not enabled.
  if (!Subtarget.useHVXOps() && VT.isPow2VectorType() && VT.getVectorNumElements() >= 16)
      return {MVT::v8i8, VT.getVectorNumElements() / 8};
  
  // Split v128i1 vectors into 2 v64i1 vectors in HVX 64-byte mode.
  if (VT == MVT::v128i1 && Subtarget.useHVX64BOps())
      return {MVT::v64i8, 2};
  
  return {MVT::INVALID_SIMPLE_VALUE_TYPE, 0};
}

}
std::pair<MVT, unsigned>
HexagonTargetLowering::handleMaskRegisterForCallingConv(
unsigned NumElts, CallingConv::ID CC, const HexagonSubtarget &Subtarget,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you can get rid of unsigned NumElts, CallingConv::ID CC. I don't see them being used within the function

Comment on lines +166 to +183
if (!Subtarget.useHVXOps()) {
switch (VT.getSimpleVT().SimpleTy) {
case MVT::v16i1:
NumIntermediates = 2;
return 2;
case MVT::v32i1:
NumIntermediates = 4;
return 4;
case MVT::v64i1:
NumIntermediates = 8;
return 8;
case MVT::v128i1:
NumIntermediates = 16;
return 16;
default:
break;
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can avoid the switch here and divide the element count by 8 here

return TargetLowering::getVectorTypeBreakdownForCallingConv(
Context, CC, VT, IntermediateVT, NumIntermediates, RegisterVT);
}
std::pair<MVT, unsigned>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Empty line before the start of the function

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Status: Needs Triage
Development

Successfully merging this pull request may close these issues.

4 participants