1//===--- ExecutorBase.h - Non-visitor methods of InstExecutor -------------===//
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// This file declares non-visitor methods of InstExecutor for code reuse.
10//
11//===----------------------------------------------------------------------===//
12
13#ifndef LLVM_TOOLS_LLUBI_EXECUTORBASE_H
14#define LLVM_TOOLS_LLUBI_EXECUTORBASE_H
15
16#include "Context.h"
17#include "Value.h"
18#include "llvm/Support/raw_ostream.h"
19#include <optional>
20#include <string>
21#include <utility>
22
23namespace llvm::ubi {
24
25enum class FrameState {
26 // It is about to enter the function.
27 // Valid transition:
28 // -> Running
29 Entry,
30 // It is executing instructions inside the function.
31 // Valid transitions:
32 // -> Pending (on call)
33 // -> Exit (on return)
34 Running,
35 // It is about to enter a callee or handle return value from the callee.
36 // Valid transitions:
37 // -> Running (after returning from callee)
38 Pending,
39 // It is about to return the control to the caller.
40 Exit,
41};
42
43/// Context for a function call.
44/// This struct maintains the state during the execution of a function,
45/// including the control flow, values of executed instructions, and stack
46/// objects.
47struct Frame {
48 Function &Func;
49 Frame *LastFrame;
50 CallBase *CallSite;
51 ArrayRef<AnyValue> Args;
52 AnyValue &RetVal;
53
54 TargetLibraryInfo TLI;
55 BasicBlock *BB;
56 BasicBlock::iterator PC;
57 FrameState State = FrameState::Entry;
58 // Stack objects allocated in this frame. They will be automatically freed
59 // when the function returns.
60 SmallVector<IntrusiveRefCntPtr<MemoryObject>> Allocas;
61 // Values of arguments and executed instructions in this function.
62 DenseMap<Value *, AnyValue> ValueMap;
63
64 // Reserved for in-flight subroutines.
65 Function *ResolvedCallee = nullptr;
66 SmallVector<AnyValue> CalleeArgs;
67 // Temporary memory objects created via pointer arguments with byval.
68 // They belong to the caller.
69 SmallVector<IntrusiveRefCntPtr<MemoryObject>> CalleeByValArgs;
70 AnyValue CalleeRetVal;
71
72 Frame(Function &F, CallBase *CallSite, Frame *LastFrame,
73 ArrayRef<AnyValue> Args, AnyValue &RetVal,
74 const TargetLibraryInfoImpl &TLIImpl);
75};
76
77enum class DiagnosticKind {
78 ImmediateUB,
79 Error,
80};
81
82class DiagnosticReporter;
83
84class ExecutorBase {
85 friend class DiagnosticReporter;
86
87protected:
88 Context &Ctx;
89 EventHandler &Handler;
90 Frame *CurrentFrame = nullptr;
91 std::optional<ProgramExitInfo> ExitInfo;
92
93 ExecutorBase(Context &C, EventHandler &H)
94 : Ctx(C), Handler(H), ExitInfo(std::nullopt) {}
95 ~ExecutorBase() = default;
96
97private:
98 void reportImmediateUBString(StringRef Msg);
99 void reportErrorString(StringRef Msg);
100
101public:
102 DiagnosticReporter reportImmediateUB();
103 DiagnosticReporter reportError();
104
105 /// Check if the upcoming memory access is valid. Returns the resolved memory
106 /// object and offset if it is valid.
107 std::pair<MemoryObject *, uint64_t> verifyMemAccess(const Pointer &Ptr,
108 uint64_t AccessSize,
109 Align Alignment,
110 bool IsStore);
111
112 AnyValue load(const AnyValue &Ptr, Align Alignment, Type *ValTy,
113 bool NoUndef);
114 void store(const AnyValue &Ptr, Align Alignment, const AnyValue &Val,
115 Type *ValTy);
116
117 void requestProgramExit(ProgramExitInfo::ProgramExitKind Kind,
118 uint64_t ExitCode = 0);
119 void setFailed();
120
121 bool hasProgramExited() const;
122 std::optional<ProgramExitInfo> getExitInfo() const;
123
124 unsigned getIntSize() const;
125
126 void dumpStackTrace() const;
127};
128
129class DiagnosticReporter {
130 ExecutorBase &Executor;
131 std::string Buf;
132 raw_string_ostream OS;
133 DiagnosticKind Kind;
134
135public:
136 DiagnosticReporter(ExecutorBase &E, DiagnosticKind K)
137 : Executor(E), OS(Buf), Kind(K) {}
138
139 DiagnosticReporter(const DiagnosticReporter &) = delete;
140 DiagnosticReporter(DiagnosticReporter &&) noexcept = delete;
141
142 DiagnosticReporter &operator=(const DiagnosticReporter &) = delete;
143 DiagnosticReporter &operator=(DiagnosticReporter &&) noexcept = delete;
144
145 ~DiagnosticReporter() {
146 switch (Kind) {
147 case DiagnosticKind::ImmediateUB:
148 Executor.reportImmediateUBString(Msg: Buf);
149 break;
150 case DiagnosticKind::Error:
151 Executor.reportErrorString(Msg: Buf);
152 break;
153 }
154 }
155
156 template <typename T> DiagnosticReporter &operator<<(const T &Val) {
157 OS << Val;
158 return *this;
159 }
160};
161
162} // namespace llvm::ubi
163
164#endif // LLVM_TOOLS_LLUBI_EXECUTORBASE_H
165