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 }