authorgravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2022-10-22 13:05:28+03:00
committergravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2022-10-22 14:52:26+03:00
log5e0b4836a1f48181b0d6df2b272add5aa79654c3
tree7ee97e61af253c029d90cd35b26cd03ef0747522
parent8fa91939a880ac5394aaac457238251d2c937059

stage2: implement RISCV C ABI


6 files changed, 138 insertions(+), 43 deletions(-)

src/arch/aarch64/abi.zig+2-2
......@@ -10,13 +10,13 @@ pub const Class = union(enum) {
1010 byval,
1111 integer,
1212 double_integer,
13 none,
1413 float_array: u8,
1514};
1615
1716/// For `float_array` the second element will be the amount of floats.
1817pub fn classifyType(ty: Type, target: std.Target) Class {
19 if (!ty.hasRuntimeBitsIgnoreComptime()) return .none;
18 std.debug.assert(ty.hasRuntimeBitsIgnoreComptime());
19
2020 var maybe_float_bits: ?u16 = null;
2121 switch (ty.zigTypeTag()) {
2222 .Struct => {
src/arch/arm/abi.zig+1-2
......@@ -7,7 +7,6 @@ const Type = @import("../../type.zig").Type;
77pub const Class = union(enum) {
88 memory,
99 byval,
10 none,
1110 i32_array: u8,
1211 i64_array: u8,
1312
......@@ -24,7 +23,7 @@ pub const Class = union(enum) {
2423pub const Context = enum { ret, arg };
2524
2625pub fn classifyType(ty: Type, target: std.Target, ctx: Context) Class {
27 if (!ty.hasRuntimeBitsIgnoreComptime()) return .none;
26 std.debug.assert(ty.hasRuntimeBitsIgnoreComptime());
2827
2928 var maybe_float_bits: ?u16 = null;
3029 const max_byval_size = 512;
src/arch/riscv64/abi.zig+69
......@@ -2,6 +2,75 @@ const std = @import("std");
22const bits = @import("bits.zig");
33const Register = bits.Register;
44const RegisterManagerFn = @import("../../register_manager.zig").RegisterManager;
5const Type = @import("../../type.zig").Type;
6
7pub const Class = enum { memory, byval, integer, double_integer };
8
9pub fn classifyType(ty: Type, target: std.Target) Class {
10 std.debug.assert(ty.hasRuntimeBitsIgnoreComptime());
11
12 const max_byval_size = target.cpu.arch.ptrBitWidth() * 2;
13 switch (ty.zigTypeTag()) {
14 .Struct => {
15 const bit_size = ty.bitSize(target);
16 if (ty.containerLayout() == .Packed) {
17 if (bit_size > max_byval_size) return .memory;
18 return .byval;
19 }
20 // TODO this doesn't exactly match what clang produces but its better than nothing
21 if (bit_size > max_byval_size) return .memory;
22 if (bit_size > max_byval_size / 2) return .double_integer;
23 return .integer;
24 },
25 .Union => {
26 const bit_size = ty.bitSize(target);
27 if (ty.containerLayout() == .Packed) {
28 if (bit_size > max_byval_size) return .memory;
29 return .byval;
30 }
31 // TODO this doesn't exactly match what clang produces but its better than nothing
32 if (bit_size > max_byval_size) return .memory;
33 if (bit_size > max_byval_size / 2) return .double_integer;
34 return .integer;
35 },
36 .Bool => return .integer,
37 .Float => return .byval,
38 .Int, .Enum, .ErrorSet => {
39 const bit_size = ty.bitSize(target);
40 if (bit_size > max_byval_size) return .memory;
41 return .byval;
42 },
43 .Vector => {
44 const bit_size = ty.bitSize(target);
45 if (bit_size > max_byval_size) return .memory;
46 return .integer;
47 },
48 .Optional => {
49 std.debug.assert(ty.isPtrLikeOptional());
50 return .byval;
51 },
52 .Pointer => {
53 std.debug.assert(!ty.isSlice());
54 return .byval;
55 },
56 .ErrorUnion,
57 .Frame,
58 .AnyFrame,
59 .NoReturn,
60 .Void,
61 .Type,
62 .ComptimeFloat,
63 .ComptimeInt,
64 .Undefined,
65 .Null,
66 .BoundFn,
67 .Fn,
68 .Opaque,
69 .EnumLiteral,
70 .Array,
71 => unreachable,
72 }
73}
574
675pub const callee_preserved_regs = [_]Register{
776 .s0, .s1, .s2, .s3, .s4, .s5, .s6, .s7, .s8, .s9, .s10, .s11,
src/codegen/llvm.zig+45-15
......@@ -25,6 +25,7 @@ const x86_64_abi = @import("../arch/x86_64/abi.zig");
2525const wasm_c_abi = @import("../arch/wasm/abi.zig");
2626const aarch64_c_abi = @import("../arch/aarch64/abi.zig");
2727const arm_c_abi = @import("../arch/arm/abi.zig");
28const riscv_c_abi = @import("../arch/riscv64/abi.zig");
2829
2930const Error = error{ OutOfMemory, CodegenFail };
3031
......@@ -10117,8 +10118,9 @@ fn firstParamSRet(fn_info: Type.Payload.Function.Data, target: std.Target) bool
1011710118 .arm, .armeb => switch (arm_c_abi.classifyType(fn_info.return_type, target, .ret)) {
1011810119 .memory, .i64_array => return true,
1011910120 .i32_array => |size| return size != 1,
10120 .none, .byval => return false,
10121 .byval => return false,
1012110122 },
10123 .riscv32, .riscv64 => return riscv_c_abi.classifyType(fn_info.return_type, target) == .memory,
1012210124 else => return false, // TODO investigate C ABI for other architectures
1012310125 },
1012410126 else => return false,
......@@ -10230,7 +10232,7 @@ fn lowerFnRetTy(dg: *DeclGen, fn_info: Type.Payload.Function.Data) !*llvm.Type {
1023010232 },
1023110233 .aarch64, .aarch64_be => {
1023210234 switch (aarch64_c_abi.classifyType(fn_info.return_type, target)) {
10233 .memory, .none => return dg.context.voidType(),
10235 .memory => return dg.context.voidType(),
1023410236 .float_array => return dg.lowerType(fn_info.return_type),
1023510237 .byval => return dg.lowerType(fn_info.return_type),
1023610238 .integer => {
......@@ -10249,7 +10251,23 @@ fn lowerFnRetTy(dg: *DeclGen, fn_info: Type.Payload.Function.Data) !*llvm.Type {
1024910251 return dg.context.voidType();
1025010252 },
1025110253 .byval => return dg.lowerType(fn_info.return_type),
10252 .none => unreachable,
10254 }
10255 },
10256 .riscv32, .riscv64 => {
10257 switch (riscv_c_abi.classifyType(fn_info.return_type, target)) {
10258 .memory => return dg.context.voidType(),
10259 .integer => {
10260 const bit_size = fn_info.return_type.bitSize(target);
10261 return dg.context.intType(@intCast(c_uint, bit_size));
10262 },
10263 .double_integer => {
10264 var llvm_types_buffer: [2]*llvm.Type = .{
10265 dg.context.intType(64),
10266 dg.context.intType(64),
10267 };
10268 return dg.context.structType(&llvm_types_buffer, 2, .False);
10269 },
10270 .byval => return dg.lowerType(fn_info.return_type),
1025310271 }
1025410272 },
1025510273 // TODO investigate C ABI for other architectures
......@@ -10328,15 +10346,6 @@ const ParamTypeIterator = struct {
1032810346 .C => {
1032910347 const is_scalar = isScalar(ty);
1033010348 switch (it.target.cpu.arch) {
10331 .riscv32, .riscv64 => {
10332 it.zig_index += 1;
10333 it.llvm_index += 1;
10334 if (ty.tag() == .f16) {
10335 return .as_u16;
10336 } else {
10337 return .byval;
10338 }
10339 },
1034010349 .mips, .mipsel => {
1034110350 it.zig_index += 1;
1034210351 it.llvm_index += 1;
......@@ -10451,7 +10460,6 @@ const ParamTypeIterator = struct {
1045110460 it.zig_index += 1;
1045210461 it.llvm_index += 1;
1045310462 switch (aarch64_c_abi.classifyType(ty, it.target)) {
10454 .none => unreachable,
1045510463 .memory => return .byref,
1045610464 .float_array => |len| return Lowering{ .float_array = len },
1045710465 .byval => return .byval,
......@@ -10467,7 +10475,6 @@ const ParamTypeIterator = struct {
1046710475 it.zig_index += 1;
1046810476 it.llvm_index += 1;
1046910477 switch (arm_c_abi.classifyType(ty, it.target, .arg)) {
10470 .none => unreachable,
1047110478 .memory => {
1047210479 it.byval_attr = true;
1047310480 return .byref;
......@@ -10477,6 +10484,21 @@ const ParamTypeIterator = struct {
1047710484 .i64_array => |size| return Lowering{ .i64_array = size },
1047810485 }
1047910486 },
10487 .riscv32, .riscv64 => {
10488 it.zig_index += 1;
10489 it.llvm_index += 1;
10490 if (ty.tag() == .f16) {
10491 return .as_u16;
10492 }
10493 switch (riscv_c_abi.classifyType(ty, it.target)) {
10494 .memory => {
10495 return .byref;
10496 },
10497 .byval => return .byval,
10498 .integer => return .abi_sized_int,
10499 .double_integer => return Lowering{ .i64_array = 2 },
10500 }
10501 },
1048010502 // TODO investigate C ABI for other architectures
1048110503 else => {
1048210504 it.zig_index += 1;
......@@ -10523,8 +10545,16 @@ fn ccAbiPromoteInt(
1052310545 };
1052410546 if (int_info.bits <= 16) return int_info.signedness;
1052510547 switch (target.cpu.arch) {
10548 .riscv64 => {
10549 if (int_info.bits == 32) {
10550 // LLVM always signextends 32 bit ints, unsure if bug.
10551 return .signed;
10552 }
10553 if (int_info.bits < 64) {
10554 return int_info.signedness;
10555 }
10556 },
1052610557 .sparc64,
10527 .riscv64,
1052810558 .powerpc64,
1052910559 .powerpc64le,
1053010560 => {
test/c_abi/cfuncs.c+20-10
......@@ -16,6 +16,10 @@ static void assert_or_panic(bool ok) {
1616# define ZIG_PPC32
1717#endif
1818
19#if defined __riscv && defined _ILP32
20# define ZIG_RISCV32
21#endif
22
1923#ifdef __i386__
2024# define ZIG_NO_I128
2125#endif
......@@ -32,6 +36,10 @@ static void assert_or_panic(bool ok) {
3236# define ZIG_NO_I128
3337#endif
3438
39#ifdef ZIG_RISCV32
40# define ZIG_NO_I128
41#endif
42
3543#ifdef __i386__
3644# define ZIG_NO_COMPLEX
3745#endif
......@@ -48,6 +56,10 @@ static void assert_or_panic(bool ok) {
4856# define ZIG_NO_COMPLEX
4957#endif
5058
59#ifdef __riscv
60# define ZIG_NO_COMPLEX
61#endif
62
5163#ifndef ZIG_NO_I128
5264struct i128 {
5365 __int128 value;
......@@ -265,7 +277,7 @@ void run_c_tests(void) {
265277 }
266278#endif
267279
268#if !defined __mips__ && !defined __riscv && !defined ZIG_PPC32
280#if !defined __mips__ && !defined ZIG_PPC32
269281 {
270282 struct BigStruct s = {1, 2, 3, 4, 5};
271283 zig_big_struct(s);
......@@ -273,7 +285,7 @@ void run_c_tests(void) {
273285#endif
274286
275287#if !defined __i386__ && !defined __arm__ && !defined __mips__ && \
276 !defined __riscv && !defined ZIG_PPC32 && !defined _ARCH_PPC64
288 !defined ZIG_PPC32 && !defined _ARCH_PPC64
277289 {
278290 struct SmallStructInts s = {1, 2, 3, 4};
279291 zig_small_struct_ints(s);
......@@ -299,14 +311,14 @@ void run_c_tests(void) {
299311 }
300312
301313#if !defined __i386__ && !defined __arm__ && !defined __mips__ && \
302 !defined __riscv && !defined ZIG_PPC32 && !defined _ARCH_PPC64
314 !defined ZIG_PPC32 && !defined _ARCH_PPC64
303315 {
304316 struct SplitStructInts s = {1234, 100, 1337};
305317 zig_split_struct_ints(s);
306318 }
307319#endif
308320
309#if !defined __arm__ && !defined __riscv && !defined ZIG_PPC32 && !defined _ARCH_PPC64
321#if !defined __arm__ && !defined ZIG_PPC32 && !defined _ARCH_PPC64
310322 {
311323 struct MedStructMixed s = {1234, 100.0f, 1337.0f};
312324 zig_med_struct_mixed(s);
......@@ -314,14 +326,14 @@ void run_c_tests(void) {
314326#endif
315327
316328#if !defined __i386__ && !defined __arm__ && !defined __mips__ && \
317 !defined __riscv && !defined ZIG_PPC32 && !defined _ARCH_PPC64
329 !defined ZIG_PPC32 && !defined _ARCH_PPC64
318330 {
319331 struct SplitStructMixed s = {1234, 100, 1337.0f};
320332 zig_split_struct_mixed(s);
321333 }
322334#endif
323335
324#if !defined __mips__ && !defined __riscv && !defined ZIG_PPC32
336#if !defined __mips__ && !defined ZIG_PPC32
325337 {
326338 struct BigStruct s = {30, 31, 32, 33, 34};
327339 struct BigStruct res = zig_big_struct_both(s);
......@@ -333,7 +345,7 @@ void run_c_tests(void) {
333345 }
334346#endif
335347
336#if !defined __riscv && !defined ZIG_PPC32 && !defined _ARCH_PPC64
348#if !defined ZIG_PPC32 && !defined _ARCH_PPC64
337349 {
338350 struct Rect r1 = {1, 21, 16, 4};
339351 struct Rect r2 = {178, 189, 21, 15};
......@@ -341,7 +353,7 @@ void run_c_tests(void) {
341353 }
342354#endif
343355
344#if !defined __mips__ && !defined __riscv && !defined ZIG_PPC32
356#if !defined __mips__ && !defined ZIG_PPC32
345357 {
346358 struct FloatRect r1 = {1, 21, 16, 4};
347359 struct FloatRect r2 = {178, 189, 21, 15};
......@@ -354,9 +366,7 @@ void run_c_tests(void) {
354366
355367 assert_or_panic(zig_ret_u8() == 0xff);
356368 assert_or_panic(zig_ret_u16() == 0xffff);
357#ifndef __riscv
358369 assert_or_panic(zig_ret_u32() == 0xffffffff);
359#endif
360370 assert_or_panic(zig_ret_u64() == 0xffffffffffffffff);
361371
362372 assert_or_panic(zig_ret_i8() == -1);
test/c_abi/main.zig+1-14
......@@ -171,7 +171,7 @@ extern fn c_cmultf(a: ComplexFloat, b: ComplexFloat) ComplexFloat;
171171extern fn c_cmultd(a: ComplexDouble, b: ComplexDouble) ComplexDouble;
172172
173173const complex_abi_compatible = builtin.cpu.arch != .i386 and !builtin.cpu.arch.isMIPS() and
174 !builtin.cpu.arch.isARM() and !builtin.cpu.arch.isPPC();
174 !builtin.cpu.arch.isARM() and !builtin.cpu.arch.isPPC() and !builtin.cpu.arch.isRISCV();
175175
176176test "C ABI complex float" {
177177 if (!complex_abi_compatible) return error.SkipZigTest;
......@@ -265,7 +265,6 @@ extern fn c_big_struct(BigStruct) void;
265265
266266test "C ABI big struct" {
267267 if (comptime builtin.cpu.arch.isMIPS()) return error.SkipZigTest;
268 if (comptime builtin.cpu.arch.isRISCV()) return error.SkipZigTest;
269268 if (comptime builtin.cpu.arch.isPPC()) return error.SkipZigTest;
270269
271270 var s = BigStruct{
......@@ -292,7 +291,6 @@ const BigUnion = extern union {
292291extern fn c_big_union(BigUnion) void;
293292
294293test "C ABI big union" {
295 if (comptime builtin.cpu.arch.isRISCV()) return error.SkipZigTest;
296294 if (comptime builtin.cpu.arch.isPPC()) return error.SkipZigTest;
297295
298296 var x = BigUnion{
......@@ -327,7 +325,6 @@ extern fn c_ret_med_struct_mixed() MedStructMixed;
327325test "C ABI medium struct of ints and floats" {
328326 if (builtin.cpu.arch == .i386) return error.SkipZigTest;
329327 if (comptime builtin.cpu.arch.isMIPS()) return error.SkipZigTest;
330 if (comptime builtin.cpu.arch.isRISCV()) return error.SkipZigTest;
331328 if (comptime builtin.cpu.arch.isPPC()) return error.SkipZigTest;
332329 if (comptime builtin.cpu.arch.isPPC64()) return error.SkipZigTest;
333330
......@@ -361,7 +358,6 @@ extern fn c_ret_small_struct_ints() SmallStructInts;
361358test "C ABI small struct of ints" {
362359 if (builtin.cpu.arch == .i386) return error.SkipZigTest;
363360 if (comptime builtin.cpu.arch.isMIPS()) return error.SkipZigTest;
364 if (comptime builtin.cpu.arch.isRISCV()) return error.SkipZigTest;
365361 if (comptime builtin.cpu.arch.isPPC()) return error.SkipZigTest;
366362 if (comptime builtin.cpu.arch.isPPC64()) return error.SkipZigTest;
367363
......@@ -444,7 +440,6 @@ extern fn c_split_struct_ints(SplitStructInt) void;
444440test "C ABI split struct of ints" {
445441 if (builtin.cpu.arch == .i386) return error.SkipZigTest;
446442 if (comptime builtin.cpu.arch.isMIPS()) return error.SkipZigTest;
447 if (comptime builtin.cpu.arch.isRISCV()) return error.SkipZigTest;
448443 if (comptime builtin.cpu.arch.isPPC()) return error.SkipZigTest;
449444 if (comptime builtin.cpu.arch.isPPC64()) return error.SkipZigTest;
450445
......@@ -473,7 +468,6 @@ extern fn c_ret_split_struct_mixed() SplitStructMixed;
473468test "C ABI split struct of ints and floats" {
474469 if (builtin.cpu.arch == .i386) return error.SkipZigTest;
475470 if (comptime builtin.cpu.arch.isMIPS()) return error.SkipZigTest;
476 if (comptime builtin.cpu.arch.isRISCV()) return error.SkipZigTest;
477471 if (comptime builtin.cpu.arch.isPPC()) return error.SkipZigTest;
478472 if (comptime builtin.cpu.arch.isPPC64()) return error.SkipZigTest;
479473
......@@ -502,7 +496,6 @@ extern fn c_multiple_struct_floats(FloatRect, FloatRect) void;
502496
503497test "C ABI sret and byval together" {
504498 if (comptime builtin.cpu.arch.isMIPS()) return error.SkipZigTest;
505 if (comptime builtin.cpu.arch.isRISCV()) return error.SkipZigTest;
506499 if (comptime builtin.cpu.arch.isPPC()) return error.SkipZigTest;
507500
508501 var s = BigStruct{
......@@ -555,7 +548,6 @@ extern fn c_big_struct_floats(Vector5) void;
555548
556549test "C ABI structs of floats as parameter" {
557550 if (comptime builtin.cpu.arch.isMIPS()) return error.SkipZigTest;
558 if (comptime builtin.cpu.arch.isRISCV()) return error.SkipZigTest;
559551 if (comptime builtin.cpu.arch.isPPC()) return error.SkipZigTest;
560552 if (comptime builtin.cpu.arch.isPPC64()) return error.SkipZigTest;
561553
......@@ -596,7 +588,6 @@ export fn zig_multiple_struct_ints(x: Rect, y: Rect) void {
596588}
597589
598590test "C ABI structs of ints as multiple parameters" {
599 if (comptime builtin.cpu.arch.isRISCV()) return error.SkipZigTest;
600591 if (comptime builtin.cpu.arch.isPPC()) return error.SkipZigTest;
601592 if (comptime builtin.cpu.arch.isPPC64()) return error.SkipZigTest;
602593
......@@ -635,7 +626,6 @@ export fn zig_multiple_struct_floats(x: FloatRect, y: FloatRect) void {
635626
636627test "C ABI structs of floats as multiple parameters" {
637628 if (comptime builtin.cpu.arch.isMIPS()) return error.SkipZigTest;
638 if (comptime builtin.cpu.arch.isRISCV()) return error.SkipZigTest;
639629 if (comptime builtin.cpu.arch.isPPC()) return error.SkipZigTest;
640630
641631 var r1 = FloatRect{
......@@ -741,7 +731,6 @@ extern fn c_ret_struct_with_array() StructWithArray;
741731test "Struct with array as padding." {
742732 if (builtin.cpu.arch == .i386) return error.SkipZigTest;
743733 if (comptime builtin.cpu.arch.isMIPS()) return error.SkipZigTest;
744 if (comptime builtin.cpu.arch.isRISCV()) return error.SkipZigTest;
745734 if (comptime builtin.cpu.arch.isPPC()) return error.SkipZigTest;
746735 if (comptime builtin.cpu.arch.isPPC64()) return error.SkipZigTest;
747736
......@@ -768,7 +757,6 @@ extern fn c_ret_float_array_struct() FloatArrayStruct;
768757
769758test "Float array like struct" {
770759 if (comptime builtin.cpu.arch.isMIPS()) return error.SkipZigTest;
771 if (comptime builtin.cpu.arch.isRISCV()) return error.SkipZigTest;
772760 if (comptime builtin.cpu.arch.isPPC()) return error.SkipZigTest;
773761
774762 c_float_array_struct(.{
......@@ -796,7 +784,6 @@ extern fn c_ret_small_vec() SmallVec;
796784
797785test "small simd vector" {
798786 if (builtin.cpu.arch == .i386) return error.SkipZigTest;
799 if (comptime builtin.cpu.arch.isRISCV()) return error.SkipZigTest;
800787 if (comptime builtin.cpu.arch.isPPC64()) return error.SkipZigTest;
801788
802789 c_small_vec(.{ 1, 2 });