Nick Lewycky | ea08c70 | 2014-02-26 03:10:45 +0000 | [diff] [blame] | 1 | //===-- InstrinsicInst.cpp - Intrinsic Instruction Wrappers ---------------===// |
Jim Laskey | 0cf8ed6 | 2006-03-23 18:05:12 +0000 | [diff] [blame] | 2 | // |
Chandler Carruth | 2946cd7 | 2019-01-19 08:50:56 +0000 | [diff] [blame] | 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 |
Jim Laskey | 0cf8ed6 | 2006-03-23 18:05:12 +0000 | [diff] [blame] | 6 | // |
| 7 | //===----------------------------------------------------------------------===// |
Jim Laskey | 864e444 | 2006-03-24 10:00:56 +0000 | [diff] [blame] | 8 | // |
| 9 | // This file implements methods that make it really easy to deal with intrinsic |
Devang Patel | be94f23 | 2010-01-05 01:10:40 +0000 | [diff] [blame] | 10 | // functions. |
Jim Laskey | 864e444 | 2006-03-24 10:00:56 +0000 | [diff] [blame] | 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. |
Wei Ding | a131d3f | 2017-08-24 04:18:24 +0000 | [diff] [blame] | 16 | // |
Jim Laskey | 864e444 | 2006-03-24 10:00:56 +0000 | [diff] [blame] | 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 |
Wei Ding | a131d3f | 2017-08-24 04:18:24 +0000 | [diff] [blame] | 19 | // cast instruction needs to be stripped away. |
Jim Laskey | 864e444 | 2006-03-24 10:00:56 +0000 | [diff] [blame] | 20 | // |
| 21 | //===----------------------------------------------------------------------===// |
Jim Laskey | 0cf8ed6 | 2006-03-23 18:05:12 +0000 | [diff] [blame] | 22 | |
Chandler Carruth | 9fb823b | 2013-01-02 11:36:10 +0000 | [diff] [blame] | 23 | #include "llvm/IR/IntrinsicInst.h" |
Chandler Carruth | 6bda14b | 2017-06-06 11:49:48 +0000 | [diff] [blame] | 24 | #include "llvm/ADT/StringSwitch.h" |
Chandler Carruth | 9fb823b | 2013-01-02 11:36:10 +0000 | [diff] [blame] | 25 | #include "llvm/IR/Constants.h" |
Bjorn Pettersson | 428caf9 | 2018-06-15 13:48:55 +0000 | [diff] [blame] | 26 | #include "llvm/IR/DebugInfoMetadata.h" |
Chandler Carruth | 9fb823b | 2013-01-02 11:36:10 +0000 | [diff] [blame] | 27 | #include "llvm/IR/GlobalVariable.h" |
| 28 | #include "llvm/IR/Metadata.h" |
Xinliang David Li | a754c47 | 2016-09-20 19:07:22 +0000 | [diff] [blame] | 29 | #include "llvm/IR/Module.h" |
Simon Moll | 2eeb6ca | 2020-04-15 12:05:07 +0200 | [diff] [blame] | 30 | #include "llvm/IR/Operator.h" |
Simon Moll | 733b319 | 2020-03-17 14:52:06 +0100 | [diff] [blame] | 31 | #include "llvm/IR/PatternMatch.h" |
| 32 | |
Reid Kleckner | c2752da | 2016-01-26 22:33:19 +0000 | [diff] [blame] | 33 | #include "llvm/Support/raw_ostream.h" |
Jim Laskey | 0cf8ed6 | 2006-03-23 18:05:12 +0000 | [diff] [blame] | 34 | using namespace llvm; |
| 35 | |
| 36 | //===----------------------------------------------------------------------===// |
Hsiangkai Wang | ef72e48 | 2018-08-06 03:59:47 +0000 | [diff] [blame] | 37 | /// DbgVariableIntrinsic - This is the common base class for debug info |
| 38 | /// intrinsics for variables. |
Jim Laskey | 0cf8ed6 | 2006-03-23 18:05:12 +0000 | [diff] [blame] | 39 | /// |
| 40 | |
Hsiangkai Wang | ef72e48 | 2018-08-06 03:59:47 +0000 | [diff] [blame] | 41 | Value *DbgVariableIntrinsic::getVariableLocation(bool AllowNullOp) const { |
Duncan P. N. Exon Smith | 40b44e1 | 2016-03-29 18:56:03 +0000 | [diff] [blame] | 42 | Value *Op = getArgOperand(0); |
| 43 | if (AllowNullOp && !Op) |
| 44 | return nullptr; |
| 45 | |
Duncan P. N. Exon Smith | 5bf8fef | 2014-12-09 18:38:53 +0000 | [diff] [blame] | 46 | auto *MD = cast<MetadataAsValue>(Op)->getMetadata(); |
| 47 | if (auto *V = dyn_cast<ValueAsMetadata>(MD)) |
| 48 | return V->getValue(); |
| 49 | |
| 50 | // When the value goes to null, it gets replaced by an empty MDNode. |
Hsiangkai Wang | ef72e48 | 2018-08-06 03:59:47 +0000 | [diff] [blame] | 51 | assert(!cast<MDNode>(MD)->getNumOperands() && "Expected an empty MDNode"); |
Duncan P. N. Exon Smith | 5bf8fef | 2014-12-09 18:38:53 +0000 | [diff] [blame] | 52 | return nullptr; |
| 53 | } |
| 54 | |
Hsiangkai Wang | ef72e48 | 2018-08-06 03:59:47 +0000 | [diff] [blame] | 55 | Optional<uint64_t> DbgVariableIntrinsic::getFragmentSizeInBits() const { |
Bjorn Pettersson | 428caf9 | 2018-06-15 13:48:55 +0000 | [diff] [blame] | 56 | if (auto Fragment = getExpression()->getFragmentInfo()) |
| 57 | return Fragment->SizeInBits; |
| 58 | return getVariable()->getSizeInBits(); |
| 59 | } |
| 60 | |
Reid Kleckner | c2752da | 2016-01-26 22:33:19 +0000 | [diff] [blame] | 61 | int llvm::Intrinsic::lookupLLVMIntrinsicByName(ArrayRef<const char *> NameTable, |
| 62 | StringRef Name) { |
| 63 | assert(Name.startswith("llvm.")); |
| 64 | |
| 65 | // Do successive binary searches of the dotted name components. For |
| 66 | // "llvm.gc.experimental.statepoint.p1i8.p1i32", we will find the range of |
| 67 | // intrinsics starting with "llvm.gc", then "llvm.gc.experimental", then |
| 68 | // "llvm.gc.experimental.statepoint", and then we will stop as the range is |
| 69 | // size 1. During the search, we can skip the prefix that we already know is |
| 70 | // identical. By using strncmp we consider names with differing suffixes to |
| 71 | // be part of the equal range. |
Reid Kleckner | c2752da | 2016-01-26 22:33:19 +0000 | [diff] [blame] | 72 | size_t CmpEnd = 4; // Skip the "llvm" component. |
| 73 | const char *const *Low = NameTable.begin(); |
| 74 | const char *const *High = NameTable.end(); |
| 75 | const char *const *LastLow = Low; |
| 76 | while (CmpEnd < Name.size() && High - Low > 0) { |
Simon Pilgrim | cc97298 | 2019-09-24 12:30:07 +0000 | [diff] [blame] | 77 | size_t CmpStart = CmpEnd; |
Reid Kleckner | c2752da | 2016-01-26 22:33:19 +0000 | [diff] [blame] | 78 | CmpEnd = Name.find('.', CmpStart + 1); |
| 79 | CmpEnd = CmpEnd == StringRef::npos ? Name.size() : CmpEnd; |
| 80 | auto Cmp = [CmpStart, CmpEnd](const char *LHS, const char *RHS) { |
| 81 | return strncmp(LHS + CmpStart, RHS + CmpStart, CmpEnd - CmpStart) < 0; |
| 82 | }; |
| 83 | LastLow = Low; |
| 84 | std::tie(Low, High) = std::equal_range(Low, High, Name.data(), Cmp); |
| 85 | } |
| 86 | if (High - Low > 0) |
| 87 | LastLow = Low; |
| 88 | |
| 89 | if (LastLow == NameTable.end()) |
| 90 | return -1; |
| 91 | StringRef NameFound = *LastLow; |
| 92 | if (Name == NameFound || |
| 93 | (Name.startswith(NameFound) && Name[NameFound.size()] == '.')) |
| 94 | return LastLow - NameTable.begin(); |
| 95 | return -1; |
| 96 | } |
Xinliang David Li | a754c47 | 2016-09-20 19:07:22 +0000 | [diff] [blame] | 97 | |
| 98 | Value *InstrProfIncrementInst::getStep() const { |
| 99 | if (InstrProfIncrementInstStep::classof(this)) { |
| 100 | return const_cast<Value *>(getArgOperand(4)); |
| 101 | } |
| 102 | const Module *M = getModule(); |
| 103 | LLVMContext &Context = M->getContext(); |
| 104 | return ConstantInt::get(Type::getInt64Ty(Context), 1); |
| 105 | } |
Andrew Kaylor | a0a1164 | 2017-01-26 23:27:59 +0000 | [diff] [blame] | 106 | |
Serge Pavlov | c7ff5b3 | 2020-03-26 14:51:09 +0700 | [diff] [blame] | 107 | Optional<RoundingMode> ConstrainedFPIntrinsic::getRoundingMode() const { |
Andrew Kaylor | f466001 | 2017-05-25 21:31:00 +0000 | [diff] [blame] | 108 | unsigned NumOperands = getNumArgOperands(); |
Wei Ding | a131d3f | 2017-08-24 04:18:24 +0000 | [diff] [blame] | 109 | Metadata *MD = |
Simon Pilgrim | 06cdcb5 | 2019-09-24 11:40:45 +0000 | [diff] [blame] | 110 | cast<MetadataAsValue>(getArgOperand(NumOperands - 2))->getMetadata(); |
Andrew Kaylor | a0a1164 | 2017-01-26 23:27:59 +0000 | [diff] [blame] | 111 | if (!MD || !isa<MDString>(MD)) |
Kevin P. Neal | 472e5dd | 2019-07-08 16:18:18 +0000 | [diff] [blame] | 112 | return None; |
| 113 | return StrToRoundingMode(cast<MDString>(MD)->getString()); |
| 114 | } |
Andrew Kaylor | a0a1164 | 2017-01-26 23:27:59 +0000 | [diff] [blame] | 115 | |
Serge Pavlov | ea8678d | 2019-08-29 19:29:11 +0700 | [diff] [blame] | 116 | Optional<fp::ExceptionBehavior> |
Andrew Kaylor | a0a1164 | 2017-01-26 23:27:59 +0000 | [diff] [blame] | 117 | ConstrainedFPIntrinsic::getExceptionBehavior() const { |
Andrew Kaylor | f466001 | 2017-05-25 21:31:00 +0000 | [diff] [blame] | 118 | unsigned NumOperands = getNumArgOperands(); |
Wei Ding | a131d3f | 2017-08-24 04:18:24 +0000 | [diff] [blame] | 119 | Metadata *MD = |
Simon Pilgrim | 06cdcb5 | 2019-09-24 11:40:45 +0000 | [diff] [blame] | 120 | cast<MetadataAsValue>(getArgOperand(NumOperands - 1))->getMetadata(); |
Andrew Kaylor | a0a1164 | 2017-01-26 23:27:59 +0000 | [diff] [blame] | 121 | if (!MD || !isa<MDString>(MD)) |
Kevin P. Neal | 472e5dd | 2019-07-08 16:18:18 +0000 | [diff] [blame] | 122 | return None; |
| 123 | return StrToExceptionBehavior(cast<MDString>(MD)->getString()); |
| 124 | } |
| 125 | |
Simon Moll | 2eeb6ca | 2020-04-15 12:05:07 +0200 | [diff] [blame] | 126 | FCmpInst::Predicate ConstrainedFPCmpIntrinsic::getPredicate() const { |
| 127 | Metadata *MD = cast<MetadataAsValue>(getArgOperand(2))->getMetadata(); |
Ulrich Weigand | 9db13b5 | 2019-12-06 11:30:04 +0100 | [diff] [blame] | 128 | if (!MD || !isa<MDString>(MD)) |
| 129 | return FCmpInst::BAD_FCMP_PREDICATE; |
| 130 | return StringSwitch<FCmpInst::Predicate>(cast<MDString>(MD)->getString()) |
Simon Moll | 2eeb6ca | 2020-04-15 12:05:07 +0200 | [diff] [blame] | 131 | .Case("oeq", FCmpInst::FCMP_OEQ) |
| 132 | .Case("ogt", FCmpInst::FCMP_OGT) |
| 133 | .Case("oge", FCmpInst::FCMP_OGE) |
| 134 | .Case("olt", FCmpInst::FCMP_OLT) |
| 135 | .Case("ole", FCmpInst::FCMP_OLE) |
| 136 | .Case("one", FCmpInst::FCMP_ONE) |
| 137 | .Case("ord", FCmpInst::FCMP_ORD) |
| 138 | .Case("uno", FCmpInst::FCMP_UNO) |
| 139 | .Case("ueq", FCmpInst::FCMP_UEQ) |
| 140 | .Case("ugt", FCmpInst::FCMP_UGT) |
| 141 | .Case("uge", FCmpInst::FCMP_UGE) |
| 142 | .Case("ult", FCmpInst::FCMP_ULT) |
| 143 | .Case("ule", FCmpInst::FCMP_ULE) |
| 144 | .Case("une", FCmpInst::FCMP_UNE) |
| 145 | .Default(FCmpInst::BAD_FCMP_PREDICATE); |
Ulrich Weigand | 9db13b5 | 2019-12-06 11:30:04 +0100 | [diff] [blame] | 146 | } |
| 147 | |
Andrew Kaylor | f466001 | 2017-05-25 21:31:00 +0000 | [diff] [blame] | 148 | bool ConstrainedFPIntrinsic::isUnaryOp() const { |
| 149 | switch (getIntrinsicID()) { |
Simon Moll | 2eeb6ca | 2020-04-15 12:05:07 +0200 | [diff] [blame] | 150 | default: |
| 151 | return false; |
Wang, Pengfei | 17b8f96 | 2020-01-17 10:32:30 +0800 | [diff] [blame] | 152 | #define INSTRUCTION(NAME, NARG, ROUND_MODE, INTRINSIC) \ |
Simon Moll | 2eeb6ca | 2020-04-15 12:05:07 +0200 | [diff] [blame] | 153 | case Intrinsic::INTRINSIC: \ |
| 154 | return NARG == 1; |
Serge Pavlov | 0c50c0b | 2019-11-05 20:42:16 +0700 | [diff] [blame] | 155 | #include "llvm/IR/ConstrainedOps.def" |
Andrew Kaylor | f466001 | 2017-05-25 21:31:00 +0000 | [diff] [blame] | 156 | } |
| 157 | } |
Wei Ding | a131d3f | 2017-08-24 04:18:24 +0000 | [diff] [blame] | 158 | |
| 159 | bool ConstrainedFPIntrinsic::isTernaryOp() const { |
| 160 | switch (getIntrinsicID()) { |
Simon Moll | 2eeb6ca | 2020-04-15 12:05:07 +0200 | [diff] [blame] | 161 | default: |
| 162 | return false; |
Wang, Pengfei | 17b8f96 | 2020-01-17 10:32:30 +0800 | [diff] [blame] | 163 | #define INSTRUCTION(NAME, NARG, ROUND_MODE, INTRINSIC) \ |
Simon Moll | 2eeb6ca | 2020-04-15 12:05:07 +0200 | [diff] [blame] | 164 | case Intrinsic::INTRINSIC: \ |
| 165 | return NARG == 3; |
Serge Pavlov | 0c50c0b | 2019-11-05 20:42:16 +0700 | [diff] [blame] | 166 | #include "llvm/IR/ConstrainedOps.def" |
| 167 | } |
| 168 | } |
| 169 | |
| 170 | bool ConstrainedFPIntrinsic::classof(const IntrinsicInst *I) { |
| 171 | switch (I->getIntrinsicID()) { |
Wang, Pengfei | 17b8f96 | 2020-01-17 10:32:30 +0800 | [diff] [blame] | 172 | #define INSTRUCTION(NAME, NARGS, ROUND_MODE, INTRINSIC) \ |
Serge Pavlov | 0c50c0b | 2019-11-05 20:42:16 +0700 | [diff] [blame] | 173 | case Intrinsic::INTRINSIC: |
| 174 | #include "llvm/IR/ConstrainedOps.def" |
| 175 | return true; |
| 176 | default: |
| 177 | return false; |
Wei Ding | a131d3f | 2017-08-24 04:18:24 +0000 | [diff] [blame] | 178 | } |
| 179 | } |
| 180 | |
Simon Moll | 733b319 | 2020-03-17 14:52:06 +0100 | [diff] [blame] | 181 | ElementCount VPIntrinsic::getStaticVectorLength() const { |
| 182 | auto GetVectorLengthOfType = [](const Type *T) -> ElementCount { |
| 183 | auto VT = cast<VectorType>(T); |
| 184 | auto ElemCount = VT->getElementCount(); |
| 185 | return ElemCount; |
| 186 | }; |
| 187 | |
| 188 | auto VPMask = getMaskParam(); |
| 189 | return GetVectorLengthOfType(VPMask->getType()); |
| 190 | } |
| 191 | |
| 192 | Value *VPIntrinsic::getMaskParam() const { |
| 193 | auto maskPos = GetMaskParamPos(getIntrinsicID()); |
| 194 | if (maskPos) |
| 195 | return getArgOperand(maskPos.getValue()); |
| 196 | return nullptr; |
| 197 | } |
| 198 | |
| 199 | Value *VPIntrinsic::getVectorLengthParam() const { |
| 200 | auto vlenPos = GetVectorLengthParamPos(getIntrinsicID()); |
| 201 | if (vlenPos) |
| 202 | return getArgOperand(vlenPos.getValue()); |
| 203 | return nullptr; |
| 204 | } |
| 205 | |
| 206 | Optional<int> VPIntrinsic::GetMaskParamPos(Intrinsic::ID IntrinsicID) { |
| 207 | switch (IntrinsicID) { |
| 208 | default: |
| 209 | return None; |
| 210 | |
| 211 | #define REGISTER_VP_INTRINSIC(VPID, MASKPOS, VLENPOS) \ |
| 212 | case Intrinsic::VPID: \ |
| 213 | return MASKPOS; |
| 214 | #include "llvm/IR/VPIntrinsics.def" |
| 215 | } |
| 216 | } |
| 217 | |
| 218 | Optional<int> VPIntrinsic::GetVectorLengthParamPos(Intrinsic::ID IntrinsicID) { |
| 219 | switch (IntrinsicID) { |
| 220 | default: |
| 221 | return None; |
| 222 | |
| 223 | #define REGISTER_VP_INTRINSIC(VPID, MASKPOS, VLENPOS) \ |
| 224 | case Intrinsic::VPID: \ |
| 225 | return VLENPOS; |
| 226 | #include "llvm/IR/VPIntrinsics.def" |
| 227 | } |
| 228 | } |
| 229 | |
| 230 | bool VPIntrinsic::IsVPIntrinsic(Intrinsic::ID ID) { |
| 231 | switch (ID) { |
| 232 | default: |
| 233 | return false; |
| 234 | |
| 235 | #define REGISTER_VP_INTRINSIC(VPID, MASKPOS, VLENPOS) \ |
| 236 | case Intrinsic::VPID: \ |
| 237 | break; |
| 238 | #include "llvm/IR/VPIntrinsics.def" |
| 239 | } |
| 240 | return true; |
| 241 | } |
| 242 | |
| 243 | // Equivalent non-predicated opcode |
| 244 | unsigned VPIntrinsic::GetFunctionalOpcodeForVP(Intrinsic::ID ID) { |
| 245 | switch (ID) { |
| 246 | default: |
| 247 | return Instruction::Call; |
| 248 | |
| 249 | #define HANDLE_VP_TO_OC(VPID, OC) \ |
| 250 | case Intrinsic::VPID: \ |
| 251 | return Instruction::OC; |
| 252 | #include "llvm/IR/VPIntrinsics.def" |
| 253 | } |
| 254 | } |
| 255 | |
| 256 | Intrinsic::ID VPIntrinsic::GetForOpcode(unsigned OC) { |
| 257 | switch (OC) { |
| 258 | default: |
| 259 | return Intrinsic::not_intrinsic; |
| 260 | |
| 261 | #define HANDLE_VP_TO_OC(VPID, OC) \ |
| 262 | case Instruction::OC: \ |
| 263 | return Intrinsic::VPID; |
| 264 | #include "llvm/IR/VPIntrinsics.def" |
| 265 | } |
| 266 | } |
| 267 | |
| 268 | bool VPIntrinsic::canIgnoreVectorLengthParam() const { |
| 269 | using namespace PatternMatch; |
| 270 | |
| 271 | ElementCount EC = getStaticVectorLength(); |
| 272 | |
| 273 | // No vlen param - no lanes masked-off by it. |
| 274 | auto *VLParam = getVectorLengthParam(); |
| 275 | if (!VLParam) |
| 276 | return true; |
| 277 | |
| 278 | // Note that the VP intrinsic causes undefined behavior if the Explicit Vector |
| 279 | // Length parameter is strictly greater-than the number of vector elements of |
| 280 | // the operation. This function returns true when this is detected statically |
| 281 | // in the IR. |
| 282 | |
David Sherwood | f4257c5 | 2020-08-14 12:15:59 +0100 | [diff] [blame] | 283 | // Check whether "W == vscale * EC.getKnownMinValue()" |
| 284 | if (EC.isScalable()) { |
Simon Moll | 733b319 | 2020-03-17 14:52:06 +0100 | [diff] [blame] | 285 | // Undig the DL |
| 286 | auto ParMod = this->getModule(); |
| 287 | if (!ParMod) |
| 288 | return false; |
| 289 | const auto &DL = ParMod->getDataLayout(); |
| 290 | |
| 291 | // Compare vscale patterns |
Simon Moll | a0dfdda | 2020-06-04 11:09:48 +0200 | [diff] [blame] | 292 | uint64_t VScaleFactor; |
| 293 | if (match(VLParam, m_c_Mul(m_ConstantInt(VScaleFactor), m_VScale(DL)))) |
David Sherwood | f4257c5 | 2020-08-14 12:15:59 +0100 | [diff] [blame] | 294 | return VScaleFactor >= EC.getKnownMinValue(); |
| 295 | return (EC.getKnownMinValue() == 1) && match(VLParam, m_VScale(DL)); |
Simon Moll | 733b319 | 2020-03-17 14:52:06 +0100 | [diff] [blame] | 296 | } |
| 297 | |
| 298 | // standard SIMD operation |
| 299 | auto VLConst = dyn_cast<ConstantInt>(VLParam); |
| 300 | if (!VLConst) |
| 301 | return false; |
| 302 | |
| 303 | uint64_t VLNum = VLConst->getZExtValue(); |
David Sherwood | f4257c5 | 2020-08-14 12:15:59 +0100 | [diff] [blame] | 304 | if (VLNum >= EC.getKnownMinValue()) |
Simon Moll | 733b319 | 2020-03-17 14:52:06 +0100 | [diff] [blame] | 305 | return true; |
| 306 | |
| 307 | return false; |
| 308 | } |
| 309 | |
Nikita Popov | 2fb0a82 | 2019-05-28 18:08:06 +0000 | [diff] [blame] | 310 | Instruction::BinaryOps BinaryOpIntrinsic::getBinaryOp() const { |
Nikita Popov | 79dffc6 | 2019-04-16 18:55:16 +0000 | [diff] [blame] | 311 | switch (getIntrinsicID()) { |
Simon Moll | 2eeb6ca | 2020-04-15 12:05:07 +0200 | [diff] [blame] | 312 | case Intrinsic::uadd_with_overflow: |
| 313 | case Intrinsic::sadd_with_overflow: |
| 314 | case Intrinsic::uadd_sat: |
| 315 | case Intrinsic::sadd_sat: |
| 316 | return Instruction::Add; |
| 317 | case Intrinsic::usub_with_overflow: |
| 318 | case Intrinsic::ssub_with_overflow: |
| 319 | case Intrinsic::usub_sat: |
| 320 | case Intrinsic::ssub_sat: |
| 321 | return Instruction::Sub; |
| 322 | case Intrinsic::umul_with_overflow: |
| 323 | case Intrinsic::smul_with_overflow: |
| 324 | return Instruction::Mul; |
| 325 | default: |
| 326 | llvm_unreachable("Invalid intrinsic"); |
Nikita Popov | 79dffc6 | 2019-04-16 18:55:16 +0000 | [diff] [blame] | 327 | } |
| 328 | } |
| 329 | |
Nikita Popov | 2fb0a82 | 2019-05-28 18:08:06 +0000 | [diff] [blame] | 330 | bool BinaryOpIntrinsic::isSigned() const { |
Nikita Popov | 79dffc6 | 2019-04-16 18:55:16 +0000 | [diff] [blame] | 331 | switch (getIntrinsicID()) { |
Simon Moll | 2eeb6ca | 2020-04-15 12:05:07 +0200 | [diff] [blame] | 332 | case Intrinsic::sadd_with_overflow: |
| 333 | case Intrinsic::ssub_with_overflow: |
| 334 | case Intrinsic::smul_with_overflow: |
| 335 | case Intrinsic::sadd_sat: |
| 336 | case Intrinsic::ssub_sat: |
| 337 | return true; |
| 338 | default: |
| 339 | return false; |
Nikita Popov | 79dffc6 | 2019-04-16 18:55:16 +0000 | [diff] [blame] | 340 | } |
| 341 | } |
| 342 | |
Nikita Popov | 2fb0a82 | 2019-05-28 18:08:06 +0000 | [diff] [blame] | 343 | unsigned BinaryOpIntrinsic::getNoWrapKind() const { |
Nikita Popov | 79dffc6 | 2019-04-16 18:55:16 +0000 | [diff] [blame] | 344 | if (isSigned()) |
| 345 | return OverflowingBinaryOperator::NoSignedWrap; |
| 346 | else |
| 347 | return OverflowingBinaryOperator::NoUnsignedWrap; |
| 348 | } |