[clang] [llvm] [Clang][RISCV] Handle RVV tuple types correctly as OutputOperand for inline asm (PR #89883)

Brandon Wu via llvm-commits llvm-commits at lists.llvm.org
Wed Apr 24 00:42:19 PDT 2024


https://github.com/4vtomat updated https://github.com/llvm/llvm-project/pull/89883

>From 671bebcb9ad76aa3b43dabada3ab7a75d6934d73 Mon Sep 17 00:00:00 2001
From: eopXD <yueh.ting.chen at gmail.com>
Date: Thu, 21 Sep 2023 06:34:57 -0700
Subject: [PATCH 1/2] [Clang][RISCV] Handle RVV tuple types correctly as
 InputOperand/OutputOperand for inline asm

The RVV tuple type maps to an aggregate type with homogeneous scalable
vectors. EmitAsmStmt does not handle this correctly and this commit
attempts to fix it.

Get pass validation check for homogeneous scalable vector types in
InlineAsm::verify.

Handle RVV tuple types correctly under CGStmt.cpp:EmitAsmStores, since
we can allow direct store for the tuple types.

A follow-up commit will deal with details when associated with
InputOperands.

Note: Input tuple type operands doesn't need another process since it
can be passed directly.

Co-authored-by: Brandon Wu <brandon.wu at sifive.com>
---
 clang/lib/CodeGen/CGStmt.cpp                  | 40 ++++++++++++-------
 .../rvv-inline-asm.c                          | 29 ++++++++++++++
 llvm/lib/IR/InlineAsm.cpp                     | 11 ++++-
 3 files changed, 63 insertions(+), 17 deletions(-)
 create mode 100644 clang/test/CodeGen/RISCV/rvv-intrinsics-handcrafted/rvv-inline-asm.c

diff --git a/clang/lib/CodeGen/CGStmt.cpp b/clang/lib/CodeGen/CGStmt.cpp
index 576fe2f7a2d46f..099faf419ba5cd 100644
--- a/clang/lib/CodeGen/CGStmt.cpp
+++ b/clang/lib/CodeGen/CGStmt.cpp
@@ -29,6 +29,7 @@
 #include "llvm/ADT/SmallSet.h"
 #include "llvm/ADT/StringExtras.h"
 #include "llvm/IR/Assumptions.h"
+#include "llvm/IR/Constants.h"
 #include "llvm/IR/DataLayout.h"
 #include "llvm/IR/InlineAsm.h"
 #include "llvm/IR/Intrinsics.h"
@@ -2487,22 +2488,28 @@ EmitAsmStores(CodeGenFunction &CGF, const AsmStmt &S,
     // ResultTypeRequiresCast elements correspond to the first
     // ResultTypeRequiresCast.size() elements of RegResults.
     if ((i < ResultTypeRequiresCast.size()) && ResultTypeRequiresCast[i]) {
-      unsigned Size = CGF.getContext().getTypeSize(ResultRegQualTys[i]);
-      Address A = Dest.getAddress(CGF).withElementType(ResultRegTypes[i]);
-      if (CGF.getTargetHooks().isScalarizableAsmOperand(CGF, TruncTy)) {
-        Builder.CreateStore(Tmp, A);
-        continue;
-      }
+      if (ResultRegQualTys[i]->isRVVSizelessBuiltinType() &&
+          Tmp->getType()->isStructTy()) {
+        Address A = Dest.getAddress(CGF).withElementType(ResultRegTypes[i]);
+        Dest = CGF.MakeAddrLValue(A, ResultRegQualTys[i]);
+      } else {
+        unsigned Size = CGF.getContext().getTypeSize(ResultRegQualTys[i]);
+        Address A = Dest.getAddress(CGF).withElementType(ResultRegTypes[i]);
+        if (CGF.getTargetHooks().isScalarizableAsmOperand(CGF, TruncTy)) {
+          Builder.CreateStore(Tmp, A);
+          continue;
+        }
 
-      QualType Ty =
-          CGF.getContext().getIntTypeForBitwidth(Size, /*Signed=*/false);
-      if (Ty.isNull()) {
-        const Expr *OutExpr = S.getOutputExpr(i);
-        CGM.getDiags().Report(OutExpr->getExprLoc(),
-                              diag::err_store_value_to_reg);
-        return;
+        QualType Ty =
+            CGF.getContext().getIntTypeForBitwidth(Size, /*Signed=*/false);
+        if (Ty.isNull()) {
+          const Expr *OutExpr = S.getOutputExpr(i);
+          CGM.getDiags().Report(OutExpr->getExprLoc(),
+                                diag::err_store_value_to_reg);
+          return;
+        }
+        Dest = CGF.MakeAddrLValue(A, Ty);
       }
-      Dest = CGF.MakeAddrLValue(A, Ty);
     }
     CGF.EmitStoreThroughLValue(RValue::get(Tmp), Dest);
   }
@@ -2648,7 +2655,10 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) {
       ResultTruncRegTypes.push_back(Ty);
       ResultTypeRequiresCast.push_back(RequiresCast);
 
-      if (RequiresCast) {
+      // Allow RVV tuple type (aggregate of homogeneous scalable vector) to be
+      // pushed into return type of inline asm call.
+      if (RequiresCast &&
+          !(QTy->isRVVSizelessBuiltinType() && Ty->isStructTy())) {
         unsigned Size = getContext().getTypeSize(QTy);
         Ty = llvm::IntegerType::get(getLLVMContext(), Size);
       }
diff --git a/clang/test/CodeGen/RISCV/rvv-intrinsics-handcrafted/rvv-inline-asm.c b/clang/test/CodeGen/RISCV/rvv-intrinsics-handcrafted/rvv-inline-asm.c
new file mode 100644
index 00000000000000..c5beb33d0ef8cd
--- /dev/null
+++ b/clang/test/CodeGen/RISCV/rvv-intrinsics-handcrafted/rvv-inline-asm.c
@@ -0,0 +1,29 @@
+// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 3
+#include <riscv_vector.h>
+
+// RUN: %clang_cc1 -triple riscv64 -target-feature +zve32x -disable-O0-optnone \
+// RUN:   -emit-llvm %s -o - | opt -S -passes=mem2reg | FileCheck %s
+
+// CHECK-LABEL: define dso_local void @foo(
+// CHECK-SAME: ) #[[ATTR0:[0-9]+]] {
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:    [[TMP0:%.*]] = call { <vscale x 2 x i32>, <vscale x 2 x i32> } asm "#NOP", "=^vr"() #[[ATTR1:[0-9]+]], !srcloc [[META6:![0-9]+]]
+// CHECK-NEXT:    ret void
+//
+void foo() {
+  vint32m1x2_t v0;
+  asm ("#NOP" : "=vr" (v0));
+}
+
+// CHECK-LABEL: define dso_local void @bar(
+// CHECK-SAME: ) #[[ATTR0]] {
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:    [[TMP0:%.*]] = call { { <vscale x 2 x i32>, <vscale x 2 x i32> }, { <vscale x 2 x i32>, <vscale x 2 x i32> } } asm "#NOP", "=^vr,=^vr"() #[[ATTR1]], !srcloc [[META7:![0-9]+]]
+// CHECK-NEXT:    [[ASMRESULT:%.*]] = extractvalue { { <vscale x 2 x i32>, <vscale x 2 x i32> }, { <vscale x 2 x i32>, <vscale x 2 x i32> } } [[TMP0]], 0
+// CHECK-NEXT:    [[ASMRESULT1:%.*]] = extractvalue { { <vscale x 2 x i32>, <vscale x 2 x i32> }, { <vscale x 2 x i32>, <vscale x 2 x i32> } } [[TMP0]], 1
+// CHECK-NEXT:    ret void
+//
+void bar() {
+  vint32m1x2_t v0, v2;
+  asm ("#NOP" : "=vr" (v0), "=vr" (v2));
+}
diff --git a/llvm/lib/IR/InlineAsm.cpp b/llvm/lib/IR/InlineAsm.cpp
index aeaa6a3741b949..319678cbb8fe16 100644
--- a/llvm/lib/IR/InlineAsm.cpp
+++ b/llvm/lib/IR/InlineAsm.cpp
@@ -321,8 +321,15 @@ Error InlineAsm::verify(FunctionType *Ty, StringRef ConstStr) {
       return makeStringError("inline asm without outputs must return void");
     break;
   case 1:
-    if (Ty->getReturnType()->isStructTy())
-      return makeStringError("inline asm with one output cannot return struct");
+    if (Ty->getReturnType()->isStructTy()) {
+      // The return type may be a structure if the output operand is from RVV
+      // tuple types. If so the structure must be a structure with homogeneous
+      // scalable vector types.
+      if (!cast<StructType>(Ty->getReturnType())
+               ->containsHomogeneousScalableVectorTypes())
+        return makeStringError(
+            "inline asm with one output cannot return struct");
+    }
     break;
   default:
     StructType *STy = dyn_cast<StructType>(Ty->getReturnType());

>From 47ea7b6f5b99b960cb49b9dd947715fb23879f2b Mon Sep 17 00:00:00 2001
From: Brandon Wu <brandon.wu at sifive.com>
Date: Wed, 24 Apr 2024 00:41:27 -0700
Subject: [PATCH 2/2] fixup! Add input operand test case

---
 .../RISCV/rvv-intrinsics-handcrafted/rvv-inline-asm.c | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/clang/test/CodeGen/RISCV/rvv-intrinsics-handcrafted/rvv-inline-asm.c b/clang/test/CodeGen/RISCV/rvv-intrinsics-handcrafted/rvv-inline-asm.c
index c5beb33d0ef8cd..dc17fa45cc602f 100644
--- a/clang/test/CodeGen/RISCV/rvv-intrinsics-handcrafted/rvv-inline-asm.c
+++ b/clang/test/CodeGen/RISCV/rvv-intrinsics-handcrafted/rvv-inline-asm.c
@@ -27,3 +27,14 @@ void bar() {
   vint32m1x2_t v0, v2;
   asm ("#NOP" : "=vr" (v0), "=vr" (v2));
 }
+
+// CHECK-LABEL: define dso_local void @baz(
+// CHECK-SAME: ) #[[ATTR0:[0-9]+]] {
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:    call void asm sideeffect "#NOP", "^vr"({ <vscale x 2 x i32>, <vscale x 2 x i32> } undef) #[[ATTR1:[0-9]+]], !srcloc [[META6:![0-9]+]]
+// CHECK-NEXT:    ret void
+//
+void baz() {
+  vint32m1x2_t v2;
+  asm ("#NOP" :: "vr" (v2));
+}



More information about the llvm-commits mailing list