brintos

brintos / llvm-project-archived public Read only

0
0
Text · 21.3 KiB · 24251e1 Raw
525 lines · cpp
1//===- AMDKernelCodeTUtils.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-exception6//7//===----------------------------------------------------------------------===//8//9/// \file - utility functions to parse/print AMDGPUMCKernelCodeT structure10//11//===----------------------------------------------------------------------===//12 13#include "AMDKernelCodeTUtils.h"14#include "AMDKernelCodeT.h"15#include "SIDefines.h"16#include "Utils/AMDGPUBaseInfo.h"17#include "Utils/SIDefinesUtils.h"18#include "llvm/ADT/StringRef.h"19#include "llvm/MC/MCContext.h"20#include "llvm/MC/MCExpr.h"21#include "llvm/MC/MCParser/AsmLexer.h"22#include "llvm/MC/MCParser/MCAsmParser.h"23#include "llvm/MC/MCStreamer.h"24#include "llvm/Support/MathExtras.h"25#include "llvm/Support/raw_ostream.h"26 27using namespace llvm;28using namespace llvm::AMDGPU;29 30// Generates the following for AMDGPUMCKernelCodeT struct members:31//   - HasMemberXXXXX class32//     A check to see if AMDGPUMCKernelCodeT has a specific member so it can33//     determine which of the original amd_kernel_code_t members are duplicated34//     (if the names don't match, the table driven strategy won't work).35//   - IsMCExprXXXXX class36//     Check whether a AMDGPUMCKernelcodeT struct member is MCExpr-ified or not.37//   - GetMemberXXXXX class38//     A retrieval helper for said member (of type const MCExpr *&). Will return39//     a `Phony` const MCExpr * initialized to nullptr to preserve reference40//     returns.41#define GEN_HAS_MEMBER(member)                                                 \42  class HasMember##member {                                                    \43    template <typename U>                                                      \44    using check_member = decltype(std::declval<U>().member);                   \45                                                                               \46  public:                                                                      \47    static constexpr bool RESULT =                                             \48        llvm::is_detected<check_member, AMDGPUMCKernelCodeT>::value;           \49  };                                                                           \50  class IsMCExpr##member {                                                     \51    template <typename U>                                                      \52    static constexpr auto HasMCExprType(int) -> std::bool_constant<            \53        HasMember##member::RESULT &&                                           \54        std::is_same_v<decltype(U::member), const MCExpr *>>;                  \55    template <typename U> static constexpr std::false_type HasMCExprType(...); \56                                                                               \57  public:                                                                      \58    static constexpr bool RESULT =                                             \59        decltype(HasMCExprType<AMDGPUMCKernelCodeT>(0))::value;                \60  };                                                                           \61  class GetMember##member {                                                    \62  public:                                                                      \63    static const MCExpr *Phony;                                                \64    template <typename U> static const MCExpr *&Get(U &C) {                    \65      if constexpr (IsMCExpr##member::RESULT)                                  \66        return C.member;                                                       \67      else                                                                     \68        return Phony;                                                          \69    }                                                                          \70  };                                                                           \71  const MCExpr *GetMember##member::Phony = nullptr;72 73// Cannot generate class declarations using the table driver approach (see table74// in AMDKernelCodeTInfo.h). Luckily, if any are missing here or eventually75// added to the table, an error should occur when trying to retrieve the table76// in getMCExprIndexTable.77GEN_HAS_MEMBER(amd_code_version_major)78GEN_HAS_MEMBER(amd_code_version_minor)79GEN_HAS_MEMBER(amd_machine_kind)80GEN_HAS_MEMBER(amd_machine_version_major)81GEN_HAS_MEMBER(amd_machine_version_minor)82GEN_HAS_MEMBER(amd_machine_version_stepping)83 84GEN_HAS_MEMBER(kernel_code_entry_byte_offset)85GEN_HAS_MEMBER(kernel_code_prefetch_byte_size)86 87GEN_HAS_MEMBER(granulated_workitem_vgpr_count)88GEN_HAS_MEMBER(granulated_wavefront_sgpr_count)89GEN_HAS_MEMBER(priority)90GEN_HAS_MEMBER(float_mode)91GEN_HAS_MEMBER(priv)92GEN_HAS_MEMBER(enable_dx10_clamp)93GEN_HAS_MEMBER(debug_mode)94GEN_HAS_MEMBER(enable_ieee_mode)95GEN_HAS_MEMBER(enable_wgp_mode)96GEN_HAS_MEMBER(enable_mem_ordered)97GEN_HAS_MEMBER(enable_fwd_progress)98 99GEN_HAS_MEMBER(enable_sgpr_private_segment_wave_byte_offset)100GEN_HAS_MEMBER(user_sgpr_count)101GEN_HAS_MEMBER(enable_trap_handler)102GEN_HAS_MEMBER(enable_sgpr_workgroup_id_x)103GEN_HAS_MEMBER(enable_sgpr_workgroup_id_y)104GEN_HAS_MEMBER(enable_sgpr_workgroup_id_z)105GEN_HAS_MEMBER(enable_sgpr_workgroup_info)106GEN_HAS_MEMBER(enable_vgpr_workitem_id)107GEN_HAS_MEMBER(enable_exception_msb)108GEN_HAS_MEMBER(granulated_lds_size)109GEN_HAS_MEMBER(enable_exception)110 111GEN_HAS_MEMBER(enable_sgpr_private_segment_buffer)112GEN_HAS_MEMBER(enable_sgpr_dispatch_ptr)113GEN_HAS_MEMBER(enable_sgpr_queue_ptr)114GEN_HAS_MEMBER(enable_sgpr_kernarg_segment_ptr)115GEN_HAS_MEMBER(enable_sgpr_dispatch_id)116GEN_HAS_MEMBER(enable_sgpr_flat_scratch_init)117GEN_HAS_MEMBER(enable_sgpr_private_segment_size)118GEN_HAS_MEMBER(enable_sgpr_grid_workgroup_count_x)119GEN_HAS_MEMBER(enable_sgpr_grid_workgroup_count_y)120GEN_HAS_MEMBER(enable_sgpr_grid_workgroup_count_z)121GEN_HAS_MEMBER(enable_wavefront_size32)122GEN_HAS_MEMBER(enable_ordered_append_gds)123GEN_HAS_MEMBER(private_element_size)124GEN_HAS_MEMBER(is_ptr64)125GEN_HAS_MEMBER(is_dynamic_callstack)126GEN_HAS_MEMBER(is_debug_enabled)127GEN_HAS_MEMBER(is_xnack_enabled)128 129GEN_HAS_MEMBER(workitem_private_segment_byte_size)130GEN_HAS_MEMBER(workgroup_group_segment_byte_size)131GEN_HAS_MEMBER(gds_segment_byte_size)132GEN_HAS_MEMBER(kernarg_segment_byte_size)133GEN_HAS_MEMBER(workgroup_fbarrier_count)134GEN_HAS_MEMBER(wavefront_sgpr_count)135GEN_HAS_MEMBER(workitem_vgpr_count)136GEN_HAS_MEMBER(reserved_vgpr_first)137GEN_HAS_MEMBER(reserved_vgpr_count)138GEN_HAS_MEMBER(reserved_sgpr_first)139GEN_HAS_MEMBER(reserved_sgpr_count)140GEN_HAS_MEMBER(debug_wavefront_private_segment_offset_sgpr)141GEN_HAS_MEMBER(debug_private_segment_buffer_sgpr)142GEN_HAS_MEMBER(kernarg_segment_alignment)143GEN_HAS_MEMBER(group_segment_alignment)144GEN_HAS_MEMBER(private_segment_alignment)145GEN_HAS_MEMBER(wavefront_size)146GEN_HAS_MEMBER(call_convention)147GEN_HAS_MEMBER(runtime_loader_kernel_symbol)148 149static ArrayRef<StringLiteral> get_amd_kernel_code_t_FldNames() {150  static constexpr StringLiteral const Table[] = {151      "", // not found placeholder152#define RECORD(name, altName, print, parse) #name153#include "Utils/AMDKernelCodeTInfo.h"154#undef RECORD155  };156  return ArrayRef(Table);157}158 159static ArrayRef<StringLiteral> get_amd_kernel_code_t_FldAltNames() {160  static constexpr StringLiteral const Table[] = {161      "", // not found placeholder162#define RECORD(name, altName, print, parse) #altName163#include "Utils/AMDKernelCodeTInfo.h"164#undef RECORD165  };166  return ArrayRef(Table);167}168 169static ArrayRef<bool> hasMCExprVersionTable() {170  static bool const Table[] = {171#define RECORD(name, altName, print, parse) (IsMCExpr##name::RESULT)172#include "Utils/AMDKernelCodeTInfo.h"173#undef RECORD174  };175  return ArrayRef(Table);176}177 178using RetrieveFx = const MCExpr *&(*)(AMDGPUMCKernelCodeT &);179 180static ArrayRef<RetrieveFx> getMCExprIndexTable() {181  static const RetrieveFx Table[] = {182#define RECORD(name, altName, print, parse) GetMember##name::Get183#include "Utils/AMDKernelCodeTInfo.h"184#undef RECORD185  };186  return ArrayRef(Table);187}188 189static StringMap<int> createIndexMap(ArrayRef<StringLiteral> names,190                                     ArrayRef<StringLiteral> altNames) {191  StringMap<int> map;192  assert(names.size() == altNames.size());193  for (unsigned i = 0; i < names.size(); ++i) {194    map.insert(std::pair(names[i], i));195    map.insert(std::pair(altNames[i], i));196  }197  return map;198}199 200static int get_amd_kernel_code_t_FieldIndex(StringRef name) {201  static const auto map = createIndexMap(get_amd_kernel_code_t_FldNames(),202                                         get_amd_kernel_code_t_FldAltNames());203  return map.lookup(name) - 1; // returns -1 if not found204}205 206class PrintField {207public:208  template <typename T, T AMDGPUMCKernelCodeT::*ptr>209  static void printField(StringRef Name, const AMDGPUMCKernelCodeT &C,210                         raw_ostream &OS, MCContext &Ctx,211                         AMDGPUMCKernelCodeT::PrintHelper Helper) {212    if constexpr (!std::is_integral_v<T>) {213      OS << Name << " = ";214      const MCExpr *Value = C.*ptr;215      Helper(Value, OS, Ctx.getAsmInfo());216    } else {217      OS << Name << " = " << (int)(C.*ptr);218    }219  }220};221 222template <typename T, T AMDGPUMCKernelCodeT::*ptr, int shift, int width = 1>223static void printBitField(StringRef Name, const AMDGPUMCKernelCodeT &C,224                          raw_ostream &OS, MCContext &,225                          AMDGPUMCKernelCodeT::PrintHelper) {226  const auto Mask = (static_cast<T>(1) << width) - 1;227  OS << Name << " = " << (int)((C.*ptr >> shift) & Mask);228}229 230using PrintFx = void (*)(StringRef, const AMDGPUMCKernelCodeT &, raw_ostream &,231                         MCContext &, AMDGPUMCKernelCodeT::PrintHelper Helper);232 233static ArrayRef<PrintFx>234getPrinterTable(AMDGPUMCKernelCodeT::PrintHelper Helper) {235  static const PrintFx Table[] = {236#define COMPPGM1(name, aname, AccMacro)                                        \237  COMPPGM(name, aname, C_00B848_##AccMacro, S_00B848_##AccMacro, 0)238#define COMPPGM2(name, aname, AccMacro)                                        \239  COMPPGM(name, aname, C_00B84C_##AccMacro, S_00B84C_##AccMacro, 32)240#define PRINTFIELD(sname, aname, name) PrintField::printField<FLD_T(name)>241#define PRINTCOMP(Complement, PGMType)                                         \242  [](StringRef Name, const AMDGPUMCKernelCodeT &C, raw_ostream &OS,            \243     MCContext &Ctx, AMDGPUMCKernelCodeT::PrintHelper Helper) {                \244    OS << Name << " = ";                                                       \245    auto [Shift, Mask] = getShiftMask(Complement);                             \246    const MCExpr *Value;                                                       \247    if (PGMType == 0) {                                                        \248      Value =                                                                  \249          maskShiftGet(C.compute_pgm_resource1_registers, Mask, Shift, Ctx);   \250    } else {                                                                   \251      Value =                                                                  \252          maskShiftGet(C.compute_pgm_resource2_registers, Mask, Shift, Ctx);   \253    }                                                                          \254    Helper(Value, OS, Ctx.getAsmInfo());                                       \255  }256#define RECORD(name, altName, print, parse) print257#include "Utils/AMDKernelCodeTInfo.h"258#undef RECORD259  };260  return ArrayRef(Table);261}262 263static bool expectAbsExpression(MCAsmParser &MCParser, int64_t &Value,264                                raw_ostream &Err) {265 266  if (MCParser.getLexer().isNot(AsmToken::Equal)) {267    Err << "expected '='";268    return false;269  }270  MCParser.getLexer().Lex();271 272  if (MCParser.parseAbsoluteExpression(Value)) {273    Err << "integer absolute expression expected";274    return false;275  }276  return true;277}278 279template <typename T, T AMDGPUMCKernelCodeT::*ptr>280static bool parseField(AMDGPUMCKernelCodeT &C, MCAsmParser &MCParser,281                       raw_ostream &Err) {282  int64_t Value = 0;283  if (!expectAbsExpression(MCParser, Value, Err))284    return false;285  C.*ptr = (T)Value;286  return true;287}288 289template <typename T, T AMDGPUMCKernelCodeT::*ptr, int shift, int width = 1>290static bool parseBitField(AMDGPUMCKernelCodeT &C, MCAsmParser &MCParser,291                          raw_ostream &Err) {292  int64_t Value = 0;293  if (!expectAbsExpression(MCParser, Value, Err))294    return false;295  const uint64_t Mask = ((UINT64_C(1) << width) - 1) << shift;296  C.*ptr &= (T)~Mask;297  C.*ptr |= (T)((Value << shift) & Mask);298  return true;299}300 301static bool parseExpr(MCAsmParser &MCParser, const MCExpr *&Value,302                      raw_ostream &Err) {303  if (MCParser.getLexer().isNot(AsmToken::Equal)) {304    Err << "expected '='";305    return false;306  }307  MCParser.getLexer().Lex();308 309  if (MCParser.parseExpression(Value)) {310    Err << "Could not parse expression";311    return false;312  }313  return true;314}315 316using ParseFx = bool (*)(AMDGPUMCKernelCodeT &, MCAsmParser &, raw_ostream &);317 318static ArrayRef<ParseFx> getParserTable() {319  static const ParseFx Table[] = {320#define COMPPGM1(name, aname, AccMacro)                                        \321  COMPPGM(name, aname, G_00B848_##AccMacro, C_00B848_##AccMacro, 0)322#define COMPPGM2(name, aname, AccMacro)                                        \323  COMPPGM(name, aname, G_00B84C_##AccMacro, C_00B84C_##AccMacro, 32)324#define PARSECOMP(Complement, PGMType)                                         \325  [](AMDGPUMCKernelCodeT &C, MCAsmParser &MCParser,                            \326     raw_ostream &Err) -> bool {                                               \327    MCContext &Ctx = MCParser.getContext();                                    \328    const MCExpr *Value;                                                       \329    if (!parseExpr(MCParser, Value, Err))                                      \330      return false;                                                            \331    auto [Shift, Mask] = getShiftMask(Complement);                             \332    Value = maskShiftSet(Value, Mask, Shift, Ctx);                             \333    const MCExpr *Compl = MCConstantExpr::create(Complement, Ctx);             \334    if (PGMType == 0) {                                                        \335      C.compute_pgm_resource1_registers = MCBinaryExpr::createAnd(             \336          C.compute_pgm_resource1_registers, Compl, Ctx);                      \337      C.compute_pgm_resource1_registers = MCBinaryExpr::createOr(              \338          C.compute_pgm_resource1_registers, Value, Ctx);                      \339    } else {                                                                   \340      C.compute_pgm_resource2_registers = MCBinaryExpr::createAnd(             \341          C.compute_pgm_resource2_registers, Compl, Ctx);                      \342      C.compute_pgm_resource2_registers = MCBinaryExpr::createOr(              \343          C.compute_pgm_resource2_registers, Value, Ctx);                      \344    }                                                                          \345    return true;                                                               \346  }347#define RECORD(name, altName, print, parse) parse348#include "Utils/AMDKernelCodeTInfo.h"349#undef RECORD350  };351  return ArrayRef(Table);352}353 354static void printAmdKernelCodeField(const AMDGPUMCKernelCodeT &C, int FldIndex,355                                    raw_ostream &OS, MCContext &Ctx,356                                    AMDGPUMCKernelCodeT::PrintHelper Helper) {357  auto Printer = getPrinterTable(Helper)[FldIndex];358  if (Printer)359    Printer(get_amd_kernel_code_t_FldNames()[FldIndex + 1], C, OS, Ctx, Helper);360}361 362void AMDGPUMCKernelCodeT::initDefault(const MCSubtargetInfo *STI,363                                      MCContext &Ctx, bool InitMCExpr) {364  AMDGPUMCKernelCodeT();365 366  AMDGPU::initDefaultAMDKernelCodeT(*this, STI);367 368  if (InitMCExpr) {369    const MCExpr *ZeroExpr = MCConstantExpr::create(0, Ctx);370    compute_pgm_resource1_registers =371        MCConstantExpr::create(Lo_32(compute_pgm_resource_registers), Ctx);372    compute_pgm_resource2_registers =373        MCConstantExpr::create(Hi_32(compute_pgm_resource_registers), Ctx);374    is_dynamic_callstack = ZeroExpr;375    wavefront_sgpr_count = ZeroExpr;376    workitem_vgpr_count = ZeroExpr;377    workitem_private_segment_byte_size = ZeroExpr;378  }379}380 381void AMDGPUMCKernelCodeT::validate(const MCSubtargetInfo *STI, MCContext &Ctx) {382  int64_t Value;383  if (!compute_pgm_resource1_registers->evaluateAsAbsolute(Value))384    return;385 386  if (G_00B848_DX10_CLAMP(Value) && AMDGPU::isGFX12Plus(*STI)) {387    Ctx.reportError({}, "enable_dx10_clamp=1 is not allowed on GFX12+");388    return;389  }390 391  if (G_00B848_IEEE_MODE(Value) && AMDGPU::isGFX12Plus(*STI)) {392    Ctx.reportError({}, "enable_ieee_mode=1 is not allowed on GFX12+");393    return;394  }395 396  if (G_00B848_WGP_MODE(Value) && !AMDGPU::isGFX10Plus(*STI)) {397    Ctx.reportError({}, "enable_wgp_mode=1 is only allowed on GFX10+");398    return;399  }400 401  if (G_00B848_MEM_ORDERED(Value) && !AMDGPU::isGFX10Plus(*STI)) {402    Ctx.reportError({}, "enable_mem_ordered=1 is only allowed on GFX10+");403    return;404  }405 406  if (G_00B848_FWD_PROGRESS(Value) && !AMDGPU::isGFX10Plus(*STI)) {407    Ctx.reportError({}, "enable_fwd_progress=1 is only allowed on GFX10+");408    return;409  }410}411 412const MCExpr *&AMDGPUMCKernelCodeT::getMCExprForIndex(int Index) {413  static const auto IndexTable = getMCExprIndexTable();414  return IndexTable[Index](*this);415}416 417bool AMDGPUMCKernelCodeT::ParseKernelCodeT(StringRef ID, MCAsmParser &MCParser,418                                           raw_ostream &Err) {419  const int Idx = get_amd_kernel_code_t_FieldIndex(ID);420  if (Idx < 0) {421    Err << "unexpected amd_kernel_code_t field name " << ID;422    return false;423  }424 425  if (hasMCExprVersionTable()[Idx]) {426    const MCExpr *Value;427    if (!parseExpr(MCParser, Value, Err))428      return false;429    getMCExprForIndex(Idx) = Value;430    return true;431  }432  auto Parser = getParserTable()[Idx];433  return Parser && Parser(*this, MCParser, Err);434}435 436void AMDGPUMCKernelCodeT::EmitKernelCodeT(raw_ostream &OS, MCContext &Ctx,437                                          PrintHelper Helper) {438  const int Size = hasMCExprVersionTable().size();439  for (int i = 0; i < Size; ++i) {440    OS << "\t\t";441    if (hasMCExprVersionTable()[i]) {442      OS << get_amd_kernel_code_t_FldNames()[i + 1] << " = ";443      const MCExpr *Value = getMCExprForIndex(i);444      Helper(Value, OS, Ctx.getAsmInfo());445    } else {446      printAmdKernelCodeField(*this, i, OS, Ctx, Helper);447    }448    OS << '\n';449  }450}451 452void AMDGPUMCKernelCodeT::EmitKernelCodeT(MCStreamer &OS, MCContext &Ctx) {453  OS.emitIntValue(amd_kernel_code_version_major, /*Size=*/4);454  OS.emitIntValue(amd_kernel_code_version_minor, /*Size=*/4);455  OS.emitIntValue(amd_machine_kind, /*Size=*/2);456  OS.emitIntValue(amd_machine_version_major, /*Size=*/2);457  OS.emitIntValue(amd_machine_version_minor, /*Size=*/2);458  OS.emitIntValue(amd_machine_version_stepping, /*Size=*/2);459  OS.emitIntValue(kernel_code_entry_byte_offset, /*Size=*/8);460  OS.emitIntValue(kernel_code_prefetch_byte_offset, /*Size=*/8);461  OS.emitIntValue(kernel_code_prefetch_byte_size, /*Size=*/8);462  OS.emitIntValue(reserved0, /*Size=*/8);463 464  if (compute_pgm_resource1_registers != nullptr)465    OS.emitValue(compute_pgm_resource1_registers, /*Size=*/4);466  else467    OS.emitIntValue(Lo_32(compute_pgm_resource_registers),468                    /*Size=*/4);469 470  if (compute_pgm_resource2_registers != nullptr)471    OS.emitValue(compute_pgm_resource2_registers, /*Size=*/4);472  else473    OS.emitIntValue(Hi_32(compute_pgm_resource_registers),474                    /*Size=*/4);475 476  if (is_dynamic_callstack != nullptr) {477    const MCExpr *CodeProps = MCConstantExpr::create(code_properties, Ctx);478    CodeProps = MCBinaryExpr::createOr(479        CodeProps,480        maskShiftSet(is_dynamic_callstack,481                     (1 << AMD_CODE_PROPERTY_IS_DYNAMIC_CALLSTACK_WIDTH) - 1,482                     AMD_CODE_PROPERTY_IS_DYNAMIC_CALLSTACK_SHIFT, Ctx),483        Ctx);484    OS.emitValue(CodeProps, /*Size=*/4);485  } else486    OS.emitIntValue(code_properties, /*Size=*/4);487 488  if (workitem_private_segment_byte_size != nullptr)489    OS.emitValue(workitem_private_segment_byte_size, /*Size=*/4);490  else491    OS.emitIntValue(0, /*Size=*/4);492 493  OS.emitIntValue(workgroup_group_segment_byte_size, /*Size=*/4);494  OS.emitIntValue(gds_segment_byte_size, /*Size=*/4);495  OS.emitIntValue(kernarg_segment_byte_size, /*Size=*/8);496  OS.emitIntValue(workgroup_fbarrier_count, /*Size=*/4);497 498  if (wavefront_sgpr_count != nullptr)499    OS.emitValue(wavefront_sgpr_count, /*Size=*/2);500  else501    OS.emitIntValue(0, /*Size=*/2);502 503  if (workitem_vgpr_count != nullptr)504    OS.emitValue(workitem_vgpr_count, /*Size=*/2);505  else506    OS.emitIntValue(0, /*Size=*/2);507 508  OS.emitIntValue(reserved_vgpr_first, /*Size=*/2);509  OS.emitIntValue(reserved_vgpr_count, /*Size=*/2);510  OS.emitIntValue(reserved_sgpr_first, /*Size=*/2);511  OS.emitIntValue(reserved_sgpr_count, /*Size=*/2);512  OS.emitIntValue(debug_wavefront_private_segment_offset_sgpr,513                  /*Size=*/2);514  OS.emitIntValue(debug_private_segment_buffer_sgpr, /*Size=*/2);515  OS.emitIntValue(kernarg_segment_alignment, /*Size=*/1);516  OS.emitIntValue(group_segment_alignment, /*Size=*/1);517  OS.emitIntValue(private_segment_alignment, /*Size=*/1);518  OS.emitIntValue(wavefront_size, /*Size=*/1);519 520  OS.emitIntValue(call_convention, /*Size=*/4);521  OS.emitBytes(StringRef((const char *)reserved3, /*Size=*/12));522  OS.emitIntValue(runtime_loader_kernel_symbol, /*Size=*/8);523  OS.emitBytes(StringRef((const char *)control_directives, /*Size=*/16 * 8));524}525