1 //===-- FPEnv.cpp ---- FP Environment -------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 /// @file
10 /// This file contains the implementations of entities that describe floating
11 /// point environment.
12 //
13 //===----------------------------------------------------------------------===//
14 
15 #include "llvm/IR/FPEnv.h"
16 #include "llvm/ADT/StringSwitch.h"
17 #include "llvm/IR/Instruction.h"
18 #include "llvm/IR/IntrinsicInst.h"
19 #include "llvm/IR/Intrinsics.h"
20 #include <optional>
21 
22 namespace llvm {
23 
convertStrToRoundingMode(StringRef RoundingArg)24 std::optional<RoundingMode> convertStrToRoundingMode(StringRef RoundingArg) {
25   // For dynamic rounding mode, we use round to nearest but we will set the
26   // 'exact' SDNodeFlag so that the value will not be rounded.
27   return StringSwitch<std::optional<RoundingMode>>(RoundingArg)
28       .Case("round.dynamic", RoundingMode::Dynamic)
29       .Case("round.tonearest", RoundingMode::NearestTiesToEven)
30       .Case("round.tonearestaway", RoundingMode::NearestTiesToAway)
31       .Case("round.downward", RoundingMode::TowardNegative)
32       .Case("round.upward", RoundingMode::TowardPositive)
33       .Case("round.towardzero", RoundingMode::TowardZero)
34       .Default(std::nullopt);
35 }
36 
convertRoundingModeToStr(RoundingMode UseRounding)37 std::optional<StringRef> convertRoundingModeToStr(RoundingMode UseRounding) {
38   std::optional<StringRef> RoundingStr;
39   switch (UseRounding) {
40   case RoundingMode::Dynamic:
41     RoundingStr = "round.dynamic";
42     break;
43   case RoundingMode::NearestTiesToEven:
44     RoundingStr = "round.tonearest";
45     break;
46   case RoundingMode::NearestTiesToAway:
47     RoundingStr = "round.tonearestaway";
48     break;
49   case RoundingMode::TowardNegative:
50     RoundingStr = "round.downward";
51     break;
52   case RoundingMode::TowardPositive:
53     RoundingStr = "round.upward";
54     break;
55   case RoundingMode::TowardZero:
56     RoundingStr = "round.towardzero";
57     break;
58   default:
59     break;
60   }
61   return RoundingStr;
62 }
63 
64 std::optional<fp::ExceptionBehavior>
convertStrToExceptionBehavior(StringRef ExceptionArg)65 convertStrToExceptionBehavior(StringRef ExceptionArg) {
66   return StringSwitch<std::optional<fp::ExceptionBehavior>>(ExceptionArg)
67       .Case("fpexcept.ignore", fp::ebIgnore)
68       .Case("fpexcept.maytrap", fp::ebMayTrap)
69       .Case("fpexcept.strict", fp::ebStrict)
70       .Default(std::nullopt);
71 }
72 
73 std::optional<StringRef>
convertExceptionBehaviorToStr(fp::ExceptionBehavior UseExcept)74 convertExceptionBehaviorToStr(fp::ExceptionBehavior UseExcept) {
75   std::optional<StringRef> ExceptStr;
76   switch (UseExcept) {
77   case fp::ebStrict:
78     ExceptStr = "fpexcept.strict";
79     break;
80   case fp::ebIgnore:
81     ExceptStr = "fpexcept.ignore";
82     break;
83   case fp::ebMayTrap:
84     ExceptStr = "fpexcept.maytrap";
85     break;
86   }
87   return ExceptStr;
88 }
89 
getConstrainedIntrinsicID(const Instruction & Instr)90 Intrinsic::ID getConstrainedIntrinsicID(const Instruction &Instr) {
91   Intrinsic::ID IID = Intrinsic::not_intrinsic;
92   switch (Instr.getOpcode()) {
93   case Instruction::FCmp:
94     // Unlike other instructions FCmp can be mapped to one of two intrinsic
95     // functions. We choose the non-signaling variant.
96     IID = Intrinsic::experimental_constrained_fcmp;
97     break;
98 
99     // Instructions
100 #define INSTRUCTION(NAME, NARG, ROUND_MODE, INTRINSIC)                         \
101   case Instruction::NAME:                                                      \
102     IID = Intrinsic::INTRINSIC;                                                \
103     break;
104 #define FUNCTION(NAME, NARG, ROUND_MODE, INTRINSIC)
105 #define CMP_INSTRUCTION(NAME, NARG, ROUND_MODE, INTRINSIC, DAGN)
106 #include "llvm/IR/ConstrainedOps.def"
107 
108   // Intrinsic calls.
109   case Instruction::Call:
110     if (auto *IntrinCall = dyn_cast<IntrinsicInst>(&Instr)) {
111       switch (IntrinCall->getIntrinsicID()) {
112 #define FUNCTION(NAME, NARG, ROUND_MODE, INTRINSIC)                            \
113   case Intrinsic::NAME:                                                        \
114     IID = Intrinsic::INTRINSIC;                                                \
115     break;
116 #define INSTRUCTION(NAME, NARG, ROUND_MODE, INTRINSIC)
117 #define CMP_INSTRUCTION(NAME, NARG, ROUND_MODE, INTRINSIC, DAGN)
118 #include "llvm/IR/ConstrainedOps.def"
119       default:
120         break;
121       }
122     }
123     break;
124   default:
125     break;
126   }
127 
128   return IID;
129 }
130 
131 } // namespace llvm
132