aboutsummaryrefslogtreecommitdiff
path: root/clang/lib/CIR/CodeGen/CIRGenConstantEmitter.h
blob: d6dac50bb1263abaab596297001664447efb982c (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
//===----------------------------------------------------------------------===//
//
// 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
//
//===----------------------------------------------------------------------===//
//
// A helper class for emitting expressions and values as cir::ConstantOp
// and as initializers for global variables.
//
// Note: this is based on clang's LLVM IR codegen in ConstantEmitter.h, reusing
// this class interface makes it easier move forward with bringing CIR codegen
// to completion.
//
//===----------------------------------------------------------------------===//

#ifndef CLANG_LIB_CIR_CODEGEN_CIRGENCONSTANTEMITTER_H
#define CLANG_LIB_CIR_CODEGEN_CIRGENCONSTANTEMITTER_H

#include "CIRGenFunction.h"
#include "CIRGenModule.h"

namespace clang::CIRGen {

class ConstantEmitter {
public:
  CIRGenModule &cgm;
  const CIRGenFunction *cgf;

private:
  bool abstract = false;

#ifndef NDEBUG
  // Variables used for asserting state consistency.

  /// Whether non-abstract components of the emitter have been initialized.
  bool initializedNonAbstract = false;

  /// Whether the emitter has been finalized.
  bool finalized = false;

  /// Whether the constant-emission failed.
  bool failed = false;
#endif // NDEBUG

  /// Whether we're in a constant context.
  bool inConstantContext = false;

public:
  /// Initialize this emission in the context of the given function.
  /// Use this if the expression might contain contextual references like
  /// block addresses or PredefinedExprs.
  ConstantEmitter(CIRGenFunction &cgf) : cgm(cgf.cgm), cgf(&cgf) {}

  ConstantEmitter(CIRGenModule &cgm, CIRGenFunction *cgf = nullptr)
      : cgm(cgm), cgf(cgf) {}

  ConstantEmitter(const ConstantEmitter &other) = delete;
  ConstantEmitter &operator=(const ConstantEmitter &other) = delete;

  ~ConstantEmitter();

  /// Try to emit the initializer of the given declaration as an abstract
  /// constant.  If this succeeds, the emission must be finalized.
  mlir::Attribute tryEmitForInitializer(const VarDecl &d);

  void finalize(cir::GlobalOp gv);

  // All of the "abstract" emission methods below permit the emission to
  // be immediately discarded without finalizing anything.  Therefore, they
  // must also promise not to do anything that will, in the future, require
  // finalization:
  //
  //   - using the CGF (if present) for anything other than establishing
  //     semantic context; for example, an expression with ignored
  //     side-effects must not be emitted as an abstract expression
  //
  //   - doing anything that would not be safe to duplicate within an
  //     initializer or to propagate to another context; for example,
  //     side effects, or emitting an initialization that requires a
  //     reference to its current location.
  mlir::Attribute emitForMemory(mlir::Attribute c, QualType t);

  /// Try to emit the initializer of the given declaration as an abstract
  /// constant.
  mlir::Attribute tryEmitAbstractForInitializer(const VarDecl &d);

  /// Emit the result of the given expression as an abstract constant,
  /// asserting that it succeeded.  This is only safe to do when the
  /// expression is known to be a constant expression with either a fairly
  /// simple type or a known simple form.
  mlir::Attribute emitAbstract(SourceLocation loc, const APValue &value,
                               QualType t);

  mlir::Attribute tryEmitConstantExpr(const ConstantExpr *ce);

  // These are private helper routines of the constant emitter that
  // can't actually be private because things are split out into helper
  // functions and classes.

  mlir::Attribute tryEmitPrivateForVarInit(const VarDecl &d);

  mlir::Attribute tryEmitPrivate(const APValue &value, QualType destType);
  mlir::Attribute tryEmitPrivateForMemory(const APValue &value, QualType t);

private:
#ifndef NDEBUG
  void initializeNonAbstract() {
    assert(!initializedNonAbstract);
    initializedNonAbstract = true;
    assert(!cir::MissingFeatures::addressSpace());
  }
  mlir::Attribute markIfFailed(mlir::Attribute init) {
    if (!init)
      failed = true;
    return init;
  }
#else
  void initializeNonAbstract() {}
  mlir::Attribute markIfFailed(mlir::Attribute init) { return init; }
#endif // NDEBUG

  class AbstractStateRAII {
    ConstantEmitter &emitter;
    bool oldValue;

  public:
    AbstractStateRAII(ConstantEmitter &emitter, bool value)
        : emitter(emitter), oldValue(emitter.abstract) {
      emitter.abstract = value;
    }
    ~AbstractStateRAII() { emitter.abstract = oldValue; }
  };
};

} // namespace clang::CIRGen

#endif // CLANG_LIB_CIR_CODEGEN_CIRGENCONSTANTEMITTER_H