llvmorg-github-actions[bot] wrote:

<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-llvm-ir

@llvm/pr-subscribers-clang-codegen

Author: Kiva (imkiva)

<details>
<summary>Changes</summary>

Adds initial LLVM and Clang support for the Zvvm/IME configuration APIs:

- Adds Clang builtins/macros for __riscv_ime_vlen(), __riscv_ime_lambda(), and 
__riscv_vsetlambda().
- Adds LLVM intrinsics for implementation geometry queries, selected 
vtype.lambda readback, and nonzero
  lambda write/readback.

This does not add full VSETVLI high-field tracking or matrix operation 
intrinsics/codegen


---

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


14 Files Affected:

- (modified) clang/include/clang/Basic/DiagnosticSemaKinds.td (+2) 
- (modified) clang/include/clang/Basic/riscv_vector.td (+28) 
- (modified) clang/lib/CodeGen/TargetBuiltins/RISCV.cpp (+71) 
- (modified) clang/lib/Sema/SemaRISCV.cpp (+35) 
- (added) clang/test/CodeGen/RISCV/rvv-intrinsics-handcrafted/ime-config.c 
(+158) 
- (added) clang/test/Sema/riscv-ime-vsetlambda.c (+38) 
- (modified) llvm/include/llvm/IR/IntrinsicsRISCV.td (+25) 
- (modified) llvm/lib/Target/RISCV/RISCVISelLowering.cpp (+282) 
- (modified) llvm/lib/Target/RISCV/RISCVInstrInfoZvvm.td (+28) 
- (modified) llvm/lib/Target/RISCV/RISCVSystemOperands.td (+1-1) 
- (added) llvm/test/CodeGen/RISCV/ime-config-intrinsics-invalid-rv32.ll (+34) 
- (added) llvm/test/CodeGen/RISCV/ime-config-intrinsics-invalid-rv64.ll (+34) 
- (added) llvm/test/CodeGen/RISCV/ime-config-intrinsics-rv32.ll (+705) 
- (added) llvm/test/CodeGen/RISCV/ime-config-intrinsics-rv64.ll (+735) 


``````````diff
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td 
b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index a3b575b7ee63a..f9e6ba99377cc 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -13601,6 +13601,8 @@ def err_riscv_builtin_requires_extension : Error<
   "builtin requires%select{| at least one of the following extensions}0: %1">;
 def err_riscv_builtin_invalid_lmul : Error<
   "LMUL argument must be in the range [0,3] or [5,7]">;
+def err_riscv_builtin_invalid_ime_lambda : Error<
+  "constant argument to RISC-V IME vsetlambda builtin must be 0 or a power of 
two in the range [1, 64]">;
 def err_riscv_type_requires_extension : Error<
   "RISC-V type %0 requires the '%1' extension">;
 def err_riscv_attribute_interrupt_requires_extension : Error<
diff --git a/clang/include/clang/Basic/riscv_vector.td 
b/clang/include/clang/Basic/riscv_vector.td
index c5ce8b7ae8fc1..f3651a9265e0e 100644
--- a/clang/include/clang/Basic/riscv_vector.td
+++ b/clang/include/clang/Basic/riscv_vector.td
@@ -2162,3 +2162,31 @@ let UnMaskedPolicyScheme = HasPassthruOperand in {
     defm vpairo : RVVOutBuiltinSet<"vpairo", "csil", [["vv", "Uv", "UvUvUv"]]>;
   }
 }
+
+//===----------------------------------------------------------------------===//
+// Zvvm - Integrated Matrix Extension configuration builtins.
+//===----------------------------------------------------------------------===//
+
+let HeaderCode =
+[{
+#define __riscv_ime_vlen() __builtin_rvv_ime_vlen()
+#define __riscv_ime_lambda() __builtin_rvv_ime_lambda()
+#define __riscv_vsetlambda(lambda) __builtin_rvv_vsetlambda((size_t)(lambda))
+}] in
+def ime_config_macro: RVVHeader;
+
+let HasBuiltinAlias = false, HasVL = false, HasMasked = false,
+    UnMaskedPolicyScheme = NonePolicy, MaskedPolicyScheme = NonePolicy,
+    Log2LMUL = [0], RequiredFeatures = ["zvvmm"],
+    ManualCodegen = [{
+      return emitRVVIMEBuiltin(this, E, ReturnValue, ResultType, ID, Ops,
+                               PolicyAttrs, IsMasked);
+    }] in
+{
+  let IRName = "ime_vlen" in
+  def ime_vlen : RVVBuiltin<"", "z", "i">;
+  let IRName = "ime_lambda" in
+  def ime_lambda : RVVBuiltin<"", "z", "i">;
+  let IRName = "ime_vsetlambda_nonzero" in
+  def vsetlambda : RVVBuiltin<"", "zz", "i">;
+}
diff --git a/clang/lib/CodeGen/TargetBuiltins/RISCV.cpp 
b/clang/lib/CodeGen/TargetBuiltins/RISCV.cpp
index 3bf7dd07d54d3..1b6e0b52c5dd8 100644
--- a/clang/lib/CodeGen/TargetBuiltins/RISCV.cpp
+++ b/clang/lib/CodeGen/TargetBuiltins/RISCV.cpp
@@ -308,6 +308,77 @@ emitRVVVsetvliBuiltin(CodeGenFunction *CGF, const CallExpr 
*E,
   return Builder.CreateCall(F, Ops, "");
 }
 
+static LLVM_ATTRIBUTE_NOINLINE Value *
+emitRVVIMEBuiltin(CodeGenFunction *CGF, const CallExpr *E,
+                  ReturnValueSlot ReturnValue, llvm::Type *ResultType,
+                  Intrinsic::ID ID, SmallVectorImpl<Value *> &Ops,
+                  int PolicyAttrs, bool IsMasked) {
+  auto &Builder = CGF->Builder;
+  auto &CGM = CGF->CGM;
+
+  switch (ID) {
+  case Intrinsic::riscv_ime_vlen:
+  case Intrinsic::riscv_ime_lambda: {
+    assert(Ops.empty() && "unexpected IME geometry operands");
+    llvm::Function *F = CGM.getIntrinsic(ID, {ResultType});
+    return Builder.CreateCall(F);
+  }
+  case Intrinsic::riscv_ime_vsetlambda_nonzero: {
+    assert(Ops.size() == 1 && "unexpected vsetlambda arity");
+    Value *Req = Ops[0];
+
+    if (auto *C = dyn_cast<llvm::ConstantInt>(Req)) {
+      if (C->isZero()) {
+        llvm::Function *ReadF =
+            CGM.getIntrinsic(Intrinsic::riscv_ime_readlambda, {ResultType});
+        return Builder.CreateCall(ReadF);
+      }
+
+      llvm::Function *SetF = CGM.getIntrinsic(
+          Intrinsic::riscv_ime_vsetlambda_nonzero, {ResultType});
+      return Builder.CreateCall(SetF, {Req});
+    }
+
+    // Runtime value. The IME API defines requested_lambda == 0 as a read-only
+    // selected-lambda query, so emit real control flow instead of an
+    // unconditional vsetvl guarded only by a selected vtype value.
+    llvm::Function *Fn = Builder.GetInsertBlock()->getParent();
+    llvm::BasicBlock *ReadBB =
+        CGF->createBasicBlock("ime.vsetlambda.read", Fn);
+    llvm::BasicBlock *SetBB =
+        CGF->createBasicBlock("ime.vsetlambda.set", Fn);
+    llvm::BasicBlock *ContBB =
+        CGF->createBasicBlock("ime.vsetlambda.cont", Fn);
+
+    Value *IsZero =
+        Builder.CreateICmpEQ(Req, llvm::ConstantInt::get(ResultType, 0));
+    Builder.CreateCondBr(IsZero, ReadBB, SetBB);
+
+    Builder.SetInsertPoint(ReadBB);
+    llvm::Function *ReadF =
+        CGM.getIntrinsic(Intrinsic::riscv_ime_readlambda, {ResultType});
+    Value *ReadVal = Builder.CreateCall(ReadF);
+    Builder.CreateBr(ContBB);
+    ReadBB = Builder.GetInsertBlock();
+
+    Builder.SetInsertPoint(SetBB);
+    llvm::Function *SetF = CGM.getIntrinsic(
+        Intrinsic::riscv_ime_vsetlambda_nonzero, {ResultType});
+    Value *SetVal = Builder.CreateCall(SetF, {Req});
+    Builder.CreateBr(ContBB);
+    SetBB = Builder.GetInsertBlock();
+
+    Builder.SetInsertPoint(ContBB);
+    llvm::PHINode *Phi = Builder.CreatePHI(ResultType, 2);
+    Phi->addIncoming(ReadVal, ReadBB);
+    Phi->addIncoming(SetVal, SetBB);
+    return Phi;
+  }
+  default:
+    llvm_unreachable("unexpected IME builtin");
+  }
+}
+
 static LLVM_ATTRIBUTE_NOINLINE Value *
 emitRVVVSEMaskBuiltin(CodeGenFunction *CGF, const CallExpr *E,
                       ReturnValueSlot ReturnValue, llvm::Type *ResultType,
diff --git a/clang/lib/Sema/SemaRISCV.cpp b/clang/lib/Sema/SemaRISCV.cpp
index 9647a7d913744..095e1cc5e808c 100644
--- a/clang/lib/Sema/SemaRISCV.cpp
+++ b/clang/lib/Sema/SemaRISCV.cpp
@@ -26,6 +26,7 @@
 #include "clang/Sema/Sema.h"
 #include "clang/Support/RISCVVIntrinsicUtils.h"
 #include "llvm/ADT/SmallVector.h"
+#include "llvm/Support/MathExtras.h"
 #include "llvm/TargetParser/RISCVISAInfo.h"
 #include "llvm/TargetParser/RISCVTargetParser.h"
 #include <optional>
@@ -677,11 +678,45 @@ bool SemaRISCV::CheckBuiltinFunctionCall(const TargetInfo 
&TI,
     return SemaRef.BuiltinConstantArgRange(TheCall, SEWOffset, 0, 3) ||
            CheckLMUL(TheCall, LMULOffset);
   };
+
+  auto CheckIMEVSetLambda = [&]() -> bool {
+    assert(TheCall->getNumArgs() == 1 && "unexpected vsetlambda arity");
+
+    Expr *Arg = TheCall->getArg(0);
+    if (Arg->isTypeDependent() || Arg->isValueDependent())
+      return false;
+    Expr *DiagArg = Arg->IgnoreParenCasts();
+
+    Expr::EvalResult Eval;
+    Expr *EvalArg = DiagArg;
+    // Prefer evaluating the user source expression before the macro-introduced
+    // (size_t) cast. This catches constants that would otherwise wrap into a
+    // valid size_t value on RV32, e.g. 0x100000004ULL -> 4.
+    if (!EvalArg->EvaluateAsInt(Eval, Context, Expr::SE_NoSideEffects))
+      return false;
+
+    llvm::APSInt Val = Eval.Val.getInt();
+    if (Val.isSigned() && Val.isNegative())
+      return Diag(DiagArg->getBeginLoc(),
+                  diag::err_riscv_builtin_invalid_ime_lambda)
+             << DiagArg->getSourceRange();
+
+    uint64_t U = Val.getLimitedValue(65);
+    if (U != 0 && (U > 64 || !llvm::isPowerOf2_64(U)))
+      return Diag(DiagArg->getBeginLoc(),
+                  diag::err_riscv_builtin_invalid_ime_lambda)
+             << DiagArg->getSourceRange();
+
+    return false;
+  };
+
   switch (BuiltinID) {
   case RISCVVector::BI__builtin_rvv_vsetvli:
     return CheckVSetVL(1, 2);
   case RISCVVector::BI__builtin_rvv_vsetvlimax:
     return CheckVSetVL(0, 1);
+  case RISCVVector::BI__builtin_rvv_vsetlambda:
+    return CheckIMEVSetLambda();
   case RISCVVector::BI__builtin_rvv_sf_vsettnt:
   case RISCVVector::BI__builtin_rvv_sf_vsettm:
   case RISCVVector::BI__builtin_rvv_sf_vsettn:
diff --git a/clang/test/CodeGen/RISCV/rvv-intrinsics-handcrafted/ime-config.c 
b/clang/test/CodeGen/RISCV/rvv-intrinsics-handcrafted/ime-config.c
new file mode 100644
index 0000000000000..d69a91fae7297
--- /dev/null
+++ b/clang/test/CodeGen/RISCV/rvv-intrinsics-handcrafted/ime-config.c
@@ -0,0 +1,158 @@
+// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py 
UTC_ARGS: --version 6
+// REQUIRES: riscv-registered-target
+// RUN: %clang_cc1 -triple riscv32 -target-feature +v \
+// RUN:     -target-feature +experimental-zvvmm -disable-O0-optnone \
+// RUN:     -emit-llvm -o - %s | FileCheck --check-prefix=RV32 %s
+// RUN: %clang_cc1 -triple riscv64 -target-feature +v \
+// RUN:     -target-feature +experimental-zvvmm -disable-O0-optnone \
+// RUN:     -emit-llvm -o - %s | FileCheck --check-prefix=RV64 %s
+
+#include <stddef.h>
+#include <riscv_vector.h>
+
+// RV32-LABEL: define dso_local i32 @test_ime_vlen(
+// RV32-SAME: ) #[[ATTR0:[0-9]+]] {
+// RV32-NEXT:  [[ENTRY:.*:]]
+// RV32-NEXT:    [[TMP0:%.*]] = call i32 @llvm.riscv.ime.vlen.i32()
+// RV32-NEXT:    ret i32 [[TMP0]]
+//
+// RV64-LABEL: define dso_local i64 @test_ime_vlen(
+// RV64-SAME: ) #[[ATTR0:[0-9]+]] {
+// RV64-NEXT:  [[ENTRY:.*:]]
+// RV64-NEXT:    [[TMP0:%.*]] = call i64 @llvm.riscv.ime.vlen.i64()
+// RV64-NEXT:    ret i64 [[TMP0]]
+//
+size_t test_ime_vlen(void) {
+  return __riscv_ime_vlen();
+}
+
+// RV32-LABEL: define dso_local i32 @test_ime_lambda(
+// RV32-SAME: ) #[[ATTR0]] {
+// RV32-NEXT:  [[ENTRY:.*:]]
+// RV32-NEXT:    [[TMP0:%.*]] = call i32 @llvm.riscv.ime.lambda.i32()
+// RV32-NEXT:    ret i32 [[TMP0]]
+//
+// RV64-LABEL: define dso_local i64 @test_ime_lambda(
+// RV64-SAME: ) #[[ATTR0]] {
+// RV64-NEXT:  [[ENTRY:.*:]]
+// RV64-NEXT:    [[TMP0:%.*]] = call i64 @llvm.riscv.ime.lambda.i64()
+// RV64-NEXT:    ret i64 [[TMP0]]
+//
+size_t test_ime_lambda(void) {
+  return __riscv_ime_lambda();
+}
+
+// RV32-LABEL: define dso_local i32 @test_vsetlambda(
+// RV32-SAME: ) #[[ATTR0]] {
+// RV32-NEXT:  [[ENTRY:.*:]]
+// RV32-NEXT:    [[TMP0:%.*]] = call i32 
@llvm.riscv.ime.vsetlambda.nonzero.i32(i32 4)
+// RV32-NEXT:    ret i32 [[TMP0]]
+//
+// RV64-LABEL: define dso_local i64 @test_vsetlambda(
+// RV64-SAME: ) #[[ATTR0]] {
+// RV64-NEXT:  [[ENTRY:.*:]]
+// RV64-NEXT:    [[TMP0:%.*]] = call i64 
@llvm.riscv.ime.vsetlambda.nonzero.i64(i64 4)
+// RV64-NEXT:    ret i64 [[TMP0]]
+//
+size_t test_vsetlambda(void) {
+  return __riscv_vsetlambda(4);
+}
+
+// RV32-LABEL: define dso_local i32 @test_vsetlambda_zero(
+// RV32-SAME: ) #[[ATTR0]] {
+// RV32-NEXT:  [[ENTRY:.*:]]
+// RV32-NEXT:    [[TMP0:%.*]] = call i32 @llvm.riscv.ime.readlambda.i32()
+// RV32-NEXT:    ret i32 [[TMP0]]
+//
+// RV64-LABEL: define dso_local i64 @test_vsetlambda_zero(
+// RV64-SAME: ) #[[ATTR0]] {
+// RV64-NEXT:  [[ENTRY:.*:]]
+// RV64-NEXT:    [[TMP0:%.*]] = call i64 @llvm.riscv.ime.readlambda.i64()
+// RV64-NEXT:    ret i64 [[TMP0]]
+//
+size_t test_vsetlambda_zero(void) {
+  return __riscv_vsetlambda(0);
+}
+
+// RV32-LABEL: define dso_local i32 @test_vsetlambda_runtime(
+// RV32-SAME: i32 noundef [[X:%.*]]) #[[ATTR0]] {
+// RV32-NEXT:  [[ENTRY:.*:]]
+// RV32-NEXT:    [[X_ADDR:%.*]] = alloca i32, align 4
+// RV32-NEXT:    store i32 [[X]], ptr [[X_ADDR]], align 4
+// RV32-NEXT:    [[TMP0:%.*]] = load i32, ptr [[X_ADDR]], align 4
+// RV32-NEXT:    [[TMP1:%.*]] = icmp eq i32 [[TMP0]], 0
+// RV32-NEXT:    br i1 [[TMP1]], label %[[IME_VSETLAMBDA_READ:.*]], label 
%[[IME_VSETLAMBDA_SET:.*]]
+// RV32:       [[IME_VSETLAMBDA_READ]]:
+// RV32-NEXT:    [[TMP2:%.*]] = call i32 @llvm.riscv.ime.readlambda.i32()
+// RV32-NEXT:    br label %[[IME_VSETLAMBDA_CONT:.*]]
+// RV32:       [[IME_VSETLAMBDA_SET]]:
+// RV32-NEXT:    [[TMP3:%.*]] = call i32 
@llvm.riscv.ime.vsetlambda.nonzero.i32(i32 [[TMP0]])
+// RV32-NEXT:    br label %[[IME_VSETLAMBDA_CONT]]
+// RV32:       [[IME_VSETLAMBDA_CONT]]:
+// RV32-NEXT:    [[TMP4:%.*]] = phi i32 [ [[TMP2]], %[[IME_VSETLAMBDA_READ]] 
], [ [[TMP3]], %[[IME_VSETLAMBDA_SET]] ]
+// RV32-NEXT:    ret i32 [[TMP4]]
+//
+// RV64-LABEL: define dso_local i64 @test_vsetlambda_runtime(
+// RV64-SAME: i64 noundef [[X:%.*]]) #[[ATTR0]] {
+// RV64-NEXT:  [[ENTRY:.*:]]
+// RV64-NEXT:    [[X_ADDR:%.*]] = alloca i64, align 8
+// RV64-NEXT:    store i64 [[X]], ptr [[X_ADDR]], align 8
+// RV64-NEXT:    [[TMP0:%.*]] = load i64, ptr [[X_ADDR]], align 8
+// RV64-NEXT:    [[TMP1:%.*]] = icmp eq i64 [[TMP0]], 0
+// RV64-NEXT:    br i1 [[TMP1]], label %[[IME_VSETLAMBDA_READ:.*]], label 
%[[IME_VSETLAMBDA_SET:.*]]
+// RV64:       [[IME_VSETLAMBDA_READ]]:
+// RV64-NEXT:    [[TMP2:%.*]] = call i64 @llvm.riscv.ime.readlambda.i64()
+// RV64-NEXT:    br label %[[IME_VSETLAMBDA_CONT:.*]]
+// RV64:       [[IME_VSETLAMBDA_SET]]:
+// RV64-NEXT:    [[TMP3:%.*]] = call i64 
@llvm.riscv.ime.vsetlambda.nonzero.i64(i64 [[TMP0]])
+// RV64-NEXT:    br label %[[IME_VSETLAMBDA_CONT]]
+// RV64:       [[IME_VSETLAMBDA_CONT]]:
+// RV64-NEXT:    [[TMP4:%.*]] = phi i64 [ [[TMP2]], %[[IME_VSETLAMBDA_READ]] 
], [ [[TMP3]], %[[IME_VSETLAMBDA_SET]] ]
+// RV64-NEXT:    ret i64 [[TMP4]]
+//
+size_t test_vsetlambda_runtime(size_t x) {
+  return __riscv_vsetlambda(x);
+}
+
+// RV32-LABEL: define dso_local i32 @test_vsetlambda_save_restore(
+// RV32-SAME: ) #[[ATTR0]] {
+// RV32-NEXT:  [[ENTRY:.*:]]
+// RV32-NEXT:    [[SAVED:%.*]] = alloca i32, align 4
+// RV32-NEXT:    [[TMP0:%.*]] = call i32 @llvm.riscv.ime.readlambda.i32()
+// RV32-NEXT:    store i32 [[TMP0]], ptr [[SAVED]], align 4
+// RV32-NEXT:    [[TMP1:%.*]] = load i32, ptr [[SAVED]], align 4
+// RV32-NEXT:    [[TMP2:%.*]] = icmp eq i32 [[TMP1]], 0
+// RV32-NEXT:    br i1 [[TMP2]], label %[[IME_VSETLAMBDA_READ:.*]], label 
%[[IME_VSETLAMBDA_SET:.*]]
+// RV32:       [[IME_VSETLAMBDA_READ]]:
+// RV32-NEXT:    [[TMP3:%.*]] = call i32 @llvm.riscv.ime.readlambda.i32()
+// RV32-NEXT:    br label %[[IME_VSETLAMBDA_CONT:.*]]
+// RV32:       [[IME_VSETLAMBDA_SET]]:
+// RV32-NEXT:    [[TMP4:%.*]] = call i32 
@llvm.riscv.ime.vsetlambda.nonzero.i32(i32 [[TMP1]])
+// RV32-NEXT:    br label %[[IME_VSETLAMBDA_CONT]]
+// RV32:       [[IME_VSETLAMBDA_CONT]]:
+// RV32-NEXT:    [[TMP5:%.*]] = phi i32 [ [[TMP3]], %[[IME_VSETLAMBDA_READ]] 
], [ [[TMP4]], %[[IME_VSETLAMBDA_SET]] ]
+// RV32-NEXT:    ret i32 [[TMP5]]
+//
+// RV64-LABEL: define dso_local i64 @test_vsetlambda_save_restore(
+// RV64-SAME: ) #[[ATTR0]] {
+// RV64-NEXT:  [[ENTRY:.*:]]
+// RV64-NEXT:    [[SAVED:%.*]] = alloca i64, align 8
+// RV64-NEXT:    [[TMP0:%.*]] = call i64 @llvm.riscv.ime.readlambda.i64()
+// RV64-NEXT:    store i64 [[TMP0]], ptr [[SAVED]], align 8
+// RV64-NEXT:    [[TMP1:%.*]] = load i64, ptr [[SAVED]], align 8
+// RV64-NEXT:    [[TMP2:%.*]] = icmp eq i64 [[TMP1]], 0
+// RV64-NEXT:    br i1 [[TMP2]], label %[[IME_VSETLAMBDA_READ:.*]], label 
%[[IME_VSETLAMBDA_SET:.*]]
+// RV64:       [[IME_VSETLAMBDA_READ]]:
+// RV64-NEXT:    [[TMP3:%.*]] = call i64 @llvm.riscv.ime.readlambda.i64()
+// RV64-NEXT:    br label %[[IME_VSETLAMBDA_CONT:.*]]
+// RV64:       [[IME_VSETLAMBDA_SET]]:
+// RV64-NEXT:    [[TMP4:%.*]] = call i64 
@llvm.riscv.ime.vsetlambda.nonzero.i64(i64 [[TMP1]])
+// RV64-NEXT:    br label %[[IME_VSETLAMBDA_CONT]]
+// RV64:       [[IME_VSETLAMBDA_CONT]]:
+// RV64-NEXT:    [[TMP5:%.*]] = phi i64 [ [[TMP3]], %[[IME_VSETLAMBDA_READ]] 
], [ [[TMP4]], %[[IME_VSETLAMBDA_SET]] ]
+// RV64-NEXT:    ret i64 [[TMP5]]
+//
+size_t test_vsetlambda_save_restore(void) {
+  size_t saved = __riscv_vsetlambda(0);
+  return __riscv_vsetlambda(saved);
+}
diff --git a/clang/test/Sema/riscv-ime-vsetlambda.c 
b/clang/test/Sema/riscv-ime-vsetlambda.c
new file mode 100644
index 0000000000000..0c41cdc491de2
--- /dev/null
+++ b/clang/test/Sema/riscv-ime-vsetlambda.c
@@ -0,0 +1,38 @@
+// REQUIRES: riscv-registered-target
+// RUN: %clang_cc1 -triple riscv32 -target-feature +v \
+// RUN:   -target-feature +experimental-zvvmm -fsyntax-only -verify %s
+// RUN: %clang_cc1 -triple riscv64 -target-feature +v \
+// RUN:   -target-feature +experimental-zvvmm -fsyntax-only -verify %s
+
+#include <stddef.h>
+#include <riscv_vector.h>
+
+void ok(void) {
+  __riscv_vsetlambda(0);
+  __riscv_vsetlambda(1);
+  __riscv_vsetlambda(2);
+  __riscv_vsetlambda(4);
+  __riscv_vsetlambda(8);
+  __riscv_vsetlambda(16);
+  __riscv_vsetlambda(32);
+  __riscv_vsetlambda(64);
+}
+
+void bad_value(void) {
+  __riscv_vsetlambda(3);   // expected-error {{constant argument to RISC-V IME 
vsetlambda builtin must be 0 or a power of two in the range [1, 64]}}
+  __riscv_vsetlambda(128); // expected-error {{constant argument to RISC-V IME 
vsetlambda builtin must be 0 or a power of two in the range [1, 64]}}
+  __riscv_vsetlambda(-1);  // expected-error {{constant argument to RISC-V IME 
vsetlambda builtin must be 0 or a power of two in the range [1, 64]}}
+}
+
+void ok_runtime(size_t x) {
+  __riscv_vsetlambda(x);
+  __riscv_vsetlambda(x++);
+}
+
+void bad_wrap(void) {
+  __riscv_vsetlambda(0x100000004ULL);       // expected-error {{constant 
argument to RISC-V IME vsetlambda builtin must be 0 or a power of two in the 
range [1, 64]}}
+  __riscv_vsetlambda(-4294967292LL);        // expected-error {{constant 
argument to RISC-V IME vsetlambda builtin must be 0 or a power of two in the 
range [1, 64]}}
+#if __SIZEOF_POINTER__ == 8
+  __riscv_vsetlambda(((__int128)1) << 70);  // expected-error {{constant 
argument to RISC-V IME vsetlambda builtin must be 0 or a power of two in the 
range [1, 64]}}
+#endif
+}
diff --git a/llvm/include/llvm/IR/IntrinsicsRISCV.td 
b/llvm/include/llvm/IR/IntrinsicsRISCV.td
index f53f752c25c30..8d809ad80f133 100644
--- a/llvm/include/llvm/IR/IntrinsicsRISCV.td
+++ b/llvm/include/llvm/IR/IntrinsicsRISCV.td
@@ -2063,6 +2063,31 @@ let TargetPrefix = "riscv" in {
   defm vfncvt_sat_f_f_q_alt : RISCVConversionRoundingMode;
 } // TargetPrefix = "riscv"
 
+//===----------------------------------------------------------------------===//
+// Zvvm - Integrated Matrix Extension
+//
+// These intrinsics expose IME configuration queries and vtype.lambda control.
+// They use llvm_anyint_ty for consistency with RVV configuration intrinsics,
+// but the only supported type is XLen.
+let TargetPrefix = "riscv" in {
+  // Implementation geometry helpers.
+  def int_riscv_ime_vlen : Intrinsic<[llvm_anyint_ty], [], [IntrNoMem]>;
+  def int_riscv_ime_lambda : Intrinsic<[llvm_anyint_ty], [], [IntrNoMem]>;
+
+  // Current selected vtype.lambda readback. This is not a memory operation,
+  // but keep it conservative until LLVM IR has a first-class vtype state 
model.
+  def int_riscv_ime_readlambda
+      : Intrinsic<[llvm_anyint_ty], [], [IntrNoMem, IntrHasSideEffects]>;
+
+  // Write a nonzero requested lambda and return the established lambda.
+  // Source-level contract: the argument is a positive power of two in
+  // {1,2,4,8,16,32,64}. Clang emits a separate readlambda path for
+  // requested_lambda == 0 before calling this primitive.
+  def int_riscv_ime_vsetlambda_nonzero
+      : Intrinsic<[llvm_anyint_ty], [LLVMMatchType<0>],
+                  [IntrNoMem, IntrHasSideEffects]>;
+} // TargetPrefix = "riscv"
+
 // Vendor extensions
 
//===----------------------------------------------------------------------===//
 include "llvm/IR/IntrinsicsRISCVXTHead.td"
diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp 
b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
index 753901d71baca..3e3d384ce76e5 100644
--- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
+++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
@@ -11567,6 +11567,279 @@ static SDValue lowerGetVectorLength(SDNode *N, 
SelectionDAG &DAG,
   return DAG.getNode(ISD::TRUNCATE, DL, N->getValueType(0), Res);
 }
 
+static unsigned getIMELambdaShift(const RISCVSubtarget &Subtarget) {
+  return Subtarget.getXLen() - 4;
+}
+
+static uint64_t getIMELambdaFieldMask(const RISCVSubtarget &Subtarget) {
+  return UINT64_C(7) << getIMELambdaShift(Subtarget);
+}
+
+static uint64_t getIMEClearLambdaMask(const RISCVSubtarget &Subtarget) {
+  uint64_t Mask = ~getIMELambdaFieldMask(Subtarget);
+  if (!Subtarget.is64Bit())
+    Mask = static_cast<uint32_t>(Mask);
+  return Mask;
+}
+
+static bool isValidIMELambdaValue(uint64_t Value) {
+  return Value != 0 && Value <= 64 && isPowerOf2_64(Value);
+}
+
+// The IME implementation lambda is derived from implementation VLEN using the
+// representative shape from the spec:
+//
+//   VLEN = 64 * lambda^2
+//
+// For a known VLEN in bits this gives:
+//
+//   log2(lambda) = (log2(VLEN) - log2(64)) / 2
+//                = (log2(VLEN) - 6) / 2
+//
+// Values below VLEN=64 produce lambda=1.  The selected vtype.lambda encoding
+// has seven non-zero values, so the maxi...
[truncated]

``````````

</details>


https://github.com/llvm/llvm-project/pull/203774
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to