llvm-native-core 0.1.6

LLVM-native core semantic engine — IR, CodeGen, X86 MC, Clang frontend pipeline
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
//! SPARC MC Encoder — instruction encoding per the SPARC Architecture
//! Manual v8/v9.
//!
//! Encodes SPARC instructions into big-endian byte sequences. Supports
//! three instruction formats:
//!
//! # Instruction Formats (32-bit)
//!
//! ```text
//! Format 1 (CALL):  op(2) | disp30(30)
//! Format 2 (SETHI): op(2) | rd(5) | op2(3) | imm22(22)
//! Format 2 (Branch): op(2) | a(1) | cond(4) | op2(3) | disp22(22)
//! Format 3 (All others): op(2) | rd(5) | op3(6) | rs1(5) | i(1) | asi_or_simm13(13)
//! ```
//!
//! Clean-room reconstruction from the SPARC Architecture Manual v8/v9.
//! Zero LLVM source code consultation.

use super::sparc_instr_info::SparcOpcode;
use super::sparc_register_info::{SPARC_FPR_BASE, SPARC_GPR_BASE};
use crate::codegen::{MachineFunction, MachineInstr, MachineOperand};

// ============================================================================
// SPARC Instruction Format Constants
// ============================================================================

// Format 1: CALL  op=01
const FMT1_CALL: u32 = 0x01;

// Format 2: SETHI op=00, Branches op=00 and op2=01x
const FMT2_SETHI: u32 = 0x00; // op=00, op2=100
const FMT2_BICC: u32 = 0x00; // op=00, op2=010
const FMT2_FBFCC: u32 = 0x00; // op=00, op2=110

// Format 3: op=10 or 11 depending on register fields
const FMT3_OP: u32 = 0x02; // 10 binary
const FMT3_OP2: u32 = 0x03; // 11 binary

// op3 field values for Format 3
const OP3_ADD: u32 = 0x00;
const OP3_ADDcc: u32 = 0x10;
const OP3_ADDC: u32 = 0x08;
const OP3_ADDCcc: u32 = 0x18;
const OP3_SUB: u32 = 0x04;
const OP3_SUBcc: u32 = 0x14;
const OP3_SUBC: u32 = 0x0C;
const OP3_SUBCcc: u32 = 0x1C;

const OP3_AND: u32 = 0x01;
const OP3_ANDcc: u32 = 0x11;
const OP3_ANDN: u32 = 0x05;
const OP3_ANDNcc: u32 = 0x15;
const OP3_OR: u32 = 0x02;
const OP3_ORcc: u32 = 0x12;
const OP3_ORN: u32 = 0x06;
const OP3_ORNcc: u32 = 0x16;
const OP3_XOR: u32 = 0x03;
const OP3_XORcc: u32 = 0x13;
const OP3_XNOR: u32 = 0x07;
const OP3_XNORcc: u32 = 0x17;

const OP3_SLL: u32 = 0x25;
const OP3_SRL: u32 = 0x26;
const OP3_SRA: u32 = 0x27;

const OP3_LD: u32 = 0x00;
const OP3_LDUB: u32 = 0x01;
const OP3_LDUH: u32 = 0x02;
const OP3_LDSB: u32 = 0x09;
const OP3_LDSH: u32 = 0x0A;
const OP3_LDD: u32 = 0x03;
const OP3_ST: u32 = 0x04;
const OP3_STB: u32 = 0x05;
const OP3_STH: u32 = 0x06;
const OP3_STD: u32 = 0x07;

const OP3_JMPL: u32 = 0x38;
const OP3_SAVE: u32 = 0x3C;
const OP3_RESTORE: u32 = 0x3D;
const OP3_RETT: u32 = 0x39;

const OP3_FPop1: u32 = 0x34;
const OP3_FPop2: u32 = 0x35;

// Branch condition codes (cond field)
const COND_BA: u32 = 0x08;
const COND_BN: u32 = 0x00;
const COND_BNE: u32 = 0x09;
const COND_BE: u32 = 0x01;
const COND_BG: u32 = 0x0A;
const COND_BLE: u32 = 0x02;
const COND_BGE: u32 = 0x0B;
const COND_BL: u32 = 0x03;
const COND_BGU: u32 = 0x0C;
const COND_BLEU: u32 = 0x04;
const COND_BCC: u32 = 0x0D;
const COND_BCS: u32 = 0x05;
const COND_BPOS: u32 = 0x0E;
const COND_BNEG: u32 = 0x06;
const COND_BVC: u32 = 0x0F;
const COND_BVS: u32 = 0x07;

// FPU opcode auxiliary for FPop1
const FPop_S: u32 = 0x41; // Single precision opcode
const FPop_D: u32 = 0x42; // Double precision opcode

// Helper to convert a u32 word to big-endian bytes
fn u32_to_be_bytes(word: u32) -> Vec<u8> {
    word.to_be_bytes().to_vec()
}

// ============================================================================
// SparcMCEncoder
// ============================================================================

/// SPARC machine code encoder. Accumulates encoded instruction bytes
/// in big-endian order.
pub struct SparcMCEncoder {
    /// Whether this targets SPARC v9 (affects opcode selection).
    pub is_64bit: bool,
    /// Accumulated output bytes.
    pub output: Vec<u8>,
}

impl SparcMCEncoder {
    /// Create a new encoder.
    pub fn new(is_64bit: bool) -> Self {
        Self {
            is_64bit,
            output: Vec::with_capacity(256),
        }
    }

    // ------------------------------------------------------------------
    // Public API
    // ------------------------------------------------------------------

    /// Encode a single `MachineInstr` and return its bytes.
    pub fn encode_instruction(&mut self, mi: &MachineInstr) -> Vec<u8> {
        let bytes = self.instruction_to_bytes(mi);
        self.output.extend_from_slice(&bytes);
        bytes
    }

    /// Encode all instructions from a `MachineFunction`.
    pub fn encode_function(&mut self, mf: &MachineFunction) -> Vec<u8> {
        for block in &mf.blocks {
            for instr in &block.instructions {
                self.encode_instruction(instr);
            }
        }
        std::mem::take(&mut self.output)
    }

    /// Convert a single `MachineInstr` into its byte representation.
    fn instruction_to_bytes(&self, mi: &MachineInstr) -> Vec<u8> {
        let word = self.encode_by_opcode(mi);
        u32_to_be_bytes(word)
    }

    // ------------------------------------------------------------------
    // Main encoding dispatch
    // ------------------------------------------------------------------

    fn encode_by_opcode(&self, mi: &MachineInstr) -> u32 {
        match get_sparc_opcode(mi.opcode) {
            SparcOpcode::ADD => self.encode_fmt3_reg(OP3_ADD, mi),
            SparcOpcode::ADDcc => self.encode_fmt3_reg(OP3_ADDcc, mi),
            SparcOpcode::SUB => self.encode_fmt3_reg(OP3_SUB, mi),
            SparcOpcode::SUBcc => self.encode_fmt3_reg(OP3_SUBcc, mi),
            SparcOpcode::AND => self.encode_fmt3_reg(OP3_AND, mi),
            SparcOpcode::ANDN => self.encode_fmt3_reg(OP3_ANDN, mi),
            SparcOpcode::OR => self.encode_fmt3_reg(OP3_OR, mi),
            SparcOpcode::ORN => self.encode_fmt3_reg(OP3_ORN, mi),
            SparcOpcode::XOR => self.encode_fmt3_reg(OP3_XOR, mi),
            SparcOpcode::XNOR => self.encode_fmt3_reg(OP3_XNOR, mi),
            SparcOpcode::SLL => self.encode_fmt3_reg(OP3_SLL, mi),
            SparcOpcode::SRL => self.encode_fmt3_reg(OP3_SRL, mi),
            SparcOpcode::SRA => self.encode_fmt3_reg(OP3_SRA, mi),
            SparcOpcode::LD => self.encode_fmt3_mem(OP3_LD, mi),
            SparcOpcode::LDUB => self.encode_fmt3_mem(OP3_LDUB, mi),
            SparcOpcode::LDUH => self.encode_fmt3_mem(OP3_LDUH, mi),
            SparcOpcode::LDSB => self.encode_fmt3_mem(OP3_LDSB, mi),
            SparcOpcode::LDSH => self.encode_fmt3_mem(OP3_LDSH, mi),
            SparcOpcode::LDD => self.encode_fmt3_mem(OP3_LDD, mi),
            SparcOpcode::ST => self.encode_fmt3_mem(OP3_ST, mi),
            SparcOpcode::STB => self.encode_fmt3_mem(OP3_STB, mi),
            SparcOpcode::STH => self.encode_fmt3_mem(OP3_STH, mi),
            SparcOpcode::STD => self.encode_fmt3_mem(OP3_STD, mi),
            SparcOpcode::BA => self.encode_fmt2_branch(COND_BA, mi),
            SparcOpcode::BN => self.encode_fmt2_branch(COND_BN, mi),
            SparcOpcode::BNE => self.encode_fmt2_branch(COND_BNE, mi),
            SparcOpcode::BE => self.encode_fmt2_branch(COND_BE, mi),
            SparcOpcode::BG => self.encode_fmt2_branch(COND_BG, mi),
            SparcOpcode::BLE => self.encode_fmt2_branch(COND_BLE, mi),
            SparcOpcode::BGE => self.encode_fmt2_branch(COND_BGE, mi),
            SparcOpcode::BL => self.encode_fmt2_branch(COND_BL, mi),
            SparcOpcode::BGU => self.encode_fmt2_branch(COND_BGU, mi),
            SparcOpcode::BLEU => self.encode_fmt2_branch(COND_BLEU, mi),
            SparcOpcode::BCC => self.encode_fmt2_branch(COND_BCC, mi),
            SparcOpcode::BCS => self.encode_fmt2_branch(COND_BCS, mi),
            SparcOpcode::BPOS => self.encode_fmt2_branch(COND_BPOS, mi),
            SparcOpcode::BNEG => self.encode_fmt2_branch(COND_BNEG, mi),
            SparcOpcode::BVC => self.encode_fmt2_branch(COND_BVC, mi),
            SparcOpcode::BVS => self.encode_fmt2_branch(COND_BVS, mi),
            SparcOpcode::CALL => self.encode_fmt1_call(mi),
            SparcOpcode::JMPL => self.encode_fmt3_reg(OP3_JMPL, mi),
            SparcOpcode::SAVE => self.encode_fmt3_reg(OP3_SAVE, mi),
            SparcOpcode::RESTORE => self.encode_fmt3_reg(OP3_RESTORE, mi),
            SparcOpcode::SETHI => self.encode_fmt2_sethi(mi),
            SparcOpcode::NOP => 0x01000000, // SETHI 0, %g0
            SparcOpcode::FADDS => self.encode_fpu_fmt3(FPop_S, 0x41, mi),
            SparcOpcode::FADDD => self.encode_fpu_fmt3(FPop_D, 0x42, mi),
            SparcOpcode::FSUBS => self.encode_fpu_fmt3(FPop_S, 0x45, mi),
            SparcOpcode::FSUBD => self.encode_fpu_fmt3(FPop_D, 0x46, mi),
            SparcOpcode::FMULS => self.encode_fpu_fmt3(FPop_S, 0x49, mi),
            SparcOpcode::FMULD => self.encode_fpu_fmt3(FPop_D, 0x4A, mi),
            SparcOpcode::FDIVS => self.encode_fpu_fmt3(FPop_S, 0x4D, mi),
            SparcOpcode::FDIVD => self.encode_fpu_fmt3(FPop_D, 0x4E, mi),
            SparcOpcode::FSQRTS => self.encode_fpu_fmt3(FPop_S, 0x29, mi),
            SparcOpcode::FSQRTD => self.encode_fpu_fmt3(FPop_D, 0x2A, mi),
            SparcOpcode::FITOS => self.encode_fpu_fmt3(FPop_S, 0xC4, mi),
            SparcOpcode::FITOD => self.encode_fpu_fmt3(FPop_S, 0xC8, mi),
            SparcOpcode::FSTOI => self.encode_fpu_fmt3(FPop_S, 0xD1, mi),
            SparcOpcode::FDTOI => self.encode_fpu_fmt3(FPop_D, 0xD2, mi),
            SparcOpcode::FMOVS => self.encode_fpu_fmt3(FPop_S, 0x01, mi),
            SparcOpcode::FMOVD => self.encode_fpu_fmt3(FPop_D, 0x02, mi),
            SparcOpcode::FCMPS => self.encode_fpu_cmp(FPop_S, 0x51, mi),
            SparcOpcode::FCMPD => self.encode_fpu_cmp(FPop_D, 0x52, mi),
            SparcOpcode::FCMPES => self.encode_fpu_cmp(FPop_S, 0x55, mi),
            SparcOpcode::FCMPED => self.encode_fpu_cmp(FPop_D, 0x56, mi),
            SparcOpcode::RET => self.encode_fmt3_ret(),
            SparcOpcode::RETL => self.encode_fmt3_retl(),
            _ => 0x01000000, // Default to NOP
        }
    }

    // ------------------------------------------------------------------
    // Format 1: CALL — op(2)=01 | disp30(30)
    // ------------------------------------------------------------------

    fn encode_fmt1_call(&self, mi: &MachineInstr) -> u32 {
        let disp30: u32 = 0; // In real encoder, compute from target address
        (FMT1_CALL << 30) | (disp30 & 0x3FFFFFFF)
    }

    // ------------------------------------------------------------------
    // Format 2: SETHI — op(2)=00 | rd(5) | op2(3)=100 | imm22(22)
    // ------------------------------------------------------------------

    fn encode_fmt2_sethi(&self, mi: &MachineInstr) -> u32 {
        let rd = Self::get_reg_field(mi, 0);
        let imm22: u32 = Self::get_imm(mi, 1) as u32 & 0x3FFFFF;
        (FMT2_SETHI << 30) | (rd << 25) | (0x04 << 22) | imm22
    }

    // ------------------------------------------------------------------
    // Format 2: Branch — op(2)=00 | a(1) | cond(4) | op2(3)=010 | disp22(22)
    // ------------------------------------------------------------------

    fn encode_fmt2_branch(&self, cond: u32, mi: &MachineInstr) -> u32 {
        let a = 0; // annul bit
        let disp22: u32 = 0; // In real encoder, compute from target offset
        (FMT2_BICC << 30) | (a << 29) | (cond << 25) | (0x02 << 22) | (disp22 & 0x3FFFFF)
    }

    // ------------------------------------------------------------------
    // Format 3: Arithmetic/Logical — op(2) | rd(5) | op3(6) | rs1(5) | i(1) | unused(5) | rs2(5)
    // ------------------------------------------------------------------

    fn encode_fmt3_reg(&self, op3: u32, mi: &MachineInstr) -> u32 {
        let rd = Self::get_reg_field(mi, 0);
        let rs1 = Self::get_reg_field(mi, 1);
        let rs2 = Self::get_reg_field(mi, 2);
        let i = 0; // 0 = register operand, 1 = immediate
        (FMT3_OP << 30) | (rd << 25) | (op3 << 19) | (rs1 << 14) | (i << 13) | rs2
    }

    // ------------------------------------------------------------------
    // Format 3: Memory — op(2) | rd(5) | op3(6) | rs1(5) | i(1) | simm13(13)
    // ------------------------------------------------------------------

    fn encode_fmt3_mem(&self, op3: u32, mi: &MachineInstr) -> u32 {
        let rd = Self::get_reg_field(mi, 0);
        let rs1 = Self::get_reg_field(mi, 1);
        let offset = Self::get_imm(mi, 2) as i32;
        let simm13: u32 = (offset & 0x1FFF) as u32;
        let i = 1; // immediate addressing
        (FMT3_OP << 30) | (rd << 25) | (op3 << 19) | (rs1 << 14) | (i << 13) | simm13
    }

    // ------------------------------------------------------------------
    // Format 3: RET — jmpl %i7+8, %g0
    // ------------------------------------------------------------------

    fn encode_fmt3_ret(&self) -> u32 {
        let rd: u32 = 0; // %g0
        let rs1: u32 = 31; // %i7
        (FMT3_OP << 30) | (rd << 25) | (OP3_JMPL << 19) | (rs1 << 14) | (1 << 13) | 8
    }

    fn encode_fmt3_retl(&self) -> u32 {
        let rd: u32 = 0; // %g0
        let rs1: u32 = 15; // %o7
        (FMT3_OP << 30) | (rd << 25) | (OP3_JMPL << 19) | (rs1 << 14) | (1 << 13) | 8
    }

    // ------------------------------------------------------------------
    // FPU Format 3
    // ------------------------------------------------------------------

    fn encode_fpu_fmt3(&self, fpop_type: u32, fpop_func: u32, mi: &MachineInstr) -> u32 {
        let rd = Self::get_reg_field(mi, 0);
        let rs1 = Self::get_reg_field(mi, 1);
        let rs2 = Self::get_reg_field(mi, 2);
        (FMT3_OP << 30) | (rd << 25) | (OP3_FPop1 << 19) | (rs1 << 14) | (fpop_type << 5) | rs2
    }

    fn encode_fpu_cmp(&self, _fpop_type: u32, _fpop_func: u32, mi: &MachineInstr) -> u32 {
        let rs1 = Self::get_reg_field(mi, 0);
        let rs2 = Self::get_reg_field(mi, 1);
        (FMT3_OP << 30) | (0x35 << 19) | (rs1 << 14) | (1 << 5) | rs2
    }

    // ------------------------------------------------------------------
    // Operand extraction helpers
    // ------------------------------------------------------------------

    /// Extract a register field (0-31) from the operand at the given index.
    fn get_reg_field(mi: &MachineInstr, index: usize) -> u32 {
        mi.operands
            .get(index)
            .map(|op| match op {
                MachineOperand::Reg(vr) => *vr & 0x1F,
                MachineOperand::PhysReg(pr) => *pr & 0x1F,
                MachineOperand::Imm(_) => 0,
                _ => 0,
            })
            .unwrap_or(0) as u32
    }

    /// Extract an immediate value.
    fn get_imm(mi: &MachineInstr, index: usize) -> i64 {
        mi.operands
            .get(index)
            .map(|op| match op {
                MachineOperand::Imm(imm) => *imm,
                _ => 0,
            })
            .unwrap_or(0)
    }
}

/// Map a raw u32 opcode back to a SparcOpcode for encoding.
fn get_sparc_opcode(opcode: u32) -> SparcOpcode {
    match opcode {
        0 => SparcOpcode::ADD,
        1 => SparcOpcode::ADDcc,
        2 => SparcOpcode::ADDC,
        3 => SparcOpcode::ADDCcc,
        4 => SparcOpcode::SUB,
        5 => SparcOpcode::SUBcc,
        6 => SparcOpcode::SUBC,
        7 => SparcOpcode::SUBCcc,
        8 => SparcOpcode::MULX,
        9 => SparcOpcode::SDIVX,
        10 => SparcOpcode::UDIVX,
        11 => SparcOpcode::SMUL,
        12 => SparcOpcode::UMUL,
        13 => SparcOpcode::SDIV,
        14 => SparcOpcode::UDIV,
        20 => SparcOpcode::AND,
        21 => SparcOpcode::ANDcc,
        22 => SparcOpcode::ANDN,
        23 => SparcOpcode::ANDNcc,
        24 => SparcOpcode::OR,
        25 => SparcOpcode::ORcc,
        26 => SparcOpcode::ORN,
        27 => SparcOpcode::ORNcc,
        28 => SparcOpcode::XOR,
        29 => SparcOpcode::XORcc,
        30 => SparcOpcode::XNOR,
        31 => SparcOpcode::XNORcc,
        40 => SparcOpcode::SLL,
        41 => SparcOpcode::SRL,
        42 => SparcOpcode::SRA,
        50 => SparcOpcode::LD,
        51 => SparcOpcode::LDUB,
        52 => SparcOpcode::LDUH,
        53 => SparcOpcode::LDSB,
        54 => SparcOpcode::LDSH,
        55 => SparcOpcode::LDD,
        60 => SparcOpcode::ST,
        61 => SparcOpcode::STB,
        62 => SparcOpcode::STH,
        63 => SparcOpcode::STD,
        70 => SparcOpcode::BA,
        71 => SparcOpcode::BN,
        72 => SparcOpcode::BNE,
        73 => SparcOpcode::BE,
        74 => SparcOpcode::BG,
        75 => SparcOpcode::BLE,
        76 => SparcOpcode::BGE,
        77 => SparcOpcode::BL,
        78 => SparcOpcode::BGU,
        79 => SparcOpcode::BLEU,
        80 => SparcOpcode::BCC,
        81 => SparcOpcode::BCS,
        82 => SparcOpcode::BPOS,
        83 => SparcOpcode::BNEG,
        84 => SparcOpcode::BVC,
        85 => SparcOpcode::BVS,
        120 => SparcOpcode::CALL,
        121 => SparcOpcode::JMPL,
        122 => SparcOpcode::RET,
        123 => SparcOpcode::RETL,
        124 => SparcOpcode::SAVE,
        125 => SparcOpcode::RESTORE,
        130 => SparcOpcode::SETHI,
        131 => SparcOpcode::NOP,
        150 => SparcOpcode::FADDS,
        151 => SparcOpcode::FADDD,
        152 => SparcOpcode::FSUBS,
        153 => SparcOpcode::FSUBD,
        154 => SparcOpcode::FMULS,
        155 => SparcOpcode::FMULD,
        156 => SparcOpcode::FDIVS,
        157 => SparcOpcode::FDIVD,
        158 => SparcOpcode::FSQRTS,
        159 => SparcOpcode::FSQRTD,
        160 => SparcOpcode::FITOS,
        161 => SparcOpcode::FITOD,
        162 => SparcOpcode::FSTOI,
        163 => SparcOpcode::FDTOI,
        164 => SparcOpcode::FMOVS,
        165 => SparcOpcode::FMOVD,
        170 => SparcOpcode::FCMPS,
        171 => SparcOpcode::FCMPD,
        172 => SparcOpcode::FCMPES,
        173 => SparcOpcode::FCMPED,
        _ => SparcOpcode::NOP,
    }
}