authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-03-21 18:21:31-04:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2022-03-21 18:21:31-04:00
log916a65cb7bc96e5faa9337ab541d1ae230b48259
tree6d33498f2e6e83fea34317df31cb15331beb2b32
parent18a43b61f92ae937e39fc5dbc3de581e26709151
parent731dda18dde439631ed93afb0c0a199dc8842726
signature Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #11224 from koachan/sparc64-codegen

stage2 sparcv9: Add instruction encoder and placeholder codegen impl

7 files changed, 1175 insertions(+), 1 deletions(-)

CMakeLists.txt+5
......@@ -614,6 +614,11 @@ set(ZIG_STAGE2_SOURCES
614614 "${CMAKE_SOURCE_DIR}/src/arch/riscv64/Mir.zig"
615615 "${CMAKE_SOURCE_DIR}/src/arch/riscv64/bits.zig"
616616 "${CMAKE_SOURCE_DIR}/src/arch/riscv64/abi.zig"
617 "${CMAKE_SOURCE_DIR}/src/arch/sparcv9/CodeGen.zig"
618 "${CMAKE_SOURCE_DIR}/src/arch/sparcv9/Emit.zig"
619 "${CMAKE_SOURCE_DIR}/src/arch/sparcv9/Mir.zig"
620 "${CMAKE_SOURCE_DIR}/src/arch/sparcv9/bits.zig"
621 "${CMAKE_SOURCE_DIR}/src/arch/sparcv9/abi.zig"
617622 "${CMAKE_SOURCE_DIR}/src/arch/wasm/CodeGen.zig"
618623 "${CMAKE_SOURCE_DIR}/src/arch/wasm/Emit.zig"
619624 "${CMAKE_SOURCE_DIR}/src/arch/wasm/Mir.zig"
src/arch/sparcv9/CodeGen.zig created+39
......@@ -0,0 +1,39 @@
1//! SPARCv9 codegen.
2//! This lowers AIR into MIR.
3const std = @import("std");
4const builtin = @import("builtin");
5const link = @import("../../link.zig");
6const Module = @import("../../Module.zig");
7const Air = @import("../../Air.zig");
8const Mir = @import("Mir.zig");
9const Emit = @import("Emit.zig");
10const Liveness = @import("../../Liveness.zig");
11
12const GenerateSymbolError = @import("../../codegen.zig").GenerateSymbolError;
13const FnResult = @import("../../codegen.zig").FnResult;
14const DebugInfoOutput = @import("../../codegen.zig").DebugInfoOutput;
15
16const bits = @import("bits.zig");
17const abi = @import("abi.zig");
18
19const Self = @This();
20
21pub fn generate(
22 bin_file: *link.File,
23 src_loc: Module.SrcLoc,
24 module_fn: *Module.Fn,
25 air: Air,
26 liveness: Liveness,
27 code: *std.ArrayList(u8),
28 debug_output: DebugInfoOutput,
29) GenerateSymbolError!FnResult {
30 _ = bin_file;
31 _ = src_loc;
32 _ = module_fn;
33 _ = air;
34 _ = liveness;
35 _ = code;
36 _ = debug_output;
37
38 @panic("TODO implement SPARCv9 codegen");
39}
src/arch/sparcv9/Emit.zig created+6
......@@ -0,0 +1,6 @@
1//! This file contains the functionality for lowering SPARCv9 MIR into
2//! machine code
3
4const Emit = @This();
5const Mir = @import("Mir.zig");
6const bits = @import("bits.zig");
src/arch/sparcv9/Mir.zig created+11
......@@ -0,0 +1,11 @@
1//! Machine Intermediate Representation.
2//! This data is produced by SPARCv9 Codegen or SPARCv9 assembly parsing
3//! These instructions have a 1:1 correspondence with machine code instructions
4//! for the target. MIR can be lowered to source-annotated textual assembly code
5//! instructions, or it can be lowered to machine code.
6//! The main purpose of MIR is to postpone the assignment of offsets until Isel,
7//! so that, for example, the smaller encodings of jump instructions can be used.
8
9const Mir = @This();
10const bits = @import("bits.zig");
11const Register = bits.Register;
src/arch/sparcv9/abi.zig created+12
......@@ -0,0 +1,12 @@
1const bits = @import("bits.zig");
2const Register = bits.Register;
3
4// Register windowing mechanism will take care of preserving registers
5// so no need to do it manually
6pub const callee_preserved_regs = [_]Register{};
7
8pub const c_abi_int_param_regs_caller_view = [_]Register{ .o0, .o1, .o2, .o3, .o4, .o5 };
9pub const c_abi_int_param_regs_callee_view = [_]Register{ .@"i0", .@"i1", .@"i2", .@"i3", .@"i4", .@"i5" };
10
11pub const c_abi_int_return_regs_caller_view = [_]Register{ .o0, .o1, .o2, .o3, .o4, .o5 };
12pub const c_abi_int_return_regs_callee_view = [_]Register{ .@"i0", .@"i1", .@"i2", .@"i3", .@"i4", .@"i5" };
src/arch/sparcv9/bits.zig created+1101
......@@ -0,0 +1,1101 @@
1const std = @import("std");
2const DW = std.dwarf;
3const assert = std.debug.assert;
4const testing = std.testing;
5
6/// General purpose registers in the SPARCv9 instruction set
7pub const Register = enum(u6) {
8 // zig fmt: off
9 g0, g1, g2, g3, g4, g5, g6, g7,
10 o0, o1, o2, o3, o4, o5, o6, o7,
11 l0, l1, l2, l3, l4, l5, l6, l7,
12 @"i0", @"i1", @"i2", @"i3", @"i4", @"i5", @"i6", @"i7",
13
14 sp = 46, // stack pointer (o6)
15 fp = 62, // frame pointer (i6)
16 // zig fmt: on
17
18 pub fn id(self: Register) u5 {
19 return @truncate(u5, @enumToInt(self));
20 }
21
22 pub fn enc(self: Register) u5 {
23 // For integer registers, enc() == id().
24 return self.id();
25 }
26
27 pub fn dwarfLocOp(reg: Register) u8 {
28 return @as(u8, reg.id()) + DW.OP.reg0;
29 }
30};
31
32test "Register.id" {
33 // SP
34 try testing.expectEqual(@as(u5, 14), Register.o6.id());
35 try testing.expectEqual(Register.o6.id(), Register.sp.id());
36
37 // FP
38 try testing.expectEqual(@as(u5, 30), Register.@"i6".id());
39 try testing.expectEqual(Register.@"i6".id(), Register.fp.id());
40
41 // x0
42 try testing.expectEqual(@as(u5, 0), Register.g0.id());
43 try testing.expectEqual(@as(u5, 8), Register.o0.id());
44 try testing.expectEqual(@as(u5, 16), Register.l0.id());
45 try testing.expectEqual(@as(u5, 24), Register.@"i0".id());
46}
47
48test "Register.enc" {
49 // x0
50 try testing.expectEqual(@as(u5, 0), Register.g0.enc());
51 try testing.expectEqual(@as(u5, 8), Register.o0.enc());
52 try testing.expectEqual(@as(u5, 16), Register.l0.enc());
53 try testing.expectEqual(@as(u5, 24), Register.@"i0".enc());
54
55 // For integer registers, enc() == id().
56 try testing.expectEqual(Register.g0.enc(), Register.g0.id());
57 try testing.expectEqual(Register.o0.enc(), Register.o0.id());
58 try testing.expectEqual(Register.l0.enc(), Register.l0.id());
59 try testing.expectEqual(Register.@"i0".enc(), Register.@"i0".id());
60}
61
62/// Scalar floating point registers in the SPARCv9 instruction set
63pub const FloatingPointRegister = enum(u7) {
64 // SPARCv9 has 64 f32 registers, 32 f64 registers, and 16 f128 registers,
65 // which are aliased in this way:
66 //
67 // | %d0 | %d2 |
68 // %q0 | %f0 | %f1 | %f2 | %f3 |
69 // | %d4 | %d6 |
70 // %q4 | %f4 | %f5 | %f6 | %f7 |
71 // ...
72 // | %d60 | %d62 |
73 // %q60 | %f60 | %f61 | %f62 | %f63 |
74 //
75 // Though, since the instructions uses five-bit addressing, only %f0-%f31
76 // is usable with f32 instructions.
77
78 // zig fmt: off
79
80 // 32-bit registers
81 @"f0", @"f1", @"f2", @"f3", @"f4", @"f5", @"f6", @"f7",
82 @"f8", @"f9", @"f10", @"f11", @"f12", @"f13", @"f14", @"f15",
83 @"f16", @"f17", @"f18", @"f19", @"f20", @"f21", @"f22", @"f23",
84 @"f24", @"f25", @"f26", @"f27", @"f28", @"f29", @"f30", @"f31",
85
86 // 64-bit registers
87 d0, d2, d4, d6, d8, d10, d12, d14,
88 d16, d18, d20, d22, d24, d26, d28, d30,
89 d32, d34, d36, d38, d40, d42, d44, d46,
90 d48, d50, d52, d54, d56, d58, d60, d62,
91
92 // 128-bit registers
93 q0, q4, q8, q12, q16, q20, q24, q28,
94 q32, q36, q40, q44, q48, q52, q56, q60,
95 // zig fmt: on
96
97 pub fn id(self: FloatingPointRegister) u6 {
98 return switch (self.size()) {
99 32 => @truncate(u6, @enumToInt(self)),
100 64 => @truncate(u6, (@enumToInt(self) - 32) * 2),
101 128 => @truncate(u6, (@enumToInt(self) - 64) * 4),
102 else => unreachable,
103 };
104 }
105
106 pub fn enc(self: FloatingPointRegister) u5 {
107 // Floating point registers use an encoding scheme to map from the 6-bit
108 // ID to 5-bit encoded value.
109 // (See section 5.1.4.1 of SPARCv9 ISA specification)
110
111 const reg_id = self.id();
112 return @truncate(u5, reg_id | (reg_id >> 5));
113 }
114
115 /// Returns the bit-width of the register.
116 pub fn size(self: FloatingPointRegister) u8 {
117 return switch (@enumToInt(self)) {
118 0...31 => 32,
119 32...63 => 64,
120 64...79 => 128,
121 else => unreachable,
122 };
123 }
124};
125
126test "FloatingPointRegister.id" {
127 // Low region
128 try testing.expectEqual(@as(u6, 0), FloatingPointRegister.q0.id());
129 try testing.expectEqual(FloatingPointRegister.q0.id(), FloatingPointRegister.d0.id());
130 try testing.expectEqual(FloatingPointRegister.d0.id(), FloatingPointRegister.@"f0".id());
131
132 try testing.expectEqual(@as(u6, 28), FloatingPointRegister.q28.id());
133 try testing.expectEqual(FloatingPointRegister.q28.id(), FloatingPointRegister.d28.id());
134 try testing.expectEqual(FloatingPointRegister.d28.id(), FloatingPointRegister.@"f28".id());
135
136 // High region
137 try testing.expectEqual(@as(u6, 32), FloatingPointRegister.q32.id());
138 try testing.expectEqual(FloatingPointRegister.q32.id(), FloatingPointRegister.d32.id());
139
140 try testing.expectEqual(@as(u6, 60), FloatingPointRegister.q60.id());
141 try testing.expectEqual(FloatingPointRegister.q60.id(), FloatingPointRegister.d60.id());
142}
143
144test "FloatingPointRegister.enc" {
145 // f registers
146 try testing.expectEqual(@as(u5, 0), FloatingPointRegister.@"f0".enc());
147 try testing.expectEqual(@as(u5, 1), FloatingPointRegister.@"f1".enc());
148 try testing.expectEqual(@as(u5, 31), FloatingPointRegister.@"f31".enc());
149
150 // d registers
151 try testing.expectEqual(@as(u5, 0), FloatingPointRegister.d0.enc());
152 try testing.expectEqual(@as(u5, 1), FloatingPointRegister.d32.enc());
153 try testing.expectEqual(@as(u5, 31), FloatingPointRegister.d62.enc());
154
155 // q registers
156 try testing.expectEqual(@as(u5, 0), FloatingPointRegister.q0.enc());
157 try testing.expectEqual(@as(u5, 1), FloatingPointRegister.q32.enc());
158 try testing.expectEqual(@as(u5, 29), FloatingPointRegister.q60.enc());
159}
160
161/// Represents an instruction in the SPARCv9 instruction set
162pub const Instruction = union(enum) {
163 // Some of the instruction formats have several minor formats, here I
164 // name them with letters since there's no official naming scheme.
165 // TODO: need to rename the minor formats to a more descriptive name.
166
167 // Format 1 (op = 1): CALL
168 format_1: packed struct {
169 op: u2 = 0b01,
170 disp30: u30,
171 },
172
173 // Format 2 (op = 0): SETHI & Branches (Bicc, BPcc, BPr, FBfcc, FBPfcc)
174 format_2a: packed struct {
175 op: u2 = 0b00,
176 rd: u5,
177 op2: u3,
178 imm22: u22,
179 },
180 format_2b: packed struct {
181 op: u2 = 0b00,
182 a: u1,
183 cond: u4,
184 op2: u3,
185 disp22: u22,
186 },
187 format_2c: packed struct {
188 op: u2 = 0b00,
189 a: u1,
190 cond: u4,
191 op2: u3,
192 cc1: u1,
193 cc0: u1,
194 p: u1,
195 disp19: u19,
196 },
197 format_2d: packed struct {
198 op: u2 = 0b00,
199 a: u1,
200 fixed: u1 = 0b0,
201 rcond: u3,
202 op2: u3,
203 d16hi: u2,
204 p: u1,
205 rs1: u5,
206 d16lo: u14,
207 },
208
209 // Format 3 (op = 2 or 3): Arithmetic, Logical, MOVr, MEMBAR, Load, and Store
210 format_3a: packed struct {
211 op: u2,
212 rd: u5,
213 op3: u6,
214 rs1: u5,
215 i: u1 = 0b0,
216 reserved: u8 = 0b00000000,
217 rs2: u5,
218 },
219 format_3b: struct {
220 op: u2,
221 rd: u5,
222 op3: u6,
223 rs1: u5,
224 i: u1 = 0b1,
225 simm13: u13,
226 },
227 format_3c: packed struct {
228 op: u2,
229 reserved1: u5 = 0b00000,
230 op3: u6,
231 rs1: u5,
232 i: u1 = 0b0,
233 reserved2: u8 = 0b00000000,
234 rs2: u5,
235 },
236 format_3d: struct {
237 op: u2,
238 reserved: u5 = 0b00000,
239 op3: u6,
240 rs1: u5,
241 i: u1 = 0b1,
242 simm13: u13,
243 },
244 format_3e: packed struct {
245 op: u2,
246 rd: u5,
247 op3: u6,
248 rs1: u5,
249 i: u1 = 0b0,
250 rcond: u3,
251 reserved: u5 = 0b00000,
252 rs2: u5,
253 },
254 format_3f: struct {
255 op: u2,
256 rd: u5,
257 op3: u6,
258 rs1: u5,
259 i: u1 = 0b1,
260 rcond: u3,
261 simm10: u10,
262 },
263 format_3g: packed struct {
264 op: u2,
265 rd: u5,
266 op3: u6,
267 rs1: u5,
268 i: u1 = 0b1,
269 reserved: u8 = 0b00000000,
270 rs2: u5,
271 },
272 format_3h: packed struct {
273 op: u2 = 0b10,
274 fixed1: u5 = 0b00000,
275 op3: u6 = 0b101000,
276 fixed2: u5 = 0b01111,
277 i: u1 = 0b1,
278 reserved: u6 = 0b000000,
279 cmask: u3,
280 mmask: u4,
281 },
282 format_3i: packed struct {
283 op: u2,
284 rd: u5,
285 op3: u6,
286 rs1: u5,
287 i: u1 = 0b0,
288 imm_asi: u8,
289 rs2: u5,
290 },
291 format_3j: packed struct {
292 op: u2,
293 impl_dep1: u5,
294 op3: u6,
295 impl_dep2: u19,
296 },
297 format_3k: packed struct {
298 op: u2,
299 rd: u5,
300 op3: u6,
301 rs1: u5,
302 i: u1 = 0b0,
303 x: u1,
304 reserved: u7 = 0b0000000,
305 rs2: u5,
306 },
307 format_3l: packed struct {
308 op: u2,
309 rd: u5,
310 op3: u6,
311 rs1: u5,
312 i: u1 = 0b1,
313 x: u1 = 0b0,
314 reserved: u7 = 0b0000000,
315 shcnt32: u5,
316 },
317 format_3m: packed struct {
318 op: u2,
319 rd: u5,
320 op3: u6,
321 rs1: u5,
322 i: u1 = 0b1,
323 x: u1 = 0b1,
324 reserved: u6 = 0b000000,
325 shcnt64: u6,
326 },
327 format_3n: packed struct {
328 op: u2,
329 rd: u5,
330 op3: u6,
331 reserved: u5 = 0b00000,
332 opf: u9,
333 rs2: u5,
334 },
335 format_3o: packed struct {
336 op: u2,
337 fixed: u3 = 0b000,
338 cc1: u1,
339 cc0: u1,
340 op3: u6,
341 rs1: u5,
342 opf: u9,
343 rs2: u5,
344 },
345 format_3p: packed struct {
346 op: u2,
347 rd: u5,
348 op3: u6,
349 rs1: u5,
350 opf: u9,
351 rs2: u5,
352 },
353 format_3q: packed struct {
354 op: u2,
355 rd: u5,
356 op3: u6,
357 rs1: u5,
358 reserved: u14 = 0b00000000000000,
359 },
360 format_3r: packed struct {
361 op: u2,
362 fcn: u5,
363 op3: u6,
364 reserved: u19 = 0b0000000000000000000,
365 },
366 format_3s: packed struct {
367 op: u2,
368 rd: u5,
369 op3: u6,
370 reserved: u19 = 0b0000000000000000000,
371 },
372
373 //Format 4 (op = 2): MOVcc, FMOVr, FMOVcc, and Tcc
374 format_4a: packed struct {
375 op: u2 = 0b10,
376 rd: u5,
377 op3: u6,
378 rs1: u5,
379 i: u1 = 0b0,
380 cc1: u1,
381 cc0: u1,
382 reserved: u6 = 0b000000,
383 rs2: u5,
384 },
385 format_4b: struct {
386 op: u2 = 0b10,
387 rd: u5,
388 op3: u6,
389 rs1: u5,
390 i: u1 = 0b1,
391 cc1: u1,
392 cc0: u1,
393 simm11: u11,
394 },
395 format_4c: packed struct {
396 op: u2 = 0b10,
397 rd: u5,
398 op3: u6,
399 cc2: u1,
400 cond: u4,
401 i: u1 = 0b0,
402 cc1: u1,
403 cc0: u1,
404 reserved: u6 = 0b000000,
405 rs2: u5,
406 },
407 format_4d: struct {
408 op: u2 = 0b10,
409 rd: u5,
410 op3: u6,
411 cc2: u1,
412 cond: u4,
413 i: u1 = 0b1,
414 cc1: u1,
415 cc0: u1,
416 simm11: u11,
417 },
418 format_4e: packed struct {
419 op: u2 = 0b10,
420 rd: u5,
421 op3: u6,
422 rs1: u5,
423 i: u1 = 0b1,
424 cc1: u1,
425 cc0: u1,
426 reserved: u4 = 0b0000,
427 sw_trap: u7,
428 },
429 format_4f: packed struct {
430 op: u2 = 0b10,
431 rd: u5,
432 op3: u6,
433 rs1: u5,
434 fixed: u1 = 0b0,
435 rcond: u3,
436 opf_low: u5,
437 rs2: u5,
438 },
439 format_4g: packed struct {
440 op: u2 = 0b10,
441 rd: u5,
442 op3: u6,
443 fixed: u1 = 0b0,
444 cond: u4,
445 opf_cc: u3,
446 opf_low: u6,
447 rs2: u5,
448 },
449
450 pub const CCR = enum(u3) {
451 fcc0,
452 fcc1,
453 fcc2,
454 fcc3,
455 icc,
456 reserved1,
457 xcc,
458 reserved2,
459 };
460
461 pub const RCondition = enum(u3) {
462 reserved1,
463 eq_zero,
464 le_zero,
465 lt_zero,
466 reserved2,
467 ne_zero,
468 gt_zero,
469 ge_zero,
470 };
471
472 pub const ASI = enum(u8) {
473 asi_nucleus = 0x04,
474 asi_nucleus_little = 0x0c,
475 asi_as_if_user_primary = 0x10,
476 asi_as_if_user_secondary = 0x11,
477 asi_as_if_user_primary_little = 0x18,
478 asi_as_if_user_secondary_little = 0x19,
479 asi_primary = 0x80,
480 asi_secondary = 0x81,
481 asi_primary_nofault = 0x82,
482 asi_secondary_nofault = 0x83,
483 asi_primary_little = 0x88,
484 asi_secondary_little = 0x89,
485 asi_primary_nofault_little = 0x8a,
486 asi_secondary_nofault_little = 0x8b,
487 };
488
489 pub const ShiftWidth = enum(u1) {
490 shift32,
491 shift64,
492 };
493
494 pub const MemOrderingConstraint = packed struct {
495 store_store: bool = false,
496 load_store: bool = false,
497 store_load: bool = false,
498 load_load: bool = false,
499 };
500
501 pub const MemCompletionConstraint = packed struct {
502 sync: bool = false,
503 mem_issue: bool = false,
504 lookaside: bool = false,
505 };
506
507 // TODO: Need to define an enum for `cond` values
508 // This is kinda challenging since the cond values have different meanings
509 // depending on whether it's operating on integer or FP CCR.
510 pub const Condition = u4;
511
512 pub fn toU32(self: Instruction) u32 {
513 // TODO: Remove this once packed structs work.
514 return switch (self) {
515 .format_1 => |v| @bitCast(u32, v),
516 .format_2a => |v| @bitCast(u32, v),
517 .format_2b => |v| @bitCast(u32, v),
518 .format_2c => |v| @bitCast(u32, v),
519 .format_2d => |v| @bitCast(u32, v),
520 .format_3a => |v| @bitCast(u32, v),
521 .format_3b => |v| (@as(u32, v.op) << 30) | (@as(u32, v.rd) << 25) | (@as(u32, v.op3) << 19) | (@as(u32, v.rs1) << 14) | (@as(u32, v.i) << 13) | @as(u32, v.simm13),
522 .format_3c => |v| @bitCast(u32, v),
523 .format_3d => |v| (@as(u32, v.op) << 30) | (@as(u32, v.reserved) << 25) | (@as(u32, v.op3) << 19) | (@as(u32, v.rs1) << 14) | (@as(u32, v.i) << 13) | @as(u32, v.simm13),
524 .format_3e => |v| @bitCast(u32, v),
525 .format_3f => |v| (@as(u32, v.op) << 30) | (@as(u32, v.rd) << 25) | (@as(u32, v.op3) << 19) | (@as(u32, v.rs1) << 14) | (@as(u32, v.i) << 13) | (@as(u32, v.rcond) << 10) | @as(u32, v.simm10),
526 .format_3g => |v| @bitCast(u32, v),
527 .format_3h => |v| @bitCast(u32, v),
528 .format_3i => |v| @bitCast(u32, v),
529 .format_3j => |v| @bitCast(u32, v),
530 .format_3k => |v| @bitCast(u32, v),
531 .format_3l => |v| @bitCast(u32, v),
532 .format_3m => |v| @bitCast(u32, v),
533 .format_3n => |v| @bitCast(u32, v),
534 .format_3o => |v| @bitCast(u32, v),
535 .format_3p => |v| @bitCast(u32, v),
536 .format_3q => |v| @bitCast(u32, v),
537 .format_3r => |v| @bitCast(u32, v),
538 .format_3s => |v| @bitCast(u32, v),
539 .format_4a => |v| @bitCast(u32, v),
540 .format_4b => |v| (@as(u32, v.op) << 30) | (@as(u32, v.rd) << 25) | (@as(u32, v.op3) << 19) | (@as(u32, v.rs1) << 14) | (@as(u32, v.i) << 13) | (@as(u32, v.cc1) << 12) | (@as(u32, v.cc0) << 11) | @as(u32, v.simm11),
541 .format_4c => |v| @bitCast(u32, v),
542 .format_4d => |v| (@as(u32, v.op) << 30) | (@as(u32, v.rd) << 25) | (@as(u32, v.op3) << 19) | (@as(u32, v.cc2) << 18) | (@as(u32, v.cond) << 14) | (@as(u32, v.i) << 13) | (@as(u32, v.cc1) << 12) | (@as(u32, v.cc0) << 11) | @as(u32, v.simm11),
543 .format_4e => |v| @bitCast(u32, v),
544 .format_4f => |v| @bitCast(u32, v),
545 .format_4g => |v| @bitCast(u32, v),
546 };
547 }
548
549 fn format1(disp: i32) Instruction {
550 const udisp = @bitCast(u32, disp);
551
552 // In SPARC, branch target needs to be aligned to 4 bytes.
553 assert(udisp % 4 == 0);
554
555 // Discard the last two bits since those are implicitly zero.
556 const udisp_truncated = @truncate(u30, udisp >> 2);
557 return Instruction{
558 .format_1 = .{
559 .disp30 = udisp_truncated,
560 },
561 };
562 }
563
564 fn format2a(op2: u3, rd: Register, imm: u22) Instruction {
565 return Instruction{
566 .format_2a = .{
567 .rd = rd.enc(),
568 .op2 = op2,
569 .imm22 = imm,
570 },
571 };
572 }
573
574 fn format2b(op2: u3, cond: Condition, annul: bool, disp: i24) Instruction {
575 const udisp = @bitCast(u24, disp);
576
577 // In SPARC, branch target needs to be aligned to 4 bytes.
578 assert(udisp % 4 == 0);
579
580 // Discard the last two bits since those are implicitly zero.
581 const udisp_truncated = @truncate(u22, udisp >> 2);
582 return Instruction{
583 .format_2b = .{
584 .a = @boolToInt(annul),
585 .cond = cond,
586 .op2 = op2,
587 .disp22 = udisp_truncated,
588 },
589 };
590 }
591
592 fn format2c(op2: u3, cond: Condition, annul: bool, pt: bool, ccr: CCR, disp: i21) Instruction {
593 const udisp = @bitCast(u21, disp);
594
595 // In SPARC, branch target needs to be aligned to 4 bytes.
596 assert(udisp % 4 == 0);
597
598 // Discard the last two bits since those are implicitly zero.
599 const udisp_truncated = @truncate(u19, udisp >> 2);
600
601 const ccr_cc1 = @truncate(u1, @enumToInt(ccr) >> 1);
602 const ccr_cc0 = @truncate(u1, @enumToInt(ccr));
603 return Instruction{
604 .format_2c = .{
605 .a = @boolToInt(annul),
606 .cond = cond,
607 .op2 = op2,
608 .cc1 = ccr_cc1,
609 .cc0 = ccr_cc0,
610 .p = @boolToInt(pt),
611 .disp19 = udisp_truncated,
612 },
613 };
614 }
615
616 fn format2d(op2: u3, rcond: RCondition, annul: bool, pt: bool, rs1: Register, disp: i18) Instruction {
617 const udisp = @bitCast(u18, disp);
618
619 // In SPARC, branch target needs to be aligned to 4 bytes.
620 assert(udisp % 4 == 0);
621
622 // Discard the last two bits since those are implicitly zero,
623 // and split it into low and high parts.
624 const udisp_truncated = @truncate(u16, udisp >> 2);
625 const udisp_hi = @truncate(u2, (udisp_truncated & 0b1100_0000_0000_0000) >> 14);
626 const udisp_lo = @truncate(u14, udisp_truncated & 0b0011_1111_1111_1111);
627 return Instruction{
628 .format_2d = .{
629 .a = @boolToInt(annul),
630 .rcond = @enumToInt(rcond),
631 .op2 = op2,
632 .p = @boolToInt(pt),
633 .rs1 = rs1.enc(),
634 .d16hi = udisp_hi,
635 .d16lo = udisp_lo,
636 },
637 };
638 }
639
640 fn format3a(op: u2, op3: u6, rs1: Register, rs2: Register, rd: Register) Instruction {
641 return Instruction{
642 .format_3a = .{
643 .op = op,
644 .rd = rd.enc(),
645 .op3 = op3,
646 .rs1 = rs1.enc(),
647 .rs2 = rs2.enc(),
648 },
649 };
650 }
651 fn format3b(op: u2, op3: u6, rs1: Register, imm: i13, rd: Register) Instruction {
652 return Instruction{
653 .format_3b = .{
654 .op = op,
655 .rd = rd.enc(),
656 .op3 = op3,
657 .rs1 = rs1.enc(),
658 .simm13 = @bitCast(u13, imm),
659 },
660 };
661 }
662 fn format3c(op: u2, op3: u6, rs1: Register, rs2: Register) Instruction {
663 return Instruction{
664 .format_3c = .{
665 .op = op,
666 .op3 = op3,
667 .rs1 = rs1.enc(),
668 .rs2 = rs2.enc(),
669 },
670 };
671 }
672 fn format3d(op: u2, op3: u6, rs1: Register, imm: i13) Instruction {
673 return Instruction{
674 .format_3d = .{
675 .op = op,
676 .op3 = op3,
677 .rs1 = rs1.enc(),
678 .simm13 = @bitCast(u13, imm),
679 },
680 };
681 }
682 fn format3e(op: u2, op3: u6, rcond: RCondition, rs1: Register, rs2: Register, rd: Register) Instruction {
683 return Instruction{
684 .format_3e = .{
685 .op = op,
686 .rd = rd.enc(),
687 .op3 = op3,
688 .rs1 = rs1.enc(),
689 .rcond = @enumToInt(rcond),
690 .rs2 = rs2.enc(),
691 },
692 };
693 }
694 fn format3f(op: u2, op3: u6, rcond: RCondition, rs1: Register, imm: i10, rd: Register) Instruction {
695 return Instruction{
696 .format_3f = .{
697 .op = op,
698 .rd = rd.enc(),
699 .op3 = op3,
700 .rs1 = rs1.enc(),
701 .rcond = @enumToInt(rcond),
702 .simm10 = @bitCast(u10, imm),
703 },
704 };
705 }
706 fn format3g(op: u2, op3: u6, rs1: Register, rs2: Register, rd: Register) Instruction {
707 return Instruction{
708 .format_3g = .{
709 .op = op,
710 .rd = rd.enc(),
711 .op3 = op3,
712 .rs1 = rs1.enc(),
713 .rs2 = rs2.enc(),
714 },
715 };
716 }
717 fn format3h(cmask: MemCompletionConstraint, mmask: MemOrderingConstraint) Instruction {
718 return Instruction{
719 .format_3h = .{
720 .cmask = @bitCast(u3, cmask),
721 .mmask = @bitCast(u4, mmask),
722 },
723 };
724 }
725 fn format3i(op: u2, op3: u6, rs1: Register, rs2: Register, rd: Register, asi: ASI) Instruction {
726 return Instruction{
727 .format_3i = .{
728 .op = op,
729 .rd = rd.enc(),
730 .op3 = op3,
731 .rs1 = rs1.enc(),
732 .imm_asi = @enumToInt(asi),
733 .rs2 = rs2.enc(),
734 },
735 };
736 }
737 fn format3j(op: u2, op3: u6, impl_dep1: u5, impl_dep2: u19) Instruction {
738 return Instruction{
739 .format_3j = .{
740 .op = op,
741 .impl_dep1 = impl_dep1,
742 .op3 = op3,
743 .impl_dep2 = impl_dep2,
744 },
745 };
746 }
747 fn format3k(op: u2, op3: u6, sw: ShiftWidth, rs1: Register, rs2: Register, rd: Register) Instruction {
748 return Instruction{
749 .format_3k = .{
750 .op = op,
751 .rd = rd.enc(),
752 .op3 = op3,
753 .rs1 = rs1.enc(),
754 .x = @enumToInt(sw),
755 .rs2 = rs2.enc(),
756 },
757 };
758 }
759 fn format3l(op: u2, op3: u6, rs1: Register, shift_count: u5, rd: Register) Instruction {
760 return Instruction{
761 .format_3l = .{
762 .op = op,
763 .rd = rd.enc(),
764 .op3 = op3,
765 .rs1 = rs1.enc(),
766 .shcnt32 = shift_count,
767 },
768 };
769 }
770 fn format3m(op: u2, op3: u6, rs1: Register, shift_count: u6, rd: Register) Instruction {
771 return Instruction{
772 .format_3m = .{
773 .op = op,
774 .rd = rd.enc(),
775 .op3 = op3,
776 .rs1 = rs1.enc(),
777 .shcnt64 = shift_count,
778 },
779 };
780 }
781 fn format3n(op: u2, op3: u6, opf: u9, rs2: Register, rd: Register) Instruction {
782 return Instruction{
783 .format_3n = .{
784 .op = op,
785 .rd = rd.enc(),
786 .op3 = op3,
787 .opf = opf,
788 .rs2 = rs2.enc(),
789 },
790 };
791 }
792 fn format3o(op: u2, op3: u6, opf: u9, ccr: CCR, rs1: Register, rs2: Register) Instruction {
793 const ccr_cc1 = @truncate(u1, @enumToInt(ccr) >> 1);
794 const ccr_cc0 = @truncate(u1, @enumToInt(ccr));
795 return Instruction{
796 .format_3o = .{
797 .op = op,
798 .cc1 = ccr_cc1,
799 .cc0 = ccr_cc0,
800 .op3 = op3,
801 .rs1 = rs1.enc(),
802 .opf = opf,
803 .rs2 = rs2.enc(),
804 },
805 };
806 }
807 fn format3p(op: u2, op3: u6, opf: u9, rs1: Register, rs2: Register, rd: Register) Instruction {
808 return Instruction{
809 .format_3p = .{
810 .op = op,
811 .rd = rd.enc(),
812 .op3 = op3,
813 .rs1 = rs1.enc(),
814 .opf = opf,
815 .rs2 = rs2.enc(),
816 },
817 };
818 }
819 fn format3q(op: u2, op3: u6, rs1: Register, rd: Register) Instruction {
820 return Instruction{
821 .format_3q = .{
822 .op = op,
823 .rd = rd.enc(),
824 .op3 = op3,
825 .rs1 = rs1.enc(),
826 },
827 };
828 }
829 fn format3r(op: u2, op3: u6, fcn: u5) Instruction {
830 return Instruction{
831 .format_3r = .{
832 .op = op,
833 .fcn = fcn,
834 .op3 = op3,
835 },
836 };
837 }
838 fn format3s(op: u2, op3: u6, rd: Register) Instruction {
839 return Instruction{
840 .format_3s = .{
841 .op = op,
842 .rd = rd.enc(),
843 .op3 = op3,
844 },
845 };
846 }
847
848 fn format4a(op3: u6, ccr: CCR, rs1: Register, rs2: Register, rd: Register) Instruction {
849 const ccr_cc1 = @truncate(u1, @enumToInt(ccr) >> 1);
850 const ccr_cc0 = @truncate(u1, @enumToInt(ccr));
851 return Instruction{
852 .format_4a = .{
853 .rd = rd.enc(),
854 .op3 = op3,
855 .rs1 = rs1.enc(),
856 .cc1 = ccr_cc1,
857 .cc0 = ccr_cc0,
858 .rs2 = rs2.enc(),
859 },
860 };
861 }
862
863 fn format4b(op3: u6, ccr: CCR, rs1: Register, imm: i11, rd: Register) Instruction {
864 const ccr_cc1 = @truncate(u1, @enumToInt(ccr) >> 1);
865 const ccr_cc0 = @truncate(u1, @enumToInt(ccr));
866 return Instruction{
867 .format_4b = .{
868 .rd = rd.enc(),
869 .op3 = op3,
870 .rs1 = rs1.enc(),
871 .cc1 = ccr_cc1,
872 .cc0 = ccr_cc0,
873 .simm11 = @bitCast(u11, imm),
874 },
875 };
876 }
877
878 fn format4c(op3: u6, cond: Condition, ccr: CCR, rs2: Register, rd: Register) Instruction {
879 const ccr_cc2 = @truncate(u1, @enumToInt(ccr) >> 2);
880 const ccr_cc1 = @truncate(u1, @enumToInt(ccr) >> 1);
881 const ccr_cc0 = @truncate(u1, @enumToInt(ccr));
882 return Instruction{
883 .format_4c = .{
884 .rd = rd.enc(),
885 .op3 = op3,
886 .cc2 = ccr_cc2,
887 .cond = cond,
888 .cc1 = ccr_cc1,
889 .cc0 = ccr_cc0,
890 .rs2 = rs2.enc(),
891 },
892 };
893 }
894
895 fn format4d(op3: u6, cond: Condition, ccr: CCR, imm: i11, rd: Register) Instruction {
896 const ccr_cc2 = @truncate(u1, @enumToInt(ccr) >> 2);
897 const ccr_cc1 = @truncate(u1, @enumToInt(ccr) >> 1);
898 const ccr_cc0 = @truncate(u1, @enumToInt(ccr));
899 return Instruction{
900 .format_4d = .{
901 .rd = rd.enc(),
902 .op3 = op3,
903 .cc2 = ccr_cc2,
904 .cond = cond,
905 .cc1 = ccr_cc1,
906 .cc0 = ccr_cc0,
907 .simm11 = @bitCast(u11, imm),
908 },
909 };
910 }
911
912 fn format4e(op3: u6, ccr: CCR, rs1: Register, rd: Register, sw_trap: u7) Instruction {
913 const ccr_cc1 = @truncate(u1, @enumToInt(ccr) >> 1);
914 const ccr_cc0 = @truncate(u1, @enumToInt(ccr));
915 return Instruction{
916 .format_4e = .{
917 .rd = rd.enc(),
918 .op3 = op3,
919 .rs1 = rs1.enc(),
920 .cc1 = ccr_cc1,
921 .cc0 = ccr_cc0,
922 .sw_trap = sw_trap,
923 },
924 };
925 }
926
927 fn format4f(
928 op3: u6,
929 opf_low: u5,
930 rcond: RCondition,
931 rs1: Register,
932 rs2: Register,
933 rd: Register,
934 ) Instruction {
935 return Instruction{
936 .format_4f = .{
937 .rd = rd.enc(),
938 .op3 = op3,
939 .rs1 = rs1.enc(),
940 .rcond = @enumToInt(rcond),
941 .opf_low = opf_low,
942 .rs2 = rs2.enc(),
943 },
944 };
945 }
946
947 fn format4g(op3: u6, opf_low: u6, opf_cc: u3, cond: Condition, rs2: Register, rd: Register) Instruction {
948 return Instruction{
949 .format_4g = .{
950 .rd = rd.enc(),
951 .op3 = op3,
952 .cond = cond,
953 .opf_cc = opf_cc,
954 .opf_low = opf_low,
955 .rs2 = rs2.enc(),
956 },
957 };
958 }
959};
960
961test "Serialize formats" {
962 const Testcase = struct {
963 inst: Instruction,
964 expected: u32,
965 };
966
967 // Note that the testcases might or might not be a valid instruction
968 // This is mostly just to check the behavior of the format packed structs
969 // since currently stage1 doesn't properly implement it in all cases
970 const testcases = [_]Testcase{
971 .{
972 .inst = Instruction.format1(4),
973 .expected = 0b01_000000000000000000000000000001,
974 },
975 .{
976 .inst = Instruction.format2a(4, .g0, 0),
977 .expected = 0b00_00000_100_0000000000000000000000,
978 },
979 .{
980 .inst = Instruction.format2b(6, 3, true, -4),
981 .expected = 0b00_1_0011_110_1111111111111111111111,
982 },
983 .{
984 .inst = Instruction.format2c(3, 0, false, true, .xcc, 8),
985 .expected = 0b00_0_0000_011_1_0_1_0000000000000000010,
986 },
987 .{
988 .inst = Instruction.format2d(7, .eq_zero, false, true, .o0, 20),
989 .expected = 0b00_0_0_001_111_00_1_01000_00000000000101,
990 },
991 .{
992 .inst = Instruction.format3a(3, 5, .g0, .o1, .l2),
993 .expected = 0b11_10010_000101_00000_0_00000000_01001,
994 },
995 .{
996 .inst = Instruction.format3b(3, 5, .g0, -1, .l2),
997 .expected = 0b11_10010_000101_00000_1_1111111111111,
998 },
999 .{
1000 .inst = Instruction.format3c(3, 5, .g0, .o1),
1001 .expected = 0b11_00000_000101_00000_0_00000000_01001,
1002 },
1003 .{
1004 .inst = Instruction.format3d(3, 5, .g0, 0),
1005 .expected = 0b11_00000_000101_00000_1_0000000000000,
1006 },
1007 .{
1008 .inst = Instruction.format3e(3, 5, .ne_zero, .g0, .o1, .l2),
1009 .expected = 0b11_10010_000101_00000_0_101_00000_01001,
1010 },
1011 .{
1012 .inst = Instruction.format3f(3, 5, .ne_zero, .g0, -1, .l2),
1013 .expected = 0b11_10010_000101_00000_1_101_1111111111,
1014 },
1015 .{
1016 .inst = Instruction.format3g(3, 5, .g0, .o1, .l2),
1017 .expected = 0b11_10010_000101_00000_1_00000000_01001,
1018 },
1019 .{
1020 .inst = Instruction.format3h(.{}, .{}),
1021 .expected = 0b10_00000_101000_01111_1_000000_000_0000,
1022 },
1023 .{
1024 .inst = Instruction.format3i(3, 5, .g0, .o1, .l2, .asi_primary_little),
1025 .expected = 0b11_10010_000101_00000_0_10001000_01001,
1026 },
1027 .{
1028 .inst = Instruction.format3j(3, 5, 31, 0),
1029 .expected = 0b11_11111_000101_0000000000000000000,
1030 },
1031 .{
1032 .inst = Instruction.format3k(3, 5, .shift32, .g0, .o1, .l2),
1033 .expected = 0b11_10010_000101_00000_0_0_0000000_01001,
1034 },
1035 .{
1036 .inst = Instruction.format3l(3, 5, .g0, 31, .l2),
1037 .expected = 0b11_10010_000101_00000_1_0_0000000_11111,
1038 },
1039 .{
1040 .inst = Instruction.format3m(3, 5, .g0, 63, .l2),
1041 .expected = 0b11_10010_000101_00000_1_1_000000_111111,
1042 },
1043 .{
1044 .inst = Instruction.format3n(3, 5, 0, .o1, .l2),
1045 .expected = 0b11_10010_000101_00000_000000000_01001,
1046 },
1047 .{
1048 .inst = Instruction.format3o(3, 5, 0, .xcc, .o1, .l2),
1049 .expected = 0b11_000_1_0_000101_01001_000000000_10010,
1050 },
1051 .{
1052 .inst = Instruction.format3p(3, 5, 0, .g0, .o1, .l2),
1053 .expected = 0b11_10010_000101_00000_000000000_01001,
1054 },
1055 .{
1056 .inst = Instruction.format3q(3, 5, .g0, .o1),
1057 .expected = 0b11_01001_000101_00000_00000000000000,
1058 },
1059 .{
1060 .inst = Instruction.format3r(3, 5, 4),
1061 .expected = 0b11_00100_000101_0000000000000000000,
1062 },
1063 .{
1064 .inst = Instruction.format3s(3, 5, .g0),
1065 .expected = 0b11_00000_000101_0000000000000000000,
1066 },
1067 .{
1068 .inst = Instruction.format4a(8, .xcc, .g0, .o1, .l2),
1069 .expected = 0b10_10010_001000_00000_0_1_0_000000_01001,
1070 },
1071 .{
1072 .inst = Instruction.format4b(8, .xcc, .g0, -1, .l2),
1073 .expected = 0b10_10010_001000_00000_1_1_0_11111111111,
1074 },
1075 .{
1076 .inst = Instruction.format4c(8, 0, .xcc, .g0, .o1),
1077 .expected = 0b10_01001_001000_1_0000_0_1_0_000000_00000,
1078 },
1079 .{
1080 .inst = Instruction.format4d(8, 0, .xcc, 0, .l2),
1081 .expected = 0b10_10010_001000_1_0000_1_1_0_00000000000,
1082 },
1083 .{
1084 .inst = Instruction.format4e(8, .xcc, .g0, .o1, 0),
1085 .expected = 0b10_01001_001000_00000_1_1_0_0000_0000000,
1086 },
1087 .{
1088 .inst = Instruction.format4f(8, 4, .eq_zero, .g0, .o1, .l2),
1089 .expected = 0b10_10010_001000_00000_0_001_00100_01001,
1090 },
1091 .{
1092 .inst = Instruction.format4g(8, 4, 2, 0, .o1, .l2),
1093 .expected = 0b10_10010_001000_0_0000_010_000100_01001,
1094 },
1095 };
1096
1097 for (testcases) |case| {
1098 const actual = case.inst.toU32();
1099 try testing.expectEqual(case.expected, actual);
1100 }
1101}
src/codegen.zig+1-1
......@@ -108,7 +108,7 @@ pub fn generateFunction(
108108 //.riscv32 => return Function(.riscv32).generate(bin_file, src_loc, func, air, liveness, code, debug_output),
109109 .riscv64 => return @import("arch/riscv64/CodeGen.zig").generate(bin_file, src_loc, func, air, liveness, code, debug_output),
110110 //.sparc => return Function(.sparc).generate(bin_file, src_loc, func, air, liveness, code, debug_output),
111 //.sparcv9 => return Function(.sparcv9).generate(bin_file, src_loc, func, air, liveness, code, debug_output),
111 .sparcv9 => return @import("arch/sparcv9/CodeGen.zig").generate(bin_file, src_loc, func, air, liveness, code, debug_output),
112112 //.sparcel => return Function(.sparcel).generate(bin_file, src_loc, func, air, liveness, code, debug_output),
113113 //.s390x => return Function(.s390x).generate(bin_file, src_loc, func, air, liveness, code, debug_output),
114114 //.tce => return Function(.tce).generate(bin_file, src_loc, func, air, liveness, code, debug_output),