[InstCombine] Signed saturation patterns
[llvm-core.git] / lib / IR / IntrinsicInst.cpp
blob26ed46a9cd918774b4d2e3a1f332bbdf35a48d85
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.
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.
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.
21 //===----------------------------------------------------------------------===//
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;
34 //===----------------------------------------------------------------------===//
35 /// DbgVariableIntrinsic - This is the common base class for debug info
36 /// intrinsics for variables.
37 ///
39 Value *DbgVariableIntrinsic::getVariableLocation(bool AllowNullOp) const {
40 Value *Op = getArgOperand(0);
41 if (AllowNullOp && !Op)
42 return nullptr;
44 auto *MD = cast<MetadataAsValue>(Op)->getMetadata();
45 if (auto *V = dyn_cast<ValueAsMetadata>(MD))
46 return V->getValue();
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;
53 Optional<uint64_t> DbgVariableIntrinsic::getFragmentSizeInBits() const {
54 if (auto Fragment = getExpression()->getFragmentInfo())
55 return Fragment->SizeInBits;
56 return getVariable()->getSizeInBits();
59 int llvm::Intrinsic::lookupLLVMIntrinsicByName(ArrayRef<const char *> NameTable,
60 StringRef Name) {
61 assert(Name.startswith("llvm."));
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;
81 LastLow = Low;
82 std::tie(Low, High) = std::equal_range(Low, High, Name.data(), Cmp);
84 if (High - Low > 0)
85 LastLow = Low;
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;
96 Value *InstrProfIncrementInst::getStep() const {
97 if (InstrProfIncrementInstStep::classof(this)) {
98 return const_cast<Value *>(getArgOperand(4));
100 const Module *M = getModule();
101 LLVMContext &Context = M->getContext();
102 return ConstantInt::get(Type::getInt64Ty(Context), 1);
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());
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);
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;
148 return RoundingStr;
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());
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);
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;
184 return ExceptStr;
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;
217 bool ConstrainedFPIntrinsic::isTernaryOp() const {
218 switch (getIntrinsicID()) {
219 default:
220 return false;
221 case Intrinsic::experimental_constrained_fma:
222 return true;
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");
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;
259 unsigned BinaryOpIntrinsic::getNoWrapKind() const {
260 if (isSigned())
261 return OverflowingBinaryOperator::NoSignedWrap;
262 else
263 return OverflowingBinaryOperator::NoUnsignedWrap;