1 //===-- AVRMCExpr.cpp - AVR specific MC expression classes ----------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "AVRMCExpr.h" 10 11 #include "llvm/MC/MCAsmLayout.h" 12 #include "llvm/MC/MCAssembler.h" 13 #include "llvm/MC/MCContext.h" 14 #include "llvm/MC/MCStreamer.h" 15 #include "llvm/MC/MCValue.h" 16 17 namespace llvm { 18 19 namespace { 20 21 const struct ModifierEntry { 22 const char *const Spelling; 23 AVRMCExpr::VariantKind VariantKind; 24 } ModifierNames[] = { 25 {"lo8", AVRMCExpr::VK_AVR_LO8}, {"hi8", AVRMCExpr::VK_AVR_HI8}, 26 {"hh8", AVRMCExpr::VK_AVR_HH8}, // synonym with hlo8 27 {"hlo8", AVRMCExpr::VK_AVR_HH8}, {"hhi8", AVRMCExpr::VK_AVR_HHI8}, 28 29 {"pm", AVRMCExpr::VK_AVR_PM}, {"pm_lo8", AVRMCExpr::VK_AVR_PM_LO8}, 30 {"pm_hi8", AVRMCExpr::VK_AVR_PM_HI8}, {"pm_hh8", AVRMCExpr::VK_AVR_PM_HH8}, 31 32 {"lo8_gs", AVRMCExpr::VK_AVR_LO8_GS}, {"hi8_gs", AVRMCExpr::VK_AVR_HI8_GS}, 33 {"gs", AVRMCExpr::VK_AVR_GS}, 34 }; 35 36 } // end of anonymous namespace 37 38 const AVRMCExpr *AVRMCExpr::create(VariantKind Kind, const MCExpr *Expr, 39 bool Negated, MCContext &Ctx) { 40 return new (Ctx) AVRMCExpr(Kind, Expr, Negated); 41 } 42 43 void AVRMCExpr::printImpl(raw_ostream &OS, const MCAsmInfo *MAI) const { 44 assert(Kind != VK_AVR_None); 45 46 if (isNegated()) 47 OS << '-'; 48 49 OS << getName() << '('; 50 getSubExpr()->print(OS, MAI); 51 OS << ')'; 52 } 53 54 bool AVRMCExpr::evaluateAsConstant(int64_t &Result) const { 55 MCValue Value; 56 57 bool isRelocatable = 58 getSubExpr()->evaluateAsRelocatable(Value, nullptr, nullptr); 59 60 if (!isRelocatable) 61 return false; 62 63 if (Value.isAbsolute()) { 64 Result = evaluateAsInt64(Value.getConstant()); 65 return true; 66 } 67 68 return false; 69 } 70 71 bool AVRMCExpr::evaluateAsRelocatableImpl(MCValue &Result, 72 const MCAsmLayout *Layout, 73 const MCFixup *Fixup) const { 74 MCValue Value; 75 bool isRelocatable = SubExpr->evaluateAsRelocatable(Value, Layout, Fixup); 76 77 if (!isRelocatable) 78 return false; 79 80 if (Value.isAbsolute()) { 81 Result = MCValue::get(evaluateAsInt64(Value.getConstant())); 82 } else { 83 if (!Layout) 84 return false; 85 86 MCContext &Context = Layout->getAssembler().getContext(); 87 const MCSymbolRefExpr *Sym = Value.getSymA(); 88 MCSymbolRefExpr::VariantKind Modifier = Sym->getKind(); 89 if (Modifier != MCSymbolRefExpr::VK_None) 90 return false; 91 if (Kind == VK_AVR_PM) { 92 Modifier = MCSymbolRefExpr::VK_AVR_PM; 93 } 94 95 Sym = MCSymbolRefExpr::create(&Sym->getSymbol(), Modifier, Context); 96 Result = MCValue::get(Sym, Value.getSymB(), Value.getConstant()); 97 } 98 99 return true; 100 } 101 102 int64_t AVRMCExpr::evaluateAsInt64(int64_t Value) const { 103 if (Negated) 104 Value *= -1; 105 106 switch (Kind) { 107 case AVRMCExpr::VK_AVR_LO8: 108 Value &= 0xff; 109 break; 110 case AVRMCExpr::VK_AVR_HI8: 111 Value &= 0xff00; 112 Value >>= 8; 113 break; 114 case AVRMCExpr::VK_AVR_HH8: 115 Value &= 0xff0000; 116 Value >>= 16; 117 break; 118 case AVRMCExpr::VK_AVR_HHI8: 119 Value &= 0xff000000; 120 Value >>= 24; 121 break; 122 case AVRMCExpr::VK_AVR_PM_LO8: 123 case AVRMCExpr::VK_AVR_LO8_GS: 124 Value >>= 1; // Program memory addresses must always be shifted by one. 125 Value &= 0xff; 126 break; 127 case AVRMCExpr::VK_AVR_PM_HI8: 128 case AVRMCExpr::VK_AVR_HI8_GS: 129 Value >>= 1; // Program memory addresses must always be shifted by one. 130 Value &= 0xff00; 131 Value >>= 8; 132 break; 133 case AVRMCExpr::VK_AVR_PM_HH8: 134 Value >>= 1; // Program memory addresses must always be shifted by one. 135 Value &= 0xff0000; 136 Value >>= 16; 137 break; 138 case AVRMCExpr::VK_AVR_PM: 139 case AVRMCExpr::VK_AVR_GS: 140 Value >>= 1; // Program memory addresses must always be shifted by one. 141 break; 142 143 case AVRMCExpr::VK_AVR_None: 144 llvm_unreachable("Uninitialized expression."); 145 } 146 return static_cast<uint64_t>(Value) & 0xff; 147 } 148 149 AVR::Fixups AVRMCExpr::getFixupKind() const { 150 AVR::Fixups Kind = AVR::Fixups::LastTargetFixupKind; 151 152 switch (getKind()) { 153 case VK_AVR_LO8: 154 Kind = isNegated() ? AVR::fixup_lo8_ldi_neg : AVR::fixup_lo8_ldi; 155 break; 156 case VK_AVR_HI8: 157 Kind = isNegated() ? AVR::fixup_hi8_ldi_neg : AVR::fixup_hi8_ldi; 158 break; 159 case VK_AVR_HH8: 160 Kind = isNegated() ? AVR::fixup_hh8_ldi_neg : AVR::fixup_hh8_ldi; 161 break; 162 case VK_AVR_HHI8: 163 Kind = isNegated() ? AVR::fixup_ms8_ldi_neg : AVR::fixup_ms8_ldi; 164 break; 165 166 case VK_AVR_PM_LO8: 167 Kind = isNegated() ? AVR::fixup_lo8_ldi_pm_neg : AVR::fixup_lo8_ldi_pm; 168 break; 169 case VK_AVR_PM_HI8: 170 Kind = isNegated() ? AVR::fixup_hi8_ldi_pm_neg : AVR::fixup_hi8_ldi_pm; 171 break; 172 case VK_AVR_PM_HH8: 173 Kind = isNegated() ? AVR::fixup_hh8_ldi_pm_neg : AVR::fixup_hh8_ldi_pm; 174 break; 175 case VK_AVR_PM: 176 case VK_AVR_GS: 177 Kind = AVR::fixup_16_pm; 178 break; 179 case VK_AVR_LO8_GS: 180 Kind = AVR::fixup_lo8_ldi_gs; 181 break; 182 case VK_AVR_HI8_GS: 183 Kind = AVR::fixup_hi8_ldi_gs; 184 break; 185 186 case VK_AVR_None: 187 llvm_unreachable("Uninitialized expression"); 188 } 189 190 return Kind; 191 } 192 193 void AVRMCExpr::visitUsedExpr(MCStreamer &Streamer) const { 194 Streamer.visitUsedExpr(*getSubExpr()); 195 } 196 197 const char *AVRMCExpr::getName() const { 198 const auto &Modifier = 199 llvm::find_if(ModifierNames, [this](ModifierEntry const &Mod) { 200 return Mod.VariantKind == Kind; 201 }); 202 203 if (Modifier != std::end(ModifierNames)) { 204 return Modifier->Spelling; 205 } 206 return nullptr; 207 } 208 209 AVRMCExpr::VariantKind AVRMCExpr::getKindByName(StringRef Name) { 210 const auto &Modifier = 211 llvm::find_if(ModifierNames, [&Name](ModifierEntry const &Mod) { 212 return Mod.Spelling == Name; 213 }); 214 215 if (Modifier != std::end(ModifierNames)) { 216 return Modifier->VariantKind; 217 } 218 return VK_AVR_None; 219 } 220 221 } // end of namespace llvm 222