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:
Andrew Kelley
2021-09-23 20:01:45 -07:00
parent cc4d38ed57
commit 418105589a
4 changed files with 1372 additions and 1191 deletions

File diff suppressed because it is too large Load Diff

1187
lib/std/special/c_stage1.zig Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -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");
}

View File

@@ -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;