mirror of
https://github.com/ziglang/zig.git
synced 2025-12-06 14:23:09 +00:00
Address Spaces: Implement in LLVM codegen
This commit is contained in:
parent
e09465fc49
commit
ea393b2bca
@ -4761,7 +4761,7 @@ pub fn populateTestFunctions(mod: *Module) !void {
|
|||||||
const builtin_file = (mod.importPkg(builtin_pkg) catch unreachable).file;
|
const builtin_file = (mod.importPkg(builtin_pkg) catch unreachable).file;
|
||||||
const builtin_namespace = builtin_file.root_decl.?.namespace;
|
const builtin_namespace = builtin_file.root_decl.?.namespace;
|
||||||
const decl = builtin_namespace.decls.get("test_functions").?;
|
const decl = builtin_namespace.decls.get("test_functions").?;
|
||||||
var buf: Type.Payload.ElemType = undefined;
|
var buf: Type.SlicePtrFieldTypeBuffer = undefined;
|
||||||
const tmp_test_fn_ty = decl.ty.slicePtrFieldType(&buf).elemType();
|
const tmp_test_fn_ty = decl.ty.slicePtrFieldType(&buf).elemType();
|
||||||
|
|
||||||
const array_decl = d: {
|
const array_decl = d: {
|
||||||
|
|||||||
@ -8390,7 +8390,7 @@ fn fieldVal(
|
|||||||
.Pointer => switch (object_ty.ptrSize()) {
|
.Pointer => switch (object_ty.ptrSize()) {
|
||||||
.Slice => {
|
.Slice => {
|
||||||
if (mem.eql(u8, field_name, "ptr")) {
|
if (mem.eql(u8, field_name, "ptr")) {
|
||||||
const buf = try arena.create(Type.Payload.ElemType);
|
const buf = try arena.create(Type.SlicePtrFieldTypeBuffer);
|
||||||
const result_ty = object_ty.slicePtrFieldType(buf);
|
const result_ty = object_ty.slicePtrFieldType(buf);
|
||||||
if (try sema.resolveMaybeUndefVal(block, object_src, object)) |val| {
|
if (try sema.resolveMaybeUndefVal(block, object_src, object)) |val| {
|
||||||
if (val.isUndef()) return sema.addConstUndef(result_ty);
|
if (val.isUndef()) return sema.addConstUndef(result_ty);
|
||||||
|
|||||||
@ -4873,7 +4873,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
|
|||||||
switch (typed_value.ty.zigTypeTag()) {
|
switch (typed_value.ty.zigTypeTag()) {
|
||||||
.Pointer => switch (typed_value.ty.ptrSize()) {
|
.Pointer => switch (typed_value.ty.ptrSize()) {
|
||||||
.Slice => {
|
.Slice => {
|
||||||
var buf: Type.Payload.ElemType = undefined;
|
var buf: Type.SlicePtrFieldTypeBuffer = undefined;
|
||||||
const ptr_type = typed_value.ty.slicePtrFieldType(&buf);
|
const ptr_type = typed_value.ty.slicePtrFieldType(&buf);
|
||||||
const ptr_mcv = try self.genTypedValue(.{ .ty = ptr_type, .val = typed_value.val });
|
const ptr_mcv = try self.genTypedValue(.{ .ty = ptr_type, .val = typed_value.val });
|
||||||
const slice_len = typed_value.val.sliceLen();
|
const slice_len = typed_value.val.sliceLen();
|
||||||
|
|||||||
@ -251,7 +251,7 @@ pub const DeclGen = struct {
|
|||||||
try writer.writeByte('(');
|
try writer.writeByte('(');
|
||||||
try dg.renderType(writer, t);
|
try dg.renderType(writer, t);
|
||||||
try writer.writeAll("){");
|
try writer.writeAll("){");
|
||||||
var buf: Type.Payload.ElemType = undefined;
|
var buf: Type.SlicePtrFieldTypeBuffer = undefined;
|
||||||
try dg.renderValue(writer, t.slicePtrFieldType(&buf), val);
|
try dg.renderValue(writer, t.slicePtrFieldType(&buf), val);
|
||||||
try writer.writeAll(", ");
|
try writer.writeAll(", ");
|
||||||
try writer.print("{d}", .{val.sliceLen()});
|
try writer.print("{d}", .{val.sliceLen()});
|
||||||
|
|||||||
@ -554,7 +554,8 @@ pub const DeclGen = struct {
|
|||||||
@intCast(c_uint, fn_param_len),
|
@intCast(c_uint, fn_param_len),
|
||||||
.False,
|
.False,
|
||||||
);
|
);
|
||||||
const llvm_fn = self.llvmModule().addFunction(decl.name, fn_type);
|
const llvm_addrspace = self.llvmAddressSpace(decl.@"addrspace");
|
||||||
|
const llvm_fn = self.llvmModule().addFunctionInAddressSpace(decl.name, fn_type, llvm_addrspace);
|
||||||
|
|
||||||
const is_extern = decl.val.tag() == .extern_fn;
|
const is_extern = decl.val.tag() == .extern_fn;
|
||||||
if (!is_extern) {
|
if (!is_extern) {
|
||||||
@ -576,7 +577,27 @@ pub const DeclGen = struct {
|
|||||||
if (llvm_module.getNamedGlobal(decl.name)) |val| return val;
|
if (llvm_module.getNamedGlobal(decl.name)) |val| return val;
|
||||||
// TODO: remove this redundant `llvmType`, it is also called in `genTypedValue`.
|
// TODO: remove this redundant `llvmType`, it is also called in `genTypedValue`.
|
||||||
const llvm_type = try self.llvmType(decl.ty);
|
const llvm_type = try self.llvmType(decl.ty);
|
||||||
return llvm_module.addGlobal(llvm_type, decl.name);
|
const llvm_addrspace = self.llvmAddressSpace(decl.@"addrspace");
|
||||||
|
return llvm_module.addGlobalInAddressSpace(llvm_type, decl.name, llvm_addrspace);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn llvmAddressSpace(self: DeclGen, address_space: std.builtin.AddressSpace) c_uint {
|
||||||
|
const target = self.module.getTarget();
|
||||||
|
return switch (address_space) {
|
||||||
|
.generic => llvm.address_space.default,
|
||||||
|
.gs => switch (target.cpu.arch) {
|
||||||
|
.i386, .x86_64 => llvm.address_space.x86.gs,
|
||||||
|
else => unreachable,
|
||||||
|
},
|
||||||
|
.fs => switch (target.cpu.arch) {
|
||||||
|
.i386, .x86_64 => llvm.address_space.x86.fs,
|
||||||
|
else => unreachable,
|
||||||
|
},
|
||||||
|
.ss => switch (target.cpu.arch) {
|
||||||
|
.i386, .x86_64 => llvm.address_space.x86.ss,
|
||||||
|
else => unreachable,
|
||||||
|
},
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
fn llvmType(self: *DeclGen, t: Type) error{ OutOfMemory, CodegenFail }!*const llvm.Type {
|
fn llvmType(self: *DeclGen, t: Type) error{ OutOfMemory, CodegenFail }!*const llvm.Type {
|
||||||
@ -605,7 +626,7 @@ pub const DeclGen = struct {
|
|||||||
.Bool => return self.context.intType(1),
|
.Bool => return self.context.intType(1),
|
||||||
.Pointer => {
|
.Pointer => {
|
||||||
if (t.isSlice()) {
|
if (t.isSlice()) {
|
||||||
var buf: Type.Payload.ElemType = undefined;
|
var buf: Type.SlicePtrFieldTypeBuffer = undefined;
|
||||||
const ptr_type = t.slicePtrFieldType(&buf);
|
const ptr_type = t.slicePtrFieldType(&buf);
|
||||||
|
|
||||||
const fields: [2]*const llvm.Type = .{
|
const fields: [2]*const llvm.Type = .{
|
||||||
@ -615,7 +636,8 @@ pub const DeclGen = struct {
|
|||||||
return self.context.structType(&fields, fields.len, .False);
|
return self.context.structType(&fields, fields.len, .False);
|
||||||
} else {
|
} else {
|
||||||
const elem_type = try self.llvmType(t.elemType());
|
const elem_type = try self.llvmType(t.elemType());
|
||||||
return elem_type.pointerType(0);
|
const llvm_addrspace = self.llvmAddressSpace(t.ptrAddressSpace());
|
||||||
|
return elem_type.pointerType(llvm_addrspace);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
.Array => {
|
.Array => {
|
||||||
@ -681,7 +703,8 @@ pub const DeclGen = struct {
|
|||||||
@intCast(c_uint, llvm_params.len),
|
@intCast(c_uint, llvm_params.len),
|
||||||
llvm.Bool.fromBool(is_var_args),
|
llvm.Bool.fromBool(is_var_args),
|
||||||
);
|
);
|
||||||
return llvm_fn_ty.pointerType(0);
|
const llvm_addrspace = self.llvmAddressSpace(t.fnAddressSpace());
|
||||||
|
return llvm_fn_ty.pointerType(llvm_addrspace);
|
||||||
},
|
},
|
||||||
.ComptimeInt => unreachable,
|
.ComptimeInt => unreachable,
|
||||||
.ComptimeFloat => unreachable,
|
.ComptimeFloat => unreachable,
|
||||||
@ -749,7 +772,7 @@ pub const DeclGen = struct {
|
|||||||
.Pointer => switch (tv.val.tag()) {
|
.Pointer => switch (tv.val.tag()) {
|
||||||
.decl_ref => {
|
.decl_ref => {
|
||||||
if (tv.ty.isSlice()) {
|
if (tv.ty.isSlice()) {
|
||||||
var buf: Type.Payload.ElemType = undefined;
|
var buf: Type.SlicePtrFieldTypeBuffer = undefined;
|
||||||
const ptr_ty = tv.ty.slicePtrFieldType(&buf);
|
const ptr_ty = tv.ty.slicePtrFieldType(&buf);
|
||||||
var slice_len: Value.Payload.U64 = .{
|
var slice_len: Value.Payload.U64 = .{
|
||||||
.base = .{ .tag = .int_u64 },
|
.base = .{ .tag = .int_u64 },
|
||||||
@ -779,12 +802,13 @@ pub const DeclGen = struct {
|
|||||||
decl.alive = true;
|
decl.alive = true;
|
||||||
const val = try self.resolveGlobalDecl(decl);
|
const val = try self.resolveGlobalDecl(decl);
|
||||||
const llvm_var_type = try self.llvmType(tv.ty);
|
const llvm_var_type = try self.llvmType(tv.ty);
|
||||||
const llvm_type = llvm_var_type.pointerType(0);
|
const llvm_addrspace = self.llvmAddressSpace(decl.@"addrspace");
|
||||||
|
const llvm_type = llvm_var_type.pointerType(llvm_addrspace);
|
||||||
return val.constBitCast(llvm_type);
|
return val.constBitCast(llvm_type);
|
||||||
},
|
},
|
||||||
.slice => {
|
.slice => {
|
||||||
const slice = tv.val.castTag(.slice).?.data;
|
const slice = tv.val.castTag(.slice).?.data;
|
||||||
var buf: Type.Payload.ElemType = undefined;
|
var buf: Type.SlicePtrFieldTypeBuffer = undefined;
|
||||||
const fields: [2]*const llvm.Value = .{
|
const fields: [2]*const llvm.Value = .{
|
||||||
try self.genTypedValue(.{
|
try self.genTypedValue(.{
|
||||||
.ty = tv.ty.slicePtrFieldType(&buf),
|
.ty = tv.ty.slicePtrFieldType(&buf),
|
||||||
|
|||||||
@ -197,6 +197,9 @@ pub const Module = opaque {
|
|||||||
pub const addFunction = LLVMAddFunction;
|
pub const addFunction = LLVMAddFunction;
|
||||||
extern fn LLVMAddFunction(*const Module, Name: [*:0]const u8, FunctionTy: *const Type) *const Value;
|
extern fn LLVMAddFunction(*const Module, Name: [*:0]const u8, FunctionTy: *const Type) *const Value;
|
||||||
|
|
||||||
|
pub const addFunctionInAddressSpace = ZigLLVMAddFunctionInAddressSpace;
|
||||||
|
extern fn ZigLLVMAddFunctionInAddressSpace(*const Module, Name: [*:0]const u8, FunctionTy: *const Type, AddressSpace: c_uint) *const Value;
|
||||||
|
|
||||||
pub const getNamedFunction = LLVMGetNamedFunction;
|
pub const getNamedFunction = LLVMGetNamedFunction;
|
||||||
extern fn LLVMGetNamedFunction(*const Module, Name: [*:0]const u8) ?*const Value;
|
extern fn LLVMGetNamedFunction(*const Module, Name: [*:0]const u8) ?*const Value;
|
||||||
|
|
||||||
@ -209,6 +212,9 @@ pub const Module = opaque {
|
|||||||
pub const addGlobal = LLVMAddGlobal;
|
pub const addGlobal = LLVMAddGlobal;
|
||||||
extern fn LLVMAddGlobal(M: *const Module, Ty: *const Type, Name: [*:0]const u8) *const Value;
|
extern fn LLVMAddGlobal(M: *const Module, Ty: *const Type, Name: [*:0]const u8) *const Value;
|
||||||
|
|
||||||
|
pub const addGlobalInAddressSpace = LLVMAddGlobalInAddressSpace;
|
||||||
|
extern fn LLVMAddGlobalInAddressSpace(M: *const Module, Ty: *const Type, Name: [*:0]const u8, AddressSpace: c_uint) *const Value;
|
||||||
|
|
||||||
pub const getNamedGlobal = LLVMGetNamedGlobal;
|
pub const getNamedGlobal = LLVMGetNamedGlobal;
|
||||||
extern fn LLVMGetNamedGlobal(M: *const Module, Name: [*:0]const u8) ?*const Value;
|
extern fn LLVMGetNamedGlobal(M: *const Module, Name: [*:0]const u8) ?*const Value;
|
||||||
|
|
||||||
@ -975,6 +981,8 @@ pub const TypeKind = enum(c_int) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
pub const address_space = struct {
|
pub const address_space = struct {
|
||||||
|
pub const default = 0;
|
||||||
|
|
||||||
// See llvm/lib/Target/X86/X86.h
|
// See llvm/lib/Target/X86/X86.h
|
||||||
pub const x86_64 = x86;
|
pub const x86_64 = x86;
|
||||||
pub const x86 = struct {
|
pub const x86 = struct {
|
||||||
|
|||||||
48
src/type.zig
48
src/type.zig
@ -2161,42 +2161,72 @@ pub const Type = extern union {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn slicePtrFieldType(self: Type, buffer: *Payload.ElemType) Type {
|
pub const SlicePtrFieldTypeBuffer = union {
|
||||||
|
elem_type: Payload.ElemType,
|
||||||
|
pointer: Payload.Pointer,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn slicePtrFieldType(self: Type, buffer: *SlicePtrFieldTypeBuffer) Type {
|
||||||
switch (self.tag()) {
|
switch (self.tag()) {
|
||||||
.const_slice_u8 => return Type.initTag(.manyptr_const_u8),
|
.const_slice_u8 => return Type.initTag(.manyptr_const_u8),
|
||||||
|
|
||||||
.const_slice => {
|
.const_slice => {
|
||||||
const elem_type = self.castTag(.const_slice).?.data;
|
const elem_type = self.castTag(.const_slice).?.data;
|
||||||
buffer.* = .{
|
buffer.elem_type = .{
|
||||||
.base = .{ .tag = .many_const_pointer },
|
.base = .{ .tag = .many_const_pointer },
|
||||||
.data = elem_type,
|
.data = elem_type,
|
||||||
};
|
};
|
||||||
return Type.initPayload(&buffer.base);
|
return Type.initPayload(&buffer.elem_type.base);
|
||||||
},
|
},
|
||||||
.mut_slice => {
|
.mut_slice => {
|
||||||
const elem_type = self.castTag(.mut_slice).?.data;
|
const elem_type = self.castTag(.mut_slice).?.data;
|
||||||
buffer.* = .{
|
buffer.elem_type = .{
|
||||||
.base = .{ .tag = .many_mut_pointer },
|
.base = .{ .tag = .many_mut_pointer },
|
||||||
.data = elem_type,
|
.data = elem_type,
|
||||||
};
|
};
|
||||||
return Type.initPayload(&buffer.base);
|
return Type.initPayload(&buffer.elem_type.base);
|
||||||
},
|
},
|
||||||
|
|
||||||
.pointer => {
|
.pointer => {
|
||||||
const payload = self.castTag(.pointer).?.data;
|
const payload = self.castTag(.pointer).?.data;
|
||||||
assert(payload.size == .Slice);
|
assert(payload.size == .Slice);
|
||||||
if (payload.mutable) {
|
|
||||||
buffer.* = .{
|
if (payload.sentinel != null or
|
||||||
|
payload.@"align" != 0 or
|
||||||
|
payload.@"addrspace" != .generic or
|
||||||
|
payload.bit_offset != 0 or
|
||||||
|
payload.host_size != 0 or
|
||||||
|
payload.@"allowzero" or
|
||||||
|
payload.@"volatile"
|
||||||
|
) {
|
||||||
|
buffer.pointer = .{
|
||||||
|
.data = .{
|
||||||
|
.pointee_type = payload.pointee_type,
|
||||||
|
.sentinel = payload.sentinel,
|
||||||
|
.@"align" = payload.@"align",
|
||||||
|
.@"addrspace" = payload.@"addrspace",
|
||||||
|
.bit_offset = payload.bit_offset,
|
||||||
|
.host_size = payload.host_size,
|
||||||
|
.@"allowzero" = payload.@"allowzero",
|
||||||
|
.mutable = payload.mutable,
|
||||||
|
.@"volatile" = payload.@"volatile",
|
||||||
|
.size = .Many
|
||||||
|
},
|
||||||
|
};
|
||||||
|
return Type.initPayload(&buffer.pointer.base);
|
||||||
|
} else if (payload.mutable) {
|
||||||
|
buffer.elem_type = .{
|
||||||
.base = .{ .tag = .many_mut_pointer },
|
.base = .{ .tag = .many_mut_pointer },
|
||||||
.data = payload.pointee_type,
|
.data = payload.pointee_type,
|
||||||
};
|
};
|
||||||
|
return Type.initPayload(&buffer.elem_type.base);
|
||||||
} else {
|
} else {
|
||||||
buffer.* = .{
|
buffer.elem_type = .{
|
||||||
.base = .{ .tag = .many_const_pointer },
|
.base = .{ .tag = .many_const_pointer },
|
||||||
.data = payload.pointee_type,
|
.data = payload.pointee_type,
|
||||||
};
|
};
|
||||||
|
return Type.initPayload(&buffer.elem_type.base);
|
||||||
}
|
}
|
||||||
return Type.initPayload(&buffer.base);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
else => unreachable,
|
else => unreachable,
|
||||||
|
|||||||
@ -416,6 +416,11 @@ ZIG_EXTERN_C LLVMTypeRef ZigLLVMTokenTypeInContext(LLVMContextRef context_ref) {
|
|||||||
return wrap(Type::getTokenTy(*unwrap(context_ref)));
|
return wrap(Type::getTokenTy(*unwrap(context_ref)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LLVMValueRef ZigLLVMAddFunctionInAddressSpace(LLVMModuleRef M, const char *Name, LLVMTypeRef FunctionTy, unsigned AddressSpace) {
|
||||||
|
Function* func = Function::Create(unwrap<FunctionType>(FunctionTy), GlobalValue::ExternalLinkage, AddressSpace, Name, unwrap(M));
|
||||||
|
return wrap(func);
|
||||||
|
}
|
||||||
|
|
||||||
LLVMValueRef ZigLLVMBuildCall(LLVMBuilderRef B, LLVMValueRef Fn, LLVMValueRef *Args,
|
LLVMValueRef ZigLLVMBuildCall(LLVMBuilderRef B, LLVMValueRef Fn, LLVMValueRef *Args,
|
||||||
unsigned NumArgs, ZigLLVM_CallingConv CC, ZigLLVM_CallAttr attr, const char *Name)
|
unsigned NumArgs, ZigLLVM_CallingConv CC, ZigLLVM_CallAttr attr, const char *Name)
|
||||||
{
|
{
|
||||||
|
|||||||
@ -65,6 +65,9 @@ ZIG_EXTERN_C LLVMTargetMachineRef ZigLLVMCreateTargetMachine(LLVMTargetRef T, co
|
|||||||
|
|
||||||
ZIG_EXTERN_C LLVMTypeRef ZigLLVMTokenTypeInContext(LLVMContextRef context_ref);
|
ZIG_EXTERN_C LLVMTypeRef ZigLLVMTokenTypeInContext(LLVMContextRef context_ref);
|
||||||
|
|
||||||
|
ZIG_EXTERN_C LLVMValueRef ZigLLVMAddFunctionInAddressSpace(LLVMModuleRef M, const char *Name,
|
||||||
|
LLVMTypeRef FunctionTy, unsigned AddressSpace);
|
||||||
|
|
||||||
enum ZigLLVM_CallingConv {
|
enum ZigLLVM_CallingConv {
|
||||||
ZigLLVM_C = 0,
|
ZigLLVM_C = 0,
|
||||||
ZigLLVM_Fast = 8,
|
ZigLLVM_Fast = 8,
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user