kit

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

native_asm.c (7241B)


      1 #include "cg/native_asm.h"
      2 
      3 #include "arch/mc.h"
      4 #include "asm/asm.h"
      5 #include "asm/asm_lex.h"
      6 #include "core/pool.h" /* pool_slice for native_asm_resolve_pin */
      7 
      8 void native_file_scope_asm(NativeTarget* t, const char* src, size_t len) {
      9   AsmLexer* lex = asm_lex_open_mem(t->c, "<file-scope-asm>", src, len);
     10   asm_parse(t->c, lex, t->mc);
     11   asm_lex_close(lex);
     12 }
     13 
     14 void native_finalize(NativeTarget* t) {
     15   if (t->mc) mc_emit_eh_frame(t->mc);
     16 }
     17 
     18 const char* native_asm_constraint_body(const char* s) {
     19   if (!s) return "";
     20   if (s[0] == '=' && s[1] == '&') return s + 2;
     21   if (s[0] == '=' || s[0] == '+' || s[0] == '&') return s + 1;
     22   return s;
     23 }
     24 
     25 int native_asm_constraint_early(const char* s) {
     26   if (!s) return 0;
     27   return (s[0] == '=' && s[1] == '&') || s[0] == '&';
     28 }
     29 
     30 int native_asm_match_index(const char* s) {
     31   int n = 0;
     32   const char* p;
     33   if (!s || s[0] < '0' || s[0] > '9') return -1;
     34   for (p = s; *p >= '0' && *p <= '9'; ++p) n = n * 10 + (*p - '0');
     35   return n;
     36 }
     37 
     38 void native_asm_abi_clobber_masks(NativeTarget* t, u32 abi_sets, u32* int_mask,
     39                                   u32* fp_mask) {
     40   *int_mask = 0;
     41   *fp_mask = 0;
     42   if (abi_sets & KIT_CG_ASM_CLOBBER_ABI_CALLER_SAVED) {
     43     *int_mask |= native_target_caller_saved_mask(t, NATIVE_REG_INT);
     44     *fp_mask |= native_target_caller_saved_mask(t, NATIVE_REG_FP);
     45   }
     46   if (abi_sets & KIT_CG_ASM_CLOBBER_ABI_CALLEE_SAVED) {
     47     *int_mask |= native_target_callee_saved_mask(t, NATIVE_REG_INT);
     48     *fp_mask |= native_target_callee_saved_mask(t, NATIVE_REG_FP);
     49   }
     50 }
     51 
     52 int native_asm_constraint_reg_class(const char* constraint,
     53                                     NativeAllocClass* cls_out) {
     54   const char* body = native_asm_constraint_body(constraint);
     55   if (!body || !body[0]) return 0;
     56   if (body[0] == 'r') {
     57     if (cls_out) *cls_out = NATIVE_REG_INT;
     58     return 1;
     59   }
     60   if (body[0] == 'f' || body[0] == 'x' || body[0] == 'w') {
     61     if (cls_out) *cls_out = NATIVE_REG_FP;
     62     return 1;
     63   }
     64   return 0;
     65 }
     66 
     67 static int native_asm_default_operand_reg_ok(const NativeRegInfo* ri,
     68                                              NativeAllocClass cls, Reg reg) {
     69   if (!ri || cls >= ri->nclasses) return 0;
     70   const NativeAllocClassInfo* ci = &ri->classes[cls];
     71   for (u32 i = 0; i < ci->nphys; ++i) {
     72     const NativePhysRegInfo* pi = &ci->phys[i];
     73     if (pi->reg != reg) continue;
     74     return (pi->flags & NATIVE_REG_RESERVED) == 0;
     75   }
     76   return 0;
     77 }
     78 
     79 int native_asm_constraint_reg_info(NativeTarget* t, const char* constraint,
     80                                    NativeAsmConstraintInfo* out) {
     81   NativeAsmConstraintInfo info;
     82   const char* body = native_asm_constraint_body(constraint);
     83   memset(&info, 0, sizeof info);
     84   info.fixed_reg = REG_NONE;
     85   if (!body || !body[0]) return 0;
     86   if (t && t->regs && t->regs->asm_constraint_reg) {
     87     Reg fixed = REG_NONE;
     88     NativeAllocClass cls = NATIVE_REG_INT;
     89     u32 allowed_mask = 0;
     90     if (t->regs->asm_constraint_reg(t->regs, body, &cls, &fixed,
     91                                     &allowed_mask)) {
     92       if (allowed_mask) {
     93         u32 filtered = 0;
     94         for (Reg r = 0; r < 32; ++r) {
     95           if ((allowed_mask & (1u << r)) == 0) continue;
     96           if (t->regs->asm_operand_reg_ok) {
     97             if (!t->regs->asm_operand_reg_ok(t->regs, cls, r)) continue;
     98           } else if (!native_asm_default_operand_reg_ok(t->regs, cls, r)) {
     99             continue;
    100           }
    101           filtered |= 1u << r;
    102         }
    103         allowed_mask = filtered;
    104         if (!allowed_mask) return 0;
    105       }
    106       if (fixed != REG_NONE) {
    107         if (t->regs->asm_operand_reg_ok) {
    108           if (!t->regs->asm_operand_reg_ok(t->regs, cls, fixed)) return 0;
    109         } else if (!native_asm_default_operand_reg_ok(t->regs, cls, fixed)) {
    110           return 0;
    111         }
    112         if (fixed >= 32) return 0;
    113         if (allowed_mask && (allowed_mask & (1u << fixed)) == 0) return 0;
    114       }
    115       info.cls = cls;
    116       info.fixed_reg = fixed;
    117       info.allowed_mask = allowed_mask;
    118       if (out) *out = info;
    119       return 1;
    120     }
    121     return 0;
    122   }
    123   if (!native_asm_constraint_reg_class(constraint, &info.cls)) return 0;
    124   if (out) *out = info;
    125   return 1;
    126 }
    127 
    128 int native_asm_constraint_is_reg(NativeTarget* t, const char* constraint) {
    129   return native_asm_constraint_reg_info(t, constraint, NULL);
    130 }
    131 
    132 NativeAsmRegPinStatus native_asm_resolve_pin(NativeTarget* t, Sym reg,
    133                                              const char* constraint,
    134                                              NativeAsmRegPin* out) {
    135   Reg r;
    136   NativeAllocClass cls;
    137   NativeAsmConstraintInfo info;
    138   if (!reg) return NATIVE_ASM_REG_PIN_ABSENT;
    139   if (!t || !t->regs || !t->regs->resolve_name)
    140     return NATIVE_ASM_REG_PIN_UNKNOWN;
    141   if (t->regs->resolve_name(t->regs, pool_slice(t->c->global, reg), &r, &cls) !=
    142       0)
    143     return NATIVE_ASM_REG_PIN_UNKNOWN;
    144   if (t->regs->asm_operand_reg_ok) {
    145     if (!t->regs->asm_operand_reg_ok(t->regs, cls, r))
    146       return NATIVE_ASM_REG_PIN_FORBIDDEN;
    147   } else if (!native_asm_default_operand_reg_ok(t->regs, cls, r)) {
    148     return NATIVE_ASM_REG_PIN_FORBIDDEN;
    149   }
    150   if (!native_asm_constraint_reg_info(t, constraint, &info))
    151     return NATIVE_ASM_REG_PIN_BAD_CONSTRAINT;
    152   if (info.cls != cls) return NATIVE_ASM_REG_PIN_CLASS_MISMATCH;
    153   if (info.fixed_reg != REG_NONE && info.fixed_reg != r)
    154     return NATIVE_ASM_REG_PIN_FIXED_MISMATCH;
    155   if (info.allowed_mask && (r >= 32 || (info.allowed_mask & (1u << r)) == 0))
    156     return NATIVE_ASM_REG_PIN_FIXED_MISMATCH;
    157   if (out) {
    158     out->reg = r;
    159     out->cls = cls;
    160   }
    161   return NATIVE_ASM_REG_PIN_OK;
    162 }
    163 
    164 NativeAsmPinnedLoc native_asm_prepare_pinned_loc(NativeTarget* t, Sym reg,
    165                                                  const char* constraint,
    166                                                  KitCgTypeId type,
    167                                                  NativeLoc loc) {
    168   NativeAsmPinnedLoc out;
    169   NativeAsmRegPin pin;
    170   memset(&out, 0, sizeof out);
    171   out.loc = loc;
    172   out.pin_status = native_asm_resolve_pin(t, reg, constraint, &pin);
    173   if (out.pin_status == NATIVE_ASM_REG_PIN_ABSENT) return out;
    174   out.has_pin = 1u;
    175   if (out.pin_status != NATIVE_ASM_REG_PIN_OK) return out;
    176   if (loc.kind != NATIVE_LOC_REG) {
    177     out.loc = native_loc_reg(type, pin.cls, pin.reg);
    178     out.needs_stage = 1u;
    179     return out;
    180   }
    181   if ((Reg)loc.v.reg != pin.reg || (NativeAllocClass)loc.cls != pin.cls)
    182     out.wrong_reg = 1u;
    183   return out;
    184 }
    185 
    186 const char* native_asm_pin_status_message(NativeAsmRegPinStatus st) {
    187   switch (st) {
    188     case NATIVE_ASM_REG_PIN_ABSENT:
    189       return "no hard register pin";
    190     case NATIVE_ASM_REG_PIN_OK:
    191       return "hard register pin resolved";
    192     case NATIVE_ASM_REG_PIN_UNKNOWN:
    193       return "unknown asm register variable name";
    194     case NATIVE_ASM_REG_PIN_FORBIDDEN:
    195       return "asm register variable names an unsupported register";
    196     case NATIVE_ASM_REG_PIN_BAD_CONSTRAINT:
    197       return "asm register variable requires a register constraint";
    198     case NATIVE_ASM_REG_PIN_CLASS_MISMATCH:
    199       return "asm register variable class does not match its constraint";
    200     case NATIVE_ASM_REG_PIN_FIXED_MISMATCH:
    201       return "asm register variable conflicts with register constraint";
    202   }
    203   return "invalid asm register variable";
    204 }