<commit_before>//===-- TargetAsmInfo.cpp - Asm Info ---------------------------------------==//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file defines target asm properties related what form asm statements
// should take.
//
//===----------------------------------------------------------------------===//

#include "llvm/Constants.h"
#include "llvm/DerivedTypes.h"
#include "llvm/GlobalVariable.h"
#include "llvm/Function.h"
#include "llvm/Module.h"
#include "llvm/Type.h"
#include "llvm/Target/TargetAsmInfo.h"
#include "llvm/Target/TargetData.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Target/TargetOptions.h"
#include "llvm/Support/Dwarf.h"
#include "llvm/Support/ErrorHandling.h"
#include <cctype>
#include <cstring>
using namespace llvm;

TargetAsmInfo::TargetAsmInfo(const TargetMachine &tm) : TM(tm) {
  BSSSection = "\t.bss";
  BSSSection_ = 0;
  ReadOnlySection = 0;
  TLSDataSection = 0;
  TLSBSSSection = 0;
  ZeroFillDirective = 0;
  NonexecutableStackDirective = 0;
  NeedsSet = false;
  MaxInstLength = 4;
  PCSymbol = "$";
  SeparatorChar = ';';
  CommentColumn = 60;
  CommentString = "#";
  FirstOperandColumn = 0;
  MaxOperandLength = 0;
  GlobalPrefix = "";
  PrivateGlobalPrefix = ".";
  LinkerPrivateGlobalPrefix = "";
  JumpTableSpecialLabelPrefix = 0;
  GlobalVarAddrPrefix = "";
  GlobalVarAddrSuffix = "";
  FunctionAddrPrefix = "";
  FunctionAddrSuffix = "";
  PersonalityPrefix = "";
  PersonalitySuffix = "";
  NeedsIndirectEncoding = false;
  InlineAsmStart = "#APP";
  InlineAsmEnd = "#NO_APP";
  AssemblerDialect = 0;
  AllowQuotesInName = false;
  ZeroDirective = "\t.zero\t";
  ZeroDirectiveSuffix = 0;
  AsciiDirective = "\t.ascii\t";
  AscizDirective = "\t.asciz\t";
  Data8bitsDirective = "\t.byte\t";
  Data16bitsDirective = "\t.short\t";
  Data32bitsDirective = "\t.long\t";
  Data64bitsDirective = "\t.quad\t";
  AlignDirective = "\t.align\t";
  AlignmentIsInBytes = true;
  TextAlignFillValue = 0;
  SwitchToSectionDirective = "\t.section\t";
  TextSectionStartSuffix = "";
  DataSectionStartSuffix = "";
  SectionEndDirectiveSuffix = 0;
  ConstantPoolSection = "\t.section .rodata";
  JumpTableDataSection = "\t.section .rodata";
  JumpTableDirective = 0;
  CStringSection = 0;
  CStringSection_ = 0;
  // FIXME: Flags are ELFish - replace with normal section stuff.
  StaticCtorsSection = "\t.section .ctors,\"aw\",@progbits";
  StaticDtorsSection = "\t.section .dtors,\"aw\",@progbits";
  GlobalDirective = "\t.globl\t";
  SetDirective = 0;
  LCOMMDirective = 0;
  COMMDirective = "\t.comm\t";
  COMMDirectiveTakesAlignment = true;
  HasDotTypeDotSizeDirective = true;
  HasSingleParameterDotFile = true;
  UsedDirective = 0;
  WeakRefDirective = 0;
  WeakDefDirective = 0;
  // FIXME: These are ELFish - move to ELFTAI.
  HiddenDirective = "\t.hidden\t";
  ProtectedDirective = "\t.protected\t";
  AbsoluteDebugSectionOffsets = false;
  AbsoluteEHSectionOffsets = false;
  HasLEB128 = false;
  HasDotLocAndDotFile = false;
  SupportsDebugInformation = false;
  SupportsExceptionHandling = false;
  DwarfRequiresFrameSection = true;
  DwarfUsesInlineInfoSection = false;
  Is_EHSymbolPrivate = true;
  GlobalEHDirective = 0;
  SupportsWeakOmittedEHFrame = true;
  DwarfSectionOffsetDirective = 0;
  DwarfAbbrevSection = ".debug_abbrev";
  DwarfInfoSection = ".debug_info";
  DwarfLineSection = ".debug_line";
  DwarfFrameSection = ".debug_frame";
  DwarfPubNamesSection = ".debug_pubnames";
  DwarfPubTypesSection = ".debug_pubtypes";
  DwarfDebugInlineSection = ".debug_inlined";
  DwarfStrSection = ".debug_str";
  DwarfLocSection = ".debug_loc";
  DwarfARangesSection = ".debug_aranges";
  DwarfRangesSection = ".debug_ranges";
  DwarfMacroInfoSection = ".debug_macinfo";
  DwarfEHFrameSection = ".eh_frame";
  DwarfExceptionSection = ".gcc_except_table";
  AsmTransCBE = 0;
}

TargetAsmInfo::~TargetAsmInfo() {
}

/// Measure the specified inline asm to determine an approximation of its
/// length.
/// Comments (which run till the next SeparatorChar or newline) do not
/// count as an instruction.
/// Any other non-whitespace text is considered an instruction, with
/// multiple instructions separated by SeparatorChar or newlines.
/// Variable-length instructions are not handled here; this function
/// may be overloaded in the target code to do that.
unsigned TargetAsmInfo::getInlineAsmLength(const char *Str) const {
  // Count the number of instructions in the asm.
  bool atInsnStart = true;
  unsigned Length = 0;
  for (; *Str; ++Str) {
    if (*Str == '\n' || *Str == SeparatorChar)
      atInsnStart = true;
    if (atInsnStart && !isspace(*Str)) {
      Length += MaxInstLength;
      atInsnStart = false;
    }
    if (atInsnStart && strncmp(Str, CommentString, strlen(CommentString))==0)
      atInsnStart = false;
  }

  return Length;
}

unsigned TargetAsmInfo::PreferredEHDataFormat(DwarfEncoding::Target Reason,
                                              bool Global) const {
  return dwarf::DW_EH_PE_absptr;
}

static bool isSuitableForBSS(const GlobalVariable *GV) {
  Constant *C = GV->getInitializer();

  // Must have zero initializer.
  if (!C->isNullValue())
    return false;

  // Leave constant zeros in readonly constant sections, so they can be shared.
  if (GV->isConstant())
    return false;

  // If the global has an explicit section specified, don't put it in BSS.
  if (!GV->getSection().empty())
    return false;

  // If -nozero-initialized-in-bss is specified, don't ever use BSS.
  if (NoZerosInBSS)
    return false;

  // Otherwise, put it in BSS!
  return true;
}

static bool isConstantString(const Constant *C) {
  // First check: is we have constant array of i8 terminated with zero
  const ConstantArray *CVA = dyn_cast<ConstantArray>(C);
  // Check, if initializer is a null-terminated string
  if (CVA && CVA->isCString())
    return true;

  // Another possibility: [1 x i8] zeroinitializer
  if (isa<ConstantAggregateZero>(C))
    if (const ArrayType *Ty = dyn_cast<ArrayType>(C->getType()))
      return (Ty->getElementType() == Type::Int8Ty &&
              Ty->getNumElements() == 1);

  return false;
}

static SectionKind::Kind SectionKindForGlobal(const GlobalValue *GV,
                                              const TargetMachine &TM) {
  Reloc::Model ReloModel = TM.getRelocationModel();

  // Early exit - functions should be always in text sections.
  const GlobalVariable *GVar = dyn_cast<GlobalVariable>(GV);
  if (GVar == 0)
    return SectionKind::Text;

  // Handle thread-local data first.
  if (GVar->isThreadLocal()) {
    if (isSuitableForBSS(GVar))
      return SectionKind::ThreadBSS;
    return SectionKind::ThreadData;
  }

  // Variable can be easily put to BSS section.
  if (isSuitableForBSS(GVar))
    return SectionKind::BSS;

  Constant *C = GVar->getInitializer();

  // If the global is marked constant, we can put it into a mergable section,
  // a mergable string section, or general .data if it contains relocations.
  if (GVar->isConstant()) {
    // If the initializer for the global contains something that requires a
    // relocation, then we may have to drop this into a wriable data section
    // even though it is marked const.
    switch (C->getRelocationInfo()) {
    default: llvm_unreachable("unknown relocation info kind");
    case Constant::NoRelocation:
      // If initializer is a null-terminated string, put it in a "cstring"
      // section if the target has it.
      if (isConstantString(C))
        return SectionKind::MergeableCString;

      // Otherwise, just drop it into a mergable constant section.  If we have
      // a section for this size, use it, otherwise use the arbitrary sized
      // mergable section.
      switch (TM.getTargetData()->getTypeAllocSize(C->getType())) {
      case 4:  return SectionKind::MergeableConst4;
      case 8:  return SectionKind::MergeableConst8;
      case 16: return SectionKind::MergeableConst16;
      default: return SectionKind::MergeableConst;
      }

    case Constant::LocalRelocation:
      // In static relocation model, the linker will resolve all addresses, so
      // the relocation entries will actually be constants by the time the app
      // starts up.
      if (ReloModel == Reloc::Static)
        return SectionKind::ReadOnly;

      // Otherwise, the dynamic linker needs to fix it up, put it in the
      // writable data.rel.local section.
      return SectionKind::ReadOnlyWithRelLocal;

    case Constant::GlobalRelocations:
      // In static relocation model, the linker will resolve all addresses, so
      // the relocation entries will actually be constants by the time the app
      // starts up.
      if (ReloModel == Reloc::Static)
        return SectionKind::ReadOnly;

      // Otherwise, the dynamic linker needs to fix it up, put it in the
      // writable data.rel section.
      return SectionKind::ReadOnlyWithRel;
    }
  }

  // Okay, this isn't a constant.  If the initializer for the global is going
  // to require a runtime relocation by the dynamic linker, put it into a more
  // specific section to improve startup time of the app.  This coalesces these
  // globals together onto fewer pages, improving the locality of the dynamic
  // linker.
  if (ReloModel == Reloc::Static)
    return SectionKind::DataNoRel;

  switch (C->getRelocationInfo()) {
  default: llvm_unreachable("unknown relocation info kind");
  case Constant::NoRelocation:
    return SectionKind::DataNoRel;
  case Constant::LocalRelocation:
    return SectionKind::DataRelLocal;
  case Constant::GlobalRelocations:
    return SectionKind::DataRel;
  }
}

/// SectionForGlobal - This method computes the appropriate section to emit
/// the specified global variable or function definition.  This should not
/// be passed external (or available externally) globals.
const Section *TargetAsmInfo::SectionForGlobal(const GlobalValue *GV) const {
  assert(!GV->isDeclaration() && !GV->hasAvailableExternallyLinkage() &&
         "Can only be used for global definitions");

  SectionKind::Kind GVKind = SectionKindForGlobal(GV, TM);

  SectionKind Kind = SectionKind::get(GVKind, GV->isWeakForLinker(),
                                      GV->hasSection());

  // Select section name.
  if (GV->hasSection()) {
    // If the target has special section hacks for specifically named globals,
    // return them now.
    if (const Section *TS = getSpecialCasedSectionGlobals(GV, Kind))
      return TS;

    // If the target has magic semantics for certain section names, make sure to
    // pick up the flags.  This allows the user to write things with attribute
    // section and still get the appropriate section flags printed.
    GVKind = getKindForNamedSection(GV->getSection().c_str(), GVKind);

    return getOrCreateSection(GV->getSection().c_str(), false, GVKind);
  }

  // If this global is linkonce/weak and the target handles this by emitting it
  // into a 'uniqued' section name, create and return the section now.
  if (Kind.isWeak()) {
    if (const char *Prefix = getSectionPrefixForUniqueGlobal(Kind)) {
      // FIXME: Use mangler interface (PR4584).
      std::string Name = Prefix+GV->getNameStr();
      return getOrCreateSection(Name.c_str(), false, GVKind);
    }
  }

  // Use default section depending on the 'type' of global
  return SelectSectionForGlobal(GV, Kind);
}

// Lame default implementation. Calculate the section name for global.
const Section*
TargetAsmInfo::SelectSectionForGlobal(const GlobalValue *GV,
                                      SectionKind Kind) const {
  assert(!Kind.isThreadLocal() && "Doesn't support TLS");

  if (Kind.isText())
    return getTextSection();

  if (Kind.isBSS())
    if (const Section *S = getBSSSection_())
      return S;

  if (Kind.isReadOnly())
    if (const Section *S = getReadOnlySection())
      return S;

  return getDataSection();
}

/// getSectionForMergableConstant - Given a mergable constant with the
/// specified size and relocation information, return a section that it
/// should be placed in.
const Section *
TargetAsmInfo::getSectionForMergeableConstant(SectionKind Kind) const {
  if (Kind.isReadOnly())
    if (const Section *S = getReadOnlySection())
      return S;

  return getDataSection();
}

const Section *TargetAsmInfo::getOrCreateSection(const char *Name,
                                                 bool isDirective,
                                                 SectionKind::Kind Kind) const {
  Section &S = Sections[Name];

  // This is newly-created section, set it up properly.
  if (S.Name.empty()) {
    S.Kind = SectionKind::get(Kind, false /*weak*/, !isDirective);
    S.Name = Name;
  }

  return &S;
}

unsigned TargetAsmInfo::getULEB128Size(unsigned Value) {
  unsigned Size = 0;
  do {
    Value >>= 7;
    Size += sizeof(int8_t);
  } while (Value);
  return Size;
}

unsigned TargetAsmInfo::getSLEB128Size(int Value) {
  unsigned Size = 0;
  int Sign = Value >> (8 * sizeof(Value) - 1);
  bool IsMore;

  do {
    unsigned Byte = Value & 0x7f;
    Value >>= 7;
    IsMore = Value != Sign || ((Byte ^ Sign) & 0x40) != 0;
    Size += sizeof(int8_t);
  } while (IsMore);
  return Size;
}
<commit_msg>add an explanatory comment about why we drop these in readonly and not in mergable<commit_after>//===-- TargetAsmInfo.cpp - Asm Info ---------------------------------------==//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file defines target asm properties related what form asm statements
// should take.
//
//===----------------------------------------------------------------------===//

#include "llvm/Constants.h"
#include "llvm/DerivedTypes.h"
#include "llvm/GlobalVariable.h"
#include "llvm/Function.h"
#include "llvm/Module.h"
#include "llvm/Type.h"
#include "llvm/Target/TargetAsmInfo.h"
#include "llvm/Target/TargetData.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Target/TargetOptions.h"
#include "llvm/Support/Dwarf.h"
#include "llvm/Support/ErrorHandling.h"
#include <cctype>
#include <cstring>
using namespace llvm;

TargetAsmInfo::TargetAsmInfo(const TargetMachine &tm) : TM(tm) {
  BSSSection = "\t.bss";
  BSSSection_ = 0;
  ReadOnlySection = 0;
  TLSDataSection = 0;
  TLSBSSSection = 0;
  ZeroFillDirective = 0;
  NonexecutableStackDirective = 0;
  NeedsSet = false;
  MaxInstLength = 4;
  PCSymbol = "$";
  SeparatorChar = ';';
  CommentColumn = 60;
  CommentString = "#";
  FirstOperandColumn = 0;
  MaxOperandLength = 0;
  GlobalPrefix = "";
  PrivateGlobalPrefix = ".";
  LinkerPrivateGlobalPrefix = "";
  JumpTableSpecialLabelPrefix = 0;
  GlobalVarAddrPrefix = "";
  GlobalVarAddrSuffix = "";
  FunctionAddrPrefix = "";
  FunctionAddrSuffix = "";
  PersonalityPrefix = "";
  PersonalitySuffix = "";
  NeedsIndirectEncoding = false;
  InlineAsmStart = "#APP";
  InlineAsmEnd = "#NO_APP";
  AssemblerDialect = 0;
  AllowQuotesInName = false;
  ZeroDirective = "\t.zero\t";
  ZeroDirectiveSuffix = 0;
  AsciiDirective = "\t.ascii\t";
  AscizDirective = "\t.asciz\t";
  Data8bitsDirective = "\t.byte\t";
  Data16bitsDirective = "\t.short\t";
  Data32bitsDirective = "\t.long\t";
  Data64bitsDirective = "\t.quad\t";
  AlignDirective = "\t.align\t";
  AlignmentIsInBytes = true;
  TextAlignFillValue = 0;
  SwitchToSectionDirective = "\t.section\t";
  TextSectionStartSuffix = "";
  DataSectionStartSuffix = "";
  SectionEndDirectiveSuffix = 0;
  ConstantPoolSection = "\t.section .rodata";
  JumpTableDataSection = "\t.section .rodata";
  JumpTableDirective = 0;
  CStringSection = 0;
  CStringSection_ = 0;
  // FIXME: Flags are ELFish - replace with normal section stuff.
  StaticCtorsSection = "\t.section .ctors,\"aw\",@progbits";
  StaticDtorsSection = "\t.section .dtors,\"aw\",@progbits";
  GlobalDirective = "\t.globl\t";
  SetDirective = 0;
  LCOMMDirective = 0;
  COMMDirective = "\t.comm\t";
  COMMDirectiveTakesAlignment = true;
  HasDotTypeDotSizeDirective = true;
  HasSingleParameterDotFile = true;
  UsedDirective = 0;
  WeakRefDirective = 0;
  WeakDefDirective = 0;
  // FIXME: These are ELFish - move to ELFTAI.
  HiddenDirective = "\t.hidden\t";
  ProtectedDirective = "\t.protected\t";
  AbsoluteDebugSectionOffsets = false;
  AbsoluteEHSectionOffsets = false;
  HasLEB128 = false;
  HasDotLocAndDotFile = false;
  SupportsDebugInformation = false;
  SupportsExceptionHandling = false;
  DwarfRequiresFrameSection = true;
  DwarfUsesInlineInfoSection = false;
  Is_EHSymbolPrivate = true;
  GlobalEHDirective = 0;
  SupportsWeakOmittedEHFrame = true;
  DwarfSectionOffsetDirective = 0;
  DwarfAbbrevSection = ".debug_abbrev";
  DwarfInfoSection = ".debug_info";
  DwarfLineSection = ".debug_line";
  DwarfFrameSection = ".debug_frame";
  DwarfPubNamesSection = ".debug_pubnames";
  DwarfPubTypesSection = ".debug_pubtypes";
  DwarfDebugInlineSection = ".debug_inlined";
  DwarfStrSection = ".debug_str";
  DwarfLocSection = ".debug_loc";
  DwarfARangesSection = ".debug_aranges";
  DwarfRangesSection = ".debug_ranges";
  DwarfMacroInfoSection = ".debug_macinfo";
  DwarfEHFrameSection = ".eh_frame";
  DwarfExceptionSection = ".gcc_except_table";
  AsmTransCBE = 0;
}

TargetAsmInfo::~TargetAsmInfo() {
}

/// Measure the specified inline asm to determine an approximation of its
/// length.
/// Comments (which run till the next SeparatorChar or newline) do not
/// count as an instruction.
/// Any other non-whitespace text is considered an instruction, with
/// multiple instructions separated by SeparatorChar or newlines.
/// Variable-length instructions are not handled here; this function
/// may be overloaded in the target code to do that.
unsigned TargetAsmInfo::getInlineAsmLength(const char *Str) const {
  // Count the number of instructions in the asm.
  bool atInsnStart = true;
  unsigned Length = 0;
  for (; *Str; ++Str) {
    if (*Str == '\n' || *Str == SeparatorChar)
      atInsnStart = true;
    if (atInsnStart && !isspace(*Str)) {
      Length += MaxInstLength;
      atInsnStart = false;
    }
    if (atInsnStart && strncmp(Str, CommentString, strlen(CommentString))==0)
      atInsnStart = false;
  }

  return Length;
}

unsigned TargetAsmInfo::PreferredEHDataFormat(DwarfEncoding::Target Reason,
                                              bool Global) const {
  return dwarf::DW_EH_PE_absptr;
}

static bool isSuitableForBSS(const GlobalVariable *GV) {
  Constant *C = GV->getInitializer();

  // Must have zero initializer.
  if (!C->isNullValue())
    return false;

  // Leave constant zeros in readonly constant sections, so they can be shared.
  if (GV->isConstant())
    return false;

  // If the global has an explicit section specified, don't put it in BSS.
  if (!GV->getSection().empty())
    return false;

  // If -nozero-initialized-in-bss is specified, don't ever use BSS.
  if (NoZerosInBSS)
    return false;

  // Otherwise, put it in BSS!
  return true;
}

static bool isConstantString(const Constant *C) {
  // First check: is we have constant array of i8 terminated with zero
  const ConstantArray *CVA = dyn_cast<ConstantArray>(C);
  // Check, if initializer is a null-terminated string
  if (CVA && CVA->isCString())
    return true;

  // Another possibility: [1 x i8] zeroinitializer
  if (isa<ConstantAggregateZero>(C))
    if (const ArrayType *Ty = dyn_cast<ArrayType>(C->getType()))
      return (Ty->getElementType() == Type::Int8Ty &&
              Ty->getNumElements() == 1);

  return false;
}

static SectionKind::Kind SectionKindForGlobal(const GlobalValue *GV,
                                              const TargetMachine &TM) {
  Reloc::Model ReloModel = TM.getRelocationModel();

  // Early exit - functions should be always in text sections.
  const GlobalVariable *GVar = dyn_cast<GlobalVariable>(GV);
  if (GVar == 0)
    return SectionKind::Text;

  // Handle thread-local data first.
  if (GVar->isThreadLocal()) {
    if (isSuitableForBSS(GVar))
      return SectionKind::ThreadBSS;
    return SectionKind::ThreadData;
  }

  // Variable can be easily put to BSS section.
  if (isSuitableForBSS(GVar))
    return SectionKind::BSS;

  Constant *C = GVar->getInitializer();

  // If the global is marked constant, we can put it into a mergable section,
  // a mergable string section, or general .data if it contains relocations.
  if (GVar->isConstant()) {
    // If the initializer for the global contains something that requires a
    // relocation, then we may have to drop this into a wriable data section
    // even though it is marked const.
    switch (C->getRelocationInfo()) {
    default: llvm_unreachable("unknown relocation info kind");
    case Constant::NoRelocation:
      // If initializer is a null-terminated string, put it in a "cstring"
      // section if the target has it.
      if (isConstantString(C))
        return SectionKind::MergeableCString;

      // Otherwise, just drop it into a mergable constant section.  If we have
      // a section for this size, use it, otherwise use the arbitrary sized
      // mergable section.
      switch (TM.getTargetData()->getTypeAllocSize(C->getType())) {
      case 4:  return SectionKind::MergeableConst4;
      case 8:  return SectionKind::MergeableConst8;
      case 16: return SectionKind::MergeableConst16;
      default: return SectionKind::MergeableConst;
      }

    case Constant::LocalRelocation:
      // In static relocation model, the linker will resolve all addresses, so
      // the relocation entries will actually be constants by the time the app
      // starts up.  However, we can't put this into a mergable section, because
      // the linker doesn't take relocations into consideration when it tries to
      // merge entries in the section.
      if (ReloModel == Reloc::Static)
        return SectionKind::ReadOnly;

      // Otherwise, the dynamic linker needs to fix it up, put it in the
      // writable data.rel.local section.
      return SectionKind::ReadOnlyWithRelLocal;

    case Constant::GlobalRelocations:
      // In static relocation model, the linker will resolve all addresses, so
      // the relocation entries will actually be constants by the time the app
      // starts up.  However, we can't put this into a mergable section, because
      // the linker doesn't take relocations into consideration when it tries to
      // merge entries in the section.
      if (ReloModel == Reloc::Static)
        return SectionKind::ReadOnly;

      // Otherwise, the dynamic linker needs to fix it up, put it in the
      // writable data.rel section.
      return SectionKind::ReadOnlyWithRel;
    }
  }

  // Okay, this isn't a constant.  If the initializer for the global is going
  // to require a runtime relocation by the dynamic linker, put it into a more
  // specific section to improve startup time of the app.  This coalesces these
  // globals together onto fewer pages, improving the locality of the dynamic
  // linker.
  if (ReloModel == Reloc::Static)
    return SectionKind::DataNoRel;

  switch (C->getRelocationInfo()) {
  default: llvm_unreachable("unknown relocation info kind");
  case Constant::NoRelocation:
    return SectionKind::DataNoRel;
  case Constant::LocalRelocation:
    return SectionKind::DataRelLocal;
  case Constant::GlobalRelocations:
    return SectionKind::DataRel;
  }
}

/// SectionForGlobal - This method computes the appropriate section to emit
/// the specified global variable or function definition.  This should not
/// be passed external (or available externally) globals.
const Section *TargetAsmInfo::SectionForGlobal(const GlobalValue *GV) const {
  assert(!GV->isDeclaration() && !GV->hasAvailableExternallyLinkage() &&
         "Can only be used for global definitions");

  SectionKind::Kind GVKind = SectionKindForGlobal(GV, TM);

  SectionKind Kind = SectionKind::get(GVKind, GV->isWeakForLinker(),
                                      GV->hasSection());

  // Select section name.
  if (GV->hasSection()) {
    // If the target has special section hacks for specifically named globals,
    // return them now.
    if (const Section *TS = getSpecialCasedSectionGlobals(GV, Kind))
      return TS;

    // If the target has magic semantics for certain section names, make sure to
    // pick up the flags.  This allows the user to write things with attribute
    // section and still get the appropriate section flags printed.
    GVKind = getKindForNamedSection(GV->getSection().c_str(), GVKind);

    return getOrCreateSection(GV->getSection().c_str(), false, GVKind);
  }

  // If this global is linkonce/weak and the target handles this by emitting it
  // into a 'uniqued' section name, create and return the section now.
  if (Kind.isWeak()) {
    if (const char *Prefix = getSectionPrefixForUniqueGlobal(Kind)) {
      // FIXME: Use mangler interface (PR4584).
      std::string Name = Prefix+GV->getNameStr();
      return getOrCreateSection(Name.c_str(), false, GVKind);
    }
  }

  // Use default section depending on the 'type' of global
  return SelectSectionForGlobal(GV, Kind);
}

// Lame default implementation. Calculate the section name for global.
const Section*
TargetAsmInfo::SelectSectionForGlobal(const GlobalValue *GV,
                                      SectionKind Kind) const {
  assert(!Kind.isThreadLocal() && "Doesn't support TLS");

  if (Kind.isText())
    return getTextSection();

  if (Kind.isBSS())
    if (const Section *S = getBSSSection_())
      return S;

  if (Kind.isReadOnly())
    if (const Section *S = getReadOnlySection())
      return S;

  return getDataSection();
}

/// getSectionForMergableConstant - Given a mergable constant with the
/// specified size and relocation information, return a section that it
/// should be placed in.
const Section *
TargetAsmInfo::getSectionForMergeableConstant(SectionKind Kind) const {
  if (Kind.isReadOnly())
    if (const Section *S = getReadOnlySection())
      return S;

  return getDataSection();
}

const Section *TargetAsmInfo::getOrCreateSection(const char *Name,
                                                 bool isDirective,
                                                 SectionKind::Kind Kind) const {
  Section &S = Sections[Name];

  // This is newly-created section, set it up properly.
  if (S.Name.empty()) {
    S.Kind = SectionKind::get(Kind, false /*weak*/, !isDirective);
    S.Name = Name;
  }

  return &S;
}

unsigned TargetAsmInfo::getULEB128Size(unsigned Value) {
  unsigned Size = 0;
  do {
    Value >>= 7;
    Size += sizeof(int8_t);
  } while (Value);
  return Size;
}

unsigned TargetAsmInfo::getSLEB128Size(int Value) {
  unsigned Size = 0;
  int Sign = Value >> (8 * sizeof(Value) - 1);
  bool IsMore;

  do {
    unsigned Byte = Value & 0x7f;
    Value >>= 7;
    IsMore = Value != Sign || ((Byte ^ Sign) & 0x40) != 0;
    Size += sizeof(int8_t);
  } while (IsMore);
  return Size;
}
<|endoftext|>


<commit_before>//===-- TargetMachine.cpp - General Target Information ---------------------==//
//
//                     The LLVM Compiler Infrastructure
//
// This file was developed by the LLVM research group and is distributed under
// the University of Illinois Open Source License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file describes the general parts of a Target machine.
//
//===----------------------------------------------------------------------===//

#include "llvm/Target/TargetMachine.h"
#include "llvm/Type.h"
#include "llvm/CodeGen/IntrinsicLowering.h"
#include "llvm/Support/CommandLine.h"
using namespace llvm;

//---------------------------------------------------------------------------
// Command-line options that tend to be useful on more than one back-end.
//

namespace llvm {
  bool PrintMachineCode;
  bool NoFramePointerElim;
  bool NoExcessFPPrecision;
  int  PatternISelTriState;
  bool UnsafeFPMath;
};
namespace {
  cl::opt<bool, true> PrintCode("print-machineinstrs",
    cl::desc("Print generated machine code"),
    cl::location(PrintMachineCode), cl::init(false));

  cl::opt<bool, true>
    DisableFPElim("disable-fp-elim",
                  cl::desc("Disable frame pointer elimination optimization"),
                  cl::location(NoFramePointerElim),
                  cl::init(false));
  cl::opt<bool, true>
  DisableExcessPrecision("disable-excess-fp-precision",
               cl::desc("Disable optimizations that may increase FP precision"),
               cl::location(NoExcessFPPrecision),
               cl::init(false));
  cl::opt<int, true> PatternISel("enable-pattern-isel",
                    cl::desc("sets the pattern ISel off(0), on(1), default(2)"),
                    cl::location(PatternISelTriState),
                    cl::init(2));
  cl::opt<bool, true>
  EnableUnsafeFPMath("enable-unsafe-fp-math",
               cl::desc("Enable optimizations that may decrease FP precision"),
               cl::location(UnsafeFPMath),
               cl::init(false));
};

//---------------------------------------------------------------------------
// TargetMachine Class
//
TargetMachine::TargetMachine(const std::string &name, IntrinsicLowering *il,
                             bool LittleEndian,
                             unsigned char PtrSize, unsigned char PtrAl,
                             unsigned char DoubleAl, unsigned char FloatAl,
                             unsigned char LongAl, unsigned char IntAl,
                             unsigned char ShortAl, unsigned char ByteAl,
                             unsigned char BoolAl)
  : Name(name), DataLayout(name, LittleEndian,
                           PtrSize, PtrAl, DoubleAl, FloatAl, LongAl,
                           IntAl, ShortAl, ByteAl, BoolAl) {
  IL = il ? il : new DefaultIntrinsicLowering();
}

TargetMachine::TargetMachine(const std::string &name, IntrinsicLowering *il,
                             const TargetData &TD)
  : Name(name), DataLayout(TD) {
  IL = il ? il : new DefaultIntrinsicLowering();
}

TargetMachine::TargetMachine(const std::string &name, IntrinsicLowering *il,
                             const Module &M)
  : Name(name), DataLayout(name, &M) {
  IL = il ? il : new DefaultIntrinsicLowering();
}

TargetMachine::~TargetMachine() {
  delete IL;
}

<commit_msg>capitalize<commit_after>//===-- TargetMachine.cpp - General Target Information ---------------------==//
//
//                     The LLVM Compiler Infrastructure
//
// This file was developed by the LLVM research group and is distributed under
// the University of Illinois Open Source License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file describes the general parts of a Target machine.
//
//===----------------------------------------------------------------------===//

#include "llvm/Target/TargetMachine.h"
#include "llvm/Type.h"
#include "llvm/CodeGen/IntrinsicLowering.h"
#include "llvm/Support/CommandLine.h"
using namespace llvm;

//---------------------------------------------------------------------------
// Command-line options that tend to be useful on more than one back-end.
//

namespace llvm {
  bool PrintMachineCode;
  bool NoFramePointerElim;
  bool NoExcessFPPrecision;
  int  PatternISelTriState;
  bool UnsafeFPMath;
};
namespace {
  cl::opt<bool, true> PrintCode("print-machineinstrs",
    cl::desc("Print generated machine code"),
    cl::location(PrintMachineCode), cl::init(false));

  cl::opt<bool, true>
    DisableFPElim("disable-fp-elim",
                  cl::desc("Disable frame pointer elimination optimization"),
                  cl::location(NoFramePointerElim),
                  cl::init(false));
  cl::opt<bool, true>
  DisableExcessPrecision("disable-excess-fp-precision",
               cl::desc("Disable optimizations that may increase FP precision"),
               cl::location(NoExcessFPPrecision),
               cl::init(false));
  cl::opt<int, true> PatternISel("enable-pattern-isel",
                    cl::desc("Turn the pattern ISel off(0), on(1), default(2)"),
                    cl::location(PatternISelTriState),
                    cl::init(2));
  cl::opt<bool, true>
  EnableUnsafeFPMath("enable-unsafe-fp-math",
               cl::desc("Enable optimizations that may decrease FP precision"),
               cl::location(UnsafeFPMath),
               cl::init(false));
};

//---------------------------------------------------------------------------
// TargetMachine Class
//
TargetMachine::TargetMachine(const std::string &name, IntrinsicLowering *il,
                             bool LittleEndian,
                             unsigned char PtrSize, unsigned char PtrAl,
                             unsigned char DoubleAl, unsigned char FloatAl,
                             unsigned char LongAl, unsigned char IntAl,
                             unsigned char ShortAl, unsigned char ByteAl,
                             unsigned char BoolAl)
  : Name(name), DataLayout(name, LittleEndian,
                           PtrSize, PtrAl, DoubleAl, FloatAl, LongAl,
                           IntAl, ShortAl, ByteAl, BoolAl) {
  IL = il ? il : new DefaultIntrinsicLowering();
}

TargetMachine::TargetMachine(const std::string &name, IntrinsicLowering *il,
                             const TargetData &TD)
  : Name(name), DataLayout(TD) {
  IL = il ? il : new DefaultIntrinsicLowering();
}

TargetMachine::TargetMachine(const std::string &name, IntrinsicLowering *il,
                             const Module &M)
  : Name(name), DataLayout(name, &M) {
  IL = il ? il : new DefaultIntrinsicLowering();
}

TargetMachine::~TargetMachine() {
  delete IL;
}

<|endoftext|>


<commit_before>//===-- TargetMachine.cpp - General Target Information ---------------------==//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file describes the general parts of a Target machine.
//
//===----------------------------------------------------------------------===//

#include "llvm/MC/MCAsmInfo.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Target/TargetOptions.h"
#include "llvm/Support/CommandLine.h"
using namespace llvm;

//---------------------------------------------------------------------------
// Command-line options that tend to be useful on more than one back-end.
//

namespace llvm {
  bool LessPreciseFPMADOption;
  bool PrintMachineCode;
  bool NoFramePointerElim;
  bool NoExcessFPPrecision;
  bool UnsafeFPMath;
  bool FiniteOnlyFPMathOption;
  bool HonorSignDependentRoundingFPMathOption;
  bool UseSoftFloat;
  FloatABI::ABIType FloatABIType;
  bool NoImplicitFloat;
  bool NoZerosInBSS;
  bool DwarfExceptionHandling;
  bool SjLjExceptionHandling;
  bool JITEmitDebugInfo;
  bool JITEmitDebugInfoToDisk;
  bool UnwindTablesMandatory;
  Reloc::Model RelocationModel;
  CodeModel::Model CMModel;
  bool PerformTailCallOpt;
  unsigned StackAlignment;
  bool RealignStack;
  bool DisableJumpTables;
  bool StrongPHIElim;
  bool AsmVerbosityDefault(false);
}

static cl::opt<bool, true>
PrintCode("print-machineinstrs",
  cl::desc("Print generated machine code"),
  cl::location(PrintMachineCode), cl::init(false));
static cl::opt<bool, true>
DisableFPElim("disable-fp-elim",
  cl::desc("Disable frame pointer elimination optimization"),
  cl::location(NoFramePointerElim),
  cl::init(false));
static cl::opt<bool, true>
DisableExcessPrecision("disable-excess-fp-precision",
  cl::desc("Disable optimizations that may increase FP precision"),
  cl::location(NoExcessFPPrecision),
  cl::init(false));
static cl::opt<bool, true>
EnableFPMAD("enable-fp-mad",
  cl::desc("Enable less precise MAD instructions to be generated"),
  cl::location(LessPreciseFPMADOption),
  cl::init(false));
static cl::opt<bool, true>
EnableUnsafeFPMath("enable-unsafe-fp-math",
  cl::desc("Enable optimizations that may decrease FP precision"),
  cl::location(UnsafeFPMath),
  cl::init(false));
static cl::opt<bool, true>
EnableFiniteOnlyFPMath("enable-finite-only-fp-math",
  cl::desc("Enable optimizations that assumes non- NaNs / +-Infs"),
  cl::location(FiniteOnlyFPMathOption),
  cl::init(false));
static cl::opt<bool, true>
EnableHonorSignDependentRoundingFPMath("enable-sign-dependent-rounding-fp-math",
  cl::Hidden,
  cl::desc("Force codegen to assume rounding mode can change dynamically"),
  cl::location(HonorSignDependentRoundingFPMathOption),
  cl::init(false));
static cl::opt<bool, true>
GenerateSoftFloatCalls("soft-float",
  cl::desc("Generate software floating point library calls"),
  cl::location(UseSoftFloat),
  cl::init(false));
static cl::opt<llvm::FloatABI::ABIType, true>
FloatABIForCalls("float-abi",
  cl::desc("Choose float ABI type"),
  cl::location(FloatABIType),
  cl::init(FloatABI::Default),
  cl::values(
    clEnumValN(FloatABI::Default, "default",
               "Target default float ABI type"),
    clEnumValN(FloatABI::Soft, "soft",
               "Soft float ABI (implied by -soft-float)"),
    clEnumValN(FloatABI::Hard, "hard",
               "Hard float ABI (uses FP registers)"),
    clEnumValEnd));
static cl::opt<bool, true>
DontPlaceZerosInBSS("nozero-initialized-in-bss",
  cl::desc("Don't place zero-initialized symbols into bss section"),
  cl::location(NoZerosInBSS),
  cl::init(false));
static cl::opt<bool, true>
EnableDwarfExceptionHandling("enable-eh",
  cl::desc("Emit DWARF exception handling (default if target supports)"),
  cl::location(DwarfExceptionHandling),
  cl::init(false));
static cl::opt<bool, true>
EnableSjLjExceptionHandling("enable-sjlj-eh",
  cl::desc("Emit SJLJ exception handling (default if target supports)"),
  cl::location(SjLjExceptionHandling),
  cl::init(false));
// In debug builds, make this default to true.
#ifdef NDEBUG
#define EMIT_DEBUG false
#else
#define EMIT_DEBUG true
#endif
static cl::opt<bool, true>
EmitJitDebugInfo("jit-emit-debug",
  cl::desc("Emit debug information to debugger"),
  cl::location(JITEmitDebugInfo),
  cl::init(EMIT_DEBUG));
#undef EMIT_DEBUG
static cl::opt<bool, true>
EmitJitDebugInfoToDisk("jit-emit-debug-to-disk",
  cl::Hidden,
  cl::desc("Emit debug info objfiles to disk"),
  cl::location(JITEmitDebugInfoToDisk),
  cl::init(false));
static cl::opt<bool, true>
EnableUnwindTables("unwind-tables",
  cl::desc("Generate unwinding tables for all functions"),
  cl::location(UnwindTablesMandatory),
  cl::init(false));

static cl::opt<llvm::Reloc::Model, true>
DefRelocationModel("relocation-model",
  cl::desc("Choose relocation model"),
  cl::location(RelocationModel),
  cl::init(Reloc::Default),
  cl::values(
    clEnumValN(Reloc::Default, "default",
               "Target default relocation model"),
    clEnumValN(Reloc::Static, "static",
               "Non-relocatable code"),
    clEnumValN(Reloc::PIC_, "pic",
               "Fully relocatable, position independent code"),
    clEnumValN(Reloc::DynamicNoPIC, "dynamic-no-pic",
               "Relocatable external references, non-relocatable code"),
    clEnumValEnd));
static cl::opt<llvm::CodeModel::Model, true>
DefCodeModel("code-model",
  cl::desc("Choose code model"),
  cl::location(CMModel),
  cl::init(CodeModel::Default),
  cl::values(
    clEnumValN(CodeModel::Default, "default",
               "Target default code model"),
    clEnumValN(CodeModel::Small, "small",
               "Small code model"),
    clEnumValN(CodeModel::Kernel, "kernel",
               "Kernel code model"),
    clEnumValN(CodeModel::Medium, "medium",
               "Medium code model"),
    clEnumValN(CodeModel::Large, "large",
               "Large code model"),
    clEnumValEnd));
static cl::opt<bool, true>
EnablePerformTailCallOpt("tailcallopt",
  cl::desc("Turn on tail call optimization."),
  cl::location(PerformTailCallOpt),
  cl::init(false));
static cl::opt<unsigned, true>
OverrideStackAlignment("stack-alignment",
  cl::desc("Override default stack alignment"),
  cl::location(StackAlignment),
  cl::init(0));
static cl::opt<bool, true>
EnableRealignStack("realign-stack",
  cl::desc("Realign stack if needed"),
  cl::location(RealignStack),
  cl::init(true));
static cl::opt<bool, true>
DisableSwitchTables(cl::Hidden, "disable-jump-tables",
  cl::desc("Do not generate jump tables."),
  cl::location(DisableJumpTables),
  cl::init(false));
static cl::opt<bool, true>
EnableStrongPHIElim(cl::Hidden, "strong-phi-elim",
  cl::desc("Use strong PHI elimination."),
  cl::location(StrongPHIElim),
  cl::init(false));

//---------------------------------------------------------------------------
// TargetMachine Class
//

TargetMachine::TargetMachine(const Target &T)
  : TheTarget(T), AsmInfo(0) {
  // Typically it will be subtargets that will adjust FloatABIType from Default
  // to Soft or Hard.
  if (UseSoftFloat)
    FloatABIType = FloatABI::Soft;
}

TargetMachine::~TargetMachine() {
  delete AsmInfo;
}

/// getRelocationModel - Returns the code generation relocation model. The
/// choices are static, PIC, and dynamic-no-pic, and target default.
Reloc::Model TargetMachine::getRelocationModel() {
  return RelocationModel;
}

/// setRelocationModel - Sets the code generation relocation model.
void TargetMachine::setRelocationModel(Reloc::Model Model) {
  RelocationModel = Model;
}

/// getCodeModel - Returns the code model. The choices are small, kernel,
/// medium, large, and target default.
CodeModel::Model TargetMachine::getCodeModel() {
  return CMModel;
}

/// setCodeModel - Sets the code model.
void TargetMachine::setCodeModel(CodeModel::Model Model) {
  CMModel = Model;
}

bool TargetMachine::getAsmVerbosityDefault() {
  return AsmVerbosityDefault;
}

void TargetMachine::setAsmVerbosityDefault(bool V) {
  AsmVerbosityDefault = V;
}

namespace llvm {
  /// LessPreciseFPMAD - This flag return true when -enable-fp-mad option
  /// is specified on the command line.  When this flag is off(default), the
  /// code generator is not allowed to generate mad (multiply add) if the
  /// result is "less precise" than doing those operations individually.
  bool LessPreciseFPMAD() { return UnsafeFPMath || LessPreciseFPMADOption; }

  /// FiniteOnlyFPMath - This returns true when the -enable-finite-only-fp-math
  /// option is specified on the command line. If this returns false (default),
  /// the code generator is not allowed to assume that FP arithmetic arguments
  /// and results are never NaNs or +-Infs.
  bool FiniteOnlyFPMath() { return UnsafeFPMath || FiniteOnlyFPMathOption; }

  /// HonorSignDependentRoundingFPMath - Return true if the codegen must assume
  /// that the rounding mode of the FPU can change from its default.
  bool HonorSignDependentRoundingFPMath() {
    return !UnsafeFPMath && HonorSignDependentRoundingFPMathOption;
  }
}
<commit_msg>Clarify what -tailcallopt option actually do.<commit_after>//===-- TargetMachine.cpp - General Target Information ---------------------==//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file describes the general parts of a Target machine.
//
//===----------------------------------------------------------------------===//

#include "llvm/MC/MCAsmInfo.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Target/TargetOptions.h"
#include "llvm/Support/CommandLine.h"
using namespace llvm;

//---------------------------------------------------------------------------
// Command-line options that tend to be useful on more than one back-end.
//

namespace llvm {
  bool LessPreciseFPMADOption;
  bool PrintMachineCode;
  bool NoFramePointerElim;
  bool NoExcessFPPrecision;
  bool UnsafeFPMath;
  bool FiniteOnlyFPMathOption;
  bool HonorSignDependentRoundingFPMathOption;
  bool UseSoftFloat;
  FloatABI::ABIType FloatABIType;
  bool NoImplicitFloat;
  bool NoZerosInBSS;
  bool DwarfExceptionHandling;
  bool SjLjExceptionHandling;
  bool JITEmitDebugInfo;
  bool JITEmitDebugInfoToDisk;
  bool UnwindTablesMandatory;
  Reloc::Model RelocationModel;
  CodeModel::Model CMModel;
  bool PerformTailCallOpt;
  unsigned StackAlignment;
  bool RealignStack;
  bool DisableJumpTables;
  bool StrongPHIElim;
  bool AsmVerbosityDefault(false);
}

static cl::opt<bool, true>
PrintCode("print-machineinstrs",
  cl::desc("Print generated machine code"),
  cl::location(PrintMachineCode), cl::init(false));
static cl::opt<bool, true>
DisableFPElim("disable-fp-elim",
  cl::desc("Disable frame pointer elimination optimization"),
  cl::location(NoFramePointerElim),
  cl::init(false));
static cl::opt<bool, true>
DisableExcessPrecision("disable-excess-fp-precision",
  cl::desc("Disable optimizations that may increase FP precision"),
  cl::location(NoExcessFPPrecision),
  cl::init(false));
static cl::opt<bool, true>
EnableFPMAD("enable-fp-mad",
  cl::desc("Enable less precise MAD instructions to be generated"),
  cl::location(LessPreciseFPMADOption),
  cl::init(false));
static cl::opt<bool, true>
EnableUnsafeFPMath("enable-unsafe-fp-math",
  cl::desc("Enable optimizations that may decrease FP precision"),
  cl::location(UnsafeFPMath),
  cl::init(false));
static cl::opt<bool, true>
EnableFiniteOnlyFPMath("enable-finite-only-fp-math",
  cl::desc("Enable optimizations that assumes non- NaNs / +-Infs"),
  cl::location(FiniteOnlyFPMathOption),
  cl::init(false));
static cl::opt<bool, true>
EnableHonorSignDependentRoundingFPMath("enable-sign-dependent-rounding-fp-math",
  cl::Hidden,
  cl::desc("Force codegen to assume rounding mode can change dynamically"),
  cl::location(HonorSignDependentRoundingFPMathOption),
  cl::init(false));
static cl::opt<bool, true>
GenerateSoftFloatCalls("soft-float",
  cl::desc("Generate software floating point library calls"),
  cl::location(UseSoftFloat),
  cl::init(false));
static cl::opt<llvm::FloatABI::ABIType, true>
FloatABIForCalls("float-abi",
  cl::desc("Choose float ABI type"),
  cl::location(FloatABIType),
  cl::init(FloatABI::Default),
  cl::values(
    clEnumValN(FloatABI::Default, "default",
               "Target default float ABI type"),
    clEnumValN(FloatABI::Soft, "soft",
               "Soft float ABI (implied by -soft-float)"),
    clEnumValN(FloatABI::Hard, "hard",
               "Hard float ABI (uses FP registers)"),
    clEnumValEnd));
static cl::opt<bool, true>
DontPlaceZerosInBSS("nozero-initialized-in-bss",
  cl::desc("Don't place zero-initialized symbols into bss section"),
  cl::location(NoZerosInBSS),
  cl::init(false));
static cl::opt<bool, true>
EnableDwarfExceptionHandling("enable-eh",
  cl::desc("Emit DWARF exception handling (default if target supports)"),
  cl::location(DwarfExceptionHandling),
  cl::init(false));
static cl::opt<bool, true>
EnableSjLjExceptionHandling("enable-sjlj-eh",
  cl::desc("Emit SJLJ exception handling (default if target supports)"),
  cl::location(SjLjExceptionHandling),
  cl::init(false));
// In debug builds, make this default to true.
#ifdef NDEBUG
#define EMIT_DEBUG false
#else
#define EMIT_DEBUG true
#endif
static cl::opt<bool, true>
EmitJitDebugInfo("jit-emit-debug",
  cl::desc("Emit debug information to debugger"),
  cl::location(JITEmitDebugInfo),
  cl::init(EMIT_DEBUG));
#undef EMIT_DEBUG
static cl::opt<bool, true>
EmitJitDebugInfoToDisk("jit-emit-debug-to-disk",
  cl::Hidden,
  cl::desc("Emit debug info objfiles to disk"),
  cl::location(JITEmitDebugInfoToDisk),
  cl::init(false));
static cl::opt<bool, true>
EnableUnwindTables("unwind-tables",
  cl::desc("Generate unwinding tables for all functions"),
  cl::location(UnwindTablesMandatory),
  cl::init(false));

static cl::opt<llvm::Reloc::Model, true>
DefRelocationModel("relocation-model",
  cl::desc("Choose relocation model"),
  cl::location(RelocationModel),
  cl::init(Reloc::Default),
  cl::values(
    clEnumValN(Reloc::Default, "default",
               "Target default relocation model"),
    clEnumValN(Reloc::Static, "static",
               "Non-relocatable code"),
    clEnumValN(Reloc::PIC_, "pic",
               "Fully relocatable, position independent code"),
    clEnumValN(Reloc::DynamicNoPIC, "dynamic-no-pic",
               "Relocatable external references, non-relocatable code"),
    clEnumValEnd));
static cl::opt<llvm::CodeModel::Model, true>
DefCodeModel("code-model",
  cl::desc("Choose code model"),
  cl::location(CMModel),
  cl::init(CodeModel::Default),
  cl::values(
    clEnumValN(CodeModel::Default, "default",
               "Target default code model"),
    clEnumValN(CodeModel::Small, "small",
               "Small code model"),
    clEnumValN(CodeModel::Kernel, "kernel",
               "Kernel code model"),
    clEnumValN(CodeModel::Medium, "medium",
               "Medium code model"),
    clEnumValN(CodeModel::Large, "large",
               "Large code model"),
    clEnumValEnd));
static cl::opt<bool, true>
EnablePerformTailCallOpt("tailcallopt",
  cl::desc("Turn fastcc calls into tail calls by (potentially) changing ABI."),
  cl::location(PerformTailCallOpt),
  cl::init(false));
static cl::opt<unsigned, true>
OverrideStackAlignment("stack-alignment",
  cl::desc("Override default stack alignment"),
  cl::location(StackAlignment),
  cl::init(0));
static cl::opt<bool, true>
EnableRealignStack("realign-stack",
  cl::desc("Realign stack if needed"),
  cl::location(RealignStack),
  cl::init(true));
static cl::opt<bool, true>
DisableSwitchTables(cl::Hidden, "disable-jump-tables",
  cl::desc("Do not generate jump tables."),
  cl::location(DisableJumpTables),
  cl::init(false));
static cl::opt<bool, true>
EnableStrongPHIElim(cl::Hidden, "strong-phi-elim",
  cl::desc("Use strong PHI elimination."),
  cl::location(StrongPHIElim),
  cl::init(false));

//---------------------------------------------------------------------------
// TargetMachine Class
//

TargetMachine::TargetMachine(const Target &T)
  : TheTarget(T), AsmInfo(0) {
  // Typically it will be subtargets that will adjust FloatABIType from Default
  // to Soft or Hard.
  if (UseSoftFloat)
    FloatABIType = FloatABI::Soft;
}

TargetMachine::~TargetMachine() {
  delete AsmInfo;
}

/// getRelocationModel - Returns the code generation relocation model. The
/// choices are static, PIC, and dynamic-no-pic, and target default.
Reloc::Model TargetMachine::getRelocationModel() {
  return RelocationModel;
}

/// setRelocationModel - Sets the code generation relocation model.
void TargetMachine::setRelocationModel(Reloc::Model Model) {
  RelocationModel = Model;
}

/// getCodeModel - Returns the code model. The choices are small, kernel,
/// medium, large, and target default.
CodeModel::Model TargetMachine::getCodeModel() {
  return CMModel;
}

/// setCodeModel - Sets the code model.
void TargetMachine::setCodeModel(CodeModel::Model Model) {
  CMModel = Model;
}

bool TargetMachine::getAsmVerbosityDefault() {
  return AsmVerbosityDefault;
}

void TargetMachine::setAsmVerbosityDefault(bool V) {
  AsmVerbosityDefault = V;
}

namespace llvm {
  /// LessPreciseFPMAD - This flag return true when -enable-fp-mad option
  /// is specified on the command line.  When this flag is off(default), the
  /// code generator is not allowed to generate mad (multiply add) if the
  /// result is "less precise" than doing those operations individually.
  bool LessPreciseFPMAD() { return UnsafeFPMath || LessPreciseFPMADOption; }

  /// FiniteOnlyFPMath - This returns true when the -enable-finite-only-fp-math
  /// option is specified on the command line. If this returns false (default),
  /// the code generator is not allowed to assume that FP arithmetic arguments
  /// and results are never NaNs or +-Infs.
  bool FiniteOnlyFPMath() { return UnsafeFPMath || FiniteOnlyFPMathOption; }

  /// HonorSignDependentRoundingFPMath - Return true if the codegen must assume
  /// that the rounding mode of the FPU can change from its default.
  bool HonorSignDependentRoundingFPMath() {
    return !UnsafeFPMath && HonorSignDependentRoundingFPMathOption;
  }
}
<|endoftext|>


<commit_before>#include "archive.hh"
#include "binary-cache-store.hh"
#include "compression.hh"
#include "derivations.hh"
#include "fs-accessor.hh"
#include "globals.hh"
#include "nar-info.hh"
#include "sync.hh"
#include "worker-protocol.hh"
#include "nar-accessor.hh"
#include "nar-info-disk-cache.hh"

#include <chrono>

namespace nix {

BinaryCacheStore::BinaryCacheStore(std::shared_ptr<Store> localStore,
    const StoreParams & params)
    : localStore(localStore)
    , compression(get(params, "compression", "xz"))
{
    auto secretKeyFile = get(params, "secret-key", "");
    if (secretKeyFile != "")
        secretKey = std::unique_ptr<SecretKey>(new SecretKey(readFile(secretKeyFile)));

    StringSink sink;
    sink << narVersionMagic1;
    narMagic = *sink.s;
}

void BinaryCacheStore::init()
{
    std::string cacheInfoFile = "nix-cache-info";
    if (!fileExists(cacheInfoFile))
        upsertFile(cacheInfoFile, "StoreDir: " + settings.nixStore + "\n");
}

void BinaryCacheStore::notImpl()
{
    throw Error("operation not implemented for binary cache stores");
}

Path BinaryCacheStore::narInfoFileFor(const Path & storePath)
{
    assertStorePath(storePath);
    return storePathToHash(storePath) + ".narinfo";
}

void BinaryCacheStore::addToCache(const ValidPathInfo & info, ref<std::string> nar)
{
    /* Verify that all references are valid. This may do some .narinfo
       reads, but typically they'll already be cached. */
    for (auto & ref : info.references)
        try {
            if (ref != info.path)
                queryPathInfo(ref);
        } catch (InvalidPath &) {
            throw Error(format("cannot add ‘%s’ to the binary cache because the reference ‘%s’ is not valid")
                % info.path % ref);
        }

    auto narInfoFile = narInfoFileFor(info.path);
    if (fileExists(narInfoFile)) return;

    assert(nar->compare(0, narMagic.size(), narMagic) == 0);

    auto narInfo = make_ref<NarInfo>(info);

    narInfo->narSize = nar->size();
    narInfo->narHash = hashString(htSHA256, *nar);

    if (info.narHash && info.narHash != narInfo->narHash)
        throw Error(format("refusing to copy corrupted path ‘%1%’ to binary cache") % info.path);

    /* Compress the NAR. */
    narInfo->compression = compression;
    auto now1 = std::chrono::steady_clock::now();
    auto narCompressed = compress(compression, nar);
    auto now2 = std::chrono::steady_clock::now();
    narInfo->fileHash = hashString(htSHA256, *narCompressed);
    narInfo->fileSize = narCompressed->size();

    auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(now2 - now1).count();
    printMsg(lvlTalkative, format("copying path ‘%1%’ (%2% bytes, compressed %3$.1f%% in %4% ms) to binary cache")
        % narInfo->path % narInfo->narSize
        % ((1.0 - (double) narCompressed->size() / nar->size()) * 100.0)
        % duration);

    /* Atomically write the NAR file. */
    narInfo->url = "nar/" + printHash32(narInfo->fileHash) + ".nar.xz";
    if (!fileExists(narInfo->url)) {
        stats.narWrite++;
        upsertFile(narInfo->url, *narCompressed);
    } else
        stats.narWriteAverted++;

    stats.narWriteBytes += nar->size();
    stats.narWriteCompressedBytes += narCompressed->size();
    stats.narWriteCompressionTimeMs += duration;

    /* Atomically write the NAR info file.*/
    if (secretKey) narInfo->sign(*secretKey);

    upsertFile(narInfoFile, narInfo->to_string());

    auto hashPart = storePathToHash(narInfo->path);

    {
        auto state_(state.lock());
        state_->pathInfoCache.upsert(hashPart, std::shared_ptr<NarInfo>(narInfo));
    }

    if (diskCache)
        diskCache->upsertNarInfo(getUri(), hashPart, std::shared_ptr<NarInfo>(narInfo));

    stats.narInfoWrite++;
}

bool BinaryCacheStore::isValidPathUncached(const Path & storePath)
{
    // FIXME: this only checks whether a .narinfo with a matching hash
    // part exists. So ‘f4kb...-foo’ matches ‘f4kb...-bar’, even
    // though they shouldn't. Not easily fixed.
    return fileExists(narInfoFileFor(storePath));
}

void BinaryCacheStore::narFromPath(const Path & storePath, Sink & sink)
{
    auto info = queryPathInfo(storePath).cast<const NarInfo>();

    auto nar = getFile(info->url);

    if (!nar) throw Error(format("file ‘%s’ missing from binary cache") % info->url);

    stats.narRead++;
    stats.narReadCompressedBytes += nar->size();

    /* Decompress the NAR. FIXME: would be nice to have the remote
       side do this. */
    nar = decompress(info->compression, ref<std::string>(nar));

    stats.narReadBytes += nar->size();

    printMsg(lvlTalkative, format("exporting path ‘%1%’ (%2% bytes)") % storePath % nar->size());

    assert(nar->size() % 8 == 0);

    sink((unsigned char *) nar->c_str(), nar->size());
}

void BinaryCacheStore::exportPath(const Path & storePath, bool sign, Sink & sink)
{
    assert(!sign);

    auto res = queryPathInfo(storePath);

    narFromPath(storePath, sink);

    // FIXME: check integrity of NAR.

    sink << exportMagic << storePath << res->references << res->deriver << 0;
}

Paths BinaryCacheStore::importPaths(bool requireSignature, Source & source,
    std::shared_ptr<FSAccessor> accessor)
{
    assert(!requireSignature);
    Paths res;
    while (true) {
        unsigned long long n = readLongLong(source);
        if (n == 0) break;
        if (n != 1) throw Error("input doesn't look like something created by ‘nix-store --export’");
        res.push_back(importPath(source, accessor));
    }
    return res;
}

struct TeeSource : Source
{
    Source & readSource;
    ref<std::string> data;
    TeeSource(Source & readSource)
        : readSource(readSource)
        , data(make_ref<std::string>())
    {
    }
    size_t read(unsigned char * data, size_t len)
    {
        size_t n = readSource.read(data, len);
        this->data->append((char *) data, n);
        return n;
    }
};

struct NopSink : ParseSink
{
};

std::shared_ptr<ValidPathInfo> BinaryCacheStore::queryPathInfoUncached(const Path & storePath)
{
    auto narInfoFile = narInfoFileFor(storePath);
    auto data = getFile(narInfoFile);
    if (!data) return 0;

    auto narInfo = make_ref<NarInfo>(*data, narInfoFile);

    stats.narInfoRead++;

    return std::shared_ptr<NarInfo>(narInfo);
}

void BinaryCacheStore::querySubstitutablePathInfos(const PathSet & paths,
    SubstitutablePathInfos & infos)
{
    PathSet left;

    if (!localStore) return;

    for (auto & storePath : paths) {
        try {
            auto info = localStore->queryPathInfo(storePath);
            SubstitutablePathInfo sub;
            sub.references = info->references;
            sub.downloadSize = 0;
            sub.narSize = info->narSize;
            infos.emplace(storePath, sub);
        } catch (InvalidPath &) {
            left.insert(storePath);
        }
    }

    if (settings.useSubstitutes)
        localStore->querySubstitutablePathInfos(left, infos);
}

Path BinaryCacheStore::addToStore(const string & name, const Path & srcPath,
    bool recursive, HashType hashAlgo, PathFilter & filter, bool repair)
{
    // FIXME: some cut&paste from LocalStore::addToStore().

    /* Read the whole path into memory. This is not a very scalable
       method for very large paths, but `copyPath' is mainly used for
       small files. */
    StringSink sink;
    Hash h;
    if (recursive) {
        dumpPath(srcPath, sink, filter);
        h = hashString(hashAlgo, *sink.s);
    } else {
        auto s = readFile(srcPath);
        dumpString(s, sink);
        h = hashString(hashAlgo, s);
    }

    ValidPathInfo info;
    info.path = makeFixedOutputPath(recursive, hashAlgo, h, name);

    if (repair || !isValidPath(info.path))
        addToCache(info, sink.s);

    return info.path;
}

Path BinaryCacheStore::addTextToStore(const string & name, const string & s,
    const PathSet & references, bool repair)
{
    ValidPathInfo info;
    info.path = computeStorePathForText(name, s, references);
    info.references = references;

    if (repair || !isValidPath(info.path)) {
        StringSink sink;
        dumpString(s, sink);
        addToCache(info, sink.s);
    }

    return info.path;
}

void BinaryCacheStore::buildPaths(const PathSet & paths, BuildMode buildMode)
{
    for (auto & storePath : paths) {
        assert(!isDerivation(storePath));

        if (isValidPath(storePath)) continue;

        if (!localStore)
            throw Error(format("don't know how to realise path ‘%1%’ in a binary cache") % storePath);

        localStore->addTempRoot(storePath);

        if (!localStore->isValidPath(storePath))
            localStore->ensurePath(storePath);

        auto info = localStore->queryPathInfo(storePath);

        for (auto & ref : info->references)
            if (ref != storePath)
                ensurePath(ref);

        StringSink sink;
        dumpPath(storePath, sink);

        addToCache(*info, sink.s);
    }
}

void BinaryCacheStore::ensurePath(const Path & path)
{
    buildPaths({path});
}

/* Given requests for a path /nix/store/<x>/<y>, this accessor will
   first download the NAR for /nix/store/<x> from the binary cache,
   build a NAR accessor for that NAR, and use that to access <y>. */
struct BinaryCacheStoreAccessor : public FSAccessor
{
    ref<BinaryCacheStore> store;

    std::map<Path, ref<FSAccessor>> nars;

    BinaryCacheStoreAccessor(ref<BinaryCacheStore> store)
        : store(store)
    {
    }

    std::pair<ref<FSAccessor>, Path> fetch(const Path & path_)
    {
        auto path = canonPath(path_);

        auto storePath = toStorePath(path);
        std::string restPath = std::string(path, storePath.size());

        if (!store->isValidPath(storePath))
            throw Error(format("path ‘%1%’ is not a valid store path") % storePath);

        auto i = nars.find(storePath);
        if (i != nars.end()) return {i->second, restPath};

        StringSink sink;
        store->exportPath(storePath, false, sink);

        auto accessor = makeNarAccessor(sink.s);
        nars.emplace(storePath, accessor);
        return {accessor, restPath};
    }

    Stat stat(const Path & path) override
    {
        auto res = fetch(path);
        return res.first->stat(res.second);
    }

    StringSet readDirectory(const Path & path) override
    {
        auto res = fetch(path);
        return res.first->readDirectory(res.second);
    }

    std::string readFile(const Path & path) override
    {
        auto res = fetch(path);
        return res.first->readFile(res.second);
    }

    std::string readLink(const Path & path) override
    {
        auto res = fetch(path);
        return res.first->readLink(res.second);
    }
};

ref<FSAccessor> BinaryCacheStore::getFSAccessor()
{
    return make_ref<BinaryCacheStoreAccessor>(ref<BinaryCacheStore>(
            std::dynamic_pointer_cast<BinaryCacheStore>(shared_from_this())));
}

Path BinaryCacheStore::importPath(Source & source, std::shared_ptr<FSAccessor> accessor)
{
    /* FIXME: some cut&paste of LocalStore::importPath(). */

    /* Extract the NAR from the source. */
    TeeSource tee(source);
    NopSink sink;
    parseDump(sink, tee);

    uint32_t magic = readInt(source);
    if (magic != exportMagic)
        throw Error("Nix archive cannot be imported; wrong format");

    ValidPathInfo info;
    info.path = readStorePath(source);

    info.references = readStorePaths<PathSet>(source);

    readString(source); // deriver, don't care

    bool haveSignature = readInt(source) == 1;
    assert(!haveSignature);

    addToCache(info, tee.data);

    auto accessor_ = std::dynamic_pointer_cast<BinaryCacheStoreAccessor>(accessor);
    if (accessor_)
        accessor_->nars.emplace(info.path, makeNarAccessor(tee.data));

    return info.path;
}

}
<commit_msg>Better error message<commit_after>#include "archive.hh"
#include "binary-cache-store.hh"
#include "compression.hh"
#include "derivations.hh"
#include "fs-accessor.hh"
#include "globals.hh"
#include "nar-info.hh"
#include "sync.hh"
#include "worker-protocol.hh"
#include "nar-accessor.hh"
#include "nar-info-disk-cache.hh"

#include <chrono>

namespace nix {

BinaryCacheStore::BinaryCacheStore(std::shared_ptr<Store> localStore,
    const StoreParams & params)
    : localStore(localStore)
    , compression(get(params, "compression", "xz"))
{
    auto secretKeyFile = get(params, "secret-key", "");
    if (secretKeyFile != "")
        secretKey = std::unique_ptr<SecretKey>(new SecretKey(readFile(secretKeyFile)));

    StringSink sink;
    sink << narVersionMagic1;
    narMagic = *sink.s;
}

void BinaryCacheStore::init()
{
    std::string cacheInfoFile = "nix-cache-info";
    if (!fileExists(cacheInfoFile))
        upsertFile(cacheInfoFile, "StoreDir: " + settings.nixStore + "\n");
}

void BinaryCacheStore::notImpl()
{
    throw Error("operation not implemented for binary cache stores");
}

Path BinaryCacheStore::narInfoFileFor(const Path & storePath)
{
    assertStorePath(storePath);
    return storePathToHash(storePath) + ".narinfo";
}

void BinaryCacheStore::addToCache(const ValidPathInfo & info, ref<std::string> nar)
{
    /* Verify that all references are valid. This may do some .narinfo
       reads, but typically they'll already be cached. */
    for (auto & ref : info.references)
        try {
            if (ref != info.path)
                queryPathInfo(ref);
        } catch (InvalidPath &) {
            throw Error(format("cannot add ‘%s’ to the binary cache because the reference ‘%s’ is not valid")
                % info.path % ref);
        }

    auto narInfoFile = narInfoFileFor(info.path);
    if (fileExists(narInfoFile)) return;

    assert(nar->compare(0, narMagic.size(), narMagic) == 0);

    auto narInfo = make_ref<NarInfo>(info);

    narInfo->narSize = nar->size();
    narInfo->narHash = hashString(htSHA256, *nar);

    if (info.narHash && info.narHash != narInfo->narHash)
        throw Error(format("refusing to copy corrupted path ‘%1%’ to binary cache") % info.path);

    /* Compress the NAR. */
    narInfo->compression = compression;
    auto now1 = std::chrono::steady_clock::now();
    auto narCompressed = compress(compression, nar);
    auto now2 = std::chrono::steady_clock::now();
    narInfo->fileHash = hashString(htSHA256, *narCompressed);
    narInfo->fileSize = narCompressed->size();

    auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(now2 - now1).count();
    printMsg(lvlTalkative, format("copying path ‘%1%’ (%2% bytes, compressed %3$.1f%% in %4% ms) to binary cache")
        % narInfo->path % narInfo->narSize
        % ((1.0 - (double) narCompressed->size() / nar->size()) * 100.0)
        % duration);

    /* Atomically write the NAR file. */
    narInfo->url = "nar/" + printHash32(narInfo->fileHash) + ".nar.xz";
    if (!fileExists(narInfo->url)) {
        stats.narWrite++;
        upsertFile(narInfo->url, *narCompressed);
    } else
        stats.narWriteAverted++;

    stats.narWriteBytes += nar->size();
    stats.narWriteCompressedBytes += narCompressed->size();
    stats.narWriteCompressionTimeMs += duration;

    /* Atomically write the NAR info file.*/
    if (secretKey) narInfo->sign(*secretKey);

    upsertFile(narInfoFile, narInfo->to_string());

    auto hashPart = storePathToHash(narInfo->path);

    {
        auto state_(state.lock());
        state_->pathInfoCache.upsert(hashPart, std::shared_ptr<NarInfo>(narInfo));
    }

    if (diskCache)
        diskCache->upsertNarInfo(getUri(), hashPart, std::shared_ptr<NarInfo>(narInfo));

    stats.narInfoWrite++;
}

bool BinaryCacheStore::isValidPathUncached(const Path & storePath)
{
    // FIXME: this only checks whether a .narinfo with a matching hash
    // part exists. So ‘f4kb...-foo’ matches ‘f4kb...-bar’, even
    // though they shouldn't. Not easily fixed.
    return fileExists(narInfoFileFor(storePath));
}

void BinaryCacheStore::narFromPath(const Path & storePath, Sink & sink)
{
    auto info = queryPathInfo(storePath).cast<const NarInfo>();

    auto nar = getFile(info->url);

    if (!nar) throw Error(format("file ‘%s’ missing from binary cache") % info->url);

    stats.narRead++;
    stats.narReadCompressedBytes += nar->size();

    /* Decompress the NAR. FIXME: would be nice to have the remote
       side do this. */
    try {
        nar = decompress(info->compression, ref<std::string>(nar));
    } catch (UnknownCompressionMethod &) {
        throw Error(format("binary cache path ‘%s’ uses unknown compression method ‘%s’")
            % storePath % info->compression);
    }

    stats.narReadBytes += nar->size();

    printMsg(lvlTalkative, format("exporting path ‘%1%’ (%2% bytes)") % storePath % nar->size());

    assert(nar->size() % 8 == 0);

    sink((unsigned char *) nar->c_str(), nar->size());
}

void BinaryCacheStore::exportPath(const Path & storePath, bool sign, Sink & sink)
{
    assert(!sign);

    auto res = queryPathInfo(storePath);

    narFromPath(storePath, sink);

    // FIXME: check integrity of NAR.

    sink << exportMagic << storePath << res->references << res->deriver << 0;
}

Paths BinaryCacheStore::importPaths(bool requireSignature, Source & source,
    std::shared_ptr<FSAccessor> accessor)
{
    assert(!requireSignature);
    Paths res;
    while (true) {
        unsigned long long n = readLongLong(source);
        if (n == 0) break;
        if (n != 1) throw Error("input doesn't look like something created by ‘nix-store --export’");
        res.push_back(importPath(source, accessor));
    }
    return res;
}

struct TeeSource : Source
{
    Source & readSource;
    ref<std::string> data;
    TeeSource(Source & readSource)
        : readSource(readSource)
        , data(make_ref<std::string>())
    {
    }
    size_t read(unsigned char * data, size_t len)
    {
        size_t n = readSource.read(data, len);
        this->data->append((char *) data, n);
        return n;
    }
};

struct NopSink : ParseSink
{
};

std::shared_ptr<ValidPathInfo> BinaryCacheStore::queryPathInfoUncached(const Path & storePath)
{
    auto narInfoFile = narInfoFileFor(storePath);
    auto data = getFile(narInfoFile);
    if (!data) return 0;

    auto narInfo = make_ref<NarInfo>(*data, narInfoFile);

    stats.narInfoRead++;

    return std::shared_ptr<NarInfo>(narInfo);
}

void BinaryCacheStore::querySubstitutablePathInfos(const PathSet & paths,
    SubstitutablePathInfos & infos)
{
    PathSet left;

    if (!localStore) return;

    for (auto & storePath : paths) {
        try {
            auto info = localStore->queryPathInfo(storePath);
            SubstitutablePathInfo sub;
            sub.references = info->references;
            sub.downloadSize = 0;
            sub.narSize = info->narSize;
            infos.emplace(storePath, sub);
        } catch (InvalidPath &) {
            left.insert(storePath);
        }
    }

    if (settings.useSubstitutes)
        localStore->querySubstitutablePathInfos(left, infos);
}

Path BinaryCacheStore::addToStore(const string & name, const Path & srcPath,
    bool recursive, HashType hashAlgo, PathFilter & filter, bool repair)
{
    // FIXME: some cut&paste from LocalStore::addToStore().

    /* Read the whole path into memory. This is not a very scalable
       method for very large paths, but `copyPath' is mainly used for
       small files. */
    StringSink sink;
    Hash h;
    if (recursive) {
        dumpPath(srcPath, sink, filter);
        h = hashString(hashAlgo, *sink.s);
    } else {
        auto s = readFile(srcPath);
        dumpString(s, sink);
        h = hashString(hashAlgo, s);
    }

    ValidPathInfo info;
    info.path = makeFixedOutputPath(recursive, hashAlgo, h, name);

    if (repair || !isValidPath(info.path))
        addToCache(info, sink.s);

    return info.path;
}

Path BinaryCacheStore::addTextToStore(const string & name, const string & s,
    const PathSet & references, bool repair)
{
    ValidPathInfo info;
    info.path = computeStorePathForText(name, s, references);
    info.references = references;

    if (repair || !isValidPath(info.path)) {
        StringSink sink;
        dumpString(s, sink);
        addToCache(info, sink.s);
    }

    return info.path;
}

void BinaryCacheStore::buildPaths(const PathSet & paths, BuildMode buildMode)
{
    for (auto & storePath : paths) {
        assert(!isDerivation(storePath));

        if (isValidPath(storePath)) continue;

        if (!localStore)
            throw Error(format("don't know how to realise path ‘%1%’ in a binary cache") % storePath);

        localStore->addTempRoot(storePath);

        if (!localStore->isValidPath(storePath))
            localStore->ensurePath(storePath);

        auto info = localStore->queryPathInfo(storePath);

        for (auto & ref : info->references)
            if (ref != storePath)
                ensurePath(ref);

        StringSink sink;
        dumpPath(storePath, sink);

        addToCache(*info, sink.s);
    }
}

void BinaryCacheStore::ensurePath(const Path & path)
{
    buildPaths({path});
}

/* Given requests for a path /nix/store/<x>/<y>, this accessor will
   first download the NAR for /nix/store/<x> from the binary cache,
   build a NAR accessor for that NAR, and use that to access <y>. */
struct BinaryCacheStoreAccessor : public FSAccessor
{
    ref<BinaryCacheStore> store;

    std::map<Path, ref<FSAccessor>> nars;

    BinaryCacheStoreAccessor(ref<BinaryCacheStore> store)
        : store(store)
    {
    }

    std::pair<ref<FSAccessor>, Path> fetch(const Path & path_)
    {
        auto path = canonPath(path_);

        auto storePath = toStorePath(path);
        std::string restPath = std::string(path, storePath.size());

        if (!store->isValidPath(storePath))
            throw Error(format("path ‘%1%’ is not a valid store path") % storePath);

        auto i = nars.find(storePath);
        if (i != nars.end()) return {i->second, restPath};

        StringSink sink;
        store->exportPath(storePath, false, sink);

        auto accessor = makeNarAccessor(sink.s);
        nars.emplace(storePath, accessor);
        return {accessor, restPath};
    }

    Stat stat(const Path & path) override
    {
        auto res = fetch(path);
        return res.first->stat(res.second);
    }

    StringSet readDirectory(const Path & path) override
    {
        auto res = fetch(path);
        return res.first->readDirectory(res.second);
    }

    std::string readFile(const Path & path) override
    {
        auto res = fetch(path);
        return res.first->readFile(res.second);
    }

    std::string readLink(const Path & path) override
    {
        auto res = fetch(path);
        return res.first->readLink(res.second);
    }
};

ref<FSAccessor> BinaryCacheStore::getFSAccessor()
{
    return make_ref<BinaryCacheStoreAccessor>(ref<BinaryCacheStore>(
            std::dynamic_pointer_cast<BinaryCacheStore>(shared_from_this())));
}

Path BinaryCacheStore::importPath(Source & source, std::shared_ptr<FSAccessor> accessor)
{
    /* FIXME: some cut&paste of LocalStore::importPath(). */

    /* Extract the NAR from the source. */
    TeeSource tee(source);
    NopSink sink;
    parseDump(sink, tee);

    uint32_t magic = readInt(source);
    if (magic != exportMagic)
        throw Error("Nix archive cannot be imported; wrong format");

    ValidPathInfo info;
    info.path = readStorePath(source);

    info.references = readStorePaths<PathSet>(source);

    readString(source); // deriver, don't care

    bool haveSignature = readInt(source) == 1;
    assert(!haveSignature);

    addToCache(info, tee.data);

    auto accessor_ = std::dynamic_pointer_cast<BinaryCacheStoreAccessor>(accessor);
    if (accessor_)
        accessor_->nars.emplace(info.path, makeNarAccessor(tee.data));

    return info.path;
}

}
<|endoftext|>


<commit_before><commit_msg>randi added to rand, namespaced a now lowecase<commit_after><|endoftext|>


<commit_before><commit_msg>MISC: Minor change to previous commit.<commit_after><|endoftext|>


<commit_before>#include "global.h"
#include "RoleFactory.h"
#include "config/constraints.h"

#include <boost/filesystem.hpp>

#include <cstring>
#include <string>  // std::string
#include <vector>  // std::vector
#include <fstream> // std::ifstream
using namespace std;

static LogCategory mainlog("main", "Main");

static ConfigGroup general_config("general");
static ConfigVariable<vector<string> > dc_files("dc_files", vector<string>(), general_config);
static ConfigVariable<string> eventlogger_addr("eventlogger", "", general_config);
static ValidAddressConstraint valid_eventlogger_addr(eventlogger_addr);

static ConfigList uberdogs_config("uberdogs");
static ConfigVariable<doid_t> uberdog_id("id", INVALID_DO_ID, uberdogs_config);
static ConfigVariable<string> uberdog_class("class", "", uberdogs_config);
static ConfigVariable<bool> uberdog_anon("anonymous", false, uberdogs_config);
static InvalidDoidConstraint id_not_invalid(uberdog_id);
static ReservedDoidConstraint id_not_reserved(uberdog_id);

static void printHelp(ostream &s);

int main(int argc, char *argv[])
{
	string cfg_file;

	int config_arg_index = -1;
	cfg_file = "astrond.yml";
	LogSeverity sev = g_logger->get_min_severity();
	for(int i = 1; i < argc; i++)
	{
		if((strcmp(argv[i], "--log") == 0 || strcmp(argv[i], "-L") == 0) && i + 1 < argc)
		{
			delete g_logger;
			g_logger = new Logger(argv[++i], sev);
		}
		else if((strcmp(argv[i], "--loglevel") == 0 || strcmp(argv[i], "-l") == 0) && i + 1 < argc)
		{
			string llstr(argv[++i]);
			if(llstr == "packet")
			{
				sev = LSEVERITY_PACKET;
				g_logger->set_min_severity(sev);
			}
			else if(llstr == "trace")
			{
				sev = LSEVERITY_TRACE;
				g_logger->set_min_severity(sev);
			}
			else if(llstr == "debug")
			{
				sev = LSEVERITY_DEBUG;
				g_logger->set_min_severity(sev);
			}
			else if(llstr == "info")
			{
				sev = LSEVERITY_INFO;
				g_logger->set_min_severity(sev);
			}
			else if(llstr == "warning")
			{
				sev = LSEVERITY_INFO;
				g_logger->set_min_severity(sev);
			}
			else if(llstr == "security")
			{
				sev = LSEVERITY_SECURITY;
				g_logger->set_min_severity(sev);
			}
			else if(llstr != "error" && llstr != "fatal")
			{
				cerr << "Unknown log-level \"" << llstr << "\"." << endl;
				printHelp(cerr);
				exit(1);
			}
		}
		else if(strcmp(argv[i], "--help") == 0 || strcmp(argv[i], "-h") == 0)
		{
			printHelp(cout);
			exit(0);
		}
		else if(argv[i][0] == '-')
		{
			cerr << "Unrecognized option \"" << string(argv[i]) << "\".\n";
			printHelp(cerr);
			exit(1);
		}
		else
		{
			if(config_arg_index != -1)
			{
				cerr << "Recieved additional positional argument \""
				     << string(argv[i]) << "\" but can only accept one."
				     << "\n  First positional: \""
				     << string(argv[config_arg_index]) << "\".\n";
			}
			else
			{
				config_arg_index = i;
			}
		}
	}

	if(config_arg_index != -1)
	{
		string filename = "";
		cfg_file = argv[config_arg_index];

		try
		{
			// seperate path
			boost::filesystem::path p(cfg_file);
			boost::filesystem::path dir = p.parent_path();
			filename = p.filename().string();
			string dir_str = dir.string();

			// change directory
			if(!dir_str.empty())
			{
				boost::filesystem::current_path(dir_str);
			}
		}
		catch(const exception &e)
		{
			mainlog.fatal() << "Could not change working directory to config directory.\n";
			exit(1);
		}

		cfg_file = filename;
	}

	mainlog.info() << "Loading configuration file...\n";

	ifstream file(cfg_file.c_str());
	if(!file.is_open())
	{
		mainlog.fatal() << "Failed to open configuration file \"" << cfg_file << "\".\n";
		return 1;
	}

	if(!g_config->load(file))
	{
		mainlog.fatal() << "Errors parsing YAML configuration file \"" << cfg_file << "\"!\n";
		return 1;
	}
	file.close();

	if(!ConfigGroup::root().validate(g_config->copy_node()))
	{
		mainlog.fatal() << "Configuration file contains errors.\n";
		return 1;
	}

	vector<string> dc_file_names = dc_files.get_val();
	for(auto it = dc_file_names.begin(); it != dc_file_names.end(); ++it)
	{
		if(!g_dcf->read(*it))
		{
			mainlog.fatal() << "Could not read DC file " << *it << endl;
			return 1;
		}
	}

	// Initialize configured MessageDirector
	MessageDirector::singleton.init_network();
	g_eventsender.init(eventlogger_addr.get_val());

	// Load uberdog metadata from configuration
	ConfigNode udnodes = g_config->copy_node()["uberdogs"];
	if(!udnodes.IsNull())
	{
		for(auto it = udnodes.begin(); it != udnodes.end(); ++it)
		{
			ConfigNode udnode = *it;
			Uberdog ud;
			ud.dcc = g_dcf->get_class_by_name(udnode["class"].as<string>());
			if(!ud.dcc)
			{
				mainlog.fatal() << "DCClass " << udnode["class"].as<string>()
				                << " does not exist!" << endl;
				exit(1);
			}
			ud.anonymous = udnode["anonymous"].as<bool>();
			g_uberdogs[udnode["id"].as<doid_t>()] = ud;
		}
	}

	// Initialize configured roles
	ConfigNode node = g_config->copy_node();
	node = node["roles"];
	for(auto it = node.begin(); it != node.end(); ++it)
	{
		RoleFactory::singleton().instantiate_role((*it)["type"].as<std::string>(), *it);
	}

	try
	{
		io_service.run();
	}
	catch(exception &e)
	{
		mainlog.fatal() << "Exception from the network io service: "
		                << e.what() << endl;
	}

	return 0;
}

// printHelp outputs the cli help-text to the given stream.
void printHelp(ostream &s)
{
	s << "Usage:    astrond [options]... [CONFIG_FILE]\n"
	     "\n"
	     "Astrond is a distributed server daemon.\n"
	     "By default Astron looks for a configuration file in the current\n"
	     "working directory as \"astrond.yml\".  A different config file path\n"
	     "can be specified as a positional argument.\n"
	     "\n"
	     "-h, --help      Print this help dialog.\n"
	     "-L, --log       Specify a file to write log messages to.\n"
	     "-l, --loglevel  Specify the minimum log level that should be logged;\n"
	     "                  Security, Error, and Fatal will always be logged;\n"
#ifdef ASTRON_DEBUG_MESSAGES
	     "                (available): packet, trace, debug, info, warning, security\n"
#else
	     "                (available): info, warning, security\n"
	     "                (unavailable): packet, trace, debug\n"
	     "                        [build with -DCMAKE_BUILD_TYPE=Debug]\n"
#endif
         "\n"
         "Example:\n"
         "    ./astrond /tmp/my_config_file.yaml\n"
         "\n";
	s.flush();
}
<commit_msg>Doc: Nitpick help text to be more cross-platform.<commit_after>#include "global.h"
#include "RoleFactory.h"
#include "config/constraints.h"

#include <boost/filesystem.hpp>

#include <cstring>
#include <string>  // std::string
#include <vector>  // std::vector
#include <fstream> // std::ifstream
using namespace std;

static LogCategory mainlog("main", "Main");

static ConfigGroup general_config("general");
static ConfigVariable<vector<string> > dc_files("dc_files", vector<string>(), general_config);
static ConfigVariable<string> eventlogger_addr("eventlogger", "", general_config);
static ValidAddressConstraint valid_eventlogger_addr(eventlogger_addr);

static ConfigList uberdogs_config("uberdogs");
static ConfigVariable<doid_t> uberdog_id("id", INVALID_DO_ID, uberdogs_config);
static ConfigVariable<string> uberdog_class("class", "", uberdogs_config);
static ConfigVariable<bool> uberdog_anon("anonymous", false, uberdogs_config);
static InvalidDoidConstraint id_not_invalid(uberdog_id);
static ReservedDoidConstraint id_not_reserved(uberdog_id);

static void printHelp(ostream &s);

int main(int argc, char *argv[])
{
	string cfg_file;

	int config_arg_index = -1;
	cfg_file = "astrond.yml";
	LogSeverity sev = g_logger->get_min_severity();
	for(int i = 1; i < argc; i++)
	{
		if((strcmp(argv[i], "--log") == 0 || strcmp(argv[i], "-L") == 0) && i + 1 < argc)
		{
			delete g_logger;
			g_logger = new Logger(argv[++i], sev);
		}
		else if((strcmp(argv[i], "--loglevel") == 0 || strcmp(argv[i], "-l") == 0) && i + 1 < argc)
		{
			string llstr(argv[++i]);
			if(llstr == "packet")
			{
				sev = LSEVERITY_PACKET;
				g_logger->set_min_severity(sev);
			}
			else if(llstr == "trace")
			{
				sev = LSEVERITY_TRACE;
				g_logger->set_min_severity(sev);
			}
			else if(llstr == "debug")
			{
				sev = LSEVERITY_DEBUG;
				g_logger->set_min_severity(sev);
			}
			else if(llstr == "info")
			{
				sev = LSEVERITY_INFO;
				g_logger->set_min_severity(sev);
			}
			else if(llstr == "warning")
			{
				sev = LSEVERITY_INFO;
				g_logger->set_min_severity(sev);
			}
			else if(llstr == "security")
			{
				sev = LSEVERITY_SECURITY;
				g_logger->set_min_severity(sev);
			}
			else if(llstr != "error" && llstr != "fatal")
			{
				cerr << "Unknown log-level \"" << llstr << "\"." << endl;
				printHelp(cerr);
				exit(1);
			}
		}
		else if(strcmp(argv[i], "--help") == 0 || strcmp(argv[i], "-h") == 0)
		{
			printHelp(cout);
			exit(0);
		}
		else if(argv[i][0] == '-')
		{
			cerr << "Unrecognized option \"" << string(argv[i]) << "\".\n";
			printHelp(cerr);
			exit(1);
		}
		else
		{
			if(config_arg_index != -1)
			{
				cerr << "Recieved additional positional argument \""
				     << string(argv[i]) << "\" but can only accept one."
				     << "\n  First positional: \""
				     << string(argv[config_arg_index]) << "\".\n";
			}
			else
			{
				config_arg_index = i;
			}
		}
	}

	if(config_arg_index != -1)
	{
		string filename = "";
		cfg_file = argv[config_arg_index];

		try
		{
			// seperate path
			boost::filesystem::path p(cfg_file);
			boost::filesystem::path dir = p.parent_path();
			filename = p.filename().string();
			string dir_str = dir.string();

			// change directory
			if(!dir_str.empty())
			{
				boost::filesystem::current_path(dir_str);
			}
		}
		catch(const exception &e)
		{
			mainlog.fatal() << "Could not change working directory to config directory.\n";
			exit(1);
		}

		cfg_file = filename;
	}

	mainlog.info() << "Loading configuration file...\n";

	ifstream file(cfg_file.c_str());
	if(!file.is_open())
	{
		mainlog.fatal() << "Failed to open configuration file \"" << cfg_file << "\".\n";
		return 1;
	}

	if(!g_config->load(file))
	{
		mainlog.fatal() << "Errors parsing YAML configuration file \"" << cfg_file << "\"!\n";
		return 1;
	}
	file.close();

	if(!ConfigGroup::root().validate(g_config->copy_node()))
	{
		mainlog.fatal() << "Configuration file contains errors.\n";
		return 1;
	}

	vector<string> dc_file_names = dc_files.get_val();
	for(auto it = dc_file_names.begin(); it != dc_file_names.end(); ++it)
	{
		if(!g_dcf->read(*it))
		{
			mainlog.fatal() << "Could not read DC file " << *it << endl;
			return 1;
		}
	}

	// Initialize configured MessageDirector
	MessageDirector::singleton.init_network();
	g_eventsender.init(eventlogger_addr.get_val());

	// Load uberdog metadata from configuration
	ConfigNode udnodes = g_config->copy_node()["uberdogs"];
	if(!udnodes.IsNull())
	{
		for(auto it = udnodes.begin(); it != udnodes.end(); ++it)
		{
			ConfigNode udnode = *it;
			Uberdog ud;
			ud.dcc = g_dcf->get_class_by_name(udnode["class"].as<string>());
			if(!ud.dcc)
			{
				mainlog.fatal() << "DCClass " << udnode["class"].as<string>()
				                << " does not exist!" << endl;
				exit(1);
			}
			ud.anonymous = udnode["anonymous"].as<bool>();
			g_uberdogs[udnode["id"].as<doid_t>()] = ud;
		}
	}

	// Initialize configured roles
	ConfigNode node = g_config->copy_node();
	node = node["roles"];
	for(auto it = node.begin(); it != node.end(); ++it)
	{
		RoleFactory::singleton().instantiate_role((*it)["type"].as<std::string>(), *it);
	}

	try
	{
		io_service.run();
	}
	catch(exception &e)
	{
		mainlog.fatal() << "Exception from the network io service: "
		                << e.what() << endl;
	}

	return 0;
}

// printHelp outputs the cli help-text to the given stream.
void printHelp(ostream &s)
{
	s << "Usage:    astrond [options]... [CONFIG_FILE]\n"
	     "\n"
	     "Astrond is a distributed server daemon.\n"
	     "By default Astron looks for a configuration file in the current\n"
	     "working directory as \"astrond.yml\".  A different config file path\n"
	     "can be specified as a positional argument.\n"
	     "\n"
	     "-h, --help      Print this help dialog.\n"
	     "-L, --log       Specify a file to write log messages to.\n"
	     "-l, --loglevel  Specify the minimum log level that should be logged;\n"
	     "                  Security, Error, and Fatal will always be logged;\n"
#ifdef ASTRON_DEBUG_MESSAGES
	     "                (available): packet, trace, debug, info, warning, security\n"
#else
	     "                (available): info, warning, security\n"
	     "                (unavailable): packet, trace, debug\n"
	     "                        [build with -DCMAKE_BUILD_TYPE=Debug]\n"
#endif
         "\n"
         "Example:\n"
         "    astrond /tmp/my_config_file.yaml\n"
         "\n";
	s.flush();
}
<|endoftext|>