xref: /freebsd/contrib/llvm-project/llvm/lib/IR/FPEnv.cpp (revision bdd1243df58e60e85101c09001d9812a789b6bc4)
1480093f4SDimitry Andric //===-- FPEnv.cpp ---- FP Environment -------------------------------------===//
2480093f4SDimitry Andric //
3480093f4SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4480093f4SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5480093f4SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6480093f4SDimitry Andric //
7480093f4SDimitry Andric //===----------------------------------------------------------------------===//
8480093f4SDimitry Andric //
9480093f4SDimitry Andric /// @file
10480093f4SDimitry Andric /// This file contains the implementations of entities that describe floating
11480093f4SDimitry Andric /// point environment.
12480093f4SDimitry Andric //
13480093f4SDimitry Andric //===----------------------------------------------------------------------===//
14480093f4SDimitry Andric 
15480093f4SDimitry Andric #include "llvm/IR/FPEnv.h"
165ffd83dbSDimitry Andric #include "llvm/ADT/StringSwitch.h"
1781ad6265SDimitry Andric #include "llvm/IR/Instruction.h"
1881ad6265SDimitry Andric #include "llvm/IR/IntrinsicInst.h"
1981ad6265SDimitry Andric #include "llvm/IR/Intrinsics.h"
20*bdd1243dSDimitry Andric #include <optional>
21480093f4SDimitry Andric 
22480093f4SDimitry Andric namespace llvm {
23480093f4SDimitry Andric 
convertStrToRoundingMode(StringRef RoundingArg)24*bdd1243dSDimitry Andric std::optional<RoundingMode> convertStrToRoundingMode(StringRef RoundingArg) {
25480093f4SDimitry Andric   // For dynamic rounding mode, we use round to nearest but we will set the
26480093f4SDimitry Andric   // 'exact' SDNodeFlag so that the value will not be rounded.
27*bdd1243dSDimitry Andric   return StringSwitch<std::optional<RoundingMode>>(RoundingArg)
285ffd83dbSDimitry Andric       .Case("round.dynamic", RoundingMode::Dynamic)
295ffd83dbSDimitry Andric       .Case("round.tonearest", RoundingMode::NearestTiesToEven)
305ffd83dbSDimitry Andric       .Case("round.tonearestaway", RoundingMode::NearestTiesToAway)
315ffd83dbSDimitry Andric       .Case("round.downward", RoundingMode::TowardNegative)
325ffd83dbSDimitry Andric       .Case("round.upward", RoundingMode::TowardPositive)
335ffd83dbSDimitry Andric       .Case("round.towardzero", RoundingMode::TowardZero)
34*bdd1243dSDimitry Andric       .Default(std::nullopt);
35480093f4SDimitry Andric }
36480093f4SDimitry Andric 
convertRoundingModeToStr(RoundingMode UseRounding)37*bdd1243dSDimitry Andric std::optional<StringRef> convertRoundingModeToStr(RoundingMode UseRounding) {
38*bdd1243dSDimitry Andric   std::optional<StringRef> RoundingStr;
39480093f4SDimitry Andric   switch (UseRounding) {
405ffd83dbSDimitry Andric   case RoundingMode::Dynamic:
41480093f4SDimitry Andric     RoundingStr = "round.dynamic";
42480093f4SDimitry Andric     break;
435ffd83dbSDimitry Andric   case RoundingMode::NearestTiesToEven:
44480093f4SDimitry Andric     RoundingStr = "round.tonearest";
45480093f4SDimitry Andric     break;
465ffd83dbSDimitry Andric   case RoundingMode::NearestTiesToAway:
475ffd83dbSDimitry Andric     RoundingStr = "round.tonearestaway";
485ffd83dbSDimitry Andric     break;
495ffd83dbSDimitry Andric   case RoundingMode::TowardNegative:
50480093f4SDimitry Andric     RoundingStr = "round.downward";
51480093f4SDimitry Andric     break;
525ffd83dbSDimitry Andric   case RoundingMode::TowardPositive:
53480093f4SDimitry Andric     RoundingStr = "round.upward";
54480093f4SDimitry Andric     break;
555ffd83dbSDimitry Andric   case RoundingMode::TowardZero:
56480093f4SDimitry Andric     RoundingStr = "round.towardzero";
57480093f4SDimitry Andric     break;
585ffd83dbSDimitry Andric   default:
595ffd83dbSDimitry Andric     break;
60480093f4SDimitry Andric   }
61480093f4SDimitry Andric   return RoundingStr;
62480093f4SDimitry Andric }
63480093f4SDimitry Andric 
64*bdd1243dSDimitry Andric std::optional<fp::ExceptionBehavior>
convertStrToExceptionBehavior(StringRef ExceptionArg)65349cc55cSDimitry Andric convertStrToExceptionBehavior(StringRef ExceptionArg) {
66*bdd1243dSDimitry Andric   return StringSwitch<std::optional<fp::ExceptionBehavior>>(ExceptionArg)
67480093f4SDimitry Andric       .Case("fpexcept.ignore", fp::ebIgnore)
68480093f4SDimitry Andric       .Case("fpexcept.maytrap", fp::ebMayTrap)
69480093f4SDimitry Andric       .Case("fpexcept.strict", fp::ebStrict)
70*bdd1243dSDimitry Andric       .Default(std::nullopt);
71480093f4SDimitry Andric }
72480093f4SDimitry Andric 
73*bdd1243dSDimitry Andric std::optional<StringRef>
convertExceptionBehaviorToStr(fp::ExceptionBehavior UseExcept)74349cc55cSDimitry Andric convertExceptionBehaviorToStr(fp::ExceptionBehavior UseExcept) {
75*bdd1243dSDimitry Andric   std::optional<StringRef> ExceptStr;
76480093f4SDimitry Andric   switch (UseExcept) {
77480093f4SDimitry Andric   case fp::ebStrict:
78480093f4SDimitry Andric     ExceptStr = "fpexcept.strict";
79480093f4SDimitry Andric     break;
80480093f4SDimitry Andric   case fp::ebIgnore:
81480093f4SDimitry Andric     ExceptStr = "fpexcept.ignore";
82480093f4SDimitry Andric     break;
83480093f4SDimitry Andric   case fp::ebMayTrap:
84480093f4SDimitry Andric     ExceptStr = "fpexcept.maytrap";
85480093f4SDimitry Andric     break;
86480093f4SDimitry Andric   }
87480093f4SDimitry Andric   return ExceptStr;
88480093f4SDimitry Andric }
8981ad6265SDimitry Andric 
getConstrainedIntrinsicID(const Instruction & Instr)9081ad6265SDimitry Andric Intrinsic::ID getConstrainedIntrinsicID(const Instruction &Instr) {
9181ad6265SDimitry Andric   Intrinsic::ID IID = Intrinsic::not_intrinsic;
9281ad6265SDimitry Andric   switch (Instr.getOpcode()) {
9381ad6265SDimitry Andric   case Instruction::FCmp:
9481ad6265SDimitry Andric     // Unlike other instructions FCmp can be mapped to one of two intrinsic
9581ad6265SDimitry Andric     // functions. We choose the non-signaling variant.
9681ad6265SDimitry Andric     IID = Intrinsic::experimental_constrained_fcmp;
9781ad6265SDimitry Andric     break;
9881ad6265SDimitry Andric 
9981ad6265SDimitry Andric     // Instructions
10081ad6265SDimitry Andric #define INSTRUCTION(NAME, NARG, ROUND_MODE, INTRINSIC)                         \
10181ad6265SDimitry Andric   case Instruction::NAME:                                                      \
10281ad6265SDimitry Andric     IID = Intrinsic::INTRINSIC;                                                \
10381ad6265SDimitry Andric     break;
10481ad6265SDimitry Andric #define FUNCTION(NAME, NARG, ROUND_MODE, INTRINSIC)
10581ad6265SDimitry Andric #define CMP_INSTRUCTION(NAME, NARG, ROUND_MODE, INTRINSIC, DAGN)
10681ad6265SDimitry Andric #include "llvm/IR/ConstrainedOps.def"
10781ad6265SDimitry Andric 
10881ad6265SDimitry Andric   // Intrinsic calls.
10981ad6265SDimitry Andric   case Instruction::Call:
11081ad6265SDimitry Andric     if (auto *IntrinCall = dyn_cast<IntrinsicInst>(&Instr)) {
11181ad6265SDimitry Andric       switch (IntrinCall->getIntrinsicID()) {
11281ad6265SDimitry Andric #define FUNCTION(NAME, NARG, ROUND_MODE, INTRINSIC)                            \
11381ad6265SDimitry Andric   case Intrinsic::NAME:                                                        \
11481ad6265SDimitry Andric     IID = Intrinsic::INTRINSIC;                                                \
11581ad6265SDimitry Andric     break;
11681ad6265SDimitry Andric #define INSTRUCTION(NAME, NARG, ROUND_MODE, INTRINSIC)
11781ad6265SDimitry Andric #define CMP_INSTRUCTION(NAME, NARG, ROUND_MODE, INTRINSIC, DAGN)
11881ad6265SDimitry Andric #include "llvm/IR/ConstrainedOps.def"
11981ad6265SDimitry Andric       default:
12081ad6265SDimitry Andric         break;
12181ad6265SDimitry Andric       }
12281ad6265SDimitry Andric     }
12381ad6265SDimitry Andric     break;
12481ad6265SDimitry Andric   default:
12581ad6265SDimitry Andric     break;
12681ad6265SDimitry Andric   }
12781ad6265SDimitry Andric 
12881ad6265SDimitry Andric   return IID;
12981ad6265SDimitry Andric }
13081ad6265SDimitry Andric 
1315ffd83dbSDimitry Andric } // namespace llvm
132