Path: blob/main/contrib/llvm-project/llvm/lib/TableGen/StringToOffsetTable.cpp
213764 views
//===- StringToOffsetTable.cpp - Emit a big concatenated string -*- C++ -*-===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//78#include "llvm/TableGen/StringToOffsetTable.h"9#include "llvm/Support/FormatVariadic.h"10#include "llvm/Support/raw_ostream.h"11#include "llvm/TableGen/Error.h"12#include "llvm/TableGen/Main.h"1314using namespace llvm;1516unsigned StringToOffsetTable::GetOrAddStringOffset(StringRef Str) {17auto [II, Inserted] = StringOffset.insert({Str, size()});18if (Inserted) {19// Add the string to the aggregate if this is the first time found.20AggregateString.append(Str.begin(), Str.end());21if (AppendZero)22AggregateString += '\0';23}2425return II->second;26}2728void StringToOffsetTable::EmitStringTableDef(raw_ostream &OS,29const Twine &Name) const {30// This generates a `llvm::StringTable` which expects that entries are null31// terminated. So fail with an error if `AppendZero` is false.32if (!AppendZero)33PrintFatalError("llvm::StringTable requires null terminated strings");3435OS << formatv(R"(36#ifdef __GNUC__37#pragma GCC diagnostic push38#pragma GCC diagnostic ignored "-Woverlength-strings"39#endif40static constexpr char {}Storage[] = )",41Name);4243// MSVC silently miscompiles string literals longer than 64k in some44// circumstances. The build system sets EmitLongStrLiterals to false when it45// detects that it is targetting MSVC. When that option is false and the46// string table is longer than 64k, emit it as an array of character47// literals.48bool UseChars = !EmitLongStrLiterals && AggregateString.size() > (64 * 1024);49OS << (UseChars ? "{\n" : "\n");5051ListSeparator LineSep(UseChars ? ",\n" : "\n");52SmallVector<StringRef> Strings(split(AggregateString, '\0'));53// We should always have an empty string at the start, and because these are54// null terminators rather than separators, we'll have one at the end as55// well. Skip the end one.56assert(Strings.front().empty() && "Expected empty initial string!");57assert(Strings.back().empty() &&58"Expected empty string at the end due to terminators!");59Strings.pop_back();60for (StringRef Str : Strings) {61OS << LineSep << " ";62// If we can, just emit this as a string literal to be concatenated.63if (!UseChars) {64OS << "\"";65OS.write_escaped(Str);66OS << "\\0\"";67continue;68}6970ListSeparator CharSep(", ");71for (char C : Str) {72OS << CharSep << "'";73OS.write_escaped(StringRef(&C, 1));74OS << "'";75}76OS << CharSep << "'\\0'";77}78OS << LineSep << (UseChars ? "};" : " ;");7980OS << formatv(R"(81#ifdef __GNUC__82#pragma GCC diagnostic pop83#endif8485static constexpr llvm::StringTable86{0} = {0}Storage;87)",88Name);89}9091void StringToOffsetTable::EmitString(raw_ostream &O) const {92// Escape the string.93SmallString<256> EscapedStr;94raw_svector_ostream(EscapedStr).write_escaped(AggregateString);9596O << " \"";97unsigned CharsPrinted = 0;98for (unsigned i = 0, e = EscapedStr.size(); i != e; ++i) {99if (CharsPrinted > 70) {100O << "\"\n \"";101CharsPrinted = 0;102}103O << EscapedStr[i];104++CharsPrinted;105106// Print escape sequences all together.107if (EscapedStr[i] != '\\')108continue;109110assert(i + 1 < EscapedStr.size() && "Incomplete escape sequence!");111if (isDigit(EscapedStr[i + 1])) {112assert(isDigit(EscapedStr[i + 2]) && isDigit(EscapedStr[i + 3]) &&113"Expected 3 digit octal escape!");114O << EscapedStr[++i];115O << EscapedStr[++i];116O << EscapedStr[++i];117CharsPrinted += 3;118} else {119O << EscapedStr[++i];120++CharsPrinted;121}122}123O << "\"";124}125126127