authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-07-25 22:38:50-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-07-25 22:38:50-07:00
log14d8a1c10da7e98ccfdbfd50473582043e48ca10
tree0b3e30ce2e327f5019f08f0ba2cc01f79c4f4225
parentc3d10dbda1fc133b7ca112787bbf0100b735ca36

stage2 llvm backend improvements working towards `zig test`

* properly set global variables to const if they are not a global variable. * implement global variable initializations. * initial implementation of llvmType() for structs and functions. * implement genTypedValue for variable tags * implement more AIR instructions: varptr, slice_ptr, slice_len, slice_elem_val, ptr_slice_elem_val, unwrap_errunion_payload, unwrap_errunion_payload_ptr, unwrap_errunion_err, unwrap_errunion_err_ptr.

3 files changed, 212 insertions(+), 33 deletions(-)

src/codegen/llvm.zig+190-31
......@@ -512,12 +512,15 @@ pub const DeclGen = struct {
512512
513513 // TODO: remove this redundant `llvmType`, it is also called in `genTypedValue`.
514514 const llvm_type = try self.llvmType(decl.ty);
515 const val = try self.genTypedValue(.{ .ty = decl.ty, .val = decl.val }, null);
516515 const global = self.llvmModule().addGlobal(llvm_type, decl.name);
517 llvm.setInitializer(global, val);
516 const init_val = if (decl.val.castTag(.variable)) |payload| init_val: {
517 const variable = payload.data;
518 global.setGlobalConstant(.False);
519 break :init_val variable.init;
520 } else decl.val;
518521
519 // TODO ask the Decl if it is const
520 // https://github.com/ziglang/zig/issues/7582
522 const llvm_init = try self.genTypedValue(.{ .ty = decl.ty, .val = init_val }, null);
523 llvm.setInitializer(global, llvm_init);
521524
522525 return global;
523526 }
......@@ -576,6 +579,36 @@ pub const DeclGen = struct {
576579 .ErrorSet => {
577580 return self.context.intType(16);
578581 },
582 .Struct => {
583 const struct_obj = t.castTag(.@"struct").?.data;
584 assert(struct_obj.haveFieldTypes());
585 const llvm_fields = try self.gpa.alloc(*const llvm.Type, struct_obj.fields.count());
586 defer self.gpa.free(llvm_fields);
587 for (struct_obj.fields.values()) |field, i| {
588 llvm_fields[i] = try self.llvmType(field.ty);
589 }
590 return self.context.structType(
591 llvm_fields.ptr,
592 @intCast(c_uint, llvm_fields.len),
593 .False,
594 );
595 },
596 .Fn => {
597 const ret_ty = try self.llvmType(t.fnReturnType());
598 const params_len = t.fnParamLen();
599 const llvm_params = try self.gpa.alloc(*const llvm.Type, params_len);
600 defer self.gpa.free(llvm_params);
601 for (llvm_params) |*llvm_param, i| {
602 llvm_param.* = try self.llvmType(t.fnParamType(i));
603 }
604 const is_var_args = t.fnIsVarArgs();
605 return llvm.functionType(
606 ret_ty,
607 llvm_params.ptr,
608 @intCast(c_uint, llvm_params.len),
609 llvm.Bool.fromBool(is_var_args),
610 );
611 },
579612 .ComptimeInt => unreachable,
580613 .ComptimeFloat => unreachable,
581614 .Type => unreachable,
......@@ -586,10 +619,8 @@ pub const DeclGen = struct {
586619 .BoundFn => @panic("TODO remove BoundFn from the language"),
587620
588621 .Float,
589 .Struct,
590622 .Enum,
591623 .Union,
592 .Fn,
593624 .Opaque,
594625 .Frame,
595626 .AnyFrame,
......@@ -645,7 +676,11 @@ pub const DeclGen = struct {
645676 _ = fg.?.builder.buildStore(try self.genTypedValue(.{ .ty = elem_type, .val = elem_value }, fg), alloca);
646677 return alloca;
647678 },
648 else => return self.todo("implement const of pointer type '{}'", .{tv.ty}),
679 .variable => {
680 const variable = tv.val.castTag(.variable).?.data;
681 return self.resolveGlobalDecl(variable.owner_decl);
682 },
683 else => |tag| return self.todo("implement const of pointer type '{}' ({})", .{ tv.ty, tag }),
649684 },
650685 .Array => {
651686 if (tv.val.castTag(.bytes)) |payload| {
......@@ -765,45 +800,64 @@ pub const FuncGen = struct {
765800 const air_tags = self.air.instructions.items(.tag);
766801 for (body) |inst| {
767802 const opt_value: ?*const llvm.Value = switch (air_tags[inst]) {
803 // zig fmt: off
768804 .add => try self.airAdd(inst),
769805 .sub => try self.airSub(inst),
770806
771 .cmp_eq => try self.airCmp(inst, .eq),
772 .cmp_gt => try self.airCmp(inst, .gt),
807 .cmp_eq => try self.airCmp(inst, .eq),
808 .cmp_gt => try self.airCmp(inst, .gt),
773809 .cmp_gte => try self.airCmp(inst, .gte),
774 .cmp_lt => try self.airCmp(inst, .lt),
810 .cmp_lt => try self.airCmp(inst, .lt),
775811 .cmp_lte => try self.airCmp(inst, .lte),
776812 .cmp_neq => try self.airCmp(inst, .neq),
777813
778 .is_non_null => try self.airIsNonNull(inst, false),
814 .is_non_null => try self.airIsNonNull(inst, false),
779815 .is_non_null_ptr => try self.airIsNonNull(inst, true),
780 .is_null => try self.airIsNull(inst, false),
781 .is_null_ptr => try self.airIsNull(inst, true),
782
783 .alloc => try self.airAlloc(inst),
784 .arg => try self.airArg(inst),
785 .bitcast => try self.airBitCast(inst),
786 .block => try self.airBlock(inst),
787 .br => try self.airBr(inst),
816 .is_null => try self.airIsNull(inst, false),
817 .is_null_ptr => try self.airIsNull(inst, true),
818 .is_non_err => try self.airIsErr(inst, true, false),
819 .is_non_err_ptr => try self.airIsErr(inst, true, true),
820 .is_err => try self.airIsErr(inst, false, false),
821 .is_err_ptr => try self.airIsErr(inst, false, true),
822
823 .alloc => try self.airAlloc(inst),
824 .arg => try self.airArg(inst),
825 .bitcast => try self.airBitCast(inst),
826 .block => try self.airBlock(inst),
827 .br => try self.airBr(inst),
788828 .breakpoint => try self.airBreakpoint(inst),
789 .call => try self.airCall(inst),
790 .cond_br => try self.airCondBr(inst),
791 .intcast => try self.airIntCast(inst),
792 .ptrtoint => try self.airPtrToInt(inst),
793 .load => try self.airLoad(inst),
794 .loop => try self.airLoop(inst),
795 .not => try self.airNot(inst),
796 .ret => try self.airRet(inst),
797 .store => try self.airStore(inst),
798 .unreach => self.airUnreach(inst),
799 .optional_payload => try self.airOptionalPayload(inst, false),
829 .call => try self.airCall(inst),
830 .cond_br => try self.airCondBr(inst),
831 .intcast => try self.airIntCast(inst),
832 .ptrtoint => try self.airPtrToInt(inst),
833 .load => try self.airLoad(inst),
834 .loop => try self.airLoop(inst),
835 .not => try self.airNot(inst),
836 .ret => try self.airRet(inst),
837 .store => try self.airStore(inst),
838 .assembly => try self.airAssembly(inst),
839 .varptr => try self.airVarPtr(inst),
840 .slice_ptr => try self.airSliceField(inst, 0),
841 .slice_len => try self.airSliceField(inst, 1),
842
843 .slice_elem_val => try self.airSliceElemVal(inst, false),
844 .ptr_slice_elem_val => try self.airSliceElemVal(inst, true),
845
846 .optional_payload => try self.airOptionalPayload(inst, false),
800847 .optional_payload_ptr => try self.airOptionalPayload(inst, true),
801 .assembly => try self.airAssembly(inst),
848
849 .unwrap_errunion_payload => try self.airErrUnionPayload(inst, false),
850 .unwrap_errunion_payload_ptr => try self.airErrUnionPayload(inst, true),
851 .unwrap_errunion_err => try self.airErrUnionErr(inst, false),
852 .unwrap_errunion_err_ptr => try self.airErrUnionErr(inst, true),
853
854 .unreach => self.airUnreach(inst),
802855 .dbg_stmt => blk: {
803856 // TODO: implement debug info
804857 break :blk null;
805858 },
806859 else => |tag| return self.todo("implement AIR instruction: {}", .{tag}),
860 // zig fmt: on
807861 };
808862 if (opt_value) |val| try self.func_inst_table.putNoClobber(self.gpa, inst, val);
809863 }
......@@ -986,6 +1040,52 @@ pub const FuncGen = struct {
9861040 return null;
9871041 }
9881042
1043 fn airVarPtr(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
1044 if (self.liveness.isUnused(inst))
1045 return null;
1046
1047 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
1048 const variable = self.air.variables[ty_pl.payload];
1049 const decl_llvm_value = self.dg.resolveGlobalDecl(variable.owner_decl);
1050 return decl_llvm_value;
1051 }
1052
1053 fn airSliceField(self: *FuncGen, inst: Air.Inst.Index, index: c_uint) !?*const llvm.Value {
1054 if (self.liveness.isUnused(inst))
1055 return null;
1056
1057 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
1058 const operand = try self.resolveInst(ty_op.operand);
1059 return self.builder.buildExtractValue(operand, index, "");
1060 }
1061
1062 fn airSliceElemVal(
1063 self: *FuncGen,
1064 inst: Air.Inst.Index,
1065 operand_is_ptr: bool,
1066 ) !?*const llvm.Value {
1067 if (self.liveness.isUnused(inst))
1068 return null;
1069
1070 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
1071 const lhs = try self.resolveInst(bin_op.lhs);
1072 const rhs = try self.resolveInst(bin_op.rhs);
1073
1074 const base_ptr = if (!operand_is_ptr) lhs else ptr: {
1075 const index_type = self.context.intType(32);
1076 const indices: [2]*const llvm.Value = .{
1077 index_type.constNull(),
1078 index_type.constInt(0, .False),
1079 };
1080 const ptr_field_ptr = self.builder.buildInBoundsGEP(lhs, &indices, 2, "");
1081 break :ptr self.builder.buildLoad(ptr_field_ptr, "");
1082 };
1083
1084 const indices: [1]*const llvm.Value = .{rhs};
1085 const ptr = self.builder.buildInBoundsGEP(base_ptr, &indices, 1, "");
1086 return self.builder.buildLoad(ptr, "");
1087 }
1088
9891089 fn airNot(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
9901090 if (self.liveness.isUnused(inst))
9911091 return null;
......@@ -1152,6 +1252,31 @@ pub const FuncGen = struct {
11521252 return self.builder.buildNot((try self.airIsNonNull(inst, operand_is_ptr)).?, "");
11531253 }
11541254
1255 fn airIsErr(
1256 self: *FuncGen,
1257 inst: Air.Inst.Index,
1258 invert_logic: bool,
1259 operand_is_ptr: bool,
1260 ) !?*const llvm.Value {
1261 if (self.liveness.isUnused(inst))
1262 return null;
1263
1264 const un_op = self.air.instructions.items(.data)[inst].un_op;
1265 const operand = try self.resolveInst(un_op);
1266 const err_union_ty = self.air.typeOf(un_op);
1267 const payload_ty = err_union_ty.errorUnionPayload();
1268
1269 if (!payload_ty.hasCodeGenBits()) {
1270 const loaded = if (operand_is_ptr) self.builder.buildLoad(operand, "") else operand;
1271 const op: llvm.IntPredicate = if (invert_logic) .EQ else .NE;
1272 const err_set_ty = try self.dg.llvmType(Type.initTag(.anyerror));
1273 const zero = err_set_ty.constNull();
1274 return self.builder.buildICmp(op, loaded, zero, "");
1275 }
1276
1277 return self.todo("implement 'airIsErr' for error unions with nonzero payload", .{});
1278 }
1279
11551280 fn airOptionalPayload(
11561281 self: *FuncGen,
11571282 inst: Air.Inst.Index,
......@@ -1177,6 +1302,40 @@ pub const FuncGen = struct {
11771302 }
11781303 }
11791304
1305 fn airErrUnionPayload(
1306 self: *FuncGen,
1307 inst: Air.Inst.Index,
1308 operand_is_ptr: bool,
1309 ) !?*const llvm.Value {
1310 if (self.liveness.isUnused(inst))
1311 return null;
1312
1313 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
1314 const operand = try self.resolveInst(ty_op.operand);
1315 const err_union_ty = self.air.typeOf(ty_op.operand);
1316 const payload_ty = err_union_ty.errorUnionPayload();
1317
1318 if (!payload_ty.hasCodeGenBits()) {
1319 return null;
1320 }
1321
1322 _ = operand;
1323 _ = operand_is_ptr;
1324 return self.todo("implement 'airErrUnionPayload' for type {}", .{self.air.typeOf(ty_op.operand)});
1325 }
1326
1327 fn airErrUnionErr(
1328 self: *FuncGen,
1329 inst: Air.Inst.Index,
1330 operand_is_ptr: bool,
1331 ) !?*const llvm.Value {
1332 if (self.liveness.isUnused(inst))
1333 return null;
1334
1335 _ = operand_is_ptr;
1336 return self.todo("implement 'airErrUnionErr'", .{});
1337 }
1338
11801339 fn airAdd(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
11811340 if (self.liveness.isUnused(inst))
11821341 return null;
src/codegen/llvm/bindings.zig+21-1
......@@ -42,6 +42,9 @@ pub const Context = opaque {
4242 Packed: Bool,
4343 ) *const Type;
4444
45 const structCreateNamed = LLVMStructCreateNamed;
46 extern fn LLVMStructCreateNamed(C: *const Context, Name: [*:0]const u8) *const Type;
47
4548 pub const constString = LLVMConstStringInContext;
4649 extern fn LLVMConstStringInContext(C: *const Context, Str: [*]const u8, Length: c_uint, DontNullTerminate: Bool) *const Value;
4750
......@@ -76,6 +79,9 @@ pub const Value = opaque {
7679
7780 pub const typeOf = LLVMTypeOf;
7881 extern fn LLVMTypeOf(Val: *const Value) *const Type;
82
83 pub const setGlobalConstant = LLVMSetGlobalConstant;
84 extern fn LLVMSetGlobalConstant(GlobalVar: *const Value, IsConstant: Bool) void;
7985};
8086
8187pub const Type = opaque {
......@@ -99,6 +105,14 @@ pub const Type = opaque {
99105
100106 pub const arrayType = LLVMArrayType;
101107 extern fn LLVMArrayType(ElementType: *const Type, ElementCount: c_uint) *const Type;
108
109 pub const structSetBody = LLVMStructSetBody;
110 extern fn LLVMStructSetBody(
111 StructTy: *const Type,
112 ElementTypes: [*]*const Type,
113 ElementCount: c_uint,
114 Packed: Bool,
115 ) void;
102116};
103117
104118pub const Module = opaque {
......@@ -257,7 +271,13 @@ pub const Builder = opaque {
257271 extern fn LLVMBuildBitCast(*const Builder, Val: *const Value, DestTy: *const Type, Name: [*:0]const u8) *const Value;
258272
259273 pub const buildInBoundsGEP = LLVMBuildInBoundsGEP;
260 extern fn LLVMBuildInBoundsGEP(B: *const Builder, Pointer: *const Value, Indices: [*]*const Value, NumIndices: c_uint, Name: [*:0]const u8) *const Value;
274 extern fn LLVMBuildInBoundsGEP(
275 B: *const Builder,
276 Pointer: *const Value,
277 Indices: [*]const *const Value,
278 NumIndices: c_uint,
279 Name: [*:0]const u8,
280 ) *const Value;
261281
262282 pub const buildICmp = LLVMBuildICmp;
263283 extern fn LLVMBuildICmp(*const Builder, Op: IntPredicate, LHS: *const Value, RHS: *const Value, Name: [*:0]const u8) *const Value;
src/type.zig+1-1
......@@ -915,7 +915,7 @@ pub const Type = extern union {
915915 }
916916 try writer.writeAll(") callconv(.");
917917 try writer.writeAll(@tagName(payload.cc));
918 try writer.writeAll(")");
918 try writer.writeAll(") ");
919919 ty = payload.return_type;
920920 continue;
921921 },