arch.c (6052B)
1 /* arch_impl_wasm: Wasm target descriptor. 2 * 3 * Native machine-code emitters (ELF/Mach-O/COFF) and the assembler are 4 * intentionally NULL for v1: the Wasm target produces a WasmModule attached to 5 * the ObjBuilder, which emit_wasm flushes via wasm_encode, and there is no 6 * assembly form for wasm32 in the toolchain. The disassembler (wasm_disasm_new) 7 * renders the code section of a .wasm module as WAT for objdump. */ 8 9 #include "arch/arch.h" 10 11 #include "arch/wasm/disasm.h" 12 #include "arch/wasm/internal.h" 13 14 /* Predefined macros mirroring clang/llvm conventions. */ 15 static const KitPredefinedMacro wasm_predefined_macros[] = { 16 {KIT_SLICE_LIT("__wasm__"), KIT_SLICE_LIT("1")}, 17 {KIT_SLICE_LIT("__wasm32__"), KIT_SLICE_LIT("1")}, 18 {KIT_SLICE_LIT("__ILP32__"), KIT_SLICE_LIT("1")}, 19 {KIT_SLICE_LIT("__ORDER_LITTLE_ENDIAN__"), KIT_SLICE_LIT("1234")}, 20 {KIT_SLICE_LIT("__ORDER_BIG_ENDIAN__"), KIT_SLICE_LIT("4321")}, 21 {KIT_SLICE_LIT("__BYTE_ORDER__"), KIT_SLICE_LIT("__ORDER_LITTLE_ENDIAN__")}, 22 {KIT_SLICE_LIT("__LITTLE_ENDIAN__"), KIT_SLICE_LIT("1")}, 23 }; 24 25 enum { 26 WASM_TFEAT_THREADS = 0, 27 WASM_TFEAT_TYPED_FUNC_REFS, 28 WASM_TFEAT_TAIL_CALLS, 29 WASM_TFEAT_MULTI_MEMORY, 30 WASM_TFEAT_MEMORY64, 31 WASM_TFEAT_BULK_MEMORY, 32 WASM_TFEAT_NONTRAPPING_FTOI, 33 }; 34 35 static const ArchTargetFeature wasm_target_features[] = { 36 {"threads"}, {"typed-func-refs"}, {"tail-calls"}, {"multi-memory"}, 37 {"memory64"}, {"bulk-memory"}, {"nontrapping-ftoi"}, 38 }; 39 40 static void wasm_feature_set(u64* words, u32 nwords, u32 idx) { 41 if (!words || idx / 64u >= nwords) return; 42 words[idx / 64u] |= 1ull << (idx % 64u); 43 } 44 45 static KitStatus wasm_target_feature_apply_isa(const Target* target, 46 KitSlice isa, u64* words, 47 u32 nwords) { 48 (void)target; 49 (void)words; 50 (void)nwords; 51 if (kit_slice_eq_cstr(isa, "wasm32") || kit_slice_eq_cstr(isa, "wasm64")) 52 return KIT_OK; 53 return KIT_UNSUPPORTED; 54 } 55 56 static void wasm_target_feature_defaults(const Target* target, u64* words, 57 u32 nwords) { 58 (void)target; 59 wasm_feature_set(words, nwords, WASM_TFEAT_THREADS); 60 wasm_feature_set(words, nwords, WASM_TFEAT_TYPED_FUNC_REFS); 61 wasm_feature_set(words, nwords, WASM_TFEAT_TAIL_CALLS); 62 wasm_feature_set(words, nwords, WASM_TFEAT_MULTI_MEMORY); 63 wasm_feature_set(words, nwords, WASM_TFEAT_MEMORY64); 64 wasm_feature_set(words, nwords, WASM_TFEAT_BULK_MEMORY); 65 wasm_feature_set(words, nwords, WASM_TFEAT_NONTRAPPING_FTOI); 66 } 67 68 static CGTarget* wasm_backend_make(Compiler* c, ObjBuilder* o, 69 const KitCodeOptions* opts) { 70 (void)opts; 71 return wasm_cgtarget_new(c, o, NULL); 72 } 73 74 /* wasm32 emits the target-C convention and its own WASM convention; no 75 * SysV/Win64/AAPCS. */ 76 static int wasm_supports_call_conv(const Compiler* c, KitCgCallConv cc) { 77 (void)c; 78 switch (cc) { 79 case KIT_CG_CC_TARGET_C: 80 case KIT_CG_CC_WASM: 81 return 1; 82 case KIT_CG_CC_SYSV: 83 case KIT_CG_CC_WIN64: 84 case KIT_CG_CC_AAPCS: 85 case KIT_CG_CC_INTERRUPT: 86 return 0; 87 } 88 return 0; 89 } 90 91 /* Capability twin of wasm_intrinsic (src/arch/wasm/emit.c); keep the two in 92 * sync. wasm lowers only the portable intrinsics — the CPU/barrier/baremetal 93 * forms have no wasm lowering (emit.c panics on them). No default case, so a 94 * new KitCgIntrinsic trips -Wswitch here. */ 95 static int wasm_supports_intrinsic(const Compiler* c, KitCgIntrinsic intrin) { 96 (void)c; 97 switch (intrin) { 98 case KIT_CG_INTRIN_TRAP: 99 case KIT_CG_INTRIN_CLZ: 100 case KIT_CG_INTRIN_CTZ: 101 case KIT_CG_INTRIN_POPCOUNT: 102 case KIT_CG_INTRIN_BSWAP: 103 case KIT_CG_INTRIN_SADD_OVERFLOW: 104 case KIT_CG_INTRIN_UADD_OVERFLOW: 105 case KIT_CG_INTRIN_SSUB_OVERFLOW: 106 case KIT_CG_INTRIN_USUB_OVERFLOW: 107 case KIT_CG_INTRIN_SMUL_OVERFLOW: 108 case KIT_CG_INTRIN_UMUL_OVERFLOW: 109 case KIT_CG_INTRIN_PREFETCH: 110 case KIT_CG_INTRIN_EXPECT: 111 case KIT_CG_INTRIN_ASSUME_ALIGNED: 112 return 1; 113 case KIT_CG_INTRIN_SETJMP: 114 case KIT_CG_INTRIN_LONGJMP: 115 case KIT_CG_INTRIN_FMA: 116 case KIT_CG_INTRIN_SYSCALL: 117 case KIT_CG_INTRIN_IRQ_SAVE: 118 case KIT_CG_INTRIN_IRQ_RESTORE: 119 case KIT_CG_INTRIN_IRQ_DISABLE: 120 case KIT_CG_INTRIN_IRQ_ENABLE: 121 case KIT_CG_INTRIN_DMB: 122 case KIT_CG_INTRIN_DSB: 123 case KIT_CG_INTRIN_ISB: 124 case KIT_CG_INTRIN_DCACHE_CLEAN: 125 case KIT_CG_INTRIN_DCACHE_INVALIDATE: 126 case KIT_CG_INTRIN_DCACHE_CLEAN_INVALIDATE: 127 case KIT_CG_INTRIN_ICACHE_INVALIDATE: 128 case KIT_CG_INTRIN_CPU_NOP: 129 case KIT_CG_INTRIN_CPU_YIELD: 130 case KIT_CG_INTRIN_WFI: 131 case KIT_CG_INTRIN_WFE: 132 case KIT_CG_INTRIN_SEV: 133 case KIT_CG_INTRIN_CORO_SWITCH: 134 /* wasm has no frame-pointer chain to walk. */ 135 case KIT_CG_INTRIN_FRAME_ADDRESS: 136 case KIT_CG_INTRIN_RETURN_ADDRESS: 137 return 0; 138 } 139 return 0; 140 } 141 142 const ArchImpl arch_impl_wasm = { 143 .backend = {.name = "wasm", .make = wasm_backend_make}, 144 .kind = KIT_ARCH_WASM, 145 .name = "wasm", 146 .cgtarget_new = wasm_cgtarget_new, 147 .asm_new = NULL, 148 .disasm_new = wasm_disasm_new, 149 .apply_label_fixup = NULL, 150 .link = NULL, 151 .predefined_macros = wasm_predefined_macros, 152 .npredefined_macros = 153 (u32)(sizeof wasm_predefined_macros / sizeof wasm_predefined_macros[0]), 154 .target_features = wasm_target_features, 155 .ntarget_features = 156 (u32)(sizeof wasm_target_features / sizeof wasm_target_features[0]), 157 .target_feature_defaults = wasm_target_feature_defaults, 158 .target_feature_apply_isa = wasm_target_feature_apply_isa, 159 .register_name = NULL, 160 .register_index = NULL, 161 .register_count = NULL, 162 .register_at = NULL, 163 .backend_features = 164 KIT_CG_BACKEND_STRICT_ALIGNMENT | KIT_CG_BACKEND_ICACHE_COHERENT, 165 /* wasm32 has 4-byte pointers but lowers 8-byte (i64) atomics lock-free. */ 166 .atomic_lock_free_max = 8u, 167 .supports_call_conv = wasm_supports_call_conv, 168 .supports_intrinsic = wasm_supports_intrinsic, 169 };