@@ -672,6 +672,10 @@ class ESIMDIntrinDescTable {
672
672
{" slm_init" , {" slm.init" , {a (0 )}}},
673
673
{" bf_cvt" , {" bf.cvt" , {a (0 )}}},
674
674
{" tf32_cvt" , {" tf32.cvt" , {a (0 )}}},
675
+ {" __devicelib_ConvertFToBF16INTEL" ,
676
+ {" __spirv_ConvertFToBF16INTEL" , {a (0 )}}},
677
+ {" __devicelib_ConvertBF16ToFINTEL" ,
678
+ {" __spirv_ConvertBF16ToFINTEL" , {a (0 )}}},
675
679
{" addc" , {" addc" , {l (0 )}}},
676
680
{" subb" , {" subb" , {l (0 )}}},
677
681
{" bfn" , {" bfn" , {a (0 ), a (1 ), a (2 ), t (0 )}}}};
@@ -703,6 +707,28 @@ static const ESIMDIntrinDesc &getIntrinDesc(StringRef SrcSpelling) {
703
707
return It->second ;
704
708
}
705
709
710
+ static bool isDevicelibFunction (StringRef FunctionName) {
711
+ return llvm::StringSwitch<bool >(FunctionName)
712
+ .Case (" __devicelib_ConvertFToBF16INTEL" , true )
713
+ .Case (" __devicelib_ConvertBF16ToFINTEL" , true )
714
+ .Default (false );
715
+ }
716
+
717
+ // Mangle deviceLib function to make it pass through the regular workflow
718
+ // These functions are defined as extern "C" which Demangler that is used
719
+ // fails to handle properly.
720
+ static std::string mangleDevicelibFunction (StringRef FunctionName) {
721
+ if (isDevicelibFunction (FunctionName)) {
722
+ if (FunctionName.startswith (" __devicelib_ConvertFToBF16INTEL" )) {
723
+ return (Twine (" _Z31" ) + FunctionName + " RKf" ).str ();
724
+ }
725
+ if (FunctionName.startswith (" __devicelib_ConvertBF16ToFINTEL" )) {
726
+ return (Twine (" _Z31" ) + FunctionName + " RKt" ).str ();
727
+ }
728
+ }
729
+ return FunctionName.str ();
730
+ }
731
+
706
732
Type *parsePrimitiveTypeString (StringRef TyStr, LLVMContext &Ctx) {
707
733
return llvm::StringSwitch<Type *>(TyStr)
708
734
.Case (" bool" , IntegerType::getInt1Ty (Ctx))
@@ -1326,6 +1352,46 @@ static void createESIMDIntrinsicArgs(const ESIMDIntrinDesc &Desc,
1326
1352
}
1327
1353
}
1328
1354
1355
+ // Create a spirv function declaration
1356
+ // This is used for lowering devicelib functions.
1357
+ // The function
1358
+ // 1. Generates spirv function definition
1359
+ // 2. Converts passed by reference argument of devicelib function into passed by
1360
+ // value argument of spirv functions
1361
+ // 3. Assigns proper attributes to generated function
1362
+ static Function *
1363
+ createDeviceLibESIMDDeclaration (const ESIMDIntrinDesc &Desc,
1364
+ SmallVector<Value *, 16 > &GenXArgs,
1365
+ CallInst &CI) {
1366
+ SmallVector<Type *, 16 > ArgTypes;
1367
+ IRBuilder<> Bld (&CI);
1368
+ for (unsigned i = 0 ; i < GenXArgs.size (); ++i) {
1369
+ Type *NTy = llvm::StringSwitch<Type *>(Desc.GenXSpelling )
1370
+ .Case (" __spirv_ConvertFToBF16INTEL" ,
1371
+ Type::getFloatTy (CI.getContext ()))
1372
+ .Case (" __spirv_ConvertBF16ToFINTEL" ,
1373
+ Type::getInt16Ty (CI.getContext ()))
1374
+ .Default (nullptr );
1375
+
1376
+ auto LI = Bld.CreateLoad (NTy, GenXArgs[i]);
1377
+ GenXArgs[i] = LI;
1378
+ ArgTypes.push_back (NTy);
1379
+ }
1380
+ auto *FType = FunctionType::get (CI.getType (), ArgTypes, false );
1381
+ Function *F = CI.getModule ()->getFunction (Desc.GenXSpelling );
1382
+ if (!F) {
1383
+ F = Function::Create (FType, GlobalVariable::ExternalLinkage,
1384
+ Desc.GenXSpelling , CI.getModule ());
1385
+ F->addFnAttr (Attribute::NoUnwind);
1386
+ F->addFnAttr (Attribute::Convergent);
1387
+ F->setDSOLocal (true );
1388
+
1389
+ F->setCallingConv (CallingConv::SPIR_FUNC);
1390
+ }
1391
+
1392
+ return F;
1393
+ }
1394
+
1329
1395
// Create a simple function declaration
1330
1396
// This is used for testing purposes, when it is impossible to query
1331
1397
// vc-intrinsics
@@ -1403,7 +1469,9 @@ static void translateESIMDIntrinsicCall(CallInst &CI) {
1403
1469
using Demangler = id::ManglingParser<SimpleAllocator>;
1404
1470
Function *F = CI.getCalledFunction ();
1405
1471
llvm::esimd::assert_and_diag (F, " function to translate is invalid" );
1406
- StringRef MnglName = F->getName ();
1472
+ std::string MnglNameStr = mangleDevicelibFunction (F->getName ());
1473
+ StringRef MnglName = MnglNameStr;
1474
+
1407
1475
Demangler Parser (MnglName.begin (), MnglName.end ());
1408
1476
id::Node *AST = Parser.parse ();
1409
1477
@@ -1416,7 +1484,9 @@ static void translateESIMDIntrinsicCall(CallInst &CI) {
1416
1484
auto *FE = static_cast <id::FunctionEncoding *>(AST);
1417
1485
id::StringView BaseNameV = FE->getName ()->getBaseName ();
1418
1486
1419
- auto PrefLen = StringRef (ESIMD_INTRIN_PREF1).size ();
1487
+ auto PrefLen = isDevicelibFunction (F->getName ())
1488
+ ? 0
1489
+ : StringRef (ESIMD_INTRIN_PREF1).size ();
1420
1490
StringRef BaseName (BaseNameV.begin () + PrefLen, BaseNameV.size () - PrefLen);
1421
1491
const auto &Desc = getIntrinDesc (BaseName);
1422
1492
if (!Desc.isValid ()) // TODO remove this once all intrinsics are supported
@@ -1429,7 +1499,9 @@ static void translateESIMDIntrinsicCall(CallInst &CI) {
1429
1499
Function *NewFDecl = nullptr ;
1430
1500
bool DoesFunctionReturnStructure =
1431
1501
isStructureReturningFunction (Desc.GenXSpelling );
1432
- if (Desc.GenXSpelling .rfind (" test.src." , 0 ) == 0 ) {
1502
+ if (isDevicelibFunction (F->getName ())) {
1503
+ NewFDecl = createDeviceLibESIMDDeclaration (Desc, GenXArgs, CI);
1504
+ } else if (Desc.GenXSpelling .rfind (" test.src." , 0 ) == 0 ) {
1433
1505
// Special case for testing purposes
1434
1506
NewFDecl = createTestESIMDDeclaration (Desc, GenXArgs, CI);
1435
1507
} else {
@@ -1724,7 +1796,7 @@ size_t SYCLLowerESIMDPass::runOnFunction(Function &F,
1724
1796
1725
1797
// See if the Name represents an ESIMD intrinsic and demangle only if it
1726
1798
// does.
1727
- if (!Name.consume_front (ESIMD_INTRIN_PREF0))
1799
+ if (!Name.consume_front (ESIMD_INTRIN_PREF0) && ! isDevicelibFunction (Name) )
1728
1800
continue ;
1729
1801
// now skip the digits
1730
1802
Name = Name.drop_while ([](char C) { return std::isdigit (C); });
@@ -1771,7 +1843,8 @@ size_t SYCLLowerESIMDPass::runOnFunction(Function &F,
1771
1843
assert (!Name.startswith (" __sycl_set_kernel_properties" ) &&
1772
1844
" __sycl_set_kernel_properties must have been lowered" );
1773
1845
1774
- if (Name.empty () || !Name.startswith (ESIMD_INTRIN_PREF1))
1846
+ if (Name.empty () ||
1847
+ (!Name.startswith (ESIMD_INTRIN_PREF1) && !isDevicelibFunction (Name)))
1775
1848
continue ;
1776
1849
// this is ESIMD intrinsic - record for later translation
1777
1850
ESIMDIntrCalls.push_back (CI);
0 commit comments