Skip to content

Conversation

@banach-space
Copy link
Contributor

This patch adds lowering support for integer svlen builtins.
Floating-point variants are omitted for now and will be added once FP
type helpers (e.g., getFP32Ty()) become available.

Because svlen builtins take scalable vector types (e.g., svuint64_t),
this change also extends cir::VectorType to represent scalable
vectors. Since cir::VectorType is ultimately converted to MLIR’s
builtin VectorType during lowering to LLVM IR, the implementation
follows the same approach: scalability is modelled using an additional
boolean member (isScalable, defaulting to false).

Further work will be needed to properly support scalable vectors within
CIR:

  • cir::VectorType::getTypeSizeInBits currently returns the
    compile-time base vector size. Its meaning and usefulness for scalable
    vectors are unclear and may need re-design.
  • The assembly format for cir::VectorType will require a custom parser
    and printer to encode scalability (and agreement on the concrete
    syntax). This is not required for this patch.

References:

This patch adds lowering support for integer `svlen` builtins.
Floating-point variants are omitted for now and will be added once FP
type helpers (e.g., `getFP32Ty()`) become available.

Because svlen builtins take scalable vector types (e.g., `svuint64_t`),
this change also extends `cir::VectorType` to represent scalable
vectors. Since `cir::VectorType` is ultimately converted to MLIR’s
builtin `VectorType` during lowering to LLVM IR, the implementation
follows the same approach: scalability is modelled using an additional
boolean member (`isScalable`, defaulting to `false`).

Further work will be needed to properly support scalable vectors within
CIR:
* `cir::VectorType::getTypeSizeInBits` currently returns the
  compile-time base vector size. Its meaning and usefulness for scalable
  vectors are unclear and may need re-design.
* The assembly format for `cir::VectorType` will require a custom parser
  and printer to encode scalability (and agreement on the concrete
  syntax). This is not required for this patch.

References:
* https://arm-software.github.io/acle/main/acle.html#markdown-toc-sve-vector-types
* https://developer.arm.com/documentation/100891/0609/coding-considerations/using-sve-intrinsics-directly-in-your-c-code
@llvmbot llvmbot added clang Clang issues not falling into any other category ClangIR Anything related to the ClangIR project labels Dec 15, 2025
@llvmbot
Copy link
Member

llvmbot commented Dec 15, 2025

@llvm/pr-subscribers-clangir

@llvm/pr-subscribers-clang

Author: Andrzej Warzyński (banach-space)

Changes

This patch adds lowering support for integer svlen builtins.
Floating-point variants are omitted for now and will be added once FP
type helpers (e.g., getFP32Ty()) become available.

Because svlen builtins take scalable vector types (e.g., svuint64_t),
this change also extends cir::VectorType to represent scalable
vectors. Since cir::VectorType is ultimately converted to MLIR’s
builtin VectorType during lowering to LLVM IR, the implementation
follows the same approach: scalability is modelled using an additional
boolean member (isScalable, defaulting to false).

Further work will be needed to properly support scalable vectors within
CIR:

  • cir::VectorType::getTypeSizeInBits currently returns the
    compile-time base vector size. Its meaning and usefulness for scalable
    vectors are unclear and may need re-design.
  • The assembly format for cir::VectorType will require a custom parser
    and printer to encode scalability (and agreement on the concrete
    syntax). This is not required for this patch.

References:


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

8 Files Affected:

  • (modified) clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h (+1-2)
  • (modified) clang/include/clang/CIR/Dialect/IR/CIRTypes.td (+9-5)
  • (modified) clang/lib/CIR/CodeGen/CIRGenBuilder.h (+2-2)
  • (modified) clang/lib/CIR/CodeGen/CIRGenBuiltinAArch64.cpp (+38-8)
  • (modified) clang/lib/CIR/CodeGen/CIRGenTypes.cpp (+48)
  • (modified) clang/lib/CIR/Dialect/IR/CIRTypes.cpp (+1-1)
  • (modified) clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp (+1-1)
  • (added) clang/test/CIR/CodeGenBuiltins/AArch64/acle_sve_len.c (+143)
diff --git a/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h b/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h
index b4b02e24f85cc..8ca07ca3f17b8 100644
--- a/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h
+++ b/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h
@@ -596,8 +596,7 @@ class CIRBaseBuilderTy : public mlir::OpBuilder {
     VectorType vecCast = mlir::cast<VectorType>(lhs.getType());
     IntType integralTy =
         getSIntNTy(getCIRIntOrFloatBitWidth(vecCast.getElementType()));
-    VectorType integralVecTy =
-        VectorType::get(context, integralTy, vecCast.getSize());
+    VectorType integralVecTy = VectorType::get(integralTy, vecCast.getSize());
     return cir::VecCmpOp::create(*this, loc, integralVecTy, kind, lhs, rhs);
   }
 
diff --git a/clang/include/clang/CIR/Dialect/IR/CIRTypes.td b/clang/include/clang/CIR/Dialect/IR/CIRTypes.td
index 59b97f0c6d39a..3ca56be4e4a10 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIRTypes.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIRTypes.td
@@ -422,8 +422,9 @@ def CIR_VectorType : CIR_Type<"Vector", "vector", [
 ]> {
   let summary = "CIR vector type";
   let description = [{
-    The `!cir.vector` type represents a fixed-size, one-dimensional vector.
-    It takes two parameters: the element type and the number of elements.
+    The `!cir.vector` type represents a one-dimensional vector.
+    It takes three parameters: the element type, the number of elements and the
+    scalability flag (optional, defaults to `false`).
 
     Syntax:
 
@@ -445,7 +446,8 @@ def CIR_VectorType : CIR_Type<"Vector", "vector", [
 
   let parameters = (ins
     CIR_VectorElementType:$elementType,
-    "uint64_t":$size
+    "uint64_t":$size,
+    OptionalParameter<"bool">:$isScalable
   );
 
   let assemblyFormat = [{
@@ -454,9 +456,10 @@ def CIR_VectorType : CIR_Type<"Vector", "vector", [
 
   let builders = [
     TypeBuilderWithInferredContext<(ins
-      "mlir::Type":$elementType, "uint64_t":$size
+      "mlir::Type":$elementType, "uint64_t":$size, CArg<"bool",
+      "false">:$isScalable
     ), [{
-        return $_get(elementType.getContext(), elementType, size);
+        return $_get(elementType.getContext(), elementType, size, isScalable);
     }]>,
   ];
 
@@ -467,6 +470,7 @@ def CIR_VectorType : CIR_Type<"Vector", "vector", [
   }];
 
   let genVerifyDecl = 1;
+  let skipDefaultBuilders = 1;
 }
 
 //===----------------------------------------------------------------------===//
diff --git a/clang/lib/CIR/CodeGen/CIRGenBuilder.h b/clang/lib/CIR/CodeGen/CIRGenBuilder.h
index 5b10bddd054ea..2a15b1f7703be 100644
--- a/clang/lib/CIR/CodeGen/CIRGenBuilder.h
+++ b/clang/lib/CIR/CodeGen/CIRGenBuilder.h
@@ -628,8 +628,8 @@ class CIRGenBuilderTy : public cir::CIRBaseBuilderTy {
   createVecShuffle(mlir::Location loc, mlir::Value vec1, mlir::Value vec2,
                    llvm::ArrayRef<mlir::Attribute> maskAttrs) {
     auto vecType = mlir::cast<cir::VectorType>(vec1.getType());
-    auto resultTy = cir::VectorType::get(getContext(), vecType.getElementType(),
-                                         maskAttrs.size());
+    auto resultTy =
+        cir::VectorType::get(vecType.getElementType(), maskAttrs.size());
     return cir::VecShuffleOp::create(*this, loc, resultTy, vec1, vec2,
                                      getArrayAttr(maskAttrs));
   }
diff --git a/clang/lib/CIR/CodeGen/CIRGenBuiltinAArch64.cpp b/clang/lib/CIR/CodeGen/CIRGenBuiltinAArch64.cpp
index 696180458a2f6..7a9661b727dc7 100644
--- a/clang/lib/CIR/CodeGen/CIRGenBuiltinAArch64.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenBuiltinAArch64.cpp
@@ -11,6 +11,7 @@
 //
 //===----------------------------------------------------------------------===//
 
+#include "CIRGenBuilder.h"
 #include "CIRGenFunction.h"
 #include "clang/CIR/MissingFeatures.h"
 
@@ -30,6 +31,17 @@ using namespace clang;
 using namespace clang::CIRGen;
 using namespace llvm;
 
+template <typename... Operands>
+static mlir::Value emitIntrinsicCallOp(CIRGenBuilderTy &builder,
+                                       mlir::Location loc, const StringRef str,
+                                       const mlir::Type &resTy,
+                                       Operands &&...op) {
+  return cir::LLVMIntrinsicCallOp::create(builder, loc,
+                                          builder.getStringAttr(str), resTy,
+                                          std::forward<Operands>(op)...)
+      .getResult();
+}
+
 std::optional<mlir::Value>
 CIRGenFunction::emitAArch64SVEBuiltinExpr(unsigned builtinID,
                                           const CallExpr *expr) {
@@ -41,6 +53,16 @@ CIRGenFunction::emitAArch64SVEBuiltinExpr(unsigned builtinID,
     return mlir::Value{};
   }
 
+  mlir::Location loc = getLoc(expr->getExprLoc());
+  // Generate vscale * scalingFactor
+  auto vscaleTimesFactor = [&](int32_t scalingFactor) {
+    StringRef intrinsicName = "vscale.i64";
+    auto vscale = emitIntrinsicCallOp(builder, loc, intrinsicName,
+                                      convertType(expr->getType()));
+    return builder.createMul(loc, vscale,
+                             builder.getUInt64(scalingFactor, loc));
+  };
+
   assert(!cir::MissingFeatures::aarch64SVEIntrinsics());
 
   switch (builtinID) {
@@ -101,18 +123,26 @@ CIRGenFunction::emitAArch64SVEBuiltinExpr(unsigned builtinID,
   case SVE::BI__builtin_sve_svdupq_n_s32:
   case SVE::BI__builtin_sve_svpfalse_b:
   case SVE::BI__builtin_sve_svpfalse_c:
-  case SVE::BI__builtin_sve_svlen_bf16:
-  case SVE::BI__builtin_sve_svlen_f16:
-  case SVE::BI__builtin_sve_svlen_f32:
-  case SVE::BI__builtin_sve_svlen_f64:
-  case SVE::BI__builtin_sve_svlen_s8:
-  case SVE::BI__builtin_sve_svlen_s16:
-  case SVE::BI__builtin_sve_svlen_s32:
-  case SVE::BI__builtin_sve_svlen_s64:
+    cgm.errorNYI(expr->getSourceRange(),
+                 std::string("unimplemented AArch64 builtin call: ") +
+                     getContext().BuiltinInfo.getName(builtinID));
+    return mlir::Value{};
   case SVE::BI__builtin_sve_svlen_u8:
+  case SVE::BI__builtin_sve_svlen_s8:
+    return vscaleTimesFactor(16);
   case SVE::BI__builtin_sve_svlen_u16:
+  case SVE::BI__builtin_sve_svlen_s16:
+  case SVE::BI__builtin_sve_svlen_f16:
+  case SVE::BI__builtin_sve_svlen_bf16:
+    return vscaleTimesFactor(8);
   case SVE::BI__builtin_sve_svlen_u32:
+  case SVE::BI__builtin_sve_svlen_s32:
+  case SVE::BI__builtin_sve_svlen_f32:
+    return vscaleTimesFactor(4);
   case SVE::BI__builtin_sve_svlen_u64:
+  case SVE::BI__builtin_sve_svlen_s64:
+  case SVE::BI__builtin_sve_svlen_f64:
+    return vscaleTimesFactor(2);
   case SVE::BI__builtin_sve_svtbl2_u8:
   case SVE::BI__builtin_sve_svtbl2_s8:
   case SVE::BI__builtin_sve_svtbl2_u16:
diff --git a/clang/lib/CIR/CodeGen/CIRGenTypes.cpp b/clang/lib/CIR/CodeGen/CIRGenTypes.cpp
index 7f000ece8a494..3bb075d7581f7 100644
--- a/clang/lib/CIR/CodeGen/CIRGenTypes.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenTypes.cpp
@@ -7,6 +7,7 @@
 #include "clang/AST/GlobalDecl.h"
 #include "clang/AST/Type.h"
 #include "clang/Basic/TargetInfo.h"
+#include "clang/CIR/Dialect/IR/CIRTypes.h"
 
 #include <cassert>
 
@@ -320,6 +321,53 @@ mlir::Type CIRGenTypes::convertType(QualType type) {
           cir::IntType::get(&getMLIRContext(), astContext.getTypeSize(ty),
                             /*isSigned=*/true);
       break;
+
+    // SVE types
+    case BuiltinType::SveInt8:
+      resultType =
+          cir::VectorType::get(builder.getSInt8Ty(), 16, /*isScalable=*/true);
+      break;
+    case BuiltinType::SveUint8:
+      resultType =
+          cir::VectorType::get(builder.getUInt8Ty(), 16, /*isScalable=*/true);
+      break;
+    case BuiltinType::SveInt16:
+      resultType =
+          cir::VectorType::get(builder.getSInt16Ty(), 8, /*isScalable=*/true);
+      break;
+    case BuiltinType::SveUint16:
+      resultType =
+          cir::VectorType::get(builder.getUInt16Ty(), 8, /*isScalable=*/true);
+      break;
+    // TODO: Waiting for FP type helpers
+    // case BuiltinType::SveFloat16:
+    //   resultType = cir::VectorType::get(builder.getF16Type(), 8,
+    //   /*isScalable=*/true); break;
+    case BuiltinType::SveInt32:
+      resultType =
+          cir::VectorType::get(builder.getSInt32Ty(), 4, /*isScalable=*/true);
+      break;
+    case BuiltinType::SveUint32:
+      resultType =
+          cir::VectorType::get(builder.getUInt32Ty(), 4, /*isScalable=*/true);
+      break;
+    // TODO: Waiting for FP type helpers
+    // case BuiltinType::SveFloat32:
+    //   resultType = cir::VectorType::get(builder.getF32Type(), 4,
+    //   /*isScalable=*/true); break;
+    case BuiltinType::SveInt64:
+      resultType =
+          cir::VectorType::get(builder.getSInt64Ty(), 2, /*isScalable=*/true);
+      break;
+    case BuiltinType::SveUint64:
+      resultType =
+          cir::VectorType::get(builder.getUInt64Ty(), 2, /*isScalable=*/true);
+      break;
+    // TODO: Waiting for FP type helpers
+    // case BuiltinType::SveFloat64:
+    //   resultType = cir::VectorType::get(builder.getF64Type(), 2,
+    //   /*isScalable=*/true); break;
+
     // Unsigned integral types.
     case BuiltinType::Char8:
     case BuiltinType::Char16:
diff --git a/clang/lib/CIR/Dialect/IR/CIRTypes.cpp b/clang/lib/CIR/Dialect/IR/CIRTypes.cpp
index 9a37a4f4e3996..c7531022fdfb8 100644
--- a/clang/lib/CIR/Dialect/IR/CIRTypes.cpp
+++ b/clang/lib/CIR/Dialect/IR/CIRTypes.cpp
@@ -822,7 +822,7 @@ cir::VectorType::getABIAlignment(const ::mlir::DataLayout &dataLayout,
 
 mlir::LogicalResult cir::VectorType::verify(
     llvm::function_ref<mlir::InFlightDiagnostic()> emitError,
-    mlir::Type elementType, uint64_t size) {
+    mlir::Type elementType, uint64_t size, bool scalable) {
   if (size == 0)
     return emitError() << "the number of vector elements must be non-zero";
   return success();
diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
index 7d854997848aa..7c9cf8e2c2e2d 100644
--- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
+++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
@@ -2910,7 +2910,7 @@ static void prepareTypeConverter(mlir::LLVMTypeConverter &converter,
   });
   converter.addConversion([&](cir::VectorType type) -> mlir::Type {
     const mlir::Type ty = converter.convertType(type.getElementType());
-    return mlir::VectorType::get(type.getSize(), ty);
+    return mlir::VectorType::get(type.getSize(), ty, {type.getIsScalable()});
   });
   converter.addConversion([&](cir::BoolType type) -> mlir::Type {
     return mlir::IntegerType::get(type.getContext(), 1,
diff --git a/clang/test/CIR/CodeGenBuiltins/AArch64/acle_sve_len.c b/clang/test/CIR/CodeGenBuiltins/AArch64/acle_sve_len.c
new file mode 100644
index 0000000000000..3ad2ddef04030
--- /dev/null
+++ b/clang/test/CIR/CodeGenBuiltins/AArch64/acle_sve_len.c
@@ -0,0 +1,143 @@
+// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 6
+// REQUIRES: aarch64-registered-target
+
+// RUN: %clang_cc1 -triple aarch64 -target-feature +sve -disable-O0-optnone -Werror -Wall -fclangir -emit-cir -o - %s | FileCheck %s --check-prefixes=ALL,CIR
+// RUN: %clang_cc1 -DSVE_OVERLOADED_FORMS -triple aarch64 -target-feature +sve -disable-O0-optnone -Werror -Wall -fclangir -emit-cir -o - %s | FileCheck %s --check-prefixes=ALL,CIR
+//
+// RUN: %clang_cc1 -triple aarch64 -target-feature +sve -disable-O0-optnone -Werror -Wall -fclangir -emit-llvm -o - %s | FileCheck %s --check-prefixes=ALL,LLVM
+// RUN: %clang_cc1 -DSVE_OVERLOADED_FORMS -triple aarch64 -target-feature +sve -disable-O0-optnone -Werror -Wall -fclangir -emit-llvm -o - %s | FileCheck %s --check-prefixes=ALL,LLVM
+
+#include <arm_sve.h>
+
+#if defined __ARM_FEATURE_SME
+#define MODE_ATTR __arm_streaming
+#else
+#define MODE_ATTR
+#endif
+
+#ifdef SVE_OVERLOADED_FORMS
+// A simple used,unused... macro, long enough to represent any SVE builtin.
+#define SVE_ACLE_FUNC(A1,A2_UNUSED,A3,A4_UNUSED) A1##A3
+#else
+#define SVE_ACLE_FUNC(A1,A2,A3,A4) A1##A2##A3##A4
+#endif
+
+// ALL-LABEL: @test_svlen_u8
+uint64_t test_svlen_u8(svuint8_t op) MODE_ATTR
+{
+// CIR:     %[[VSCALE:.*]] = cir.call_llvm_intrinsic "vscale.i64"  : () -> !u64i
+// CIR:     %[[C16:.*]] = cir.const #cir.int<16> : !u64i
+// CIR:     %[[BINOP:.*]] = cir.binop(mul, %[[VSCALE]], %[[C16]]) : !u64i
+
+// LLVM:    [[VSCALE:%.*]] = call i64 @llvm.vscale.i64()
+// LLVM:    [[RES:%.*]] = mul i64 [[VSCALE]], 16
+  return SVE_ACLE_FUNC(svlen,_u8,,)(op);
+}
+
+// ALL-LABEL: @test_svlen_s8(
+uint64_t test_svlen_s8(svint8_t op) MODE_ATTR
+{
+// CIR:     %[[VSCALE:.*]] = cir.call_llvm_intrinsic "vscale.i64"  : () -> !u64i
+// CIR:     %[[C16:.*]] = cir.const #cir.int<16> : !u64i
+// CIR:     %[[BINOP:.*]] = cir.binop(mul, %[[VSCALE]], %[[C16]]) : !u64i
+
+// LLVM:    [[VSCALE:%.*]] = call i64 @llvm.vscale.i64()
+// LLVM:    [[RES:%.*]] = mul i64 [[VSCALE]], 16
+  return SVE_ACLE_FUNC(svlen,_s8,,)(op);
+}
+
+// ALL-LABEL: @test_svlen_u16(
+uint64_t test_svlen_u16(svuint16_t op) MODE_ATTR
+{
+// CIR:           %[[VSCALE:.*]] = cir.call_llvm_intrinsic "vscale.i64"  : () -> !u64i
+// CIR:           %[[C8:.*]] = cir.const #cir.int<8> : !u64i
+// CIR:           %[[BINOP:.*]] = cir.binop(mul, %[[VSCALE]], %[[C8]]) : !u64i
+
+// LLVM:    [[VSCALE:%.*]] = call i64 @llvm.vscale.i64()
+// LLVM:    [[RES:%.*]] = mul i64 [[VSCALE]], 8
+  return SVE_ACLE_FUNC(svlen,_u16,,)(op);
+}
+
+// ALL-LABEL: @test_svlen_s16(
+uint64_t test_svlen_s16(svint16_t op) MODE_ATTR
+{
+// CIR:           %[[VSCALE:.*]] = cir.call_llvm_intrinsic "vscale.i64"  : () -> !u64i
+// CIR:           %[[C8:.*]] = cir.const #cir.int<8> : !u64i
+// CIR:           %[[BINOP:.*]] = cir.binop(mul, %[[VSCALE]], %[[C8]]) : !u64i
+
+// LLVM:    [[VSCALE:%.*]] = call i64 @llvm.vscale.i64()
+// LLVM:    [[RES:%.*]] = mul i64 [[VSCALE]], 8
+  return SVE_ACLE_FUNC(svlen,_s16,,)(op);
+}
+
+// TODO: Waiting for FP type helpers
+// uint64_t test_svlen_f16(svfloat16_t op) MODE_ATTR
+// {
+//   return SVE_ACLE_FUNC(svlen,_f16,,)(op);
+// }
+
+// TODO: Waiting for FP type helpers
+// uint64_t test_svlen_bf16(svbfloat16_t op) MODE_ATTR
+// {
+//   return SVE_ACLE_FUNC(svlen,_bf16,,)(op);
+// }
+
+// ALL-LABEL: @test_svlen_u32(
+uint64_t test_svlen_u32(svuint32_t op) MODE_ATTR
+{
+// CIR:           %[[VSCALE:.*]] = cir.call_llvm_intrinsic "vscale.i64"  : () -> !u64i
+// CIR:           %[[C4:.*]] = cir.const #cir.int<4> : !u64i
+// CIR:           %[[BINOP:.*]] = cir.binop(mul, %[[VSCALE]], %[[C4]]) : !u64i
+
+// LLVM:    [[VSCALE:%.*]] = call i64 @llvm.vscale.i64()
+// LLVM:    [[RES:%.*]] = mul i64  [[VSCALE]], 4
+  return SVE_ACLE_FUNC(svlen,_u32,,)(op);
+}
+
+// ALL-LABEL: @test_svlen_s32(
+uint64_t test_svlen_s32(svint32_t op) MODE_ATTR
+{
+// CIR:           %[[VSCALE:.*]] = cir.call_llvm_intrinsic "vscale.i64"  : () -> !u64i
+// CIR:           %[[C4:.*]] = cir.const #cir.int<4> : !u64i
+// CIR:           %[[BINOP:.*]] = cir.binop(mul, %[[VSCALE]], %[[C4]]) : !u64i
+
+// LLVM:    [[VSCALE:%.*]] = call i64 @llvm.vscale.i64()
+// LLVM:    [[RES:%.*]] = mul i64 [[VSCALE]], 4
+  return SVE_ACLE_FUNC(svlen,_s32,,)(op);
+}
+
+// TODO: Waiting for FP type helpers
+// uint64_t test_svlen_f32(svfloat32_t op) MODE_ATTR
+// {
+//   return SVE_ACLE_FUNC(svlen,_f32,,)(op);
+// }
+
+// ALL-LABEL: @test_svlen_u64(
+uint64_t test_svlen_u64(svuint64_t op) MODE_ATTR
+{
+// CIR:           %[[VSCALE:.*]] = cir.call_llvm_intrinsic "vscale.i64"  : () -> !u64i
+// CIR:           %[[C2:.*]] = cir.const #cir.int<2> : !u64i
+// CIR:           %[[BINOP:.*]] = cir.binop(mul, %[[VSCALE]], %[[C2]]) : !u64i
+
+// LLVM:    [[VSCALE:%.*]] = call i64 @llvm.vscale.i64()
+// LLVM:    [[RES:%.*]] = mul i64  [[VSCALE]], 2
+  return SVE_ACLE_FUNC(svlen,_u64,,)(op);
+}
+
+// ALL-LABEL: @test_svlen_s64
+uint64_t test_svlen_s64(svint64_t op) MODE_ATTR
+{
+// CIR:           %[[VSCALE:.*]] = cir.call_llvm_intrinsic "vscale.i64"  : () -> !u64i
+// CIR:           %[[C2:.*]] = cir.const #cir.int<2> : !u64i
+// CIR:           %[[BINOP:.*]] = cir.binop(mul, %[[VSCALE]], %[[C2]]) : !u64i
+
+// LLVM:    [[VSCALE:%.*]] = call i64 @llvm.vscale.i64()
+// LLVM:    [[RES:%.*]] = mul i64 [[VSCALE]], 2
+  return SVE_ACLE_FUNC(svlen,_s64,,)(op);
+}
+
+// TODO: Waiting for FP type helpers
+// uint64_t test_svlen_f64(svfloat64_t op) MODE_ATTR
+// {
+//   return SVE_ACLE_FUNC(svlen,_f64,,)(op);
+// }

Copy link
Contributor

@andykaylor andykaylor left a comment

Choose a reason for hiding this comment

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

Thanks for getting us started on AArch64 builtins!

getSIntNTy(getCIRIntOrFloatBitWidth(vecCast.getElementType()));
VectorType integralVecTy =
VectorType::get(context, integralTy, vecCast.getSize());
VectorType integralVecTy = VectorType::get(integralTy, vecCast.getSize());
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
VectorType integralVecTy = VectorType::get(integralTy, vecCast.getSize());
VectorType integralVecTy = cir::VectorType::get(integralTy, vecCast.getSize());

We've been trying to make cir namespace uses explicit to avoid ambiguity, but it looks like we missed this one (and the cast earlier in this function).

CIR_VectorElementType:$elementType,
"uint64_t":$size
"uint64_t":$size,
OptionalParameter<"bool">:$isScalable
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
OptionalParameter<"bool">:$isScalable
OptionalParameter<"bool">:$is_scalable

We've decided to standardize on snake_case in our dialect definition files, but a lot of places haven't been updated since we made that decision.

}];

let parameters = (ins
CIR_VectorElementType:$elementType,
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
CIR_VectorElementType:$elementType,
CIR_VectorElementType:$element_type,

Comment on lines +59 to +60
StringRef intrinsicName = "vscale.i64";
auto vscale = emitIntrinsicCallOp(builder, loc, intrinsicName,
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
StringRef intrinsicName = "vscale.i64";
auto vscale = emitIntrinsicCallOp(builder, loc, intrinsicName,
StringRef intrinsicName = "vscale.i64";
auto vscale = emitIntrinsicCallOp(builder, loc, "vscale",

The suffix will get added automatically during lowering to LLVM IR.

Do you think it's useful to add a cir.vscale operation to make this easier to identify in transformation passes?

StringRef intrinsicName = "vscale.i64";
auto vscale = emitIntrinsicCallOp(builder, loc, intrinsicName,
convertType(expr->getType()));
return builder.createMul(loc, vscale,
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
return builder.createMul(loc, vscale,
return builder.createNUWAMul(loc, vscale,

I'm not sure why this isn't createNUWMul


mlir::Location loc = getLoc(expr->getExprLoc());
// Generate vscale * scalingFactor
auto vscaleTimesFactor = [&](int32_t scalingFactor) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Maybe make this a separate static function rather than a lambda?

break;
// TODO: Waiting for FP type helpers
// case BuiltinType::SveFloat16:
// resultType = cir::VectorType::get(builder.getF16Type(), 8,
Copy link
Contributor

Choose a reason for hiding this comment

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

Can you add the type helpers? We already have fP16Ty, floatTy, and doubleTy in CIRGenTypeCache so it should be trivial.

Comment on lines +7 to +8
// RUN: %clang_cc1 -triple aarch64 -target-feature +sve -disable-O0-optnone -Werror -Wall -fclangir -emit-llvm -o - %s | FileCheck %s --check-prefixes=ALL,LLVM
// RUN: %clang_cc1 -DSVE_OVERLOADED_FORMS -triple aarch64 -target-feature +sve -disable-O0-optnone -Werror -Wall -fclangir -emit-llvm -o - %s | FileCheck %s --check-prefixes=ALL,LLVM
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
// RUN: %clang_cc1 -triple aarch64 -target-feature +sve -disable-O0-optnone -Werror -Wall -fclangir -emit-llvm -o - %s | FileCheck %s --check-prefixes=ALL,LLVM
// RUN: %clang_cc1 -DSVE_OVERLOADED_FORMS -triple aarch64 -target-feature +sve -disable-O0-optnone -Werror -Wall -fclangir -emit-llvm -o - %s | FileCheck %s --check-prefixes=ALL,LLVM
// RUN: %clang_cc1 -triple aarch64 -target-feature +sve -disable-O0-optnone -Werror -Wall -fclangir -emit-llvm -o - %s | FileCheck %s --check-prefixes=ALL,LLVM
// RUN: %clang_cc1 -DSVE_OVERLOADED_FORMS -triple aarch64 -target-feature +sve -disable-O0-optnone -Werror -Wall -fclangir -emit-llvm -o - %s | FileCheck %s --check-prefixes=ALL,LLVM
// RUN: %clang_cc1 -triple aarch64 -target-feature +sve -disable-O0-optnone -Werror -Wall -emit-llvm -o - %s | FileCheck %s --check-prefixes=ALL,OGCG
// RUN: %clang_cc1 -DSVE_OVERLOADED_FORMS -triple aarch64 -target-feature +sve -disable-O0-optnone -Werror -Wall -emit-llvm -o - %s | FileCheck %s --check-prefixes=ALL,OGCG

Can you add checks for OGCG so we can visually compare the LLVM output via CIR to the direct LLVM output to verify that we're doing the same thing?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

clang Clang issues not falling into any other category ClangIR Anything related to the ClangIR project

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants