arch.c (23984B)
1 #include "arch/arch.h" 2 3 #include <string.h> 4 5 #include "arch/riscv/asm.h" 6 #include "arch/riscv/disasm.h" 7 #include "arch/riscv/regs.h" 8 #include "arch/riscv/rv64.h" 9 #include "arch/riscv/variant.h" 10 #include "cg/native_direct_target.h" 11 #include "core/bytes.h" 12 #include "core/strbuf.h" 13 #include "link/link_arch.h" 14 #include "obj/obj.h" 15 16 extern const LinkArchDesc link_arch_rv64; 17 extern const ArchDbgOps rv64_dbg_ops; 18 extern const ArchEmuOps rv64_emu_ops; 19 extern const ArchDwarfOps rv64_dwarf_ops; 20 extern const ArchAsmOps rv64_asm_ops; 21 extern const LinkArchDesc link_arch_rv32; 22 extern const ArchDbgOps rv32_dbg_ops; 23 24 static int rv64_register_at_public(uint32_t idx, KitArchReg* out) { 25 return arch_register_at_public(idx, out, rv64_register_iter_get); 26 } 27 28 static SrcLoc rv64_no_loc(void) { 29 SrcLoc l = {0, 0, 0}; 30 return l; 31 } 32 33 static int rv64_apply_label_fixup(Compiler* c, const ArchLabelFixup* fx) { 34 const Section* s; 35 u8 cur[4]; 36 u32 word; 37 u32 b; 38 39 (void)c; 40 if (!fx) return 1; 41 s = obj_section_get(fx->obj, fx->sec_id); 42 if (!s) return 0; 43 44 /* INTRA_AUIPC_ADDI is a width=8 pair; other kinds patch a single 4-byte 45 * instruction. Read the first word only for the 4-byte cases. */ 46 if (fx->kind != R_RV_INTRA_AUIPC_ADDI) { 47 if (fx->width != 4) return 1; 48 buf_read(&s->bytes, fx->offset, cur, 4); 49 word = rd_u32_le(cur); 50 } else { 51 buf_read(&s->bytes, fx->offset, cur, 4); 52 word = rd_u32_le(cur); 53 } 54 b = (u32)fx->disp; 55 56 switch (fx->kind) { 57 case R_RV_BRANCH: 58 /* B-type reaches ±4 KiB. Conditional branches are emitted over a jal 59 * (see rv_cmp_branch) so this only carries small fixed displacements; 60 * a violation is a backend bug, not silently-truncated code. */ 61 if ((i64)fx->disp < -(i64)(1 << 12) || (i64)fx->disp >= (i64)(1 << 12)) 62 compiler_panic(c, rv64_no_loc(), "rv64: BRANCH out of range (±4KiB)"); 63 word &= 0x01fff07fu; 64 word |= ((b >> 12) & 1u) << 31; 65 word |= ((b >> 5) & 0x3fu) << 25; 66 word |= ((b >> 1) & 0xfu) << 8; 67 word |= ((b >> 11) & 1u) << 7; 68 break; 69 case R_RV_JAL: 70 /* J-type reaches ±1 MiB — ample for intra-function jumps (including the 71 * long leg of a conditional branch). Fail loudly rather than wrap. */ 72 if ((i64)fx->disp < -(i64)(1 << 20) || (i64)fx->disp >= (i64)(1 << 20)) 73 compiler_panic(c, rv64_no_loc(), "rv64: JAL out of range (±1MiB)"); 74 word &= 0x00000fffu; 75 word |= ((b >> 20) & 1u) << 31; 76 word |= ((b >> 1) & 0x3ffu) << 21; 77 word |= ((b >> 11) & 1u) << 20; 78 word |= ((b >> 12) & 0xffu) << 12; 79 break; 80 case R_RV_INTRA_AUIPC_ADDI: { 81 /* width=8: patch both the AUIPC at fx->offset and the ADDI at 82 * fx->offset+4. disp is the byte offset from the AUIPC PC to the 83 * target label. */ 84 u8 cur2[4]; 85 u32 word2; 86 i32 disp = (i32)fx->disp; 87 /* hi20 is the top 20 bits of (disp + 0x800) so the sign-extended 88 * 12-bit lo12 cancels out. */ 89 u32 hi20 = (u32)((disp + 0x800) >> 12) & 0xfffffu; 90 u32 lo12 = (u32)disp & 0xfffu; 91 if (fx->width != 8) return 1; 92 /* AUIPC: keep rd (bits 11:7) and opcode (bits 6:0); patch imm[31:12]. */ 93 word = (word & 0x00000fffu) | (hi20 << 12); 94 wr_u32_le(cur, word); 95 obj_patch(fx->obj, fx->sec_id, fx->offset, cur, 4); 96 buf_read(&s->bytes, fx->offset + 4, cur2, 4); 97 word2 = rd_u32_le(cur2); 98 /* ADDI: keep rs1/funct3/rd/opcode (bits 19:0); patch imm[11:0]. */ 99 word2 = (word2 & 0x000fffffu) | (lo12 << 20); 100 wr_u32_le(cur2, word2); 101 obj_patch(fx->obj, fx->sec_id, fx->offset + 4, cur2, 4); 102 return 0; 103 } 104 default: 105 return 1; 106 } 107 108 wr_u32_le(cur, word); 109 obj_patch(fx->obj, fx->sec_id, fx->offset, cur, 4); 110 return 0; 111 } 112 113 /* Mirrors `clang --target=riscv64-linux-gnu -E -dM` for the in-scope 114 * RV64GC profile: I/M/F/D/A/C + Zicsr-minimal. Macros that depend on 115 * extensions outside scope (V, B, Zve*, Zfh, …) are deliberately 116 * absent. The float-ABI-dependent macros (__riscv_float_abi_*, __riscv_flen, 117 * __riscv_fdiv, __riscv_fsqrt) are emitted per resolved float_abi by 118 * rv64_float_predefines, not baked here — see that hook. Default ABI is lp64d. */ 119 static const KitPredefinedMacro rv64_predefined_macros[] = { 120 {KIT_SLICE_LIT("__riscv"), KIT_SLICE_LIT("1")}, 121 {KIT_SLICE_LIT("__riscv_xlen"), KIT_SLICE_LIT("64")}, 122 {KIT_SLICE_LIT("__riscv_atomic"), KIT_SLICE_LIT("1")}, 123 {KIT_SLICE_LIT("__riscv_mul"), KIT_SLICE_LIT("1")}, 124 {KIT_SLICE_LIT("__riscv_div"), KIT_SLICE_LIT("1")}, 125 {KIT_SLICE_LIT("__riscv_muldiv"), KIT_SLICE_LIT("1")}, 126 {KIT_SLICE_LIT("__riscv_compressed"), KIT_SLICE_LIT("1")}, 127 {KIT_SLICE_LIT("__riscv_zicsr"), KIT_SLICE_LIT("1")}, 128 {KIT_SLICE_LIT("__riscv_zifencei"), KIT_SLICE_LIT("1")}, 129 {KIT_SLICE_LIT("__riscv_arch_test"), KIT_SLICE_LIT("1")}, 130 {KIT_SLICE_LIT("__LP64__"), KIT_SLICE_LIT("1")}, 131 {KIT_SLICE_LIT("_LP64"), KIT_SLICE_LIT("1")}, 132 {KIT_SLICE_LIT("__ORDER_LITTLE_ENDIAN__"), KIT_SLICE_LIT("1234")}, 133 {KIT_SLICE_LIT("__ORDER_BIG_ENDIAN__"), KIT_SLICE_LIT("4321")}, 134 {KIT_SLICE_LIT("__BYTE_ORDER__"), KIT_SLICE_LIT("__ORDER_LITTLE_ENDIAN__")}, 135 {KIT_SLICE_LIT("__LITTLE_ENDIAN__"), KIT_SLICE_LIT("1")}, 136 }; 137 138 /* Mirrors `clang --target=riscv32-linux-gnu -march=rv32imac_zicsr_zifencei 139 * -mabi=ilp32 -E -dM` for the DEFAULT ilp32 SOFT-float MCU profile: 140 * I/M/A/C + Zicsr-minimal, no hardware float. __ILP32__/_ILP32 replace 141 * __LP64__/_LP64. 142 * 143 * The float-ABI-dependent macros (__riscv_float_abi_*, __riscv_flen, 144 * __riscv_fdiv, __riscv_fsqrt) are NOT baked here: a static table can encode 145 * only one float profile, but rv32 supports soft (ilp32, the default), single 146 * (ilp32f) and a soft-double layout, and the preprocessor must agree with the 147 * codegen ABI (rt/lib/coro keys on __riscv_flen). rv64_float_predefines emits 148 * them per resolved c->target.float_abi instead — shared by rv32 and rv64. */ 149 static const KitPredefinedMacro rv32_predefined_macros[] = { 150 {KIT_SLICE_LIT("__riscv"), KIT_SLICE_LIT("1")}, 151 {KIT_SLICE_LIT("__riscv_xlen"), KIT_SLICE_LIT("32")}, 152 {KIT_SLICE_LIT("__riscv_atomic"), KIT_SLICE_LIT("1")}, 153 {KIT_SLICE_LIT("__riscv_mul"), KIT_SLICE_LIT("1")}, 154 {KIT_SLICE_LIT("__riscv_div"), KIT_SLICE_LIT("1")}, 155 {KIT_SLICE_LIT("__riscv_muldiv"), KIT_SLICE_LIT("1")}, 156 {KIT_SLICE_LIT("__riscv_compressed"), KIT_SLICE_LIT("1")}, 157 {KIT_SLICE_LIT("__riscv_zicsr"), KIT_SLICE_LIT("1")}, 158 {KIT_SLICE_LIT("__riscv_zifencei"), KIT_SLICE_LIT("1")}, 159 {KIT_SLICE_LIT("__riscv_arch_test"), KIT_SLICE_LIT("1")}, 160 {KIT_SLICE_LIT("__ILP32__"), KIT_SLICE_LIT("1")}, 161 {KIT_SLICE_LIT("_ILP32"), KIT_SLICE_LIT("1")}, 162 {KIT_SLICE_LIT("__ORDER_LITTLE_ENDIAN__"), KIT_SLICE_LIT("1234")}, 163 {KIT_SLICE_LIT("__ORDER_BIG_ENDIAN__"), KIT_SLICE_LIT("4321")}, 164 {KIT_SLICE_LIT("__BYTE_ORDER__"), KIT_SLICE_LIT("__ORDER_LITTLE_ENDIAN__")}, 165 {KIT_SLICE_LIT("__LITTLE_ENDIAN__"), KIT_SLICE_LIT("1")}, 166 }; 167 168 enum { 169 RV64_FEAT_I = 0, 170 RV64_FEAT_M, 171 RV64_FEAT_A, 172 RV64_FEAT_F, 173 RV64_FEAT_D, 174 RV64_FEAT_C, 175 RV64_FEAT_ZICSR, 176 RV64_FEAT_ZIFENCEI, 177 }; 178 179 static const ArchTargetFeature rv64_target_features[] = { 180 {"i"}, {"m"}, {"a"}, {"f"}, {"d"}, {"c"}, {"zicsr"}, {"zifencei"}, 181 }; 182 183 static void rv64_feature_set(u64* words, u32 nwords, u32 idx) { 184 if (!words || idx / 64u >= nwords) return; 185 words[idx / 64u] |= 1ull << (idx % 64u); 186 } 187 188 static void rv64_feature_clear(u64* words, u32 nwords, u32 idx) { 189 if (!words || idx / 64u >= nwords) return; 190 words[idx / 64u] &= ~(1ull << (idx % 64u)); 191 } 192 193 static void rv64_feature_disable_all(u64* words, u32 nwords) { 194 rv64_feature_clear(words, nwords, RV64_FEAT_I); 195 rv64_feature_clear(words, nwords, RV64_FEAT_M); 196 rv64_feature_clear(words, nwords, RV64_FEAT_A); 197 rv64_feature_clear(words, nwords, RV64_FEAT_F); 198 rv64_feature_clear(words, nwords, RV64_FEAT_D); 199 rv64_feature_clear(words, nwords, RV64_FEAT_C); 200 rv64_feature_clear(words, nwords, RV64_FEAT_ZICSR); 201 rv64_feature_clear(words, nwords, RV64_FEAT_ZIFENCEI); 202 } 203 204 static void rv64_feature_enable_g(u64* words, u32 nwords) { 205 rv64_feature_set(words, nwords, RV64_FEAT_I); 206 rv64_feature_set(words, nwords, RV64_FEAT_M); 207 rv64_feature_set(words, nwords, RV64_FEAT_A); 208 rv64_feature_set(words, nwords, RV64_FEAT_F); 209 rv64_feature_set(words, nwords, RV64_FEAT_D); 210 rv64_feature_set(words, nwords, RV64_FEAT_ZICSR); 211 rv64_feature_set(words, nwords, RV64_FEAT_ZIFENCEI); 212 } 213 214 static int rv64_has_prefix(const char* p, const char* end, const char* lit) { 215 size_t n = strlen(lit); 216 return (size_t)(end - p) >= n && memcmp(p, lit, n) == 0; 217 } 218 219 static void rv64_skip_version(const char** pp, const char* end) { 220 const char* p = *pp; 221 while (p < end && ((*p >= '0' && *p <= '9') || *p == 'p')) ++p; 222 *pp = p; 223 } 224 225 static KitStatus rv64_target_feature_apply_isa(const Target* target, 226 KitSlice isa, u64* words, 227 u32 nwords) { 228 const char* p; 229 const char* end; 230 const RiscvVariant* v = riscv_variant_for_kind(target->arch); 231 if (isa.len < 5 || memcmp(isa.s, v->isa_prefix, 4) != 0) 232 return KIT_UNSUPPORTED; 233 p = isa.s + 4; 234 end = isa.s + isa.len; 235 rv64_feature_disable_all(words, nwords); 236 while (p < end) { 237 if (*p == '_') { 238 ++p; 239 continue; 240 } 241 switch (*p) { 242 case 'i': 243 rv64_feature_set(words, nwords, RV64_FEAT_I); 244 ++p; 245 rv64_skip_version(&p, end); 246 continue; 247 case 'm': 248 rv64_feature_set(words, nwords, RV64_FEAT_M); 249 ++p; 250 rv64_skip_version(&p, end); 251 continue; 252 case 'a': 253 rv64_feature_set(words, nwords, RV64_FEAT_A); 254 ++p; 255 rv64_skip_version(&p, end); 256 continue; 257 case 'f': 258 rv64_feature_set(words, nwords, RV64_FEAT_F); 259 ++p; 260 rv64_skip_version(&p, end); 261 continue; 262 case 'd': 263 rv64_feature_set(words, nwords, RV64_FEAT_D); 264 ++p; 265 rv64_skip_version(&p, end); 266 continue; 267 case 'c': 268 rv64_feature_set(words, nwords, RV64_FEAT_C); 269 ++p; 270 rv64_skip_version(&p, end); 271 continue; 272 case 'g': 273 rv64_feature_enable_g(words, nwords); 274 ++p; 275 rv64_skip_version(&p, end); 276 continue; 277 case 'z': 278 if (rv64_has_prefix(p, end, "zicsr")) { 279 rv64_feature_set(words, nwords, RV64_FEAT_ZICSR); 280 p += 5; 281 rv64_skip_version(&p, end); 282 continue; 283 } 284 if (rv64_has_prefix(p, end, "zifencei")) { 285 rv64_feature_set(words, nwords, RV64_FEAT_ZIFENCEI); 286 p += 8; 287 rv64_skip_version(&p, end); 288 continue; 289 } 290 break; 291 } 292 return KIT_UNSUPPORTED; 293 } 294 return KIT_OK; 295 } 296 297 static void rv64_target_feature_defaults(const Target* target, u64* words, 298 u32 nwords) { 299 rv64_feature_set(words, nwords, RV64_FEAT_I); 300 rv64_feature_set(words, nwords, RV64_FEAT_M); 301 rv64_feature_set(words, nwords, RV64_FEAT_A); 302 /* rv32 default profile is rv32imac_zicsr_zifencei (ilp32 SOFT float): most 303 * 32-bit RISC-V microcontrollers (e.g. ESP32-C3 = rv32imc) ship no F/D 304 * hardware, and a hard-float default silently emits FLW/FSW that fault on the 305 * chip. Opt into the FPU explicitly with -march=rv32imafc -mabi=ilp32f. rv64 306 * keeps the full G+C (lp64d) profile including F+D. */ 307 if (target->arch != KIT_ARCH_RV32) { 308 rv64_feature_set(words, nwords, RV64_FEAT_F); 309 rv64_feature_set(words, nwords, RV64_FEAT_D); 310 } 311 rv64_feature_set(words, nwords, RV64_FEAT_C); 312 rv64_feature_set(words, nwords, RV64_FEAT_ZICSR); 313 rv64_feature_set(words, nwords, RV64_FEAT_ZIFENCEI); 314 } 315 316 static CgTarget* rv64_backend_make(Compiler* c, ObjBuilder* o, 317 const KitCodeOptions* opts) { 318 return native_direct_backend_make(c, o, opts, rv64_native_target_new, 319 rv64_native_direct_ops()); 320 } 321 322 static CgTarget* rv64_semantic_target_new(Compiler* c, ObjBuilder* o, 323 MCEmitter* mc) { 324 return native_direct_semantic_target_new(c, o, mc, rv64_native_target_new, 325 rv64_native_direct_ops()); 326 } 327 328 /* RISC-V emits only the target-C convention; it has no SysV/Win64/AAPCS/WASM 329 * variant. Shared by rv64 and rv32 (one backend, one answer). */ 330 static int rv64_supports_call_conv(const Compiler* c, KitCgCallConv cc) { 331 (void)c; 332 return cc == KIT_CG_CC_TARGET_C; 333 } 334 335 /* Capability twin of rv_intrinsic (src/arch/riscv/native.c); keep the two in 336 * sync. rv32 and rv64 share one backend, so they share this answer (the old 337 * type.c matrix normalized rv32->rv64 for exactly this reason). No default 338 * case, so a new KitCgIntrinsic trips -Wswitch here. */ 339 static int rv64_supports_intrinsic(const Compiler* c, KitCgIntrinsic intrin) { 340 switch (intrin) { 341 case KIT_CG_INTRIN_TRAP: 342 case KIT_CG_INTRIN_CLZ: 343 case KIT_CG_INTRIN_CTZ: 344 case KIT_CG_INTRIN_POPCOUNT: 345 case KIT_CG_INTRIN_BSWAP: 346 case KIT_CG_INTRIN_SADD_OVERFLOW: 347 case KIT_CG_INTRIN_UADD_OVERFLOW: 348 case KIT_CG_INTRIN_SSUB_OVERFLOW: 349 case KIT_CG_INTRIN_USUB_OVERFLOW: 350 case KIT_CG_INTRIN_SMUL_OVERFLOW: 351 case KIT_CG_INTRIN_UMUL_OVERFLOW: 352 case KIT_CG_INTRIN_PREFETCH: 353 case KIT_CG_INTRIN_EXPECT: 354 case KIT_CG_INTRIN_ASSUME_ALIGNED: 355 case KIT_CG_INTRIN_CPU_NOP: 356 case KIT_CG_INTRIN_CPU_YIELD: 357 case KIT_CG_INTRIN_ISB: 358 case KIT_CG_INTRIN_DMB: 359 case KIT_CG_INTRIN_DSB: 360 case KIT_CG_INTRIN_WFI: 361 case KIT_CG_INTRIN_FRAME_ADDRESS: 362 case KIT_CG_INTRIN_RETURN_ADDRESS: 363 return 1; 364 case KIT_CG_INTRIN_READCYCLECOUNTER: 365 /* rv64 reads the 64-bit `cycle` CSR inline with a single RDCYCLE. rv32's 366 * result spans the cycle/cycleh CSR pair (a register pair the single- 367 * register intrinsic path can't carry), so it routes to the 368 * __kit_readcyclecounter libkit_rt helper instead (src/cg/arith.c). */ 369 return c->target.arch == KIT_ARCH_RV64 || c->target.arch == KIT_ARCH_RV32; 370 case KIT_CG_INTRIN_SMUL_HIGH: 371 case KIT_CG_INTRIN_UMUL_HIGH: 372 return 1; 373 case KIT_CG_INTRIN_SYSCALL: 374 return c->target.os == KIT_OS_LINUX || 375 c->target.os == KIT_OS_FREESTANDING; 376 case KIT_CG_INTRIN_SETJMP: 377 case KIT_CG_INTRIN_LONGJMP: 378 case KIT_CG_INTRIN_FMA: 379 case KIT_CG_INTRIN_IRQ_SAVE: 380 case KIT_CG_INTRIN_IRQ_RESTORE: 381 case KIT_CG_INTRIN_IRQ_DISABLE: 382 case KIT_CG_INTRIN_IRQ_ENABLE: 383 case KIT_CG_INTRIN_WFE: 384 case KIT_CG_INTRIN_SEV: 385 case KIT_CG_INTRIN_DCACHE_CLEAN: 386 case KIT_CG_INTRIN_DCACHE_INVALIDATE: 387 case KIT_CG_INTRIN_DCACHE_CLEAN_INVALIDATE: 388 case KIT_CG_INTRIN_ICACHE_INVALIDATE: 389 case KIT_CG_INTRIN_CORO_SWITCH: 390 return 0; 391 } 392 return 0; 393 } 394 395 static int rv64_feature_get(const u64* words, u32 nwords, u32 idx) { 396 if (!words || idx / 64u >= nwords) return 0; 397 return (words[idx / 64u] & (1ull << (idx % 64u))) != 0; 398 } 399 400 /* RISC-V float-ABI resolution + validation, factored out of src/api/core.c so 401 * non-arch code resolves the ABI by capability (arch_resolve_float_abi) instead 402 * of an `arch == RV32 || RV64` branch. Shared by rv32 and rv64 (one backend). 403 * Mirrors the historical core.c logic exactly: an explicit -mabi (`abi`) picks 404 * the ABI and must match the pointer width; otherwise the ABI is derived from 405 * the resolved -march F/D bits. A hard single/double ABI requires the matching 406 * extension. Writes spec->float_abi on success; on error returns KIT_INVALID 407 * and fills `err`. */ 408 static KitStatus rv64_resolve_float_abi(const ArchImpl* impl, 409 KitTargetSpec* spec, 410 const u64* feature_words, 411 u32 nfeature_words, KitSlice abi, 412 char* err, size_t errcap) { 413 u32 fidx, didx; 414 int has_f; 415 int has_d; 416 KitFloatAbi fa; 417 StrBuf sb; 418 strbuf_init(&sb, err, errcap); 419 has_f = arch_target_feature_index(impl, kit_slice_cstr("f"), &fidx) && 420 rv64_feature_get(feature_words, nfeature_words, fidx); 421 has_d = arch_target_feature_index(impl, kit_slice_cstr("d"), &didx) && 422 rv64_feature_get(feature_words, nfeature_words, didx); 423 424 if (abi.s && abi.len) { 425 int is_ilp32 = 0; 426 int is_lp64 = 0; 427 if (kit_slice_eq_cstr(abi, "ilp32") || kit_slice_eq_cstr(abi, "ilp32f") || 428 kit_slice_eq_cstr(abi, "ilp32d")) { 429 is_ilp32 = 1; 430 } else if (kit_slice_eq_cstr(abi, "lp64") || 431 kit_slice_eq_cstr(abi, "lp64f") || 432 kit_slice_eq_cstr(abi, "lp64d")) { 433 is_lp64 = 1; 434 } else { 435 strbuf_puts(&sb, "unsupported ABI for "); 436 strbuf_puts(&sb, impl->name); 437 strbuf_puts(&sb, ": "); 438 strbuf_put_slice(&sb, abi); 439 return KIT_INVALID; 440 } 441 /* Width prefix must match pointer size. */ 442 if ((is_ilp32 && spec->ptr_size != 4u) || 443 (is_lp64 && spec->ptr_size != 8u)) { 444 strbuf_puts(&sb, "ABI "); 445 strbuf_put_slice(&sb, abi); 446 strbuf_puts(&sb, " does not match pointer width for "); 447 strbuf_puts(&sb, impl->name); 448 return KIT_INVALID; 449 } 450 if (kit_slice_eq_cstr(abi, "ilp32d") || kit_slice_eq_cstr(abi, "lp64d")) { 451 fa = KIT_FLOAT_ABI_DOUBLE; 452 } else if (kit_slice_eq_cstr(abi, "ilp32f") || 453 kit_slice_eq_cstr(abi, "lp64f")) { 454 fa = KIT_FLOAT_ABI_SINGLE; 455 } else { 456 fa = KIT_FLOAT_ABI_SOFT; 457 } 458 } else { 459 /* Derive from the resolved -march feature bits. */ 460 if (has_d) 461 fa = KIT_FLOAT_ABI_DOUBLE; 462 else if (has_f) 463 fa = KIT_FLOAT_ABI_SINGLE; 464 else 465 fa = KIT_FLOAT_ABI_SOFT; 466 } 467 468 if (fa == KIT_FLOAT_ABI_SINGLE && !has_f) { 469 strbuf_puts(&sb, 470 "hardware single-float ABI requires the 'f' extension for "); 471 strbuf_puts(&sb, impl->name); 472 return KIT_INVALID; 473 } 474 if (fa == KIT_FLOAT_ABI_DOUBLE && !has_d) { 475 strbuf_puts(&sb, 476 "hardware double-float ABI requires the 'd' extension for "); 477 strbuf_puts(&sb, impl->name); 478 return KIT_INVALID; 479 } 480 spec->float_abi = (uint8_t)fa; 481 return KIT_OK; 482 } 483 484 /* Float-ABI-dependent predefined macros, keyed on the resolved float ABI (see 485 * ArchImpl.float_predefines). kit's RISC-V codegen only touches FP registers 486 * under a hardware-float ABI, so __riscv_flen (and the coro FP-save it gates) 487 * tracks float_abi rather than the raw F/D ISA bits. Shared by rv32 + rv64. */ 488 static const KitPredefinedMacro rv_float_macros_soft[] = { 489 {KIT_SLICE_LIT("__riscv_float_abi_soft"), KIT_SLICE_LIT("1")}, 490 }; 491 static const KitPredefinedMacro rv_float_macros_single[] = { 492 {KIT_SLICE_LIT("__riscv_float_abi_single"), KIT_SLICE_LIT("1")}, 493 {KIT_SLICE_LIT("__riscv_flen"), KIT_SLICE_LIT("32")}, 494 {KIT_SLICE_LIT("__riscv_fdiv"), KIT_SLICE_LIT("1")}, 495 {KIT_SLICE_LIT("__riscv_fsqrt"), KIT_SLICE_LIT("1")}, 496 }; 497 static const KitPredefinedMacro rv_float_macros_double[] = { 498 {KIT_SLICE_LIT("__riscv_float_abi_double"), KIT_SLICE_LIT("1")}, 499 {KIT_SLICE_LIT("__riscv_flen"), KIT_SLICE_LIT("64")}, 500 {KIT_SLICE_LIT("__riscv_fdiv"), KIT_SLICE_LIT("1")}, 501 {KIT_SLICE_LIT("__riscv_fsqrt"), KIT_SLICE_LIT("1")}, 502 }; 503 504 static u32 rv64_float_predefines(const ArchImpl* impl, 505 const KitTargetSpec* spec, 506 const KitPredefinedMacro** out) { 507 (void)impl; 508 switch ((KitFloatAbi)spec->float_abi) { 509 case KIT_FLOAT_ABI_SINGLE: 510 *out = rv_float_macros_single; 511 return (u32)(sizeof rv_float_macros_single / sizeof rv_float_macros_single[0]); 512 case KIT_FLOAT_ABI_DOUBLE: 513 *out = rv_float_macros_double; 514 return (u32)(sizeof rv_float_macros_double / sizeof rv_float_macros_double[0]); 515 case KIT_FLOAT_ABI_SOFT: 516 case KIT_FLOAT_ABI_DEFAULT: 517 break; 518 } 519 /* SOFT (and the unreached DEFAULT — RISC-V always resolves a concrete ABI). */ 520 *out = rv_float_macros_soft; 521 return (u32)(sizeof rv_float_macros_soft / sizeof rv_float_macros_soft[0]); 522 } 523 524 const ArchImpl arch_impl_rv64 = { 525 .backend = {.name = "rv64", .make = rv64_backend_make}, 526 .kind = KIT_ARCH_RV64, 527 .name = "rv64", 528 .cgtarget_new = rv64_semantic_target_new, 529 .asm_new = rv64_arch_asm_new, 530 .disasm_new = rv64_disasm_new, 531 .apply_label_fixup = rv64_apply_label_fixup, 532 .decode = &rv64_decode_ops, 533 .emu = &rv64_emu_ops, 534 .link = &link_arch_rv64, 535 .dwarf = &rv64_dwarf_ops, 536 .dbg = &rv64_dbg_ops, 537 .asm_ops = &rv64_asm_ops, 538 .predefined_macros = rv64_predefined_macros, 539 .npredefined_macros = 540 (u32)(sizeof rv64_predefined_macros / sizeof rv64_predefined_macros[0]), 541 .target_features = rv64_target_features, 542 .ntarget_features = 543 (u32)(sizeof rv64_target_features / sizeof rv64_target_features[0]), 544 .target_feature_defaults = rv64_target_feature_defaults, 545 .target_feature_apply_isa = rv64_target_feature_apply_isa, 546 .register_name = rv64_register_name, 547 .register_index = rv64_register_index, 548 .register_count = rv64_register_iter_size, 549 .register_at = rv64_register_at_public, 550 /* RISC-V psABI: return address in x1 (ra). 4-byte aligned insns 551 * (cover 2-byte C-ext too via code_align=2). Data align -8 for 552 * doubleword stack stride. CFA = sp at entry. */ 553 .cfi_return_addr_reg = 1u, 554 .cfi_code_align_factor = 2, 555 .cfi_data_align_factor = -8, 556 .cfi_cfa_init_reg = 2u, 557 .cfi_cfa_init_offset = 0, 558 .backend_features = KIT_CG_BACKEND_STRICT_ALIGNMENT, 559 .atomic_lock_free_max = 8u, 560 .supports_call_conv = rv64_supports_call_conv, 561 .supports_intrinsic = rv64_supports_intrinsic, 562 .resolve_float_abi = rv64_resolve_float_abi, 563 .float_predefines = rv64_float_predefines, 564 }; 565 566 /* RV32 shares nearly all of the RISC-V backend with rv64 — the per-XLEN 567 * differences are threaded through RiscvVariant inside the shared functions. 568 * Differs only in: backend/arch names + kind, the link descriptor + dbg ops 569 * (rv_lw / 2-byte min insn), the ilp32 (soft-float) predefined-macro table, and 570 * the CFI data alignment factor (-4 word stride vs rv64's -8 doubleword). */ 571 const ArchImpl arch_impl_rv32 = { 572 .backend = {.name = "rv32", .make = rv64_backend_make}, 573 .kind = KIT_ARCH_RV32, 574 .name = "rv32", 575 .cgtarget_new = rv64_semantic_target_new, 576 .asm_new = rv64_arch_asm_new, 577 .disasm_new = rv64_disasm_new, 578 .apply_label_fixup = rv64_apply_label_fixup, 579 .decode = &rv64_decode_ops, 580 .emu = &rv64_emu_ops, 581 .link = &link_arch_rv32, 582 .dwarf = &rv64_dwarf_ops, 583 .dbg = &rv32_dbg_ops, 584 .asm_ops = &rv64_asm_ops, 585 .predefined_macros = rv32_predefined_macros, 586 .npredefined_macros = 587 (u32)(sizeof rv32_predefined_macros / sizeof rv32_predefined_macros[0]), 588 .target_features = rv64_target_features, 589 .ntarget_features = 590 (u32)(sizeof rv64_target_features / sizeof rv64_target_features[0]), 591 .target_feature_defaults = rv64_target_feature_defaults, 592 .target_feature_apply_isa = rv64_target_feature_apply_isa, 593 .register_name = rv64_register_name, 594 .register_index = rv64_register_index, 595 .register_count = rv64_register_iter_size, 596 .register_at = rv64_register_at_public, 597 /* RISC-V psABI: return address in x1 (ra). 4-byte aligned insns 598 * (cover 2-byte C-ext too via code_align=2). Data align -4 for 599 * word stack stride (rv32). CFA = sp at entry. */ 600 .cfi_return_addr_reg = 1u, 601 .cfi_code_align_factor = 2, 602 .cfi_data_align_factor = -4, 603 .cfi_cfa_init_reg = 2u, 604 .cfi_cfa_init_offset = 0, 605 .backend_features = KIT_CG_BACKEND_STRICT_ALIGNMENT, 606 /* rv32 has no native 64-bit atomics (no lr.d/sc.d/amo*.d). */ 607 .atomic_lock_free_max = 4u, 608 .supports_call_conv = rv64_supports_call_conv, 609 .supports_intrinsic = rv64_supports_intrinsic, 610 .resolve_float_abi = rv64_resolve_float_abi, 611 .float_predefines = rv64_float_predefines, 612 };