Resubmit commit r211533

"Fix PR20056: Implement pseudo LDR <reg>, =<literal/label> for AArch64"
Missed files are added in this commit.



git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@211605 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Weiming Zhao 2014-06-24 16:21:38 +00:00
parent fde22c17f5
commit c33b4883b3
7 changed files with 386 additions and 1 deletions

View File

@ -86,6 +86,27 @@ public:
virtual void finish();
};
class AArch64TargetStreamer : public MCTargetStreamer {
public:
AArch64TargetStreamer(MCStreamer &S);
~AArch64TargetStreamer();
void finish() override;
/// 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 *);
/// Callback used to implemnt the .ltorg directive.
/// Emit contents of constant pool for the current section.
void emitCurrentConstantPool();
private:
std::unique_ptr<AssemblerConstantPools> ConstantPools;
};
// FIXME: declared here because it is used from
// lib/CodeGen/AsmPrinter/ARMException.cpp.
class ARMTargetStreamer : public MCTargetStreamer {

View File

@ -43,6 +43,11 @@ private:
MCSubtargetInfo &STI;
MCAsmParser &Parser;
AArch64TargetStreamer &getTargetStreamer() {
MCTargetStreamer &TS = *getParser().getStreamer().getTargetStreamer();
return static_cast<AArch64TargetStreamer &>(TS);
}
MCAsmParser &getParser() const { return Parser; }
MCAsmLexer &getLexer() const { return Parser.getLexer(); }
@ -67,6 +72,7 @@ private:
bool parseDirectiveTLSDescCall(SMLoc L);
bool parseDirectiveLOH(StringRef LOH, SMLoc L);
bool parseDirectiveLtorg(SMLoc L);
bool validateInstruction(MCInst &Inst, SmallVectorImpl<SMLoc> &Loc);
bool MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
@ -105,6 +111,8 @@ public:
const MCTargetOptions &Options)
: MCTargetAsmParser(), STI(_STI), Parser(_Parser) {
MCAsmParserExtension::Initialize(_Parser);
if (Parser.getStreamer().getTargetStreamer() == nullptr)
new AArch64TargetStreamer(Parser.getStreamer());
// Initialize the set of available features.
setAvailableFeatures(ComputeAvailableFeatures(STI.getFeatureBits()));
@ -3004,6 +3012,43 @@ bool AArch64AsmParser::parseOperand(OperandVector &Operands, bool isCondCode,
Operands.push_back(AArch64Operand::CreateImm(ImmVal, S, E, getContext()));
return false;
}
case AsmToken::Equal: {
SMLoc Loc = Parser.getTok().getLoc();
if (Mnemonic != "ldr") // only parse for ldr pseudo (e.g. ldr r0, =val)
return Error(Loc, "unexpected token in operand");
Parser.Lex(); // Eat '='
const MCExpr *SubExprVal;
if (getParser().parseExpression(SubExprVal))
return true;
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());
uint64_t Imm = (cast<MCConstantExpr>(SubExprVal))->getValue();
uint32_t ShiftAmt = 0, MaxShiftAmt = IsXReg ? 48 : 16;
while(Imm > 0xFFFF && countTrailingZeros(Imm) >= 16) {
ShiftAmt += 16;
Imm >>= 16;
}
if (ShiftAmt <= MaxShiftAmt && Imm <= 0xFFFF) {
Operands[0] = AArch64Operand::CreateToken("movz", false, Loc, Ctx);
Operands.push_back(AArch64Operand::CreateImm(
MCConstantExpr::Create(Imm, Ctx), S, E, Ctx));
if (ShiftAmt)
Operands.push_back(AArch64Operand::CreateShiftExtend(AArch64_AM::LSL,
ShiftAmt, true, S, E, Ctx));
return false;
}
}
// If it is a label or an imm that cannot fit in a movz, put it into CP.
const MCExpr *CPLoc = getTargetStreamer().addConstantPoolEntry(SubExprVal);
Operands.push_back(AArch64Operand::CreateImm(CPLoc, S, E, Ctx));
return false;
}
}
}
@ -3810,7 +3855,8 @@ bool AArch64AsmParser::ParseDirective(AsmToken DirectiveID) {
return parseDirectiveWord(8, Loc);
if (IDVal == ".tlsdesccall")
return parseDirectiveTLSDescCall(Loc);
if (IDVal == ".ltorg" || IDVal == ".pool")
return parseDirectiveLtorg(Loc);
return parseDirectiveLOH(IDVal, Loc);
}
@ -3911,6 +3957,13 @@ bool AArch64AsmParser::parseDirectiveLOH(StringRef IDVal, SMLoc Loc) {
return false;
}
/// parseDirectiveLtorg
/// ::= .ltorg | .pool
bool AArch64AsmParser::parseDirectiveLtorg(SMLoc L) {
getTargetStreamer().emitCurrentConstantPool();
return false;
}
bool
AArch64AsmParser::classifySymbolRef(const MCExpr *Expr,
AArch64MCExpr::VariantKind &ELFRefKind,

View File

@ -0,0 +1,40 @@
//===- AArch64TargetStreamer.cpp - AArch64TargetStreamer 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 AArch64TargetStreamer class.
//
//===----------------------------------------------------------------------===//
#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;
//
// AArch64TargetStreamer Implemenation
//
AArch64TargetStreamer::AArch64TargetStreamer(MCStreamer &S)
: MCTargetStreamer(S), ConstantPools(new AssemblerConstantPools()) {}
AArch64TargetStreamer::~AArch64TargetStreamer() {}
// The constant pool handling is shared by all AArch64TargetStreamer
// implementations.
const MCExpr *AArch64TargetStreamer::addConstantPoolEntry(const MCExpr *Expr) {
return ConstantPools->addEntry(Streamer, Expr);
}
void AArch64TargetStreamer::emitCurrentConstantPool() {
ConstantPools->emitForCurrentSection(Streamer);
}
// finish() - write out any non-empty assembler constant pools.
void AArch64TargetStreamer::finish() { ConstantPools->emitAll(Streamer); }

View File

@ -7,6 +7,7 @@ add_llvm_library(LLVMAArch64Desc
AArch64MCExpr.cpp
AArch64MCTargetDesc.cpp
AArch64MachObjectWriter.cpp
AArch64TargetStreamer.cpp
)
add_dependencies(LLVMAArch64Desc AArch64CommonTableGen)

View File

@ -0,0 +1,26 @@
; We actually need to use -filetype=obj in this test because if we output
; assembly, the current code path will bypass the parser and just write the
; raw text out to the Streamer. We need to actually parse the inlineasm to
; demonstrate the bug. Going the asm->obj route does not show the issue.
; RUN: llc -mtriple=aarch64 < %s -filetype=obj | llvm-objdump -arch=aarch64 -d - | FileCheck %s
; CHECK-LABEL: foo:
; CHECK: a0 79 95 d2 movz x0, #0xabcd
; CHECK: c0 03 5f d6 ret
define i32 @foo() nounwind {
entry:
%0 = tail call i32 asm sideeffect "ldr $0,=0xabcd", "=r"() nounwind
ret i32 %0
}
; CHECK-LABEL: bar:
; CHECK: 40 00 00 58 ldr x0, #8
; CHECK: c0 03 5f d6 ret
; Make sure the constant pool entry comes after the return
; CHECK-LABEL: $d.1:
define i32 @bar() nounwind {
entry:
%0 = tail call i32 asm sideeffect "ldr $0,=0x10001", "=r"() nounwind
ret i32 %0
}

View File

@ -0,0 +1,13 @@
//RUN: not llvm-mc -arch aarch64 -filetype=obj %s -o %t1 2> %t2
//RUN: cat %t2 | FileCheck %s
//These tests look for errors that should be reported for invalid object layout
//with the ldr pseudo. They are tested separately from parse errors because they
//only trigger when the file has successfully parsed and the object file is about
//to be written out.
.text
foo:
ldr x0, =0x10111
.space 0xdeadb0
// CHECK: LVM ERROR: fixup value out of range

View File

@ -0,0 +1,231 @@
//RUN: llvm-mc -arch aarch64 %s | FileCheck %s
//
// Check that large constants are converted to ldr from constant pool
//
// simple test
.section a, "ax", @progbits
// CHECK-LABEL: f1:
f1:
ldr x0, =0x1234
// CHECK: movz x0, #0x1234
ldr w1, =0x4567
// CHECK: movz w1, #0x4567
ldr x0, =0x12340000
// CHECK: movz x0, #0x1234, lsl #16
ldr w1, =0x45670000
// CHECK: movz w1, #0x4567, lsl #16
ldr x0, =0xabc00000000
// CHECK: movz x0, #0xabc, lsl #32
ldr x0, =0xbeef000000000000
// CHECK: movz x0, #0xbeef, lsl #48
.section b,"ax",@progbits
// CHECK-LABEL: f3:
f3:
ldr x0, =0x10001
// CHECK: ldr x0, .Ltmp[[TMP0:[0-9]+]]
// loading multiple constants
.section c,"ax",@progbits
// CHECK-LABEL: f4:
f4:
ldr x0, =0x10002
// CHECK: ldr x0, .Ltmp[[TMP1:[0-9]+]]
adds x0, x0, #1
adds x0, x0, #1
adds x0, x0, #1
adds x0, x0, #1
ldr x0, =0x10003
// CHECK: ldr x0, .Ltmp[[TMP2:[0-9]+]]
adds x0, x0, #1
adds x0, x0, #1
// TODO: the same constants should have the same constant pool location
.section d,"ax",@progbits
// CHECK-LABEL: f5:
f5:
ldr x0, =0x10004
// CHECK: ldr x0, .Ltmp[[TMP3:[0-9]+]]
adds x0, x0, #1
adds x0, x0, #1
adds x0, x0, #1
adds x0, x0, #1
adds x0, x0, #1
adds x0, x0, #1
adds x0, x0, #1
ldr x0, =0x10004
// CHECK: ldr x0, .Ltmp[[TMP4:[0-9]+]]
adds x0, x0, #1
adds x0, x0, #1
adds x0, x0, #1
adds x0, x0, #1
adds x0, x0, #1
adds x0, x0, #1
// a section defined in multiple pieces should be merged and use a single constant pool
.section e,"ax",@progbits
// CHECK-LABEL: f6:
f6:
ldr x0, =0x10006
// CHECK: ldr x0, .Ltmp[[TMP5:[0-9]+]]
adds x0, x0, #1
adds x0, x0, #1
adds x0, x0, #1
.section f, "ax", @progbits
// CHECK-LABEL: f7:
f7:
adds x0, x0, #1
adds x0, x0, #1
adds x0, x0, #1
.section e, "ax", @progbits
// CHECK-LABEL: f8:
f8:
adds x0, x0, #1
ldr x0, =0x10007
// CHECK: ldr x0, .Ltmp[[TMP6:[0-9]+]]
adds x0, x0, #1
adds x0, x0, #1
//
// Check that symbols can be loaded using ldr pseudo
//
// load an undefined symbol
.section g,"ax",@progbits
// CHECK-LABEL: f9:
f9:
ldr x0, =foo
// CHECK: ldr x0, .Ltmp[[TMP7:[0-9]+]]
// load a symbol from another section
.section h,"ax",@progbits
// CHECK-LABEL: f10:
f10:
ldr x0, =f5
// CHECK: ldr x0, .Ltmp[[TMP8:[0-9]+]]
// load a symbol from the same section
.section i,"ax",@progbits
// CHECK-LABEL: f11:
f11:
ldr x0, =f12
// CHECK: ldr x0, .Ltmp[[TMP9:[0-9]+]]
ldr w0,=0x3C000
// CHECK: ldr w0, .Ltmp[[TMP10:[0-9]+]]
// CHECK-LABEL: f12:
f12:
adds x0, x0, #1
adds x0, x0, #1
.section j,"ax",@progbits
// mix of symbols and constants
// CHECK-LABEL: f13:
f13:
adds x0, x0, #1
adds x0, x0, #1
ldr x0, =0x101
// CHECK: movz x0, #0x101
adds x0, x0, #1
adds x0, x0, #1
ldr x0, =bar
// CHECK: ldr x0, .Ltmp[[TMP11:[0-9]+]]
adds x0, x0, #1
adds x0, x0, #1
//
// Check for correct usage in other contexts
//
// usage in macro
.macro useit_in_a_macro
ldr x0, =0x10008
ldr x0, =baz
.endm
.section k,"ax",@progbits
// CHECK-LABEL: f14:
f14:
useit_in_a_macro
// CHECK: ldr x0, .Ltmp[[TMP12:[0-9]+]]
// CHECK: ldr x0, .Ltmp[[TMP13:[0-9]+]]
// usage with expressions
.section l, "ax", @progbits
// CHECK-LABEL: f15:
f15:
ldr x0, =0x10001+8
// CHECK: ldr x0, .Ltmp[[TMP14:[0-9]+]]
adds x0, x0, #1
ldr x0, =bar+4
// CHECK: ldr x0, .Ltmp[[TMP15:[0-9]+]]
adds x0, x0, #1
//
// Constant Pools
//
// CHECK: .section b,"ax",@progbits
// CHECK: .align 2
// CHECK: .Ltmp[[TMP0]]
// CHECK: .word 65537
// CHECK: .section c,"ax",@progbits
// CHECK: .align 2
// CHECK: .Ltmp[[TMP1]]
// CHECK: .word 65538
// CHECK: .Ltmp[[TMP2]]
// CHECK: .word 65539
// CHECK: .section d,"ax",@progbits
// CHECK: .align 2
// CHECK: .Ltmp[[TMP3]]
// CHECK: .word 65540
// CHECK: .Ltmp[[TMP4]]
// CHECK: .word 65540
// CHECK: .section e,"ax",@progbits
// CHECK: .align 2
// CHECK: .Ltmp[[TMP5]]
// CHECK: .word 65542
// CHECK: .Ltmp[[TMP6]]
// CHECK: .word 65543
// Should not switch to section because it has no constant pool
// CHECK-NOT: .section f,"ax",@progbits
// CHECK: .section g,"ax",@progbits
// CHECK: .align 2
// CHECK: .Ltmp[[TMP7]]
// CHECK: .word foo
// CHECK: .section h,"ax",@progbits
// CHECK: .align 2
// CHECK: .Ltmp[[TMP8]]
// CHECK: .word f5
// CHECK: .section i,"ax",@progbits
// CHECK: .align 2
// CHECK: .Ltmp[[TMP9]]
// CHECK: .word f12
// CHECK: .Ltmp[[TMP10]]
// CHECK: .word 245760
// CHECK: .section j,"ax",@progbits
// CHECK: .align 2
// CHECK: .Ltmp[[TMP11]]
// CHECK: .word bar
// CHECK: .section k,"ax",@progbits
// CHECK: .align 2
// CHECK: .Ltmp[[TMP12]]
// CHECK: .word 65544
// CHECK: .Ltmp[[TMP13]]
// CHECK: .word baz
// CHECK: .section l,"ax",@progbits
// CHECK: .align 2
// CHECK: .Ltmp[[TMP14]]
// CHECK: .word 65545
// CHECK: .Ltmp[[TMP15]]
// CHECK: .word bar+4