stage2: prepare for building freestanding libc
Extracts lib/std/special/c_stage1.zig from lib/std/special/c.zig. When the self-hosted compiler is further along, all the logic from c_stage1.zig will be migrated back c.zig and then c_stage1.zig will be deleted. Until then we have a simpler implementation of c.zig that only uses features already implemented in self-hosted. So far it only contains memcpy and memset, with slightly different (arguably more correct!) implementations that are compatible with self-hosted. Additionally, this commit improves the LLVM backend: * use the more efficient and convenient fnInfo() when lowering function type info. * fix incremental compilation not deleting all basic blocks of a function. * hook up calling conventions * hook up the following function attributes: - noredzone, nounwind, uwtable, minsize, optsize, sanitize_thread
This commit is contained in:
File diff suppressed because it is too large
Load Diff
1187
lib/std/special/c_stage1.zig
Normal file
1187
lib/std/special/c_stage1.zig
Normal file
File diff suppressed because it is too large
Load Diff
@@ -370,17 +370,16 @@ pub const Object = struct {
|
||||
}
|
||||
|
||||
// This gets the LLVM values from the function and stores them in `dg.args`.
|
||||
const fn_param_len = decl.ty.fnParamLen();
|
||||
var args = try dg.gpa.alloc(*const llvm.Value, fn_param_len);
|
||||
const fn_info = decl.ty.fnInfo();
|
||||
var args = try dg.gpa.alloc(*const llvm.Value, fn_info.param_types.len);
|
||||
|
||||
for (args) |*arg, i| {
|
||||
arg.* = llvm.getParam(llvm_func, @intCast(c_uint, i));
|
||||
}
|
||||
|
||||
// We remove all the basic blocks of a function to support incremental
|
||||
// compilation!
|
||||
// TODO: remove all basic blocks if functions can have more than one
|
||||
if (llvm_func.getFirstBasicBlock()) |bb| {
|
||||
// Remove all the basic blocks of a function in order to start over, generating
|
||||
// LLVM IR from an empty function body.
|
||||
while (llvm_func.getFirstBasicBlock()) |bb| {
|
||||
bb.deleteBasicBlock();
|
||||
}
|
||||
|
||||
@@ -545,20 +544,16 @@ pub const DeclGen = struct {
|
||||
|
||||
assert(decl.has_tv);
|
||||
const zig_fn_type = decl.ty;
|
||||
const return_type = zig_fn_type.fnReturnType();
|
||||
const fn_param_len = zig_fn_type.fnParamLen();
|
||||
const fn_info = zig_fn_type.fnInfo();
|
||||
const return_type = fn_info.return_type;
|
||||
|
||||
const fn_param_types = try self.gpa.alloc(Type, fn_param_len);
|
||||
defer self.gpa.free(fn_param_types);
|
||||
zig_fn_type.fnParamTypes(fn_param_types);
|
||||
|
||||
const llvm_param_buffer = try self.gpa.alloc(*const llvm.Type, fn_param_len);
|
||||
const llvm_param_buffer = try self.gpa.alloc(*const llvm.Type, fn_info.param_types.len);
|
||||
defer self.gpa.free(llvm_param_buffer);
|
||||
|
||||
var llvm_params_len: c_uint = 0;
|
||||
for (fn_param_types) |fn_param| {
|
||||
if (fn_param.hasCodeGenBits()) {
|
||||
llvm_param_buffer[llvm_params_len] = try self.llvmType(fn_param);
|
||||
for (fn_info.param_types) |param_ty| {
|
||||
if (param_ty.hasCodeGenBits()) {
|
||||
llvm_param_buffer[llvm_params_len] = try self.llvmType(param_ty);
|
||||
llvm_params_len += 1;
|
||||
}
|
||||
}
|
||||
@@ -583,8 +578,85 @@ pub const DeclGen = struct {
|
||||
llvm_fn.setUnnamedAddr(.True);
|
||||
}
|
||||
|
||||
// TODO: calling convention, linkage, tsan, etc. see codegen.cpp `make_fn_llvm_value`.
|
||||
// TODO: more attributes. see codegen.cpp `make_fn_llvm_value`.
|
||||
const target = self.module.getTarget();
|
||||
switch (fn_info.cc) {
|
||||
.Unspecified, .Inline, .Async => {
|
||||
llvm_fn.setFunctionCallConv(.Fast);
|
||||
},
|
||||
.C => {
|
||||
llvm_fn.setFunctionCallConv(.C);
|
||||
},
|
||||
.Naked => {
|
||||
self.addFnAttr(llvm_fn, "naked");
|
||||
},
|
||||
.Stdcall => {
|
||||
llvm_fn.setFunctionCallConv(.X86_StdCall);
|
||||
},
|
||||
.Fastcall => {
|
||||
llvm_fn.setFunctionCallConv(.X86_FastCall);
|
||||
},
|
||||
.Vectorcall => {
|
||||
switch (target.cpu.arch) {
|
||||
.i386, .x86_64 => {
|
||||
llvm_fn.setFunctionCallConv(.X86_VectorCall);
|
||||
},
|
||||
.aarch64, .aarch64_be, .aarch64_32 => {
|
||||
llvm_fn.setFunctionCallConv(.AArch64_VectorCall);
|
||||
},
|
||||
else => unreachable,
|
||||
}
|
||||
},
|
||||
.Thiscall => {
|
||||
llvm_fn.setFunctionCallConv(.X86_ThisCall);
|
||||
},
|
||||
.APCS => {
|
||||
llvm_fn.setFunctionCallConv(.ARM_APCS);
|
||||
},
|
||||
.AAPCS => {
|
||||
llvm_fn.setFunctionCallConv(.ARM_AAPCS);
|
||||
},
|
||||
.AAPCSVFP => {
|
||||
llvm_fn.setFunctionCallConv(.ARM_AAPCS_VFP);
|
||||
},
|
||||
.Interrupt => {
|
||||
switch (target.cpu.arch) {
|
||||
.i386, .x86_64 => {
|
||||
llvm_fn.setFunctionCallConv(.X86_INTR);
|
||||
},
|
||||
.avr => {
|
||||
llvm_fn.setFunctionCallConv(.AVR_INTR);
|
||||
},
|
||||
.msp430 => {
|
||||
llvm_fn.setFunctionCallConv(.MSP430_INTR);
|
||||
},
|
||||
else => unreachable,
|
||||
}
|
||||
},
|
||||
.Signal => {
|
||||
llvm_fn.setFunctionCallConv(.AVR_SIGNAL);
|
||||
},
|
||||
.SysV => {
|
||||
llvm_fn.setFunctionCallConv(.X86_64_SysV);
|
||||
},
|
||||
}
|
||||
|
||||
// Function attributes that are independent of analysis results of the function body.
|
||||
if (!self.module.comp.bin_file.options.red_zone) {
|
||||
self.addFnAttr(llvm_fn, "noredzone");
|
||||
}
|
||||
self.addFnAttr(llvm_fn, "nounwind");
|
||||
if (self.module.comp.unwind_tables) {
|
||||
self.addFnAttr(llvm_fn, "uwtable");
|
||||
}
|
||||
if (self.module.comp.bin_file.options.optimize_mode == .ReleaseSmall) {
|
||||
self.addFnAttr(llvm_fn, "minsize");
|
||||
self.addFnAttr(llvm_fn, "optsize");
|
||||
}
|
||||
if (self.module.comp.bin_file.options.tsan) {
|
||||
self.addFnAttr(llvm_fn, "sanitize_thread");
|
||||
}
|
||||
// TODO add target-cpu and target-features fn attributes
|
||||
if (return_type.isNoReturn()) {
|
||||
self.addFnAttr(llvm_fn, "noreturn");
|
||||
}
|
||||
|
||||
@@ -145,6 +145,12 @@ pub const Value = opaque {
|
||||
|
||||
pub const setAlignment = LLVMSetAlignment;
|
||||
extern fn LLVMSetAlignment(V: *const Value, Bytes: c_uint) void;
|
||||
|
||||
pub const getFunctionCallConv = LLVMGetFunctionCallConv;
|
||||
extern fn LLVMGetFunctionCallConv(Fn: *const Value) CallConv;
|
||||
|
||||
pub const setFunctionCallConv = LLVMSetFunctionCallConv;
|
||||
extern fn LLVMSetFunctionCallConv(Fn: *const Value, CC: CallConv) void;
|
||||
};
|
||||
|
||||
pub const Type = opaque {
|
||||
@@ -1028,6 +1034,53 @@ pub const TypeKind = enum(c_int) {
|
||||
X86_AMX,
|
||||
};
|
||||
|
||||
pub const CallConv = enum(c_uint) {
|
||||
C = 0,
|
||||
Fast = 8,
|
||||
Cold = 9,
|
||||
GHC = 10,
|
||||
HiPE = 11,
|
||||
WebKit_JS = 12,
|
||||
AnyReg = 13,
|
||||
PreserveMost = 14,
|
||||
PreserveAll = 15,
|
||||
Swift = 16,
|
||||
CXX_FAST_TLS = 17,
|
||||
|
||||
X86_StdCall = 64,
|
||||
X86_FastCall = 65,
|
||||
ARM_APCS = 66,
|
||||
ARM_AAPCS = 67,
|
||||
ARM_AAPCS_VFP = 68,
|
||||
MSP430_INTR = 69,
|
||||
X86_ThisCall = 70,
|
||||
PTX_Kernel = 71,
|
||||
PTX_Device = 72,
|
||||
SPIR_FUNC = 75,
|
||||
SPIR_KERNEL = 76,
|
||||
Intel_OCL_BI = 77,
|
||||
X86_64_SysV = 78,
|
||||
Win64 = 79,
|
||||
X86_VectorCall = 80,
|
||||
HHVM = 81,
|
||||
HHVM_C = 82,
|
||||
X86_INTR = 83,
|
||||
AVR_INTR = 84,
|
||||
AVR_SIGNAL = 85,
|
||||
AVR_BUILTIN = 86,
|
||||
AMDGPU_VS = 87,
|
||||
AMDGPU_GS = 88,
|
||||
AMDGPU_PS = 89,
|
||||
AMDGPU_CS = 90,
|
||||
AMDGPU_KERNEL = 91,
|
||||
X86_RegCall = 92,
|
||||
AMDGPU_HS = 93,
|
||||
MSP430_BUILTIN = 94,
|
||||
AMDGPU_LS = 95,
|
||||
AMDGPU_ES = 96,
|
||||
AArch64_VectorCall = 97,
|
||||
};
|
||||
|
||||
pub const address_space = struct {
|
||||
pub const default: c_uint = 0;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user