Line data Source code
1 : //===-- llvm/Operator.h - Operator utility subclass -------------*- C++ -*-===//
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 defines various classes for working with Instructions and
10 : // ConstantExprs.
11 : //
12 : //===----------------------------------------------------------------------===//
13 :
14 : #ifndef LLVM_IR_OPERATOR_H
15 : #define LLVM_IR_OPERATOR_H
16 :
17 : #include "llvm/ADT/MapVector.h"
18 : #include "llvm/IR/Constants.h"
19 : #include "llvm/IR/FMF.h"
20 : #include "llvm/IR/GEPNoWrapFlags.h"
21 : #include "llvm/IR/Instruction.h"
22 : #include "llvm/IR/Type.h"
23 : #include "llvm/IR/Value.h"
24 : #include "llvm/Support/Casting.h"
25 : #include <cstddef>
26 : #include <optional>
27 :
28 : namespace llvm {
29 :
30 : /// This is a utility class that provides an abstraction for the common
31 : /// functionality between Instructions and ConstantExprs.
32 : class Operator : public User {
33 : public:
34 : // The Operator class is intended to be used as a utility, and is never itself
35 : // instantiated.
36 : Operator() = delete;
37 : ~Operator() = delete;
38 :
39 : void *operator new(size_t s) = delete;
40 :
41 : /// Return the opcode for this Instruction or ConstantExpr.
42 : unsigned getOpcode() const {
43 : if (const Instruction *I = dyn_cast<Instruction>(this))
44 : return I->getOpcode();
45 : return cast<ConstantExpr>(this)->getOpcode();
46 : }
47 :
48 : /// If V is an Instruction or ConstantExpr, return its opcode.
49 : /// Otherwise return UserOp1.
50 : static unsigned getOpcode(const Value *V) {
51 : if (const Instruction *I = dyn_cast<Instruction>(V))
52 : return I->getOpcode();
53 : if (const ConstantExpr *CE = dyn_cast<ConstantExpr>(V))
54 : return CE->getOpcode();
55 : return Instruction::UserOp1;
56 : }
57 :
58 : static bool classof(const Instruction *) { return true; }
59 : static bool classof(const ConstantExpr *) { return true; }
60 : static bool classof(const Value *V) {
61 : return isa<Instruction>(V) || isa<ConstantExpr>(V);
62 : }
63 :
64 : /// Return true if this operator has flags which may cause this operator
65 : /// to evaluate to poison despite having non-poison inputs.
66 : bool hasPoisonGeneratingFlags() const;
67 :
68 : /// Return true if this operator has poison-generating flags,
69 : /// return attributes or metadata. The latter two is only possible for
70 : /// instructions.
71 : bool hasPoisonGeneratingAnnotations() const;
72 : };
73 :
74 : /// Utility class for integer operators which may exhibit overflow - Add, Sub,
75 : /// Mul, and Shl. It does not include SDiv, despite that operator having the
76 : /// potential for overflow.
77 : class OverflowingBinaryOperator : public Operator {
78 : public:
79 : enum {
80 : AnyWrap = 0,
81 : NoUnsignedWrap = (1 << 0),
82 : NoSignedWrap = (1 << 1)
83 : };
84 :
85 : private:
86 : friend class Instruction;
87 : friend class ConstantExpr;
88 :
89 : void setHasNoUnsignedWrap(bool B) {
90 : SubclassOptionalData =
91 : (SubclassOptionalData & ~NoUnsignedWrap) | (B * NoUnsignedWrap);
92 : }
93 : void setHasNoSignedWrap(bool B) {
94 : SubclassOptionalData =
95 : (SubclassOptionalData & ~NoSignedWrap) | (B * NoSignedWrap);
96 : }
97 :
98 : public:
99 : /// Transparently provide more efficient getOperand methods.
100 : DECLARE_TRANSPARENT_OPERAND_ACCESSORS(Value);
101 :
102 : /// Test whether this operation is known to never
103 : /// undergo unsigned overflow, aka the nuw property.
104 : bool hasNoUnsignedWrap() const {
105 : return SubclassOptionalData & NoUnsignedWrap;
106 : }
107 :
108 : /// Test whether this operation is known to never
109 : /// undergo signed overflow, aka the nsw property.
110 : bool hasNoSignedWrap() const {
111 : return (SubclassOptionalData & NoSignedWrap) != 0;
112 : }
113 :
114 : /// Returns the no-wrap kind of the operation.
115 : unsigned getNoWrapKind() const {
116 : unsigned NoWrapKind = 0;
117 : if (hasNoUnsignedWrap())
118 : NoWrapKind |= NoUnsignedWrap;
119 :
120 : if (hasNoSignedWrap())
121 : NoWrapKind |= NoSignedWrap;
122 :
123 : return NoWrapKind;
124 : }
125 :
126 : static bool classof(const Instruction *I) {
127 : return I->getOpcode() == Instruction::Add ||
128 : I->getOpcode() == Instruction::Sub ||
129 : I->getOpcode() == Instruction::Mul ||
130 : I->getOpcode() == Instruction::Shl;
131 : }
132 : static bool classof(const ConstantExpr *CE) {
133 : return CE->getOpcode() == Instruction::Add ||
134 : CE->getOpcode() == Instruction::Sub ||
135 : CE->getOpcode() == Instruction::Mul ||
136 : CE->getOpcode() == Instruction::Shl;
137 : }
138 : static bool classof(const Value *V) {
139 : return (isa<Instruction>(V) && classof(cast<Instruction>(V))) ||
140 : (isa<ConstantExpr>(V) && classof(cast<ConstantExpr>(V)));
141 : }
142 : };
143 :
144 : template <>
145 : struct OperandTraits<OverflowingBinaryOperator>
146 : : public FixedNumOperandTraits<OverflowingBinaryOperator, 2> {};
147 :
148 : DEFINE_TRANSPARENT_OPERAND_ACCESSORS(OverflowingBinaryOperator, Value)
149 :
150 : /// A udiv or sdiv instruction, which can be marked as "exact",
151 : /// indicating that no bits are destroyed.
152 : class PossiblyExactOperator : public Operator {
153 : public:
154 : enum {
155 : IsExact = (1 << 0)
156 : };
157 :
158 : private:
159 : friend class Instruction;
160 : friend class ConstantExpr;
161 :
162 : void setIsExact(bool B) {
163 : SubclassOptionalData = (SubclassOptionalData & ~IsExact) | (B * IsExact);
164 : }
165 :
166 : public:
167 : /// Transparently provide more efficient getOperand methods.
168 : DECLARE_TRANSPARENT_OPERAND_ACCESSORS(Value);
169 :
170 : /// Test whether this division is known to be exact, with zero remainder.
171 : bool isExact() const {
172 : return SubclassOptionalData & IsExact;
173 : }
174 :
175 : static bool isPossiblyExactOpcode(unsigned OpC) {
176 : return OpC == Instruction::SDiv ||
177 : OpC == Instruction::UDiv ||
178 : OpC == Instruction::AShr ||
179 : OpC == Instruction::LShr;
180 : }
181 :
182 : static bool classof(const ConstantExpr *CE) {
183 : return isPossiblyExactOpcode(CE->getOpcode());
184 : }
185 : static bool classof(const Instruction *I) {
186 : return isPossiblyExactOpcode(I->getOpcode());
187 : }
188 : static bool classof(const Value *V) {
189 : return (isa<Instruction>(V) && classof(cast<Instruction>(V))) ||
190 : (isa<ConstantExpr>(V) && classof(cast<ConstantExpr>(V)));
191 : }
192 : };
193 :
194 : template <>
195 : struct OperandTraits<PossiblyExactOperator>
196 : : public FixedNumOperandTraits<PossiblyExactOperator, 2> {};
197 :
198 : DEFINE_TRANSPARENT_OPERAND_ACCESSORS(PossiblyExactOperator, Value)
199 :
200 : /// Utility class for floating point operations which can have
201 : /// information about relaxed accuracy requirements attached to them.
202 : class FPMathOperator : public Operator {
203 : private:
204 : friend class Instruction;
205 :
206 : /// 'Fast' means all bits are set.
207 : void setFast(bool B) {
208 : setHasAllowReassoc(B);
209 : setHasNoNaNs(B);
210 : setHasNoInfs(B);
211 : setHasNoSignedZeros(B);
212 : setHasAllowReciprocal(B);
213 : setHasAllowContract(B);
214 : setHasApproxFunc(B);
215 : }
216 :
217 : void setHasAllowReassoc(bool B) {
218 : SubclassOptionalData =
219 : (SubclassOptionalData & ~FastMathFlags::AllowReassoc) |
220 : (B * FastMathFlags::AllowReassoc);
221 : }
222 :
223 : void setHasNoNaNs(bool B) {
224 : SubclassOptionalData =
225 : (SubclassOptionalData & ~FastMathFlags::NoNaNs) |
226 : (B * FastMathFlags::NoNaNs);
227 : }
228 :
229 : void setHasNoInfs(bool B) {
230 : SubclassOptionalData =
231 : (SubclassOptionalData & ~FastMathFlags::NoInfs) |
232 : (B * FastMathFlags::NoInfs);
233 : }
234 :
235 : void setHasNoSignedZeros(bool B) {
236 : SubclassOptionalData =
237 : (SubclassOptionalData & ~FastMathFlags::NoSignedZeros) |
238 : (B * FastMathFlags::NoSignedZeros);
239 : }
240 :
241 : void setHasAllowReciprocal(bool B) {
242 : SubclassOptionalData =
243 : (SubclassOptionalData & ~FastMathFlags::AllowReciprocal) |
244 : (B * FastMathFlags::AllowReciprocal);
245 : }
246 :
247 : void setHasAllowContract(bool B) {
248 : SubclassOptionalData =
249 : (SubclassOptionalData & ~FastMathFlags::AllowContract) |
250 : (B * FastMathFlags::AllowContract);
251 : }
252 :
253 : void setHasApproxFunc(bool B) {
254 : SubclassOptionalData =
255 : (SubclassOptionalData & ~FastMathFlags::ApproxFunc) |
256 : (B * FastMathFlags::ApproxFunc);
257 : }
258 :
259 : /// Convenience function for setting multiple fast-math flags.
260 : /// FMF is a mask of the bits to set.
261 : void setFastMathFlags(FastMathFlags FMF) {
262 : SubclassOptionalData |= FMF.Flags;
263 : }
264 :
265 : /// Convenience function for copying all fast-math flags.
266 : /// All values in FMF are transferred to this operator.
267 : void copyFastMathFlags(FastMathFlags FMF) {
268 : SubclassOptionalData = FMF.Flags;
269 : }
270 :
271 : public:
272 : /// Test if this operation allows all non-strict floating-point transforms.
273 : bool isFast() const {
274 : return ((SubclassOptionalData & FastMathFlags::AllowReassoc) != 0 &&
275 : (SubclassOptionalData & FastMathFlags::NoNaNs) != 0 &&
276 : (SubclassOptionalData & FastMathFlags::NoInfs) != 0 &&
277 : (SubclassOptionalData & FastMathFlags::NoSignedZeros) != 0 &&
278 : (SubclassOptionalData & FastMathFlags::AllowReciprocal) != 0 &&
279 : (SubclassOptionalData & FastMathFlags::AllowContract) != 0 &&
280 : (SubclassOptionalData & FastMathFlags::ApproxFunc) != 0);
281 : }
282 :
283 : /// Test if this operation may be simplified with reassociative transforms.
284 : bool hasAllowReassoc() const {
285 : return (SubclassOptionalData & FastMathFlags::AllowReassoc) != 0;
286 : }
287 :
288 : /// Test if this operation's arguments and results are assumed not-NaN.
289 : bool hasNoNaNs() const {
290 : return (SubclassOptionalData & FastMathFlags::NoNaNs) != 0;
291 : }
292 :
293 : /// Test if this operation's arguments and results are assumed not-infinite.
294 : bool hasNoInfs() const {
295 : return (SubclassOptionalData & FastMathFlags::NoInfs) != 0;
296 : }
297 :
298 : /// Test if this operation can ignore the sign of zero.
299 : bool hasNoSignedZeros() const {
300 : return (SubclassOptionalData & FastMathFlags::NoSignedZeros) != 0;
301 : }
302 :
303 : /// Test if this operation can use reciprocal multiply instead of division.
304 : bool hasAllowReciprocal() const {
305 : return (SubclassOptionalData & FastMathFlags::AllowReciprocal) != 0;
306 : }
307 :
308 : /// Test if this operation can be floating-point contracted (FMA).
309 : bool hasAllowContract() const {
310 : return (SubclassOptionalData & FastMathFlags::AllowContract) != 0;
311 : }
312 :
313 : /// Test if this operation allows approximations of math library functions or
314 : /// intrinsics.
315 : bool hasApproxFunc() const {
316 : return (SubclassOptionalData & FastMathFlags::ApproxFunc) != 0;
317 : }
318 :
319 : /// Convenience function for getting all the fast-math flags
320 : FastMathFlags getFastMathFlags() const {
321 : return FastMathFlags(SubclassOptionalData);
322 : }
323 :
324 : /// Get the maximum error permitted by this operation in ULPs. An accuracy of
325 : /// 0.0 means that the operation should be performed with the default
326 : /// precision.
327 : float getFPAccuracy() const;
328 :
329 0 : static bool classof(const Value *V) {
330 : unsigned Opcode;
331 0 : if (auto *I = dyn_cast<Instruction>(V))
332 0 : Opcode = I->getOpcode();
333 : else
334 0 : return false;
335 :
336 0 : switch (Opcode) {
337 0 : case Instruction::FNeg:
338 : case Instruction::FAdd:
339 : case Instruction::FSub:
340 : case Instruction::FMul:
341 : case Instruction::FDiv:
342 : case Instruction::FRem:
343 : // FIXME: To clean up and correct the semantics of fast-math-flags, FCmp
344 : // should not be treated as a math op, but the other opcodes should.
345 : // This would make things consistent with Select/PHI (FP value type
346 : // determines whether they are math ops and, therefore, capable of
347 : // having fast-math-flags).
348 : case Instruction::FCmp:
349 0 : return true;
350 0 : case Instruction::PHI:
351 : case Instruction::Select:
352 : case Instruction::Call: {
353 0 : Type *Ty = V->getType();
354 0 : while (ArrayType *ArrTy = dyn_cast<ArrayType>(Ty))
355 0 : Ty = ArrTy->getElementType();
356 0 : return Ty->isFPOrFPVectorTy();
357 : }
358 0 : default:
359 0 : return false;
360 : }
361 : }
362 : };
363 :
364 : /// A helper template for defining operators for individual opcodes.
365 : template<typename SuperClass, unsigned Opc>
366 : class ConcreteOperator : public SuperClass {
367 : public:
368 : static bool classof(const Instruction *I) {
369 : return I->getOpcode() == Opc;
370 : }
371 : static bool classof(const ConstantExpr *CE) {
372 : return CE->getOpcode() == Opc;
373 : }
374 : static bool classof(const Value *V) {
375 : return (isa<Instruction>(V) && classof(cast<Instruction>(V))) ||
376 : (isa<ConstantExpr>(V) && classof(cast<ConstantExpr>(V)));
377 : }
378 : };
379 :
380 : class AddOperator
381 : : public ConcreteOperator<OverflowingBinaryOperator, Instruction::Add> {
382 : };
383 : class SubOperator
384 : : public ConcreteOperator<OverflowingBinaryOperator, Instruction::Sub> {
385 : };
386 : class MulOperator
387 : : public ConcreteOperator<OverflowingBinaryOperator, Instruction::Mul> {
388 : };
389 : class ShlOperator
390 : : public ConcreteOperator<OverflowingBinaryOperator, Instruction::Shl> {
391 : };
392 :
393 : class AShrOperator
394 : : public ConcreteOperator<PossiblyExactOperator, Instruction::AShr> {
395 : };
396 : class LShrOperator
397 : : public ConcreteOperator<PossiblyExactOperator, Instruction::LShr> {
398 : };
399 :
400 : class GEPOperator
401 : : public ConcreteOperator<Operator, Instruction::GetElementPtr> {
402 : public:
403 : /// Transparently provide more efficient getOperand methods.
404 : DECLARE_TRANSPARENT_OPERAND_ACCESSORS(Value);
405 :
406 : GEPNoWrapFlags getNoWrapFlags() const {
407 : return GEPNoWrapFlags::fromRaw(SubclassOptionalData);
408 : }
409 :
410 : /// Test whether this is an inbounds GEP, as defined by LangRef.html.
411 : bool isInBounds() const { return getNoWrapFlags().isInBounds(); }
412 :
413 : bool hasNoUnsignedSignedWrap() const {
414 : return getNoWrapFlags().hasNoUnsignedSignedWrap();
415 : }
416 :
417 : bool hasNoUnsignedWrap() const {
418 : return getNoWrapFlags().hasNoUnsignedWrap();
419 : }
420 :
421 : /// Returns the offset of the index with an inrange attachment, or
422 : /// std::nullopt if none.
423 : std::optional<ConstantRange> getInRange() const;
424 :
425 : inline op_iterator idx_begin() { return op_begin()+1; }
426 : inline const_op_iterator idx_begin() const { return op_begin()+1; }
427 : inline op_iterator idx_end() { return op_end(); }
428 : inline const_op_iterator idx_end() const { return op_end(); }
429 :
430 : inline iterator_range<op_iterator> indices() {
431 : return make_range(idx_begin(), idx_end());
432 : }
433 :
434 : inline iterator_range<const_op_iterator> indices() const {
435 : return make_range(idx_begin(), idx_end());
436 : }
437 :
438 : Value *getPointerOperand() {
439 : return getOperand(0);
440 : }
441 : const Value *getPointerOperand() const {
442 : return getOperand(0);
443 : }
444 : static unsigned getPointerOperandIndex() {
445 : return 0U; // get index for modifying correct operand
446 : }
447 :
448 : /// Method to return the pointer operand as a PointerType.
449 : Type *getPointerOperandType() const {
450 : return getPointerOperand()->getType();
451 : }
452 :
453 : Type *getSourceElementType() const;
454 : Type *getResultElementType() const;
455 :
456 : /// Method to return the address space of the pointer operand.
457 : unsigned getPointerAddressSpace() const {
458 : return getPointerOperandType()->getPointerAddressSpace();
459 : }
460 :
461 : unsigned getNumIndices() const { // Note: always non-negative
462 : return getNumOperands() - 1;
463 : }
464 :
465 : bool hasIndices() const {
466 : return getNumOperands() > 1;
467 : }
468 :
469 : /// Return true if all of the indices of this GEP are zeros.
470 : /// If so, the result pointer and the first operand have the same
471 : /// value, just potentially different types.
472 : bool hasAllZeroIndices() const {
473 : for (const_op_iterator I = idx_begin(), E = idx_end(); I != E; ++I) {
474 : if (ConstantInt *C = dyn_cast<ConstantInt>(I))
475 : if (C->isZero())
476 : continue;
477 : return false;
478 : }
479 : return true;
480 : }
481 :
482 : /// Return true if all of the indices of this GEP are constant integers.
483 : /// If so, the result pointer and the first operand have
484 : /// a constant offset between them.
485 : bool hasAllConstantIndices() const {
486 : for (const_op_iterator I = idx_begin(), E = idx_end(); I != E; ++I) {
487 : if (!isa<ConstantInt>(I))
488 : return false;
489 : }
490 : return true;
491 : }
492 :
493 : unsigned countNonConstantIndices() const {
494 : return count_if(indices(), [](const Use& use) {
495 : return !isa<ConstantInt>(*use);
496 : });
497 : }
498 :
499 : /// Compute the maximum alignment that this GEP is garranteed to preserve.
500 : Align getMaxPreservedAlignment(const DataLayout &DL) const;
501 :
502 : /// Accumulate the constant address offset of this GEP if possible.
503 : ///
504 : /// This routine accepts an APInt into which it will try to accumulate the
505 : /// constant offset of this GEP.
506 : ///
507 : /// If \p ExternalAnalysis is provided it will be used to calculate a offset
508 : /// when a operand of GEP is not constant.
509 : /// For example, for a value \p ExternalAnalysis might try to calculate a
510 : /// lower bound. If \p ExternalAnalysis is successful, it should return true.
511 : ///
512 : /// If the \p ExternalAnalysis returns false or the value returned by \p
513 : /// ExternalAnalysis results in a overflow/underflow, this routine returns
514 : /// false and the value of the offset APInt is undefined (it is *not*
515 : /// preserved!).
516 : ///
517 : /// The APInt passed into this routine must be at exactly as wide as the
518 : /// IntPtr type for the address space of the base GEP pointer.
519 : bool accumulateConstantOffset(
520 : const DataLayout &DL, APInt &Offset,
521 : function_ref<bool(Value &, APInt &)> ExternalAnalysis = nullptr) const;
522 :
523 : static bool accumulateConstantOffset(
524 : Type *SourceType, ArrayRef<const Value *> Index, const DataLayout &DL,
525 : APInt &Offset,
526 : function_ref<bool(Value &, APInt &)> ExternalAnalysis = nullptr);
527 :
528 : /// Collect the offset of this GEP as a map of Values to their associated
529 : /// APInt multipliers, as well as a total Constant Offset.
530 : bool collectOffset(const DataLayout &DL, unsigned BitWidth,
531 : MapVector<Value *, APInt> &VariableOffsets,
532 : APInt &ConstantOffset) const;
533 : };
534 :
535 : template <>
536 : struct OperandTraits<GEPOperator>
537 : : public VariadicOperandTraits<GEPOperator, 1> {};
538 :
539 : DEFINE_TRANSPARENT_OPERAND_ACCESSORS(GEPOperator, Value)
540 :
541 : class PtrToIntOperator
542 : : public ConcreteOperator<Operator, Instruction::PtrToInt> {
543 : friend class PtrToInt;
544 : friend class ConstantExpr;
545 :
546 : public:
547 : /// Transparently provide more efficient getOperand methods.
548 : DECLARE_TRANSPARENT_OPERAND_ACCESSORS(Value);
549 :
550 : Value *getPointerOperand() {
551 : return getOperand(0);
552 : }
553 : const Value *getPointerOperand() const {
554 : return getOperand(0);
555 : }
556 :
557 : static unsigned getPointerOperandIndex() {
558 : return 0U; // get index for modifying correct operand
559 : }
560 :
561 : /// Method to return the pointer operand as a PointerType.
562 : Type *getPointerOperandType() const {
563 : return getPointerOperand()->getType();
564 : }
565 :
566 : /// Method to return the address space of the pointer operand.
567 : unsigned getPointerAddressSpace() const {
568 : return cast<PointerType>(getPointerOperandType())->getAddressSpace();
569 : }
570 : };
571 :
572 : template <>
573 : struct OperandTraits<PtrToIntOperator>
574 : : public FixedNumOperandTraits<PtrToIntOperator, 1> {};
575 :
576 : DEFINE_TRANSPARENT_OPERAND_ACCESSORS(PtrToIntOperator, Value)
577 :
578 : class BitCastOperator
579 : : public ConcreteOperator<Operator, Instruction::BitCast> {
580 : friend class BitCastInst;
581 : friend class ConstantExpr;
582 :
583 : public:
584 : /// Transparently provide more efficient getOperand methods.
585 : DECLARE_TRANSPARENT_OPERAND_ACCESSORS(Value);
586 :
587 : Type *getSrcTy() const {
588 : return getOperand(0)->getType();
589 : }
590 :
591 : Type *getDestTy() const {
592 : return getType();
593 : }
594 : };
595 :
596 : template <>
597 : struct OperandTraits<BitCastOperator>
598 : : public FixedNumOperandTraits<BitCastOperator, 1> {};
599 :
600 : DEFINE_TRANSPARENT_OPERAND_ACCESSORS(BitCastOperator, Value)
601 :
602 : class AddrSpaceCastOperator
603 : : public ConcreteOperator<Operator, Instruction::AddrSpaceCast> {
604 : friend class AddrSpaceCastInst;
605 : friend class ConstantExpr;
606 :
607 : public:
608 : /// Transparently provide more efficient getOperand methods.
609 : DECLARE_TRANSPARENT_OPERAND_ACCESSORS(Value);
610 :
611 : Value *getPointerOperand() { return getOperand(0); }
612 :
613 : const Value *getPointerOperand() const { return getOperand(0); }
614 :
615 : unsigned getSrcAddressSpace() const {
616 : return getPointerOperand()->getType()->getPointerAddressSpace();
617 : }
618 :
619 : unsigned getDestAddressSpace() const {
620 : return getType()->getPointerAddressSpace();
621 : }
622 : };
623 :
624 : template <>
625 : struct OperandTraits<AddrSpaceCastOperator>
626 : : public FixedNumOperandTraits<AddrSpaceCastOperator, 1> {};
627 :
628 : DEFINE_TRANSPARENT_OPERAND_ACCESSORS(AddrSpaceCastOperator, Value)
629 :
630 : } // end namespace llvm
631 :
632 : #endif // LLVM_IR_OPERATOR_H
|