|
41 | 41 | #include "llvm/IR/InlineAsm.h"
|
42 | 42 | #include "llvm/IR/IntrinsicInst.h"
|
43 | 43 | #include "llvm/IR/Intrinsics.h"
|
| 44 | +#include "llvm/IR/IntrinsicsRISCV.h" |
44 | 45 | #include "llvm/IR/Type.h"
|
45 | 46 | #include "llvm/Transforms/Utils/Local.h"
|
46 | 47 | #include <optional>
|
@@ -1329,9 +1330,77 @@ static llvm::Value *CreateCoercedLoad(Address Src, llvm::Type *Ty,
|
1329 | 1330 | llvm::TypeSize DstSize = CGF.CGM.getDataLayout().getTypeAllocSize(Ty);
|
1330 | 1331 |
|
1331 | 1332 | 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 | + } |
1335 | 1404 | }
|
1336 | 1405 |
|
1337 | 1406 | llvm::TypeSize SrcSize = CGF.CGM.getDataLayout().getTypeAllocSize(SrcTy);
|
@@ -1412,6 +1481,87 @@ void CodeGenFunction::CreateCoercedStore(llvm::Value *Src, Address Dst,
|
1412 | 1481 | if (SrcTy != Dst.getElementType()) {
|
1413 | 1482 | if (llvm::StructType *DstSTy =
|
1414 | 1483 | 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 |
| 1486 | + // of array of fixed vector of length >1 might be lowered using vector |
| 1487 | + // tuple 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 |
| 1541 | + // vector, 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 | + |
1415 | 1565 | assert(!SrcSize.isScalable());
|
1416 | 1566 | Dst = EnterStructPointerForCoercedAccess(Dst, DstSTy,
|
1417 | 1567 | SrcSize.getFixedValue(), *this);
|
@@ -3335,17 +3485,6 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI,
|
3335 | 3485 | }
|
3336 | 3486 | }
|
3337 | 3487 |
|
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 |
| - |
3349 | 3488 | llvm::StructType *STy =
|
3350 | 3489 | dyn_cast<llvm::StructType>(ArgI.getCoerceToType());
|
3351 | 3490 | Address Alloca =
|
|
0 commit comments