kit

kit
git clone https://git.ryansepassi.com/git/kit.git
Log | Files | Refs | README

const.c (14829B)


      1 #include "cg/internal.h"
      2 
      3 static u64 const_mask(u32 width) {
      4   if (width >= 64u) return UINT64_MAX;
      5   return (1ull << width) - 1ull;
      6 }
      7 
      8 static int const_type_width(KitCg* g, KitCgTypeId type, u32* width_out) {
      9   u32 width;
     10   if (!g || !width_out) return 0;
     11   width = api_int_like_width(g->c, type);
     12   if (!width || width > 128u) return 0;
     13   *width_out = width;
     14   return 1;
     15 }
     16 
     17 static KitCgConstInt const_normalize(KitCgConstInt v, u32 width) {
     18   v.width = (uint16_t)width;
     19   if (!v.known || width == 0 || width > 128u) {
     20     memset(&v, 0, sizeof v);
     21     v.width = (uint16_t)width;
     22     return v;
     23   }
     24   if (width < 64u) {
     25     v.lo &= const_mask(width);
     26     v.hi = 0;
     27   } else if (width == 64u) {
     28     v.hi = 0;
     29   } else if (width < 128u) {
     30     v.hi &= const_mask(width - 64u);
     31   }
     32   v.known = 1;
     33   return v;
     34 }
     35 
     36 static int const_is_zero(KitCgConstInt v) {
     37   return v.known && v.lo == 0 && v.hi == 0;
     38 }
     39 
     40 static int const_sign_bit(KitCgConstInt v) {
     41   u32 width = v.width;
     42   if (!width) return 0;
     43   if (width <= 64u) return ((v.lo >> (width - 1u)) & 1u) != 0;
     44   return ((v.hi >> (width - 65u)) & 1u) != 0;
     45 }
     46 
     47 static int const_cmp_unsigned(KitCgConstInt a, KitCgConstInt b) {
     48   if (a.hi != b.hi) return a.hi < b.hi ? -1 : 1;
     49   if (a.lo != b.lo) return a.lo < b.lo ? -1 : 1;
     50   return 0;
     51 }
     52 
     53 static int const_cmp_signed(KitCgConstInt a, KitCgConstInt b) {
     54   int as = const_sign_bit(a);
     55   int bs = const_sign_bit(b);
     56   if (as != bs) return as ? -1 : 1;
     57   return const_cmp_unsigned(a, b);
     58 }
     59 
     60 static u64 const_low_masked(KitCgConstInt v) {
     61   if (v.width >= 64u) return v.lo;
     62   return v.lo & const_mask(v.width);
     63 }
     64 
     65 static u64 const_abs_signed64_bits(u64 bits, u32 width, int* neg_out) {
     66   u64 mask = const_mask(width);
     67   int neg = width && ((bits >> (width - 1u)) & 1u) != 0;
     68   bits &= mask;
     69   if (neg) bits = ((~bits) + 1u) & mask;
     70   if (neg_out) *neg_out = neg;
     71   return bits;
     72 }
     73 
     74 static int const_divrem64(BinOp op, u32 width, u64 a, u64 b, u64* out) {
     75   u64 mask = const_mask(width);
     76   if (!out || b == 0) return 0;
     77   a &= mask;
     78   b &= mask;
     79   switch (op) {
     80     case BO_UDIV:
     81       *out = (a / b) & mask;
     82       return 1;
     83     case BO_UREM:
     84       *out = (a % b) & mask;
     85       return 1;
     86     case BO_SDIV:
     87     case BO_SREM: {
     88       int an, bn;
     89       u64 aa = const_abs_signed64_bits(a, width, &an);
     90       u64 bb = const_abs_signed64_bits(b, width, &bn);
     91       u64 r;
     92       if (bb == 0) return 0;
     93       if (op == BO_SDIV) {
     94         r = aa / bb;
     95         if (an != bn) r = ((~r) + 1u) & mask;
     96       } else {
     97         r = aa % bb;
     98         if (an) r = ((~r) + 1u) & mask;
     99       }
    100       *out = r & mask;
    101       return 1;
    102     }
    103     default:
    104       return 0;
    105   }
    106 }
    107 
    108 static KitCgConstInt const_add(KitCgConstInt a, KitCgConstInt b) {
    109   KitCgConstInt r = a;
    110   u64 lo = a.lo + b.lo;
    111   u64 carry = lo < a.lo;
    112   r.lo = lo;
    113   r.hi = a.hi + b.hi + carry;
    114   return const_normalize(r, r.width);
    115 }
    116 
    117 static KitCgConstInt const_sub(KitCgConstInt a, KitCgConstInt b) {
    118   KitCgConstInt r = a;
    119   u64 borrow = a.lo < b.lo;
    120   r.lo = a.lo - b.lo;
    121   r.hi = a.hi - b.hi - borrow;
    122   return const_normalize(r, r.width);
    123 }
    124 
    125 static KitCgConstInt const_mul(KitCgConstInt a, KitCgConstInt b) {
    126   KitCgConstInt r = a;
    127   u16 al[8];
    128   u16 bl[8];
    129   u16 rl[8];
    130   u32 i;
    131   u32 k;
    132   for (i = 0; i < 4u; ++i) {
    133     al[i] = (u16)(a.lo >> (i * 16u));
    134     bl[i] = (u16)(b.lo >> (i * 16u));
    135     al[i + 4u] = (u16)(a.hi >> (i * 16u));
    136     bl[i + 4u] = (u16)(b.hi >> (i * 16u));
    137     rl[i] = 0;
    138     rl[i + 4u] = 0;
    139   }
    140   {
    141     u64 carry = 0;
    142     for (k = 0; k < 8u; ++k) {
    143       u64 sum = carry;
    144       for (i = 0; i <= k; ++i) sum += (u32)al[i] * (u32)bl[k - i];
    145       rl[k] = (u16)sum;
    146       carry = sum >> 16;
    147     }
    148   }
    149   r.lo = 0;
    150   r.hi = 0;
    151   for (i = 0; i < 4u; ++i) {
    152     r.lo |= (u64)rl[i] << (i * 16u);
    153     r.hi |= (u64)rl[i + 4u] << (i * 16u);
    154   }
    155   return const_normalize(r, r.width);
    156 }
    157 
    158 static KitCgConstInt const_shl(KitCgConstInt a, u32 sh) {
    159   KitCgConstInt r = a;
    160   sh &= (u32)(a.width - 1u);
    161   if (sh == 0) return const_normalize(r, r.width);
    162   if (sh >= 64u) {
    163     r.hi = a.lo << (sh - 64u);
    164     r.lo = 0;
    165   } else {
    166     r.hi = (a.hi << sh) | (a.lo >> (64u - sh));
    167     r.lo = a.lo << sh;
    168   }
    169   return const_normalize(r, r.width);
    170 }
    171 
    172 static KitCgConstInt const_lshr(KitCgConstInt a, u32 sh) {
    173   KitCgConstInt r = a;
    174   sh &= (u32)(a.width - 1u);
    175   if (sh == 0) return const_normalize(r, r.width);
    176   if (sh >= 64u) {
    177     r.lo = a.hi >> (sh - 64u);
    178     r.hi = 0;
    179   } else {
    180     r.lo = (a.lo >> sh) | (a.hi << (64u - sh));
    181     r.hi = a.hi >> sh;
    182   }
    183   return const_normalize(r, r.width);
    184 }
    185 
    186 static KitCgConstInt const_ashr(KitCgConstInt a, u32 sh) {
    187   KitCgConstInt r = const_lshr(a, sh);
    188   u32 width = a.width;
    189   if (!const_sign_bit(a)) return r;
    190   sh &= (u32)(width - 1u);
    191   if (sh == 0) return r;
    192   if (width <= 64u) {
    193     u64 fill = ~const_mask(width - sh);
    194     r.lo |= fill & const_mask(width);
    195     r.hi = 0;
    196   } else {
    197     u32 top_bits = sh;
    198     while (top_bits) {
    199       u32 bit = width - top_bits;
    200       if (bit < 64u)
    201         r.lo |= 1ull << bit;
    202       else
    203         r.hi |= 1ull << (bit - 64u);
    204       --top_bits;
    205     }
    206   }
    207   return const_normalize(r, width);
    208 }
    209 
    210 static KitCgConstInt const_sext(KitCgConstInt v, u32 src_width, u32 dst_width) {
    211   int neg;
    212   v = const_normalize(v, src_width);
    213   neg = const_sign_bit(v);
    214   v.width = (uint16_t)dst_width;
    215   if (neg && dst_width > src_width) {
    216     u32 bit;
    217     for (bit = src_width; bit < dst_width; ++bit) {
    218       if (bit < 64u)
    219         v.lo |= 1ull << bit;
    220       else
    221         v.hi |= 1ull << (bit - 64u);
    222     }
    223   }
    224   return const_normalize(v, dst_width);
    225 }
    226 
    227 int api_unevaluated(KitCg* g) { return g && g->unevaluated_depth != 0; }
    228 
    229 ApiSValue api_uneval_value(KitCg* g, KitCgTypeId type) {
    230   KitCgTypeId ty = type ? resolve_type(g->c, type) : KIT_CG_TYPE_NONE;
    231   return api_make_sv(api_op_imm(0, ty), ty);
    232 }
    233 
    234 ApiSValue api_uneval_place(KitCg* g, KitCgTypeId type) {
    235   KitCgTypeId ty = type ? resolve_type(g->c, type) : KIT_CG_TYPE_NONE;
    236   return api_make_lv(api_op_indirect(CG_LOCAL_NONE, 0, ty), ty);
    237 }
    238 
    239 ApiConstValue api_const_unknown(KitCgTypeId type) {
    240   ApiConstValue cv;
    241   memset(&cv, 0, sizeof cv);
    242   cv.type = type;
    243   return cv;
    244 }
    245 
    246 ApiConstValue api_const_int_result(KitCg* g, KitCgTypeId type, u64 lo, u64 hi,
    247                                    int is_signed) {
    248   ApiConstValue cv = api_const_unknown(type);
    249   u32 width;
    250   if (!const_type_width(g, type, &width)) return cv;
    251   cv.value.lo = lo;
    252   cv.value.hi = hi;
    253   cv.value.width = (uint16_t)width;
    254   cv.value.is_signed = is_signed ? 1u : 0u;
    255   cv.value.known = 1u;
    256   cv.value = const_normalize(cv.value, width);
    257   return cv;
    258 }
    259 
    260 ApiConstValue api_const_for_push(KitCg* g, KitCgTypeId type,
    261                                  const KitCgConstInt* value) {
    262   ApiConstValue cv = api_const_unknown(type);
    263   u32 width;
    264   if (!value || !value->known || !const_type_width(g, type, &width)) return cv;
    265   cv.type = type;
    266   cv.value = const_normalize(*value, width);
    267   cv.value.known = 1u;
    268   return cv;
    269 }
    270 
    271 ApiConstValue api_const_from_sv(KitCg* g, const ApiSValue* sv) {
    272   KitCgTypeId type;
    273   if (!g || !sv) return api_const_unknown(KIT_CG_TYPE_NONE);
    274   type = api_sv_type(sv);
    275   if (api_sv_kind(sv) == SV_OPERAND && sv->op.kind == OPK_IMM) {
    276     return api_const_int_result(g, type, (u64)sv->op.v.imm, 0, 0);
    277   }
    278   return api_const_unknown(type);
    279 }
    280 
    281 ApiConstValue api_const_at(KitCg* g, u32 depth) {
    282   if (!g || depth >= g->sp || !g->const_stack)
    283     return api_const_unknown(KIT_CG_TYPE_NONE);
    284   return g->const_stack[g->sp - 1u - depth];
    285 }
    286 
    287 void api_const_set_top(KitCg* g, ApiConstValue value) {
    288   if (!g || !g->sp || !g->const_stack) return;
    289   g->const_stack[g->sp - 1u] = value;
    290 }
    291 
    292 void api_const_set_at(KitCg* g, u32 depth, ApiConstValue value) {
    293   if (!g || depth >= g->sp || !g->const_stack) return;
    294   g->const_stack[g->sp - 1u - depth] = value;
    295 }
    296 
    297 void api_const_copy_top_from(KitCg* g, ApiConstValue value) {
    298   api_const_set_top(g, value);
    299 }
    300 
    301 int api_const_fold_binop(KitCg* g, BinOp op, KitCgTypeId type, ApiConstValue a,
    302                          ApiConstValue b, u32 flags, ApiConstValue* out) {
    303   ApiConstValue r;
    304   u32 width;
    305   if (!out) return 0;
    306   r = api_const_unknown(type);
    307   if (!g || flags || !a.value.known || !b.value.known ||
    308       !const_type_width(g, type, &width)) {
    309     *out = r;
    310     return 0;
    311   }
    312   a.value = const_normalize(a.value, width);
    313   b.value = const_normalize(b.value, width);
    314   r = api_const_int_result(g, type, 0, 0, a.value.is_signed);
    315   switch (op) {
    316     case BO_IADD:
    317       r.value = const_add(a.value, b.value);
    318       break;
    319     case BO_ISUB:
    320       r.value = const_sub(a.value, b.value);
    321       break;
    322     case BO_IMUL:
    323       r.value = const_mul(a.value, b.value);
    324       break;
    325     case BO_AND:
    326       r.value.lo = a.value.lo & b.value.lo;
    327       r.value.hi = a.value.hi & b.value.hi;
    328       r.value = const_normalize(r.value, width);
    329       break;
    330     case BO_OR:
    331       r.value.lo = a.value.lo | b.value.lo;
    332       r.value.hi = a.value.hi | b.value.hi;
    333       r.value = const_normalize(r.value, width);
    334       break;
    335     case BO_XOR:
    336       r.value.lo = a.value.lo ^ b.value.lo;
    337       r.value.hi = a.value.hi ^ b.value.hi;
    338       r.value = const_normalize(r.value, width);
    339       break;
    340     case BO_SHL:
    341       r.value = const_shl(a.value, (u32)b.value.lo);
    342       break;
    343     case BO_SHR_U:
    344       r.value = const_lshr(a.value, (u32)b.value.lo);
    345       break;
    346     case BO_SHR_S:
    347       r.value = const_ashr(a.value, (u32)b.value.lo);
    348       break;
    349     case BO_SDIV:
    350     case BO_UDIV:
    351     case BO_SREM:
    352     case BO_UREM: {
    353       u64 folded;
    354       if (width > 64u || !const_divrem64(op, width, const_low_masked(a.value),
    355                                          const_low_masked(b.value), &folded)) {
    356         *out = api_const_unknown(type);
    357         return 0;
    358       }
    359       r.value =
    360           api_const_int_result(g, type, folded, 0, a.value.is_signed).value;
    361       break;
    362     }
    363     default:
    364       *out = api_const_unknown(type);
    365       return 0;
    366   }
    367   r.type = type;
    368   r.value.known = 1u;
    369   *out = r;
    370   return 1;
    371 }
    372 
    373 int api_const_fold_unop(KitCg* g, UnOp op, KitCgTypeId type, ApiConstValue a,
    374                         u32 flags, ApiConstValue* out) {
    375   ApiConstValue r;
    376   u32 width;
    377   if (!out) return 0;
    378   r = api_const_unknown(type);
    379   if (!g || flags || !a.value.known || !const_type_width(g, type, &width)) {
    380     *out = r;
    381     return 0;
    382   }
    383   a.value = const_normalize(a.value, width);
    384   r = api_const_int_result(g, type, 0, 0, a.value.is_signed);
    385   switch (op) {
    386     case UO_NEG:
    387       r.value.lo = ~a.value.lo;
    388       r.value.hi = ~a.value.hi;
    389       r.value = const_add(const_normalize(r.value, width),
    390                           api_const_int_result(g, type, 1, 0, 0).value);
    391       break;
    392     case UO_NOT:
    393       r.value.lo = const_is_zero(a.value) ? 1u : 0u;
    394       r.value.hi = 0;
    395       r.value = const_normalize(r.value, width);
    396       break;
    397     case UO_BNOT:
    398       r.value.lo = ~a.value.lo;
    399       r.value.hi = ~a.value.hi;
    400       r.value = const_normalize(r.value, width);
    401       break;
    402     default:
    403       *out = api_const_unknown(type);
    404       return 0;
    405   }
    406   r.type = type;
    407   r.value.known = 1u;
    408   *out = r;
    409   return 1;
    410 }
    411 
    412 int api_const_fold_cmp(KitCg* g, CmpOp op, ApiConstValue a, ApiConstValue b,
    413                        ApiConstValue* out) {
    414   KitCgTypeId bool_ty = builtin_id(KIT_CG_BUILTIN_I32);
    415   ApiConstValue r;
    416   u32 width = a.value.width ? a.value.width : b.value.width;
    417   int cmp;
    418   int ok;
    419   if (!out) return 0;
    420   r = api_const_unknown(bool_ty);
    421   if (!g || !a.value.known || !b.value.known || !width || width > 128u) {
    422     *out = r;
    423     return 0;
    424   }
    425   a.value = const_normalize(a.value, width);
    426   b.value = const_normalize(b.value, width);
    427   switch (op) {
    428     case CMP_EQ:
    429       ok = a.value.lo == b.value.lo && a.value.hi == b.value.hi;
    430       break;
    431     case CMP_NE:
    432       ok = a.value.lo != b.value.lo || a.value.hi != b.value.hi;
    433       break;
    434     case CMP_LT_U:
    435       ok = const_cmp_unsigned(a.value, b.value) < 0;
    436       break;
    437     case CMP_LE_U:
    438       ok = const_cmp_unsigned(a.value, b.value) <= 0;
    439       break;
    440     case CMP_GT_U:
    441       ok = const_cmp_unsigned(a.value, b.value) > 0;
    442       break;
    443     case CMP_GE_U:
    444       ok = const_cmp_unsigned(a.value, b.value) >= 0;
    445       break;
    446     case CMP_LT_S:
    447       cmp = const_cmp_signed(a.value, b.value);
    448       ok = cmp < 0;
    449       break;
    450     case CMP_LE_S:
    451       cmp = const_cmp_signed(a.value, b.value);
    452       ok = cmp <= 0;
    453       break;
    454     case CMP_GT_S:
    455       cmp = const_cmp_signed(a.value, b.value);
    456       ok = cmp > 0;
    457       break;
    458     case CMP_GE_S:
    459       cmp = const_cmp_signed(a.value, b.value);
    460       ok = cmp >= 0;
    461       break;
    462     default:
    463       *out = r;
    464       return 0;
    465   }
    466   r = api_const_int_result(g, bool_ty, ok ? 1u : 0u, 0, 0);
    467   *out = r;
    468   return 1;
    469 }
    470 
    471 int api_const_fold_convert(KitCg* g, ConvKind ck, KitCgTypeId src_type,
    472                            KitCgTypeId dst_type, ApiConstValue in,
    473                            ApiConstValue* out) {
    474   ApiConstValue r;
    475   u32 sw;
    476   u32 dw;
    477   if (!out) return 0;
    478   r = api_const_unknown(dst_type);
    479   if (!g || !in.value.known || !const_type_width(g, src_type, &sw) ||
    480       !const_type_width(g, dst_type, &dw)) {
    481     *out = r;
    482     return 0;
    483   }
    484   switch (ck) {
    485     case CV_TRUNC:
    486     case CV_ZEXT:
    487       r = api_const_int_result(g, dst_type, in.value.lo, in.value.hi,
    488                                in.value.is_signed);
    489       break;
    490     case CV_SEXT:
    491       r = api_const_int_result(g, dst_type, 0, 0, 1);
    492       r.value = const_sext(in.value, sw, dw);
    493       r.value.known = 1u;
    494       r.value.is_signed = 1u;
    495       break;
    496     case CV_BITCAST:
    497       if (sw != dw) {
    498         *out = r;
    499         return 0;
    500       }
    501       r = api_const_int_result(g, dst_type, in.value.lo, in.value.hi,
    502                                in.value.is_signed);
    503       break;
    504     default:
    505       *out = r;
    506       return 0;
    507   }
    508   r.type = dst_type;
    509   *out = r;
    510   return r.value.known != 0;
    511 }
    512 
    513 void kit_cg_unevaluated_push(KitCg* g) {
    514   if (!g) return;
    515   ++g->unevaluated_depth;
    516   CG_REQUIRE(g, g->unevaluated_depth != 0, "KitCg: unevaluated depth overflow");
    517 }
    518 
    519 void kit_cg_unevaluated_pop(KitCg* g) {
    520   if (!g) return;
    521   CG_REQUIRE(g, g->unevaluated_depth, "KitCg: unevaluated pop underflow");
    522   --g->unevaluated_depth;
    523 }
    524 
    525 int kit_cg_top_const_int_ex(KitCg* g, KitCgConstInt* out_value) {
    526   ApiConstValue cv;
    527   if (!g || !g->sp) return 0;
    528   cv = api_const_at(g, 0);
    529   if (!cv.value.known) return 0;
    530   if (out_value) *out_value = cv.value;
    531   return 1;
    532 }
    533 
    534 int kit_cg_top_const_i64(KitCg* g, int64_t* out_value) {
    535   KitCgConstInt v;
    536   if (!out_value || !kit_cg_top_const_int_ex(g, &v) || v.width > 64u) return 0;
    537   if (v.is_signed)
    538     *out_value = api_sign_extend_width(v.lo, v.width);
    539   else
    540     *out_value = (int64_t)const_low_masked(v);
    541   return 1;
    542 }
    543 
    544 int kit_cg_top_const_int(KitCg* g, int64_t* out_value) {
    545   return kit_cg_top_const_i64(g, out_value);
    546 }