arch.c (22912B)
1 /* arch_impl_arm32: the ARM32 (ARMv7-M Thumb-2, arm-none-eabi) ArchImpl. 2 * 3 * The backend is built on the shared NativeDirectTarget/MCEmitter substrate; 4 * arch.c wires the factories, register metadata, CFI defaults, predefined 5 * macros, target features, and the intra-function Thumb-2 branch label-fixup 6 * patcher. The -march/-mcpu/-mfpu/-mfloat-abi axes resolve here: -march/-mcpu 7 * set the dsp feature (ARMv7-M baseline vs ARMv7E-M), -mfpu sets vfp/fpv5, and 8 * feature_predefines emits the matching __ARM_* macros. Soft-float v1 (the 9 * driver still rejects -mfloat-abi=hard/softfp). See doc/plan/ARM32.md. */ 10 #include "arch/arch.h" 11 12 #include <string.h> 13 14 #include "arch/arm32/arm32.h" 15 #include "arch/arm32/regs.h" 16 #include "arch/arm32/variant.h" 17 #include "cg/native_direct_target.h" 18 #include "core/bytes.h" 19 #include "core/core.h" 20 #include "core/strbuf.h" 21 #include "link/link_arch.h" 22 #include "obj/obj.h" 23 24 extern const LinkArchDesc link_arch_arm32; 25 extern const ArchDbgOps arm32_dbg_ops; 26 extern const ArchDwarfOps arm32_dwarf_ops; 27 extern const ArchDecodeOps arm32_decode_ops; 28 extern const ArchAsmOps arm32_asm_ops; 29 extern ArchAsm* arm32_arch_asm_new(Compiler*); 30 extern ArchDisasm* arm32_disasm_new(Compiler*); 31 32 static int arm32_register_at_public(uint32_t idx, KitArchReg* out) { 33 return arch_register_at_public(idx, out, arm32_register_iter_get); 34 } 35 36 static SrcLoc arm32_no_loc(void) { 37 SrcLoc l = {0, 0, 0}; 38 return l; 39 } 40 41 /* Read/write a 32-bit Thumb-2 instruction stored as two little-endian 42 * half-words (high half-word first): the returned value has hw1 in [31:16], 43 * hw2 in [15:0]. */ 44 static u32 arm_rd_t32(const u8* p) { 45 return ((u32)rd_u16_le(p) << 16) | (u32)rd_u16_le(p + 2); 46 } 47 static void arm_wr_t32(u8* p, u32 instr) { 48 wr_u16_le(p, (u16)(instr >> 16)); 49 wr_u16_le(p + 2, (u16)(instr & 0xffffu)); 50 } 51 52 /* Patch an intra-function Thumb-2 branch recorded by the MCEmitter label-fixup 53 * path: B.W (T4, R_ARM_THM_JUMP24, +-16MiB) and B<cond>.W (T3, 54 * R_ARM_THM_JUMP19, +-1MiB). fx->disp is the site-relative byte displacement 55 * (target - branch_start); the Thumb pipeline reads PC as branch_start + 4, so 56 * the encoded offset is fx->disp - 4. The opcode/cond bits the emitter wrote 57 * are preserved; only the split immediate fields are filled in. */ 58 static int arm32_apply_label_fixup(Compiler* c, const ArchLabelFixup* fx) { 59 const Section* s; 60 u8 cur[4]; 61 u32 instr; 62 i64 d; 63 64 if (!fx) return 1; 65 if (fx->width != 4) return 1; 66 s = obj_section_get(fx->obj, fx->sec_id); 67 if (!s) return 0; 68 buf_read(&s->bytes, fx->offset, cur, 4); 69 instr = arm_rd_t32(cur); 70 d = (i64)fx->disp - 4; /* Thumb PC bias */ 71 72 switch (fx->kind) { 73 case R_ARM_THM_JUMP24: { 74 u32 sbit, i1, i2, j1, j2, imm10, imm11; 75 if (d < -(i64)(1 << 24) || d >= (i64)(1 << 24)) 76 compiler_panic(c, arm32_no_loc(), "arm32: B.W out of range (+-16MiB)"); 77 sbit = (u32)((d >> 24) & 1u); 78 i1 = (u32)((d >> 23) & 1u); 79 i2 = (u32)((d >> 22) & 1u); 80 imm10 = (u32)((d >> 12) & 0x3ffu); 81 imm11 = (u32)((d >> 1) & 0x7ffu); 82 j1 = (~(i1 ^ sbit)) & 1u; 83 j2 = (~(i2 ^ sbit)) & 1u; 84 instr &= 0xf800d000u; /* keep opcode (11110), hw2[15:14]=10, hw2[12]=1 */ 85 instr |= (sbit << 26) | (imm10 << 16); 86 instr |= (j1 << 13) | (j2 << 11) | imm11; 87 break; 88 } 89 case R_ARM_THM_JUMP19: { 90 /* B<cond>.W T3: imm32 = SignExtend(S:J2:J1:imm6:imm11:0), no XOR-with-S. */ 91 u32 sbit, j1, j2, imm6, imm11; 92 if (d < -(i64)(1 << 20) || d >= (i64)(1 << 20)) 93 compiler_panic(c, arm32_no_loc(), "arm32: B.cond.W out of range (+-1MiB)"); 94 sbit = (u32)((d >> 20) & 1u); 95 j2 = (u32)((d >> 19) & 1u); 96 j1 = (u32)((d >> 18) & 1u); 97 imm6 = (u32)((d >> 12) & 0x3fu); 98 imm11 = (u32)((d >> 1) & 0x7ffu); 99 /* clear S(26), imm6(21:16), J1(13), J2(11), imm11(10:0); keep opcode, 100 * cond(25:22), hw2[15:14]=10, hw2[12]=0. */ 101 instr &= ~((1u << 26) | (0x3fu << 16) | (1u << 13) | (1u << 11) | 0x7ffu); 102 instr |= (sbit << 26) | (imm6 << 16) | (j1 << 13) | (j2 << 11) | imm11; 103 break; 104 } 105 default: 106 return 1; 107 } 108 109 arm_wr_t32(cur, instr); 110 obj_patch(fx->obj, fx->sec_id, fx->offset, cur, 4); 111 return 0; 112 } 113 114 /* The always-on base of the arm32 predefined-macro set: everything that does 115 * NOT vary with the -march/-mcpu DSP extension or the -mfpu/-mfloat-abi float 116 * configuration. Validated against 117 * `clang --target=arm-none-eabi -march=armv7-m -mfloat-abi=soft -E -dM` (and the 118 * armv7e-m / hard-float variants — see arm32_feature_predefines). The ILP32 119 * size/type macros are emitted by the preprocessor from target.ptr_size=4. 120 * 121 * The feature-keyed macros — the arch revision (__ARM_ARCH_7M__ vs 122 * __ARM_ARCH_7EM__), the DSP set, and the float set (__ARM_FP / __SOFTFP__ / 123 * __ARM_PCS_VFP / ...) — are NOT in this table; they are selected by 124 * arm32_feature_predefines from the resolved feature words + spec->float_abi. */ 125 static const KitPredefinedMacro arm32_predefined_macros[] = { 126 {KIT_SLICE_LIT("__arm__"), KIT_SLICE_LIT("1")}, 127 {KIT_SLICE_LIT("__ARMEL__"), KIT_SLICE_LIT("1")}, 128 {KIT_SLICE_LIT("__THUMBEL__"), KIT_SLICE_LIT("1")}, 129 {KIT_SLICE_LIT("__thumb__"), KIT_SLICE_LIT("1")}, 130 {KIT_SLICE_LIT("__thumb2__"), KIT_SLICE_LIT("1")}, 131 {KIT_SLICE_LIT("__THUMB_INTERWORK__"), KIT_SLICE_LIT("1")}, 132 /* arm-none-eabi is an ELF target with no symbol-name prefix; gcc/clang 133 * define both. Without them, hand-written runtime asm that branches on the 134 * object format (compiler-rt's assembly.h) falls through to the COFF path 135 * (`.def/.scl/.endef`, a leading `_`). __USER_LABEL_PREFIX__ is empty. */ 136 {KIT_SLICE_LIT("__ELF__"), KIT_SLICE_LIT("1")}, 137 {KIT_SLICE_LIT("__USER_LABEL_PREFIX__"), KIT_SLICE_LIT("")}, 138 {KIT_SLICE_LIT("__ARM_32BIT_STATE"), KIT_SLICE_LIT("1")}, 139 {KIT_SLICE_LIT("__ARM_ACLE"), KIT_SLICE_LIT("200")}, 140 {KIT_SLICE_LIT("__ARM_ARCH"), KIT_SLICE_LIT("7")}, 141 {KIT_SLICE_LIT("__ARM_ARCH_PROFILE"), KIT_SLICE_LIT("'M'")}, 142 {KIT_SLICE_LIT("__ARM_ARCH_ISA_THUMB"), KIT_SLICE_LIT("2")}, 143 {KIT_SLICE_LIT("__ARM_ARCH_ISA_ARM"), KIT_SLICE_LIT("0")}, 144 {KIT_SLICE_LIT("__ARM_EABI__"), KIT_SLICE_LIT("1")}, 145 {KIT_SLICE_LIT("__ARM_PCS"), KIT_SLICE_LIT("1")}, 146 {KIT_SLICE_LIT("__ARM_FEATURE_CLZ"), KIT_SLICE_LIT("1")}, 147 {KIT_SLICE_LIT("__ARM_FEATURE_QBIT"), KIT_SLICE_LIT("1")}, 148 {KIT_SLICE_LIT("__ARM_FEATURE_SAT"), KIT_SLICE_LIT("1")}, 149 {KIT_SLICE_LIT("__ARM_FEATURE_UNALIGNED"), KIT_SLICE_LIT("1")}, 150 {KIT_SLICE_LIT("__ARM_FEATURE_LDREX"), KIT_SLICE_LIT("0x7")}, 151 {KIT_SLICE_LIT("__ARM_FEATURE_COPROC"), KIT_SLICE_LIT("0xf")}, 152 {KIT_SLICE_LIT("__ARM_FEATURE_IDIV"), KIT_SLICE_LIT("1")}, 153 {KIT_SLICE_LIT("__ARM_ARCH_EXT_IDIV__"), KIT_SLICE_LIT("1")}, 154 {KIT_SLICE_LIT("__ARM_FP16_FORMAT_IEEE"), KIT_SLICE_LIT("1")}, 155 {KIT_SLICE_LIT("__ARM_FP16_ARGS"), KIT_SLICE_LIT("1")}, 156 {KIT_SLICE_LIT("__ARM_SIZEOF_WCHAR_T"), KIT_SLICE_LIT("4")}, 157 {KIT_SLICE_LIT("__ARM_SIZEOF_MINIMAL_ENUM"), KIT_SLICE_LIT("4")}, 158 /* __VFP_FP__ denotes the VFP *number format* (IEEE-754, little-endian word 159 * order), not FPU presence; clang/gcc define it even on soft-float. */ 160 {KIT_SLICE_LIT("__VFP_FP__"), KIT_SLICE_LIT("1")}, 161 {KIT_SLICE_LIT("__ORDER_LITTLE_ENDIAN__"), KIT_SLICE_LIT("1234")}, 162 {KIT_SLICE_LIT("__ORDER_BIG_ENDIAN__"), KIT_SLICE_LIT("4321")}, 163 {KIT_SLICE_LIT("__BYTE_ORDER__"), KIT_SLICE_LIT("__ORDER_LITTLE_ENDIAN__")}, 164 {KIT_SLICE_LIT("__LITTLE_ENDIAN__"), KIT_SLICE_LIT("1")}, 165 }; 166 167 /* Feature-word indices — MUST match arm32_target_features[] order below. */ 168 enum { 169 ARM32_FEAT_DSP = 0, /* ARMv7E-M saturating + packed-SIMD (the DSP extension) */ 170 ARM32_FEAT_VFP = 1, /* VFP present (FPv4-SP, Cortex-M4F) */ 171 ARM32_FEAT_FPV5 = 2, /* FPv5 (Cortex-M7) — implies VFP */ 172 }; 173 174 static const ArchTargetFeature arm32_target_features[] = { 175 {"dsp"}, 176 {"vfp"}, 177 {"fpv5"}, 178 }; 179 180 static void arm32_feature_set(u64* words, u32 nwords, u32 idx) { 181 if (!words || idx / 64u >= nwords) return; 182 words[idx / 64u] |= 1ull << (idx % 64u); 183 } 184 185 static void arm32_feature_clear(u64* words, u32 nwords, u32 idx) { 186 if (!words || idx / 64u >= nwords) return; 187 words[idx / 64u] &= ~(1ull << (idx % 64u)); 188 } 189 190 static int arm32_feature_get(const u64* words, u32 nwords, u32 idx) { 191 if (!words || idx / 64u >= nwords) return 0; 192 return (words[idx / 64u] & (1ull << (idx % 64u))) != 0; 193 } 194 195 static void arm32_target_feature_defaults(const Target* t, u64* words, 196 u32 nwords) { 197 (void)t; 198 (void)words; 199 (void)nwords; /* baseline ARMv7-M (Cortex-M3) soft: no features default-on. */ 200 } 201 202 /* -march= profile -> the DSP feature bit. armv7-m / thumbv7m is the ARMv7-M 203 * baseline (no DSP); armv7e-m / thumbv7em is ARMv7E-M (DSP). The FP features 204 * come from -mfpu= (an explicit feature), not -march=. */ 205 static KitStatus arm32_target_feature_apply_isa(const Target* t, KitSlice isa, 206 u64* words, u32 nwords) { 207 (void)t; 208 if (kit_slice_eq_cstr(isa, "armv7-m") || kit_slice_eq_cstr(isa, "thumbv7m")) { 209 arm32_feature_clear(words, nwords, ARM32_FEAT_DSP); 210 return KIT_OK; 211 } 212 if (kit_slice_eq_cstr(isa, "armv7e-m") || 213 kit_slice_eq_cstr(isa, "thumbv7em")) { 214 arm32_feature_set(words, nwords, ARM32_FEAT_DSP); 215 return KIT_OK; 216 } 217 return KIT_UNSUPPORTED; 218 } 219 220 /* -mcpu= core -> ISA profile (the DSP bit). cortex-m3 is ARMv7-M (no DSP); 221 * cortex-m4/m4f/m7/m7f are ARMv7E-M (DSP). The trailing 'f' selects an FPU 222 * (hard-float, a follow-on) — it does not change the integer/DSP profile, and 223 * the FP features still arrive via -mfpu=, so cortex-m4 and cortex-m4f resolve 224 * the same DSP bit here. */ 225 static KitStatus arm32_target_feature_apply_cpu(const Target* t, KitSlice cpu, 226 u64* words, u32 nwords) { 227 (void)t; 228 if (kit_slice_eq_cstr(cpu, "cortex-m3")) { 229 arm32_feature_clear(words, nwords, ARM32_FEAT_DSP); 230 return KIT_OK; 231 } 232 if (kit_slice_eq_cstr(cpu, "cortex-m4") || 233 kit_slice_eq_cstr(cpu, "cortex-m4f") || 234 kit_slice_eq_cstr(cpu, "cortex-m7") || 235 kit_slice_eq_cstr(cpu, "cortex-m7f")) { 236 arm32_feature_set(words, nwords, ARM32_FEAT_DSP); 237 return KIT_OK; 238 } 239 return KIT_UNSUPPORTED; 240 } 241 242 /* Resolve & validate spec->float_abi for arm-none-eabi. 243 * (empty) / "soft" -> SOFT (no FPU; float/double via AEABI helpers). 244 * "softfp" / "hard" -> SINGLE (FPv4-SP / FPv5 single-precision hard-float), 245 * requiring a VFP/FPV5 feature (else KIT_INVALID). 246 * SOFT gates the arch-neutral soft-float lowering in src/cg/arith.c 247 * (api_target_has_no_hw_double). The driver still rejects -mfloat-abi=hard/softfp 248 * (hard-float codegen is a separate work item), so the non-SOFT branches are 249 * written and unit-testable at the kit_target_new API level but unreachable via 250 * the CLI today. `double` stays soft on FPv4-SP (the FPV5 axis would extend 251 * this), mirroring rv32 ilp32f. */ 252 static KitStatus arm32_resolve_float_abi(const ArchImpl* impl, 253 KitTargetSpec* spec, 254 const u64* feature_words, 255 u32 nfeature_words, KitSlice abi, 256 char* err, size_t errcap) { 257 StrBuf sb; 258 int has_vfp; 259 strbuf_init(&sb, err, errcap); 260 has_vfp = arm32_feature_get(feature_words, nfeature_words, ARM32_FEAT_VFP) || 261 arm32_feature_get(feature_words, nfeature_words, ARM32_FEAT_FPV5); 262 263 if (!abi.s || abi.len == 0 || kit_slice_eq_cstr(abi, "soft")) { 264 if (spec) spec->float_abi = (uint8_t)KIT_FLOAT_ABI_SOFT; 265 return KIT_OK; 266 } 267 if (kit_slice_eq_cstr(abi, "softfp") || kit_slice_eq_cstr(abi, "hard")) { 268 if (!has_vfp) { 269 strbuf_puts(&sb, "hardware float ABI ("); 270 strbuf_put_slice(&sb, abi); 271 strbuf_puts(&sb, ") requires an FPU (-mfpu=fpv4-sp-d16 / fpv5-d16) for "); 272 strbuf_puts(&sb, impl->name); 273 return KIT_INVALID; 274 } 275 if (spec) spec->float_abi = (uint8_t)KIT_FLOAT_ABI_SINGLE; 276 return KIT_OK; 277 } 278 strbuf_puts(&sb, "unsupported float ABI for "); 279 strbuf_puts(&sb, impl->name); 280 strbuf_puts(&sb, ": "); 281 strbuf_put_slice(&sb, abi); 282 return KIT_INVALID; 283 } 284 285 /* ---- Feature-keyed predefined macros ------------------------------------- 286 * Each discrete {arch-rev} x {float-config} combination is a fully precomputed 287 * `static const` table; the hook selects exactly one and returns it (no mutable 288 * state — same rodata-table contract as arm32_predefined_macros). Validated 289 * against host clang (see arm32_predefined_macros). 290 * 291 * Arch revision is mutually exclusive on the DSP bit: no-DSP -> __ARM_ARCH_7M__; 292 * DSP -> __ARM_ARCH_7EM__ + __ARM_FEATURE_DSP + __ARM_FEATURE_SIMD32. 293 * 294 * Float config keys on float_abi + (vfp | fpv5). SOFT defines only __SOFTFP__ 295 * and leaves __ARM_FP UNDEFINED (so `#ifdef __ARM_FP` selects the integer path — 296 * e.g. the coro asm skips the d8..d15 VFP saves). A resolved hardware ABI 297 * defines __ARM_FP + __ARM_FEATURE_FMA + __ARM_PCS_VFP + the legacy 298 * __ARM_VFPV2/3/4__ aliases; FPV5 (Cortex-M7) raises __ARM_FP to 0xe and adds 299 * __ARM_FPV5__. */ 300 301 /* macros: __ARM_ARCH_7M__ */ 302 static const KitPredefinedMacro arm32_macros_7m_soft[] = { 303 {KIT_SLICE_LIT("__ARM_ARCH_7M__"), KIT_SLICE_LIT("1")}, 304 {KIT_SLICE_LIT("__SOFTFP__"), KIT_SLICE_LIT("1")}, 305 }; 306 static const KitPredefinedMacro arm32_macros_7m_v4hard[] = { 307 {KIT_SLICE_LIT("__ARM_ARCH_7M__"), KIT_SLICE_LIT("1")}, 308 {KIT_SLICE_LIT("__ARM_FP"), KIT_SLICE_LIT("0x6")}, 309 {KIT_SLICE_LIT("__ARM_FEATURE_FMA"), KIT_SLICE_LIT("1")}, 310 {KIT_SLICE_LIT("__ARM_VFPV2__"), KIT_SLICE_LIT("1")}, 311 {KIT_SLICE_LIT("__ARM_VFPV3__"), KIT_SLICE_LIT("1")}, 312 {KIT_SLICE_LIT("__ARM_VFPV4__"), KIT_SLICE_LIT("1")}, 313 {KIT_SLICE_LIT("__ARM_PCS_VFP"), KIT_SLICE_LIT("1")}, 314 }; 315 static const KitPredefinedMacro arm32_macros_7m_v5hard[] = { 316 {KIT_SLICE_LIT("__ARM_ARCH_7M__"), KIT_SLICE_LIT("1")}, 317 {KIT_SLICE_LIT("__ARM_FP"), KIT_SLICE_LIT("0xe")}, 318 {KIT_SLICE_LIT("__ARM_FEATURE_FMA"), KIT_SLICE_LIT("1")}, 319 {KIT_SLICE_LIT("__ARM_FPV5__"), KIT_SLICE_LIT("1")}, 320 {KIT_SLICE_LIT("__ARM_VFPV2__"), KIT_SLICE_LIT("1")}, 321 {KIT_SLICE_LIT("__ARM_VFPV3__"), KIT_SLICE_LIT("1")}, 322 {KIT_SLICE_LIT("__ARM_VFPV4__"), KIT_SLICE_LIT("1")}, 323 {KIT_SLICE_LIT("__ARM_PCS_VFP"), KIT_SLICE_LIT("1")}, 324 }; 325 326 /* macros: __ARM_ARCH_7EM__ + DSP */ 327 static const KitPredefinedMacro arm32_macros_7em_soft[] = { 328 {KIT_SLICE_LIT("__ARM_ARCH_7EM__"), KIT_SLICE_LIT("1")}, 329 {KIT_SLICE_LIT("__ARM_FEATURE_DSP"), KIT_SLICE_LIT("1")}, 330 {KIT_SLICE_LIT("__ARM_FEATURE_SIMD32"), KIT_SLICE_LIT("1")}, 331 {KIT_SLICE_LIT("__SOFTFP__"), KIT_SLICE_LIT("1")}, 332 }; 333 static const KitPredefinedMacro arm32_macros_7em_v4hard[] = { 334 {KIT_SLICE_LIT("__ARM_ARCH_7EM__"), KIT_SLICE_LIT("1")}, 335 {KIT_SLICE_LIT("__ARM_FEATURE_DSP"), KIT_SLICE_LIT("1")}, 336 {KIT_SLICE_LIT("__ARM_FEATURE_SIMD32"), KIT_SLICE_LIT("1")}, 337 {KIT_SLICE_LIT("__ARM_FP"), KIT_SLICE_LIT("0x6")}, 338 {KIT_SLICE_LIT("__ARM_FEATURE_FMA"), KIT_SLICE_LIT("1")}, 339 {KIT_SLICE_LIT("__ARM_VFPV2__"), KIT_SLICE_LIT("1")}, 340 {KIT_SLICE_LIT("__ARM_VFPV3__"), KIT_SLICE_LIT("1")}, 341 {KIT_SLICE_LIT("__ARM_VFPV4__"), KIT_SLICE_LIT("1")}, 342 {KIT_SLICE_LIT("__ARM_PCS_VFP"), KIT_SLICE_LIT("1")}, 343 }; 344 static const KitPredefinedMacro arm32_macros_7em_v5hard[] = { 345 {KIT_SLICE_LIT("__ARM_ARCH_7EM__"), KIT_SLICE_LIT("1")}, 346 {KIT_SLICE_LIT("__ARM_FEATURE_DSP"), KIT_SLICE_LIT("1")}, 347 {KIT_SLICE_LIT("__ARM_FEATURE_SIMD32"), KIT_SLICE_LIT("1")}, 348 {KIT_SLICE_LIT("__ARM_FP"), KIT_SLICE_LIT("0xe")}, 349 {KIT_SLICE_LIT("__ARM_FEATURE_FMA"), KIT_SLICE_LIT("1")}, 350 {KIT_SLICE_LIT("__ARM_FPV5__"), KIT_SLICE_LIT("1")}, 351 {KIT_SLICE_LIT("__ARM_VFPV2__"), KIT_SLICE_LIT("1")}, 352 {KIT_SLICE_LIT("__ARM_VFPV3__"), KIT_SLICE_LIT("1")}, 353 {KIT_SLICE_LIT("__ARM_VFPV4__"), KIT_SLICE_LIT("1")}, 354 {KIT_SLICE_LIT("__ARM_PCS_VFP"), KIT_SLICE_LIT("1")}, 355 }; 356 357 static u32 arm32_feature_predefines(const ArchImpl* impl, 358 const KitTargetSpec* spec, const u64* words, 359 u32 nwords, const KitPredefinedMacro** out) { 360 int dsp = arm32_feature_get(words, nwords, ARM32_FEAT_DSP); 361 int vfp = arm32_feature_get(words, nwords, ARM32_FEAT_VFP); 362 int fpv5 = arm32_feature_get(words, nwords, ARM32_FEAT_FPV5); 363 KitFloatAbi fa = spec ? (KitFloatAbi)spec->float_abi : KIT_FLOAT_ABI_SOFT; 364 /* Hardware float = a resolved single/double ABI with a VFP feature present. 365 * kit's KitFloatAbi has no distinct softfp encoding, so a resolved hardware 366 * ABI follows the hard-float macro convention (__ARM_PCS_VFP). FPV5 raises the 367 * profile. With no VFP feature or an unresolved/soft ABI, the float set is 368 * soft (__SOFTFP__, __ARM_FP undefined). */ 369 int hardfp = 370 (fa == KIT_FLOAT_ABI_SINGLE || fa == KIT_FLOAT_ABI_DOUBLE) && (vfp || fpv5); 371 (void)impl; 372 373 if (!dsp) { 374 if (!hardfp) { 375 *out = arm32_macros_7m_soft; 376 return (u32)(sizeof arm32_macros_7m_soft / sizeof arm32_macros_7m_soft[0]); 377 } 378 if (fpv5) { 379 *out = arm32_macros_7m_v5hard; 380 return (u32)(sizeof arm32_macros_7m_v5hard / 381 sizeof arm32_macros_7m_v5hard[0]); 382 } 383 *out = arm32_macros_7m_v4hard; 384 return (u32)(sizeof arm32_macros_7m_v4hard / sizeof arm32_macros_7m_v4hard[0]); 385 } 386 if (!hardfp) { 387 *out = arm32_macros_7em_soft; 388 return (u32)(sizeof arm32_macros_7em_soft / sizeof arm32_macros_7em_soft[0]); 389 } 390 if (fpv5) { 391 *out = arm32_macros_7em_v5hard; 392 return (u32)(sizeof arm32_macros_7em_v5hard / 393 sizeof arm32_macros_7em_v5hard[0]); 394 } 395 *out = arm32_macros_7em_v4hard; 396 return (u32)(sizeof arm32_macros_7em_v4hard / 397 sizeof arm32_macros_7em_v4hard[0]); 398 } 399 400 static int arm32_supports_call_conv(const Compiler* c, KitCgCallConv cc) { 401 (void)c; 402 return cc == KIT_CG_CC_TARGET_C; 403 } 404 405 /* Kept in lockstep with arm_intrinsic in native.c: returning 1 for an 406 * intrinsic this backend does not lower panics at emit. No default: case so 407 * -Wswitch enforces the twin-sync invariant. Lowered: TRAP, CLZ, CTZ (RBIT+CLZ), 408 * BSWAP (REV/REV16; the 64-bit form is a __bswapdi2 libcall in cg), the no-op / 409 * event hints (NOP/YIELD/WFI/WFE/SEV), and the barriers (DMB/DSB/ISB). POPCOUNT, 410 * the overflow forms, FMA, syscall/setjmp, IRQ/cache ops are other tracks. */ 411 static int arm32_supports_intrinsic(const Compiler* c, KitCgIntrinsic intrin) { 412 (void)c; 413 switch (intrin) { 414 case KIT_CG_INTRIN_TRAP: 415 case KIT_CG_INTRIN_CLZ: 416 case KIT_CG_INTRIN_CTZ: 417 case KIT_CG_INTRIN_BSWAP: 418 case KIT_CG_INTRIN_CPU_NOP: 419 case KIT_CG_INTRIN_CPU_YIELD: 420 case KIT_CG_INTRIN_ISB: 421 case KIT_CG_INTRIN_DMB: 422 case KIT_CG_INTRIN_DSB: 423 case KIT_CG_INTRIN_WFI: 424 case KIT_CG_INTRIN_WFE: 425 case KIT_CG_INTRIN_SEV: 426 case KIT_CG_INTRIN_SADD_OVERFLOW: 427 case KIT_CG_INTRIN_UADD_OVERFLOW: 428 case KIT_CG_INTRIN_SSUB_OVERFLOW: 429 case KIT_CG_INTRIN_USUB_OVERFLOW: 430 case KIT_CG_INTRIN_SMUL_OVERFLOW: 431 case KIT_CG_INTRIN_UMUL_OVERFLOW: 432 case KIT_CG_INTRIN_FRAME_ADDRESS: 433 case KIT_CG_INTRIN_RETURN_ADDRESS: 434 case KIT_CG_INTRIN_POPCOUNT: 435 case KIT_CG_INTRIN_PREFETCH: 436 case KIT_CG_INTRIN_EXPECT: 437 case KIT_CG_INTRIN_ASSUME_ALIGNED: 438 case KIT_CG_INTRIN_SMUL_HIGH: 439 case KIT_CG_INTRIN_UMUL_HIGH: 440 return 1; 441 case KIT_CG_INTRIN_READCYCLECOUNTER: 442 case KIT_CG_INTRIN_SYSCALL: 443 case KIT_CG_INTRIN_SETJMP: 444 case KIT_CG_INTRIN_LONGJMP: 445 case KIT_CG_INTRIN_FMA: 446 case KIT_CG_INTRIN_IRQ_SAVE: 447 case KIT_CG_INTRIN_IRQ_RESTORE: 448 case KIT_CG_INTRIN_IRQ_DISABLE: 449 case KIT_CG_INTRIN_IRQ_ENABLE: 450 case KIT_CG_INTRIN_DCACHE_CLEAN: 451 case KIT_CG_INTRIN_DCACHE_INVALIDATE: 452 case KIT_CG_INTRIN_DCACHE_CLEAN_INVALIDATE: 453 case KIT_CG_INTRIN_ICACHE_INVALIDATE: 454 case KIT_CG_INTRIN_CORO_SWITCH: 455 return 0; 456 } 457 return 0; 458 } 459 460 static CgTarget* arm32_backend_make(Compiler* c, ObjBuilder* o, 461 const KitCodeOptions* opts) { 462 return native_direct_backend_make(c, o, opts, arm32_native_target_new, 463 arm32_native_direct_ops()); 464 } 465 466 static CgTarget* arm32_semantic_target_new(Compiler* c, ObjBuilder* o, 467 MCEmitter* mc) { 468 return native_direct_semantic_target_new(c, o, mc, arm32_native_target_new, 469 arm32_native_direct_ops()); 470 } 471 472 const ArchImpl arch_impl_arm32 = { 473 .backend = {.name = "arm32", .make = arm32_backend_make}, 474 .kind = KIT_ARCH_ARM_32, 475 .name = "arm32", 476 .cgtarget_new = arm32_semantic_target_new, 477 .asm_new = arm32_arch_asm_new, 478 .disasm_new = arm32_disasm_new, 479 .apply_label_fixup = arm32_apply_label_fixup, 480 .decode = &arm32_decode_ops, 481 /* .emu omitted (NULL) — no emu lifter for arm32 yet (like aa64/x64). */ 482 .link = &link_arch_arm32, 483 .dwarf = &arm32_dwarf_ops, 484 .dbg = &arm32_dbg_ops, 485 .asm_ops = &arm32_asm_ops, 486 .predefined_macros = arm32_predefined_macros, 487 .npredefined_macros = 488 (u32)(sizeof arm32_predefined_macros / sizeof arm32_predefined_macros[0]), 489 .target_features = arm32_target_features, 490 .ntarget_features = 491 (u32)(sizeof arm32_target_features / sizeof arm32_target_features[0]), 492 .target_feature_defaults = arm32_target_feature_defaults, 493 .target_feature_apply_isa = arm32_target_feature_apply_isa, 494 .target_feature_apply_cpu = arm32_target_feature_apply_cpu, 495 .register_name = arm32_register_name, 496 .register_index = arm32_register_index, 497 .register_count = arm32_register_iter_size, 498 .register_at = arm32_register_at_public, 499 /* AAPCS32 / Thumb-2: LR = r14, SP = r13 (legacy AArch32 DWARF numbering). 500 * 2-byte minimum insn width -> code_align 2; word stack stride -> 501 * data_align -4. CFA = sp at entry. */ 502 .cfi_return_addr_reg = 14u, 503 .cfi_code_align_factor = 2, 504 .cfi_data_align_factor = -4, 505 .cfi_cfa_init_reg = 13u, 506 .cfi_cfa_init_offset = 0, 507 .backend_features = KIT_CG_BACKEND_STRICT_ALIGNMENT, 508 .atomic_lock_free_max = 4u, /* no LDREXD/STREXD on M-profile -> 8B spinlock */ 509 .supports_call_conv = arm32_supports_call_conv, 510 .supports_intrinsic = arm32_supports_intrinsic, 511 /* float_abi resolves to SOFT unless an FPU feature + a hardware ABI is set 512 * (gates cg soft-float). The driver still rejects -mfloat-abi=hard/softfp. */ 513 .resolve_float_abi = arm32_resolve_float_abi, 514 /* arm32 folds its float macros into feature_predefines (it has both the 515 * feature words and spec->float_abi there), so float_predefines stays NULL. 516 * feature_predefines selects __ARM_ARCH_7M__/7EM__ + DSP + the float set. */ 517 .feature_predefines = arm32_feature_predefines, 518 };