| ... | ... | @@ -10,27 +10,374 @@ |
| 10 | 10 | #include "ir_print.hpp" |
| 11 | 11 | #include "os.hpp" |
| 12 | 12 | |
| 13 | static uint32_t hash_instruction_ptr(IrInstruction* instruction) { |
| 14 | return (uint32_t)(uintptr_t)instruction; |
| 15 | } |
| 16 | |
| 17 | static bool instruction_ptr_equal(IrInstruction* a, IrInstruction* b) { |
| 18 | return a == b; |
| 19 | } |
| 20 | |
| 21 | using InstructionSet = HashMap<IrInstruction*, uint8_t, hash_instruction_ptr, instruction_ptr_equal>; |
| 22 | using InstructionList = ZigList<IrInstruction*>; |
| 23 | |
| 13 | 24 | struct IrPrint { |
| 25 | size_t pass_num; |
| 14 | 26 | CodeGen *codegen; |
| 15 | 27 | FILE *f; |
| 16 | 28 | int indent; |
| 17 | 29 | int indent_size; |
| 30 | |
| 31 | // When printing pass 2 instructions referenced var instructions are not |
| 32 | // present in the instruction list. Thus we track which instructions |
| 33 | // are printed (per executable) and after each pass 2 instruction those |
| 34 | // var instructions are rendered in a trailing fashion. |
| 35 | InstructionSet printed; |
| 36 | InstructionList pending; |
| 18 | 37 | }; |
| 19 | 38 | |
| 20 | 39 | static void ir_print_other_instruction(IrPrint *irp, IrInstruction *instruction); |
| 21 | 40 | |
| 41 | static const char* ir_instruction_type_str(IrInstruction* instruction) { |
| 42 | switch (instruction->id) { |
| 43 | case IrInstructionIdInvalid: |
| 44 | return "Invalid"; |
| 45 | case IrInstructionIdDeclVarSrc: |
| 46 | return "DeclVarSrc"; |
| 47 | case IrInstructionIdDeclVarGen: |
| 48 | return "DeclVarGen"; |
| 49 | case IrInstructionIdBr: |
| 50 | return "Br"; |
| 51 | case IrInstructionIdCondBr: |
| 52 | return "CondBr"; |
| 53 | case IrInstructionIdSwitchBr: |
| 54 | return "SwitchBr"; |
| 55 | case IrInstructionIdSwitchVar: |
| 56 | return "SwitchVar"; |
| 57 | case IrInstructionIdSwitchElseVar: |
| 58 | return "SwitchElseVar"; |
| 59 | case IrInstructionIdSwitchTarget: |
| 60 | return "SwitchTarget"; |
| 61 | case IrInstructionIdPhi: |
| 62 | return "Phi"; |
| 63 | case IrInstructionIdUnOp: |
| 64 | return "UnOp"; |
| 65 | case IrInstructionIdBinOp: |
| 66 | return "BinOp"; |
| 67 | case IrInstructionIdLoadPtr: |
| 68 | return "LoadPtr"; |
| 69 | case IrInstructionIdLoadPtrGen: |
| 70 | return "LoadPtrGen"; |
| 71 | case IrInstructionIdStorePtr: |
| 72 | return "StorePtr"; |
| 73 | case IrInstructionIdFieldPtr: |
| 74 | return "FieldPtr"; |
| 75 | case IrInstructionIdStructFieldPtr: |
| 76 | return "StructFieldPtr"; |
| 77 | case IrInstructionIdUnionFieldPtr: |
| 78 | return "UnionFieldPtr"; |
| 79 | case IrInstructionIdElemPtr: |
| 80 | return "ElemPtr"; |
| 81 | case IrInstructionIdVarPtr: |
| 82 | return "VarPtr"; |
| 83 | case IrInstructionIdReturnPtr: |
| 84 | return "ReturnPtr"; |
| 85 | case IrInstructionIdCallSrc: |
| 86 | return "CallSrc"; |
| 87 | case IrInstructionIdCallGen: |
| 88 | return "CallGen"; |
| 89 | case IrInstructionIdConst: |
| 90 | return "Const"; |
| 91 | case IrInstructionIdReturn: |
| 92 | return "Return"; |
| 93 | case IrInstructionIdCast: |
| 94 | return "Cast"; |
| 95 | case IrInstructionIdResizeSlice: |
| 96 | return "ResizeSlice"; |
| 97 | case IrInstructionIdContainerInitList: |
| 98 | return "ContainerInitList"; |
| 99 | case IrInstructionIdContainerInitFields: |
| 100 | return "ContainerInitFields"; |
| 101 | case IrInstructionIdUnreachable: |
| 102 | return "Unreachable"; |
| 103 | case IrInstructionIdTypeOf: |
| 104 | return "TypeOf"; |
| 105 | case IrInstructionIdSetCold: |
| 106 | return "SetCold"; |
| 107 | case IrInstructionIdSetRuntimeSafety: |
| 108 | return "SetRuntimeSafety"; |
| 109 | case IrInstructionIdSetFloatMode: |
| 110 | return "SetFloatMode"; |
| 111 | case IrInstructionIdArrayType: |
| 112 | return "ArrayType"; |
| 113 | case IrInstructionIdAnyFrameType: |
| 114 | return "AnyFrameType"; |
| 115 | case IrInstructionIdSliceType: |
| 116 | return "SliceType"; |
| 117 | case IrInstructionIdGlobalAsm: |
| 118 | return "GlobalAsm"; |
| 119 | case IrInstructionIdAsm: |
| 120 | return "Asm"; |
| 121 | case IrInstructionIdSizeOf: |
| 122 | return "SizeOf"; |
| 123 | case IrInstructionIdTestNonNull: |
| 124 | return "TestNonNull"; |
| 125 | case IrInstructionIdOptionalUnwrapPtr: |
| 126 | return "OptionalUnwrapPtr"; |
| 127 | case IrInstructionIdOptionalWrap: |
| 128 | return "OptionalWrap"; |
| 129 | case IrInstructionIdUnionTag: |
| 130 | return "UnionTag"; |
| 131 | case IrInstructionIdClz: |
| 132 | return "Clz"; |
| 133 | case IrInstructionIdCtz: |
| 134 | return "Ctz"; |
| 135 | case IrInstructionIdPopCount: |
| 136 | return "PopCount"; |
| 137 | case IrInstructionIdBswap: |
| 138 | return "Bswap"; |
| 139 | case IrInstructionIdBitReverse: |
| 140 | return "BitReverse"; |
| 141 | case IrInstructionIdImport: |
| 142 | return "Import"; |
| 143 | case IrInstructionIdCImport: |
| 144 | return "CImport"; |
| 145 | case IrInstructionIdCInclude: |
| 146 | return "CInclude"; |
| 147 | case IrInstructionIdCDefine: |
| 148 | return "CDefine"; |
| 149 | case IrInstructionIdCUndef: |
| 150 | return "CUndef"; |
| 151 | case IrInstructionIdRef: |
| 152 | return "Ref"; |
| 153 | case IrInstructionIdRefGen: |
| 154 | return "RefGen"; |
| 155 | case IrInstructionIdCompileErr: |
| 156 | return "CompileErr"; |
| 157 | case IrInstructionIdCompileLog: |
| 158 | return "CompileLog"; |
| 159 | case IrInstructionIdErrName: |
| 160 | return "ErrName"; |
| 161 | case IrInstructionIdEmbedFile: |
| 162 | return "EmbedFile"; |
| 163 | case IrInstructionIdCmpxchgSrc: |
| 164 | return "CmpxchgSrc"; |
| 165 | case IrInstructionIdCmpxchgGen: |
| 166 | return "CmpxchgGen"; |
| 167 | case IrInstructionIdFence: |
| 168 | return "Fence"; |
| 169 | case IrInstructionIdTruncate: |
| 170 | return "Truncate"; |
| 171 | case IrInstructionIdIntCast: |
| 172 | return "IntCast"; |
| 173 | case IrInstructionIdFloatCast: |
| 174 | return "FloatCast"; |
| 175 | case IrInstructionIdIntToFloat: |
| 176 | return "IntToFloat"; |
| 177 | case IrInstructionIdFloatToInt: |
| 178 | return "FloatToInt"; |
| 179 | case IrInstructionIdBoolToInt: |
| 180 | return "BoolToInt"; |
| 181 | case IrInstructionIdIntType: |
| 182 | return "IntType"; |
| 183 | case IrInstructionIdVectorType: |
| 184 | return "VectorType"; |
| 185 | case IrInstructionIdBoolNot: |
| 186 | return "BoolNot"; |
| 187 | case IrInstructionIdMemset: |
| 188 | return "Memset"; |
| 189 | case IrInstructionIdMemcpy: |
| 190 | return "Memcpy"; |
| 191 | case IrInstructionIdSliceSrc: |
| 192 | return "SliceSrc"; |
| 193 | case IrInstructionIdSliceGen: |
| 194 | return "SliceGen"; |
| 195 | case IrInstructionIdMemberCount: |
| 196 | return "MemberCount"; |
| 197 | case IrInstructionIdMemberType: |
| 198 | return "MemberType"; |
| 199 | case IrInstructionIdMemberName: |
| 200 | return "MemberName"; |
| 201 | case IrInstructionIdBreakpoint: |
| 202 | return "Breakpoint"; |
| 203 | case IrInstructionIdReturnAddress: |
| 204 | return "ReturnAddress"; |
| 205 | case IrInstructionIdFrameAddress: |
| 206 | return "FrameAddress"; |
| 207 | case IrInstructionIdFrameHandle: |
| 208 | return "FrameHandle"; |
| 209 | case IrInstructionIdFrameType: |
| 210 | return "FrameType"; |
| 211 | case IrInstructionIdFrameSizeSrc: |
| 212 | return "FrameSizeSrc"; |
| 213 | case IrInstructionIdFrameSizeGen: |
| 214 | return "FrameSizeGen"; |
| 215 | case IrInstructionIdAlignOf: |
| 216 | return "AlignOf"; |
| 217 | case IrInstructionIdOverflowOp: |
| 218 | return "OverflowOp"; |
| 219 | case IrInstructionIdTestErrSrc: |
| 220 | return "TestErrSrc"; |
| 221 | case IrInstructionIdTestErrGen: |
| 222 | return "TestErrGen"; |
| 223 | case IrInstructionIdMulAdd: |
| 224 | return "MulAdd"; |
| 225 | case IrInstructionIdFloatOp: |
| 226 | return "FloatOp"; |
| 227 | case IrInstructionIdUnwrapErrCode: |
| 228 | return "UnwrapErrCode"; |
| 229 | case IrInstructionIdUnwrapErrPayload: |
| 230 | return "UnwrapErrPayload"; |
| 231 | case IrInstructionIdErrWrapCode: |
| 232 | return "ErrWrapCode"; |
| 233 | case IrInstructionIdErrWrapPayload: |
| 234 | return "ErrWrapPayload"; |
| 235 | case IrInstructionIdFnProto: |
| 236 | return "FnProto"; |
| 237 | case IrInstructionIdTestComptime: |
| 238 | return "TestComptime"; |
| 239 | case IrInstructionIdPtrCastSrc: |
| 240 | return "PtrCastSrc"; |
| 241 | case IrInstructionIdPtrCastGen: |
| 242 | return "PtrCastGen"; |
| 243 | case IrInstructionIdBitCastSrc: |
| 244 | return "BitCastSrc"; |
| 245 | case IrInstructionIdBitCastGen: |
| 246 | return "BitCastGen"; |
| 247 | case IrInstructionIdWidenOrShorten: |
| 248 | return "WidenOrShorten"; |
| 249 | case IrInstructionIdIntToPtr: |
| 250 | return "IntToPtr"; |
| 251 | case IrInstructionIdPtrToInt: |
| 252 | return "PtrToInt"; |
| 253 | case IrInstructionIdIntToEnum: |
| 254 | return "IntToEnum"; |
| 255 | case IrInstructionIdEnumToInt: |
| 256 | return "EnumToInt"; |
| 257 | case IrInstructionIdIntToErr: |
| 258 | return "IntToErr"; |
| 259 | case IrInstructionIdErrToInt: |
| 260 | return "ErrToInt"; |
| 261 | case IrInstructionIdCheckSwitchProngs: |
| 262 | return "CheckSwitchProngs"; |
| 263 | case IrInstructionIdCheckStatementIsVoid: |
| 264 | return "CheckStatementIsVoid"; |
| 265 | case IrInstructionIdTypeName: |
| 266 | return "TypeName"; |
| 267 | case IrInstructionIdDeclRef: |
| 268 | return "DeclRef"; |
| 269 | case IrInstructionIdPanic: |
| 270 | return "Panic"; |
| 271 | case IrInstructionIdTagName: |
| 272 | return "TagName"; |
| 273 | case IrInstructionIdTagType: |
| 274 | return "TagType"; |
| 275 | case IrInstructionIdFieldParentPtr: |
| 276 | return "FieldParentPtr"; |
| 277 | case IrInstructionIdByteOffsetOf: |
| 278 | return "ByteOffsetOf"; |
| 279 | case IrInstructionIdBitOffsetOf: |
| 280 | return "BitOffsetOf"; |
| 281 | case IrInstructionIdTypeInfo: |
| 282 | return "TypeInfo"; |
| 283 | case IrInstructionIdHasField: |
| 284 | return "HasField"; |
| 285 | case IrInstructionIdTypeId: |
| 286 | return "TypeId"; |
| 287 | case IrInstructionIdSetEvalBranchQuota: |
| 288 | return "SetEvalBranchQuota"; |
| 289 | case IrInstructionIdPtrType: |
| 290 | return "PtrType"; |
| 291 | case IrInstructionIdAlignCast: |
| 292 | return "AlignCast"; |
| 293 | case IrInstructionIdImplicitCast: |
| 294 | return "ImplicitCast"; |
| 295 | case IrInstructionIdResolveResult: |
| 296 | return "ResolveResult"; |
| 297 | case IrInstructionIdResetResult: |
| 298 | return "ResetResult"; |
| 299 | case IrInstructionIdOpaqueType: |
| 300 | return "OpaqueType"; |
| 301 | case IrInstructionIdSetAlignStack: |
| 302 | return "SetAlignStack"; |
| 303 | case IrInstructionIdArgType: |
| 304 | return "ArgType"; |
| 305 | case IrInstructionIdExport: |
| 306 | return "Export"; |
| 307 | case IrInstructionIdErrorReturnTrace: |
| 308 | return "ErrorReturnTrace"; |
| 309 | case IrInstructionIdErrorUnion: |
| 310 | return "ErrorUnion"; |
| 311 | case IrInstructionIdAtomicRmw: |
| 312 | return "AtomicRmw"; |
| 313 | case IrInstructionIdAtomicLoad: |
| 314 | return "AtomicLoad"; |
| 315 | case IrInstructionIdSaveErrRetAddr: |
| 316 | return "SaveErrRetAddr"; |
| 317 | case IrInstructionIdAddImplicitReturnType: |
| 318 | return "AddImplicitReturnType"; |
| 319 | case IrInstructionIdErrSetCast: |
| 320 | return "ErrSetCast"; |
| 321 | case IrInstructionIdToBytes: |
| 322 | return "ToBytes"; |
| 323 | case IrInstructionIdFromBytes: |
| 324 | return "FromBytes"; |
| 325 | case IrInstructionIdCheckRuntimeScope: |
| 326 | return "CheckRuntimeScope"; |
| 327 | case IrInstructionIdVectorToArray: |
| 328 | return "VectorToArray"; |
| 329 | case IrInstructionIdArrayToVector: |
| 330 | return "ArrayToVector"; |
| 331 | case IrInstructionIdAssertZero: |
| 332 | return "AssertZero"; |
| 333 | case IrInstructionIdAssertNonNull: |
| 334 | return "AssertNonNull"; |
| 335 | case IrInstructionIdHasDecl: |
| 336 | return "HasDecl"; |
| 337 | case IrInstructionIdUndeclaredIdent: |
| 338 | return "UndeclaredIdent"; |
| 339 | case IrInstructionIdAllocaSrc: |
| 340 | return "AllocaSrc"; |
| 341 | case IrInstructionIdAllocaGen: |
| 342 | return "AllocaGen"; |
| 343 | case IrInstructionIdEndExpr: |
| 344 | return "EndExpr"; |
| 345 | case IrInstructionIdPtrOfArrayToSlice: |
| 346 | return "PtrOfArrayToSlice"; |
| 347 | case IrInstructionIdUnionInitNamedField: |
| 348 | return "UnionInitNamedField"; |
| 349 | case IrInstructionIdSuspendBegin: |
| 350 | return "SuspendBegin"; |
| 351 | case IrInstructionIdSuspendFinish: |
| 352 | return "SuspendFinish"; |
| 353 | case IrInstructionIdAwaitSrc: |
| 354 | return "AwaitSrc"; |
| 355 | case IrInstructionIdAwaitGen: |
| 356 | return "AwaitGen"; |
| 357 | case IrInstructionIdResume: |
| 358 | return "Resume"; |
| 359 | case IrInstructionIdSpillBegin: |
| 360 | return "SpillBegin"; |
| 361 | case IrInstructionIdSpillEnd: |
| 362 | return "SpillEnd"; |
| 363 | } |
| 364 | zig_unreachable(); |
| 365 | } |
| 366 | |
| 22 | 367 | static void ir_print_indent(IrPrint *irp) { |
| 23 | 368 | for (int i = 0; i < irp->indent; i += 1) { |
| 24 | 369 | fprintf(irp->f, " "); |
| 25 | 370 | } |
| 26 | 371 | } |
| 27 | 372 | |
| 28 | | static void ir_print_prefix(IrPrint *irp, IrInstruction *instruction) { |
| 373 | static void ir_print_prefix(IrPrint *irp, IrInstruction *instruction, bool trailing) { |
| 29 | 374 | ir_print_indent(irp); |
| 375 | const char mark = trailing ? ':' : '#'; |
| 30 | 376 | const char *type_name = instruction->value.type ? buf_ptr(&instruction->value.type->name) : "(unknown)"; |
| 31 | 377 | const char *ref_count = ir_has_side_effects(instruction) ? |
| 32 | 378 | "-" : buf_ptr(buf_sprintf("%" ZIG_PRI_usize "", instruction->ref_count)); |
| 33 | | fprintf(irp->f, "#%-3zu| %-12s| %-2s| ", instruction->debug_id, type_name, ref_count); |
| 379 | fprintf(irp->f, "%c%-3zu| %-22s| %-12s| %-2s| ", mark, instruction->debug_id, |
| 380 | ir_instruction_type_str(instruction), type_name, ref_count); |
| 34 | 381 | } |
| 35 | 382 | |
| 36 | 383 | static void ir_print_const_value(IrPrint *irp, ConstExprValue *const_val) { |
| ... | ... | @@ -42,6 +389,10 @@ static void ir_print_const_value(IrPrint *irp, ConstExprValue *const_val) { |
| 42 | 389 | |
| 43 | 390 | static void ir_print_var_instruction(IrPrint *irp, IrInstruction *instruction) { |
| 44 | 391 | fprintf(irp->f, "#%" ZIG_PRI_usize "", instruction->debug_id); |
| 392 | if (irp->pass_num == 2 && irp->printed.maybe_get(instruction) == nullptr) { |
| 393 | irp->printed.put(instruction, 0); |
| 394 | irp->pending.append(instruction); |
| 395 | } |
| 45 | 396 | } |
| 46 | 397 | |
| 47 | 398 | static void ir_print_other_instruction(IrPrint *irp, IrInstruction *instruction) { |
| ... | ... | @@ -49,6 +400,7 @@ static void ir_print_other_instruction(IrPrint *irp, IrInstruction *instruction) |
| 49 | 400 | fprintf(irp->f, "(null)"); |
| 50 | 401 | return; |
| 51 | 402 | } |
| 403 | |
| 52 | 404 | if (instruction->value.special != ConstValSpecialRuntime) { |
| 53 | 405 | ir_print_const_value(irp, &instruction->value); |
| 54 | 406 | } else { |
| ... | ... | @@ -1550,8 +1902,8 @@ static void ir_print_spill_end(IrPrint *irp, IrInstructionSpillEnd *instruction) |
| 1550 | 1902 | fprintf(irp->f, ")"); |
| 1551 | 1903 | } |
| 1552 | 1904 | |
| 1553 | | static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { |
| 1554 | | ir_print_prefix(irp, instruction); |
| 1905 | static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction, bool trailing) { |
| 1906 | ir_print_prefix(irp, instruction, trailing); |
| 1555 | 1907 | switch (instruction->id) { |
| 1556 | 1908 | case IrInstructionIdInvalid: |
| 1557 | 1909 | zig_unreachable(); |
| ... | ... | @@ -2036,31 +2388,48 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { |
| 2036 | 2388 | fprintf(irp->f, "\n"); |
| 2037 | 2389 | } |
| 2038 | 2390 | |
| 2039 | | void ir_print(CodeGen *codegen, FILE *f, IrExecutable *executable, int indent_size) { |
| 2391 | void ir_print(CodeGen *codegen, FILE *f, IrExecutable *executable, int indent_size, size_t pass_num) { |
| 2040 | 2392 | IrPrint ir_print = {}; |
| 2041 | 2393 | IrPrint *irp = &ir_print; |
| 2394 | irp->pass_num = pass_num; |
| 2042 | 2395 | irp->codegen = codegen; |
| 2043 | 2396 | irp->f = f; |
| 2044 | 2397 | irp->indent = indent_size; |
| 2045 | 2398 | irp->indent_size = indent_size; |
| 2399 | irp->printed = {}; |
| 2400 | irp->printed.init(64); |
| 2401 | irp->pending = {}; |
| 2046 | 2402 | |
| 2047 | 2403 | for (size_t bb_i = 0; bb_i < executable->basic_block_list.length; bb_i += 1) { |
| 2048 | 2404 | IrBasicBlock *current_block = executable->basic_block_list.at(bb_i); |
| 2049 | 2405 | fprintf(irp->f, "%s_%" ZIG_PRI_usize ":\n", current_block->name_hint, current_block->debug_id); |
| 2050 | 2406 | for (size_t instr_i = 0; instr_i < current_block->instruction_list.length; instr_i += 1) { |
| 2051 | 2407 | IrInstruction *instruction = current_block->instruction_list.at(instr_i); |
| 2052 | | ir_print_instruction(irp, instruction); |
| 2408 | if (irp->pass_num == 2) { |
| 2409 | irp->printed.put(instruction, 0); |
| 2410 | irp->pending.clear(); |
| 2411 | } |
| 2412 | ir_print_instruction(irp, instruction, false); |
| 2413 | for (size_t j = 0; j < irp->pending.length; ++j) |
| 2414 | ir_print_instruction(irp, irp->pending.at(j), true); |
| 2053 | 2415 | } |
| 2054 | 2416 | } |
| 2417 | |
| 2418 | irp->pending.deinit(); |
| 2419 | irp->printed.deinit(); |
| 2055 | 2420 | } |
| 2056 | 2421 | |
| 2057 | | void ir_print_instruction(CodeGen *codegen, FILE *f, IrInstruction *instruction, int indent_size) { |
| 2422 | void ir_print_instruction(CodeGen *codegen, FILE *f, IrInstruction *instruction, int indent_size, size_t pass_num) { |
| 2058 | 2423 | IrPrint ir_print = {}; |
| 2059 | 2424 | IrPrint *irp = &ir_print; |
| 2425 | irp->pass_num = pass_num; |
| 2060 | 2426 | irp->codegen = codegen; |
| 2061 | 2427 | irp->f = f; |
| 2062 | 2428 | irp->indent = indent_size; |
| 2063 | 2429 | irp->indent_size = indent_size; |
| 2430 | irp->printed = {}; |
| 2431 | irp->printed.init(4); |
| 2432 | irp->pending = {}; |
| 2064 | 2433 | |
| 2065 | | ir_print_instruction(irp, instruction); |
| 2434 | ir_print_instruction(irp, instruction, false); |
| 2066 | 2435 | } |