| ... | @@ -961,7 +961,11 @@ pub const Object = struct { | ... | @@ -961,7 +961,11 @@ pub const Object = struct { |
| 961 | defer args.deinit(); | 961 | defer args.deinit(); |
| 962 | | 962 | |
| 963 | { | 963 | { |
| 964 | var llvm_arg_i = @as(c_uint, @intFromBool(ret_ptr != null)) + @intFromBool(err_return_tracing); | 964 | var llvm_arg_i = |
| | 965 | @as(c_uint, @intFromBool(ret_ptr != null)) + |
| | 966 | @intFromBool(err_return_tracing) + |
| | 967 | @intFromBool(func.isAsync()); |
| | 968 | |
| 965 | var it = iterateParamTypes(o, fn_info); | 969 | var it = iterateParamTypes(o, fn_info); |
| 966 | while (it.next()) |lowering| switch (lowering) { | 970 | while (it.next()) |lowering| switch (lowering) { |
| 967 | .no_bits => continue, | 971 | .no_bits => continue, |
| ... | @@ -1215,25 +1219,27 @@ pub const Object = struct { | ... | @@ -1215,25 +1219,27 @@ pub const Object = struct { |
| 1215 | }; | 1219 | }; |
| 1216 | defer fg.deinit(); | 1220 | defer fg.deinit(); |
| 1217 | | 1221 | |
| 1218 | if (func.isAsync()) { | 1222 | const llvm_usize = o.context.intType(target.ptrBitWidth()); |
| 1219 | const frame_ty = try mod.asyncFrameType(func_index); | | |
| 1220 | const frame_size = frame_ty.abiSize(mod); | | |
| 1221 | const llvm_usize = dg.context.intType(target.ptrBitWidth()); | | |
| 1222 | const size_val = llvm_usize.constInt(frame_size, .False); | | |
| 1223 | llvm_func.functionSetPrefixData(size_val); | | |
| 1224 | | 1223 | |
| 1225 | const async_preamble_bb = dg.context.appendBasicBlock(llvm_func, "AsyncSwitch"); | 1224 | if (func.isAsync()) { |
| 1226 | const bad_resume_bb = dg.context.appendBasicBlock(llvm_func, "BadResume"); | 1225 | const bad_resume_bb = o.context.appendBasicBlock(llvm_func, "BadResume"); |
| 1227 | builder.positionBuilderAtEnd(bad_resume_bb); | 1226 | builder.positionBuilderAtEnd(bad_resume_bb); |
| 1228 | _ = builder.buildUnreachable(); // TODO make this a safety panic | 1227 | _ = builder.buildUnreachable(); // TODO make this a safety panic |
| 1229 | | 1228 | |
| 1230 | builder.positionBuilderAtEnd(async_preamble_bb); | 1229 | builder.positionBuilderAtEnd(entry_block); |
| 1231 | const l = asyncFrameLayout(); | 1230 | const l = asyncFrameLayout(); |
| 1232 | const frame_llvm_ty = try dg.lowerType(frame_ty); | 1231 | const frame_llvm_ty = try o.lowerAsyncFrameHeader(fn_info.return_type.toType()); |
| 1233 | const frame_ptr = llvm_func.getParam(0); | 1232 | const frame_ptr = llvm_func.getParam(0); |
| 1234 | fg.resume_index_ptr = builder.buildStructGEP(frame_llvm_ty, frame_ptr, l.resume_index, ""); | 1233 | fg.resume_index_ptr = builder.buildStructGEP(frame_llvm_ty, frame_ptr, l.resume_index, ""); |
| 1235 | const resume_index = builder.buildLoad(llvm_usize, fg.resume_index_ptr, ""); | 1234 | const resume_index = builder.buildLoad(llvm_usize, fg.resume_index_ptr, ""); |
| 1236 | fg.async_switch = builder.buildSwitch(resume_index, bad_resume_bb, 4); | 1235 | fg.async_switch = builder.buildSwitch(resume_index, bad_resume_bb, 4); |
| | 1236 | |
| | 1237 | const init_bb = o.context.appendBasicBlock(llvm_func, "Init"); |
| | 1238 | const new_block_index = fg.resume_block_index; |
| | 1239 | fg.resume_block_index += 1; |
| | 1240 | const new_block_index_llvm_val = llvm_usize.constInt(new_block_index, .False); |
| | 1241 | fg.async_switch.addCase(new_block_index_llvm_val, init_bb); |
| | 1242 | builder.positionBuilderAtEnd(init_bb); |
| 1237 | } | 1243 | } |
| 1238 | | 1244 | |
| 1239 | fg.genBody(air.getMainBody()) catch |err| switch (err) { | 1245 | fg.genBody(air.getMainBody()) catch |err| switch (err) { |
| ... | @@ -1246,6 +1252,12 @@ pub const Object = struct { | ... | @@ -1246,6 +1252,12 @@ pub const Object = struct { |
| 1246 | else => |e| return e, | 1252 | else => |e| return e, |
| 1247 | }; | 1253 | }; |
| 1248 | | 1254 | |
| | 1255 | if (func.isAsync()) { |
| | 1256 | const frame_size = 3 * (target.ptrBitWidth() / 8); |
| | 1257 | const size_val = llvm_usize.constInt(frame_size, .False); |
| | 1258 | llvm_func.functionSetPrefixData(size_val); |
| | 1259 | } |
| | 1260 | |
| 1249 | try o.updateDeclExports(mod, decl_index, mod.getDeclExports(decl_index)); | 1261 | try o.updateDeclExports(mod, decl_index, mod.getDeclExports(decl_index)); |
| 1250 | } | 1262 | } |
| 1251 | | 1263 | |
| ... | @@ -2499,16 +2511,20 @@ pub const Object = struct { | ... | @@ -2499,16 +2511,20 @@ pub const Object = struct { |
| 2499 | const mod = o.module; | 2511 | const mod = o.module; |
| 2500 | const gpa = o.gpa; | 2512 | const gpa = o.gpa; |
| 2501 | const decl = mod.declPtr(decl_index); | 2513 | const decl = mod.declPtr(decl_index); |
| 2502 | const zig_fn_type = decl.ty; | | |
| 2503 | const gop = try o.decl_map.getOrPut(gpa, decl_index); | 2514 | const gop = try o.decl_map.getOrPut(gpa, decl_index); |
| 2504 | if (gop.found_existing) return gop.value_ptr.*; | 2515 | if (gop.found_existing) return gop.value_ptr.*; |
| 2505 | | 2516 | |
| 2506 | assert(decl.has_tv); | 2517 | assert(decl.has_tv); |
| 2507 | const fn_info = mod.typeToFunc(zig_fn_type).?; | 2518 | const func = decl.getOwnedFunction(mod).?; |
| | 2519 | const zig_fn_type = decl.ty; |
| | 2520 | const fn_info = info: { |
| | 2521 | var info = mod.typeToFunc(zig_fn_type).?; |
| | 2522 | if (func.isAsync()) info.cc = .Async; |
| | 2523 | break :info info; |
| | 2524 | }; |
| 2508 | const target = mod.getTarget(); | 2525 | const target = mod.getTarget(); |
| 2509 | const sret = firstParamSRet(fn_info, mod); | 2526 | const sret = firstParamSRet(fn_info, mod); |
| 2510 | | 2527 | const fn_type = try o.lowerTypeFn(fn_info); |
| 2511 | const fn_type = try o.lowerType(zig_fn_type); | | |
| 2512 | | 2528 | |
| 2513 | const fqn = try decl.getFullyQualifiedName(mod); | 2529 | const fqn = try decl.getFullyQualifiedName(mod); |
| 2514 | | 2530 | |
| ... | @@ -2531,32 +2547,33 @@ pub const Object = struct { | ... | @@ -2531,32 +2547,33 @@ pub const Object = struct { |
| 2531 | } | 2547 | } |
| 2532 | } | 2548 | } |
| 2533 | | 2549 | |
| | 2550 | var llvm_param_i: u32 = 0; |
| | 2551 | |
| 2534 | if (sret) { | 2552 | if (sret) { |
| 2535 | o.addArgAttr(llvm_fn, 0, "nonnull"); // Sret pointers must not be address 0 | 2553 | o.addArgAttr(llvm_fn, llvm_param_i, "nonnull"); // Sret pointers must not be address 0 |
| 2536 | o.addArgAttr(llvm_fn, 0, "noalias"); | 2554 | o.addArgAttr(llvm_fn, llvm_param_i, "noalias"); |
| 2537 | | 2555 | |
| 2538 | const raw_llvm_ret_ty = try o.lowerType(fn_info.return_type.toType()); | 2556 | const raw_llvm_ret_ty = try o.lowerType(fn_info.return_type.toType()); |
| 2539 | llvm_fn.addSretAttr(raw_llvm_ret_ty); | 2557 | llvm_fn.addSretAttr(raw_llvm_ret_ty); |
| | 2558 | |
| | 2559 | llvm_param_i += 1; |
| 2540 | } | 2560 | } |
| 2541 | | 2561 | |
| 2542 | const err_return_tracing = fn_info.return_type.toType().isError(mod) and | 2562 | const err_return_tracing = fn_info.return_type.toType().isError(mod) and |
| 2543 | mod.comp.bin_file.options.error_return_tracing; | 2563 | mod.comp.bin_file.options.error_return_tracing; |
| 2544 | | 2564 | |
| 2545 | if (err_return_tracing) { | 2565 | if (err_return_tracing) { |
| 2546 | o.addArgAttr(llvm_fn, @intFromBool(sret), "nonnull"); | 2566 | o.addArgAttr(llvm_fn, llvm_param_i, "nonnull"); |
| | 2567 | llvm_param_i += 1; |
| 2547 | } | 2568 | } |
| 2548 | | 2569 | |
| 2549 | switch (fn_info.cc) { | 2570 | switch (fn_info.cc) { |
| 2550 | .Unspecified, .Inline => { | 2571 | .Unspecified, .Inline, .Async => { |
| 2551 | llvm_fn.setFunctionCallConv(.Fast); | 2572 | llvm_fn.setFunctionCallConv(.Fast); |
| 2552 | }, | 2573 | }, |
| 2553 | .Naked => { | 2574 | .Naked => { |
| 2554 | o.addFnAttr(llvm_fn, "naked"); | 2575 | o.addFnAttr(llvm_fn, "naked"); |
| 2555 | }, | 2576 | }, |
| 2556 | .Async => { | | |
| 2557 | llvm_fn.setFunctionCallConv(.Fast); | | |
| 2558 | @panic("TODO: LLVM backend lower async function"); | | |
| 2559 | }, | | |
| 2560 | else => { | 2577 | else => { |
| 2561 | llvm_fn.setFunctionCallConv(toLlvmCallConv(fn_info.cc, target)); | 2578 | llvm_fn.setFunctionCallConv(toLlvmCallConv(fn_info.cc, target)); |
| 2562 | }, | 2579 | }, |
| ... | @@ -2577,8 +2594,7 @@ pub const Object = struct { | ... | @@ -2577,8 +2594,7 @@ pub const Object = struct { |
| 2577 | // because functions with bodies are handled in `updateFunc`. | 2594 | // because functions with bodies are handled in `updateFunc`. |
| 2578 | if (is_extern) { | 2595 | if (is_extern) { |
| 2579 | var it = iterateParamTypes(o, fn_info); | 2596 | var it = iterateParamTypes(o, fn_info); |
| 2580 | it.llvm_index += @intFromBool(sret); | 2597 | it.llvm_index += llvm_param_i; |
| 2581 | it.llvm_index += @intFromBool(err_return_tracing); | | |
| 2582 | while (it.next()) |lowering| switch (lowering) { | 2598 | while (it.next()) |lowering| switch (lowering) { |
| 2583 | .byval => { | 2599 | .byval => { |
| 2584 | const param_index = it.zig_index - 1; | 2600 | const param_index = it.zig_index - 1; |
| ... | @@ -3052,7 +3068,7 @@ pub const Object = struct { | ... | @@ -3052,7 +3068,7 @@ pub const Object = struct { |
| 3052 | llvm_union_ty.structSetBody(&llvm_fields, llvm_fields_len, .False); | 3068 | llvm_union_ty.structSetBody(&llvm_fields, llvm_fields_len, .False); |
| 3053 | return llvm_union_ty; | 3069 | return llvm_union_ty; |
| 3054 | }, | 3070 | }, |
| 3055 | .Fn => return lowerTypeFn(o, t), | 3071 | .Fn => return lowerTypeFn(o, mod.typeToFunc(t).?), |
| 3056 | .ComptimeInt => unreachable, | 3072 | .ComptimeInt => unreachable, |
| 3057 | .ComptimeFloat => unreachable, | 3073 | .ComptimeFloat => unreachable, |
| 3058 | .Type => unreachable, | 3074 | .Type => unreachable, |
| ... | @@ -3089,12 +3105,16 @@ pub const Object = struct { | ... | @@ -3089,12 +3105,16 @@ pub const Object = struct { |
| 3089 | } | 3105 | } |
| 3090 | | 3106 | |
| 3091 | fn lowerAsyncFrameHeader(o: *Object, ret_ty: Type) !*llvm.Type { | 3107 | fn lowerAsyncFrameHeader(o: *Object, ret_ty: Type) !*llvm.Type { |
| | 3108 | const mod = o.module; |
| 3092 | const opaque_ptr_ty = o.context.pointerType(0); | 3109 | const opaque_ptr_ty = o.context.pointerType(0); |
| 3093 | const l = asyncFrameLayout(); | 3110 | const l = asyncFrameLayout(); |
| 3094 | var fields: [4]*llvm.Type = undefined; | 3111 | var fields: [4]*llvm.Type = undefined; |
| 3095 | fields[l.fn_ptr] = opaque_ptr_ty; | 3112 | fields[l.fn_ptr] = opaque_ptr_ty; |
| 3096 | fields[l.resume_index] = try o.lowerType(Type.usize); | 3113 | fields[l.resume_index] = try o.lowerType(Type.usize); |
| 3097 | fields[l.awaiter] = opaque_ptr_ty; | 3114 | fields[l.awaiter] = opaque_ptr_ty; |
| | 3115 | if (!ret_ty.hasRuntimeBitsIgnoreComptime(mod)) { |
| | 3116 | return o.context.structType(&fields, 3, .False); |
| | 3117 | } |
| 3098 | fields[l.ret_val] = try o.lowerType(ret_ty); | 3118 | fields[l.ret_val] = try o.lowerType(ret_ty); |
| 3099 | return o.context.structType(&fields, fields.len, .False); | 3119 | return o.context.structType(&fields, fields.len, .False); |
| 3100 | } | 3120 | } |
| ... | @@ -3122,23 +3142,29 @@ pub const Object = struct { | ... | @@ -3122,23 +3142,29 @@ pub const Object = struct { |
| 3122 | return llvm_struct_ty; | 3142 | return llvm_struct_ty; |
| 3123 | } | 3143 | } |
| 3124 | | 3144 | |
| 3125 | fn lowerTypeFn(o: *Object, fn_ty: Type) Allocator.Error!*llvm.Type { | 3145 | fn lowerTypeFn(o: *Object, fn_info: InternPool.Key.FuncType) Allocator.Error!*llvm.Type { |
| 3126 | const mod = o.module; | 3146 | const mod = o.module; |
| 3127 | const fn_info = mod.typeToFunc(fn_ty).?; | | |
| 3128 | const llvm_ret_ty = try lowerFnRetTy(o, fn_info); | 3147 | const llvm_ret_ty = try lowerFnRetTy(o, fn_info); |
| 3129 | | 3148 | |
| 3130 | var llvm_params = std.ArrayList(*llvm.Type).init(o.gpa); | 3149 | var llvm_params = std.ArrayList(*llvm.Type).init(o.gpa); |
| 3131 | defer llvm_params.deinit(); | 3150 | defer llvm_params.deinit(); |
| 3132 | | 3151 | |
| | 3152 | try llvm_params.ensureUnusedCapacity(3); |
| | 3153 | |
| 3133 | if (firstParamSRet(fn_info, mod)) { | 3154 | if (firstParamSRet(fn_info, mod)) { |
| 3134 | try llvm_params.append(o.context.pointerType(0)); | 3155 | llvm_params.appendAssumeCapacity(o.context.pointerType(0)); |
| | 3156 | } |
| | 3157 | |
| | 3158 | if (fn_info.cc == .Async) { |
| | 3159 | // frame_ptr |
| | 3160 | llvm_params.appendAssumeCapacity(o.context.pointerType(0)); |
| 3135 | } | 3161 | } |
| 3136 | | 3162 | |
| 3137 | if (fn_info.return_type.toType().isError(mod) and | 3163 | if (fn_info.return_type.toType().isError(mod) and |
| 3138 | mod.comp.bin_file.options.error_return_tracing) | 3164 | mod.comp.bin_file.options.error_return_tracing) |
| 3139 | { | 3165 | { |
| 3140 | const ptr_ty = try mod.singleMutPtrType(try o.getStackTraceType()); | 3166 | const ptr_ty = try mod.singleMutPtrType(try o.getStackTraceType()); |
| 3141 | try llvm_params.append(try o.lowerType(ptr_ty)); | 3167 | llvm_params.appendAssumeCapacity(try o.lowerType(ptr_ty)); |
| 3142 | } | 3168 | } |
| 3143 | | 3169 | |
| 3144 | var it = iterateParamTypes(o, fn_info); | 3170 | var it = iterateParamTypes(o, fn_info); |
| ... | @@ -4860,9 +4886,11 @@ pub const FuncGen = struct { | ... | @@ -4860,9 +4886,11 @@ pub const FuncGen = struct { |
| 4860 | } | 4886 | } |
| 4861 | | 4887 | |
| 4862 | fn genSuspendBegin(fg: *FuncGen, name_hint: [*:0]const u8) *llvm.BasicBlock { | 4888 | fn genSuspendBegin(fg: *FuncGen, name_hint: [*:0]const u8) *llvm.BasicBlock { |
| 4863 | const target = fg.getTarget(); | 4889 | const o = fg.dg.object; |
| 4864 | const llvm_usize = fg.dg.context.intType(target.ptrBitWidth()); | 4890 | const mod = o.module; |
| 4865 | const resume_bb = fg.context.appendBasicBlock(fg.llvm_func, name_hint); | 4891 | const target = mod.getTarget(); |
| | 4892 | const llvm_usize = o.context.intType(target.ptrBitWidth()); |
| | 4893 | const resume_bb = o.context.appendBasicBlock(fg.llvm_func, name_hint); |
| 4866 | const new_block_index = fg.resume_block_index; | 4894 | const new_block_index = fg.resume_block_index; |
| 4867 | fg.resume_block_index += 1; | 4895 | fg.resume_block_index += 1; |
| 4868 | const new_block_index_llvm_val = llvm_usize.constInt(new_block_index, .False); | 4896 | const new_block_index_llvm_val = llvm_usize.constInt(new_block_index, .False); |