[libc] Switch to using the generic `<gpuintrin.h>` implementations (#121810)
[llvm-project.git] / lldb / source / DataFormatters / FormatterBytecode.cpp
blob7f3dbe0dba37d66b966915edbaf93f4037ce1aa0
1 //===-- FormatterBytecode.cpp ---------------------------------------------===//
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 //===----------------------------------------------------------------------===//
9 #include "FormatterBytecode.h"
10 #include "lldb/Utility/LLDBLog.h"
11 #include "lldb/ValueObject/ValueObject.h"
12 #include "llvm/ADT/StringExtras.h"
13 #include "llvm/Support/DataExtractor.h"
14 #include "llvm/Support/Format.h"
15 #include "llvm/Support/FormatProviders.h"
16 #include "llvm/Support/FormatVariadicDetails.h"
18 using namespace lldb;
19 namespace lldb_private {
21 std::string toString(FormatterBytecode::OpCodes op) {
22 switch (op) {
23 #define DEFINE_OPCODE(OP, MNEMONIC, NAME) \
24 case OP: { \
25 const char *s = MNEMONIC; \
26 return s ? s : #NAME; \
28 #include "FormatterBytecode.def"
29 #undef DEFINE_SIGNATURE
31 return llvm::utostr(op);
34 std::string toString(FormatterBytecode::Selectors sel) {
35 switch (sel) {
36 #define DEFINE_SELECTOR(ID, NAME) \
37 case ID: \
38 return "@" #NAME;
39 #include "FormatterBytecode.def"
40 #undef DEFINE_SIGNATURE
42 return "@" + llvm::utostr(sel);
45 std::string toString(FormatterBytecode::Signatures sig) {
46 switch (sig) {
47 #define DEFINE_SIGNATURE(ID, NAME) \
48 case ID: \
49 return "@" #NAME;
50 #include "FormatterBytecode.def"
51 #undef DEFINE_SIGNATURE
53 return llvm::utostr(sig);
56 std::string toString(const FormatterBytecode::DataStack &data) {
57 std::string s;
58 llvm::raw_string_ostream os(s);
59 os << "[ ";
60 for (auto &d : data) {
61 if (auto s = std::get_if<std::string>(&d))
62 os << '"' << *s << '"';
63 else if (auto u = std::get_if<uint64_t>(&d))
64 os << *u << 'u';
65 else if (auto i = std::get_if<int64_t>(&d))
66 os << *i;
67 else if (auto valobj = std::get_if<ValueObjectSP>(&d)) {
68 if (!valobj->get())
69 os << "null";
70 else
71 os << "object(" << valobj->get()->GetValueAsCString() << ')';
72 } else if (auto type = std::get_if<CompilerType>(&d)) {
73 os << '(' << type->GetTypeName(true) << ')';
74 } else if (auto sel = std::get_if<FormatterBytecode::Selectors>(&d)) {
75 os << toString(*sel);
77 os << ' ';
79 os << ']';
80 return s;
83 namespace FormatterBytecode {
85 /// Implement the @format function.
86 static llvm::Error FormatImpl(DataStack &data) {
87 auto fmt = data.Pop<std::string>();
88 auto replacements =
89 llvm::formatv_object_base::parseFormatString(fmt, 0, false);
90 std::string s;
91 llvm::raw_string_ostream os(s);
92 unsigned num_args = 0;
93 for (const auto &r : replacements)
94 if (r.Type == llvm::ReplacementType::Format)
95 num_args = std::max(num_args, r.Index + 1);
97 if (data.size() < num_args)
98 return llvm::createStringError("not enough arguments");
100 for (const auto &r : replacements) {
101 if (r.Type == llvm::ReplacementType::Literal) {
102 os << r.Spec;
103 continue;
105 using namespace llvm::support::detail;
106 auto arg = data[data.size() - num_args + r.Index];
107 auto format = [&](format_adapter &&adapter) {
108 llvm::FmtAlign Align(adapter, r.Where, r.Width, r.Pad);
109 Align.format(os, r.Options);
112 if (auto s = std::get_if<std::string>(&arg))
113 format(build_format_adapter(s->c_str()));
114 else if (auto u = std::get_if<uint64_t>(&arg))
115 format(build_format_adapter(u));
116 else if (auto i = std::get_if<int64_t>(&arg))
117 format(build_format_adapter(i));
118 else if (auto valobj = std::get_if<ValueObjectSP>(&arg)) {
119 if (!valobj->get())
120 format(build_format_adapter("null object"));
121 else
122 format(build_format_adapter(valobj->get()->GetValueAsCString()));
123 } else if (auto type = std::get_if<CompilerType>(&arg))
124 format(build_format_adapter(type->GetDisplayTypeName()));
125 else if (auto sel = std::get_if<FormatterBytecode::Selectors>(&arg))
126 format(build_format_adapter(toString(*sel)));
128 data.Push(s);
129 return llvm::Error::success();
132 static llvm::Error TypeCheck(llvm::ArrayRef<DataStackElement> data,
133 DataType type) {
134 if (data.size() < 1)
135 return llvm::createStringError("not enough elements on data stack");
137 auto &elem = data.back();
138 switch (type) {
139 case Any:
140 break;
141 case String:
142 if (!std::holds_alternative<std::string>(elem))
143 return llvm::createStringError("expected String");
144 break;
145 case UInt:
146 if (!std::holds_alternative<uint64_t>(elem))
147 return llvm::createStringError("expected UInt");
148 break;
149 case Int:
150 if (!std::holds_alternative<int64_t>(elem))
151 return llvm::createStringError("expected Int");
152 break;
153 case Object:
154 if (!std::holds_alternative<ValueObjectSP>(elem))
155 return llvm::createStringError("expected Object");
156 break;
157 case Type:
158 if (!std::holds_alternative<CompilerType>(elem))
159 return llvm::createStringError("expected Type");
160 break;
161 case Selector:
162 if (!std::holds_alternative<Selectors>(elem))
163 return llvm::createStringError("expected Selector");
164 break;
166 return llvm::Error::success();
169 static llvm::Error TypeCheck(llvm::ArrayRef<DataStackElement> data,
170 DataType type1, DataType type2) {
171 if (auto error = TypeCheck(data, type2))
172 return error;
173 return TypeCheck(data.drop_back(), type1);
176 static llvm::Error TypeCheck(llvm::ArrayRef<DataStackElement> data,
177 DataType type1, DataType type2, DataType type3) {
178 if (auto error = TypeCheck(data, type3))
179 return error;
180 return TypeCheck(data.drop_back(1), type2, type1);
183 llvm::Error Interpret(std::vector<ControlStackElement> &control,
184 DataStack &data, Selectors sel) {
185 if (control.empty())
186 return llvm::Error::success();
187 // Since the only data types are single endian and ULEBs, the
188 // endianness should not matter.
189 llvm::DataExtractor cur_block(control.back(), true, 64);
190 llvm::DataExtractor::Cursor pc(0);
192 while (!control.empty()) {
193 /// Activate the top most block from the control stack.
194 auto activate_block = [&]() {
195 // Save the return address.
196 if (control.size() > 1)
197 control[control.size() - 2] = cur_block.getData().drop_front(pc.tell());
198 cur_block = llvm::DataExtractor(control.back(), true, 64);
199 if (pc)
200 pc = llvm::DataExtractor::Cursor(0);
203 /// Fetch the next byte in the instruction stream.
204 auto next_byte = [&]() -> uint8_t {
205 // At the end of the current block?
206 while (pc.tell() >= cur_block.size() && !control.empty()) {
207 if (control.size() == 1) {
208 control.pop_back();
209 return 0;
211 control.pop_back();
212 activate_block();
215 // Fetch the next instruction.
216 return cur_block.getU8(pc);
219 // Fetch the next opcode.
220 OpCodes opcode = (OpCodes)next_byte();
221 if (control.empty() || !pc)
222 return pc.takeError();
224 LLDB_LOGV(GetLog(LLDBLog::DataFormatters),
225 "[eval {0}] opcode={1}, control={2}, data={3}", toString(sel),
226 toString(opcode), control.size(), toString(data));
228 // Various shorthands to improve the readability of error handling.
229 #define TYPE_CHECK(...) \
230 if (auto error = TypeCheck(data, __VA_ARGS__)) \
231 return error;
233 auto error = [&](llvm::Twine msg) {
234 return llvm::createStringError(msg + "(opcode=" + toString(opcode) + ")");
237 switch (opcode) {
238 // Data stack manipulation.
239 case op_dup:
240 TYPE_CHECK(Any);
241 data.Push(data.back());
242 continue;
243 case op_drop:
244 TYPE_CHECK(Any);
245 data.pop_back();
246 continue;
247 case op_pick: {
248 TYPE_CHECK(UInt);
249 uint64_t idx = data.Pop<uint64_t>();
250 if (idx >= data.size())
251 return error("index out of bounds");
252 data.Push(data[idx]);
253 continue;
255 case op_over:
256 TYPE_CHECK(Any, Any);
257 data.Push(data[data.size() - 2]);
258 continue;
259 case op_swap: {
260 TYPE_CHECK(Any, Any);
261 auto x = data.PopAny();
262 auto y = data.PopAny();
263 data.Push(x);
264 data.Push(y);
265 continue;
267 case op_rot: {
268 TYPE_CHECK(Any, Any, Any);
269 auto z = data.PopAny();
270 auto y = data.PopAny();
271 auto x = data.PopAny();
272 data.Push(z);
273 data.Push(x);
274 data.Push(y);
275 continue;
278 // Control stack manipulation.
279 case op_begin: {
280 uint64_t length = cur_block.getULEB128(pc);
281 if (!pc)
282 return pc.takeError();
283 llvm::StringRef block = cur_block.getBytes(pc, length);
284 if (!pc)
285 return pc.takeError();
286 control.push_back(block);
287 continue;
289 case op_if:
290 TYPE_CHECK(UInt);
291 if (data.Pop<uint64_t>() != 0) {
292 if (!cur_block.size())
293 return error("empty control stack");
294 activate_block();
295 } else
296 control.pop_back();
297 continue;
298 case op_ifelse:
299 TYPE_CHECK(UInt);
300 if (cur_block.size() < 2)
301 return error("empty control stack");
302 if (data.Pop<uint64_t>() == 0)
303 control[control.size() - 2] = control.back();
304 control.pop_back();
305 activate_block();
306 continue;
307 case op_return:
308 control.clear();
309 return pc.takeError();
311 // Literals.
312 case op_lit_uint:
313 data.Push(cur_block.getULEB128(pc));
314 continue;
315 case op_lit_int:
316 data.Push(cur_block.getSLEB128(pc));
317 continue;
318 case op_lit_selector:
319 data.Push(Selectors(cur_block.getU8(pc)));
320 continue;
321 case op_lit_string: {
322 uint64_t length = cur_block.getULEB128(pc);
323 llvm::StringRef bytes = cur_block.getBytes(pc, length);
324 data.Push(bytes.str());
325 continue;
327 case op_as_uint: {
328 TYPE_CHECK(Int);
329 uint64_t casted;
330 int64_t val = data.Pop<int64_t>();
331 memcpy(&casted, &val, sizeof(val));
332 data.Push(casted);
333 continue;
335 case op_as_int: {
336 TYPE_CHECK(UInt);
337 int64_t casted;
338 uint64_t val = data.Pop<uint64_t>();
339 memcpy(&casted, &val, sizeof(val));
340 data.Push(casted);
341 continue;
343 case op_is_null: {
344 TYPE_CHECK(Object);
345 data.Push(data.Pop<ValueObjectSP>() ? (uint64_t)0 : (uint64_t)1);
346 continue;
349 // Arithmetic, logic, etc.
350 #define BINOP_IMPL(OP, CHECK_ZERO) \
352 TYPE_CHECK(Any, Any); \
353 auto y = data.PopAny(); \
354 if (std::holds_alternative<uint64_t>(y)) { \
355 if (CHECK_ZERO && !std::get<uint64_t>(y)) \
356 return error(#OP " by zero"); \
357 TYPE_CHECK(UInt); \
358 data.Push((uint64_t)(data.Pop<uint64_t>() OP std::get<uint64_t>(y))); \
359 } else if (std::holds_alternative<int64_t>(y)) { \
360 if (CHECK_ZERO && !std::get<int64_t>(y)) \
361 return error(#OP " by zero"); \
362 TYPE_CHECK(Int); \
363 data.Push((int64_t)(data.Pop<int64_t>() OP std::get<int64_t>(y))); \
364 } else \
365 return error("unsupported data types"); \
367 #define BINOP(OP) BINOP_IMPL(OP, false)
368 #define BINOP_CHECKZERO(OP) BINOP_IMPL(OP, true)
369 case op_plus:
370 BINOP(+);
371 continue;
372 case op_minus:
373 BINOP(-);
374 continue;
375 case op_mul:
376 BINOP(*);
377 continue;
378 case op_div:
379 BINOP_CHECKZERO(/);
380 continue;
381 case op_mod:
382 BINOP_CHECKZERO(%);
383 continue;
384 case op_shl:
385 #define SHIFTOP(OP, LEFT) \
387 TYPE_CHECK(Any, UInt); \
388 uint64_t y = data.Pop<uint64_t>(); \
389 if (y > 64) \
390 return error("shift out of bounds"); \
391 if (std::holds_alternative<uint64_t>(data.back())) { \
392 uint64_t x = data.Pop<uint64_t>(); \
393 data.Push(x OP y); \
394 } else if (std::holds_alternative<int64_t>(data.back())) { \
395 int64_t x = data.Pop<int64_t>(); \
396 if (x < 0 && LEFT) \
397 return error("left shift of negative value"); \
398 if (y > 64) \
399 return error("shift out of bounds"); \
400 data.Push(x OP y); \
401 } else \
402 return error("unsupported data types"); \
404 SHIFTOP(<<, true);
405 continue;
406 case op_shr:
407 SHIFTOP(>>, false);
408 continue;
409 case op_and:
410 BINOP(&);
411 continue;
412 case op_or:
413 BINOP(|);
414 continue;
415 case op_xor:
416 BINOP(^);
417 continue;
418 case op_not:
419 TYPE_CHECK(UInt);
420 data.Push(~data.Pop<uint64_t>());
421 continue;
422 case op_eq:
423 BINOP(==);
424 continue;
425 case op_neq:
426 BINOP(!=);
427 continue;
428 case op_lt:
429 BINOP(<);
430 continue;
431 case op_gt:
432 BINOP(>);
433 continue;
434 case op_le:
435 BINOP(<=);
436 continue;
437 case op_ge:
438 BINOP(>=);
439 continue;
440 case op_call: {
441 TYPE_CHECK(Selector);
442 Selectors sel = data.Pop<Selectors>();
444 // Shorthand to improve readability.
445 #define POP_VALOBJ(VALOBJ) \
446 auto VALOBJ = data.Pop<ValueObjectSP>(); \
447 if (!VALOBJ) \
448 return error("null object");
450 auto sel_error = [&](const char *msg) {
451 return llvm::createStringError("{0} (opcode={1}, selector={2})", msg,
452 toString(opcode).c_str(),
453 toString(sel).c_str());
456 switch (sel) {
457 case sel_summary: {
458 TYPE_CHECK(Object);
459 POP_VALOBJ(valobj);
460 const char *summary = valobj->GetSummaryAsCString();
461 data.Push(summary ? std::string(valobj->GetSummaryAsCString())
462 : std::string());
463 break;
465 case sel_get_num_children: {
466 TYPE_CHECK(Object);
467 POP_VALOBJ(valobj);
468 auto result = valobj->GetNumChildren();
469 if (!result)
470 return result.takeError();
471 data.Push((uint64_t)*result);
472 break;
474 case sel_get_child_at_index: {
475 TYPE_CHECK(Object, UInt);
476 auto index = data.Pop<uint64_t>();
477 POP_VALOBJ(valobj);
478 data.Push(valobj->GetChildAtIndex(index));
479 break;
481 case sel_get_child_with_name: {
482 TYPE_CHECK(Object, String);
483 auto name = data.Pop<std::string>();
484 POP_VALOBJ(valobj);
485 data.Push(valobj->GetChildMemberWithName(name));
486 break;
488 case sel_get_child_index: {
489 TYPE_CHECK(Object, String);
490 auto name = data.Pop<std::string>();
491 POP_VALOBJ(valobj);
492 data.Push((uint64_t)valobj->GetIndexOfChildWithName(name));
493 break;
495 case sel_get_type: {
496 TYPE_CHECK(Object);
497 POP_VALOBJ(valobj);
498 // FIXME: do we need to control dynamic type resolution?
499 data.Push(valobj->GetTypeImpl().GetCompilerType(false));
500 break;
502 case sel_get_template_argument_type: {
503 TYPE_CHECK(Type, UInt);
504 auto index = data.Pop<uint64_t>();
505 auto type = data.Pop<CompilerType>();
506 // FIXME: There is more code in SBType::GetTemplateArgumentType().
507 data.Push(type.GetTypeTemplateArgument(index, true));
508 break;
510 case sel_get_value: {
511 TYPE_CHECK(Object);
512 POP_VALOBJ(valobj);
513 data.Push(std::string(valobj->GetValueAsCString()));
514 break;
516 case sel_get_value_as_unsigned: {
517 TYPE_CHECK(Object);
518 POP_VALOBJ(valobj);
519 bool success;
520 uint64_t val = valobj->GetValueAsUnsigned(0, &success);
521 data.Push(val);
522 if (!success)
523 return sel_error("failed to get value");
524 break;
526 case sel_get_value_as_signed: {
527 TYPE_CHECK(Object);
528 POP_VALOBJ(valobj);
529 bool success;
530 int64_t val = valobj->GetValueAsSigned(0, &success);
531 data.Push(val);
532 if (!success)
533 return sel_error("failed to get value");
534 break;
536 case sel_get_value_as_address: {
537 TYPE_CHECK(Object);
538 POP_VALOBJ(valobj);
539 bool success;
540 uint64_t addr = valobj->GetValueAsUnsigned(0, &success);
541 if (!success)
542 return sel_error("failed to get value");
543 if (auto process_sp = valobj->GetProcessSP())
544 addr = process_sp->FixDataAddress(addr);
545 data.Push(addr);
546 break;
548 case sel_cast: {
549 TYPE_CHECK(Object, Type);
550 auto type = data.Pop<CompilerType>();
551 POP_VALOBJ(valobj);
552 data.Push(valobj->Cast(type));
553 break;
555 case sel_strlen: {
556 TYPE_CHECK(String);
557 data.Push((uint64_t)data.Pop<std::string>().size());
558 break;
560 case sel_fmt: {
561 TYPE_CHECK(String);
562 if (auto error = FormatImpl(data))
563 return error;
564 break;
566 default:
567 return sel_error("selector not implemented");
569 continue;
572 return error("opcode not implemented");
574 return pc.takeError();
576 } // namespace FormatterBytecode
578 } // namespace lldb_private