Coverage Report

Created: 2020-11-24 06:42

/Users/buildslave/jenkins/workspace/coverage/llvm-project/clang/lib/AST/Interp/ByteCodeEmitter.cpp
Line
Count
Source (jump to first uncovered line)
1
//===--- ByteCodeEmitter.cpp - Instruction emitter for the VM ---*- 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
#include "ByteCodeEmitter.h"
10
#include "Context.h"
11
#include "Opcode.h"
12
#include "Program.h"
13
#include "clang/AST/DeclCXX.h"
14
15
using namespace clang;
16
using namespace clang::interp;
17
18
using APSInt = llvm::APSInt;
19
using Error = llvm::Error;
20
21
1
Expected<Function *> ByteCodeEmitter::compileFunc(const FunctionDecl *F) {
22
  // Do not try to compile undefined functions.
23
1
  if (!F->isDefined(F) || (!F->hasBody() && 
F->willHaveBody()0
))
24
0
    return nullptr;
25
26
  // Set up argument indices.
27
1
  unsigned ParamOffset = 0;
28
1
  SmallVector<PrimType, 8> ParamTypes;
29
1
  llvm::DenseMap<unsigned, Function::ParamDescriptor> ParamDescriptors;
30
31
  // If the return is not a primitive, a pointer to the storage where the value
32
  // is initialized in is passed as the first argument.
33
1
  QualType Ty = F->getReturnType();
34
1
  if (!Ty->isVoidType() && !Ctx.classify(Ty)) {
35
0
    ParamTypes.push_back(PT_Ptr);
36
0
    ParamOffset += align(primSize(PT_Ptr));
37
0
  }
38
39
  // Assign descriptors to all parameters.
40
  // Composite objects are lowered to pointers.
41
2
  for (const ParmVarDecl *PD : F->parameters()) {
42
2
    PrimType Ty;
43
2
    if (llvm::Optional<PrimType> T = Ctx.classify(PD->getType())) {
44
2
      Ty = *T;
45
0
    } else {
46
0
      Ty = PT_Ptr;
47
0
    }
48
49
2
    Descriptor *Desc = P.createDescriptor(PD, Ty);
50
2
    ParamDescriptors.insert({ParamOffset, {Ty, Desc}});
51
2
    Params.insert({PD, ParamOffset});
52
2
    ParamOffset += align(primSize(Ty));
53
2
    ParamTypes.push_back(Ty);
54
2
  }
55
56
  // Create a handle over the emitted code.
57
1
  Function *Func = P.createFunction(F, ParamOffset, std::move(ParamTypes),
58
1
                                    std::move(ParamDescriptors));
59
  // Compile the function body.
60
1
  if (!F->isConstexpr() || !visitFunc(F)) {
61
    // Return a dummy function if compilation failed.
62
0
    if (BailLocation)
63
0
      return llvm::make_error<ByteCodeGenError>(*BailLocation);
64
0
    else
65
0
      return Func;
66
1
  } else {
67
    // Create scopes from descriptors.
68
1
    llvm::SmallVector<Scope, 2> Scopes;
69
0
    for (auto &DS : Descriptors) {
70
0
      Scopes.emplace_back(std::move(DS));
71
0
    }
72
73
    // Set the function's code.
74
1
    Func->setCode(NextLocalOffset, std::move(Code), std::move(SrcMap),
75
1
                  std::move(Scopes));
76
1
    return Func;
77
1
  }
78
1
}
79
80
0
Scope::Local ByteCodeEmitter::createLocal(Descriptor *D) {
81
0
  NextLocalOffset += sizeof(Block);
82
0
  unsigned Location = NextLocalOffset;
83
0
  NextLocalOffset += align(D->getAllocSize());
84
0
  return {Location, D};
85
0
}
86
87
2
void ByteCodeEmitter::emitLabel(LabelTy Label) {
88
2
  const size_t Target = Code.size();
89
2
  LabelOffsets.insert({Label, Target});
90
2
  auto It = LabelRelocs.find(Label);
91
2
  if (It != LabelRelocs.end()) {
92
2
    for (unsigned Reloc : It->second) {
93
2
      using namespace llvm::support;
94
95
      /// Rewrite the operand of all jumps to this label.
96
2
      void *Location = Code.data() + Reloc - sizeof(int32_t);
97
2
      const int32_t Offset = Target - static_cast<int64_t>(Reloc);
98
2
      endian::write<int32_t, endianness::native, 1>(Location, Offset);
99
2
    }
100
2
    LabelRelocs.erase(It);
101
2
  }
102
2
}
103
104
2
int32_t ByteCodeEmitter::getOffset(LabelTy Label) {
105
  // Compute the PC offset which the jump is relative to.
106
2
  const int64_t Position = Code.size() + sizeof(Opcode) + sizeof(int32_t);
107
108
  // If target is known, compute jump offset.
109
2
  auto It = LabelOffsets.find(Label);
110
2
  if (It != LabelOffsets.end()) {
111
0
    return It->second - Position;
112
0
  }
113
114
  // Otherwise, record relocation and return dummy offset.
115
2
  LabelRelocs[Label].push_back(Position);
116
2
  return 0ull;
117
2
}
118
119
0
bool ByteCodeEmitter::bail(const SourceLocation &Loc) {
120
0
  if (!BailLocation)
121
0
    BailLocation = Loc;
122
0
  return false;
123
0
}
124
125
template <typename... Tys>
126
14
bool ByteCodeEmitter::emitOp(Opcode Op, const Tys &... Args, const SourceInfo &SI) {
127
14
  bool Success = true;
128
129
  /// Helper to write bytecode and bail out if 32-bit offsets become invalid.
130
22
  auto emit = [this, &Success](const char *Data, size_t Size) {
131
22
    if (Code.size() + Size > std::numeric_limits<unsigned>::max()) {
132
0
      Success = false;
133
0
      return;
134
0
    }
135
22
    Code.insert(Code.end(), Data, Data + Size);
136
22
  };
bool clang::interp::ByteCodeEmitter::emitOp<>(clang::interp::Opcode, clang::interp::SourceInfo const&)::'lambda'(char const*, unsigned long)::operator()(char const*, unsigned long) const
Line
Count
Source
130
6
  auto emit = [this, &Success](const char *Data, size_t Size) {
131
6
    if (Code.size() + Size > std::numeric_limits<unsigned>::max()) {
132
0
      Success = false;
133
0
      return;
134
0
    }
135
6
    Code.insert(Code.end(), Data, Data + Size);
136
6
  };
Unexecuted instantiation: bool clang::interp::ByteCodeEmitter::emitOp<bool>(clang::interp::Opcode, bool const&, clang::interp::SourceInfo const&)::'lambda'(char const*, unsigned long)::operator()(char const*, unsigned long) const
Unexecuted instantiation: bool clang::interp::ByteCodeEmitter::emitOp<short>(clang::interp::Opcode, short const&, clang::interp::SourceInfo const&)::'lambda'(char const*, unsigned long)::operator()(char const*, unsigned long) const
bool clang::interp::ByteCodeEmitter::emitOp<int>(clang::interp::Opcode, int const&, clang::interp::SourceInfo const&)::'lambda'(char const*, unsigned long)::operator()(char const*, unsigned long) const
Line
Count
Source
130
4
  auto emit = [this, &Success](const char *Data, size_t Size) {
131
4
    if (Code.size() + Size > std::numeric_limits<unsigned>::max()) {
132
0
      Success = false;
133
0
      return;
134
0
    }
135
4
    Code.insert(Code.end(), Data, Data + Size);
136
4
  };
Unexecuted instantiation: bool clang::interp::ByteCodeEmitter::emitOp<long long>(clang::interp::Opcode, long long const&, clang::interp::SourceInfo const&)::'lambda'(char const*, unsigned long)::operator()(char const*, unsigned long) const
Unexecuted instantiation: bool clang::interp::ByteCodeEmitter::emitOp<signed char>(clang::interp::Opcode, signed char const&, clang::interp::SourceInfo const&)::'lambda'(char const*, unsigned long)::operator()(char const*, unsigned long) const
Unexecuted instantiation: bool clang::interp::ByteCodeEmitter::emitOp<unsigned short>(clang::interp::Opcode, unsigned short const&, clang::interp::SourceInfo const&)::'lambda'(char const*, unsigned long)::operator()(char const*, unsigned long) const
bool clang::interp::ByteCodeEmitter::emitOp<unsigned int>(clang::interp::Opcode, unsigned int const&, clang::interp::SourceInfo const&)::'lambda'(char const*, unsigned long)::operator()(char const*, unsigned long) const
Line
Count
Source
130
12
  auto emit = [this, &Success](const char *Data, size_t Size) {
131
12
    if (Code.size() + Size > std::numeric_limits<unsigned>::max()) {
132
0
      Success = false;
133
0
      return;
134
0
    }
135
12
    Code.insert(Code.end(), Data, Data + Size);
136
12
  };
Unexecuted instantiation: bool clang::interp::ByteCodeEmitter::emitOp<unsigned long long>(clang::interp::Opcode, unsigned long long const&, clang::interp::SourceInfo const&)::'lambda'(char const*, unsigned long)::operator()(char const*, unsigned long) const
Unexecuted instantiation: bool clang::interp::ByteCodeEmitter::emitOp<unsigned char>(clang::interp::Opcode, unsigned char const&, clang::interp::SourceInfo const&)::'lambda'(char const*, unsigned long)::operator()(char const*, unsigned long) const
Unexecuted instantiation: bool clang::interp::ByteCodeEmitter::emitOp<clang::RecordDecl const*>(clang::interp::Opcode, clang::RecordDecl const* const&, clang::interp::SourceInfo const&)::'lambda'(char const*, unsigned long)::operator()(char const*, unsigned long) const
Unexecuted instantiation: bool clang::interp::ByteCodeEmitter::emitOp<clang::interp::Record::Field const*>(clang::interp::Opcode, clang::interp::Record::Field const* const&, clang::interp::SourceInfo const&)::'lambda'(char const*, unsigned long)::operator()(char const*, unsigned long) const
137
138
  /// The opcode is followed by arguments. The source info is
139
  /// attached to the address after the opcode.
140
14
  emit(reinterpret_cast<const char *>(&Op), sizeof(Opcode));
141
14
  if (SI)
142
11
    SrcMap.emplace_back(Code.size(), SI);
143
144
  /// The initializer list forces the expression to be evaluated
145
  /// for each argument in the variadic template, in order.
146
14
  (void)std::initializer_list<int>{
147
14
      (emit(reinterpret_cast<const char *>(&Args), sizeof(Args)), 0)...};
148
149
14
  return Success;
150
14
}
bool clang::interp::ByteCodeEmitter::emitOp<>(clang::interp::Opcode, clang::interp::SourceInfo const&)
Line
Count
Source
126
6
bool ByteCodeEmitter::emitOp(Opcode Op, const Tys &... Args, const SourceInfo &SI) {
127
6
  bool Success = true;
128
129
  /// Helper to write bytecode and bail out if 32-bit offsets become invalid.
130
6
  auto emit = [this, &Success](const char *Data, size_t Size) {
131
6
    if (Code.size() + Size > std::numeric_limits<unsigned>::max()) {
132
6
      Success = false;
133
6
      return;
134
6
    }
135
6
    Code.insert(Code.end(), Data, Data + Size);
136
6
  };
137
138
  /// The opcode is followed by arguments. The source info is
139
  /// attached to the address after the opcode.
140
6
  emit(reinterpret_cast<const char *>(&Op), sizeof(Opcode));
141
6
  if (SI)
142
5
    SrcMap.emplace_back(Code.size(), SI);
143
144
  /// The initializer list forces the expression to be evaluated
145
  /// for each argument in the variadic template, in order.
146
6
  (void)std::initializer_list<int>{
147
6
      (emit(reinterpret_cast<const char *>(&Args), sizeof(Args)), 0)...};
148
149
6
  return Success;
150
6
}
Unexecuted instantiation: bool clang::interp::ByteCodeEmitter::emitOp<bool>(clang::interp::Opcode, bool const&, clang::interp::SourceInfo const&)
Unexecuted instantiation: bool clang::interp::ByteCodeEmitter::emitOp<short>(clang::interp::Opcode, short const&, clang::interp::SourceInfo const&)
bool clang::interp::ByteCodeEmitter::emitOp<int>(clang::interp::Opcode, int const&, clang::interp::SourceInfo const&)
Line
Count
Source
126
2
bool ByteCodeEmitter::emitOp(Opcode Op, const Tys &... Args, const SourceInfo &SI) {
127
2
  bool Success = true;
128
129
  /// Helper to write bytecode and bail out if 32-bit offsets become invalid.
130
2
  auto emit = [this, &Success](const char *Data, size_t Size) {
131
2
    if (Code.size() + Size > std::numeric_limits<unsigned>::max()) {
132
2
      Success = false;
133
2
      return;
134
2
    }
135
2
    Code.insert(Code.end(), Data, Data + Size);
136
2
  };
137
138
  /// The opcode is followed by arguments. The source info is
139
  /// attached to the address after the opcode.
140
2
  emit(reinterpret_cast<const char *>(&Op), sizeof(Opcode));
141
2
  if (SI)
142
0
    SrcMap.emplace_back(Code.size(), SI);
143
144
  /// The initializer list forces the expression to be evaluated
145
  /// for each argument in the variadic template, in order.
146
2
  (void)std::initializer_list<int>{
147
2
      (emit(reinterpret_cast<const char *>(&Args), sizeof(Args)), 0)...};
148
149
2
  return Success;
150
2
}
Unexecuted instantiation: bool clang::interp::ByteCodeEmitter::emitOp<long long>(clang::interp::Opcode, long long const&, clang::interp::SourceInfo const&)
Unexecuted instantiation: bool clang::interp::ByteCodeEmitter::emitOp<signed char>(clang::interp::Opcode, signed char const&, clang::interp::SourceInfo const&)
Unexecuted instantiation: bool clang::interp::ByteCodeEmitter::emitOp<unsigned short>(clang::interp::Opcode, unsigned short const&, clang::interp::SourceInfo const&)
bool clang::interp::ByteCodeEmitter::emitOp<unsigned int>(clang::interp::Opcode, unsigned int const&, clang::interp::SourceInfo const&)
Line
Count
Source
126
6
bool ByteCodeEmitter::emitOp(Opcode Op, const Tys &... Args, const SourceInfo &SI) {
127
6
  bool Success = true;
128
129
  /// Helper to write bytecode and bail out if 32-bit offsets become invalid.
130
6
  auto emit = [this, &Success](const char *Data, size_t Size) {
131
6
    if (Code.size() + Size > std::numeric_limits<unsigned>::max()) {
132
6
      Success = false;
133
6
      return;
134
6
    }
135
6
    Code.insert(Code.end(), Data, Data + Size);
136
6
  };
137
138
  /// The opcode is followed by arguments. The source info is
139
  /// attached to the address after the opcode.
140
6
  emit(reinterpret_cast<const char *>(&Op), sizeof(Opcode));
141
6
  if (SI)
142
6
    SrcMap.emplace_back(Code.size(), SI);
143
144
  /// The initializer list forces the expression to be evaluated
145
  /// for each argument in the variadic template, in order.
146
6
  (void)std::initializer_list<int>{
147
6
      (emit(reinterpret_cast<const char *>(&Args), sizeof(Args)), 0)...};
148
149
6
  return Success;
150
6
}
Unexecuted instantiation: bool clang::interp::ByteCodeEmitter::emitOp<unsigned long long>(clang::interp::Opcode, unsigned long long const&, clang::interp::SourceInfo const&)
Unexecuted instantiation: bool clang::interp::ByteCodeEmitter::emitOp<unsigned char>(clang::interp::Opcode, unsigned char const&, clang::interp::SourceInfo const&)
Unexecuted instantiation: bool clang::interp::ByteCodeEmitter::emitOp<clang::RecordDecl const*>(clang::interp::Opcode, clang::RecordDecl const* const&, clang::interp::SourceInfo const&)
Unexecuted instantiation: bool clang::interp::ByteCodeEmitter::emitOp<clang::interp::Record::Field const*>(clang::interp::Opcode, clang::interp::Record::Field const* const&, clang::interp::SourceInfo const&)
151
152
0
bool ByteCodeEmitter::jumpTrue(const LabelTy &Label) {
153
0
  return emitJt(getOffset(Label), SourceInfo{});
154
0
}
155
156
1
bool ByteCodeEmitter::jumpFalse(const LabelTy &Label) {
157
1
  return emitJf(getOffset(Label), SourceInfo{});
158
1
}
159
160
1
bool ByteCodeEmitter::jump(const LabelTy &Label) {
161
1
  return emitJmp(getOffset(Label), SourceInfo{});
162
1
}
163
164
0
bool ByteCodeEmitter::fallthrough(const LabelTy &Label) {
165
0
  emitLabel(Label);
166
0
  return true;
167
0
}
168
169
//===----------------------------------------------------------------------===//
170
// Opcode emitters
171
//===----------------------------------------------------------------------===//
172
173
#define GET_LINK_IMPL
174
#include "Opcodes.inc"
175
#undef GET_LINK_IMPL