Skip to content

[Clang][RISCV] Handle RVV tuple types correctly as InputOperand/OutputOperand for inline asm #89883

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

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 25 additions & 15 deletions clang/lib/CodeGen/CGStmt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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);
}
Expand Down Expand Up @@ -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);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// 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));
}

// 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));
}
11 changes: 9 additions & 2 deletions llvm/lib/IR/InlineAsm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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());
Expand Down
Loading