@@ -216,6 +216,8 @@ class SPIRVEmitIntrinsics
216216 bool processFunctionPointers (Module &M);
217217 void parseFunDeclarations (Module &M);
218218
219+ void useRoundingMode (ConstrainedFPIntrinsic *FPI, IRBuilder<> &B);
220+
219221public:
220222 static char ID;
221223 SPIRVEmitIntrinsics () : ModulePass(ID) {
@@ -1291,6 +1293,37 @@ void SPIRVEmitIntrinsics::preprocessCompositeConstants(IRBuilder<> &B) {
12911293 }
12921294}
12931295
1296+ static void createDecorationIntrinsic (Instruction *I, MDNode *Node,
1297+ IRBuilder<> &B) {
1298+ LLVMContext &Ctx = I->getContext ();
1299+ setInsertPointAfterDef (B, I);
1300+ B.CreateIntrinsic (Intrinsic::spv_assign_decoration, {I->getType ()},
1301+ {I, MetadataAsValue::get (Ctx, MDNode::get (Ctx, {Node}))});
1302+ }
1303+
1304+ static void createRoundingModeDecoration (Instruction *I,
1305+ unsigned RoundingModeDeco,
1306+ IRBuilder<> &B) {
1307+ LLVMContext &Ctx = I->getContext ();
1308+ Type *Int32Ty = Type::getInt32Ty (Ctx);
1309+ MDNode *RoundingModeNode = MDNode::get (
1310+ Ctx,
1311+ {ConstantAsMetadata::get (
1312+ ConstantInt::get (Int32Ty, SPIRV::Decoration::FPRoundingMode)),
1313+ ConstantAsMetadata::get (ConstantInt::get (Int32Ty, RoundingModeDeco))});
1314+ createDecorationIntrinsic (I, RoundingModeNode, B);
1315+ }
1316+
1317+ static void createSaturatedConversionDecoration (Instruction *I,
1318+ IRBuilder<> &B) {
1319+ LLVMContext &Ctx = I->getContext ();
1320+ Type *Int32Ty = Type::getInt32Ty (Ctx);
1321+ MDNode *SaturatedConversionNode =
1322+ MDNode::get (Ctx, {ConstantAsMetadata::get (ConstantInt::get (
1323+ Int32Ty, SPIRV::Decoration::SaturatedConversion))});
1324+ createDecorationIntrinsic (I, SaturatedConversionNode, B);
1325+ }
1326+
12941327Instruction *SPIRVEmitIntrinsics::visitCallInst (CallInst &Call) {
12951328 if (!Call.isInlineAsm ())
12961329 return &Call;
@@ -1312,6 +1345,40 @@ Instruction *SPIRVEmitIntrinsics::visitCallInst(CallInst &Call) {
13121345 return &Call;
13131346}
13141347
1348+ // Use a tip about rounding mode to create a decoration.
1349+ void SPIRVEmitIntrinsics::useRoundingMode (ConstrainedFPIntrinsic *FPI,
1350+ IRBuilder<> &B) {
1351+ std::optional<RoundingMode> RM = FPI->getRoundingMode ();
1352+ if (!RM.has_value ())
1353+ return ;
1354+ unsigned RoundingModeDeco = std::numeric_limits<unsigned >::max ();
1355+ switch (RM.value ()) {
1356+ default :
1357+ // ignore unknown rounding modes
1358+ break ;
1359+ case RoundingMode::NearestTiesToEven:
1360+ RoundingModeDeco = SPIRV::FPRoundingMode::FPRoundingMode::RTE;
1361+ break ;
1362+ case RoundingMode::TowardNegative:
1363+ RoundingModeDeco = SPIRV::FPRoundingMode::FPRoundingMode::RTN;
1364+ break ;
1365+ case RoundingMode::TowardPositive:
1366+ RoundingModeDeco = SPIRV::FPRoundingMode::FPRoundingMode::RTP;
1367+ break ;
1368+ case RoundingMode::TowardZero:
1369+ RoundingModeDeco = SPIRV::FPRoundingMode::FPRoundingMode::RTZ;
1370+ break ;
1371+ case RoundingMode::Dynamic:
1372+ case RoundingMode::NearestTiesToAway:
1373+ // TODO: check if supported
1374+ break ;
1375+ }
1376+ if (RoundingModeDeco == std::numeric_limits<unsigned >::max ())
1377+ return ;
1378+ // Convert the tip about rounding mode into a decoration record.
1379+ createRoundingModeDecoration (FPI, RoundingModeDeco, B);
1380+ }
1381+
13151382Instruction *SPIRVEmitIntrinsics::visitSwitchInst (SwitchInst &I) {
13161383 BasicBlock *ParentBB = I.getParent ();
13171384 IRBuilder<> B (ParentBB);
@@ -1809,6 +1876,18 @@ bool SPIRVEmitIntrinsics::insertAssignPtrTypeIntrs(Instruction *I,
18091876 return true ;
18101877}
18111878
1879+ static unsigned roundingModeMDToDecorationConst (StringRef S) {
1880+ if (S == " rte" )
1881+ return SPIRV::FPRoundingMode::FPRoundingMode::RTE;
1882+ if (S == " rtz" )
1883+ return SPIRV::FPRoundingMode::FPRoundingMode::RTZ;
1884+ if (S == " rtp" )
1885+ return SPIRV::FPRoundingMode::FPRoundingMode::RTP;
1886+ if (S == " rtn" )
1887+ return SPIRV::FPRoundingMode::FPRoundingMode::RTN;
1888+ return std::numeric_limits<unsigned >::max ();
1889+ }
1890+
18121891void SPIRVEmitIntrinsics::insertAssignTypeIntrs (Instruction *I,
18131892 IRBuilder<> &B) {
18141893 // TODO: extend the list of functions with known result types
@@ -1826,8 +1905,9 @@ void SPIRVEmitIntrinsics::insertAssignTypeIntrs(Instruction *I,
18261905 Function *CalledF = CI->getCalledFunction ();
18271906 std::string DemangledName =
18281907 getOclOrSpirvBuiltinDemangledName (CalledF->getName ());
1908+ std::string Postfix;
18291909 if (DemangledName.length () > 0 )
1830- DemangledName = SPIRV::lookupBuiltinNameHelper (DemangledName);
1910+ DemangledName = SPIRV::lookupBuiltinNameHelper (DemangledName, &Postfix );
18311911 auto ResIt = ResTypeWellKnown.find (DemangledName);
18321912 if (ResIt != ResTypeWellKnown.end ()) {
18331913 IsKnown = true ;
@@ -1839,6 +1919,19 @@ void SPIRVEmitIntrinsics::insertAssignTypeIntrs(Instruction *I,
18391919 break ;
18401920 }
18411921 }
1922+ // check if a floating rounding mode info is present
1923+ StringRef S = Postfix;
1924+ SmallVector<StringRef, 8 > Parts;
1925+ S.split (Parts, " _" , -1 , false );
1926+ if (Parts.size () > 1 ) {
1927+ // Convert the info about rounding mode into a decoration record.
1928+ unsigned RoundingModeDeco = roundingModeMDToDecorationConst (Parts[1 ]);
1929+ if (RoundingModeDeco != std::numeric_limits<unsigned >::max ())
1930+ createRoundingModeDecoration (CI, RoundingModeDeco, B);
1931+ // Check if the SaturatedConversion info is present.
1932+ if (Parts[1 ] == " sat" )
1933+ createSaturatedConversionDecoration (CI, B);
1934+ }
18421935 }
18431936 }
18441937
@@ -2264,6 +2357,9 @@ bool SPIRVEmitIntrinsics::runOnFunction(Function &Func) {
22642357 // already, and force it to be i8 if not
22652358 if (Postpone && !GR->findAssignPtrTypeInstr (I))
22662359 insertAssignPtrTypeIntrs (I, B, true );
2360+
2361+ if (auto *FPI = dyn_cast<ConstrainedFPIntrinsic>(I))
2362+ useRoundingMode (FPI, B);
22672363 }
22682364
22692365 // Pass backward: use instructions results to specify/update/cast operands
0 commit comments