clang 23.0.0git
InterpStack.h
Go to the documentation of this file.
1//===--- InterpStack.h - Stack implementation 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// Defines the upwards-growing stack used by the interpreter.
10//
11//===----------------------------------------------------------------------===//
12
13#ifndef LLVM_CLANG_AST_INTERP_INTERPSTACK_H
14#define LLVM_CLANG_AST_INTERP_INTERPSTACK_H
15
16#include "FixedPoint.h"
17#include "IntegralAP.h"
18#include "MemberPointer.h"
19#include "PrimType.h"
20
21namespace clang {
22namespace interp {
23
24/// Stack frame storing temporaries and parameters.
25class InterpStack final {
26public:
27 InterpStack() = default;
28
29 /// Destroys the stack, freeing up storage.
31
32 /// Constructs a value in place on the top of the stack.
33 template <typename T, typename... Tys> void push(Tys &&...Args) {
34 new (grow<aligned_size<T>()>()) T(std::forward<Tys>(Args)...);
35 ItemTypes.push_back(toPrimType<T>());
36 }
37
38 /// Returns the value from the top of the stack and removes it.
39 template <typename T> T pop() {
40 assert(!ItemTypes.empty());
41 assert(ItemTypes.back() == toPrimType<T>());
42 ItemTypes.pop_back();
43 T *Ptr = &peekInternal<T>();
44 T Value = std::move(*Ptr);
45 shrink(aligned_size<T>());
46 return Value;
47 }
48
49 /// Discards the top value from the stack.
50 template <typename T> void discard() {
51 assert(!ItemTypes.empty());
52 assert(ItemTypes.back() == toPrimType<T>());
53 ItemTypes.pop_back();
54 T *Ptr = &peekInternal<T>();
55 if constexpr (!std::is_trivially_destructible_v<T>) {
56 Ptr->~T();
57 }
58 shrink(aligned_size<T>());
59 }
60 void discardSlow();
61
62 /// Returns a reference to the value on the top of the stack.
63 template <typename T> T &peek() const {
64 assert(!ItemTypes.empty());
65 assert(ItemTypes.back() == toPrimType<T>());
66 return peekInternal<T>();
67 }
68
69 template <typename T> T &peek(size_t Offset) const {
70 assert(aligned(Offset));
71 return *reinterpret_cast<T *>(peekData(Offset));
72 }
73
74 /// Returns a pointer to the top object.
75 void *top() const { return Chunk ? peekData(0) : nullptr; }
76
77 /// Returns the size of the stack in bytes.
78 size_t size() const { return StackSize; }
79
80 /// Clears the stack.
81 void clear();
82 void clearTo(size_t NewSize);
83
84 /// Returns whether the stack is empty.
85 bool empty() const { return StackSize == 0; }
86
87 /// dump the stack contents to stderr.
88 void dump() const;
89
90private:
91 /// All stack slots are aligned to the native pointer alignment for storage.
92 /// The size of an object is rounded up to a pointer alignment multiple.
93 template <typename T> static constexpr size_t aligned_size() {
94 constexpr size_t PtrAlign = alignof(void *);
95 return ((sizeof(T) + PtrAlign - 1) / PtrAlign) * PtrAlign;
96 }
97
98 /// Like the public peek(), but without the debug type checks.
99 template <typename T> T &peekInternal() const {
100 return *reinterpret_cast<T *>(peekData(aligned_size<T>()));
101 }
102
103 /// Grows the stack to accommodate a value and returns a pointer to it.
104 template <size_t Size> void *grow() {
105 assert(Size < ChunkSize - sizeof(StackChunk) && "Object too large");
106 static_assert(aligned(Size));
107
108 // Allocate a new stack chunk if necessary.
109 if (LLVM_UNLIKELY(!Chunk)) {
110 Chunk = new (std::malloc(ChunkSize)) StackChunk(Chunk);
111 } else if (LLVM_UNLIKELY(Chunk->size() >
112 ChunkSize - sizeof(StackChunk) - Size)) {
113 if (Chunk->Next) {
114 Chunk = Chunk->Next;
115 } else {
116 StackChunk *Next = new (std::malloc(ChunkSize)) StackChunk(Chunk);
117 Chunk->Next = Next;
118 Chunk = Next;
119 }
120 }
121
122 auto *Object = reinterpret_cast<void *>(Chunk->start() + Chunk->Size);
123 Chunk->Size += Size;
124 StackSize += Size;
125 return Object;
126 }
127
128 /// Returns a pointer from the top of the stack.
129 void *peekData(size_t Size) const;
130 /// Shrinks the stack.
131 void shrink(size_t Size);
132
133 /// Allocate stack space in 1Mb chunks.
134 static constexpr size_t ChunkSize = 1024 * 1024;
135
136 /// Metadata for each stack chunk.
137 ///
138 /// The stack is composed of a linked list of chunks. Whenever an allocation
139 /// is out of bounds, a new chunk is linked. When a chunk becomes empty,
140 /// it is not immediately freed: a chunk is deallocated only when the
141 /// predecessor becomes empty.
142 struct StackChunk {
143 StackChunk *Next;
144 StackChunk *Prev;
145 uint32_t Size;
146
147 StackChunk(StackChunk *Prev = nullptr)
148 : Next(nullptr), Prev(Prev), Size(0) {}
149
150 /// Returns the size of the chunk, minus the header.
151 size_t size() const { return Size; }
152
153 /// Returns a pointer to the start of the data region.
154 char *start() { return reinterpret_cast<char *>(this + 1); }
155 const char *start() const {
156 return reinterpret_cast<const char *>(this + 1);
157 }
158 };
159 static_assert(sizeof(StackChunk) < ChunkSize, "Invalid chunk size");
160
161 /// First chunk on the stack.
162 StackChunk *Chunk = nullptr;
163 /// Total size of the stack.
164 size_t StackSize = 0;
165
166 /// SmallVector recording the type of data we pushed into the stack.
167 /// We don't usually need this during normal code interpretation but
168 /// when aborting, we need type information to call the destructors
169 /// for what's left on the stack.
170 llvm::SmallVector<PrimType> ItemTypes;
171
172 template <typename T> static constexpr PrimType toPrimType() {
173 if constexpr (std::is_same_v<T, Pointer>)
174 return PT_Ptr;
175 else if constexpr (std::is_same_v<T, bool> || std::is_same_v<T, Boolean>)
176 return PT_Bool;
177 else if constexpr (std::is_same_v<T, int8_t> ||
178 std::is_same_v<T, Char<true>>)
179 return PT_Sint8;
180 else if constexpr (std::is_same_v<T, uint8_t> ||
181 std::is_same_v<T, Char<false>>)
182 return PT_Uint8;
183 else if constexpr (std::is_same_v<T, Integral<16, true>>)
184 return PT_Sint16;
185 else if constexpr (std::is_same_v<T, Integral<16, false>>)
186 return PT_Uint16;
187 else if constexpr (std::is_same_v<T, Integral<32, true>>)
188 return PT_Sint32;
189 else if constexpr (std::is_same_v<T, Integral<32, false>>)
190 return PT_Uint32;
191 else if constexpr (std::is_same_v<T, Integral<64, true>>)
192 return PT_Sint64;
193 else if constexpr (std::is_same_v<T, Integral<64, false>>)
194 return PT_Uint64;
195
196 else if constexpr (std::is_same_v<T, Floating>)
197 return PT_Float;
198 else if constexpr (std::is_same_v<T, IntegralAP<true>>)
199 return PT_IntAP;
200 else if constexpr (std::is_same_v<T, IntegralAP<false>>)
201 return PT_IntAP;
202 else if constexpr (std::is_same_v<T, MemberPointer>)
203 return PT_MemberPtr;
204 else if constexpr (std::is_same_v<T, FixedPoint>)
205 return PT_FixedPoint;
206
207 llvm_unreachable("unknown type push()'ed into InterpStack");
208 }
209};
210
211} // namespace interp
212} // namespace clang
213
214#endif
FormatToken * Next
The next token in the unwrapped line.
llvm::json::Object Object
void clearTo(size_t NewSize)
T pop()
Returns the value from the top of the stack and removes it.
Definition InterpStack.h:39
void push(Tys &&...Args)
Constructs a value in place on the top of the stack.
Definition InterpStack.h:33
T & peek(size_t Offset) const
Definition InterpStack.h:69
void dump() const
dump the stack contents to stderr.
void * top() const
Returns a pointer to the top object.
Definition InterpStack.h:75
void clear()
Clears the stack.
size_t size() const
Returns the size of the stack in bytes.
Definition InterpStack.h:78
bool empty() const
Returns whether the stack is empty.
Definition InterpStack.h:85
void discard()
Discards the top value from the stack.
Definition InterpStack.h:50
~InterpStack()
Destroys the stack, freeing up storage.
T & peek() const
Returns a reference to the value on the top of the stack.
Definition InterpStack.h:63
constexpr bool aligned(uintptr_t Value)
Definition PrimType.h:205
PrimType
Enumeration of the primitive types of the VM.
Definition PrimType.h:34
The JSON file list parser is used to communicate input to InstallAPI.
nullptr
This class represents a compute construct, representing a 'Kind' of ‘parallel’, 'serial',...
__packed_splat4 __packed_splat2 __packed_splat8 __packed_splat4 __packed_splat2 __packed_splat4 __packed_splat2 __packed_splat8 __packed_splat4 uint32_t