Skip to content

Commit 8b90033

Browse files
committed
[clang][RISCV] Fix crash on VLS calling convention
This patch handle struct of fixed vector and struct of array of fixed vector correctly for VLS calling convention in EmitFunctionProlog, EmitFunctionEpilog and EmitCall.
1 parent 9f66ebe commit 8b90033

File tree

3 files changed

+246
-46
lines changed

3 files changed

+246
-46
lines changed

clang/lib/CodeGen/CGCall.cpp

Lines changed: 153 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
#include "llvm/IR/InlineAsm.h"
4242
#include "llvm/IR/IntrinsicInst.h"
4343
#include "llvm/IR/Intrinsics.h"
44+
#include "llvm/IR/IntrinsicsRISCV.h"
4445
#include "llvm/IR/Type.h"
4546
#include "llvm/Transforms/Utils/Local.h"
4647
#include <optional>
@@ -1329,9 +1330,77 @@ static llvm::Value *CreateCoercedLoad(Address Src, llvm::Type *Ty,
13291330
llvm::TypeSize DstSize = CGF.CGM.getDataLayout().getTypeAllocSize(Ty);
13301331

13311332
if (llvm::StructType *SrcSTy = dyn_cast<llvm::StructType>(SrcTy)) {
1332-
Src = EnterStructPointerForCoercedAccess(Src, SrcSTy,
1333-
DstSize.getFixedValue(), CGF);
1334-
SrcTy = Src.getElementType();
1333+
if (llvm::TargetExtType *TupTy = dyn_cast<llvm::TargetExtType>(Ty)) {
1334+
// In RISC-V VLS calling convention, struct of fixed vectors or struct of
1335+
// array of fixed vector of length >1 might be lowered using vector tuple
1336+
// type, we consider it as a valid load, e.g.
1337+
// struct i32x4x2 {
1338+
// __attribute__((vector_size(16))) int i;
1339+
// __attribute__((vector_size(16))) int i;
1340+
// };
1341+
// or
1342+
// struct i32x4 {
1343+
// __attribute__((vector_size(16))) int i[2];
1344+
// };
1345+
// is lowered to target("riscv.vector.tuple", <vscale x 8 x i8>, 2)
1346+
// when ABI_VLEN = 128 bits, please checkout
1347+
// clang/test/CodeGen/RISCV/riscv-vector-callingconv-llvm-ir.c
1348+
// for more information.
1349+
assert(TupTy->getName() == "riscv.vector.tuple");
1350+
llvm::Type *EltTy = TupTy->getTypeParameter(0);
1351+
unsigned NumElts = TupTy->getIntParameter(0);
1352+
1353+
if (auto *ArrayTy = dyn_cast<llvm::ArrayType>(SrcSTy->getElementType(0)))
1354+
Src = Src.withElementType(ArrayTy);
1355+
1356+
// Perform extract element and load
1357+
llvm::Value *PoisonTuple = llvm::PoisonValue::get(Ty);
1358+
auto *Load = CGF.Builder.CreateLoad(Src);
1359+
for (unsigned i = 0; i < NumElts; ++i) {
1360+
// Extract from struct
1361+
llvm::Value *ExtractFromLoad = CGF.Builder.CreateExtractValue(Load, i);
1362+
// Element in vector tuple type is always i8, so we need to cast back to
1363+
// it's original element type.
1364+
EltTy = cast<llvm::ScalableVectorType>(
1365+
llvm::VectorType::getWithSizeAndScalar(
1366+
cast<llvm::VectorType>(EltTy), ExtractFromLoad->getType()));
1367+
llvm::Value *PoisonVec = llvm::PoisonValue::get(EltTy);
1368+
// Insert to scalable vector
1369+
PoisonVec = CGF.Builder.CreateInsertVector(
1370+
EltTy, PoisonVec, ExtractFromLoad, uint64_t(0), "cast.scalable");
1371+
// Insert scalable vector to vector tuple
1372+
llvm::Value *Idx = llvm::ConstantInt::get(CGF.Builder.getInt32Ty(), i);
1373+
PoisonTuple = CGF.Builder.CreateIntrinsic(
1374+
llvm::Intrinsic::riscv_tuple_insert, {Ty, EltTy},
1375+
{PoisonTuple, PoisonVec, Idx});
1376+
}
1377+
return PoisonTuple;
1378+
}
1379+
1380+
if (Ty->isScalableTy()) {
1381+
// In RISC-V VLS calling convention, struct of fixed vector or struct of
1382+
// fixed vector array of length 1 might be lowered using scalable vector,
1383+
// we consider it as a valid load, e.g.
1384+
// struct i32x4 {
1385+
// __attribute__((vector_size(16))) int i;
1386+
// };
1387+
// or
1388+
// struct i32x4 {
1389+
// __attribute__((vector_size(16))) int i[1];
1390+
// };
1391+
// is lowered to <vscale x 2 x i32>
1392+
// when ABI_VLEN = 128 bits, please checkout
1393+
// clang/test/CodeGen/RISCV/riscv-vector-callingconv-llvm-ir.c
1394+
// for more information.
1395+
SrcTy = SrcSTy->getElementType(0);
1396+
if (auto *ArrayTy = dyn_cast<llvm::ArrayType>(SrcTy))
1397+
SrcTy = ArrayTy->getElementType();
1398+
Src = Src.withElementType(SrcTy);
1399+
} else {
1400+
Src = EnterStructPointerForCoercedAccess(Src, SrcSTy,
1401+
DstSize.getFixedValue(), CGF);
1402+
SrcTy = Src.getElementType();
1403+
}
13351404
}
13361405

13371406
llvm::TypeSize SrcSize = CGF.CGM.getDataLayout().getTypeAllocSize(SrcTy);
@@ -1412,6 +1481,87 @@ void CodeGenFunction::CreateCoercedStore(llvm::Value *Src, Address Dst,
14121481
if (SrcTy != Dst.getElementType()) {
14131482
if (llvm::StructType *DstSTy =
14141483
dyn_cast<llvm::StructType>(Dst.getElementType())) {
1484+
if (llvm::TargetExtType *TupTy = dyn_cast<llvm::TargetExtType>(SrcTy)) {
1485+
// In RISC-V VLS calling convention, struct of fixed vectors or struct of
1486+
// array of fixed vector of length >1 might be lowered using vector tuple
1487+
// type, we consider it as a valid load, e.g.
1488+
// struct i32x4x2 {
1489+
// __attribute__((vector_size(16))) int i;
1490+
// __attribute__((vector_size(16))) int i;
1491+
// };
1492+
// or
1493+
// struct i32x4 {
1494+
// __attribute__((vector_size(16))) int i[2];
1495+
// };
1496+
// is lowered to target("riscv.vector.tuple", <vscale x 8 x i8>, 2)
1497+
// when ABI_VLEN = 128 bits, please checkout
1498+
// clang/test/CodeGen/RISCV/riscv-vector-callingconv-llvm-ir.c
1499+
// for more information.
1500+
assert(TupTy->getName() == "riscv.vector.tuple");
1501+
llvm::Type *EltTy = TupTy->getTypeParameter(0);
1502+
unsigned NumElts = TupTy->getIntParameter(0);
1503+
1504+
llvm::Type *FixedVecTy = DstSTy->getElementType(0);
1505+
if (auto *ArrayTy =
1506+
dyn_cast<llvm::ArrayType>(DstSTy->getElementType(0))) {
1507+
Dst = Dst.withElementType(ArrayTy);
1508+
FixedVecTy = ArrayTy->getArrayElementType();
1509+
}
1510+
1511+
// Perform extract element and store
1512+
for (unsigned i = 0; i < NumElts; ++i) {
1513+
// Element in vector tuple type is always i8, so we need to cast back
1514+
// to it's original element type.
1515+
EltTy = cast<llvm::ScalableVectorType>(
1516+
llvm::VectorType::getWithSizeAndScalar(
1517+
cast<llvm::VectorType>(EltTy), FixedVecTy));
1518+
// Extract scalable vector from tuple
1519+
llvm::Value *Idx = llvm::ConstantInt::get(Builder.getInt32Ty(), i);
1520+
auto *TupleElement = Builder.CreateIntrinsic(
1521+
llvm::Intrinsic::riscv_tuple_extract, {EltTy, TupTy}, {Src, Idx});
1522+
1523+
// Extract fixed vector from scalable vector
1524+
auto *ExtractVec = Builder.CreateExtractVector(
1525+
FixedVecTy, TupleElement, uint64_t(0));
1526+
// Store fixed vector to corresponding address
1527+
Address EltPtr = Address::invalid();
1528+
if (Dst.getElementType()->isStructTy())
1529+
EltPtr = Builder.CreateStructGEP(Dst, i);
1530+
else
1531+
EltPtr = Builder.CreateConstArrayGEP(Dst, i);
1532+
auto *I = Builder.CreateStore(ExtractVec, EltPtr, DstIsVolatile);
1533+
addInstToCurrentSourceAtom(I, ExtractVec);
1534+
}
1535+
return;
1536+
}
1537+
1538+
if (SrcTy->isScalableTy()) {
1539+
// In RISC-V VLS calling convention, struct of fixed vector or struct of
1540+
// fixed vector array of length 1 might be lowered using scalable vector,
1541+
// we consider it as a valid load, e.g.
1542+
// struct i32x4 {
1543+
// __attribute__((vector_size(16))) int i;
1544+
// };
1545+
// or
1546+
// struct i32x4 {
1547+
// __attribute__((vector_size(16))) int i[1];
1548+
// };
1549+
// is lowered to <vscale x 2 x i32>
1550+
// when ABI_VLEN = 128 bits, please checkout
1551+
// clang/test/CodeGen/RISCV/riscv-vector-callingconv-llvm-ir.c
1552+
// for more information.
1553+
llvm::Type *EltTy = DstSTy->getElementType(0);
1554+
if (auto *ArrayTy = dyn_cast<llvm::ArrayType>(EltTy)) {
1555+
assert(ArrayTy->getNumElements() == 1);
1556+
EltTy = ArrayTy->getElementType();
1557+
}
1558+
auto *Coerced = Builder.CreateExtractVector(
1559+
cast<llvm::FixedVectorType>(EltTy), Src, uint64_t(0));
1560+
auto *I = Builder.CreateStore(Coerced, Dst, DstIsVolatile);
1561+
addInstToCurrentSourceAtom(I, Src);
1562+
return;
1563+
}
1564+
14151565
assert(!SrcSize.isScalable());
14161566
Dst = EnterStructPointerForCoercedAccess(Dst, DstSTy,
14171567
SrcSize.getFixedValue(), *this);
@@ -3335,17 +3485,6 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI,
33353485
}
33363486
}
33373487

3338-
// Struct of fixed-length vectors and struct of array of fixed-length
3339-
// vector in VLS calling convention are coerced to vector tuple
3340-
// type(represented as TargetExtType) and scalable vector type
3341-
// respectively, they're no longer handled as struct.
3342-
if (ArgI.isDirect() && isa<llvm::StructType>(ConvertType(Ty)) &&
3343-
(isa<llvm::TargetExtType>(ArgI.getCoerceToType()) ||
3344-
isa<llvm::ScalableVectorType>(ArgI.getCoerceToType()))) {
3345-
ArgVals.push_back(ParamValue::forDirect(AI));
3346-
break;
3347-
}
3348-
33493488
llvm::StructType *STy =
33503489
dyn_cast<llvm::StructType>(ArgI.getCoerceToType());
33513490
Address Alloca =

0 commit comments

Comments
 (0)