diff --git a/llvm/include/llvm/MC/MCExpr.h b/llvm/include/llvm/MC/MCExpr.h --- a/llvm/include/llvm/MC/MCExpr.h +++ b/llvm/include/llvm/MC/MCExpr.h @@ -242,6 +242,7 @@ VK_AVR_DIFF8, VK_AVR_DIFF16, VK_AVR_DIFF32, + VK_AVR_PM, VK_PPC_LO, // symbol@l VK_PPC_HI, // symbol@h diff --git a/llvm/lib/MC/MCExpr.cpp b/llvm/lib/MC/MCExpr.cpp --- a/llvm/lib/MC/MCExpr.cpp +++ b/llvm/lib/MC/MCExpr.cpp @@ -269,6 +269,7 @@ case VK_AVR_DIFF8: return "diff8"; case VK_AVR_DIFF16: return "diff16"; case VK_AVR_DIFF32: return "diff32"; + case VK_AVR_PM: return "pm"; case VK_PPC_LO: return "l"; case VK_PPC_HI: return "h"; case VK_PPC_HA: return "ha"; diff --git a/llvm/lib/Target/AVR/AVRAsmPrinter.cpp b/llvm/lib/Target/AVR/AVRAsmPrinter.cpp --- a/llvm/lib/Target/AVR/AVRAsmPrinter.cpp +++ b/llvm/lib/Target/AVR/AVRAsmPrinter.cpp @@ -15,6 +15,7 @@ #include "AVRMCInstLower.h" #include "AVRSubtarget.h" #include "MCTargetDesc/AVRInstPrinter.h" +#include "MCTargetDesc/AVRMCExpr.h" #include "TargetInfo/AVRTargetInfo.h" #include "llvm/CodeGen/AsmPrinter.h" @@ -53,6 +54,8 @@ void emitInstruction(const MachineInstr *MI) override; + const MCExpr *lowerConstant(const Constant *CV) override; + private: const MCRegisterInfo &MRI; }; @@ -176,6 +179,20 @@ EmitToStreamer(*OutStreamer, I); } +const MCExpr *AVRAsmPrinter::lowerConstant(const Constant *CV) { + MCContext &Ctx = OutContext; + + if (const GlobalValue *GV = dyn_cast(CV)) { + bool IsProgMem = GV->getAddressSpace() == AVR::ProgramMemory; + if (IsProgMem) { + const MCExpr *Expr = MCSymbolRefExpr::create(getSymbol(GV), Ctx); + return AVRMCExpr::create(AVRMCExpr::VK_AVR_PM, Expr, false, Ctx); + } + } + + return AsmPrinter::lowerConstant(CV); +} + } // end of namespace llvm extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeAVRAsmPrinter() { diff --git a/llvm/lib/Target/AVR/MCTargetDesc/AVRELFObjectWriter.cpp b/llvm/lib/Target/AVR/MCTargetDesc/AVRELFObjectWriter.cpp --- a/llvm/lib/Target/AVR/MCTargetDesc/AVRELFObjectWriter.cpp +++ b/llvm/lib/Target/AVR/MCTargetDesc/AVRELFObjectWriter.cpp @@ -7,6 +7,7 @@ //===----------------------------------------------------------------------===// #include "MCTargetDesc/AVRFixupKinds.h" +#include "MCTargetDesc/AVRMCExpr.h" #include "MCTargetDesc/AVRMCTargetDesc.h" #include "llvm/MC/MCAssembler.h" @@ -72,6 +73,7 @@ case MCSymbolRefExpr::VK_None: return ELF::R_AVR_16; case MCSymbolRefExpr::VK_AVR_NONE: + case MCSymbolRefExpr::VK_AVR_PM: return ELF::R_AVR_16_PM; case MCSymbolRefExpr::VK_AVR_DIFF16: return ELF::R_AVR_DIFF16; diff --git a/llvm/lib/Target/AVR/MCTargetDesc/AVRMCExpr.h b/llvm/lib/Target/AVR/MCTargetDesc/AVRMCExpr.h --- a/llvm/lib/Target/AVR/MCTargetDesc/AVRMCExpr.h +++ b/llvm/lib/Target/AVR/MCTargetDesc/AVRMCExpr.h @@ -20,13 +20,14 @@ public: /// Specifies the type of an expression. enum VariantKind { - VK_AVR_None, + VK_AVR_None = 0, VK_AVR_HI8, ///< Corresponds to `hi8()`. VK_AVR_LO8, ///< Corresponds to `lo8()`. VK_AVR_HH8, ///< Corresponds to `hlo8() and hh8()`. VK_AVR_HHI8, ///< Corresponds to `hhi8()`. + VK_AVR_PM, ///< Corresponds to `pm()`, reference to program memory. VK_AVR_PM_LO8, ///< Corresponds to `pm_lo8()`. VK_AVR_PM_HI8, ///< Corresponds to `pm_hi8()`. VK_AVR_PM_HH8, ///< Corresponds to `pm_hh8()`. diff --git a/llvm/lib/Target/AVR/MCTargetDesc/AVRMCExpr.cpp b/llvm/lib/Target/AVR/MCTargetDesc/AVRMCExpr.cpp --- a/llvm/lib/Target/AVR/MCTargetDesc/AVRMCExpr.cpp +++ b/llvm/lib/Target/AVR/MCTargetDesc/AVRMCExpr.cpp @@ -26,6 +26,7 @@ {"hh8", AVRMCExpr::VK_AVR_HH8}, // synonym with hlo8 {"hlo8", AVRMCExpr::VK_AVR_HH8}, {"hhi8", AVRMCExpr::VK_AVR_HHI8}, + {"pm", AVRMCExpr::VK_AVR_PM}, {"pm_lo8", AVRMCExpr::VK_AVR_PM_LO8}, {"pm_hi8", AVRMCExpr::VK_AVR_PM_HI8}, {"pm_hh8", AVRMCExpr::VK_AVR_PM_HH8}, @@ -87,6 +88,9 @@ MCSymbolRefExpr::VariantKind Modifier = Sym->getKind(); if (Modifier != MCSymbolRefExpr::VK_None) return false; + if (Kind == VK_AVR_PM) { + Modifier = MCSymbolRefExpr::VK_AVR_PM; + } Sym = MCSymbolRefExpr::create(&Sym->getSymbol(), Modifier, Context); Result = MCValue::get(Sym, Value.getSymB(), Value.getConstant()); @@ -131,6 +135,7 @@ Value &= 0xff0000; Value >>= 16; break; + case AVRMCExpr::VK_AVR_PM: case AVRMCExpr::VK_AVR_GS: Value >>= 1; // Program memory addresses must always be shifted by one. break; @@ -167,6 +172,7 @@ case VK_AVR_PM_HH8: Kind = isNegated() ? AVR::fixup_hh8_ldi_pm_neg : AVR::fixup_hh8_ldi_pm; break; + case VK_AVR_PM: case VK_AVR_GS: Kind = AVR::fixup_16_pm; break; diff --git a/llvm/test/CodeGen/AVR/rust-trait-object.ll b/llvm/test/CodeGen/AVR/rust-trait-object.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/AVR/rust-trait-object.ll @@ -0,0 +1,112 @@ +; RUN: llc < %s -march=avr -filetype=asm | FileCheck %s -check-prefix=CHECK-ASM +; RUN: llc < %s -march=avr -filetype=obj | llvm-objdump -Dr - \ +; RUN: | FileCheck %s -check-prefix=CHECK-OBJ + +; Somewhat pruned test case from rustc using trait objects + +%TraitObjectA = type {} + +; CHECK-ASM-LABEL: vtable.0: +; CHECK-ASM-NEXT: .short pm(drop_in_place2) +; CHECK-ASM-NEXT: .short 0 +; CHECK-ASM-NEXT: .short 1 +; CHECK-ASM-NEXT: .short pm(trait_fn2) + +; CHECK-OBJ-LABEL: : +; CHECK-OBJ-NEXT: 00 00 +; CHECK-OBJ-NEXT: R_AVR_16_PM .text +; CHECK-OBJ-NEXT: 00 00 +; CHECK-OBJ-NEXT: 01 00 00 00 +; CHECK-OBJ-NEXT: R_AVR_16_PM .text +@vtable.0 = private constant { + void (%TraitObjectA*) addrspace(1)*, + i16, + i16, + i8 (%TraitObjectA*) addrspace(1)* + } { + void (%TraitObjectA*) addrspace(1)* + @drop_in_place2, + i16 0, + i16 1, + i8 (%TraitObjectA*) addrspace(1)* + @trait_fn2 + }, align 1 + +; CHECK-ASM-LABEL: vtable.1: +; CHECK-ASM-NEXT: .short pm(drop_in_place1) +; CHECK-ASM-NEXT: .short 0 +; CHECK-ASM-NEXT: .short 1 +; CHECK-ASM-NEXT: .short pm(trait_fn1) + +; CHECK-OBJ-LABEL: : +; CHECK-OBJ-NEXT: 00 00 +; CHECK-OBJ-NEXT: R_AVR_16_PM .text +; CHECK-OBJ-NEXT: 00 00 +; CHECK-OBJ-NEXT: 01 00 00 00 +; CHECK-OBJ-NEXT: R_AVR_16_PM .text +@vtable.1 = private constant { + void (%TraitObjectA*) addrspace(1)*, + i16, + i16, + i8 (%TraitObjectA*) addrspace(1)* + } { + void (%TraitObjectA*) addrspace(1)* + @drop_in_place1, + i16 0, + i16 1, + i8 (%TraitObjectA*) addrspace(1)* + @trait_fn1 + }, align 1 + +define internal fastcc i8 @TraitObjectA_method(i1 zeroext %choice) addrspace(1) { +start: + %b = alloca %TraitObjectA, align 1 + + %c = select i1 %choice, [3 x i16]* bitcast ({ + void (%TraitObjectA*) addrspace(1)*, + i16, + i16, + i8 (%TraitObjectA*) addrspace(1)* + }* @vtable.0 to [3 x i16]*), + [3 x i16]* bitcast ({ + void (%TraitObjectA*) addrspace(1)*, + i16, + i16, + i8 (%TraitObjectA*) addrspace(1)* + }* @vtable.1 to [3 x i16]*) + %b2 = bitcast %TraitObjectA* %b to {}* + + %res = call fastcc addrspace(1) i8 @call_trait_object({}* nonnull align 1 %b2, [3 x i16]* noalias readonly align 1 dereferenceable(6) %c) + ret i8 %res +} + +define internal fastcc i8 @call_trait_object({}* nonnull align 1 %a, [3 x i16]* noalias nocapture readonly align 1 dereferenceable(6) %b) addrspace(1) { +start: + %b2 = getelementptr inbounds [3 x i16], [3 x i16]* %b, i16 0, i16 3 + %c = bitcast i16* %b2 to i8 ({}*) addrspace(1)** + %d = load i8 ({}*) addrspace(1)*, i8 ({}*) addrspace(1)** %c, align 1, !invariant.load !1, !nonnull !1 + %res = tail call addrspace(1) i8 %d({}* nonnull align 1 %a) + ret i8 %res +} + +define internal void @drop_in_place1(%TraitObjectA* nocapture %a) addrspace(1) { +start: + ret void +} + +define internal i8 @trait_fn1(%TraitObjectA* noalias nocapture nonnull readonly align 1 %self) addrspace(1) { +start: + ret i8 89 +} + +define internal void @drop_in_place2(%TraitObjectA* nocapture %a) addrspace(1) { +start: + ret void +} + +define internal i8 @trait_fn2(%TraitObjectA* noalias nocapture nonnull readonly align 1 %self) addrspace(1) { +start: + ret i8 79 +} + +!1 = !{} diff --git a/llvm/test/MC/AVR/relocations.s b/llvm/test/MC/AVR/relocations.s --- a/llvm/test/MC/AVR/relocations.s +++ b/llvm/test/MC/AVR/relocations.s @@ -135,12 +135,15 @@ ; CHECK-NEXT: R_AVR_HI8_LDI_GS foo ldi r18, hi8(gs(foo)) -; CHECK-NEXT: R_AVR_16 +; CHECK-NEXT: R_AVR_16 foo .short foo -; CHECK-NEXT: R_AVR_16_PM +; CHECK-NEXT: R_AVR_16_PM foo .short gs(foo) +; CHECK-NEXT: R_AVR_16_PM foo +.short pm(foo) + ; CHECK-NEXT: R_AVR_8 .byte foo