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 @@ -241,6 +241,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 @@ -264,6 +264,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 IsFunction = isa(GV); + if (IsFunction) { + 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 @@ -8,6 +8,7 @@ #include "MCTargetDesc/AVRFixupKinds.h" #include "MCTargetDesc/AVRMCTargetDesc.h" +#include "MCTargetDesc/AVRMCExpr.h" #include "llvm/MC/MCAssembler.h" #include "llvm/MC/MCELFObjectWriter.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,150 @@ +; 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 + +target datalayout = "e-P1-p:16:8-i8:8-i16:8-i32:8-i64:8-f32:8-f64:8-n8-a:8" +target triple = "avr-unknown-unknown" + +%"uno_traitobject2::A" = type {} + +; CHECK-ASM-LABEL: vtable.0: +; CHECK-ASM-NEXT: .short pm("core::ptr::drop_in_place::h3b9da2938e5622e1") +; CHECK-ASM-NEXT: .short 0 +; CHECK-ASM-NEXT: .short 1 +; CHECK-ASM-NEXT: .short pm("::trait_fn::h705f8daa75fb4b4d") + +; 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 unnamed_addr constant { + void (%"uno_traitobject2::A"*) addrspace(1)*, + i16, + i16, + i8 (%"uno_traitobject2::A"*) addrspace(1)* + } { + void (%"uno_traitobject2::A"*) addrspace(1)* + @"core::ptr::drop_in_place::h3b9da2938e5622e1", + i16 0, + i16 1, + i8 (%"uno_traitobject2::A"*) addrspace(1)* + @"::trait_fn::h705f8daa75fb4b4d" + }, align 1 + +; CHECK-ASM-LABEL: vtable.1: +; CHECK-ASM-NEXT: .short pm("core::ptr::drop_in_place::h1c5aa009609a9a59") +; CHECK-ASM-NEXT: .short 0 +; CHECK-ASM-NEXT: .short 1 +; CHECK-ASM-NEXT: .short pm("::trait_fn::h0d0fb094f42c91f4") + +; 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 unnamed_addr constant { + void (%"uno_traitobject2::A"*) addrspace(1)*, + i16, + i16, + i8 (%"uno_traitobject2::A"*) addrspace(1)* + } { + void (%"uno_traitobject2::A"*) addrspace(1)* + @"core::ptr::drop_in_place::h1c5aa009609a9a59", + i16 0, + i16 1, + i8 (%"uno_traitobject2::A"*) addrspace(1)* + @"::trait_fn::h0d0fb094f42c91f4" + }, align 1 + +; Function Attrs: argmemonly nounwind willreturn +declare void @llvm.lifetime.start.p0i8(i64 immarg, i8* nocapture) addrspace(1) #2 + +; Function Attrs: argmemonly nounwind willreturn +declare void @llvm.lifetime.end.p0i8(i64 immarg, i8* nocapture) addrspace(1) #2 + +; uno_traitobject2::test +; Function Attrs: noinline nounwind optsize +define internal fastcc i8 @"uno_traitobject2::test::haeec7ec13f8f89c7"(i1 zeroext %choice) unnamed_addr addrspace(1) #3 { +start: + %b = alloca %"uno_traitobject2::A", align 1 + + %. = select i1 %choice, [3 x i16]* bitcast ({ + void (%"uno_traitobject2::A"*) addrspace(1)*, + i16, + i16, + i8 (%"uno_traitobject2::A"*) addrspace(1)* + }* @vtable.0 to [3 x i16]*), + [3 x i16]* bitcast ({ + void (%"uno_traitobject2::A"*) addrspace(1)*, + i16, + i16, + i8 (%"uno_traitobject2::A"*) addrspace(1)* + }* @vtable.1 to [3 x i16]*) + %_6.sroa.0.0 = bitcast %"uno_traitobject2::A"* %b to {}* + + +; call uno_traitobject2::call_trait_object + %0 = call fastcc addrspace(1) i8 @"uno_traitobject2::call_trait_object::hb4ae93d54abda045"({}* nonnull align 1 %_6.sroa.0.0, [3 x i16]* noalias readonly align 1 dereferenceable(6) %.) + ret i8 %0 +} + +; uno_traitobject2::call_trait_object +; Function Attrs: noinline nounwind optsize +define internal fastcc i8 @"uno_traitobject2::call_trait_object::hb4ae93d54abda045"({}* nonnull align 1 %t.0, [3 x i16]* noalias nocapture readonly align 1 dereferenceable(6) %t.1) unnamed_addr addrspace(1) #3 { +start: + + + %0 = getelementptr inbounds [3 x i16], [3 x i16]* %t.1, i16 0, i16 3 + %1 = bitcast i16* %0 to i8 ({}*) addrspace(1)** + %2 = load i8 ({}*) addrspace(1)*, i8 ({}*) addrspace(1)** %1, align 1, !invariant.load !4, !nonnull !4 + %3 = tail call addrspace(1) i8 %2({}* nonnull align 1 %t.0) #5 + ret i8 %3 +} + +; core::ptr::drop_in_place +; Function Attrs: norecurse nounwind optsize readnone +define internal void @"core::ptr::drop_in_place::h1c5aa009609a9a59"(%"uno_traitobject2::A"* nocapture %_1) unnamed_addr addrspace(1) #4 { +start: + + ret void +} + +; ::trait_fn +; Function Attrs: norecurse nounwind optsize readnone +define internal i8 @"::trait_fn::h0d0fb094f42c91f4"(%"uno_traitobject2::A"* noalias nocapture nonnull readonly align 1 %self) unnamed_addr addrspace(1) #4 { +start: + + ret i8 89 +} + +; core::ptr::drop_in_place +; Function Attrs: norecurse nounwind optsize readnone +define internal void @"core::ptr::drop_in_place::h3b9da2938e5622e1"(%"uno_traitobject2::A"* nocapture %_1) unnamed_addr addrspace(1) #4 { +start: + + ret void +} + +; ::trait_fn +; Function Attrs: norecurse nounwind optsize readnone +define internal i8 @"::trait_fn::h705f8daa75fb4b4d"(%"uno_traitobject2::A"* noalias nocapture nonnull readonly align 1 %self) unnamed_addr addrspace(1) #4 { +start: + + ret i8 79 +} + +attributes #0 = { nounwind readnone speculatable willreturn } +attributes #1 = { noreturn nounwind optsize "target-cpu"="atmega328p" } +attributes #2 = { argmemonly nounwind willreturn } +attributes #3 = { noinline nounwind optsize "target-cpu"="atmega328p" } +attributes #4 = { norecurse nounwind optsize readnone "target-cpu"="atmega328p" } +attributes #5 = { nounwind } + +!4 = !{} +!1186 = !{i32 524241} +!1188 = !{i8 0, i8 2} \ No newline at end of file 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