Skip to content

Commit

Permalink
MC: support different sized constants in constant pools
Browse files Browse the repository at this point in the history
    
On AArch64 the pseudo instruction ldr <reg>, =... supports both
32-bit and 64-bit constants. Add support for 64 bit constants for
the pools to support the pseudo instruction fully.

Changes the AArch64 ldr-pseudo tests to use 32-bit registers and
adds tests with 64-bit registers.

Patch by Janne Grunau!

Differential Revision: http://reviews.llvm.org/D4279

llvm-svn: 213387
  • Loading branch information
dmpots committed Jul 18, 2014
1 parent a2347ba commit ae5ba76
Show file tree
Hide file tree
Showing 10 changed files with 200 additions and 67 deletions.
16 changes: 13 additions & 3 deletions llvm/include/llvm/MC/ConstantPools.h
Expand Up @@ -22,10 +22,17 @@ class MCExpr;
class MCSection;
class MCStreamer;
class MCSymbol;

struct ConstantPoolEntry {
MCSymbol *Label;
const MCExpr *Value;
unsigned Size;
};

// A class to keep track of assembler-generated constant pools that are use to
// implement the ldr-pseudo.
class ConstantPool {
typedef SmallVector<std::pair<MCSymbol *, const MCExpr *>, 4> EntryVecTy;
typedef SmallVector<ConstantPoolEntry, 4> EntryVecTy;
EntryVecTy Entries;

public:
Expand All @@ -34,9 +41,11 @@ class ConstantPool {

// Add a new entry to the constant pool in the next slot.
// \param Value is the new entry to put in the constant pool.
// \param Size is the size in bytes of the entry
//
// \returns a MCExpr that references the newly inserted value
const MCExpr *addEntry(const MCExpr *Value, MCContext &Context);
const MCExpr *addEntry(const MCExpr *Value, MCContext &Context,
unsigned Size);

// Emit the contents of the constant pool using the provided streamer.
void emitEntries(MCStreamer &Streamer);
Expand Down Expand Up @@ -69,7 +78,8 @@ class AssemblerConstantPools {

void emitAll(MCStreamer &Streamer);
void emitForCurrentSection(MCStreamer &Streamer);
const MCExpr *addEntry(MCStreamer &Streamer, const MCExpr *Expr);
const MCExpr *addEntry(MCStreamer &Streamer, const MCExpr *Expr,
unsigned Size);

private:
ConstantPool *getConstantPool(const MCSection *Section);
Expand Down
2 changes: 1 addition & 1 deletion llvm/include/llvm/MC/MCStreamer.h
Expand Up @@ -97,7 +97,7 @@ class AArch64TargetStreamer : public MCTargetStreamer {
/// Callback used to implement the ldr= pseudo.
/// Add a new entry to the constant pool for the current section and return an
/// MCExpr that can be used to refer to the constant pool location.
const MCExpr *addConstantPoolEntry(const MCExpr *);
const MCExpr *addConstantPoolEntry(const MCExpr *, unsigned Size);

/// Callback used to implemnt the .ltorg directive.
/// Emit contents of constant pool for the current section.
Expand Down
17 changes: 10 additions & 7 deletions llvm/lib/MC/ConstantPools.cpp
Expand Up @@ -24,21 +24,22 @@ using namespace llvm;
void ConstantPool::emitEntries(MCStreamer &Streamer) {
if (Entries.empty())
return;
Streamer.EmitCodeAlignment(4); // align to 4-byte address
Streamer.EmitDataRegion(MCDR_DataRegion);
for (EntryVecTy::const_iterator I = Entries.begin(), E = Entries.end();
I != E; ++I) {
Streamer.EmitLabel(I->first);
Streamer.EmitValue(I->second, 4);
Streamer.EmitCodeAlignment(I->Size); // align naturally
Streamer.EmitLabel(I->Label);
Streamer.EmitValue(I->Value, I->Size);
}
Streamer.EmitDataRegion(MCDR_DataRegionEnd);
Entries.clear();
}

const MCExpr *ConstantPool::addEntry(const MCExpr *Value, MCContext &Context) {
const MCExpr *ConstantPool::addEntry(const MCExpr *Value, MCContext &Context,
unsigned Size) {
MCSymbol *CPEntryLabel = Context.CreateTempSymbol();

Entries.push_back(std::make_pair(CPEntryLabel, Value));
Entries.push_back( { CPEntryLabel, Value, Size } );
return MCSymbolRefExpr::Create(CPEntryLabel, Context);
}

Expand Down Expand Up @@ -89,7 +90,9 @@ void AssemblerConstantPools::emitForCurrentSection(MCStreamer &Streamer) {
}

const MCExpr *AssemblerConstantPools::addEntry(MCStreamer &Streamer,
const MCExpr *Expr) {
const MCExpr *Expr,
unsigned Size) {
const MCSection *Section = Streamer.getCurrentSection().first;
return getOrCreateConstantPool(Section).addEntry(Expr, Streamer.getContext());
return getOrCreateConstantPool(Section).addEntry(Expr, Streamer.getContext(),
Size);
}
21 changes: 16 additions & 5 deletions llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp
Expand Up @@ -25,6 +25,7 @@
#include "llvm/Support/TargetRegistry.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/ADT/APInt.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/STLExtras.h"
Expand Down Expand Up @@ -3067,13 +3068,18 @@ bool AArch64AsmParser::parseOperand(OperandVector &Operands, bool isCondCode,
if (getParser().parseExpression(SubExprVal))
return true;

if (Operands.size() < 2 ||
!static_cast<AArch64Operand &>(*Operands[1]).isReg())
return true;

bool IsXReg =
AArch64MCRegisterClasses[AArch64::GPR64allRegClassID].contains(
Operands[1]->getReg());

MCContext& Ctx = getContext();
E = SMLoc::getFromPointer(Loc.getPointer() - 1);
// If the op is an imm and can be fit into a mov, then replace ldr with mov.
if (isa<MCConstantExpr>(SubExprVal) && Operands.size() >= 2 &&
static_cast<AArch64Operand &>(*Operands[1]).isReg()) {
bool IsXReg = AArch64MCRegisterClasses[AArch64::GPR64allRegClassID].contains(
Operands[1]->getReg());
if (isa<MCConstantExpr>(SubExprVal)) {
uint64_t Imm = (cast<MCConstantExpr>(SubExprVal))->getValue();
uint32_t ShiftAmt = 0, MaxShiftAmt = IsXReg ? 48 : 16;
while(Imm > 0xFFFF && countTrailingZeros(Imm) >= 16) {
Expand All @@ -3089,9 +3095,14 @@ bool AArch64AsmParser::parseOperand(OperandVector &Operands, bool isCondCode,
ShiftAmt, true, S, E, Ctx));
return false;
}
APInt Simm = APInt(64, Imm << ShiftAmt);
// check if the immediate is an unsigned or signed 32-bit int for W regs
if (!IsXReg && !(Simm.isIntN(32) || Simm.isSignedIntN(32)))
return Error(Loc, "Immediate too large for register");
}
// If it is a label or an imm that cannot fit in a movz, put it into CP.
const MCExpr *CPLoc = getTargetStreamer().addConstantPoolEntry(SubExprVal);
const MCExpr *CPLoc =
getTargetStreamer().addConstantPoolEntry(SubExprVal, IsXReg ? 8 : 4);
Operands.push_back(AArch64Operand::CreateImm(CPLoc, S, E, Ctx));
return false;
}
Expand Down
Expand Up @@ -28,8 +28,9 @@ AArch64TargetStreamer::~AArch64TargetStreamer() {}

// The constant pool handling is shared by all AArch64TargetStreamer
// implementations.
const MCExpr *AArch64TargetStreamer::addConstantPoolEntry(const MCExpr *Expr) {
return ConstantPools->addEntry(Streamer, Expr);
const MCExpr *AArch64TargetStreamer::addConstantPoolEntry(const MCExpr *Expr,
unsigned Size) {
return ConstantPools->addEntry(Streamer, Expr, Size);
}

void AArch64TargetStreamer::emitCurrentConstantPool() {
Expand Down
2 changes: 1 addition & 1 deletion llvm/lib/Target/ARM/MCTargetDesc/ARMTargetStreamer.cpp
Expand Up @@ -28,7 +28,7 @@ ARMTargetStreamer::~ARMTargetStreamer() {}
// The constant pool handling is shared by all ARMTargetStreamer
// implementations.
const MCExpr *ARMTargetStreamer::addConstantPoolEntry(const MCExpr *Expr) {
return ConstantPools->addEntry(Streamer, Expr);
return ConstantPools->addEntry(Streamer, Expr, 4);
}

void ARMTargetStreamer::emitCurrentConstantPool() {
Expand Down
14 changes: 14 additions & 0 deletions llvm/test/MC/AArch64/ldr-pseudo-diagnostics.s
@@ -0,0 +1,14 @@
//RUN: not llvm-mc -triple=aarch64-linux-gnu - < %s 2>&1 | FileCheck --check-prefix=CHECK-ERROR %s

// simple test
.section a, "ax", @progbits
f1:
ldr w0, =0x100000001
// CHECK-ERROR: error: Immediate too large for register
// CHECK-ERROR: ldr w0, =0x100000001
// CHECK-ERROR: ^
f2:
ldr w0, =-0x80000001
// CHECK-ERROR: error: Immediate too large for register
// CHECK-ERROR: ldr w0, =-0x80000001
// CHECK-ERROR: ^

0 comments on commit ae5ba76

Please sign in to comment.