[llvm] [clang] riscv vector cc (PR #77560)

via llvm-commits llvm-commits at lists.llvm.org
Tue Jan 9 22:46:07 PST 2024


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-backend-risc-v

Author: Brandon Wu (4vtomat)

<details>
<summary>Changes</summary>

    [RISCV] RISCV vector calling convention (1/2)

    This is the vector calling convention based on
    https://github.com/riscv-non-isa/riscv-elf-psabi-doc,
    the idea is to split between "scalar" callee-saved registers
    and "vector" callee-saved registers. "scalar" ones remain the
    original strategy, however, "vector" ones are handled together
    with RVV objects.

    The stack layout would be:

      |--------------------------| <-- FP
      | callee-allocated save    |
      | area for register varargs|
      |--------------------------|
      | callee-saved registers   | <-- scalar callee-saved
      |        (scalar)          |
      |--------------------------|
      | RVV alignment padding    |
      |--------------------------|
      | callee-saved registers   | <-- vector callee-saved
      |        (vector)          |
      |--------------------------|
      | RVV objects              |
      |--------------------------|
      | padding before RVV       |
      |--------------------------|
      | scalar local variables   |
      |--------------------------| <-- BP
      | variable size objects    |
      |--------------------------| <-- SP

    Note: This patch doesn't contain "tuple" type, e.g. vint32m1x2.
          It will be handled in https://github.com/riscv-non-isa/riscv-elf-psabi-doc (2/2).

    [RISCV] Add CFI information for vector callee-saved registers

    Currently the CFI offset for RVV registers are not handled entirely,
    this patch add those information for either stack unwinding or
    debugger to work correctly on RVV callee-saved stack object.


---

Patch is 176.82 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/77560.diff


137 Files Affected:

- (modified) clang/include/clang/Basic/Attr.td (+5) 
- (modified) clang/include/clang/Basic/AttrDocs.td (+10) 
- (modified) clang/include/clang/Basic/Specifiers.h (+1) 
- (modified) clang/lib/AST/ItaniumMangle.cpp (+1) 
- (modified) clang/lib/AST/Type.cpp (+2) 
- (modified) clang/lib/AST/TypePrinter.cpp (+6) 
- (modified) clang/lib/Basic/Targets/RISCV.cpp (+11) 
- (modified) clang/lib/Basic/Targets/RISCV.h (+2) 
- (modified) clang/lib/CodeGen/CGCall.cpp (+4) 
- (modified) clang/lib/Sema/SemaDeclAttr.cpp (+7) 
- (modified) clang/lib/Sema/SemaType.cpp (+4-1) 
- (added) clang/test/CodeGen/RISCV/riscv-vector-callingconv-llvm-ir.c (+27) 
- (added) clang/test/CodeGen/RISCV/riscv-vector-callingconv.cpp (+19) 
- (modified) llvm/include/llvm/AsmParser/LLToken.h (+1) 
- (modified) llvm/include/llvm/IR/CallingConv.h (+3) 
- (modified) llvm/lib/AsmParser/LLLexer.cpp (+1) 
- (modified) llvm/lib/AsmParser/LLParser.cpp (+2) 
- (modified) llvm/lib/IR/AsmWriter.cpp (+1) 
- (modified) llvm/lib/Target/RISCV/RISCVCallingConv.td (+13) 
- (modified) llvm/lib/Target/RISCV/RISCVFrameLowering.cpp (+215-39) 
- (modified) llvm/lib/Target/RISCV/RISCVFrameLowering.h (+5) 
- (modified) llvm/lib/Target/RISCV/RISCVISelLowering.cpp (+1) 
- (modified) llvm/lib/Target/RISCV/RISCVRegisterInfo.cpp (+15) 
- (modified) llvm/test/CodeGen/RISCV/early-clobber-tied-def-subreg-liveness.ll (+1) 
- (modified) llvm/test/CodeGen/RISCV/intrinsic-cttz-elts-vscale.ll (+1) 
- (modified) llvm/test/CodeGen/RISCV/regalloc-last-chance-recoloring-failure.ll (+2) 
- (added) llvm/test/CodeGen/RISCV/rvv-cfi-info.ll (+119) 
- (modified) llvm/test/CodeGen/RISCV/rvv/abs-vp.ll (+1) 
- (modified) llvm/test/CodeGen/RISCV/rvv/access-fixed-objects-by-rvv.ll (+1) 
- (modified) llvm/test/CodeGen/RISCV/rvv/addi-scalable-offset.mir (+1) 
- (modified) llvm/test/CodeGen/RISCV/rvv/alloca-load-store-scalable-array.ll (+1) 
- (modified) llvm/test/CodeGen/RISCV/rvv/alloca-load-store-scalable-struct.ll (+1) 
- (modified) llvm/test/CodeGen/RISCV/rvv/bitreverse-sdnode.ll (+1) 
- (modified) llvm/test/CodeGen/RISCV/rvv/bitreverse-vp.ll (+7) 
- (modified) llvm/test/CodeGen/RISCV/rvv/bswap-sdnode.ll (+1) 
- (modified) llvm/test/CodeGen/RISCV/rvv/bswap-vp.ll (+7) 
- (added) llvm/test/CodeGen/RISCV/rvv/callee-saved-regs.ll (+95) 
- (modified) llvm/test/CodeGen/RISCV/rvv/calling-conv-fastcc.ll (+8) 
- (modified) llvm/test/CodeGen/RISCV/rvv/calling-conv.ll (+2) 
- (modified) llvm/test/CodeGen/RISCV/rvv/ceil-vp.ll (+1) 
- (modified) llvm/test/CodeGen/RISCV/rvv/ctlz-vp.ll (+1) 
- (modified) llvm/test/CodeGen/RISCV/rvv/ctpop-vp.ll (+3) 
- (modified) llvm/test/CodeGen/RISCV/rvv/cttz-vp.ll (+4) 
- (modified) llvm/test/CodeGen/RISCV/rvv/emergency-slot.mir (+1) 
- (modified) llvm/test/CodeGen/RISCV/rvv/extractelt-fp.ll (+4) 
- (modified) llvm/test/CodeGen/RISCV/rvv/extractelt-int-rv32.ll (+2) 
- (modified) llvm/test/CodeGen/RISCV/rvv/extractelt-int-rv64.ll (+2) 
- (modified) llvm/test/CodeGen/RISCV/rvv/fixed-vectors-bitreverse-vp.ll (+7) 
- (modified) llvm/test/CodeGen/RISCV/rvv/fixed-vectors-bswap-vp.ll (+7) 
- (modified) llvm/test/CodeGen/RISCV/rvv/fixed-vectors-ceil-vp.ll (+1) 
- (modified) llvm/test/CodeGen/RISCV/rvv/fixed-vectors-ctlz-vp.ll (+6) 
- (modified) llvm/test/CodeGen/RISCV/rvv/fixed-vectors-ctpop-vp.ll (+3) 
- (modified) llvm/test/CodeGen/RISCV/rvv/fixed-vectors-cttz-vp.ll (+6) 
- (modified) llvm/test/CodeGen/RISCV/rvv/fixed-vectors-floor-vp.ll (+1) 
- (modified) llvm/test/CodeGen/RISCV/rvv/fixed-vectors-fp-interleave.ll (+1) 
- (modified) llvm/test/CodeGen/RISCV/rvv/fixed-vectors-fshr-fshl-vp.ll (+126) 
- (modified) llvm/test/CodeGen/RISCV/rvv/fixed-vectors-insert-subvector.ll (+2) 
- (modified) llvm/test/CodeGen/RISCV/rvv/fixed-vectors-int-interleave.ll (+1) 
- (modified) llvm/test/CodeGen/RISCV/rvv/fixed-vectors-interleaved-access.ll (+2) 
- (modified) llvm/test/CodeGen/RISCV/rvv/fixed-vectors-llrint.ll (+8) 
- (modified) llvm/test/CodeGen/RISCV/rvv/fixed-vectors-nearbyint-vp.ll (+1) 
- (modified) llvm/test/CodeGen/RISCV/rvv/fixed-vectors-reduction-int.ll (+4) 
- (modified) llvm/test/CodeGen/RISCV/rvv/fixed-vectors-rint-vp.ll (+1) 
- (modified) llvm/test/CodeGen/RISCV/rvv/fixed-vectors-round-vp.ll (+1) 
- (modified) llvm/test/CodeGen/RISCV/rvv/fixed-vectors-roundeven-vp.ll (+1) 
- (modified) llvm/test/CodeGen/RISCV/rvv/fixed-vectors-roundtozero-vp.ll (+1) 
- (modified) llvm/test/CodeGen/RISCV/rvv/fixed-vectors-setcc-fp-vp.ll (+3) 
- (modified) llvm/test/CodeGen/RISCV/rvv/fixed-vectors-setcc-int-vp.ll (+3) 
- (modified) llvm/test/CodeGen/RISCV/rvv/fixed-vectors-trunc-vp.ll (+1) 
- (modified) llvm/test/CodeGen/RISCV/rvv/fixed-vectors-vcopysign-vp.ll (+1) 
- (modified) llvm/test/CodeGen/RISCV/rvv/fixed-vectors-vfma-vp.ll (+2) 
- (modified) llvm/test/CodeGen/RISCV/rvv/fixed-vectors-vfmax-vp.ll (+1) 
- (modified) llvm/test/CodeGen/RISCV/rvv/fixed-vectors-vfmin-vp.ll (+1) 
- (modified) llvm/test/CodeGen/RISCV/rvv/fixed-vectors-vfmuladd-vp.ll (+2) 
- (modified) llvm/test/CodeGen/RISCV/rvv/fixed-vectors-vfwadd.ll (+2) 
- (modified) llvm/test/CodeGen/RISCV/rvv/fixed-vectors-vfwmul.ll (+2) 
- (modified) llvm/test/CodeGen/RISCV/rvv/fixed-vectors-vfwsub.ll (+2) 
- (modified) llvm/test/CodeGen/RISCV/rvv/fixed-vectors-vpmerge.ll (+1) 
- (modified) llvm/test/CodeGen/RISCV/rvv/fixed-vectors-vpscatter.ll (+4) 
- (modified) llvm/test/CodeGen/RISCV/rvv/fixed-vectors-vscale-range.ll (+1) 
- (modified) llvm/test/CodeGen/RISCV/rvv/fixed-vectors-vselect-vp.ll (+4) 
- (modified) llvm/test/CodeGen/RISCV/rvv/fixed-vectors-vwmul.ll (+3) 
- (modified) llvm/test/CodeGen/RISCV/rvv/fixed-vectors-vwmulsu.ll (+3) 
- (modified) llvm/test/CodeGen/RISCV/rvv/fixed-vectors-vwmulu.ll (+3) 
- (modified) llvm/test/CodeGen/RISCV/rvv/floor-vp.ll (+1) 
- (modified) llvm/test/CodeGen/RISCV/rvv/fmaximum-sdnode.ll (+1) 
- (modified) llvm/test/CodeGen/RISCV/rvv/fminimum-sdnode.ll (+1) 
- (modified) llvm/test/CodeGen/RISCV/rvv/fpclamptosat_vec.ll (+24) 
- (modified) llvm/test/CodeGen/RISCV/rvv/fshr-fshl-vp.ll (+12) 
- (modified) llvm/test/CodeGen/RISCV/rvv/get-vlen-debugloc.mir (+1) 
- (modified) llvm/test/CodeGen/RISCV/rvv/large-rvv-stack-size.mir (+1) 
- (modified) llvm/test/CodeGen/RISCV/rvv/localvar.ll (+8) 
- (modified) llvm/test/CodeGen/RISCV/rvv/memory-args.ll (+1) 
- (modified) llvm/test/CodeGen/RISCV/rvv/mgather-sdnode.ll (+1) 
- (modified) llvm/test/CodeGen/RISCV/rvv/mscatter-sdnode.ll (+1) 
- (modified) llvm/test/CodeGen/RISCV/rvv/named-vector-shuffle-reverse.ll (+2) 
- (modified) llvm/test/CodeGen/RISCV/rvv/nearbyint-vp.ll (+3) 
- (modified) llvm/test/CodeGen/RISCV/rvv/no-reserved-frame.ll (+1) 
- (modified) llvm/test/CodeGen/RISCV/rvv/reg-alloc-reserve-bp.ll (+1) 
- (modified) llvm/test/CodeGen/RISCV/rvv/rint-vp.ll (+3) 
- (modified) llvm/test/CodeGen/RISCV/rvv/round-vp.ll (+3) 
- (modified) llvm/test/CodeGen/RISCV/rvv/roundeven-vp.ll (+3) 
- (modified) llvm/test/CodeGen/RISCV/rvv/roundtozero-vp.ll (+3) 
- (modified) llvm/test/CodeGen/RISCV/rvv/rvv-args-by-mem.ll (+1) 
- (modified) llvm/test/CodeGen/RISCV/rvv/setcc-fp-vp.ll (+3) 
- (modified) llvm/test/CodeGen/RISCV/rvv/setcc-int-vp.ll (+2) 
- (modified) llvm/test/CodeGen/RISCV/rvv/strided-vpstore.ll (+1) 
- (modified) llvm/test/CodeGen/RISCV/rvv/vcopysign-vp.ll (+2) 
- (modified) llvm/test/CodeGen/RISCV/rvv/vector-deinterleave-load.ll (+1) 
- (modified) llvm/test/CodeGen/RISCV/rvv/vector-deinterleave.ll (+2) 
- (modified) llvm/test/CodeGen/RISCV/rvv/vector-interleave-store.ll (+1) 
- (modified) llvm/test/CodeGen/RISCV/rvv/vector-interleave.ll (+4) 
- (modified) llvm/test/CodeGen/RISCV/rvv/vfadd-vp.ll (+2) 
- (modified) llvm/test/CodeGen/RISCV/rvv/vfdiv-vp.ll (+2) 
- (modified) llvm/test/CodeGen/RISCV/rvv/vfma-vp.ll (+2) 
- (modified) llvm/test/CodeGen/RISCV/rvv/vfmadd-constrained-sdnode.ll (+4) 
- (modified) llvm/test/CodeGen/RISCV/rvv/vfmadd-sdnode.ll (+3) 
- (modified) llvm/test/CodeGen/RISCV/rvv/vfmax-vp.ll (+2) 
- (modified) llvm/test/CodeGen/RISCV/rvv/vfmin-vp.ll (+2) 
- (modified) llvm/test/CodeGen/RISCV/rvv/vfmsub-constrained-sdnode.ll (+2) 
- (modified) llvm/test/CodeGen/RISCV/rvv/vfmul-vp.ll (+2) 
- (modified) llvm/test/CodeGen/RISCV/rvv/vfmuladd-vp.ll (+2) 
- (modified) llvm/test/CodeGen/RISCV/rvv/vfnmadd-constrained-sdnode.ll (+2) 
- (modified) llvm/test/CodeGen/RISCV/rvv/vfnmsub-constrained-sdnode.ll (+4) 
- (modified) llvm/test/CodeGen/RISCV/rvv/vfptrunc-vp.ll (+2) 
- (modified) llvm/test/CodeGen/RISCV/rvv/vfsub-vp.ll (+2) 
- (modified) llvm/test/CodeGen/RISCV/rvv/vfwmacc-vp.ll (+1) 
- (modified) llvm/test/CodeGen/RISCV/rvv/vfwnmacc-vp.ll (+1) 
- (modified) llvm/test/CodeGen/RISCV/rvv/vfwnmsac-vp.ll (+1) 
- (modified) llvm/test/CodeGen/RISCV/rvv/vp-reverse-int.ll (+1) 
- (modified) llvm/test/CodeGen/RISCV/rvv/vpmerge-sdnode.ll (+1) 
- (modified) llvm/test/CodeGen/RISCV/rvv/vpscatter-sdnode.ll (+3) 
- (modified) llvm/test/CodeGen/RISCV/rvv/vpstore.ll (+1) 
- (modified) llvm/test/CodeGen/RISCV/rvv/vselect-fp.ll (+1) 
- (modified) llvm/test/CodeGen/RISCV/rvv/vselect-vp.ll (+3) 
- (modified) llvm/test/CodeGen/RISCV/rvv/vtrunc-vp.ll (+1) 
- (modified) llvm/test/CodeGen/RISCV/rvv/zvlsseg-spill.mir (+1) 


``````````diff
diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td
index d5eabaad488965..ea9f157df98373 100644
--- a/clang/include/clang/Basic/Attr.td
+++ b/clang/include/clang/Basic/Attr.td
@@ -2891,6 +2891,11 @@ def M68kRTD: DeclOrTypeAttr {
   let Documentation = [M68kRTDDocs];
 }
 
+def RISCVVectorCC: DeclOrTypeAttr {
+ let Spellings = [Clang<"riscv_vector_cc">];
+ let Documentation = [RISCVVectorCCDocs];
+}
+
 def Target : InheritableAttr {
   let Spellings = [GCC<"target">];
   let Args = [StringArgument<"featuresStr">];
diff --git a/clang/include/clang/Basic/AttrDocs.td b/clang/include/clang/Basic/AttrDocs.td
index 5416a0cbdd0757..75359c65004a97 100644
--- a/clang/include/clang/Basic/AttrDocs.td
+++ b/clang/include/clang/Basic/AttrDocs.td
@@ -5400,6 +5400,16 @@ for clang builtin functions.
   }];
 }
 
+def RISCVVectorCCDocs : Documentation {
+ let Category = DocCatCallingConvs;
+ let Content = [{
+The ``riscv_vector_cc`` attribute can be applied to a function. It preserves 15
+registers namely, v1-v7 and v24-v31 as callee-saved. Callers thus don't need
+to save these registers before function calls, and callees only need to save
+them only if they use them.
+ }];
+}
+
 def PreferredNameDocs : Documentation {
   let Category = DocCatDecl;
   let Content = [{
diff --git a/clang/include/clang/Basic/Specifiers.h b/clang/include/clang/Basic/Specifiers.h
index 87f29c8ae10bd9..72a10e25c923e9 100644
--- a/clang/include/clang/Basic/Specifiers.h
+++ b/clang/include/clang/Basic/Specifiers.h
@@ -293,6 +293,7 @@ namespace clang {
     CC_AArch64SVEPCS, // __attribute__((aarch64_sve_pcs))
     CC_AMDGPUKernelCall, // __attribute__((amdgpu_kernel))
     CC_M68kRTD,       // __attribute__((m68k_rtd))
+    CC_RISCVVectorCall, // __attribute__((riscv_vector_cc))
   };
 
   /// Checks whether the given calling convention supports variadic
diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp
index b1678479888eb7..6af83a83c22fc7 100644
--- a/clang/lib/AST/ItaniumMangle.cpp
+++ b/clang/lib/AST/ItaniumMangle.cpp
@@ -3442,6 +3442,7 @@ StringRef CXXNameMangler::getCallingConvQualifierName(CallingConv CC) {
   case CC_PreserveMost:
   case CC_PreserveAll:
   case CC_M68kRTD:
+  case CC_RISCVVectorCall:
     // FIXME: we should be mangling all of the above.
     return "";
 
diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp
index a894d3289eb185..8895a1065d949b 100644
--- a/clang/lib/AST/Type.cpp
+++ b/clang/lib/AST/Type.cpp
@@ -3409,6 +3409,7 @@ StringRef FunctionType::getNameForCallConv(CallingConv CC) {
   case CC_PreserveMost: return "preserve_most";
   case CC_PreserveAll: return "preserve_all";
   case CC_M68kRTD: return "m68k_rtd";
+  case CC_RISCVVectorCall: return "riscv_vector_cc";
   }
 
   llvm_unreachable("Invalid calling convention.");
@@ -3896,6 +3897,7 @@ bool AttributedType::isCallingConv() const {
   case attr::PreserveMost:
   case attr::PreserveAll:
   case attr::M68kRTD:
+  case attr::RISCVVectorCC:
     return true;
   }
   llvm_unreachable("invalid attr kind");
diff --git a/clang/lib/AST/TypePrinter.cpp b/clang/lib/AST/TypePrinter.cpp
index f6941242927367..6138ea47941c7e 100644
--- a/clang/lib/AST/TypePrinter.cpp
+++ b/clang/lib/AST/TypePrinter.cpp
@@ -1047,6 +1047,9 @@ void TypePrinter::printFunctionAfter(const FunctionType::ExtInfo &Info,
     case CC_M68kRTD:
       OS << " __attribute__((m68k_rtd))";
       break;
+    case CC_RISCVVectorCall:
+      OS << "__attribute__((riscv_vector_cc))";
+      break;
     }
   }
 
@@ -1885,6 +1888,9 @@ void TypePrinter::printAttributedAfter(const AttributedType *T,
   case attr::M68kRTD:
     OS << "m68k_rtd";
     break;
+  case attr::RISCVVectorCC:
+    OS << "riscv_vector_cc";
+    break;
   case attr::NoDeref:
     OS << "noderef";
     break;
diff --git a/clang/lib/Basic/Targets/RISCV.cpp b/clang/lib/Basic/Targets/RISCV.cpp
index daaa8639ae8358..0a5cf09040eedf 100644
--- a/clang/lib/Basic/Targets/RISCV.cpp
+++ b/clang/lib/Basic/Targets/RISCV.cpp
@@ -480,3 +480,14 @@ ParsedTargetAttr RISCVTargetInfo::parseTargetAttr(StringRef Features) const {
   }
   return Ret;
 }
+
+TargetInfo::CallingConvCheckResult
+RISCVTargetInfo::checkCallingConvention(CallingConv CC) const {
+  switch (CC) {
+    default:
+      return CCCR_Warning;
+    case CC_C:
+    case CC_RISCVVectorCall:
+      return CCCR_OK;
+  }
+}
diff --git a/clang/lib/Basic/Targets/RISCV.h b/clang/lib/Basic/Targets/RISCV.h
index f98c88cd45f831..e65a6a1f127e8d 100644
--- a/clang/lib/Basic/Targets/RISCV.h
+++ b/clang/lib/Basic/Targets/RISCV.h
@@ -110,6 +110,8 @@ class RISCVTargetInfo : public TargetInfo {
 
   bool hasBFloat16Type() const override { return true; }
 
+  CallingConvCheckResult checkCallingConvention(CallingConv CC) const override;
+
   bool useFP16ConversionIntrinsics() const override {
     return false;
   }
diff --git a/clang/lib/CodeGen/CGCall.cpp b/clang/lib/CodeGen/CGCall.cpp
index 51a43b5f85b3cc..a099bb0efd73f6 100644
--- a/clang/lib/CodeGen/CGCall.cpp
+++ b/clang/lib/CodeGen/CGCall.cpp
@@ -73,6 +73,7 @@ unsigned CodeGenTypes::ClangCallConvToLLVMCallConv(CallingConv CC) {
   case CC_Swift: return llvm::CallingConv::Swift;
   case CC_SwiftAsync: return llvm::CallingConv::SwiftTail;
   case CC_M68kRTD: return llvm::CallingConv::M68k_RTD;
+  case CC_RISCVVectorCall: return llvm::CallingConv::RISCV_VectorCall;
   }
 }
 
@@ -256,6 +257,9 @@ static CallingConv getCallingConventionForDecl(const ObjCMethodDecl *D,
   if (D->hasAttr<M68kRTDAttr>())
     return CC_M68kRTD;
 
+  if (D->hasAttr<RISCVVectorCCAttr>())
+    return CC_RISCVVectorCall;
+
   return CC_C;
 }
 
diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp
index d059b406ef86e0..4322d2106737e8 100644
--- a/clang/lib/Sema/SemaDeclAttr.cpp
+++ b/clang/lib/Sema/SemaDeclAttr.cpp
@@ -5235,6 +5235,9 @@ static void handleCallConvAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
   case ParsedAttr::AT_M68kRTD:
     D->addAttr(::new (S.Context) M68kRTDAttr(S.Context, AL));
     return;
+  case ParsedAttr::AT_RISCVVectorCC:
+    D->addAttr(::new (S.Context) RISCVVectorCCAttr(S.Context, AL));
+    return;
   default:
     llvm_unreachable("unexpected attribute kind");
   }
@@ -5441,6 +5444,9 @@ bool Sema::CheckCallingConvAttr(const ParsedAttr &Attrs, CallingConv &CC,
   case ParsedAttr::AT_M68kRTD:
     CC = CC_M68kRTD;
     break;
+  case ParsedAttr::AT_RISCVVectorCC:
+    CC = CC_RISCVVectorCall;
+    break;
   default: llvm_unreachable("unexpected attribute kind");
   }
 
@@ -9373,6 +9379,7 @@ ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, const ParsedAttr &AL,
   case ParsedAttr::AT_AArch64SVEPcs:
   case ParsedAttr::AT_AMDGPUKernelCall:
   case ParsedAttr::AT_M68kRTD:
+  case ParsedAttr::AT_RISCVVectorCC:
     handleCallConvAttr(S, D, AL);
     break;
   case ParsedAttr::AT_Suppress:
diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp
index a376f20fa4f4e0..03695c907bdcd5 100644
--- a/clang/lib/Sema/SemaType.cpp
+++ b/clang/lib/Sema/SemaType.cpp
@@ -137,7 +137,8 @@ static void diagnoseBadTypeAttribute(Sema &S, const ParsedAttr &attr,
   case ParsedAttr::AT_IntelOclBicc:                                            \
   case ParsedAttr::AT_PreserveMost:                                            \
   case ParsedAttr::AT_PreserveAll:                                             \
-  case ParsedAttr::AT_M68kRTD
+  case ParsedAttr::AT_M68kRTD:                                                 \
+  case ParsedAttr::AT_RISCVVectorCC
 
 // Function type attributes.
 #define FUNCTION_TYPE_ATTRS_CASELIST                                           \
@@ -7852,6 +7853,8 @@ static Attr *getCCTypeAttr(ASTContext &Ctx, ParsedAttr &Attr) {
     return createSimpleAttr<PreserveAllAttr>(Ctx, Attr);
   case ParsedAttr::AT_M68kRTD:
     return createSimpleAttr<M68kRTDAttr>(Ctx, Attr);
+  case ParsedAttr::AT_RISCVVectorCC:
+    return createSimpleAttr<RISCVVectorCCAttr>(Ctx, Attr);
   }
   llvm_unreachable("unexpected attribute kind!");
 }
diff --git a/clang/test/CodeGen/RISCV/riscv-vector-callingconv-llvm-ir.c b/clang/test/CodeGen/RISCV/riscv-vector-callingconv-llvm-ir.c
new file mode 100644
index 00000000000000..a5b59306223dfb
--- /dev/null
+++ b/clang/test/CodeGen/RISCV/riscv-vector-callingconv-llvm-ir.c
@@ -0,0 +1,27 @@
+// REQUIRES: riscv-registered-target
+// RUN: %clang_cc1 -triple riscv64 -target-feature +v \
+// RUN:   -emit-llvm %s -o - | FileCheck -check-prefix=CHECK-LLVM %s
+
+#include <riscv_vector.h>
+
+// CHECK-LLVM: call riscv_vector_cc <vscale x 2 x i32> @bar
+vint32m1_t __attribute__((riscv_vector_cc)) bar(vint32m1_t input);
+vint32m1_t test_vector_cc_attr(vint32m1_t input, int32_t *base, size_t vl) {
+  vint32m1_t ret;
+  vint32m1_t val;
+  val = __riscv_vle32_v_i32m1(base, vl);
+  ret = bar(input);
+  __riscv_vse32_v_i32m1(base, val, vl);
+  return ret;
+}
+
+// CHECK-LLVM: call <vscale x 2 x i32> @baz
+vint32m1_t baz(vint32m1_t input);
+vint32m1_t test_no_vector_cc_attr(vint32m1_t input, int32_t *base, size_t vl) {
+  vint32m1_t ret;
+  vint32m1_t val;
+  val = __riscv_vle32_v_i32m1(base, vl);
+  ret = baz(input);
+  __riscv_vse32_v_i32m1(base, val, vl);
+  return ret;
+}
diff --git a/clang/test/CodeGen/RISCV/riscv-vector-callingconv.cpp b/clang/test/CodeGen/RISCV/riscv-vector-callingconv.cpp
new file mode 100644
index 00000000000000..22761146093fde
--- /dev/null
+++ b/clang/test/CodeGen/RISCV/riscv-vector-callingconv.cpp
@@ -0,0 +1,19 @@
+// REQUIRES: riscv-registered-target
+// RUN: %clang_cc1 %s -triple riscv64 -target-feature +v -verify
+
+__attribute__((riscv_vector_cc)) int var; // expected-warning {{'riscv_vector_cc' only applies to function types; type here is 'int'}}
+
+__attribute__((riscv_vector_cc)) void func();
+__attribute__((riscv_vector_cc(1))) void func_invalid(); // expected-error {{'riscv_vector_cc' attribute takes no arguments}}
+
+void test_no_attribute(int); // expected-note {{previous declaration is here}}
+void __attribute__((riscv_vector_cc)) test_no_attribute(int x) { } // expected-error {{function declared 'riscv_vector_cc' here was previously declared without calling convention}}
+
+class test_cc {
+  __attribute__((riscv_vector_cc)) void member_func();
+};
+
+void test_lambda() {
+  __attribute__((riscv_vector_cc)) auto lambda = []() { // expected-warning {{'riscv_vector_cc' only applies to function types; type here is 'auto'}}
+  };
+}
diff --git a/llvm/include/llvm/AsmParser/LLToken.h b/llvm/include/llvm/AsmParser/LLToken.h
index 147cf56c821aa1..f6c2e7339fb1b2 100644
--- a/llvm/include/llvm/AsmParser/LLToken.h
+++ b/llvm/include/llvm/AsmParser/LLToken.h
@@ -179,6 +179,7 @@ enum Kind {
   kw_tailcc,
   kw_m68k_rtdcc,
   kw_graalcc,
+  kw_riscv_vector_cc,
 
   // Attributes:
   kw_attributes,
diff --git a/llvm/include/llvm/IR/CallingConv.h b/llvm/include/llvm/IR/CallingConv.h
index 3a522c239ad59e..f20f2c4ccb781b 100644
--- a/llvm/include/llvm/IR/CallingConv.h
+++ b/llvm/include/llvm/IR/CallingConv.h
@@ -251,6 +251,9 @@ namespace CallingConv {
     /// Used by GraalVM. Two additional registers are reserved.
     GRAAL = 107,
 
+    /// Calling convention used for RISC-V V-extension.
+    RISCV_VectorCall = 108,
+
     /// The highest possible ID. Must be some 2^k - 1.
     MaxID = 1023
   };
diff --git a/llvm/lib/AsmParser/LLLexer.cpp b/llvm/lib/AsmParser/LLLexer.cpp
index c8da3efbb68aff..b4ddecf02d265b 100644
--- a/llvm/lib/AsmParser/LLLexer.cpp
+++ b/llvm/lib/AsmParser/LLLexer.cpp
@@ -636,6 +636,7 @@ lltok::Kind LLLexer::LexIdentifier() {
   KEYWORD(tailcc);
   KEYWORD(m68k_rtdcc);
   KEYWORD(graalcc);
+  KEYWORD(riscv_vector_cc);
 
   KEYWORD(cc);
   KEYWORD(c);
diff --git a/llvm/lib/AsmParser/LLParser.cpp b/llvm/lib/AsmParser/LLParser.cpp
index fb9e1ba875e1fa..bcdbb75abdd7c0 100644
--- a/llvm/lib/AsmParser/LLParser.cpp
+++ b/llvm/lib/AsmParser/LLParser.cpp
@@ -2005,6 +2005,7 @@ void LLParser::parseOptionalDLLStorageClass(unsigned &Res) {
 ///   ::= 'tailcc'
 ///   ::= 'm68k_rtdcc'
 ///   ::= 'graalcc'
+///   ::= 'riscv_vector_cc'
 ///   ::= 'cc' UINT
 ///
 bool LLParser::parseOptionalCallingConv(unsigned &CC) {
@@ -2074,6 +2075,7 @@ bool LLParser::parseOptionalCallingConv(unsigned &CC) {
   case lltok::kw_tailcc:         CC = CallingConv::Tail; break;
   case lltok::kw_m68k_rtdcc:     CC = CallingConv::M68k_RTD; break;
   case lltok::kw_graalcc:        CC = CallingConv::GRAAL; break;
+  case lltok::kw_riscv_vector_cc:CC = CallingConv::RISCV_VectorCall; break;
   case lltok::kw_cc: {
       Lex.Lex();
       return parseUInt32(CC);
diff --git a/llvm/lib/IR/AsmWriter.cpp b/llvm/lib/IR/AsmWriter.cpp
index 278cdfce411050..119092e5c61081 100644
--- a/llvm/lib/IR/AsmWriter.cpp
+++ b/llvm/lib/IR/AsmWriter.cpp
@@ -362,6 +362,7 @@ static void PrintCallingConv(unsigned cc, raw_ostream &Out) {
   case CallingConv::AMDGPU_KERNEL: Out << "amdgpu_kernel"; break;
   case CallingConv::AMDGPU_Gfx:    Out << "amdgpu_gfx"; break;
   case CallingConv::M68k_RTD:      Out << "m68k_rtdcc"; break;
+  case CallingConv::RISCV_VectorCall: Out << "riscv_vector_cc"; break;
   }
 }
 
diff --git a/llvm/lib/Target/RISCV/RISCVCallingConv.td b/llvm/lib/Target/RISCV/RISCVCallingConv.td
index 3dd0b372382865..25e54044aa6d61 100644
--- a/llvm/lib/Target/RISCV/RISCVCallingConv.td
+++ b/llvm/lib/Target/RISCV/RISCVCallingConv.td
@@ -24,6 +24,19 @@ def CSR_ILP32D_LP64D
     : CalleeSavedRegs<(add CSR_ILP32_LP64,
                        F8_D, F9_D, (sequence "F%u_D", 18, 27))>;
 
+defvar CSR_V = (add (sequence "V%u", 1, 7), (sequence "V%u", 24, 31),
+                     V2M2, V4M2, V6M2, V24M2, V26M2, V28M2, V30M2,
+                     V4M4, V24M4, V28M4, V24M8);
+
+def CSR_ILP32_LP64_V
+    : CalleeSavedRegs<(add CSR_ILP32_LP64, CSR_V)>;
+
+def CSR_ILP32F_LP64F_V
+    : CalleeSavedRegs<(add CSR_ILP32F_LP64F, CSR_V)>;
+
+def CSR_ILP32D_LP64D_V
+    : CalleeSavedRegs<(add CSR_ILP32D_LP64D, CSR_V)>;
+
 // Needed for implementation of RISCVRegisterInfo::getNoPreservedMask()
 def CSR_NoRegs : CalleeSavedRegs<(add)>;
 
diff --git a/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp b/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp
index 8dfea6d3862057..ae51dbdb92ad3e 100644
--- a/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp
+++ b/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp
@@ -365,6 +365,21 @@ getUnmanagedCSI(const MachineFunction &MF,
   return NonLibcallCSI;
 }
 
+static SmallVector<CalleeSavedInfo, 8>
+getRVVCalleeSavedInfo(const MachineFunction &MF,
+                      const std::vector<CalleeSavedInfo> &CSI) {
+  const MachineFrameInfo &MFI = MF.getFrameInfo();
+  SmallVector<CalleeSavedInfo, 8> RVVCSI;
+
+  for (auto &CS : CSI) {
+    int FI = CS.getFrameIdx();
+    if (FI >= 0 && MFI.getStackID(FI) == TargetStackID::ScalableVector)
+      RVVCSI.push_back(CS);
+  }
+
+  return RVVCSI;
+}
+
 void RISCVFrameLowering::adjustStackForRVV(MachineFunction &MF,
                                            MachineBasicBlock &MBB,
                                            MachineBasicBlock::iterator MBBI,
@@ -397,6 +412,32 @@ void RISCVFrameLowering::adjustStackForRVV(MachineFunction &MF,
                Flag, getStackAlign());
 }
 
+static void appendScalableVectorExpression(SmallVectorImpl<char> &Expr,
+                                           int FixedOffset, int ScalableOffset,
+                                           unsigned DwarfVlenb,
+                                           llvm::raw_string_ostream &Comment) {
+  uint8_t buffer[16];
+  if (FixedOffset) {
+    Expr.push_back(dwarf::DW_OP_consts);
+    Expr.append(buffer, buffer + encodeSLEB128(FixedOffset, buffer));
+    Expr.push_back((uint8_t)dwarf::DW_OP_plus);
+    Comment << (FixedOffset < 0 ? " - " : " + ") << std::abs(FixedOffset);
+  }
+
+  Expr.push_back((uint8_t)dwarf::DW_OP_consts);
+  Expr.append(buffer, buffer + encodeSLEB128(ScalableOffset, buffer));
+
+  Expr.push_back((uint8_t)dwarf::DW_OP_bregx);
+  Expr.append(buffer, buffer + encodeULEB128(DwarfVlenb, buffer));
+  Expr.push_back(0);
+
+  Expr.push_back((uint8_t)dwarf::DW_OP_mul);
+  Expr.push_back((uint8_t)dwarf::DW_OP_plus);
+
+  Comment << (ScalableOffset < 0 ? " - " : " + ") << std::abs(ScalableOffset)
+          << " * vlenb";
+}
+
 static MCCFIInstruction createDefCFAExpression(const TargetRegisterInfo &TRI,
                                                Register Reg,
                                                uint64_t FixedOffset,
@@ -414,29 +455,40 @@ static MCCFIInstruction createDefCFAExpression(const TargetRegisterInfo &TRI,
   else
     Comment << printReg(Reg, &TRI);
 
-  uint8_t buffer[16];
-  if (FixedOffset) {
-    Expr.push_back(dwarf::DW_OP_consts);
-    Expr.append(buffer, buffer + encodeSLEB128(FixedOffset, buffer));
-    Expr.push_back((uint8_t)dwarf::DW_OP_plus);
-    Comment << " + " << FixedOffset;
-  }
+  appendScalableVectorExpression(
+      Expr, FixedOffset, ScalableOffset,
+      TRI.getDwarfRegNum(RISCV::VLENB, true), Comment);
 
-  Expr.push_back((uint8_t)dwarf::DW_OP_consts);
-  Expr.append(buffer, buffer + encodeSLEB128(ScalableOffset, buffer));
+  SmallString<64> DefCfaExpr;
+  uint8_t buffer[16];
+  DefCfaExpr.push_back(dwarf::DW_CFA_def_cfa_expression);
+  DefCfaExpr.append(buffer, buffer + encodeULEB128(Expr.size(), buffer));
+  DefCfaExpr.append(Expr.str());
 
-  unsigned DwarfVlenb = TRI.getDwarfRegNum(RISCV::VLENB, true);
-  Expr.push_back((uint8_t)dwarf::DW_OP_bregx);
-  Expr.append(buffer, buffer + encodeULEB128(DwarfVlenb, buffer));
-  Expr.push_back(0);
+  return MCCFIInstruction::createEscape(nullptr, DefCfaExpr.str(), SMLoc(),
+                                        Comment.str());
+}
 
-  Expr.push_back((uint8_t)dwarf::DW_OP_mul);
-  Expr.push_back((uint8_t)dwarf::DW_OP_plus);
+static MCCFIInstruction createDefCFAOffset(const TargetRegisterInfo &TRI,
+                                           Register Reg,
+                                           uint64_t FixedOffset,
+                                           uint64_t ScalableOffset) {
+  assert(ScalableOffset != 0 && "Did not need to adjust CFA for RVV");
+  SmallString<64> Expr;
+  std::string CommentBuffer;
+  llvm::raw_string_ostream Comment(CommentBuffer);
+  Comment << printReg(Reg, &TRI) << "  @ cfa";
 
-  Comment << " + " << ScalableOffset << " * vlenb";
+  // Build up the expression (FixedOffset + ScalableOffset * VLENB).
+  appendScalableVectorExpression(
+      Expr, FixedOffset, ScalableOffset,
+      TRI.getDwarfRegNum(RISCV::VLENB, true), Comment);
 
   SmallString<64> DefCfaExpr;
-  DefCfaExpr.push_back(dwarf::DW_CFA_def_cfa_expression);
+  uint8_t buffer[16];
+  unsigned DwarfReg = TRI.getDwarfRegNum(Reg, true);
+  DefCfaExpr.push_back(dwarf::DW_CFA_expression);
+  DefCfaExpr.append(buffer, buffer + encodeULEB128(DwarfReg, buffer));
   DefCfaExpr.append(buffer, buffer + encodeULEB128(Expr.size(), buffer));
   DefCfaExpr.append(Expr.str());
 
@@ -563,6 +615,10 @@ void RISCVFrameLowering::emitPrologue(MachineFunction &MF,
   // directives.
   for (const auto &Entry : CSI) {
     int FrameIdx = Entry.getFrameIdx();
+    if (FrameIdx >=0 &&
+        MFI.getStackID(FrameIdx) == TargetStackID::ScalableVector)
+      continue;
+
     int64_t Offset;
     // Offsets for objects with fixed locations (IE: those saved by libcall) are
     // simply calculated from the frame index.
@@ -638,6 +694,9 @@ void RISCVFrameLowering::emitPrologue(MachineFunction &MF,
           .addCFIIndex(CFIIndex)
           .setMIFlag(MachineInstr::FrameSetup);
     }
+
+    std::advance(MBBI, getRVVCalleeSavedInfo(MF, CSI).size());
+    emitCalleeSavedRVVPrologCFI(MBB, MBBI, hasFP(MF));
   }
 
   if (hasFP(MF)) {
@@ -712,7 +771,7 @@ void RISCVFrameLowering::emitEpilogue(MachineFunction &MF,
 
   const auto &CSI = getUnmanagedCSI(MF, MFI.getCalleeSavedInfo());
 
-  // Skip to before the restores of callee-saved registers
+  // Skip to before the restores of scalar callee-saved registers
   // FIXME: assumes exactly one instruction is used to restore each
   // callee-saved register.
   auto LastFrameDestroy = MBBI;
@@ -724,6 +783,9 @@ void RISCVFrameLowering::emitEpilogue(MachineFunction &MF,
   uint64_t FPOffset = RealStackSize - RVFI->getVarArgsSaveSize();
   uint64_t RVVStackSize = RVFI->getRVVStackSize();
 
+  if (RVVStackSize)
+    emitCalleeSavedRVVEpilogCFI(MBB, LastFrameDestroy);
+
   // Restore the stack pointer using the value of the frame pointer. Only
   // necessary if the stack pointer was modified, me...
[truncated]

``````````

</details>


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


More information about the llvm-commits mailing list