value.c (19497B)
1 #include "cg/internal.h" 2 3 int api_type_is_float(Compiler* c, KitCgTypeId ty) { 4 const CgType* cg; 5 ty = api_unalias_type(c, ty); 6 cg = cg_type_get(c, ty); 7 return cg && cg->kind == KIT_CG_TYPE_FLOAT; 8 } 9 10 int api_is_f128_type(Compiler* c, KitCgTypeId ty) { 11 const CgType* cg; 12 ty = api_unalias_type(c, ty); 13 cg = cg_type_get(c, ty); 14 return cg && cg->kind == KIT_CG_TYPE_FLOAT && cg->fp.width == 128; 15 } 16 17 int api_is_i128_type(Compiler* c, KitCgTypeId ty) { 18 const CgType* cg; 19 ty = api_unalias_type(c, ty); 20 cg = cg_type_get(c, ty); 21 return cg && cg->kind == KIT_CG_TYPE_INT && cg->integer.width == 128; 22 } 23 24 int api_is_wide16_scalar_type(Compiler* c, KitCgTypeId ty) { 25 return api_is_f128_type(c, ty) || api_is_i128_type(c, ty); 26 } 27 28 /* 8-byte scalar split into two 4-byte lanes by the selected ABI. This covers 29 * 32-bit native ABIs whose generic CG path cannot keep the value in a single 30 * scalar register/value. Such values are forced memory-resident so operations 31 * can be legalized as lane sequences or runtime calls. */ 32 int api_is_wide8_scalar_type(Compiler* c, KitCgTypeId ty) { 33 ABITypeInfo ti; 34 if (!c || !c->abi || !ty) return 0; 35 if (abi_cg_scalar_split_lane_size(c->abi, ty) != 4u) return 0; 36 ti = abi_cg_type_info(c->abi, ty); 37 return ti.size == 8u && 38 (ti.scalar_kind == ABI_SC_INT || ti.scalar_kind == ABI_SC_FLOAT); 39 } 40 41 Operand api_op_imm(i64 v, KitCgTypeId ty) { 42 Operand o; 43 memset(&o, 0, sizeof o); 44 o.kind = OPK_IMM; 45 o.type = ty; 46 o.v.imm = v; 47 return o; 48 } 49 50 Operand api_op_local(CGLocal local, KitCgTypeId ty) { 51 Operand o; 52 memset(&o, 0, sizeof o); 53 o.kind = OPK_LOCAL; 54 o.type = ty; 55 o.v.local = local; 56 return o; 57 } 58 59 Operand api_op_global(ObjSymId sym, i64 addend, KitCgTypeId ty) { 60 Operand o; 61 memset(&o, 0, sizeof o); 62 o.kind = OPK_GLOBAL; 63 o.type = ty; 64 o.v.global.sym = sym; 65 o.v.global.addend = addend; 66 return o; 67 } 68 69 Operand api_op_indirect(CGLocal base, i32 ofs, KitCgTypeId ty) { 70 Operand o; 71 memset(&o, 0, sizeof o); 72 o.kind = OPK_INDIRECT; 73 o.type = ty; 74 o.v.ind.base = base; 75 o.v.ind.index = CG_LOCAL_NONE; 76 o.v.ind.log2_scale = 0; 77 o.v.ind.ofs = ofs; 78 return o; 79 } 80 81 Operand api_op_indirect_indexed(CGLocal base, CGLocal index, u8 log2_scale, 82 i32 ofs, KitCgTypeId ty) { 83 Operand o; 84 memset(&o, 0, sizeof o); 85 o.kind = OPK_INDIRECT; 86 o.type = ty; 87 o.v.ind.base = base; 88 o.v.ind.index = index; 89 o.v.ind.log2_scale = log2_scale; 90 o.v.ind.ofs = ofs; 91 return o; 92 } 93 94 u8 api_residency_for(const Operand* o) { 95 if (o->kind == OPK_LOCAL || o->kind == OPK_INDIRECT) return RES_LOCAL; 96 return RES_INHERENT; 97 } 98 99 ApiSValue api_make_sv(Operand op, KitCgTypeId ty) { 100 ApiSValue sv; 101 memset(&sv, 0, sizeof sv); 102 sv.kind = SV_OPERAND; 103 sv.op = op; 104 sv.type = ty; 105 sv.res = api_residency_for(&op); 106 sv.source_local = KIT_CG_LOCAL_NONE; 107 return sv; 108 } 109 110 ApiSValue api_make_lv(Operand op, KitCgTypeId ty) { 111 ApiSValue sv = api_make_sv(op, ty); 112 sv.lvalue = 1; 113 return sv; 114 } 115 116 ApiSValue api_make_sv_with_local_ownership(Operand op, KitCgTypeId ty, 117 int owned) { 118 ApiSValue sv = api_make_sv(op, ty); 119 if (op.kind == OPK_LOCAL && !owned) sv.res = RES_FIXED_LOCAL; 120 return sv; 121 } 122 123 KitCgTypeId api_sv_type(const ApiSValue* sv) { 124 return sv->type ? sv->type : sv->op.type; 125 } 126 127 int api_operand_can_address(const Operand* o) { 128 return o->kind == OPK_LOCAL || o->kind == OPK_GLOBAL || 129 o->kind == OPK_INDIRECT; 130 } 131 132 int api_sv_op_is(const ApiSValue* sv, OpKind kind) { 133 return sv->kind == SV_OPERAND && sv->op.kind == kind; 134 } 135 136 int api_sv_op_is_local_or_imm(const ApiSValue* sv) { 137 return sv->kind == SV_OPERAND && 138 (sv->op.kind == OPK_IMM || sv->op.kind == OPK_LOCAL); 139 } 140 141 /* A PLACE (lvalue) is exactly an SV_OPERAND whose operand addresses storage: 142 * op.kind in { OPK_LOCAL, OPK_GLOBAL, OPK_INDIRECT } (api_operand_can_address). 143 * This is a kind-based predicate, not a heuristic: the `lvalue` flag marks the 144 * value as a place, SV_OPERAND guarantees `op` is meaningful (SV_CMP/SV_ARITH 145 * never carry lvalue=1 — see fold.c, which clears it on materialization), and 146 * the operand kind decides addressability. The former heuristic OR'd in 147 * `bitfield_lvalue` and a (source_local && OPK_LOCAL) term, both subsumed here: 148 * a bit-field place is an ordinary addressable place (it addresses the storage 149 * unit) that additionally carries a bit descriptor — see api_sv_is_bitfield and 150 * kit_cg_field — and source_local only co-occurs with OPK_LOCAL, so 151 * api_operand_can_address already covers both. */ 152 int api_is_lvalue_sv(const ApiSValue* sv) { 153 return sv->lvalue && sv->kind == SV_OPERAND && 154 api_operand_can_address(&sv->op); 155 } 156 157 /* A bit-field PLACE is a PLACE that additionally carries bit geometry (set by 158 * kit_cg_field when it projects to a bit-field). The plain load/store detect 159 * this and perform the extract/insert; there is no separate bit-field memop. */ 160 int api_sv_is_bitfield(const ApiSValue* sv) { 161 return sv->bitfield.bit_width != 0; 162 } 163 164 /* Rebuild the full BitFieldAccess the extract/insert helper consumes from the 165 * geometry the place carries plus the storage operand it addresses. The storage 166 * MemAccess is derived from the operand + field type, the way the old 167 * bf_from_access did, so the place need only carry the bit geometry. */ 168 /* Build the bit-field MemAccess that rides the generic load/store: the storage 169 * unit ({type,size}) plus the bf_* bit geometry from the place's descriptor. 170 * The CgTarget impl reconstructs a BitFieldAccess via bf_from_mem. */ 171 MemAccess api_mem_for_bitfield(KitCg* g, const ApiSValue* sv, 172 const Operand* storage, KitCgTypeId field_ty) { 173 MemAccess m = api_mem_for_lvalue(g, storage, field_ty); 174 if (sv->bitfield.bit_storage_size) m.size = sv->bitfield.bit_storage_size; 175 m.bf_offset = sv->bitfield.bit_offset; 176 m.bf_width = sv->bitfield.bit_width; 177 m.bf_signed = sv->bitfield.bit_signed ? 1 : 0; 178 return m; 179 } 180 181 void api_stack_grow(KitCg* g, u32 want) { 182 Heap* h = g->c->ctx->heap; 183 u32 cap = g->cap; 184 ApiSValue* nb; 185 if (cap >= want) return; 186 while (cap < want) cap = cap ? cap * 2u : API_CG_STACK_INITIAL; 187 nb = (ApiSValue*)h->alloc(h, sizeof(ApiSValue) * cap, _Alignof(ApiSValue)); 188 if (g->stack) { 189 memcpy(nb, g->stack, sizeof(ApiSValue) * g->sp); 190 h->free(h, g->stack, sizeof(ApiSValue) * g->cap); 191 } 192 g->stack = nb; 193 g->cap = cap; 194 } 195 196 void api_push(KitCg* g, ApiSValue v) { 197 /* An aggregate (record) can only ever be a PLACE: it is addressed, loaded, 198 * and passed by SRET/BYVAL/BYREF, never materialized as a scalar VALUE. Catch 199 * any aggregate VALUE at the point it would enter the stack. i128/f128 are 200 * scalars (cg_type_is_aggregate is false for them), so they remain valid 201 * VALUEs and are unaffected. */ 202 if (cg_type_is_aggregate(g->c, api_sv_type(&v)) && !api_is_lvalue_sv(&v)) { 203 compiler_panic(g->c, g->cur_loc, 204 "KitCg: aggregate must be a place, not a value; load the " 205 "place or pass it by reference"); 206 } 207 api_stack_grow(g, g->sp + 1); 208 g->stack[g->sp++] = v; 209 } 210 211 ApiSValue api_pop(KitCg* g) { 212 if (g->sp == 0) { 213 compiler_panic(g->c, g->cur_loc, "KitCg: stack underflow"); 214 } 215 return g->stack[--g->sp]; 216 } 217 218 /* ---- local helpers ---- */ 219 220 CGLocal api_local_of_sv(const ApiSValue* sv) { 221 if (sv->kind == SV_ARITH || sv->kind == SV_CMP) return (CGLocal)CG_LOCAL_NONE; 222 if (sv->op.kind == OPK_LOCAL) return sv->op.v.local; 223 if (sv->op.kind == OPK_INDIRECT) return sv->op.v.ind.base; 224 return (CGLocal)CG_LOCAL_NONE; 225 } 226 227 void api_set_owned_local(ApiSValue* sv, CGLocal r) { 228 if (sv->op.kind == OPK_LOCAL) 229 sv->op.v.local = r; 230 else if (sv->op.kind == OPK_INDIRECT) 231 sv->op.v.ind.base = r; 232 } 233 234 KitCgTypeId api_owned_local_type(KitCg* g, const ApiSValue* sv) { 235 if (sv->op.kind == OPK_INDIRECT) { 236 KitCgTypeId base = sv->type ? sv->type : builtin_id(KIT_CG_BUILTIN_VOID); 237 return cg_type_ptr_to(g->c, base); 238 } 239 return api_sv_type(sv); 240 } 241 242 /* ---- temporary local allocation ---- */ 243 244 void api_temp_locals_begin(KitCg* g) { (void)g; } 245 246 void api_temp_locals_finish(KitCg* g) { (void)g; } 247 248 CGLocal api_alloc_temp_local(KitCg* g, KitCgTypeId ty) { 249 CGLocalDesc d; 250 CGLocal local; 251 memset(&d, 0, sizeof d); 252 d.type = ty; 253 if (ty) { 254 d.size = abi_cg_sizeof(g->c->abi, ty); 255 d.align = abi_cg_alignof(g->c->abi, ty); 256 } 257 /* A split-lane 8-byte scalar temp must live in memory so its two words are 258 * addressable for lane ops and the multi-part ABI path; the allocator gives 259 * an unflagged scalar one value slot, which would truncate it. (wide16 temps 260 * are already forced via the size>word auto-home in cg_ir_lower.) */ 261 if (ty && api_is_wide8_scalar_type(g->c, ty)) 262 d.flags |= CG_LOCAL_MEMORY_REQUIRED; 263 local = g->target->local(g->target, &d); 264 if (local == CG_LOCAL_NONE) { 265 compiler_panic(g->c, g->cur_loc, 266 "KitCg: target failed to allocate temporary local"); 267 } 268 return local; 269 } 270 271 void api_release_temp_local(KitCg* g, CGLocal r) { 272 (void)g; 273 (void)r; 274 } 275 276 MemAccess api_mem_for_lvalue(KitCg* g, const Operand* lv, KitCgTypeId ty) { 277 MemAccess m; 278 memset(&m, 0, sizeof m); 279 m.type = ty; 280 m.size = ty ? abi_cg_sizeof(g->c->abi, ty) : 0; 281 m.align = ty ? abi_cg_alignof(g->c->abi, ty) : 0; 282 m.flags = MF_NONE; 283 if (lv->kind == OPK_LOCAL) { 284 m.alias.kind = (u8)ALIAS_LOCAL; 285 m.alias.v.local_id = (i32)lv->v.local; 286 } else if (lv->kind == OPK_GLOBAL) { 287 m.alias.kind = (u8)ALIAS_GLOBAL; 288 } else { 289 m.alias.kind = (u8)ALIAS_UNKNOWN; 290 } 291 return m; 292 } 293 294 MemAccess api_mem_from_access(KitCg* g, const Operand* lv, 295 KitCgMemAccess access) { 296 KitCgTypeId ty = resolve_type(g->c, access.type); 297 MemAccess m = api_mem_for_lvalue(g, lv, ty); 298 if (access.align) m.align = access.align; 299 m.addr_space = (u16)access.address_space; 300 if (access.flags & KIT_CG_MEM_VOLATILE) m.flags |= MF_VOLATILE; 301 if (!access.align || (ty && access.align < abi_cg_alignof(g->c->abi, ty))) { 302 m.flags |= MF_UNALIGNED; 303 } 304 return m; 305 } 306 307 KitCgTypeId api_mem_access_type(KitCg* g, KitCgMemAccess access, 308 KitCgTypeId fallback, const char* who) { 309 KitCgTypeId ty = resolve_type(g->c, access.type); 310 if (!ty) ty = resolve_type(g->c, fallback); 311 if (!ty) { 312 compiler_panic(g->c, g->cur_loc, "KitCg: %.*s has no value type", 313 SLICE_ARG(slice_from_cstr(who))); 314 } 315 return ty; 316 } 317 318 u32 api_mem_type_size(KitCg* g, KitCgTypeId ty, const char* who) { 319 ty = resolve_type(g->c, ty); 320 if (!ty) { 321 compiler_panic(g->c, g->cur_loc, "KitCg: %.*s has invalid type", 322 SLICE_ARG(slice_from_cstr(who))); 323 } 324 if (cg_type_is_void(g->c, ty)) { 325 compiler_panic(g->c, g->cur_loc, "KitCg: %.*s uses void type", 326 SLICE_ARG(slice_from_cstr(who))); 327 } 328 return abi_cg_sizeof(g->c->abi, ty); 329 } 330 331 void api_require_scalar_mem_type(KitCg* g, const char* who, KitCgTypeId ty) { 332 if (cg_type_is_aggregate(g->c, ty)) { 333 compiler_panic(g->c, g->cur_loc, 334 "KitCg: %.*s cannot use aggregate value type (size %u); " 335 "copy fields or use byte memory operations", 336 SLICE_ARG(slice_from_cstr(who)), 337 (unsigned)api_mem_type_size(g, ty, who)); 338 } 339 (void)api_mem_type_size(g, ty, who); 340 } 341 342 void api_require_pointer_value(KitCg* g, const char* who, KitCgTypeId ty) { 343 if (!cg_type_pointee(g->c, ty)) { 344 compiler_panic(g->c, g->cur_loc, "KitCg: %.*s operand must be a pointer", 345 SLICE_ARG(slice_from_cstr(who))); 346 } 347 } 348 349 void api_validate_memory_value(KitCg* g, const char* who, KitCgTypeId access_ty, 350 KitCgTypeId value_ty) { 351 u32 access_size; 352 u32 value_size; 353 access_ty = resolve_type(g->c, access_ty); 354 value_ty = resolve_type(g->c, value_ty); 355 api_require_scalar_mem_type(g, who, access_ty); 356 if (!value_ty) { 357 compiler_panic(g->c, g->cur_loc, "KitCg: %.*s value has no type", 358 SLICE_ARG(slice_from_cstr(who))); 359 } 360 if (cg_type_is_aggregate(g->c, value_ty)) { 361 compiler_panic(g->c, g->cur_loc, 362 "KitCg: %.*s value is aggregate (size %u); copy fields or " 363 "use byte memory operations", 364 SLICE_ARG(slice_from_cstr(who)), 365 (unsigned)api_mem_type_size(g, value_ty, who)); 366 } 367 access_size = api_mem_type_size(g, access_ty, who); 368 value_size = api_mem_type_size(g, value_ty, who); 369 if (access_size != value_size || 370 api_type_is_float(g->c, access_ty) != api_type_is_float(g->c, value_ty)) { 371 compiler_panic(g->c, g->cur_loc, 372 "KitCg: %.*s value type/size mismatch: access size %u, " 373 "value size %u", 374 SLICE_ARG(slice_from_cstr(who)), (unsigned)access_size, 375 (unsigned)value_size); 376 } 377 } 378 379 void api_release_operand_local(KitCg* g, Operand op) { 380 if (op.kind == OPK_LOCAL) api_release_temp_local(g, op.v.local); 381 } 382 383 int api_sv_owns_operand_local(const ApiSValue* sv, const Operand* op) { 384 return sv->res == RES_LOCAL && op->kind == OPK_LOCAL && 385 sv->op.kind == OPK_LOCAL && sv->op.v.local == op->v.local; 386 } 387 388 void api_ensure_local(KitCg* g, ApiSValue* sv) { 389 if (sv->kind == SV_CMP) { 390 KitCgTypeId ty = api_sv_type(sv); 391 Operand dst; 392 if (sv->delayed.cmp.a_owned && sv->delayed.cmp.a.kind == OPK_LOCAL && 393 api_unalias_type(g->c, sv->delayed.cmp.a.type) == 394 api_unalias_type(g->c, ty)) { 395 dst = api_op_local(sv->delayed.cmp.a.v.local, ty); 396 } else if (sv->delayed.cmp.b_owned && sv->delayed.cmp.b.kind == OPK_LOCAL && 397 api_unalias_type(g->c, sv->delayed.cmp.b.type) == 398 api_unalias_type(g->c, ty)) { 399 dst = api_op_local(sv->delayed.cmp.b.v.local, ty); 400 } else { 401 CGLocal r = 402 api_alloc_temp_local(g, ty ? ty : builtin_id(KIT_CG_BUILTIN_I32)); 403 dst = api_op_local(r, ty); 404 } 405 api_materialize_cmp_to(g, sv, dst); 406 return; 407 } 408 if (sv->kind == SV_ARITH) { 409 KitCgTypeId ty = api_sv_type(sv); 410 Operand dst; 411 if (sv->delayed.arith.a_owned && sv->delayed.arith.a.kind == OPK_LOCAL && 412 api_unalias_type(g->c, sv->delayed.arith.a.type) == 413 api_unalias_type(g->c, ty)) { 414 dst = api_op_local(sv->delayed.arith.a.v.local, ty); 415 } else if (api_arith_rhs_reusable(sv) && sv->delayed.arith.b_owned && 416 sv->delayed.arith.b.kind == OPK_LOCAL && 417 api_unalias_type(g->c, sv->delayed.arith.b.type) == 418 api_unalias_type(g->c, ty)) { 419 dst = api_op_local(sv->delayed.arith.b.v.local, ty); 420 } else { 421 CGLocal r = 422 api_alloc_temp_local(g, ty ? ty : builtin_id(KIT_CG_BUILTIN_I32)); 423 dst = api_op_local(r, ty); 424 } 425 api_materialize_arith_to(g, sv, dst); 426 return; 427 } 428 return; 429 } 430 431 Operand api_force_local(KitCg* g, ApiSValue* v, KitCgTypeId ty) { 432 CgTarget* T = g->target; 433 ty = api_unalias_type(g->c, ty); 434 api_ensure_local(g, v); 435 if (v->op.kind == OPK_LOCAL && !api_is_lvalue_sv(v)) { 436 return v->op; 437 } 438 CGLocal r = api_alloc_temp_local(g, ty); 439 Operand dst = api_op_local(r, ty); 440 if (v->op.kind == OPK_IMM) { 441 T->load_imm(T, dst, v->op.v.imm); 442 } else if (api_is_lvalue_sv(v)) { 443 T->load(T, dst, v->op, api_mem_for_lvalue(g, &v->op, ty)); 444 if (v->op.kind == OPK_INDIRECT) { 445 api_release_temp_local(g, v->op.v.ind.base); 446 } 447 } else if (v->op.kind == OPK_GLOBAL) { 448 T->addr_of(T, dst, v->op); 449 } else { 450 compiler_panic(g->c, g->cur_loc, "KitCg: cannot force operand to local"); 451 } 452 v->op = dst; 453 v->res = RES_LOCAL; 454 return dst; 455 } 456 457 Operand api_force_local_unless_imm(KitCg* g, ApiSValue* v, KitCgTypeId ty) { 458 if (api_sv_op_is(v, OPK_IMM)) return v->op; 459 return api_force_local(g, v, ty); 460 } 461 462 void api_release(KitCg* g, ApiSValue* sv) { 463 if (sv->kind == SV_CMP) { 464 api_release_cmp(g, sv); 465 } else if (sv->kind == SV_ARITH) { 466 api_release_arith(g, sv); 467 } else if (sv->res == RES_LOCAL) { 468 api_release_temp_local(g, (CGLocal)api_local_of_sv(sv)); 469 } 470 sv->res = RES_INHERENT; 471 } 472 473 /* ---- BinOp / UnOp / CmpOp mapping ---- */ 474 475 BinOp api_map_int_binop(KitCgIntBinOp op) { 476 switch (op) { 477 case KIT_CG_INT_ADD: 478 return BO_IADD; 479 case KIT_CG_INT_SUB: 480 return BO_ISUB; 481 case KIT_CG_INT_MUL: 482 return BO_IMUL; 483 case KIT_CG_INT_SDIV: 484 return BO_SDIV; 485 case KIT_CG_INT_UDIV: 486 return BO_UDIV; 487 case KIT_CG_INT_SREM: 488 return BO_SREM; 489 case KIT_CG_INT_UREM: 490 return BO_UREM; 491 case KIT_CG_INT_AND: 492 return BO_AND; 493 case KIT_CG_INT_OR: 494 return BO_OR; 495 case KIT_CG_INT_XOR: 496 return BO_XOR; 497 case KIT_CG_INT_SHL: 498 return BO_SHL; 499 case KIT_CG_INT_LSHR: 500 return BO_SHR_U; 501 case KIT_CG_INT_ASHR: 502 return BO_SHR_S; 503 } 504 return BO_IADD; 505 } 506 507 BinOp api_map_fp_binop(KitCgFpBinOp op) { 508 switch (op) { 509 case KIT_CG_FP_ADD: 510 return BO_FADD; 511 case KIT_CG_FP_SUB: 512 return BO_FSUB; 513 case KIT_CG_FP_MUL: 514 return BO_FMUL; 515 case KIT_CG_FP_DIV: 516 return BO_FDIV; 517 } 518 return BO_FADD; 519 } 520 521 UnOp api_map_int_unop(KitCgIntUnOp op) { 522 switch (op) { 523 case KIT_CG_INT_NEG: 524 return UO_NEG; 525 case KIT_CG_INT_NOT: 526 return UO_NOT; 527 case KIT_CG_INT_BNOT: 528 return UO_BNOT; 529 } 530 return UO_NEG; 531 } 532 533 CmpOp api_map_int_cmp(KitCgIntCmpOp op) { 534 switch (op) { 535 case KIT_CG_INT_EQ: 536 return CMP_EQ; 537 case KIT_CG_INT_NE: 538 return CMP_NE; 539 case KIT_CG_INT_LT_S: 540 return CMP_LT_S; 541 case KIT_CG_INT_LE_S: 542 return CMP_LE_S; 543 case KIT_CG_INT_GT_S: 544 return CMP_GT_S; 545 case KIT_CG_INT_GE_S: 546 return CMP_GE_S; 547 case KIT_CG_INT_LT_U: 548 return CMP_LT_U; 549 case KIT_CG_INT_LE_U: 550 return CMP_LE_U; 551 case KIT_CG_INT_GT_U: 552 return CMP_GT_U; 553 case KIT_CG_INT_GE_U: 554 return CMP_GE_U; 555 } 556 return CMP_EQ; 557 } 558 559 /* 1:1: the internal FP block mirrors KitCgFpCmpOp's order, so the public 560 * ordered/unordered distinction is preserved all the way to the backends. */ 561 CmpOp api_map_fp_cmp(KitCgFpCmpOp op) { 562 switch (op) { 563 case KIT_CG_FP_OEQ: 564 return CMP_OEQ_F; 565 case KIT_CG_FP_ONE: 566 return CMP_ONE_F; 567 case KIT_CG_FP_OLT: 568 return CMP_OLT_F; 569 case KIT_CG_FP_OLE: 570 return CMP_OLE_F; 571 case KIT_CG_FP_OGT: 572 return CMP_OGT_F; 573 case KIT_CG_FP_OGE: 574 return CMP_OGE_F; 575 case KIT_CG_FP_UEQ: 576 return CMP_UEQ_F; 577 case KIT_CG_FP_UNE: 578 return CMP_UNE_F; 579 case KIT_CG_FP_ULT: 580 return CMP_ULT_F; 581 case KIT_CG_FP_ULE: 582 return CMP_ULE_F; 583 case KIT_CG_FP_UGT: 584 return CMP_UGT_F; 585 case KIT_CG_FP_UGE: 586 return CMP_UGE_F; 587 } 588 return CMP_OEQ_F; 589 } 590 591 Operand api_lvalue_addr(KitCg* g, ApiSValue* v, KitCgTypeId pty) { 592 CgTarget* T; 593 ApiSourceLocal* rec; 594 CGLocal r; 595 Operand dst; 596 api_local_const_address_taken(g, v->source_local); 597 api_ensure_local(g, v); 598 if (!api_is_lvalue_sv(v)) { 599 compiler_panic(g->c, g->cur_loc, "KitCg: addr operand is not an lvalue"); 600 } 601 T = g->target; 602 r = api_alloc_temp_local(g, pty); 603 dst = api_op_local(r, pty); 604 rec = v->source_local != KIT_CG_LOCAL_NONE 605 ? api_local_from_handle(g, v->source_local) 606 : NULL; 607 if (rec && rec->storage != CG_LOCAL_NONE && T->local_addr) 608 T->local_addr(T, dst, &rec->desc, rec->storage); 609 else 610 T->addr_of(T, dst, v->op); 611 return dst; 612 } 613 614 /* ---- C-symbol mangling ---- */