1 //===- ARMTargetStreamer.cpp - ARMTargetStreamer class --*- C++ -*---------===// 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 // This file implements the ARMTargetStreamer class. 10 // 11 //===----------------------------------------------------------------------===// 12 13 #include "MCTargetDesc/ARMMCTargetDesc.h" 14 #include "llvm/MC/ConstantPools.h" 15 #include "llvm/MC/MCAsmInfo.h" 16 #include "llvm/MC/MCContext.h" 17 #include "llvm/MC/MCExpr.h" 18 #include "llvm/MC/MCStreamer.h" 19 #include "llvm/MC/MCSubtargetInfo.h" 20 #include "llvm/Support/ARMBuildAttributes.h" 21 #include "llvm/Support/TargetParser.h" 22 23 using namespace llvm; 24 25 // 26 // ARMTargetStreamer Implemenation 27 // 28 29 ARMTargetStreamer::ARMTargetStreamer(MCStreamer &S) 30 : MCTargetStreamer(S), ConstantPools(new AssemblerConstantPools()) {} 31 32 ARMTargetStreamer::~ARMTargetStreamer() = default; 33 34 // The constant pool handling is shared by all ARMTargetStreamer 35 // implementations. 36 const MCExpr *ARMTargetStreamer::addConstantPoolEntry(const MCExpr *Expr, SMLoc Loc) { 37 return ConstantPools->addEntry(Streamer, Expr, 4, Loc); 38 } 39 40 void ARMTargetStreamer::emitCurrentConstantPool() { 41 ConstantPools->emitForCurrentSection(Streamer); 42 ConstantPools->clearCacheForCurrentSection(Streamer); 43 } 44 45 // finish() - write out any non-empty assembler constant pools. 46 void ARMTargetStreamer::finish() { ConstantPools->emitAll(Streamer); } 47 48 // reset() - Reset any state 49 void ARMTargetStreamer::reset() {} 50 51 void ARMTargetStreamer::emitInst(uint32_t Inst, char Suffix) { 52 unsigned Size; 53 char Buffer[4]; 54 const bool LittleEndian = getStreamer().getContext().getAsmInfo()->isLittleEndian(); 55 56 switch (Suffix) { 57 case '\0': 58 Size = 4; 59 60 for (unsigned II = 0, IE = Size; II != IE; II++) { 61 const unsigned I = LittleEndian ? (Size - II - 1) : II; 62 Buffer[Size - II - 1] = uint8_t(Inst >> I * CHAR_BIT); 63 } 64 65 break; 66 case 'n': 67 case 'w': 68 Size = (Suffix == 'n' ? 2 : 4); 69 70 // Thumb wide instructions are emitted as a pair of 16-bit words of the 71 // appropriate endianness. 72 for (unsigned II = 0, IE = Size; II != IE; II = II + 2) { 73 const unsigned I0 = LittleEndian ? II + 0 : II + 1; 74 const unsigned I1 = LittleEndian ? II + 1 : II + 0; 75 Buffer[Size - II - 2] = uint8_t(Inst >> I0 * CHAR_BIT); 76 Buffer[Size - II - 1] = uint8_t(Inst >> I1 * CHAR_BIT); 77 } 78 79 break; 80 default: 81 llvm_unreachable("Invalid Suffix"); 82 } 83 getStreamer().EmitBytes(StringRef(Buffer, Size)); 84 } 85 86 // The remaining callbacks should be handled separately by each 87 // streamer. 88 void ARMTargetStreamer::emitFnStart() {} 89 void ARMTargetStreamer::emitFnEnd() {} 90 void ARMTargetStreamer::emitCantUnwind() {} 91 void ARMTargetStreamer::emitPersonality(const MCSymbol *Personality) {} 92 void ARMTargetStreamer::emitPersonalityIndex(unsigned Index) {} 93 void ARMTargetStreamer::emitHandlerData() {} 94 void ARMTargetStreamer::emitSetFP(unsigned FpReg, unsigned SpReg, 95 int64_t Offset) {} 96 void ARMTargetStreamer::emitMovSP(unsigned Reg, int64_t Offset) {} 97 void ARMTargetStreamer::emitPad(int64_t Offset) {} 98 void ARMTargetStreamer::emitRegSave(const SmallVectorImpl<unsigned> &RegList, 99 bool isVector) {} 100 void ARMTargetStreamer::emitUnwindRaw(int64_t StackOffset, 101 const SmallVectorImpl<uint8_t> &Opcodes) { 102 } 103 void ARMTargetStreamer::switchVendor(StringRef Vendor) {} 104 void ARMTargetStreamer::emitAttribute(unsigned Attribute, unsigned Value) {} 105 void ARMTargetStreamer::emitTextAttribute(unsigned Attribute, 106 StringRef String) {} 107 void ARMTargetStreamer::emitIntTextAttribute(unsigned Attribute, 108 unsigned IntValue, 109 StringRef StringValue) {} 110 void ARMTargetStreamer::emitArch(ARM::ArchKind Arch) {} 111 void ARMTargetStreamer::emitArchExtension(unsigned ArchExt) {} 112 void ARMTargetStreamer::emitObjectArch(ARM::ArchKind Arch) {} 113 void ARMTargetStreamer::emitFPU(unsigned FPU) {} 114 void ARMTargetStreamer::finishAttributeSection() {} 115 void 116 ARMTargetStreamer::AnnotateTLSDescriptorSequence(const MCSymbolRefExpr *SRE) {} 117 void ARMTargetStreamer::emitThumbSet(MCSymbol *Symbol, const MCExpr *Value) {} 118 119 static ARMBuildAttrs::CPUArch getArchForCPU(const MCSubtargetInfo &STI) { 120 if (STI.getCPU() == "xscale") 121 return ARMBuildAttrs::v5TEJ; 122 123 if (STI.hasFeature(ARM::HasV8Ops)) { 124 if (STI.hasFeature(ARM::FeatureRClass)) 125 return ARMBuildAttrs::v8_R; 126 return ARMBuildAttrs::v8_A; 127 } else if (STI.hasFeature(ARM::HasV8MMainlineOps)) 128 return ARMBuildAttrs::v8_M_Main; 129 else if (STI.hasFeature(ARM::HasV7Ops)) { 130 if (STI.hasFeature(ARM::FeatureMClass) && STI.hasFeature(ARM::FeatureDSP)) 131 return ARMBuildAttrs::v7E_M; 132 return ARMBuildAttrs::v7; 133 } else if (STI.hasFeature(ARM::HasV6T2Ops)) 134 return ARMBuildAttrs::v6T2; 135 else if (STI.hasFeature(ARM::HasV8MBaselineOps)) 136 return ARMBuildAttrs::v8_M_Base; 137 else if (STI.hasFeature(ARM::HasV6MOps)) 138 return ARMBuildAttrs::v6S_M; 139 else if (STI.hasFeature(ARM::HasV6Ops)) 140 return ARMBuildAttrs::v6; 141 else if (STI.hasFeature(ARM::HasV5TEOps)) 142 return ARMBuildAttrs::v5TE; 143 else if (STI.hasFeature(ARM::HasV5TOps)) 144 return ARMBuildAttrs::v5T; 145 else if (STI.hasFeature(ARM::HasV4TOps)) 146 return ARMBuildAttrs::v4T; 147 else 148 return ARMBuildAttrs::v4; 149 } 150 151 static bool isV8M(const MCSubtargetInfo &STI) { 152 // Note that v8M Baseline is a subset of v6T2! 153 return (STI.hasFeature(ARM::HasV8MBaselineOps) && 154 !STI.hasFeature(ARM::HasV6T2Ops)) || 155 STI.hasFeature(ARM::HasV8MMainlineOps); 156 } 157 158 /// Emit the build attributes that only depend on the hardware that we expect 159 // /to be available, and not on the ABI, or any source-language choices. 160 void ARMTargetStreamer::emitTargetAttributes(const MCSubtargetInfo &STI) { 161 switchVendor("aeabi"); 162 163 const StringRef CPUString = STI.getCPU(); 164 if (!CPUString.empty() && !CPUString.startswith("generic")) { 165 // FIXME: remove krait check when GNU tools support krait cpu 166 if (STI.hasFeature(ARM::ProcKrait)) { 167 emitTextAttribute(ARMBuildAttrs::CPU_name, "cortex-a9"); 168 // We consider krait as a "cortex-a9" + hwdiv CPU 169 // Enable hwdiv through ".arch_extension idiv" 170 if (STI.hasFeature(ARM::FeatureHWDivThumb) || 171 STI.hasFeature(ARM::FeatureHWDivARM)) 172 emitArchExtension(ARM::AEK_HWDIVTHUMB | ARM::AEK_HWDIVARM); 173 } else { 174 emitTextAttribute(ARMBuildAttrs::CPU_name, CPUString); 175 } 176 } 177 178 emitAttribute(ARMBuildAttrs::CPU_arch, getArchForCPU(STI)); 179 180 if (STI.hasFeature(ARM::FeatureAClass)) { 181 emitAttribute(ARMBuildAttrs::CPU_arch_profile, 182 ARMBuildAttrs::ApplicationProfile); 183 } else if (STI.hasFeature(ARM::FeatureRClass)) { 184 emitAttribute(ARMBuildAttrs::CPU_arch_profile, 185 ARMBuildAttrs::RealTimeProfile); 186 } else if (STI.hasFeature(ARM::FeatureMClass)) { 187 emitAttribute(ARMBuildAttrs::CPU_arch_profile, 188 ARMBuildAttrs::MicroControllerProfile); 189 } 190 191 emitAttribute(ARMBuildAttrs::ARM_ISA_use, STI.hasFeature(ARM::FeatureNoARM) 192 ? ARMBuildAttrs::Not_Allowed 193 : ARMBuildAttrs::Allowed); 194 195 if (isV8M(STI)) { 196 emitAttribute(ARMBuildAttrs::THUMB_ISA_use, 197 ARMBuildAttrs::AllowThumbDerived); 198 } else if (STI.hasFeature(ARM::FeatureThumb2)) { 199 emitAttribute(ARMBuildAttrs::THUMB_ISA_use, 200 ARMBuildAttrs::AllowThumb32); 201 } else if (STI.hasFeature(ARM::HasV4TOps)) { 202 emitAttribute(ARMBuildAttrs::THUMB_ISA_use, ARMBuildAttrs::Allowed); 203 } 204 205 if (STI.hasFeature(ARM::FeatureNEON)) { 206 /* NEON is not exactly a VFP architecture, but GAS emit one of 207 * neon/neon-fp-armv8/neon-vfpv4/vfpv3/vfpv2 for .fpu parameters */ 208 if (STI.hasFeature(ARM::FeatureFPARMv8)) { 209 if (STI.hasFeature(ARM::FeatureCrypto)) 210 emitFPU(ARM::FK_CRYPTO_NEON_FP_ARMV8); 211 else 212 emitFPU(ARM::FK_NEON_FP_ARMV8); 213 } else if (STI.hasFeature(ARM::FeatureVFP4)) 214 emitFPU(ARM::FK_NEON_VFPV4); 215 else 216 emitFPU(STI.hasFeature(ARM::FeatureFP16) ? ARM::FK_NEON_FP16 217 : ARM::FK_NEON); 218 // Emit Tag_Advanced_SIMD_arch for ARMv8 architecture 219 if (STI.hasFeature(ARM::HasV8Ops)) 220 emitAttribute(ARMBuildAttrs::Advanced_SIMD_arch, 221 STI.hasFeature(ARM::HasV8_1aOps) 222 ? ARMBuildAttrs::AllowNeonARMv8_1a 223 : ARMBuildAttrs::AllowNeonARMv8); 224 } else { 225 if (STI.hasFeature(ARM::FeatureFPARMv8_D16_SP)) 226 // FPv5 and FP-ARMv8 have the same instructions, so are modeled as one 227 // FPU, but there are two different names for it depending on the CPU. 228 emitFPU(STI.hasFeature(ARM::FeatureD32) 229 ? ARM::FK_FP_ARMV8 230 : (STI.hasFeature(ARM::FeatureFP64) ? ARM::FK_FPV5_D16 231 : ARM::FK_FPV5_SP_D16)); 232 else if (STI.hasFeature(ARM::FeatureVFP4_D16_SP)) 233 emitFPU(STI.hasFeature(ARM::FeatureD32) 234 ? ARM::FK_VFPV4 235 : (STI.hasFeature(ARM::FeatureFP64) ? ARM::FK_VFPV4_D16 236 : ARM::FK_FPV4_SP_D16)); 237 else if (STI.hasFeature(ARM::FeatureVFP3_D16_SP)) 238 emitFPU( 239 STI.hasFeature(ARM::FeatureD32) 240 // +d32 241 ? (STI.hasFeature(ARM::FeatureFP16) ? ARM::FK_VFPV3_FP16 242 : ARM::FK_VFPV3) 243 // -d32 244 : (STI.hasFeature(ARM::FeatureFP64) 245 ? (STI.hasFeature(ARM::FeatureFP16) 246 ? ARM::FK_VFPV3_D16_FP16 247 : ARM::FK_VFPV3_D16) 248 : (STI.hasFeature(ARM::FeatureFP16) ? ARM::FK_VFPV3XD_FP16 249 : ARM::FK_VFPV3XD))); 250 else if (STI.hasFeature(ARM::FeatureVFP2_D16_SP)) 251 emitFPU(ARM::FK_VFPV2); 252 } 253 254 // ABI_HardFP_use attribute to indicate single precision FP. 255 if (STI.hasFeature(ARM::FeatureVFP2_D16_SP) && !STI.hasFeature(ARM::FeatureFP64)) 256 emitAttribute(ARMBuildAttrs::ABI_HardFP_use, 257 ARMBuildAttrs::HardFPSinglePrecision); 258 259 if (STI.hasFeature(ARM::FeatureFP16)) 260 emitAttribute(ARMBuildAttrs::FP_HP_extension, ARMBuildAttrs::AllowHPFP); 261 262 if (STI.hasFeature(ARM::FeatureMP)) 263 emitAttribute(ARMBuildAttrs::MPextension_use, ARMBuildAttrs::AllowMP); 264 265 // Hardware divide in ARM mode is part of base arch, starting from ARMv8. 266 // If only Thumb hwdiv is present, it must also be in base arch (ARMv7-R/M). 267 // It is not possible to produce DisallowDIV: if hwdiv is present in the base 268 // arch, supplying -hwdiv downgrades the effective arch, via ClearImpliedBits. 269 // AllowDIVExt is only emitted if hwdiv isn't available in the base arch; 270 // otherwise, the default value (AllowDIVIfExists) applies. 271 if (STI.hasFeature(ARM::FeatureHWDivARM) && !STI.hasFeature(ARM::HasV8Ops)) 272 emitAttribute(ARMBuildAttrs::DIV_use, ARMBuildAttrs::AllowDIVExt); 273 274 if (STI.hasFeature(ARM::FeatureDSP) && isV8M(STI)) 275 emitAttribute(ARMBuildAttrs::DSP_extension, ARMBuildAttrs::Allowed); 276 277 if (STI.hasFeature(ARM::FeatureStrictAlign)) 278 emitAttribute(ARMBuildAttrs::CPU_unaligned_access, 279 ARMBuildAttrs::Not_Allowed); 280 else 281 emitAttribute(ARMBuildAttrs::CPU_unaligned_access, 282 ARMBuildAttrs::Allowed); 283 284 if (STI.hasFeature(ARM::FeatureTrustZone) && 285 STI.hasFeature(ARM::FeatureVirtualization)) 286 emitAttribute(ARMBuildAttrs::Virtualization_use, 287 ARMBuildAttrs::AllowTZVirtualization); 288 else if (STI.hasFeature(ARM::FeatureTrustZone)) 289 emitAttribute(ARMBuildAttrs::Virtualization_use, ARMBuildAttrs::AllowTZ); 290 else if (STI.hasFeature(ARM::FeatureVirtualization)) 291 emitAttribute(ARMBuildAttrs::Virtualization_use, 292 ARMBuildAttrs::AllowVirtualization); 293 } 294