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 
21 namespace llvm {
22 
23 Optional<RoundingMode> convertStrToRoundingMode(StringRef RoundingArg) {
24   // For dynamic rounding mode, we use round to nearest but we will set the
25   // 'exact' SDNodeFlag so that the value will not be rounded.
26   return StringSwitch<Optional<RoundingMode>>(RoundingArg)
27       .Case("round.dynamic", RoundingMode::Dynamic)
28       .Case("round.tonearest", RoundingMode::NearestTiesToEven)
29       .Case("round.tonearestaway", RoundingMode::NearestTiesToAway)
30       .Case("round.downward", RoundingMode::TowardNegative)
31       .Case("round.upward", RoundingMode::TowardPositive)
32       .Case("round.towardzero", RoundingMode::TowardZero)
33       .Default(None);
34 }
35 
36 Optional<StringRef> convertRoundingModeToStr(RoundingMode UseRounding) {
37   Optional<StringRef> RoundingStr = None;
38   switch (UseRounding) {
39   case RoundingMode::Dynamic:
40     RoundingStr = "round.dynamic";
41     break;
42   case RoundingMode::NearestTiesToEven:
43     RoundingStr = "round.tonearest";
44     break;
45   case RoundingMode::NearestTiesToAway:
46     RoundingStr = "round.tonearestaway";
47     break;
48   case RoundingMode::TowardNegative:
49     RoundingStr = "round.downward";
50     break;
51   case RoundingMode::TowardPositive:
52     RoundingStr = "round.upward";
53     break;
54   case RoundingMode::TowardZero:
55     RoundingStr = "round.towardzero";
56     break;
57   default:
58     break;
59   }
60   return RoundingStr;
61 }
62 
63 Optional<fp::ExceptionBehavior>
64 convertStrToExceptionBehavior(StringRef ExceptionArg) {
65   return StringSwitch<Optional<fp::ExceptionBehavior>>(ExceptionArg)
66       .Case("fpexcept.ignore", fp::ebIgnore)
67       .Case("fpexcept.maytrap", fp::ebMayTrap)
68       .Case("fpexcept.strict", fp::ebStrict)
69       .Default(None);
70 }
71 
72 Optional<StringRef>
73 convertExceptionBehaviorToStr(fp::ExceptionBehavior UseExcept) {
74   Optional<StringRef> ExceptStr = None;
75   switch (UseExcept) {
76   case fp::ebStrict:
77     ExceptStr = "fpexcept.strict";
78     break;
79   case fp::ebIgnore:
80     ExceptStr = "fpexcept.ignore";
81     break;
82   case fp::ebMayTrap:
83     ExceptStr = "fpexcept.maytrap";
84     break;
85   }
86   return ExceptStr;
87 }
88 
89 Intrinsic::ID getConstrainedIntrinsicID(const Instruction &Instr) {
90   Intrinsic::ID IID = Intrinsic::not_intrinsic;
91   switch (Instr.getOpcode()) {
92   case Instruction::FCmp:
93     // Unlike other instructions FCmp can be mapped to one of two intrinsic
94     // functions. We choose the non-signaling variant.
95     IID = Intrinsic::experimental_constrained_fcmp;
96     break;
97 
98     // Instructions
99 #define INSTRUCTION(NAME, NARG, ROUND_MODE, INTRINSIC)                         \
100   case Instruction::NAME:                                                      \
101     IID = Intrinsic::INTRINSIC;                                                \
102     break;
103 #define FUNCTION(NAME, NARG, ROUND_MODE, INTRINSIC)
104 #define CMP_INSTRUCTION(NAME, NARG, ROUND_MODE, INTRINSIC, DAGN)
105 #include "llvm/IR/ConstrainedOps.def"
106 
107   // Intrinsic calls.
108   case Instruction::Call:
109     if (auto *IntrinCall = dyn_cast<IntrinsicInst>(&Instr)) {
110       switch (IntrinCall->getIntrinsicID()) {
111 #define FUNCTION(NAME, NARG, ROUND_MODE, INTRINSIC)                            \
112   case Intrinsic::NAME:                                                        \
113     IID = Intrinsic::INTRINSIC;                                                \
114     break;
115 #define INSTRUCTION(NAME, NARG, ROUND_MODE, INTRINSIC)
116 #define CMP_INSTRUCTION(NAME, NARG, ROUND_MODE, INTRINSIC, DAGN)
117 #include "llvm/IR/ConstrainedOps.def"
118       default:
119         break;
120       }
121     }
122     break;
123   default:
124     break;
125   }
126 
127   return IID;
128 }
129 
130 } // namespace llvm
131