arm32_target_features_test.c (6876B)
1 /* arm32_target_features_test — the arm-none-eabi -march/-mcpu/-mfpu/-mfloat-abi 2 * resolution at the public kit_target_new level: the apply_cpu hook (-mcpu=) 3 * and the vfp/fpv5 features (-mfpu=) that drive the dsp feature, the float ABI 4 * resolution, and (indirectly) the feature_predefines macro selection. 5 * 6 * Reds before the apply_cpu hook + arm32 wiring land; green after. */ 7 8 #include <kit/core.h> 9 #include <kit/target.h> 10 #include <string.h> 11 12 #include "lib/kit_unit.h" 13 14 static KitUnit g_u; 15 #define EXPECT(c, ...) CU_EXPECT(&g_u, c, __VA_ARGS__) 16 17 static KitTargetSpec arm32_spec(void) { 18 KitTargetSpec t = kit_unit_target(KIT_ARCH_ARM_32, KIT_OS_FREESTANDING, 19 KIT_OBJ_ELF); 20 t.ptr_size = 4; 21 t.ptr_align = 4; 22 return t; 23 } 24 25 /* Build an arm32 target with optional -march (isa), -mcpu (cpu), -mabi (abi), 26 * and an explicit feature list (the -mfpu lowering records vfp/fpv5 there). */ 27 static KitStatus make_arm32(KitSlice isa, KitSlice cpu, KitSlice abi, 28 const KitTargetFeature* features, uint32_t nfeatures, 29 KitTarget** out) { 30 KitTargetOptions opts; 31 memset(&opts, 0, sizeof opts); 32 opts.spec = arm32_spec(); 33 opts.isa = isa; 34 opts.cpu = cpu; 35 opts.abi = abi; 36 opts.features = features; 37 opts.nfeatures = nfeatures; 38 return kit_target_new(&g_u.ctx, &opts, out); 39 } 40 41 static int has(KitTarget* t, const char* name) { 42 return kit_target_has_feature(t, kit_slice_cstr(name)); 43 } 44 45 static void check_cpu_dsp(void) { 46 KitTarget* t = NULL; 47 48 /* cortex-m3 = ARMv7-M baseline: no DSP. */ 49 EXPECT(make_arm32(KIT_SLICE_NULL, KIT_SLICE_LIT("cortex-m3"), KIT_SLICE_NULL, 50 NULL, 0, &t) == KIT_OK, 51 "cortex-m3 target"); 52 EXPECT(!has(t, "dsp"), "cortex-m3 lacks dsp"); 53 EXPECT(!has(t, "vfp"), "cortex-m3 lacks vfp (soft)"); 54 kit_target_free(t); 55 56 /* cortex-m4 = ARMv7E-M: DSP. */ 57 t = NULL; 58 EXPECT(make_arm32(KIT_SLICE_NULL, KIT_SLICE_LIT("cortex-m4"), KIT_SLICE_NULL, 59 NULL, 0, &t) == KIT_OK, 60 "cortex-m4 target"); 61 EXPECT(has(t, "dsp"), "cortex-m4 has dsp"); 62 kit_target_free(t); 63 64 /* cortex-m7 = ARMv7E-M: DSP. */ 65 t = NULL; 66 EXPECT(make_arm32(KIT_SLICE_NULL, KIT_SLICE_LIT("cortex-m7"), KIT_SLICE_NULL, 67 NULL, 0, &t) == KIT_OK, 68 "cortex-m7 target"); 69 EXPECT(has(t, "dsp"), "cortex-m7 has dsp"); 70 kit_target_free(t); 71 } 72 73 static void check_march_dsp(void) { 74 KitTarget* t = NULL; 75 76 /* -march=armv7-m: no DSP. */ 77 EXPECT(make_arm32(KIT_SLICE_LIT("armv7-m"), KIT_SLICE_NULL, KIT_SLICE_NULL, 78 NULL, 0, &t) == KIT_OK, 79 "armv7-m target"); 80 EXPECT(!has(t, "dsp"), "armv7-m lacks dsp"); 81 kit_target_free(t); 82 83 /* -march=armv7e-m: DSP. */ 84 t = NULL; 85 EXPECT(make_arm32(KIT_SLICE_LIT("armv7e-m"), KIT_SLICE_NULL, KIT_SLICE_NULL, 86 NULL, 0, &t) == KIT_OK, 87 "armv7e-m target"); 88 EXPECT(has(t, "dsp"), "armv7e-m has dsp"); 89 kit_target_free(t); 90 91 /* thumbv7em alias: DSP. */ 92 t = NULL; 93 EXPECT(make_arm32(KIT_SLICE_LIT("thumbv7em"), KIT_SLICE_NULL, KIT_SLICE_NULL, 94 NULL, 0, &t) == KIT_OK, 95 "thumbv7em target"); 96 EXPECT(has(t, "dsp"), "thumbv7em has dsp"); 97 kit_target_free(t); 98 } 99 100 static void check_mfpu_features(void) { 101 /* -mfpu=fpv4-sp-d16 lowers to the "vfp" feature (the driver does the 102 * name->feature mapping; here we record it directly). cortex-m4 + vfp = 103 * dsp + vfp. */ 104 KitTargetFeature vfp[] = { 105 {KIT_SLICE_LIT("vfp"), true}, 106 }; 107 KitTargetFeature fpv5[] = { 108 {KIT_SLICE_LIT("vfp"), true}, 109 {KIT_SLICE_LIT("fpv5"), true}, 110 }; 111 KitTarget* t = NULL; 112 113 EXPECT(make_arm32(KIT_SLICE_NULL, KIT_SLICE_LIT("cortex-m4"), KIT_SLICE_NULL, 114 vfp, 1, &t) == KIT_OK, 115 "cortex-m4 + vfp target"); 116 EXPECT(has(t, "dsp"), "cortex-m4 + vfp has dsp"); 117 EXPECT(has(t, "vfp"), "cortex-m4 + vfp has vfp"); 118 EXPECT(!has(t, "fpv5"), "cortex-m4 + vfp lacks fpv5"); 119 kit_target_free(t); 120 121 /* cortex-m7 + fpv5 (the fpv5-d16 fpu). */ 122 t = NULL; 123 EXPECT(make_arm32(KIT_SLICE_NULL, KIT_SLICE_LIT("cortex-m7"), KIT_SLICE_NULL, 124 fpv5, 2, &t) == KIT_OK, 125 "cortex-m7 + fpv5 target"); 126 EXPECT(has(t, "dsp"), "cortex-m7 + fpv5 has dsp"); 127 EXPECT(has(t, "vfp"), "cortex-m7 + fpv5 has vfp"); 128 EXPECT(has(t, "fpv5"), "cortex-m7 + fpv5 has fpv5"); 129 kit_target_free(t); 130 } 131 132 static void check_float_abi(void) { 133 KitTargetFeature vfp[] = { 134 {KIT_SLICE_LIT("vfp"), true}, 135 }; 136 KitTarget* t = NULL; 137 KitTargetSpec resolved; 138 139 /* Default / soft: float_abi resolves to SOFT (gates soft-float lowering). */ 140 EXPECT(make_arm32(KIT_SLICE_NULL, KIT_SLICE_LIT("cortex-m3"), KIT_SLICE_NULL, 141 NULL, 0, &t) == KIT_OK, 142 "cortex-m3 soft target"); 143 resolved = kit_target_spec(t); 144 EXPECT(resolved.float_abi == (uint8_t)KIT_FLOAT_ABI_SOFT, 145 "cortex-m3 resolves SOFT float ABI"); 146 kit_target_free(t); 147 148 /* -mabi=hard with a VFP feature resolves to a hardware (single) float ABI. 149 * (The driver still rejects -mfloat-abi=hard, but the resolver is exercisable 150 * here at the API level.) */ 151 t = NULL; 152 EXPECT(make_arm32(KIT_SLICE_NULL, KIT_SLICE_LIT("cortex-m4"), 153 KIT_SLICE_LIT("hard"), vfp, 1, &t) == KIT_OK, 154 "cortex-m4 hard+vfp target"); 155 resolved = kit_target_spec(t); 156 EXPECT(resolved.float_abi == (uint8_t)KIT_FLOAT_ABI_SINGLE, 157 "cortex-m4 hard+vfp resolves SINGLE float ABI"); 158 kit_target_free(t); 159 160 /* -mabi=hard WITHOUT a VFP feature is invalid. */ 161 t = NULL; 162 g_u.last_diag[0] = '\0'; 163 EXPECT(make_arm32(KIT_SLICE_NULL, KIT_SLICE_LIT("cortex-m4"), 164 KIT_SLICE_LIT("hard"), NULL, 0, &t) == KIT_INVALID, 165 "hard ABI without FPU rejected"); 166 EXPECT(t == NULL, "hard ABI without FPU leaves target NULL"); 167 kit_target_free(t); 168 } 169 170 static void check_errors(void) { 171 KitTarget* t = NULL; 172 173 /* Unknown CPU is rejected (KIT_INVALID, with a diagnostic). */ 174 g_u.last_diag[0] = '\0'; 175 EXPECT(make_arm32(KIT_SLICE_NULL, KIT_SLICE_LIT("cortex-a9"), KIT_SLICE_NULL, 176 NULL, 0, &t) == KIT_INVALID, 177 "unknown cpu rejected"); 178 EXPECT(t == NULL, "unknown cpu leaves target NULL"); 179 EXPECT(strstr(g_u.last_diag, "unsupported CPU") != NULL, 180 "unknown cpu diagnostic"); 181 182 /* Unknown -march is rejected. */ 183 t = NULL; 184 g_u.last_diag[0] = '\0'; 185 EXPECT(make_arm32(KIT_SLICE_LIT("armv6-m"), KIT_SLICE_NULL, KIT_SLICE_NULL, 186 NULL, 0, &t) == KIT_INVALID, 187 "unknown march rejected"); 188 EXPECT(t == NULL, "unknown march leaves target NULL"); 189 } 190 191 int main(void) { 192 kit_unit_init(&g_u); 193 check_cpu_dsp(); 194 check_march_dsp(); 195 check_mfpu_features(); 196 check_float_abi(); 197 check_errors(); 198 kit_unit_summary(&g_u, "arm32_target_features_test"); 199 return kit_unit_status(&g_u); 200 }