summaryrefslogtreecommitdiff
path: root/clang/lib/CIR/CodeGen/Address.h
blob: c8ce530a7b0d392d239ad18d298862ca8f409547 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This class provides a simple wrapper for a pair of a pointer and an
// alignment.
//
//===----------------------------------------------------------------------===//

#ifndef CLANG_LIB_CIR_ADDRESS_H
#define CLANG_LIB_CIR_ADDRESS_H

#include "mlir/IR/Value.h"
#include "clang/AST/CharUnits.h"
#include "clang/CIR/Dialect/IR/CIRAttrs.h"
#include "clang/CIR/Dialect/IR/CIRTypes.h"
#include "clang/CIR/MissingFeatures.h"
#include "llvm/ADT/PointerIntPair.h"
#include "llvm/Support/Casting.h"

namespace clang::CIRGen {

// Forward declaration to avoid a circular dependency
class CIRGenBuilderTy;

class Address {

  // The boolean flag indicates whether the pointer is known to be non-null.
  llvm::PointerIntPair<mlir::Value, 1, bool> pointerAndKnownNonNull;

  /// The expected CIR type of the pointer. Carrying accurate element type
  /// information in Address makes it more convenient to work with Address
  /// values and allows frontend assertions to catch simple mistakes.
  mlir::Type elementType;

  clang::CharUnits alignment;

protected:
  Address(std::nullptr_t) : elementType(nullptr) {}

public:
  Address(mlir::Value pointer, mlir::Type elementType,
          clang::CharUnits alignment)
      : pointerAndKnownNonNull(pointer, false), elementType(elementType),
        alignment(alignment) {
    assert(pointer && "Pointer cannot be null");
    assert(elementType && "Element type cannot be null");
    assert(!alignment.isZero() && "Alignment cannot be zero");

    assert(mlir::isa<cir::PointerType>(pointer.getType()) &&
           "Expected cir.ptr type");

    assert(mlir::cast<cir::PointerType>(pointer.getType()).getPointee() ==
           elementType);
  }

  Address(mlir::Value pointer, clang::CharUnits alignment)
      : Address(pointer,
                mlir::cast<cir::PointerType>(pointer.getType()).getPointee(),
                alignment) {
    assert((!alignment.isZero() || pointer == nullptr) &&
           "creating valid address with invalid alignment");
  }

  static Address invalid() { return Address(nullptr); }
  bool isValid() const {
    return pointerAndKnownNonNull.getPointer() != nullptr;
  }

  /// Return address with different pointer, but same element type and
  /// alignment.
  Address withPointer(mlir::Value newPtr) const {
    return Address(newPtr, getElementType(), getAlignment());
  }

  /// Return address with different element type, a bitcast pointer, and
  /// the same alignment.
  Address withElementType(CIRGenBuilderTy &builder, mlir::Type ElemTy) const;

  mlir::Value getPointer() const {
    assert(isValid());
    return pointerAndKnownNonNull.getPointer();
  }

  mlir::Value getBasePointer() const {
    // TODO(cir): Remove the version above when we catchup with OG codegen on
    // ptr auth.
    assert(isValid() && "pointer isn't valid");
    return getPointer();
  }

  /// Return the pointer contained in this class after authenticating it and
  /// adding offset to it if necessary.
  mlir::Value emitRawPointer() const {
    assert(!cir::MissingFeatures::addressPointerAuthInfo());
    return getBasePointer();
  }

  mlir::Type getType() const {
    assert(mlir::cast<cir::PointerType>(
               pointerAndKnownNonNull.getPointer().getType())
               .getPointee() == elementType);

    return mlir::cast<cir::PointerType>(getPointer().getType());
  }

  mlir::Type getElementType() const {
    assert(isValid());
    assert(mlir::cast<cir::PointerType>(
               pointerAndKnownNonNull.getPointer().getType())
               .getPointee() == elementType);
    return elementType;
  }

  cir::TargetAddressSpaceAttr getAddressSpace() const {
    auto ptrTy = mlir::dyn_cast<cir::PointerType>(getType());
    return ptrTy.getAddrSpace();
  }

  clang::CharUnits getAlignment() const { return alignment; }

  /// Get the operation which defines this address.
  mlir::Operation *getDefiningOp() const {
    if (!isValid())
      return nullptr;
    return getPointer().getDefiningOp();
  }

  template <typename OpTy> OpTy getDefiningOp() const {
    return mlir::dyn_cast_or_null<OpTy>(getDefiningOp());
  }
};

} // namespace clang::CIRGen

#endif // CLANG_LIB_CIR_ADDRESS_H