opnsense-src/contrib/llvm/lib/MC/ConstantPools.cpp
Dimitry Andric 5423d0917e Pull in r302416 from upstream llvm trunk (by Martin Storsjö):
[ARM] Clear the constant pool cache on explicit .ltorg directives

  Multiple ldr pseudoinstructions with the same constant value will
  reuse the same constant pool entry. However, if the constant pool is
  explicitly flushed with a .ltorg directive, we should not try to
  reference constants in the previous pool any longer, since they may
  be out of range.

  This fixes assembling hand-written assembler source which repeatedly
  loads the same constant value, across a binary size larger than the
  pc-relative fixup range for ldr instructions (4096 bytes). Such
  assembler source already uses explicit .ltorg instructions to emit
  constant pools with regular intervals. However if we try to reuse
  constants emitted in earlier pools, they end up out of range.

  This makes the output of the testcase match what binutils gas does
  (prior to this patch, it would fail to assemble).

  Differential Revision: https://reviews.llvm.org/D32847

This should fix "out of range pc-relative fixup value" errors, when
compiling certain ARM inline assembly for www/webkit-gtk[23].

Reported by:	mmel
MFC after:	3 days
2017-05-22 16:16:48 +00:00

115 lines
3.7 KiB
C++

//===- ConstantPools.cpp - ConstantPool class --*- C++ -*---------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements the ConstantPool and AssemblerConstantPools classes.
//
//===----------------------------------------------------------------------===//
#include "llvm/ADT/MapVector.h"
#include "llvm/MC/ConstantPools.h"
#include "llvm/MC/MCContext.h"
#include "llvm/MC/MCExpr.h"
#include "llvm/MC/MCStreamer.h"
using namespace llvm;
//
// ConstantPool implementation
//
// Emit the contents of the constant pool using the provided streamer.
void ConstantPool::emitEntries(MCStreamer &Streamer) {
if (Entries.empty())
return;
Streamer.EmitDataRegion(MCDR_DataRegion);
for (const ConstantPoolEntry &Entry : Entries) {
Streamer.EmitCodeAlignment(Entry.Size); // align naturally
Streamer.EmitLabel(Entry.Label);
Streamer.EmitValue(Entry.Value, Entry.Size, Entry.Loc);
}
Streamer.EmitDataRegion(MCDR_DataRegionEnd);
Entries.clear();
}
const MCExpr *ConstantPool::addEntry(const MCExpr *Value, MCContext &Context,
unsigned Size, SMLoc Loc) {
const MCConstantExpr *C = dyn_cast<MCConstantExpr>(Value);
// Check if there is existing entry for the same constant. If so, reuse it.
auto Itr = C ? CachedEntries.find(C->getValue()) : CachedEntries.end();
if (Itr != CachedEntries.end())
return Itr->second;
MCSymbol *CPEntryLabel = Context.createTempSymbol();
Entries.push_back(ConstantPoolEntry(CPEntryLabel, Value, Size, Loc));
const auto SymRef = MCSymbolRefExpr::create(CPEntryLabel, Context);
if (C)
CachedEntries[C->getValue()] = SymRef;
return SymRef;
}
bool ConstantPool::empty() { return Entries.empty(); }
void ConstantPool::clearCache() {
CachedEntries.clear();
}
//
// AssemblerConstantPools implementation
//
ConstantPool *AssemblerConstantPools::getConstantPool(MCSection *Section) {
ConstantPoolMapTy::iterator CP = ConstantPools.find(Section);
if (CP == ConstantPools.end())
return nullptr;
return &CP->second;
}
ConstantPool &
AssemblerConstantPools::getOrCreateConstantPool(MCSection *Section) {
return ConstantPools[Section];
}
static void emitConstantPool(MCStreamer &Streamer, MCSection *Section,
ConstantPool &CP) {
if (!CP.empty()) {
Streamer.SwitchSection(Section);
CP.emitEntries(Streamer);
}
}
void AssemblerConstantPools::emitAll(MCStreamer &Streamer) {
// Dump contents of assembler constant pools.
for (auto &CPI : ConstantPools) {
MCSection *Section = CPI.first;
ConstantPool &CP = CPI.second;
emitConstantPool(Streamer, Section, CP);
}
}
void AssemblerConstantPools::emitForCurrentSection(MCStreamer &Streamer) {
MCSection *Section = Streamer.getCurrentSectionOnly();
if (ConstantPool *CP = getConstantPool(Section)) {
emitConstantPool(Streamer, Section, *CP);
}
}
void AssemblerConstantPools::clearCacheForCurrentSection(MCStreamer &Streamer) {
MCSection *Section = Streamer.getCurrentSectionOnly();
if (ConstantPool *CP = getConstantPool(Section)) {
CP->clearCache();
}
}
const MCExpr *AssemblerConstantPools::addEntry(MCStreamer &Streamer,
const MCExpr *Expr,
unsigned Size, SMLoc Loc) {
MCSection *Section = Streamer.getCurrentSectionOnly();
return getOrCreateConstantPool(Section).addEntry(Expr, Streamer.getContext(),
Size, Loc);
}