From c33b4883b39a63c518f829e5ce992928137f9551 Mon Sep 17 00:00:00 2001 From: Weiming Zhao Date: Tue, 24 Jun 2014 16:21:38 +0000 Subject: Resubmit commit r211533 "Fix PR20056: Implement pseudo LDR , = 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 --- include/llvm/MC/MCStreamer.h | 21 ++ lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp | 55 ++++- .../AArch64/MCTargetDesc/AArch64TargetStreamer.cpp | 40 ++++ lib/Target/AArch64/MCTargetDesc/CMakeLists.txt | 1 + test/CodeGen/AArch64/inlineasm-ldr-pseudo.ll | 26 +++ test/MC/AArch64/ldr-pseudo-obj-errors.s | 13 ++ test/MC/AArch64/ldr-pseudo.s | 231 +++++++++++++++++++++ 7 files changed, 386 insertions(+), 1 deletion(-) create mode 100644 lib/Target/AArch64/MCTargetDesc/AArch64TargetStreamer.cpp create mode 100644 test/CodeGen/AArch64/inlineasm-ldr-pseudo.ll create mode 100644 test/MC/AArch64/ldr-pseudo-obj-errors.s create mode 100644 test/MC/AArch64/ldr-pseudo.s diff --git a/include/llvm/MC/MCStreamer.h b/include/llvm/MC/MCStreamer.h index bf224979de..cd1fa9b6a8 100644 --- a/include/llvm/MC/MCStreamer.h +++ b/include/llvm/MC/MCStreamer.h @@ -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 ConstantPools; +}; + // FIXME: declared here because it is used from // lib/CodeGen/AsmPrinter/ARMException.cpp. class ARMTargetStreamer : public MCTargetStreamer { diff --git a/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp b/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp index 5d363a00dc..c4d840d90b 100644 --- a/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp +++ b/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp @@ -43,6 +43,11 @@ private: MCSubtargetInfo &STI; MCAsmParser &Parser; + AArch64TargetStreamer &getTargetStreamer() { + MCTargetStreamer &TS = *getParser().getStreamer().getTargetStreamer(); + return static_cast(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 &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(SubExprVal) && Operands.size() >= 2 && + static_cast(*Operands[1]).isReg()) { + bool IsXReg = AArch64MCRegisterClasses[AArch64::GPR64allRegClassID].contains( + Operands[1]->getReg()); + uint64_t Imm = (cast(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, diff --git a/lib/Target/AArch64/MCTargetDesc/AArch64TargetStreamer.cpp b/lib/Target/AArch64/MCTargetDesc/AArch64TargetStreamer.cpp new file mode 100644 index 0000000000..f9aeb35b64 --- /dev/null +++ b/lib/Target/AArch64/MCTargetDesc/AArch64TargetStreamer.cpp @@ -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); } diff --git a/lib/Target/AArch64/MCTargetDesc/CMakeLists.txt b/lib/Target/AArch64/MCTargetDesc/CMakeLists.txt index 7d5bced17a..6d8be5e63f 100644 --- a/lib/Target/AArch64/MCTargetDesc/CMakeLists.txt +++ b/lib/Target/AArch64/MCTargetDesc/CMakeLists.txt @@ -7,6 +7,7 @@ add_llvm_library(LLVMAArch64Desc AArch64MCExpr.cpp AArch64MCTargetDesc.cpp AArch64MachObjectWriter.cpp + AArch64TargetStreamer.cpp ) add_dependencies(LLVMAArch64Desc AArch64CommonTableGen) diff --git a/test/CodeGen/AArch64/inlineasm-ldr-pseudo.ll b/test/CodeGen/AArch64/inlineasm-ldr-pseudo.ll new file mode 100644 index 0000000000..645214ac8e --- /dev/null +++ b/test/CodeGen/AArch64/inlineasm-ldr-pseudo.ll @@ -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 +} + + diff --git a/test/MC/AArch64/ldr-pseudo-obj-errors.s b/test/MC/AArch64/ldr-pseudo-obj-errors.s new file mode 100644 index 0000000000..e38933cc59 --- /dev/null +++ b/test/MC/AArch64/ldr-pseudo-obj-errors.s @@ -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 diff --git a/test/MC/AArch64/ldr-pseudo.s b/test/MC/AArch64/ldr-pseudo.s new file mode 100644 index 0000000000..5f5bc5b3f5 --- /dev/null +++ b/test/MC/AArch64/ldr-pseudo.s @@ -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 -- cgit v1.2.3