-
Notifications
You must be signed in to change notification settings - Fork 1.6k
/
Copy pathconstants_riscv.h
1789 lines (1601 loc) · 58.1 KB
/
constants_riscv.h
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
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
#ifndef RUNTIME_VM_CONSTANTS_RISCV_H_
#define RUNTIME_VM_CONSTANTS_RISCV_H_
#ifndef RUNTIME_VM_CONSTANTS_H_
#error Do not include constants_riscv.h directly; use constants.h instead.
#endif
#include <sstream>
#include "platform/assert.h"
#include "platform/globals.h"
#include "platform/utils.h"
#include "vm/constants_base.h"
#include "vm/flags.h"
namespace dart {
#if defined(TARGET_ARCH_RISCV32)
typedef uint32_t uintx_t;
typedef int32_t intx_t;
constexpr intx_t kMaxIntX = kMaxInt32;
constexpr uintx_t kMaxUIntX = kMaxUint32;
constexpr intx_t kMinIntX = kMinInt32;
#define XLEN 32
#elif defined(TARGET_ARCH_RISCV64)
typedef uint64_t uintx_t;
typedef int64_t intx_t;
constexpr intx_t kMaxIntX = kMaxInt64;
constexpr uintx_t kMaxUIntX = kMaxUint64;
constexpr intx_t kMinIntX = kMinInt64;
#define XLEN 64
#else
#error What XLEN?
#endif
enum Register {
// The correct name for this register is ZERO, but this conflicts with other
// globals.
ZR = 0,
RA = 1,
SP = 2,
GP = 3, // Shadow call stack on Fuchsia and Android
TP = 4,
T0 = 5,
T1 = 6,
T2 = 7,
FP = 8,
S1 = 9, // THR
A0 = 10,
A1 = 11,
A2 = 12, // CODE_REG
A3 = 13, // TMP
A4 = 14, // TMP2
A5 = 15, // PP, untagged
A6 = 16,
A7 = 17,
S2 = 18,
S3 = 19,
S4 = 20, // ARGS_DESC_REG
S5 = 21, // IC_DATA_REG
S6 = 22,
S7 = 23, // CALLEE_SAVED_TEMP2
S8 = 24, // CALLEE_SAVED_TEMP / FAR_TMP
S9 = 25, // DISPATCH_TABLE_REG
S10 = 26, // NULL_REG
S11 = 27, // WRITE_BARRIER_STATE
T3 = 28,
T4 = 29,
T5 = 30,
T6 = 31,
kNumberOfCpuRegisters = 32,
kNoRegister = -1,
RA2 = T0,
S0 = FP,
// Note that some compressed instructions can only take registers x8-x15 for
// some of their operands, so to reduce code size we assign the most popular
// uses to these registers.
// If the base register of a load/store is not SP, both the base register and
// source/destination register must be in x8-x15 and the offset must be
// aligned to make use a compressed instruction. So either,
// - PP, CODE_REG and IC_DATA_REG should all be assigned to x8-x15 and we
// should hold PP untagged like on ARM64. This makes the loads in the call
// sequence shorter, but adds extra PP tagging/untagging on entry and
// return.
// - PP should be assigned to a C-preserved register to avoid spilling it on
// leaf runtime calls.
};
enum FRegister {
FT0 = 0,
FT1 = 1,
FT2 = 2,
FT3 = 3,
FT4 = 4,
FT5 = 5,
FT6 = 6,
FT7 = 7,
FS0 = 8,
FS1 = 9,
FA0 = 10,
FA1 = 11,
FA2 = 12,
FA3 = 13,
FA4 = 14,
FA5 = 15,
FA6 = 16,
FA7 = 17,
FS2 = 18,
FS3 = 19,
FS4 = 20,
FS5 = 21,
FS6 = 22,
FS7 = 23,
FS8 = 24,
FS9 = 25,
FS10 = 26,
FS11 = 27,
FT8 = 28,
FT9 = 29,
FT10 = 30,
FT11 = 31,
kNumberOfFpuRegisters = 32,
kNoFpuRegister = -1,
};
// Register alias for floating point scratch register.
const FRegister FTMP = FT11;
// Architecture independent aliases.
typedef FRegister FpuRegister;
const FpuRegister FpuTMP = FTMP;
const int kFpuRegisterSize = 8;
typedef double fpu_register_t;
extern const char* const cpu_reg_names[kNumberOfCpuRegisters];
extern const char* const cpu_reg_abi_names[kNumberOfCpuRegisters];
extern const char* const fpu_reg_names[kNumberOfFpuRegisters];
// Register aliases.
constexpr Register TMP = A3; // Used as scratch register by assembler.
constexpr Register TMP2 = A4;
constexpr Register FAR_TMP = S8;
constexpr Register PP = A5; // Caches object pool pointer in generated code.
constexpr Register DISPATCH_TABLE_REG = S9; // Dispatch table register.
constexpr Register CODE_REG = A2;
// Set when calling Dart functions in JIT mode, used by LazyCompileStub.
constexpr Register FUNCTION_REG = T0;
constexpr Register FPREG = FP; // Frame pointer register.
constexpr Register SPREG = SP; // Stack pointer register.
constexpr Register IC_DATA_REG = S5; // ICData/MegamorphicCache register.
constexpr Register ARGS_DESC_REG = S4; // Arguments descriptor register.
constexpr Register THR = S1; // Caches current thread in generated code.
constexpr Register CALLEE_SAVED_TEMP = S8;
constexpr Register CALLEE_SAVED_TEMP2 = S7;
constexpr Register WRITE_BARRIER_STATE = S11;
constexpr Register NULL_REG = S10; // Caches NullObject() value.
#define DART_ASSEMBLER_HAS_NULL_REG 1
// ABI for catch-clause entry point.
constexpr Register kExceptionObjectReg = A0;
constexpr Register kStackTraceObjectReg = A1;
// ABI for write barrier stub.
constexpr Register kWriteBarrierObjectReg = A0;
constexpr Register kWriteBarrierValueReg = A1;
constexpr Register kWriteBarrierSlotReg = A6;
// Common ABI for shared slow path stubs.
struct SharedSlowPathStubABI {
static constexpr Register kResultReg = A0;
};
// ABI for instantiation stubs.
struct InstantiationABI {
static constexpr Register kUninstantiatedTypeArgumentsReg = T1;
static constexpr Register kInstantiatorTypeArgumentsReg = T2;
static constexpr Register kFunctionTypeArgumentsReg = T3;
static constexpr Register kResultTypeArgumentsReg = A0;
static constexpr Register kResultTypeReg = A0;
static constexpr Register kScratchReg = T4;
};
// Registers in addition to those listed in InstantiationABI used inside the
// implementation of the InstantiateTypeArguments stubs.
struct InstantiateTAVInternalRegs {
// The set of registers that must be pushed/popped when probing a hash-based
// cache due to overlap with the registers in InstantiationABI.
static constexpr intptr_t kSavedRegisters = 0;
// Additional registers used to probe hash-based caches.
static constexpr Register kEntryStartReg = S2;
static constexpr Register kProbeMaskReg = S3;
static constexpr Register kProbeDistanceReg = S4;
static constexpr Register kCurrentEntryIndexReg = S5;
};
// Registers in addition to those listed in TypeTestABI used inside the
// implementation of type testing stubs that are _not_ preserved.
struct TTSInternalRegs {
static constexpr Register kInstanceTypeArgumentsReg = S2;
static constexpr Register kScratchReg = S3;
static constexpr Register kSubTypeArgumentReg = S4;
static constexpr Register kSuperTypeArgumentReg = S5;
// Must be pushed/popped whenever generic type arguments are being checked as
// they overlap with registers in TypeTestABI.
static constexpr intptr_t kSavedTypeArgumentRegisters = 0;
static constexpr intptr_t kInternalRegisters =
((1 << kInstanceTypeArgumentsReg) | (1 << kScratchReg) |
(1 << kSubTypeArgumentReg) | (1 << kSuperTypeArgumentReg)) &
~kSavedTypeArgumentRegisters;
};
// Registers in addition to those listed in TypeTestABI used inside the
// implementation of subtype test cache stubs that are _not_ preserved.
struct STCInternalRegs {
static constexpr Register kInstanceCidOrSignatureReg = S2;
static constexpr Register kInstanceInstantiatorTypeArgumentsReg = S3;
static constexpr Register kInstanceParentFunctionTypeArgumentsReg = S4;
static constexpr Register kInstanceDelayedFunctionTypeArgumentsReg = S5;
static constexpr Register kCacheEntriesEndReg = S6;
static constexpr Register kCacheContentsSizeReg = A6;
static constexpr Register kProbeDistanceReg = A7;
static constexpr intptr_t kInternalRegisters =
(1 << kInstanceCidOrSignatureReg) |
(1 << kInstanceInstantiatorTypeArgumentsReg) |
(1 << kInstanceParentFunctionTypeArgumentsReg) |
(1 << kInstanceDelayedFunctionTypeArgumentsReg) |
(1 << kCacheEntriesEndReg) | (1 << kCacheContentsSizeReg) |
(1 << kProbeDistanceReg);
};
// Calling convention when calling TypeTestingStub and SubtypeTestCacheStub.
struct TypeTestABI {
static constexpr Register kInstanceReg = A0;
static constexpr Register kDstTypeReg = T1;
static constexpr Register kInstantiatorTypeArgumentsReg = T2;
static constexpr Register kFunctionTypeArgumentsReg = T3;
static constexpr Register kSubtypeTestCacheReg = T4;
static constexpr Register kScratchReg = T5;
// For calls to SubtypeNTestCacheStub. Must be distinct from the registers
// listed above.
static constexpr Register kSubtypeTestCacheResultReg = T0;
// For calls to InstanceOfStub.
static constexpr Register kInstanceOfResultReg = kInstanceReg;
static constexpr intptr_t kPreservedAbiRegisters =
(1 << kInstanceReg) | (1 << kDstTypeReg) |
(1 << kInstantiatorTypeArgumentsReg) | (1 << kFunctionTypeArgumentsReg);
static constexpr intptr_t kNonPreservedAbiRegisters =
TTSInternalRegs::kInternalRegisters |
STCInternalRegs::kInternalRegisters | (1 << kSubtypeTestCacheReg) |
(1 << kScratchReg) | (1 << kSubtypeTestCacheResultReg) | (1 << CODE_REG);
static constexpr intptr_t kAbiRegisters =
kPreservedAbiRegisters | kNonPreservedAbiRegisters;
};
// Calling convention when calling AssertSubtypeStub.
struct AssertSubtypeABI {
static constexpr Register kSubTypeReg = T1;
static constexpr Register kSuperTypeReg = T2;
static constexpr Register kInstantiatorTypeArgumentsReg = T3;
static constexpr Register kFunctionTypeArgumentsReg = T4;
static constexpr Register kDstNameReg = T5;
static constexpr intptr_t kAbiRegisters =
(1 << kSubTypeReg) | (1 << kSuperTypeReg) |
(1 << kInstantiatorTypeArgumentsReg) | (1 << kFunctionTypeArgumentsReg) |
(1 << kDstNameReg);
// No result register, as AssertSubtype is only run for side effect
// (throws if the subtype check fails).
};
// ABI for InitStaticFieldStub.
struct InitStaticFieldABI {
static constexpr Register kFieldReg = T2;
static constexpr Register kResultReg = A0;
};
// Registers used inside the implementation of InitLateStaticFieldStub.
struct InitLateStaticFieldInternalRegs {
static constexpr Register kAddressReg = T3;
static constexpr Register kScratchReg = T4;
};
// ABI for InitInstanceFieldStub.
struct InitInstanceFieldABI {
static constexpr Register kInstanceReg = T1;
static constexpr Register kFieldReg = T2;
static constexpr Register kResultReg = A0;
};
// Registers used inside the implementation of InitLateInstanceFieldStub.
struct InitLateInstanceFieldInternalRegs {
static constexpr Register kAddressReg = T3;
static constexpr Register kScratchReg = T4;
};
// ABI for LateInitializationError stubs.
struct LateInitializationErrorABI {
static constexpr Register kFieldReg = T2;
};
// ABI for ThrowStub.
struct ThrowABI {
static constexpr Register kExceptionReg = A0;
};
// ABI for ReThrowStub.
struct ReThrowABI {
static constexpr Register kExceptionReg = A0;
static constexpr Register kStackTraceReg = A1;
};
// ABI for RangeErrorStub.
struct RangeErrorABI {
static constexpr Register kLengthReg = T1;
static constexpr Register kIndexReg = T2;
};
// ABI for AllocateObjectStub.
struct AllocateObjectABI {
static constexpr Register kResultReg = A0;
static constexpr Register kTypeArgumentsReg = A1;
static constexpr Register kTagsReg = T2;
};
// ABI for AllocateClosureStub.
struct AllocateClosureABI {
static constexpr Register kResultReg = AllocateObjectABI::kResultReg;
static constexpr Register kFunctionReg = T1;
static constexpr Register kContextReg = T2;
static constexpr Register kInstantiatorTypeArgsReg = T3;
static constexpr Register kScratchReg = T4;
};
// ABI for AllocateMintShared*Stub.
struct AllocateMintABI {
static constexpr Register kResultReg = AllocateObjectABI::kResultReg;
static constexpr Register kTempReg = T2;
};
// ABI for Allocate{Mint,Double,Float32x4,Float64x2}Stub.
struct AllocateBoxABI {
static constexpr Register kResultReg = AllocateObjectABI::kResultReg;
static constexpr Register kTempReg = T2;
};
// ABI for AllocateArrayStub.
struct AllocateArrayABI {
static constexpr Register kResultReg = AllocateObjectABI::kResultReg;
static constexpr Register kLengthReg = T2;
static constexpr Register kTypeArgumentsReg = T1;
};
// ABI for AllocateRecordStub.
struct AllocateRecordABI {
static constexpr Register kResultReg = AllocateObjectABI::kResultReg;
static constexpr Register kShapeReg = T1;
static constexpr Register kTemp1Reg = T2;
static constexpr Register kTemp2Reg = T3;
};
// ABI for AllocateSmallRecordStub (AllocateRecord2, AllocateRecord2Named,
// AllocateRecord3, AllocateRecord3Named).
struct AllocateSmallRecordABI {
static constexpr Register kResultReg = AllocateObjectABI::kResultReg;
static constexpr Register kShapeReg = T2;
static constexpr Register kValue0Reg = T3;
static constexpr Register kValue1Reg = T4;
static constexpr Register kValue2Reg = A1;
static constexpr Register kTempReg = T1;
};
// ABI for AllocateTypedDataArrayStub.
struct AllocateTypedDataArrayABI {
static constexpr Register kResultReg = AllocateObjectABI::kResultReg;
static constexpr Register kLengthReg = T2;
};
// ABI for BoxDoubleStub.
struct BoxDoubleStubABI {
static constexpr FpuRegister kValueReg = FA0;
static constexpr Register kTempReg = T1;
static constexpr Register kResultReg = A0;
};
// ABI for DoubleToIntegerStub.
struct DoubleToIntegerStubABI {
static constexpr FpuRegister kInputReg = FA0;
static constexpr Register kRecognizedKindReg = T1;
static constexpr Register kResultReg = A0;
};
// ABI for SuspendStub (AwaitStub, AwaitWithTypeCheckStub, YieldAsyncStarStub,
// SuspendSyncStarAtStartStub, SuspendSyncStarAtYieldStub).
struct SuspendStubABI {
static constexpr Register kArgumentReg = A0;
static constexpr Register kTypeArgsReg = T0; // Can be the same as kTempReg
static constexpr Register kTempReg = T0;
static constexpr Register kFrameSizeReg = T1;
static constexpr Register kSuspendStateReg = T2;
static constexpr Register kFunctionDataReg = T3;
static constexpr Register kSrcFrameReg = T4;
static constexpr Register kDstFrameReg = T5;
// Number of bytes to skip after
// suspend stub return address in order to resume.
static constexpr intptr_t kResumePcDistance = 0;
};
// ABI for InitSuspendableFunctionStub (InitAsyncStub, InitAsyncStarStub,
// InitSyncStarStub).
struct InitSuspendableFunctionStubABI {
static constexpr Register kTypeArgsReg = A0;
};
// ABI for ResumeStub
struct ResumeStubABI {
static constexpr Register kSuspendStateReg = T1;
static constexpr Register kTempReg = T0;
// Registers for the frame copying (the 1st part).
static constexpr Register kFrameSizeReg = T2;
static constexpr Register kSrcFrameReg = T3;
static constexpr Register kDstFrameReg = T4;
// Registers for control transfer.
// (the 2nd part, can reuse registers from the 1st part)
static constexpr Register kResumePcReg = T2;
// Can also reuse kSuspendStateReg but should not conflict with CODE_REG/PP.
static constexpr Register kExceptionReg = T3;
static constexpr Register kStackTraceReg = T4;
};
// ABI for ReturnStub (ReturnAsyncStub, ReturnAsyncNotFutureStub,
// ReturnAsyncStarStub).
struct ReturnStubABI {
static constexpr Register kSuspendStateReg = T1;
};
// ABI for AsyncExceptionHandlerStub.
struct AsyncExceptionHandlerStubABI {
static constexpr Register kSuspendStateReg = T1;
};
// ABI for CloneSuspendStateStub.
struct CloneSuspendStateStubABI {
static constexpr Register kSourceReg = A0;
static constexpr Register kDestinationReg = A1;
static constexpr Register kTempReg = T0;
static constexpr Register kFrameSizeReg = T1;
static constexpr Register kSrcFrameReg = T2;
static constexpr Register kDstFrameReg = T3;
};
// ABI for FfiAsyncCallbackSendStub.
struct FfiAsyncCallbackSendStubABI {
static constexpr Register kArgsReg = A0;
};
// ABI for DispatchTableNullErrorStub and consequently for all dispatch
// table calls (though normal functions will not expect or use this
// register). This ABI is added to distinguish memory corruption errors from
// null errors.
struct DispatchTableNullErrorABI {
static constexpr Register kClassIdReg = A2;
};
typedef uint32_t RegList;
const RegList kAllCpuRegistersList = 0xFFFFFFFF;
const RegList kAllFpuRegistersList = 0xFFFFFFFF;
#define R(reg) (static_cast<RegList>(1) << (reg))
// C++ ABI call registers.
constexpr RegList kAbiArgumentCpuRegs =
R(A0) | R(A1) | R(A2) | R(A3) | R(A4) | R(A5) | R(A6) | R(A7);
constexpr RegList kAbiVolatileCpuRegs = kAbiArgumentCpuRegs | R(T0) | R(T1) |
R(T2) | R(T3) | R(T4) | R(T5) | R(T6) |
R(RA);
constexpr RegList kAbiPreservedCpuRegs = R(S1) | R(S2) | R(S3) | R(S4) | R(S5) |
R(S6) | R(S7) | R(S8) | R(S9) |
R(S10) | R(S11);
constexpr int kAbiPreservedCpuRegCount = 11;
constexpr RegList kReservedCpuRegisters =
R(ZR) | R(TP) | R(GP) | R(SP) | R(FP) | R(TMP) | R(TMP2) | R(PP) | R(THR) |
R(RA) | R(WRITE_BARRIER_STATE) | R(NULL_REG) | R(DISPATCH_TABLE_REG) |
R(FAR_TMP);
constexpr intptr_t kNumberOfReservedCpuRegisters =
Utils::CountOneBits32(kReservedCpuRegisters);
// CPU registers available to Dart allocator.
constexpr RegList kDartAvailableCpuRegs =
kAllCpuRegistersList & ~kReservedCpuRegisters;
constexpr int kNumberOfDartAvailableCpuRegs =
kNumberOfCpuRegisters - kNumberOfReservedCpuRegisters;
// Registers X8-15 (S0-1,A0-5) have more compressed instructions available.
constexpr int kRegisterAllocationBias = 8;
// Registers available to Dart that are not preserved by runtime calls.
constexpr RegList kDartVolatileCpuRegs =
kDartAvailableCpuRegs & ~kAbiPreservedCpuRegs;
constexpr RegList kAbiArgumentFpuRegs =
R(FA0) | R(FA1) | R(FA2) | R(FA3) | R(FA4) | R(FA5) | R(FA6) | R(FA7);
constexpr RegList kAbiVolatileFpuRegs =
kAbiArgumentFpuRegs | R(FT0) | R(FT1) | R(FT2) | R(FT3) | R(FT4) | R(FT5) |
R(FT6) | R(FT7) | R(FT8) | R(FT9) | R(FT10) | R(FT11);
constexpr RegList kAbiPreservedFpuRegs = R(FS0) | R(FS1) | R(FS2) | R(FS3) |
R(FS4) | R(FS5) | R(FS6) | R(FS7) |
R(FS8) | R(FS9) | R(FS10) | R(FS11);
constexpr int kAbiPreservedFpuRegCount = 12;
constexpr intptr_t kReservedFpuRegisters = 0;
constexpr intptr_t kNumberOfReservedFpuRegisters = 0;
constexpr int kStoreBufferWrapperSize = 26;
class CallingConventions {
public:
static constexpr intptr_t kArgumentRegisters = kAbiArgumentCpuRegs;
static const Register ArgumentRegisters[];
static constexpr intptr_t kNumArgRegs = 8;
static constexpr Register kPointerToReturnStructRegisterCall = A0;
static constexpr Register kPointerToReturnStructRegisterReturn = A0;
static const FpuRegister FpuArgumentRegisters[];
static constexpr intptr_t kFpuArgumentRegisters =
R(FA0) | R(FA1) | R(FA2) | R(FA3) | R(FA4) | R(FA5) | R(FA6) | R(FA7);
static constexpr intptr_t kNumFpuArgRegs = 8;
static constexpr bool kArgumentIntRegXorFpuReg = false;
static constexpr intptr_t kCalleeSaveCpuRegisters = kAbiPreservedCpuRegs;
// Whether larger than wordsize arguments are aligned to even registers.
static constexpr AlignmentStrategy kArgumentRegisterAlignment =
kAlignedToWordSize;
static constexpr AlignmentStrategy kArgumentRegisterAlignmentVarArgs =
kAlignedToWordSizeAndValueSize;
// How stack arguments are aligned.
static constexpr AlignmentStrategy kArgumentStackAlignment =
kAlignedToWordSizeAndValueSize;
static constexpr AlignmentStrategy kArgumentStackAlignmentVarArgs =
kArgumentStackAlignment;
// How fields in compounds are aligned.
static constexpr AlignmentStrategy kFieldAlignment = kAlignedToValueSize;
// Whether 1 or 2 byte-sized arguments or return values are passed extended
// to 4 bytes.
#if XLEN == 32
static constexpr ExtensionStrategy kReturnRegisterExtension = kExtendedTo4;
static constexpr ExtensionStrategy kArgumentRegisterExtension = kExtendedTo4;
static constexpr ExtensionStrategy kArgumentStackExtension = kExtendedTo4;
#else
static constexpr ExtensionStrategy kReturnRegisterExtension = kExtendedTo8;
static constexpr ExtensionStrategy kArgumentRegisterExtension = kExtendedTo8;
static constexpr ExtensionStrategy kArgumentStackExtension = kExtendedTo8;
#endif
static constexpr Register kReturnReg = A0;
static constexpr Register kSecondReturnReg = A1;
static constexpr FpuRegister kReturnFpuReg = FA0;
// S0=FP, S1=THR
static constexpr Register kFfiAnyNonAbiRegister = S2;
static constexpr Register kFirstNonArgumentRegister = T0;
static constexpr Register kSecondNonArgumentRegister = T1;
static constexpr Register kStackPointerRegister = SPREG;
COMPILE_ASSERT(
((R(kFirstNonArgumentRegister) | R(kSecondNonArgumentRegister)) &
(kArgumentRegisters | R(kPointerToReturnStructRegisterCall))) == 0);
};
// Register based calling convention used for Dart functions.
//
// See |compiler::ComputeCallingConvention| for more details.
struct DartCallingConvention {
// A2-A5 have conflicting uses. The order should be revisited once we
// implement Location::MayBeSameAsInput, likely putting A0 first.
static constexpr Register kCpuRegistersForArgs[] = {A1, A6, A0, A7};
static constexpr FpuRegister kFpuRegistersForArgs[] = {FA0, FA1, FA2, FA3};
};
// TODO(riscv): Architecture-independent parts of the compiler should use
// compare-and-branch instead of condition codes.
enum Condition {
kNoCondition = -1,
EQ = 0, // equal
NE = 1, // not equal
CS = 2, // carry set/unsigned higher or same
CC = 3, // carry clear/unsigned lower
MI = 4, // minus/negative
PL = 5, // plus/positive or zero
VS = 6, // overflow
VC = 7, // no overflow
HI = 8, // unsigned higher
LS = 9, // unsigned lower or same
GE = 10, // signed greater than or equal
LT = 11, // signed less than
GT = 12, // signed greater than
LE = 13, // signed less than or equal
AL = 14, // always (unconditional)
NV = 15, // special condition (refer to section C1.2.3)
kNumberOfConditions = 16,
// Platform-independent variants declared for all platforms
EQUAL = EQ,
ZERO = EQUAL,
NOT_EQUAL = NE,
NOT_ZERO = NOT_EQUAL,
LESS = LT,
LESS_EQUAL = LE,
GREATER_EQUAL = GE,
GREATER = GT,
UNSIGNED_LESS = CC,
UNSIGNED_LESS_EQUAL = LS,
UNSIGNED_GREATER = HI,
UNSIGNED_GREATER_EQUAL = CS,
OVERFLOW = VS,
NO_OVERFLOW = VC,
kInvalidCondition = 16
};
static inline Condition InvertCondition(Condition c) {
COMPILE_ASSERT((EQ ^ NE) == 1);
COMPILE_ASSERT((CS ^ CC) == 1);
COMPILE_ASSERT((MI ^ PL) == 1);
COMPILE_ASSERT((VS ^ VC) == 1);
COMPILE_ASSERT((HI ^ LS) == 1);
COMPILE_ASSERT((GE ^ LT) == 1);
COMPILE_ASSERT((GT ^ LE) == 1);
COMPILE_ASSERT((AL ^ NV) == 1);
ASSERT(c != AL);
ASSERT(c != kInvalidCondition);
return static_cast<Condition>(c ^ 1);
}
enum ScaleFactor {
TIMES_1 = 0,
TIMES_2 = 1,
TIMES_4 = 2,
TIMES_8 = 3,
TIMES_16 = 4,
// We can't include vm/compiler/runtime_api.h, so just be explicit instead
// of using (dart::)kWordSizeLog2.
#if defined(TARGET_ARCH_IS_64_BIT)
// Used for Smi-boxed indices.
TIMES_HALF_WORD_SIZE = kInt64SizeLog2 - 1,
// Used for unboxed indices.
TIMES_WORD_SIZE = kInt64SizeLog2,
#elif defined(TARGET_ARCH_IS_32_BIT)
// Used for Smi-boxed indices.
TIMES_HALF_WORD_SIZE = kInt32SizeLog2 - 1,
// Used for unboxed indices.
TIMES_WORD_SIZE = kInt32SizeLog2,
#else
#error "Unexpected word size"
#endif
#if !defined(DART_COMPRESSED_POINTERS)
TIMES_COMPRESSED_WORD_SIZE = TIMES_WORD_SIZE,
#else
TIMES_COMPRESSED_WORD_SIZE = TIMES_HALF_WORD_SIZE,
#endif
// Used for Smi-boxed indices.
TIMES_COMPRESSED_HALF_WORD_SIZE = TIMES_COMPRESSED_WORD_SIZE - 1,
};
const uword kBreakInstructionFiller = 0; // trap or c.trap
inline int32_t SignExtend(int N, int32_t value) {
return static_cast<int32_t>(static_cast<uint32_t>(value) << (32 - N)) >>
(32 - N);
}
inline intx_t sign_extend(int8_t x) {
return static_cast<intx_t>(x);
}
inline intx_t sign_extend(int16_t x) {
return static_cast<intx_t>(x);
}
inline intx_t sign_extend(int32_t x) {
return static_cast<intx_t>(x);
}
inline intx_t sign_extend(int64_t x) {
return static_cast<intx_t>(x);
}
inline intx_t sign_extend(uint8_t x) {
return static_cast<intx_t>(static_cast<int8_t>(x));
}
inline intx_t sign_extend(uint16_t x) {
return static_cast<intx_t>(static_cast<int16_t>(x));
}
inline intx_t sign_extend(uint32_t x) {
return static_cast<intx_t>(static_cast<int32_t>(x));
}
inline intx_t sign_extend(uint64_t x) {
return static_cast<intx_t>(static_cast<int64_t>(x));
}
enum Opcode {
LUI = 0b0110111,
AUIPC = 0b0010111,
JAL = 0b1101111,
JALR = 0b1100111,
BRANCH = 0b1100011,
LOAD = 0b0000011,
STORE = 0b0100011,
OPIMM = 0b0010011,
OP = 0b0110011,
MISCMEM = 0b0001111,
SYSTEM = 0b1110011,
OP32 = 0b0111011,
OPIMM32 = 0b0011011,
AMO = 0b0101111,
LOADFP = 0b0000111,
STOREFP = 0b0100111,
FMADD = 0b1000011,
FMSUB = 0b1000111,
FNMSUB = 0b1001011,
FNMADD = 0b1001111,
OPFP = 0b1010011,
};
enum Funct12 {
ECALL = 0,
EBREAK = 1,
};
enum Funct3 {
F3_0 = 0,
F3_1 = 1,
BEQ = 0b000,
BNE = 0b001,
BLT = 0b100,
BGE = 0b101,
BLTU = 0b110,
BGEU = 0b111,
LB = 0b000,
LH = 0b001,
LW = 0b010,
LBU = 0b100,
LHU = 0b101,
LWU = 0b110,
LD = 0b011,
SB = 0b000,
SH = 0b001,
SW = 0b010,
SD = 0b011,
ADDI = 0b000,
SLLI = 0b001,
SLTI = 0b010,
SLTIU = 0b011,
XORI = 0b100,
SRI = 0b101,
ORI = 0b110,
ANDI = 0b111,
ADD = 0b000,
SLL = 0b001,
SLT = 0b010,
SLTU = 0b011,
XOR = 0b100,
SR = 0b101,
OR = 0b110,
AND = 0b111,
FENCE = 0b000,
FENCEI = 0b001,
CSRRW = 0b001,
CSRRS = 0b010,
CSRRC = 0b011,
CSRRWI = 0b101,
CSRRSI = 0b110,
CSRRCI = 0b111,
MUL = 0b000,
MULH = 0b001,
MULHSU = 0b010,
MULHU = 0b011,
DIV = 0b100,
DIVU = 0b101,
REM = 0b110,
REMU = 0b111,
MULW = 0b000,
DIVW = 0b100,
DIVUW = 0b101,
REMW = 0b110,
REMUW = 0b111,
WIDTH8 = 0b000,
WIDTH16 = 0b001,
WIDTH32 = 0b010,
WIDTH64 = 0b011,
S = 0b010,
D = 0b011,
J = 0b000,
JN = 0b001,
JX = 0b010,
FMIN = 0b000,
FMAX = 0b001,
FMINM = 0b010,
FMAXM = 0b011,
FEQ = 0b010,
FLT = 0b001,
FLE = 0b000,
FLTQ = 0b101,
FLEQ = 0b100,
SH1ADD = 0b010,
SH2ADD = 0b100,
SH3ADD = 0b110,
F3_COUNT = 0b001,
MAX = 0b110,
MAXU = 0b111,
MIN = 0b100,
MINU = 0b101,
CLMUL = 0b001,
CLMULH = 0b011,
CLMULR = 0b010,
SEXT = 0b001,
ZEXT = 0b100,
ROL = 0b001,
ROR = 0b101,
BCLR = 0b001,
BEXT = 0b101,
F3_BINV = 0b001,
F3_BSET = 0b001,
CZEROEQZ = 0b101,
CZERONEZ = 0b111,
};
enum Funct7 {
F7_0 = 0,
SRA = 0b0100000,
SUB = 0b0100000,
MULDIV = 0b0000001,
FADDS = 0b0000000,
FSUBS = 0b0000100,
FMULS = 0b0001000,
FDIVS = 0b0001100,
FSQRTS = 0b0101100,
FSGNJS = 0b0010000,
FMINMAXS = 0b0010100,
FCMPS = 0b1010000,
FCLASSS = 0b1110000,
FCVTintS = 0b1100000,
FCVTSint = 0b1101000,
FMVXW = 0b1110000,
FMVWX = 0b1111000,
FADDD = 0b0000001,
FSUBD = 0b0000101,
FMULD = 0b0001001,
FDIVD = 0b0001101,
FSQRTD = 0b0101101,
FSGNJD = 0b0010001,
FMINMAXD = 0b0010101,
FCVTS = 0b0100000,
FCVTD = 0b0100001,
FCMPD = 0b1010001,
FCLASSD = 0b1110001,
FCVTintD = 0b1100001,
FCVTDint = 0b1101001,
FMVXD = 0b1110001,
FMVDX = 0b1111001,
FMVHXD = 0b1110001,
FMVPDX = 0b1011001,
ADDUW = 0b0000100,
SHADD = 0b0010000,
SLLIUW = 0b0000100,
COUNT = 0b0110000,
MINMAXCLMUL = 0b0000101,
ROTATE = 0b0110000,
BCLRBEXT = 0b0100100,
BINV = 0b0110100,
BSET = 0b0010100,
CZERO = 0b0000111,
};
enum Funct5 {
LR = 0b00010,
SC = 0b00011,
AMOSWAP = 0b00001,
AMOADD = 0b00000,
AMOXOR = 0b00100,
AMOAND = 0b01100,
AMOOR = 0b01000,
AMOMIN = 0b10000,
AMOMAX = 0b10100,
AMOMINU = 0b11000,
AMOMAXU = 0b11100,
LOADORDERED = 0b00110,
STOREORDERED = 0b00111,
};
enum Funct2 {
F2_S = 0b00,
F2_D = 0b01,
};
enum RoundingMode {
RNE = 0b000, // Round to Nearest, ties to Even
RTZ = 0b001, // Round toward Zero
RDN = 0b010, // Round Down (toward negative infinity)
RUP = 0b011, // Round Up (toward positive infinity)
RMM = 0b100, // Round to nearest, ties to Max Magnitude
DYN = 0b111, // Dynamic rounding mode
};
enum FcvtRs2 {
W = 0b00000,
WU = 0b00001,
L = 0b00010,
LU = 0b00011,
};
enum FClass {
kFClassNegInfinity = 1 << 0,
kFClassNegNormal = 1 << 1,
kFClassNegSubnormal = 1 << 2,
kFClassNegZero = 1 << 3,
kFClassPosZero = 1 << 4,
kFClassPosSubnormal = 1 << 5,
kFClassPosNormal = 1 << 6,
kFClassPosInfinity = 1 << 7,
kFClassSignallingNan = 1 << 8,
kFClassQuietNan = 1 << 9,
};
enum HartEffects {
kWrite = 1 << 0,
kRead = 1 << 1,
kOutput = 1 << 2,
kInput = 1 << 3,
kMemory = kWrite | kRead,
kIO = kOutput | kInput,
kAll = kMemory | kIO,
};
const intptr_t kReleaseShift = 25;
const intptr_t kAcquireShift = 26;
constexpr uint32_t kFlisConstants[32] = {
0xbf800000, // -1.0
0x00800000, // min positive normal
0x37800000, // 2^-16
0x38000000, // 2^-15
0x3b800000, // 2^-8
0x3c000000, // 2^-7
0x3d800000, // 0.0625
0x3e000000, // 0.125
0x3e800000, // 0.25
0x3ea00000, // 0.3125
0x3ec00000, // 0.375
0x3ee00000, // 0.4375
0x3f000000, // 0.5
0x3f200000, // 0.625
0x3f400000, // 0.75
0x3f600000, // 0.875
0x3f800000, // 1.0
0x3fa00000, // 1.25
0x3fc00000, // 1.5
0x3fe00000, // 1.75
0x40000000, // 2.0
0x40200000, // 2.5
0x40400000, // 3
0x40800000, // 4