ir.h (7778B)
1 #ifndef KIT_CG_IR_H 2 #define KIT_CG_IR_H 3 4 #include "cg/cgtarget.h" 5 #include "core/arena.h" 6 #include "core/hashmap.h" 7 8 HASHMAP_DEFINE(ObjSymSet, ObjSymId, u8, hash_u32); 9 10 typedef enum CgIrOp { 11 CG_IR_NOP, 12 CG_IR_LABEL, 13 14 CG_IR_LOAD_IMM, 15 CG_IR_LOAD_CONST, 16 CG_IR_COPY, 17 CG_IR_LOAD, 18 CG_IR_STORE, 19 CG_IR_ADDR_OF, 20 CG_IR_TLS_ADDR_OF, 21 CG_IR_AGG_COPY, 22 CG_IR_AGG_SET, 23 CG_IR_BITFIELD_LOAD, 24 CG_IR_BITFIELD_STORE, 25 26 CG_IR_BINOP, 27 CG_IR_UNOP, 28 CG_IR_CMP, 29 CG_IR_CONVERT, 30 31 CG_IR_CALL, 32 CG_IR_RET, 33 CG_IR_UNREACHABLE, 34 35 CG_IR_BR, 36 CG_IR_CMP_BRANCH, 37 CG_IR_SWITCH, 38 CG_IR_INDIRECT_BRANCH, 39 CG_IR_LOAD_LABEL_ADDR, 40 CG_IR_LOCAL_STATIC_DATA_BEGIN, 41 CG_IR_LOCAL_STATIC_DATA_WRITE, 42 CG_IR_LOCAL_STATIC_DATA_LABEL_ADDR, 43 CG_IR_LOCAL_STATIC_DATA_END, 44 CG_IR_SCOPE_BEGIN, 45 CG_IR_SCOPE_END, 46 CG_IR_BREAK_TO, 47 CG_IR_CONTINUE_TO, 48 49 CG_IR_ALLOCA, 50 CG_IR_VA_START, 51 CG_IR_VA_ARG, 52 CG_IR_VA_END, 53 CG_IR_VA_COPY, 54 55 CG_IR_ATOMIC_LOAD, 56 CG_IR_ATOMIC_STORE, 57 CG_IR_ATOMIC_RMW, 58 CG_IR_ATOMIC_CAS, 59 CG_IR_FENCE, 60 61 CG_IR_INTRINSIC, 62 CG_IR_ASM_BLOCK, 63 } CgIrOp; 64 65 typedef struct CgIrLocal { 66 CGLocal id; 67 CGLocalDesc desc; 68 u32 param_index; 69 u8 is_param; 70 u8 address_taken; 71 u8 pad[2]; 72 } CgIrLocal; 73 74 typedef struct CgIrParam { 75 CGLocal local; 76 CGParamDesc desc; 77 } CgIrParam; 78 79 typedef struct CgIrLabel { 80 Label id; 81 SrcLoc first_place_loc; 82 u32 nplaces; 83 } CgIrLabel; 84 85 typedef struct CgIrScope { 86 CGScope id; 87 CGScopeDesc desc; 88 } CgIrScope; 89 90 typedef struct CgIrTlsAux { 91 ObjSymId sym; 92 i64 addend; 93 } CgIrTlsAux; 94 95 typedef struct CgIrAggAux { 96 AggregateAccess access; 97 } CgIrAggAux; 98 99 typedef struct CgIrBitFieldAux { 100 BitFieldAccess access; 101 } CgIrBitFieldAux; 102 103 typedef struct CgIrCallAux { 104 CGCallDesc desc; 105 } CgIrCallAux; 106 107 typedef struct CgIrRetAux { 108 CGLocal value; /* CG_LOCAL_NONE when present == 0 (void return) */ 109 u8 present; 110 } CgIrRetAux; 111 112 typedef struct CgIrCmpBranchAux { 113 CmpOp op; 114 Label target; 115 } CgIrCmpBranchAux; 116 117 typedef struct CgIrSwitchAux { 118 KitCgTypeId selector_type; 119 Label default_label; 120 CGSwitchCase* cases; 121 u32 ncases; 122 u8 hint; 123 u8 opt_level; 124 u8 pad[2]; 125 } CgIrSwitchAux; 126 127 typedef struct CgIrIndirectAux { 128 Label* targets; 129 u32 ntargets; 130 } CgIrIndirectAux; 131 132 typedef struct CgIrLocalStaticBeginAux { 133 CGLocalStaticDataDesc desc; 134 } CgIrLocalStaticBeginAux; 135 136 typedef struct CgIrLocalStaticWriteAux { 137 u8* data; 138 u64 len; 139 u8 has_data; 140 u8 pad[7]; 141 } CgIrLocalStaticWriteAux; 142 143 typedef struct CgIrLocalStaticLabelAux { 144 Label target; 145 i64 addend; 146 u32 width; 147 u32 address_space; 148 } CgIrLocalStaticLabelAux; 149 150 typedef struct CgIrScopeAux { 151 CGScope scope; 152 CGScopeDesc desc; 153 } CgIrScopeAux; 154 155 typedef struct CgIrAtomicAux { 156 MemAccess mem; 157 KitCgMemOrder order; 158 KitCgAtomicOp op; 159 KitCgMemOrder failure; 160 } CgIrAtomicAux; 161 162 typedef struct CgIrAsmAux { 163 char* tmpl; 164 AsmConstraint* outs; 165 Operand* out_ops; 166 AsmConstraint* ins; 167 Operand* in_ops; 168 Sym* clobbers; 169 u32 nout; 170 u32 nin; 171 u32 nclob; 172 u32 clobber_abi_sets; /* KitCgAsmClobberAbiSet bits */ 173 } CgIrAsmAux; 174 175 typedef struct CgIrIntrinsicAux { 176 IntrinKind kind; 177 Operand* dsts; 178 Operand* args; 179 u32 ndst; 180 u32 narg; 181 } CgIrIntrinsicAux; 182 183 /* Per-instruction semantic-mode flags carried in CgIrInst.flags. They select, 184 * per op, between the IR's portable edge-case semantics (default, bit clear) 185 * and the target's native-instruction semantics (bit set). Both modes are fully 186 * defined — the IR has no undefined behavior in either; the target-defined 187 * choice trades cross-target portability for the cheapest lowering when the 188 * source language already declares the edge undefined. See the "Semantic modes" 189 * and "Well-definedness" sections of doc/IR.md. Honoring these bits is per 190 * consumer; a consumer that does not understand a bit must implement the 191 * portable semantics, which is always a safe refinement. */ 192 typedef enum CgIrInstFlag { 193 CG_IR_INST_FLAG_NONE = 0, 194 /* BINOP sdiv/udiv/srem/urem: a zero divisor and INT_MIN/-1 follow the target 195 * divide instruction instead of the portable trap (zero) / wrap (INT_MIN/-1). 196 */ 197 CG_IR_INST_TARGET_DIV_EDGES = 1u << 0, 198 /* BINOP shl/shr_s/shr_u: an out-of-range shift count follows the target shift 199 * instruction instead of the portable reduce-modulo-width. */ 200 CG_IR_INST_TARGET_SHIFT_EDGES = 1u << 1, 201 /* CONVERT ftoi_s/ftoi_u: out-of-range / NaN / inf inputs follow the target 202 * convert instruction instead of the portable saturate (NaN -> 0). */ 203 CG_IR_INST_TARGET_FPTOINT_EDGES = 1u << 2, 204 } CgIrInstFlag; 205 206 typedef struct CgIrInst { 207 u32 id; 208 u16 op; 209 u16 flags; /* CgIrInstFlag: per-op portable-vs-target-defined edge semantics 210 */ 211 SrcLoc loc; 212 u32 nopnds; 213 Operand* opnds; 214 union { 215 i64 imm; 216 ConstBytes cbytes; 217 MemAccess mem; 218 void* aux; 219 } extra; 220 } CgIrInst; 221 222 typedef struct CgIrFunc { 223 Arena* arena; 224 Compiler* c; 225 CGFuncDesc desc; 226 227 CgIrInst* insts; 228 u32 ninsts; 229 u32 insts_cap; 230 231 CgIrLocal* locals; 232 u32 nlocals; 233 u32 locals_cap; 234 235 CgIrParam* params; 236 u32 nparams; 237 u32 params_cap; 238 239 CgIrLabel* labels; 240 u32 nlabels; 241 u32 labels_cap; 242 243 CgIrScope* scopes; 244 u32 nscopes; 245 u32 scopes_cap; 246 247 ObjSymSet call_refs; 248 ObjSymSet global_refs; 249 250 u32 next_inst_id; 251 u8 complete; 252 u8 removed; 253 u8 pad[2]; 254 } CgIrFunc; 255 256 typedef struct CgIrAlias { 257 ObjSymId alias_sym; 258 ObjSymId target_sym; 259 KitCgTypeId type; 260 } CgIrAlias; 261 262 /* A file-scope `__asm__(...)` block, captured verbatim for replay. The 263 * single-pass target emits it inline during recording; the optimizer path has 264 * no live target then, so the module retains it for opt_on_finalize to replay 265 * (see cg_ir_module_add_file_scope_asm). */ 266 typedef struct CgIrFileScopeAsm { 267 const char* src; 268 size_t len; 269 } CgIrFileScopeAsm; 270 271 typedef struct CgIrModule { 272 Arena* arena; 273 Compiler* c; 274 CgIrFunc** funcs; 275 u32 nfuncs; 276 u32 funcs_cap; 277 CgIrAlias* aliases; 278 u32 naliases; 279 u32 aliases_cap; 280 CgIrFileScopeAsm* file_scope_asms; 281 u32 nfile_scope_asms; 282 u32 file_scope_asms_cap; 283 } CgIrModule; 284 285 CgIrModule* cg_ir_module_new(Compiler*); 286 CgIrFunc* cg_ir_func_new(Compiler*, const CGFuncDesc*); 287 void cg_ir_module_add_func(CgIrModule*, CgIrFunc*); 288 void cg_ir_module_add_alias(CgIrModule*, ObjSymId alias_sym, 289 ObjSymId target_sym, KitCgTypeId type); 290 void cg_ir_module_add_file_scope_asm(CgIrModule*, const char* src, size_t len); 291 void cg_ir_module_refsets_fini(CgIrModule*); 292 293 void cg_ir_symset_init_lazy(Compiler*, ObjSymSet*); 294 void cg_ir_symset_add(Compiler*, ObjSymSet*, ObjSymId); 295 int cg_ir_symset_contains(const ObjSymSet*, ObjSymId); 296 void cg_ir_symset_fini(ObjSymSet*); 297 298 CGLocal cg_ir_func_add_local(CgIrFunc*, const CGLocalDesc*, int is_param, 299 u32 param_index); 300 void cg_ir_func_mark_local_address_taken(CgIrFunc*, CGLocal); 301 void cg_ir_func_add_param(CgIrFunc*, CGLocal, const CGParamDesc*); 302 Label cg_ir_func_add_label(CgIrFunc*); 303 void cg_ir_func_note_label_place(CgIrFunc*, Label, SrcLoc); 304 CGScope cg_ir_func_add_scope(CgIrFunc*, const CGScopeDesc*); 305 306 CgIrInst* cg_ir_emit(CgIrFunc*, CgIrOp, SrcLoc); 307 308 /* Render the semantic CG IR tape to `w` as line-oriented text. Stable enough 309 * for golden-file diffs; symbols appear by numeric id (sym#N). */ 310 void cg_ir_func_dump(const CgIrFunc*, Writer*); 311 312 Operand* cg_ir_dup_operands(Arena*, const Operand*, u32 n); 313 CGLocal* cg_ir_dup_locals(Arena*, const CGLocal*, u32 n); 314 Label* cg_ir_dup_labels(Arena*, const Label*, u32 n); 315 CGSwitchCase* cg_ir_dup_switch_cases(Arena*, const CGSwitchCase*, u32 n); 316 ConstBytes cg_ir_dup_const_bytes(Arena*, ConstBytes); 317 CGCallDesc cg_ir_dup_call_desc(Arena*, const CGCallDesc*); 318 AsmConstraint* cg_ir_dup_asm_constraints(Arena*, const AsmConstraint*, u32 n); 319 char* cg_ir_dup_cstr(Arena*, const char*); 320 321 #endif