• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

SamboyCoding / Cpp2IL / 13988197905

21 Mar 2025 09:03AM UTC coverage: 23.407% (-3.8%) from 27.187%
13988197905

Pull #426

github

web-flow
Merge 4aa36af61 into 76a9b72af
Pull Request #426: ISIL -> CIL Decompiler

1270 of 7736 branches covered (16.42%)

Branch coverage included in aggregate %.

5 of 1526 new or added lines in 31 files covered. (0.33%)

4 existing lines in 3 files now uncovered.

3383 of 12143 relevant lines covered (27.86%)

107291.03 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/Cpp2IL.Core/InstructionSets/NewArmV8InstructionSet.cs
1
using System;
2
using System.Collections.Generic;
3
using System.Diagnostics;
4
using System.Linq;
5
using Disarm;
6
using Cpp2IL.Core.Api;
7
using Cpp2IL.Core.Il2CppApiFunctions;
8
using Cpp2IL.Core.ISIL;
9
using Cpp2IL.Core.Model.Contexts;
10
using Cpp2IL.Core.Utils;
11
using Cpp2IL.Decompiler.IL;
12
using Disarm.InternalDisassembly;
13
using LibCpp2IL;
14

15
namespace Cpp2IL.Core.InstructionSets;
16

17
public class NewArmV8InstructionSet : Cpp2IlInstructionSet
18
{
19
    public override Memory<byte> GetRawBytesForMethod(MethodAnalysisContext context, bool isAttributeGenerator)
20
    {
21
        if (context is not ConcreteGenericMethodAnalysisContext)
×
22
        {
23
            //Managed method or attr gen => grab raw byte range between a and b
24
            var startOfNextFunction = (int)MiscUtils.GetAddressOfNextFunctionStart(context.UnderlyingPointer);
×
25
            var ptrAsInt = (int)context.UnderlyingPointer;
×
26
            var count = startOfNextFunction - ptrAsInt;
×
27

28
            if (startOfNextFunction > 0)
×
29
                return LibCpp2IlMain.Binary!.GetRawBinaryContent().AsMemory(ptrAsInt, count);
×
30
        }
31

32
        var result = NewArm64Utils.GetArm64MethodBodyAtVirtualAddress(context.UnderlyingPointer);
×
33
        var endVa = result.LastValid().Address + 4;
×
34

35
        var start = (int)context.AppContext.Binary.MapVirtualAddressToRaw(context.UnderlyingPointer);
×
36
        var end = (int)context.AppContext.Binary.MapVirtualAddressToRaw(endVa);
×
37

38
        //Sanity check
39
        if (start < 0 || end < 0 || start >= context.AppContext.Binary.RawLength || end >= context.AppContext.Binary.RawLength)
×
40
            throw new Exception($"Failed to map virtual address 0x{context.UnderlyingPointer:X} to raw address for method {context!.DeclaringType?.FullName}/{context.Name} - start: 0x{start:X}, end: 0x{end:X} are out of bounds for length {context.AppContext.Binary.RawLength}.");
×
41

42
        return context.AppContext.Binary.GetRawBinaryContent().AsMemory(start, end - start);
×
43
    }
44

45
    public override List<InstructionSetIndependentInstruction> GetIsilFromMethod(MethodAnalysisContext context)
46
    {
47
        var insns = NewArm64Utils.GetArm64MethodBodyAtVirtualAddress(context.UnderlyingPointer);
×
48

49
        var builder = new IsilBuilder();
×
50

51
        foreach (var instruction in insns)
×
52
        {
53
            ConvertInstructionStatement(instruction, builder, context);
×
54
        }
55

56
        builder.FixJumps();
×
57

58
        return builder.BackingStatementList;
×
59
    }
60

61
    public override List<Instruction> GetDecompilerIlFromMethod(MethodAnalysisContext context, out List<object> ilParams)
62
    {
NEW
63
        ilParams = [];
×
NEW
64
        return [];
×
65
    }
66

67
    private void ConvertInstructionStatement(Arm64Instruction instruction, IsilBuilder builder, MethodAnalysisContext context)
68
    {
69
        switch (instruction.Mnemonic)
×
70
        {
71
            case Arm64Mnemonic.MOV:
72
            case Arm64Mnemonic.MOVZ:
73
            case Arm64Mnemonic.FMOV:
74
            case Arm64Mnemonic.SXTW: // move and sign extend Wn to Xd
75
            case Arm64Mnemonic.LDR:
76
            case Arm64Mnemonic.LDRB:
77
                //Load and move are (dest, src)
78
                if (instruction.MemIsPreIndexed) //  such as  X8, [X19,#0x30]! 
×
79
                {
80
                    var operate = ConvertOperand(instruction, 1);
×
81
                    if (operate.Data is IsilMemoryOperand operand)
×
82
                    {
83
                        var register = operand.Base!.Value;
×
84
                        // X19= X19, #0x30
85
                        builder.Add(instruction.Address, register, register, InstructionSetIndependentOperand.MakeImmediate(operand.Addend));
×
86
                        //X8 = [X19]
87
                        builder.Move(instruction.Address, ConvertOperand(instruction, 0), InstructionSetIndependentOperand.MakeMemory(new IsilMemoryOperand(
×
88
                            InstructionSetIndependentOperand.MakeRegister(register.ToString()!.ToUpperInvariant()),
×
89
                            0)));
×
90
                        break;
×
91
                    }
92
                }
93

94
                builder.Move(instruction.Address, ConvertOperand(instruction, 0), ConvertOperand(instruction, 1));
×
95
                break;
×
96
            case Arm64Mnemonic.MOVN:
97
            {
98
                // dest = ~src
99
                var temp = InstructionSetIndependentOperand.MakeRegister("TEMP");
×
100
                builder.Move(instruction.Address, temp, ConvertOperand(instruction, 1));
×
101
                builder.Not(instruction.Address, temp);
×
102
                builder.Move(instruction.Address, ConvertOperand(instruction, 0), temp);
×
103
            }
104
                break;
×
105
            case Arm64Mnemonic.STR:
106
            case Arm64Mnemonic.STUR: // unscaled
107
            case Arm64Mnemonic.STRB:
108
                //Store is (src, dest)
109
                builder.Move(instruction.Address, ConvertOperand(instruction, 1), ConvertOperand(instruction, 0));
×
110
                break;
×
111
            case Arm64Mnemonic.STP:
112
                // store pair of registers (reg1, reg2, dest)
113
            {
114
                var dest = ConvertOperand(instruction, 2);
×
115
                if (dest.Data is IsilRegisterOperand { RegisterName: "X31" }) // if stack
×
116
                {
117
                    builder.Move(instruction.Address, dest, ConvertOperand(instruction, 0));
×
118
                    builder.Move(instruction.Address, dest, ConvertOperand(instruction, 1));
×
119
                }
120
                else if (dest.Data is IsilMemoryOperand memory)
×
121
                {
122
                    var firstRegister = ConvertOperand(instruction, 0);
×
123
                    long size = ((IsilRegisterOperand)firstRegister.Data).RegisterName[0] == 'W' ? 4 : 8;
×
124
                    builder.Move(instruction.Address, dest, firstRegister); // [REG + offset] = REG1
×
125
                    memory = new IsilMemoryOperand(memory.Base!.Value, memory.Addend + size);
×
126
                    dest = InstructionSetIndependentOperand.MakeMemory(memory);
×
127
                    builder.Move(instruction.Address, dest, ConvertOperand(instruction, 1)); // [REG + offset + size] = REG2
×
128
                }
129
                else // reg pointer
130
                {
131
                    var firstRegister = ConvertOperand(instruction, 0);
×
132
                    long size = ((IsilRegisterOperand)firstRegister.Data).RegisterName[0] == 'W' ? 4 : 8;
×
133
                    builder.Move(instruction.Address, dest, firstRegister);
×
134
                    builder.Add(instruction.Address, dest, dest, InstructionSetIndependentOperand.MakeImmediate(size));
×
135
                    builder.Move(instruction.Address, dest, ConvertOperand(instruction, 1));
×
136
                }
137
            }
138
                break;
×
139
            case Arm64Mnemonic.ADRP:
140
                //Just handle as a move
141
                builder.Move(instruction.Address, ConvertOperand(instruction, 0), ConvertOperand(instruction, 1));
×
142
                break;
×
143
            case Arm64Mnemonic.LDP when instruction.Op2Kind == Arm64OperandKind.Memory:
×
144
                //LDP (dest1, dest2, [mem]) - basically just treat as two loads, with the second offset by the length of the first
145
                var destRegSize = instruction.Op0Reg switch
×
146
                {
×
147
                    //vector (128 bit)
×
148
                    >= Arm64Register.V0 and <= Arm64Register.V31 => 16, //TODO check if this is accurate
×
149
                    //double
×
150
                    >= Arm64Register.D0 and <= Arm64Register.D31 => 8,
×
151
                    //single
×
152
                    >= Arm64Register.S0 and <= Arm64Register.S31 => 4,
×
153
                    //half
×
154
                    >= Arm64Register.H0 and <= Arm64Register.H31 => 2,
×
155
                    //word
×
156
                    >= Arm64Register.W0 and <= Arm64Register.W31 => 4,
×
157
                    //x
×
158
                    >= Arm64Register.X0 and <= Arm64Register.X31 => 8,
×
159
                    _ => throw new($"Unknown register size for LDP: {instruction.Op0Reg}")
×
160
                };
×
161

162
                var dest1 = ConvertOperand(instruction, 0);
×
163
                var dest2 = ConvertOperand(instruction, 1);
×
164
                var mem = ConvertOperand(instruction, 2);
×
165

166
                //TODO clean this mess up
167
                var memInternal = mem.Data as IsilMemoryOperand?;
×
168
                var mem2 = new IsilMemoryOperand(memInternal!.Value.Base!.Value, memInternal.Value.Addend + destRegSize);
×
169

170
                builder.Move(instruction.Address, dest1, mem);
×
171
                builder.Move(instruction.Address, dest2, InstructionSetIndependentOperand.MakeMemory(mem2));
×
172
                break;
×
173
            case Arm64Mnemonic.BL:
174
                builder.Call(instruction.Address, instruction.BranchTarget, GetArgumentOperandsForCall(context, instruction.BranchTarget).ToArray());
×
175
                break;
×
176
            case Arm64Mnemonic.RET:
177
                builder.Return(instruction.Address, GetReturnRegisterForContext(context));
×
178
                break;
×
179
            case Arm64Mnemonic.B:
180
                var target = instruction.BranchTarget;
×
181

182
                if (target < context.UnderlyingPointer || target > context.UnderlyingPointer + (ulong)context.RawBytes.Length)
×
183
                {
184
                    //Unconditional branch to outside the method, treat as call (tail-call, specifically) followed by return
185
                    builder.Call(instruction.Address, instruction.BranchTarget, GetArgumentOperandsForCall(context, instruction.BranchTarget).ToArray());
×
186
                    builder.Return(instruction.Address, GetReturnRegisterForContext(context));
×
187
                }
188

189
                break;
×
190
            case Arm64Mnemonic.BR:
191
                // branches unconditionally to an address in a register, with a hint that this is not a subroutine return.
192
                builder.CallRegister(instruction.Address, ConvertOperand(instruction, 0), noReturn: true);
×
193
                break;
×
194
            case Arm64Mnemonic.CBNZ:
195
            case Arm64Mnemonic.CBZ:
196
            {
197
                //Compare and branch if (non-)zero
198
                var targetAddr = (ulong)((long)instruction.Address + instruction.Op1Imm);
×
199

200
                //Compare to zero...
201
                builder.Compare(instruction.Address, ConvertOperand(instruction, 0), InstructionSetIndependentOperand.MakeImmediate(0));
×
202

203
                //And jump if (not) equal
204
                if (instruction.Mnemonic == Arm64Mnemonic.CBZ)
×
205
                    builder.JumpIfEqual(instruction.Address, targetAddr);
×
206
                else
207
                    builder.JumpIfNotEqual(instruction.Address, targetAddr);
×
208
            }
209
                break;
×
210

211
            case Arm64Mnemonic.CMP:
212
                // Compare: set flag (N or Z or C or V) = (reg1 - reg2)
213
                // builder.Compare(instruction.Address, ConvertOperand(instruction, 0), ConvertOperand(instruction, 0));
214
                goto default;
215

216
            case Arm64Mnemonic.TBNZ:
217
            // TBNZ R<t>, #imm, label
218
            // test bit and branch if NonZero
219
            case Arm64Mnemonic.TBZ:
220
                // TBZ R<t>, #imm, label
221
                // test bit and branch if Zero
222
            {
223
                var targetAddr = (ulong)((long)instruction.Address + instruction.Op2Imm);
×
224
                var bit = InstructionSetIndependentOperand.MakeImmediate(1 << (int)instruction.Op1Imm);
×
225
                var temp = InstructionSetIndependentOperand.MakeRegister("TEMP");
×
226
                var src = ConvertOperand(instruction, 0);
×
227
                builder.Move(instruction.Address, temp, src); // temp = src
×
228
                builder.And(instruction.Address, temp, temp, bit); // temp = temp & bit
×
229
                builder.Compare(instruction.Address, temp, bit); // result = temp == bit
×
230
                if (instruction.Mnemonic == Arm64Mnemonic.TBNZ)
×
231
                    builder.JumpIfEqual(instruction.Address, targetAddr); // if (result) goto targetAddr
×
232
                else
233
                    builder.JumpIfNotEqual(instruction.Address, targetAddr); // if (result) goto targetAddr
×
234
            }
235
                break;
×
236
            case Arm64Mnemonic.UBFM:
237
                // UBFM dest, src, #<immr>, #<imms>
238
                // dest = (src >> #<immr>) & ((1 << #<imms>) - 1)
239
            {
240
                var dest = ConvertOperand(instruction, 0);
×
241
                builder.Move(instruction.Address, dest, ConvertOperand(instruction, 1)); // dest = src
×
242
                builder.ShiftRight(instruction.Address, dest, ConvertOperand(instruction, 2)); // dest >> #<immr>
×
243
                var imms = (int)instruction.Op3Imm;
×
244
                builder.And(instruction.Address, dest, dest,
×
245
                    InstructionSetIndependentOperand.MakeImmediate((1 << imms) - 1)); // dest & constexpr { ((1 << #<imms>) - 1) }
×
246
            }
247
                break;
×
248

249
            case Arm64Mnemonic.MUL:
250
            case Arm64Mnemonic.FMUL:
251
                //Multiply is (dest, src1, src2)
252
                builder.Multiply(instruction.Address, ConvertOperand(instruction, 0), ConvertOperand(instruction, 1), ConvertOperand(instruction, 2));
×
253
                break;
×
254

255
            case Arm64Mnemonic.ADD:
256
            case Arm64Mnemonic.ADDS: // settings flags
257
            case Arm64Mnemonic.FADD:
258
                //Add is (dest, src1, src2)
259
                builder.Add(instruction.Address, ConvertOperand(instruction, 0), ConvertOperand(instruction, 1), ConvertOperand(instruction, 2));
×
260
                break;
×
261

262
            case Arm64Mnemonic.SUB:
263
            case Arm64Mnemonic.SUBS: // settings flags
264
            case Arm64Mnemonic.FSUB:
265
                //Sub is (dest, src1, src2)
266
                builder.Subtract(instruction.Address, ConvertOperand(instruction, 0), ConvertOperand(instruction, 1), ConvertOperand(instruction, 2));
×
267
                break;
×
268

269
            case Arm64Mnemonic.AND:
270
            case Arm64Mnemonic.ANDS:
271
                //And is (dest, src1, src2)
272
                builder.And(instruction.Address, ConvertOperand(instruction, 0), ConvertOperand(instruction, 1), ConvertOperand(instruction, 2));
×
273
                break;
×
274

275
            case Arm64Mnemonic.ORR:
276
                //Orr is (dest, src1, src2)
277
                builder.Or(instruction.Address, ConvertOperand(instruction, 0), ConvertOperand(instruction, 1), ConvertOperand(instruction, 2));
×
278
                break;
×
279

280
            case Arm64Mnemonic.EOR:
281
                //Eor (aka xor) is (dest, src1, src2)
282
                builder.Xor(instruction.Address, ConvertOperand(instruction, 0), ConvertOperand(instruction, 1), ConvertOperand(instruction, 2));
×
283
                break;
×
284

285
            default:
286
                builder.NotImplemented(instruction.Address, $"Instruction {instruction.Mnemonic} not yet implemented.");
×
287
                break;
288
        }
289
    }
×
290

291
    private InstructionSetIndependentOperand ConvertOperand(Arm64Instruction instruction, int operand)
292
    {
293
        var kind = operand switch
×
294
        {
×
295
            0 => instruction.Op0Kind,
×
296
            1 => instruction.Op1Kind,
×
297
            2 => instruction.Op2Kind,
×
298
            3 => instruction.Op3Kind,
×
299
            _ => throw new ArgumentOutOfRangeException(nameof(operand), $"Operand must be between 0 and 3, inclusive. Got {operand}")
×
300
        };
×
301

302
        if (kind is Arm64OperandKind.Immediate or Arm64OperandKind.ImmediatePcRelative)
×
303
        {
304
            var imm = operand switch
×
305
            {
×
306
                0 => instruction.Op0Imm,
×
307
                1 => instruction.Op1Imm,
×
308
                2 => instruction.Op2Imm,
×
309
                3 => instruction.Op3Imm,
×
310
                _ => throw new ArgumentOutOfRangeException(nameof(operand), $"Operand must be between 0 and 3, inclusive. Got {operand}")
×
311
            };
×
312

313
            if (kind == Arm64OperandKind.ImmediatePcRelative)
×
314
                imm += (long)instruction.Address + 4; //Add 4 to the address to get the address of the next instruction (PC-relative addressing is relative to the address of the next instruction, not the current one
×
315

316
            return InstructionSetIndependentOperand.MakeImmediate(imm);
×
317
        }
318

319
        if (kind == Arm64OperandKind.FloatingPointImmediate)
×
320
        {
321
            var imm = operand switch
×
322
            {
×
323
                0 => instruction.Op0FpImm,
×
324
                1 => instruction.Op1FpImm,
×
325
                2 => instruction.Op2FpImm,
×
326
                3 => instruction.Op3FpImm,
×
327
                _ => throw new ArgumentOutOfRangeException(nameof(operand), $"Operand must be between 0 and 3, inclusive. Got {operand}")
×
328
            };
×
329

330
            return InstructionSetIndependentOperand.MakeImmediate(imm);
×
331
        }
332

333
        if (kind == Arm64OperandKind.Register)
×
334
        {
335
            var reg = operand switch
×
336
            {
×
337
                0 => instruction.Op0Reg,
×
338
                1 => instruction.Op1Reg,
×
339
                2 => instruction.Op2Reg,
×
340
                3 => instruction.Op3Reg,
×
341
                _ => throw new ArgumentOutOfRangeException(nameof(operand), $"Operand must be between 0 and 3, inclusive. Got {operand}")
×
342
            };
×
343

344
            return InstructionSetIndependentOperand.MakeRegister(reg.ToString().ToUpperInvariant());
×
345
        }
346

347
        if (kind == Arm64OperandKind.Memory)
×
348
        {
349
            var reg = instruction.MemBase;
×
350
            var offset = instruction.MemOffset;
×
351
            var isPreIndexed = instruction.MemIsPreIndexed;
×
352

353
            if (reg == Arm64Register.INVALID)
×
354
                //Offset only
355
                return InstructionSetIndependentOperand.MakeMemory(new IsilMemoryOperand(offset));
×
356

357
            //TODO Handle more stuff here
358
            return InstructionSetIndependentOperand.MakeMemory(new IsilMemoryOperand(
×
359
                InstructionSetIndependentOperand.MakeRegister(reg.ToString().ToUpperInvariant()),
×
360
                offset));
×
361
        }
362

363
        if (kind == Arm64OperandKind.VectorRegisterElement)
×
364
        {
365
            var reg = operand switch
×
366
            {
×
367
                0 => instruction.Op0Reg,
×
368
                1 => instruction.Op1Reg,
×
369
                2 => instruction.Op2Reg,
×
370
                3 => instruction.Op3Reg,
×
371
                _ => throw new ArgumentOutOfRangeException(nameof(operand), $"Operand must be between 0 and 3, inclusive. Got {operand}")
×
372
            };
×
373

374
            var vectorElement = operand switch
×
375
            {
×
376
                0 => instruction.Op0VectorElement,
×
377
                1 => instruction.Op1VectorElement,
×
378
                2 => instruction.Op2VectorElement,
×
379
                3 => instruction.Op3VectorElement,
×
380
                _ => throw new ArgumentOutOfRangeException(nameof(operand), $"Operand must be between 0 and 3, inclusive. Got {operand}")
×
381
            };
×
382

383
            var width = vectorElement.Width switch
×
384
            {
×
385
                Arm64VectorElementWidth.B => IsilVectorRegisterElementOperand.VectorElementWidth.B,
×
386
                Arm64VectorElementWidth.H => IsilVectorRegisterElementOperand.VectorElementWidth.H,
×
387
                Arm64VectorElementWidth.S => IsilVectorRegisterElementOperand.VectorElementWidth.S,
×
388
                Arm64VectorElementWidth.D => IsilVectorRegisterElementOperand.VectorElementWidth.D,
×
389
                _ => throw new ArgumentOutOfRangeException(nameof(vectorElement.Width), $"Unknown vector element width {vectorElement.Width}")
×
390
            };
×
391

392
            //<Reg>.<Width>[<Index>]
393
            return InstructionSetIndependentOperand.MakeVectorElement(reg.ToString().ToUpperInvariant(), width, vectorElement.Index);
×
394
        }
395

396
        return InstructionSetIndependentOperand.MakeImmediate($"<UNIMPLEMENTED OPERAND TYPE {kind}>");
×
397
    }
398

399
    public override BaseKeyFunctionAddresses CreateKeyFunctionAddressesInstance() => new NewArm64KeyFunctionAddresses();
×
400

401
    public override string PrintAssembly(MethodAnalysisContext context) => context.RawBytes.Span.Length <= 0 ? "" : string.Join("\n", Disassembler.Disassemble(context.RawBytes.Span, context.UnderlyingPointer, new Disassembler.Options(true, true, false)).ToList());
×
402

403
    private InstructionSetIndependentOperand? GetReturnRegisterForContext(MethodAnalysisContext context)
404
    {
405
        var returnType = context.ReturnTypeContext;
×
406
        if (returnType.Namespace == nameof(System))
×
407
        {
408
            return returnType.Name switch
×
409
            {
×
410
                "Void" => null, //Void is no return
×
411
                "Double" => InstructionSetIndependentOperand.MakeRegister(nameof(Arm64Register.V0)), //Builtin double is v0
×
412
                "Single" => InstructionSetIndependentOperand.MakeRegister(nameof(Arm64Register.V0)), //Builtin float is v0
×
413
                _ => InstructionSetIndependentOperand.MakeRegister(nameof(Arm64Register.X0)), //All other system types are x0 like any other pointer
×
414
            };
×
415
        }
416

417
        //TODO Do certain value types have different return registers?
418

419
        //Any user type is returned in x0
420
        return InstructionSetIndependentOperand.MakeRegister(nameof(Arm64Register.X0));
×
421
    }
422

423
    private List<InstructionSetIndependentOperand> GetArgumentOperandsForCall(MethodAnalysisContext contextBeingAnalyzed, ulong callAddr)
424
    {
425
        if (!contextBeingAnalyzed.AppContext.MethodsByAddress.TryGetValue(callAddr, out var methodsAtAddress))
×
426
            //TODO
427
            return [];
×
428

429
        //For the sake of arguments, all we care about is the first method at the address, because they'll only be shared if they have the same signature.
430
        var contextBeingCalled = methodsAtAddress.First();
×
431

432
        var vectorCount = 0;
×
433
        var nonVectorCount = 0;
×
434

435
        var ret = new List<InstructionSetIndependentOperand>();
×
436

437
        //Handle 'this' if it's an instance method
438
        if (!contextBeingCalled.IsStatic)
×
439
        {
440
            ret.Add(InstructionSetIndependentOperand.MakeRegister(nameof(Arm64Register.X0)));
×
441
            nonVectorCount++;
×
442
        }
443

444
        foreach (var parameter in contextBeingCalled.Parameters)
×
445
        {
446
            var paramType = parameter.ParameterTypeContext;
×
447
            if (paramType.Namespace == nameof(System))
×
448
            {
449
                switch (paramType.Name)
×
450
                {
451
                    case "Single":
452
                    case "Double":
453
                        ret.Add(InstructionSetIndependentOperand.MakeRegister((Arm64Register.V0 + vectorCount++).ToString().ToUpperInvariant()));
×
454
                        break;
×
455
                    default:
456
                        ret.Add(InstructionSetIndependentOperand.MakeRegister((Arm64Register.X0 + nonVectorCount++).ToString().ToUpperInvariant()));
×
457
                        break;
×
458
                }
459
            }
460
            else
461
            {
462
                ret.Add(InstructionSetIndependentOperand.MakeRegister((Arm64Register.X0 + nonVectorCount++).ToString().ToUpperInvariant()));
×
463
            }
464
        }
465

466
        return ret;
×
467
    }
468
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc