UDocumentation UE5.7 10.02.2026 (Source)
API documentation for Unreal Engine 5.7
VVMBytecodeEmitter.h
Go to the documentation of this file.
1// Copyright Epic Games, Inc. All Rights Reserved.
2
3#pragma once
4
5#if WITH_VERSE_VM || defined(__INTELLISENSE__)
6
7#include "Containers/Array.h"
12#include "VerseVM/VVMFalse.h"
13#include "VerseVM/VVMLog.h"
14#include "VerseVM/VVMValue.h"
15
16namespace Verse
17{
18struct VProcedure;
19struct FAllocationContext;
20
21struct FOpEmitter
22{
23 struct FLabel
24 {
25 private:
26 friend struct FOpEmitter;
29 : Index(InIndex)
30 {
31 }
32 };
33
34 FOpEmitter(FAllocationContext Context, VUniqueString& FilePath, VUniqueString& ProcedureName, uint32 NumPositionalParameters, uint32 NumNamedParameters)
35 : FilePath(Context, FilePath)
37 , NumRegisters(FRegisterIndex::PARAMETER_START + NumPositionalParameters + NumNamedParameters)
39 , NumNamedParameters(NumNamedParameters)
40 {
41 // Sentinel unwind region covering the function body.
42 UnwindStack.Push(FUnwindRegion{FLabel(0), 0, false});
43 }
44
45 VUniqueString& GetFilePath()
46 {
47 return *FilePath;
48 }
49
50 bool IsEmpty() const { return OpBytes.IsEmpty(); }
51
53 {
54 const uint32 ConstantIndex = Constants.Add(Constant);
56 }
57
59 {
60 Constants[Constant.Index] = Value;
61 }
62
64 {
65 return FRegisterIndex{FRegisterIndex::UNINITIALIZED};
66 }
67
69 {
70 return FRegisterIndex{FRegisterIndex::SELF};
71 }
72
73 FRegisterIndex Scope()
74 {
75 return FRegisterIndex{FRegisterIndex::SCOPE};
76 }
77
78 FRegisterIndex Argument(uint32 ArgumentIndex)
79 {
80 V_DIE_UNLESS(ArgumentIndex < NumPositionalParameters + NumNamedParameters);
81 return FRegisterIndex{FRegisterIndex::PARAMETER_START + ArgumentIndex};
82 }
83
85 {
87 }
88
90 {
91 const uint32 RegisterIndex = NumRegisters++;
93 }
94
96 {
99 return Result;
100 }
101
103 {
105 Reset(Location, Register);
106 return Register;
107 }
108
110 {
112 Reset(Location, Register);
113 return Register;
114 }
115
117 {
119 return FLabel(LabelIndex);
120 }
121
122 void BindLabel(FLabel Label)
123 {
124 LabelOffsets[Label.Index] = OpBytes.Num();
125 }
126
128 {
129 FLabel Label = AllocateLabel();
130 BindLabel(Label);
131 return Label;
132 }
133
134 uint32 GetOffsetForLabel(FLabel Label) const
135 {
136 return LabelOffsets[Label.Index];
137 }
138
140 {
141 int32 Offset = OpBytes.Num();
142
144 if (Outer.bHandlesUnwind)
145 {
146 UnwindEdges.Add(FUnwindEdge{Outer.Begin, Offset, CoerceOperand(Outer.OnUnwind)});
147 }
148
149 FUnwindRegion& Inner = UnwindStack.Emplace_GetRef(OnUnwind);
150 Inner.Begin = Offset;
151 Inner.bHandlesUnwind = false;
152 }
153
154 void NoteUnwind()
155 {
156 // The outer sentinel region never handles an unwind.
157 if (UnwindStack.Num() > 1)
158 {
159 UnwindStack.Top().bHandlesUnwind = true;
160 }
161 }
162
163 void LeaveUnwindRegion()
164 {
165 int32 Offset = OpBytes.Num();
166
168 if (Inner.bHandlesUnwind)
169 {
170 UnwindEdges.Add(FUnwindEdge{Inner.Begin, Offset, CoerceOperand(Inner.OnUnwind)});
171 }
172
174 Outer.Begin = Offset;
175 Outer.bHandlesUnwind = false;
176 }
177
178 COREUOBJECT_API VProcedure& MakeProcedure(FAllocationContext Context);
179
180#define VISIT_OP(Name) \
181 template <typename... ArgumentTypes> \
182 int32 Name(ArgumentTypes&&... Arguments) \
183 { \
184 return EmitOp<FOp##Name>(Forward<ArgumentTypes>(Arguments)...); \
185 }
187#undef VISIT_OP
188
189 int32 Fail(const FLocation& Location)
190 {
191 return Query(Location, AllocateRegister(Location), AllocateConstant(VValue(GlobalFalse())));
192 }
193
194 template <typename Opcode, typename... ArgumentTypes>
195 int32 EmitOp(const FLocation& Location, ArgumentTypes&&... Arguments)
196 {
197 const int32 Offset = OpBytes.AddUninitialized(sizeof(Opcode));
198 if (OpLocations.IsEmpty() || OpLocations.Top().Location != Location)
199 {
200 OpLocations.Emplace(Offset, Location);
201 }
202 Opcode* NewOp = new (std::launder(OpBytes.GetData() + Offset)) Opcode(CoerceOperand(Forward<ArgumentTypes>(Arguments))...);
203 checkSlow((BitCast<uint64>(NewOp) % alignof(Opcode)) == 0);
204 if constexpr (std::is_same_v<Opcode, FOpReset>)
205 {
206 ResetOffsets.Add(Offset);
207 }
209 return Offset;
210 }
211
213 inline uint32 GetNumNamedParameters() const { return NumNamedParameters; }
214
215 TArray<FNamedParam> NamedParameters;
216
218
220
221private:
224 uint32 NumRegisters;
226 uint32 NumNamedParameters;
227 TArray<VValue> Constants;
233 bool bEnableRegisterAllocation{true};
234
235 // An open region of the program with an associated unwind label. Nested regions wrap this label with their own.
236 // As code generation proceeds, this stack is flattened into a series of non-overlapping "unwind edges."
237 struct FUnwindRegion
238 {
240 int32 Begin;
241 bool bHandlesUnwind;
242 };
244
247
249
250 // Elements are not guaranteed to be unique and should not be relied on outside of debugging purposes.
252
254
255 template <typename ArgumentType>
256 decltype(auto) CoerceOperand(ArgumentType&& Operand)
257 {
258 return Forward<ArgumentType>(Operand);
259 }
260
261 template <typename CellType, typename AllocatorType>
263 {
264 int32 Index = Constants.Num();
265 for (TWriteBarrier<CellType>& Operand : InOperands)
266 {
267 if constexpr (TWriteBarrier<CellType>::bIsVValue)
268 {
269 Constants.Add(Operand.Get());
270 }
271 else
272 {
273 Constants.Add(*Operand);
274 }
275 }
277 }
278
279 template <typename AllocatorType>
281 {
282 int32 Index = Operands.Num();
283 Operands.Append(InOperands);
285 }
286
288 {
289 // Store the label index as an offset until it can be replaced with the actual label offset.
290 check(Label.Index < INT32_MAX);
291 return FLabelOffset{static_cast<int32>(Label.Index)};
292 }
293
294 template <typename AllocatorType>
296 {
297 for (FLabel Label : InLabels)
298 {
299 check(Label.Index < INT32_MAX);
300 }
301 int32 Index = Labels.Num();
302 Labels.Append(InLabels);
304 }
305
306 // Don't allow emitting label offsets directly.
309
310 template <typename OpType>
311 void RegisterJumpRelocation(OpType& Op)
312 {
313 Op.ForEachJump([&](auto& Label, const TCHAR* Name) {
315 });
316 }
317
319 {
320 // Store the offset of this jump for fixup once we know the location of all labels.
321 const size_t LabelOffsetOffset = BitCast<uint8*>(&LabelOffset) - OpBytes.GetData();
324 }
325
327 {
328 // Variadic label operands live in one flat array; no need to remember their location here.
329 }
330};
331} // namespace Verse
332
333#endif
#define checkSlow(expr)
Definition AssertionMacros.h:332
#define check(expr)
Definition AssertionMacros.h:314
return Self
Definition CocoaThread.cpp:337
FPlatformTypes::TCHAR TCHAR
Either ANSICHAR or WIDECHAR, depending on whether the platform supports wide characters or the requir...
Definition Platform.h:1135
FPlatformTypes::int32 int32
A 32-bit signed integer.
Definition Platform.h:1125
UE_FORCEINLINE_HINT TSharedRef< CastToType, Mode > StaticCastSharedRef(TSharedRef< CastFromType, Mode > const &InSharedRef)
Definition SharedPointer.h:127
uint32 Offset
Definition VulkanMemory.cpp:4033
uint32_t uint32
Definition binka_ue_file_header.h:6
Definition ArrayView.h:139
Definition Array.h:670
UE_REWRITE SizeType Num() const
Definition Array.h:1144
UE_NODEBUG UE_FORCEINLINE_HINT SizeType Add(ElementType &&Item)
Definition Array.h:2696
FText Labels[NumberOfLabels]
Definition STimecode.cpp:19
UE_STRING_CLASS Result(Forward< LhsType >(Lhs), RhsLen)
Definition String.cpp.inl:732
Definition Archive.h:36
U16 Index
Definition radfft.cpp:71