xref: /freebsd/contrib/llvm-project/llvm/lib/IR/IntrinsicInst.cpp (revision 9dba64be9536c28e4800e06512b7f29b43ade345)
1 //===-- InstrinsicInst.cpp - Intrinsic Instruction Wrappers ---------------===//
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 // This file implements methods that make it really easy to deal with intrinsic
10 // functions.
11 //
12 // All intrinsic function calls are instances of the call instruction, so these
13 // are all subclasses of the CallInst class.  Note that none of these classes
14 // has state or virtual methods, which is an important part of this gross/neat
15 // hack working.
16 //
17 // In some cases, arguments to intrinsics need to be generic and are defined as
18 // type pointer to empty struct { }*.  To access the real item of interest the
19 // cast instruction needs to be stripped away.
20 //
21 //===----------------------------------------------------------------------===//
22 
23 #include "llvm/IR/IntrinsicInst.h"
24 #include "llvm/IR/Operator.h"
25 #include "llvm/ADT/StringSwitch.h"
26 #include "llvm/IR/Constants.h"
27 #include "llvm/IR/DebugInfoMetadata.h"
28 #include "llvm/IR/GlobalVariable.h"
29 #include "llvm/IR/Metadata.h"
30 #include "llvm/IR/Module.h"
31 #include "llvm/Support/raw_ostream.h"
32 using namespace llvm;
33 
34 //===----------------------------------------------------------------------===//
35 /// DbgVariableIntrinsic - This is the common base class for debug info
36 /// intrinsics for variables.
37 ///
38 
39 Value *DbgVariableIntrinsic::getVariableLocation(bool AllowNullOp) const {
40   Value *Op = getArgOperand(0);
41   if (AllowNullOp && !Op)
42     return nullptr;
43 
44   auto *MD = cast<MetadataAsValue>(Op)->getMetadata();
45   if (auto *V = dyn_cast<ValueAsMetadata>(MD))
46     return V->getValue();
47 
48   // When the value goes to null, it gets replaced by an empty MDNode.
49   assert(!cast<MDNode>(MD)->getNumOperands() && "Expected an empty MDNode");
50   return nullptr;
51 }
52 
53 Optional<uint64_t> DbgVariableIntrinsic::getFragmentSizeInBits() const {
54   if (auto Fragment = getExpression()->getFragmentInfo())
55     return Fragment->SizeInBits;
56   return getVariable()->getSizeInBits();
57 }
58 
59 int llvm::Intrinsic::lookupLLVMIntrinsicByName(ArrayRef<const char *> NameTable,
60                                                StringRef Name) {
61   assert(Name.startswith("llvm."));
62 
63   // Do successive binary searches of the dotted name components. For
64   // "llvm.gc.experimental.statepoint.p1i8.p1i32", we will find the range of
65   // intrinsics starting with "llvm.gc", then "llvm.gc.experimental", then
66   // "llvm.gc.experimental.statepoint", and then we will stop as the range is
67   // size 1. During the search, we can skip the prefix that we already know is
68   // identical. By using strncmp we consider names with differing suffixes to
69   // be part of the equal range.
70   size_t CmpEnd = 4; // Skip the "llvm" component.
71   const char *const *Low = NameTable.begin();
72   const char *const *High = NameTable.end();
73   const char *const *LastLow = Low;
74   while (CmpEnd < Name.size() && High - Low > 0) {
75     size_t CmpStart = CmpEnd;
76     CmpEnd = Name.find('.', CmpStart + 1);
77     CmpEnd = CmpEnd == StringRef::npos ? Name.size() : CmpEnd;
78     auto Cmp = [CmpStart, CmpEnd](const char *LHS, const char *RHS) {
79       return strncmp(LHS + CmpStart, RHS + CmpStart, CmpEnd - CmpStart) < 0;
80     };
81     LastLow = Low;
82     std::tie(Low, High) = std::equal_range(Low, High, Name.data(), Cmp);
83   }
84   if (High - Low > 0)
85     LastLow = Low;
86 
87   if (LastLow == NameTable.end())
88     return -1;
89   StringRef NameFound = *LastLow;
90   if (Name == NameFound ||
91       (Name.startswith(NameFound) && Name[NameFound.size()] == '.'))
92     return LastLow - NameTable.begin();
93   return -1;
94 }
95 
96 Value *InstrProfIncrementInst::getStep() const {
97   if (InstrProfIncrementInstStep::classof(this)) {
98     return const_cast<Value *>(getArgOperand(4));
99   }
100   const Module *M = getModule();
101   LLVMContext &Context = M->getContext();
102   return ConstantInt::get(Type::getInt64Ty(Context), 1);
103 }
104 
105 Optional<ConstrainedFPIntrinsic::RoundingMode>
106 ConstrainedFPIntrinsic::getRoundingMode() const {
107   unsigned NumOperands = getNumArgOperands();
108   Metadata *MD =
109       cast<MetadataAsValue>(getArgOperand(NumOperands - 2))->getMetadata();
110   if (!MD || !isa<MDString>(MD))
111     return None;
112   return StrToRoundingMode(cast<MDString>(MD)->getString());
113 }
114 
115 Optional<ConstrainedFPIntrinsic::RoundingMode>
116 ConstrainedFPIntrinsic::StrToRoundingMode(StringRef RoundingArg) {
117   // For dynamic rounding mode, we use round to nearest but we will set the
118   // 'exact' SDNodeFlag so that the value will not be rounded.
119   return StringSwitch<Optional<RoundingMode>>(RoundingArg)
120     .Case("round.dynamic",    rmDynamic)
121     .Case("round.tonearest",  rmToNearest)
122     .Case("round.downward",   rmDownward)
123     .Case("round.upward",     rmUpward)
124     .Case("round.towardzero", rmTowardZero)
125     .Default(None);
126 }
127 
128 Optional<StringRef>
129 ConstrainedFPIntrinsic::RoundingModeToStr(RoundingMode UseRounding) {
130   Optional<StringRef> RoundingStr = None;
131   switch (UseRounding) {
132   case ConstrainedFPIntrinsic::rmDynamic:
133     RoundingStr = "round.dynamic";
134     break;
135   case ConstrainedFPIntrinsic::rmToNearest:
136     RoundingStr = "round.tonearest";
137     break;
138   case ConstrainedFPIntrinsic::rmDownward:
139     RoundingStr = "round.downward";
140     break;
141   case ConstrainedFPIntrinsic::rmUpward:
142     RoundingStr = "round.upward";
143     break;
144   case ConstrainedFPIntrinsic::rmTowardZero:
145     RoundingStr = "round.towardzero";
146     break;
147   }
148   return RoundingStr;
149 }
150 
151 Optional<ConstrainedFPIntrinsic::ExceptionBehavior>
152 ConstrainedFPIntrinsic::getExceptionBehavior() const {
153   unsigned NumOperands = getNumArgOperands();
154   Metadata *MD =
155       cast<MetadataAsValue>(getArgOperand(NumOperands - 1))->getMetadata();
156   if (!MD || !isa<MDString>(MD))
157     return None;
158   return StrToExceptionBehavior(cast<MDString>(MD)->getString());
159 }
160 
161 Optional<ConstrainedFPIntrinsic::ExceptionBehavior>
162 ConstrainedFPIntrinsic::StrToExceptionBehavior(StringRef ExceptionArg) {
163   return StringSwitch<Optional<ExceptionBehavior>>(ExceptionArg)
164     .Case("fpexcept.ignore",  ebIgnore)
165     .Case("fpexcept.maytrap", ebMayTrap)
166     .Case("fpexcept.strict",  ebStrict)
167     .Default(None);
168 }
169 
170 Optional<StringRef>
171 ConstrainedFPIntrinsic::ExceptionBehaviorToStr(ExceptionBehavior UseExcept) {
172   Optional<StringRef> ExceptStr = None;
173   switch (UseExcept) {
174   case ConstrainedFPIntrinsic::ebStrict:
175     ExceptStr = "fpexcept.strict";
176     break;
177   case ConstrainedFPIntrinsic::ebIgnore:
178     ExceptStr = "fpexcept.ignore";
179     break;
180   case ConstrainedFPIntrinsic::ebMayTrap:
181     ExceptStr = "fpexcept.maytrap";
182     break;
183   }
184   return ExceptStr;
185 }
186 
187 bool ConstrainedFPIntrinsic::isUnaryOp() const {
188   switch (getIntrinsicID()) {
189     default:
190       return false;
191     case Intrinsic::experimental_constrained_fptosi:
192     case Intrinsic::experimental_constrained_fptoui:
193     case Intrinsic::experimental_constrained_fptrunc:
194     case Intrinsic::experimental_constrained_fpext:
195     case Intrinsic::experimental_constrained_sqrt:
196     case Intrinsic::experimental_constrained_sin:
197     case Intrinsic::experimental_constrained_cos:
198     case Intrinsic::experimental_constrained_exp:
199     case Intrinsic::experimental_constrained_exp2:
200     case Intrinsic::experimental_constrained_log:
201     case Intrinsic::experimental_constrained_log10:
202     case Intrinsic::experimental_constrained_log2:
203     case Intrinsic::experimental_constrained_lrint:
204     case Intrinsic::experimental_constrained_llrint:
205     case Intrinsic::experimental_constrained_rint:
206     case Intrinsic::experimental_constrained_nearbyint:
207     case Intrinsic::experimental_constrained_ceil:
208     case Intrinsic::experimental_constrained_floor:
209     case Intrinsic::experimental_constrained_lround:
210     case Intrinsic::experimental_constrained_llround:
211     case Intrinsic::experimental_constrained_round:
212     case Intrinsic::experimental_constrained_trunc:
213       return true;
214   }
215 }
216 
217 bool ConstrainedFPIntrinsic::isTernaryOp() const {
218   switch (getIntrinsicID()) {
219     default:
220       return false;
221     case Intrinsic::experimental_constrained_fma:
222       return true;
223   }
224 }
225 
226 Instruction::BinaryOps BinaryOpIntrinsic::getBinaryOp() const {
227   switch (getIntrinsicID()) {
228     case Intrinsic::uadd_with_overflow:
229     case Intrinsic::sadd_with_overflow:
230     case Intrinsic::uadd_sat:
231     case Intrinsic::sadd_sat:
232       return Instruction::Add;
233     case Intrinsic::usub_with_overflow:
234     case Intrinsic::ssub_with_overflow:
235     case Intrinsic::usub_sat:
236     case Intrinsic::ssub_sat:
237       return Instruction::Sub;
238     case Intrinsic::umul_with_overflow:
239     case Intrinsic::smul_with_overflow:
240       return Instruction::Mul;
241     default:
242       llvm_unreachable("Invalid intrinsic");
243   }
244 }
245 
246 bool BinaryOpIntrinsic::isSigned() const {
247   switch (getIntrinsicID()) {
248     case Intrinsic::sadd_with_overflow:
249     case Intrinsic::ssub_with_overflow:
250     case Intrinsic::smul_with_overflow:
251     case Intrinsic::sadd_sat:
252     case Intrinsic::ssub_sat:
253       return true;
254     default:
255       return false;
256   }
257 }
258 
259 unsigned BinaryOpIntrinsic::getNoWrapKind() const {
260   if (isSigned())
261     return OverflowingBinaryOperator::NoSignedWrap;
262   else
263     return OverflowingBinaryOperator::NoUnsignedWrap;
264 }
265