mirror of
https://github.com/ziglang/zig.git
synced 2025-12-25 15:43:06 +00:00
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.
This commit is contained in:
parent
c3d10dbda1
commit
14d8a1c10d
@ -512,12 +512,15 @@ pub const DeclGen = struct {
|
||||
|
||||
// TODO: remove this redundant `llvmType`, it is also called in `genTypedValue`.
|
||||
const llvm_type = try self.llvmType(decl.ty);
|
||||
const val = try self.genTypedValue(.{ .ty = decl.ty, .val = decl.val }, null);
|
||||
const global = self.llvmModule().addGlobal(llvm_type, decl.name);
|
||||
llvm.setInitializer(global, val);
|
||||
const init_val = if (decl.val.castTag(.variable)) |payload| init_val: {
|
||||
const variable = payload.data;
|
||||
global.setGlobalConstant(.False);
|
||||
break :init_val variable.init;
|
||||
} else decl.val;
|
||||
|
||||
// TODO ask the Decl if it is const
|
||||
// https://github.com/ziglang/zig/issues/7582
|
||||
const llvm_init = try self.genTypedValue(.{ .ty = decl.ty, .val = init_val }, null);
|
||||
llvm.setInitializer(global, llvm_init);
|
||||
|
||||
return global;
|
||||
}
|
||||
@ -576,6 +579,36 @@ pub const DeclGen = struct {
|
||||
.ErrorSet => {
|
||||
return self.context.intType(16);
|
||||
},
|
||||
.Struct => {
|
||||
const struct_obj = t.castTag(.@"struct").?.data;
|
||||
assert(struct_obj.haveFieldTypes());
|
||||
const llvm_fields = try self.gpa.alloc(*const llvm.Type, struct_obj.fields.count());
|
||||
defer self.gpa.free(llvm_fields);
|
||||
for (struct_obj.fields.values()) |field, i| {
|
||||
llvm_fields[i] = try self.llvmType(field.ty);
|
||||
}
|
||||
return self.context.structType(
|
||||
llvm_fields.ptr,
|
||||
@intCast(c_uint, llvm_fields.len),
|
||||
.False,
|
||||
);
|
||||
},
|
||||
.Fn => {
|
||||
const ret_ty = try self.llvmType(t.fnReturnType());
|
||||
const params_len = t.fnParamLen();
|
||||
const llvm_params = try self.gpa.alloc(*const llvm.Type, params_len);
|
||||
defer self.gpa.free(llvm_params);
|
||||
for (llvm_params) |*llvm_param, i| {
|
||||
llvm_param.* = try self.llvmType(t.fnParamType(i));
|
||||
}
|
||||
const is_var_args = t.fnIsVarArgs();
|
||||
return llvm.functionType(
|
||||
ret_ty,
|
||||
llvm_params.ptr,
|
||||
@intCast(c_uint, llvm_params.len),
|
||||
llvm.Bool.fromBool(is_var_args),
|
||||
);
|
||||
},
|
||||
.ComptimeInt => unreachable,
|
||||
.ComptimeFloat => unreachable,
|
||||
.Type => unreachable,
|
||||
@ -586,10 +619,8 @@ pub const DeclGen = struct {
|
||||
.BoundFn => @panic("TODO remove BoundFn from the language"),
|
||||
|
||||
.Float,
|
||||
.Struct,
|
||||
.Enum,
|
||||
.Union,
|
||||
.Fn,
|
||||
.Opaque,
|
||||
.Frame,
|
||||
.AnyFrame,
|
||||
@ -645,7 +676,11 @@ pub const DeclGen = struct {
|
||||
_ = fg.?.builder.buildStore(try self.genTypedValue(.{ .ty = elem_type, .val = elem_value }, fg), alloca);
|
||||
return alloca;
|
||||
},
|
||||
else => return self.todo("implement const of pointer type '{}'", .{tv.ty}),
|
||||
.variable => {
|
||||
const variable = tv.val.castTag(.variable).?.data;
|
||||
return self.resolveGlobalDecl(variable.owner_decl);
|
||||
},
|
||||
else => |tag| return self.todo("implement const of pointer type '{}' ({})", .{ tv.ty, tag }),
|
||||
},
|
||||
.Array => {
|
||||
if (tv.val.castTag(.bytes)) |payload| {
|
||||
@ -765,45 +800,64 @@ pub const FuncGen = struct {
|
||||
const air_tags = self.air.instructions.items(.tag);
|
||||
for (body) |inst| {
|
||||
const opt_value: ?*const llvm.Value = switch (air_tags[inst]) {
|
||||
// zig fmt: off
|
||||
.add => try self.airAdd(inst),
|
||||
.sub => try self.airSub(inst),
|
||||
|
||||
.cmp_eq => try self.airCmp(inst, .eq),
|
||||
.cmp_gt => try self.airCmp(inst, .gt),
|
||||
.cmp_eq => try self.airCmp(inst, .eq),
|
||||
.cmp_gt => try self.airCmp(inst, .gt),
|
||||
.cmp_gte => try self.airCmp(inst, .gte),
|
||||
.cmp_lt => try self.airCmp(inst, .lt),
|
||||
.cmp_lt => try self.airCmp(inst, .lt),
|
||||
.cmp_lte => try self.airCmp(inst, .lte),
|
||||
.cmp_neq => try self.airCmp(inst, .neq),
|
||||
|
||||
.is_non_null => try self.airIsNonNull(inst, false),
|
||||
.is_non_null => try self.airIsNonNull(inst, false),
|
||||
.is_non_null_ptr => try self.airIsNonNull(inst, true),
|
||||
.is_null => try self.airIsNull(inst, false),
|
||||
.is_null_ptr => try self.airIsNull(inst, true),
|
||||
.is_null => try self.airIsNull(inst, false),
|
||||
.is_null_ptr => try self.airIsNull(inst, true),
|
||||
.is_non_err => try self.airIsErr(inst, true, false),
|
||||
.is_non_err_ptr => try self.airIsErr(inst, true, true),
|
||||
.is_err => try self.airIsErr(inst, false, false),
|
||||
.is_err_ptr => try self.airIsErr(inst, false, true),
|
||||
|
||||
.alloc => try self.airAlloc(inst),
|
||||
.arg => try self.airArg(inst),
|
||||
.bitcast => try self.airBitCast(inst),
|
||||
.block => try self.airBlock(inst),
|
||||
.br => try self.airBr(inst),
|
||||
.alloc => try self.airAlloc(inst),
|
||||
.arg => try self.airArg(inst),
|
||||
.bitcast => try self.airBitCast(inst),
|
||||
.block => try self.airBlock(inst),
|
||||
.br => try self.airBr(inst),
|
||||
.breakpoint => try self.airBreakpoint(inst),
|
||||
.call => try self.airCall(inst),
|
||||
.cond_br => try self.airCondBr(inst),
|
||||
.intcast => try self.airIntCast(inst),
|
||||
.ptrtoint => try self.airPtrToInt(inst),
|
||||
.load => try self.airLoad(inst),
|
||||
.loop => try self.airLoop(inst),
|
||||
.not => try self.airNot(inst),
|
||||
.ret => try self.airRet(inst),
|
||||
.store => try self.airStore(inst),
|
||||
.unreach => self.airUnreach(inst),
|
||||
.optional_payload => try self.airOptionalPayload(inst, false),
|
||||
.call => try self.airCall(inst),
|
||||
.cond_br => try self.airCondBr(inst),
|
||||
.intcast => try self.airIntCast(inst),
|
||||
.ptrtoint => try self.airPtrToInt(inst),
|
||||
.load => try self.airLoad(inst),
|
||||
.loop => try self.airLoop(inst),
|
||||
.not => try self.airNot(inst),
|
||||
.ret => try self.airRet(inst),
|
||||
.store => try self.airStore(inst),
|
||||
.assembly => try self.airAssembly(inst),
|
||||
.varptr => try self.airVarPtr(inst),
|
||||
.slice_ptr => try self.airSliceField(inst, 0),
|
||||
.slice_len => try self.airSliceField(inst, 1),
|
||||
|
||||
.slice_elem_val => try self.airSliceElemVal(inst, false),
|
||||
.ptr_slice_elem_val => try self.airSliceElemVal(inst, true),
|
||||
|
||||
.optional_payload => try self.airOptionalPayload(inst, false),
|
||||
.optional_payload_ptr => try self.airOptionalPayload(inst, true),
|
||||
.assembly => try self.airAssembly(inst),
|
||||
|
||||
.unwrap_errunion_payload => try self.airErrUnionPayload(inst, false),
|
||||
.unwrap_errunion_payload_ptr => try self.airErrUnionPayload(inst, true),
|
||||
.unwrap_errunion_err => try self.airErrUnionErr(inst, false),
|
||||
.unwrap_errunion_err_ptr => try self.airErrUnionErr(inst, true),
|
||||
|
||||
.unreach => self.airUnreach(inst),
|
||||
.dbg_stmt => blk: {
|
||||
// TODO: implement debug info
|
||||
break :blk null;
|
||||
},
|
||||
else => |tag| return self.todo("implement AIR instruction: {}", .{tag}),
|
||||
// zig fmt: on
|
||||
};
|
||||
if (opt_value) |val| try self.func_inst_table.putNoClobber(self.gpa, inst, val);
|
||||
}
|
||||
@ -986,6 +1040,52 @@ pub const FuncGen = struct {
|
||||
return null;
|
||||
}
|
||||
|
||||
fn airVarPtr(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
|
||||
if (self.liveness.isUnused(inst))
|
||||
return null;
|
||||
|
||||
const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
|
||||
const variable = self.air.variables[ty_pl.payload];
|
||||
const decl_llvm_value = self.dg.resolveGlobalDecl(variable.owner_decl);
|
||||
return decl_llvm_value;
|
||||
}
|
||||
|
||||
fn airSliceField(self: *FuncGen, inst: Air.Inst.Index, index: c_uint) !?*const llvm.Value {
|
||||
if (self.liveness.isUnused(inst))
|
||||
return null;
|
||||
|
||||
const ty_op = self.air.instructions.items(.data)[inst].ty_op;
|
||||
const operand = try self.resolveInst(ty_op.operand);
|
||||
return self.builder.buildExtractValue(operand, index, "");
|
||||
}
|
||||
|
||||
fn airSliceElemVal(
|
||||
self: *FuncGen,
|
||||
inst: Air.Inst.Index,
|
||||
operand_is_ptr: bool,
|
||||
) !?*const llvm.Value {
|
||||
if (self.liveness.isUnused(inst))
|
||||
return null;
|
||||
|
||||
const bin_op = self.air.instructions.items(.data)[inst].bin_op;
|
||||
const lhs = try self.resolveInst(bin_op.lhs);
|
||||
const rhs = try self.resolveInst(bin_op.rhs);
|
||||
|
||||
const base_ptr = if (!operand_is_ptr) lhs else ptr: {
|
||||
const index_type = self.context.intType(32);
|
||||
const indices: [2]*const llvm.Value = .{
|
||||
index_type.constNull(),
|
||||
index_type.constInt(0, .False),
|
||||
};
|
||||
const ptr_field_ptr = self.builder.buildInBoundsGEP(lhs, &indices, 2, "");
|
||||
break :ptr self.builder.buildLoad(ptr_field_ptr, "");
|
||||
};
|
||||
|
||||
const indices: [1]*const llvm.Value = .{rhs};
|
||||
const ptr = self.builder.buildInBoundsGEP(base_ptr, &indices, 1, "");
|
||||
return self.builder.buildLoad(ptr, "");
|
||||
}
|
||||
|
||||
fn airNot(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
|
||||
if (self.liveness.isUnused(inst))
|
||||
return null;
|
||||
@ -1152,6 +1252,31 @@ pub const FuncGen = struct {
|
||||
return self.builder.buildNot((try self.airIsNonNull(inst, operand_is_ptr)).?, "");
|
||||
}
|
||||
|
||||
fn airIsErr(
|
||||
self: *FuncGen,
|
||||
inst: Air.Inst.Index,
|
||||
invert_logic: bool,
|
||||
operand_is_ptr: bool,
|
||||
) !?*const llvm.Value {
|
||||
if (self.liveness.isUnused(inst))
|
||||
return null;
|
||||
|
||||
const un_op = self.air.instructions.items(.data)[inst].un_op;
|
||||
const operand = try self.resolveInst(un_op);
|
||||
const err_union_ty = self.air.typeOf(un_op);
|
||||
const payload_ty = err_union_ty.errorUnionPayload();
|
||||
|
||||
if (!payload_ty.hasCodeGenBits()) {
|
||||
const loaded = if (operand_is_ptr) self.builder.buildLoad(operand, "") else operand;
|
||||
const op: llvm.IntPredicate = if (invert_logic) .EQ else .NE;
|
||||
const err_set_ty = try self.dg.llvmType(Type.initTag(.anyerror));
|
||||
const zero = err_set_ty.constNull();
|
||||
return self.builder.buildICmp(op, loaded, zero, "");
|
||||
}
|
||||
|
||||
return self.todo("implement 'airIsErr' for error unions with nonzero payload", .{});
|
||||
}
|
||||
|
||||
fn airOptionalPayload(
|
||||
self: *FuncGen,
|
||||
inst: Air.Inst.Index,
|
||||
@ -1177,6 +1302,40 @@ pub const FuncGen = struct {
|
||||
}
|
||||
}
|
||||
|
||||
fn airErrUnionPayload(
|
||||
self: *FuncGen,
|
||||
inst: Air.Inst.Index,
|
||||
operand_is_ptr: bool,
|
||||
) !?*const llvm.Value {
|
||||
if (self.liveness.isUnused(inst))
|
||||
return null;
|
||||
|
||||
const ty_op = self.air.instructions.items(.data)[inst].ty_op;
|
||||
const operand = try self.resolveInst(ty_op.operand);
|
||||
const err_union_ty = self.air.typeOf(ty_op.operand);
|
||||
const payload_ty = err_union_ty.errorUnionPayload();
|
||||
|
||||
if (!payload_ty.hasCodeGenBits()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
_ = operand;
|
||||
_ = operand_is_ptr;
|
||||
return self.todo("implement 'airErrUnionPayload' for type {}", .{self.air.typeOf(ty_op.operand)});
|
||||
}
|
||||
|
||||
fn airErrUnionErr(
|
||||
self: *FuncGen,
|
||||
inst: Air.Inst.Index,
|
||||
operand_is_ptr: bool,
|
||||
) !?*const llvm.Value {
|
||||
if (self.liveness.isUnused(inst))
|
||||
return null;
|
||||
|
||||
_ = operand_is_ptr;
|
||||
return self.todo("implement 'airErrUnionErr'", .{});
|
||||
}
|
||||
|
||||
fn airAdd(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
|
||||
if (self.liveness.isUnused(inst))
|
||||
return null;
|
||||
|
||||
@ -42,6 +42,9 @@ pub const Context = opaque {
|
||||
Packed: Bool,
|
||||
) *const Type;
|
||||
|
||||
const structCreateNamed = LLVMStructCreateNamed;
|
||||
extern fn LLVMStructCreateNamed(C: *const Context, Name: [*:0]const u8) *const Type;
|
||||
|
||||
pub const constString = LLVMConstStringInContext;
|
||||
extern fn LLVMConstStringInContext(C: *const Context, Str: [*]const u8, Length: c_uint, DontNullTerminate: Bool) *const Value;
|
||||
|
||||
@ -76,6 +79,9 @@ pub const Value = opaque {
|
||||
|
||||
pub const typeOf = LLVMTypeOf;
|
||||
extern fn LLVMTypeOf(Val: *const Value) *const Type;
|
||||
|
||||
pub const setGlobalConstant = LLVMSetGlobalConstant;
|
||||
extern fn LLVMSetGlobalConstant(GlobalVar: *const Value, IsConstant: Bool) void;
|
||||
};
|
||||
|
||||
pub const Type = opaque {
|
||||
@ -99,6 +105,14 @@ pub const Type = opaque {
|
||||
|
||||
pub const arrayType = LLVMArrayType;
|
||||
extern fn LLVMArrayType(ElementType: *const Type, ElementCount: c_uint) *const Type;
|
||||
|
||||
pub const structSetBody = LLVMStructSetBody;
|
||||
extern fn LLVMStructSetBody(
|
||||
StructTy: *const Type,
|
||||
ElementTypes: [*]*const Type,
|
||||
ElementCount: c_uint,
|
||||
Packed: Bool,
|
||||
) void;
|
||||
};
|
||||
|
||||
pub const Module = opaque {
|
||||
@ -257,7 +271,13 @@ pub const Builder = opaque {
|
||||
extern fn LLVMBuildBitCast(*const Builder, Val: *const Value, DestTy: *const Type, Name: [*:0]const u8) *const Value;
|
||||
|
||||
pub const buildInBoundsGEP = LLVMBuildInBoundsGEP;
|
||||
extern fn LLVMBuildInBoundsGEP(B: *const Builder, Pointer: *const Value, Indices: [*]*const Value, NumIndices: c_uint, Name: [*:0]const u8) *const Value;
|
||||
extern fn LLVMBuildInBoundsGEP(
|
||||
B: *const Builder,
|
||||
Pointer: *const Value,
|
||||
Indices: [*]const *const Value,
|
||||
NumIndices: c_uint,
|
||||
Name: [*:0]const u8,
|
||||
) *const Value;
|
||||
|
||||
pub const buildICmp = LLVMBuildICmp;
|
||||
extern fn LLVMBuildICmp(*const Builder, Op: IntPredicate, LHS: *const Value, RHS: *const Value, Name: [*:0]const u8) *const Value;
|
||||
|
||||
@ -915,7 +915,7 @@ pub const Type = extern union {
|
||||
}
|
||||
try writer.writeAll(") callconv(.");
|
||||
try writer.writeAll(@tagName(payload.cc));
|
||||
try writer.writeAll(")");
|
||||
try writer.writeAll(") ");
|
||||
ty = payload.return_type;
|
||||
continue;
|
||||
},
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user