| ... | ... | @@ -211,6 +211,15 @@ const reserved_idents = std.ComptimeStringMap(void, .{ |
| 211 | 211 | .{ "volatile", {} }, |
| 212 | 212 | .{ "while ", {} }, |
| 213 | 213 | |
| 214 | // stdarg.h |
| 215 | .{ "va_start", {} }, |
| 216 | .{ "va_arg", {} }, |
| 217 | .{ "va_end", {} }, |
| 218 | .{ "va_copy", {} }, |
| 219 | |
| 220 | // stddef.h |
| 221 | .{ "offsetof", {} }, |
| 222 | |
| 214 | 223 | // windows.h |
| 215 | 224 | .{ "max", {} }, |
| 216 | 225 | .{ "min", {} }, |
| ... | ... | @@ -2952,10 +2961,10 @@ fn genBodyInner(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, |
| 2952 | 2961 | .error_set_has_value => return f.fail("TODO: C backend: implement error_set_has_value", .{}), |
| 2953 | 2962 | .vector_store_elem => return f.fail("TODO: C backend: implement vector_store_elem", .{}), |
| 2954 | 2963 | |
| 2955 | | .c_va_arg => return f.fail("TODO implement c_va_arg", .{}), |
| 2956 | | .c_va_copy => return f.fail("TODO implement c_va_copy", .{}), |
| 2957 | | .c_va_end => return f.fail("TODO implement c_va_end", .{}), |
| 2958 | | .c_va_start => return f.fail("TODO implement c_va_start", .{}), |
| 2964 | .c_va_start => try airCVaStart(f, inst), |
| 2965 | .c_va_arg => try airCVaArg(f, inst), |
| 2966 | .c_va_end => try airCVaEnd(f, inst), |
| 2967 | .c_va_copy => try airCVaCopy(f, inst), |
| 2959 | 2968 | // zig fmt: on |
| 2960 | 2969 | }; |
| 2961 | 2970 | if (result_value == .new_local) { |
| ... | ... | @@ -6862,6 +6871,82 @@ fn airMulAdd(f: *Function, inst: Air.Inst.Index) !CValue { |
| 6862 | 6871 | return local; |
| 6863 | 6872 | } |
| 6864 | 6873 | |
| 6874 | fn airCVaStart(f: *Function, inst: Air.Inst.Index) !CValue { |
| 6875 | if (f.liveness.isUnused(inst)) return .none; |
| 6876 | |
| 6877 | const inst_ty = f.air.typeOfIndex(inst); |
| 6878 | const fn_cty = try f.typeToCType(f.object.dg.decl.?.ty, .complete); |
| 6879 | |
| 6880 | const param_len = fn_cty.castTag(.varargs_function).?.data.param_types.len; |
| 6881 | if (param_len == 0) |
| 6882 | return f.fail("CBE: C requires at least one runtime argument for varargs functions", .{}); |
| 6883 | |
| 6884 | const writer = f.object.writer(); |
| 6885 | const local = try f.allocLocal(inst, inst_ty); |
| 6886 | try writer.writeAll("va_start(*(va_list *)&"); |
| 6887 | try f.writeCValue(writer, local, .Other); |
| 6888 | try writer.writeAll(", "); |
| 6889 | try f.writeCValue(writer, .{ .arg = param_len - 1 }, .FunctionArgument); |
| 6890 | try writer.writeAll(");\n"); |
| 6891 | return local; |
| 6892 | } |
| 6893 | |
| 6894 | fn airCVaArg(f: *Function, inst: Air.Inst.Index) !CValue { |
| 6895 | const ty_op = f.air.instructions.items(.data)[inst].ty_op; |
| 6896 | if (f.liveness.isUnused(inst)) { |
| 6897 | try reap(f, inst, &.{ty_op.operand}); |
| 6898 | return .none; |
| 6899 | } |
| 6900 | |
| 6901 | const inst_ty = f.air.typeOfIndex(inst); |
| 6902 | const va_list = try f.resolveInst(ty_op.operand); |
| 6903 | try reap(f, inst, &.{ty_op.operand}); |
| 6904 | |
| 6905 | const writer = f.object.writer(); |
| 6906 | const local = try f.allocLocal(inst, inst_ty); |
| 6907 | try f.writeCValue(writer, local, .Other); |
| 6908 | try writer.writeAll(" = va_arg(*(va_list *)"); |
| 6909 | try f.writeCValue(writer, va_list, .Other); |
| 6910 | try writer.writeAll(", "); |
| 6911 | try f.renderType(writer, f.air.getRefType(ty_op.ty)); |
| 6912 | try writer.writeAll(");\n"); |
| 6913 | return local; |
| 6914 | } |
| 6915 | |
| 6916 | fn airCVaEnd(f: *Function, inst: Air.Inst.Index) !CValue { |
| 6917 | const un_op = f.air.instructions.items(.data)[inst].un_op; |
| 6918 | |
| 6919 | const va_list = try f.resolveInst(un_op); |
| 6920 | try reap(f, inst, &.{un_op}); |
| 6921 | |
| 6922 | const writer = f.object.writer(); |
| 6923 | try writer.writeAll("va_end(*(va_list *)"); |
| 6924 | try f.writeCValue(writer, va_list, .Other); |
| 6925 | try writer.writeAll(");\n"); |
| 6926 | return .none; |
| 6927 | } |
| 6928 | |
| 6929 | fn airCVaCopy(f: *Function, inst: Air.Inst.Index) !CValue { |
| 6930 | const ty_op = f.air.instructions.items(.data)[inst].ty_op; |
| 6931 | if (f.liveness.isUnused(inst)) { |
| 6932 | try reap(f, inst, &.{ty_op.operand}); |
| 6933 | return .none; |
| 6934 | } |
| 6935 | |
| 6936 | const inst_ty = f.air.typeOfIndex(inst); |
| 6937 | const va_list = try f.resolveInst(ty_op.operand); |
| 6938 | try reap(f, inst, &.{ty_op.operand}); |
| 6939 | |
| 6940 | const writer = f.object.writer(); |
| 6941 | const local = try f.allocLocal(inst, inst_ty); |
| 6942 | try writer.writeAll("va_copy(*(va_list *)&"); |
| 6943 | try f.writeCValue(writer, local, .Other); |
| 6944 | try writer.writeAll(", *(va_list *)"); |
| 6945 | try f.writeCValue(writer, va_list, .Other); |
| 6946 | try writer.writeAll(");\n"); |
| 6947 | return local; |
| 6948 | } |
| 6949 | |
| 6865 | 6950 | fn toMemoryOrder(order: std.builtin.AtomicOrder) [:0]const u8 { |
| 6866 | 6951 | return switch (order) { |
| 6867 | 6952 | // Note: unordered is actually even less atomic than relaxed |