Skip to content

Commit 0b8715c

Browse files
author
vole-dev
committed
default mabi based on RISC-V extensions and -mabi build option
The target abi can also be set in build.zig via LibExeObjStep.target_abi The value passed in is checked that it is a valid value in std.Target.TargetAbi The target abi is also validated against the target cpu
1 parent d6067db commit 0b8715c

File tree

15 files changed

+145
-15
lines changed

15 files changed

+145
-15
lines changed

lib/std/build.zig

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1447,6 +1447,7 @@ pub const LibExeObjStep = struct {
14471447
filter: ?[]const u8,
14481448
single_threaded: bool,
14491449
test_evented_io: bool = false,
1450+
target_abi: ?std.Target.TargetAbi = null,
14501451
code_model: std.builtin.CodeModel = .default,
14511452
wasi_exec_model: ?std.builtin.WasiExecModel = null,
14521453

@@ -2432,6 +2433,9 @@ pub const LibExeObjStep = struct {
24322433
try zig_args.append("-rdynamic");
24332434
}
24342435

2436+
if (self.target_abi) |target_abi| {
2437+
try zig_args.append(builder.fmt("-mabi={s}", .{target_abi.string()}));
2438+
}
24352439
if (self.code_model != .default) {
24362440
try zig_args.append("-mcmodel");
24372441
try zig_args.append(@tagName(self.code_model));

lib/std/target.zig

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -550,6 +550,103 @@ pub const Target = struct {
550550
}
551551
};
552552

553+
/// processor specific ABI
554+
pub const TargetAbi = enum {
555+
//TODO add ARM, Mips, and PowerPC
556+
ilp32,
557+
ilp32d,
558+
ilp32e,
559+
ilp32f,
560+
lp64,
561+
lp64d,
562+
lp64f,
563+
564+
const Riscv32ABI = struct {
565+
fn default(features: Cpu.Feature.Set) TargetAbi {
566+
if (riscv.featureSetHas(features, .d)) {
567+
return .ilp32d;
568+
} else if (riscv.featureSetHas(features, .e)) {
569+
return .ilp32e;
570+
} else {
571+
return .ilp32;
572+
}
573+
}
574+
fn validate(target_abi: TargetAbi, features: Cpu.Feature.Set) ParseError!void {
575+
const has_e = riscv.featureSetHas(features, .e);
576+
const has_f = riscv.featureSetHas(features, .f);
577+
const has_d = riscv.featureSetHas(features, .d);
578+
return switch (target_abi) {
579+
.ilp32e => if (has_e) void{} else error.FeatureAbiMismatch,
580+
.ilp32 => if (!has_e) void{} else error.FeatureAbiMismatch,
581+
.ilp32f => if (!has_e and has_f) void{} else error.FeatureAbiMismatch,
582+
.ilp32d => if (!has_e and has_d) void{} else error.FeatureAbiMismatch,
583+
else => error.ArchAbiMismatch,
584+
};
585+
}
586+
};
587+
const Riscv64ABI = struct {
588+
fn default(features: Cpu.Feature.Set) TargetAbi {
589+
if (riscv.featureSetHas(features, .d)) {
590+
return .lp64d;
591+
} else {
592+
return .lp64;
593+
}
594+
}
595+
fn validate(target_abi: TargetAbi, features: Cpu.Feature.Set) ParseError!void {
596+
const has_f = riscv.featureSetHas(features, .f);
597+
const has_d = riscv.featureSetHas(features, .d);
598+
return switch (target_abi) {
599+
.lp64 => void{},
600+
.lp64f => if (has_f) void{} else error.FeatureAbiMismatch,
601+
.lp64d => if (has_d) void{} else error.FeatureAbiMismatch,
602+
else => error.ArchAbiMismatch,
603+
};
604+
}
605+
};
606+
pub fn default(arch: Cpu.Arch, features: Cpu.Feature.Set) ?TargetAbi {
607+
return switch (arch) {
608+
.riscv32 => Riscv32ABI.default(features),
609+
.riscv64 => Riscv64ABI.default(features),
610+
else => null,
611+
};
612+
}
613+
614+
// re-implementing @tagName because @tagName is not null-terminated in the stage0 compiler
615+
fn tagName(value: anytype) [:0]const u8 {
616+
const T = @TypeOf(value);
617+
const info = @typeInfo(T);
618+
619+
switch (info) {
620+
.Enum => |enum_info| {
621+
comptime var names: [enum_info.fields.len][:0]const u8 = undefined;
622+
inline for (enum_info.fields) |field, i| {
623+
names[i] = field.name ++ [0:0]u8{};
624+
}
625+
return names[@enumToInt(value)];
626+
},
627+
else => @compileError("tagName does not support type " ++ @typeName(T) ++ "."),
628+
}
629+
}
630+
pub fn string(self: TargetAbi) [:0]const u8 {
631+
return tagName(self);
632+
}
633+
pub const ParseError = error{
634+
InvalidAbi,
635+
ArchAbiMismatch,
636+
FeatureAbiMismatch,
637+
};
638+
pub fn parse(cpu: Cpu, abi_string: []const u8) ParseError!TargetAbi {
639+
const target_abi = std.meta.stringToEnum(TargetAbi, abi_string) orelse return error.InvalidAbi;
640+
641+
switch (cpu.arch) {
642+
.riscv32 => try Riscv32ABI.validate(target_abi, cpu.features),
643+
.riscv64 => try Riscv64ABI.validate(target_abi, cpu.features),
644+
else => return error.ArchAbiMismatch,
645+
}
646+
return target_abi;
647+
}
648+
};
649+
553650
pub const ObjectFormat = enum {
554651
/// Common Object File Format (Windows)
555652
coff,

src/Compilation.zig

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -752,6 +752,7 @@ pub const InitOptions = struct {
752752
version: ?std.builtin.Version = null,
753753
libc_installation: ?*const LibCInstallation = null,
754754
machine_code_model: std.builtin.CodeModel = .default,
755+
target_abi: ?std.Target.TargetAbi,
755756
clang_preprocessor_mode: ClangPreprocessorMode = .no,
756757
/// This is for stage1 and should be deleted upon completion of self-hosting.
757758
color: @import("main.zig").Color = .auto,
@@ -1152,6 +1153,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
11521153
cache.hash.add(options.target.os.getVersionRange());
11531154
cache.hash.add(options.is_native_os);
11541155
cache.hash.add(options.target.abi);
1156+
cache.hash.addBytes(if (options.target_abi) |t| t.string() else ".");
11551157
cache.hash.add(ofmt);
11561158
cache.hash.add(pic);
11571159
cache.hash.add(pie);
@@ -1436,6 +1438,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
14361438
.single_threaded = single_threaded,
14371439
.verbose_link = options.verbose_link,
14381440
.machine_code_model = options.machine_code_model,
1441+
.target_abi = options.target_abi,
14391442
.dll_export_fns = dll_export_fns,
14401443
.error_return_tracing = error_return_tracing,
14411444
.llvm_cpu_features = llvm_cpu_features,
@@ -3299,6 +3302,10 @@ pub fn addCCArgs(
32993302
try argv.append("-mthumb");
33003303
}
33013304

3305+
if (comp.bin_file.options.target_abi) |target_abi| {
3306+
try argv.append(try std.fmt.allocPrint(arena, "-mabi={s}", .{target_abi.string()}));
3307+
}
3308+
33023309
if (comp.haveFramePointer()) {
33033310
try argv.append("-fno-omit-frame-pointer");
33043311
} else {
@@ -3437,6 +3444,11 @@ pub fn addCCArgs(
34373444
// TODO
34383445
},
34393446
}
3447+
3448+
if (comp.bin_file.options.target_abi) |target_abi| {
3449+
try argv.append(try std.fmt.allocPrint(arena, "-mabi={s}", .{target_abi.string()}));
3450+
}
3451+
34403452
if (target_util.clangAssemblerSupportsMcpuArg(target)) {
34413453
if (target.cpu.model.llvm_name) |llvm_name| {
34423454
try argv.append(try std.fmt.allocPrint(arena, "-mcpu={s}", .{llvm_name}));
@@ -4170,6 +4182,7 @@ fn buildOutputFromZig(
41704182
.strip = comp.compilerRtStrip(),
41714183
.is_native_os = comp.bin_file.options.is_native_os,
41724184
.is_native_abi = comp.bin_file.options.is_native_abi,
4185+
.target_abi = comp.bin_file.options.target_abi,
41734186
.self_exe_path = comp.self_exe_path,
41744187
.verbose_cc = comp.verbose_cc,
41754188
.verbose_link = comp.bin_file.options.verbose_link,
@@ -4357,6 +4370,7 @@ fn updateStage1Module(comp: *Compilation, main_progress_node: *std.Progress.Node
43574370
.is_native_cpu = false, // Only true when bootstrapping the compiler.
43584371
.llvm_cpu_name = if (target.cpu.model.llvm_name) |s| s.ptr else null,
43594372
.llvm_cpu_features = comp.bin_file.options.llvm_cpu_features.?,
4373+
.llvm_target_abi = if (comp.bin_file.options.target_abi) |t| t.string().ptr else null,
43604374
};
43614375

43624376
comp.stage1_cache_manifest = &man;
@@ -4608,6 +4622,7 @@ pub fn build_crt_file(
46084622
.strip = comp.compilerRtStrip(),
46094623
.is_native_os = comp.bin_file.options.is_native_os,
46104624
.is_native_abi = comp.bin_file.options.is_native_abi,
4625+
.target_abi = comp.bin_file.options.target_abi,
46114626
.self_exe_path = comp.self_exe_path,
46124627
.c_source_files = c_source_files,
46134628
.verbose_cc = comp.verbose_cc,

src/codegen/llvm.zig

Lines changed: 1 addition & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -244,18 +244,7 @@ pub const Object = struct {
244244
// TODO handle float ABI better- it should depend on the ABI portion of std.Target
245245
const float_abi: llvm.ABIType = .Default;
246246

247-
// TODO a way to override this as part of std.Target ABI?
248-
const abi_name: ?[*:0]const u8 = switch (options.target.cpu.arch) {
249-
.riscv32 => switch (options.target.os.tag) {
250-
.linux => "ilp32d",
251-
else => "ilp32",
252-
},
253-
.riscv64 => switch (options.target.os.tag) {
254-
.linux => "lp64d",
255-
else => "lp64",
256-
},
257-
else => null,
258-
};
247+
const abi_name: ?[*:0]const u8 = if (options.target_abi) |t| t.string().ptr else null;
259248

260249
const target_machine = llvm.TargetMachine.create(
261250
target,

src/glibc.zig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -960,6 +960,7 @@ fn buildSharedLib(
960960
.strip = comp.compilerRtStrip(),
961961
.is_native_os = false,
962962
.is_native_abi = false,
963+
.target_abi = comp.bin_file.options.target_abi,
963964
.self_exe_path = comp.self_exe_path,
964965
.verbose_cc = comp.verbose_cc,
965966
.verbose_link = comp.bin_file.options.verbose_link,

src/libcxx.zig

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,7 @@ pub fn buildLibCXX(comp: *Compilation) !void {
200200
.strip = comp.compilerRtStrip(),
201201
.is_native_os = comp.bin_file.options.is_native_os,
202202
.is_native_abi = comp.bin_file.options.is_native_abi,
203+
.target_abi = comp.bin_file.options.target_abi,
203204
.self_exe_path = comp.self_exe_path,
204205
.c_source_files = c_source_files.items,
205206
.verbose_cc = comp.verbose_cc,
@@ -333,6 +334,7 @@ pub fn buildLibCXXABI(comp: *Compilation) !void {
333334
.strip = comp.compilerRtStrip(),
334335
.is_native_os = comp.bin_file.options.is_native_os,
335336
.is_native_abi = comp.bin_file.options.is_native_abi,
337+
.target_abi = comp.bin_file.options.target_abi,
336338
.self_exe_path = comp.self_exe_path,
337339
.c_source_files = c_source_files.items,
338340
.verbose_cc = comp.verbose_cc,

src/libtsan.zig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,7 @@ pub fn buildTsan(comp: *Compilation) !void {
218218
.strip = comp.compilerRtStrip(),
219219
.is_native_os = comp.bin_file.options.is_native_os,
220220
.is_native_abi = comp.bin_file.options.is_native_abi,
221+
.target_abi = comp.bin_file.options.target_abi,
221222
.self_exe_path = comp.self_exe_path,
222223
.c_source_files = c_source_files.items,
223224
.verbose_cc = comp.verbose_cc,

src/libunwind.zig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,7 @@ pub fn buildStaticLib(comp: *Compilation) !void {
124124
.strip = comp.compilerRtStrip(),
125125
.is_native_os = comp.bin_file.options.is_native_os,
126126
.is_native_abi = comp.bin_file.options.is_native_abi,
127+
.target_abi = comp.bin_file.options.target_abi,
127128
.self_exe_path = comp.self_exe_path,
128129
.c_source_files = &c_source_files,
129130
.verbose_cc = comp.verbose_cc,

src/link.zig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,7 @@ pub const Options = struct {
111111
version_script: ?[]const u8,
112112
soname: ?[]const u8,
113113
llvm_cpu_features: ?[*:0]const u8,
114+
target_abi: ?std.Target.TargetAbi,
114115
/// Extra args passed directly to LLD. Ignored when not linking with LLD.
115116
extra_lld_args: []const []const u8,
116117

src/main.zig

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -318,6 +318,7 @@ const usage_build_generic =
318318
\\Compile Options:
319319
\\ -target [name] <arch><sub>-<os>-<abi> see the targets command
320320
\\ -mcpu [cpu] Specify target CPU and feature set
321+
\\ -mabi [target-abi] Specify processor specific target-abi
321322
\\ -mcmodel=[default|tiny| Limit range of code and data virtual addresses
322323
\\ small|kernel|
323324
\\ medium|large]
@@ -626,6 +627,7 @@ fn buildOutputType(
626627
var sysroot: ?[]const u8 = null;
627628
var libc_paths_file: ?[]const u8 = try optionalStringEnvVar(arena, "ZIG_LIBC");
628629
var machine_code_model: std.builtin.CodeModel = .default;
630+
var target_abi_str: ?[]const u8 = null;
629631
var runtime_args_start: ?usize = null;
630632
var test_filter: ?[]const u8 = null;
631633
var test_name_prefix: ?[]const u8 = null;
@@ -888,6 +890,12 @@ fn buildOutputType(
888890
target_mcpu = arg["-mcpu=".len..];
889891
} else if (mem.startsWith(u8, arg, "-mcmodel=")) {
890892
machine_code_model = parseCodeModel(arg["-mcmodel=".len..]);
893+
} else if (mem.eql(u8, arg, "-mabi")) {
894+
if (i + 1 >= args.len) fatal("expected parameter after {s}", .{arg});
895+
i += 1;
896+
target_abi_str = args[i];
897+
} else if (mem.startsWith(u8, arg, "-mabi=")) {
898+
target_abi_str = arg["-mabi=".len..];
891899
} else if (mem.startsWith(u8, arg, "-O")) {
892900
optimize_mode_string = arg["-O".len..];
893901
} else if (mem.eql(u8, arg, "--dynamic-linker")) {
@@ -1682,6 +1690,12 @@ fn buildOutputType(
16821690

16831691
const target_info = try detectNativeTargetInfo(gpa, cross_target);
16841692

1693+
const target_abi = if (target_abi_str) |s| std.Target.TargetAbi.parse(target_info.target.cpu, s) catch |err| switch (err) {
1694+
error.InvalidAbi => fatal("invalid target-abi value '{s}'", .{target_abi_str}),
1695+
error.ArchAbiMismatch => fatal("target-abi {s} is not valid for arch {s}", .{ target_abi_str, target_info.target.cpu.arch }),
1696+
error.FeatureAbiMismatch => fatal("target-abi {s} is not compatible with CPU features", .{target_abi_str}),
1697+
} else std.Target.TargetAbi.default(target_info.target.cpu.arch, target_info.target.cpu.features);
1698+
16851699
if (target_info.target.os.tag != .freestanding) {
16861700
if (ensure_libc_on_non_freestanding)
16871701
link_libc = true;
@@ -2173,6 +2187,7 @@ fn buildOutputType(
21732187
.verbose_cimport = verbose_cimport,
21742188
.verbose_llvm_cpu_features = verbose_llvm_cpu_features,
21752189
.machine_code_model = machine_code_model,
2190+
.target_abi = target_abi,
21762191
.color = color,
21772192
.time_report = time_report,
21782193
.stack_report = stack_report,
@@ -3095,6 +3110,7 @@ pub fn cmdBuild(gpa: *Allocator, arena: *Allocator, args: []const []const u8) !v
30953110
.target = target_info.target,
30963111
.is_native_os = cross_target.isNativeOs(),
30973112
.is_native_abi = cross_target.isNativeAbi(),
3113+
.target_abi = std.Target.TargetAbi.default(target_info.target.cpu.arch, target_info.target.cpu.features),
30983114
.dynamic_linker = target_info.dynamic_linker.get(),
30993115
.output_mode = .Exe,
31003116
.main_pkg = &main_pkg,

0 commit comments

Comments
 (0)