-
Notifications
You must be signed in to change notification settings - Fork 392
/
OMRCodeGenerator.hpp
902 lines (691 loc) · 37.4 KB
/
OMRCodeGenerator.hpp
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
/*******************************************************************************
* Copyright (c) 2000, 2021 IBM Corp. and others
*
* This program and the accompanying materials are made available under
* the terms of the Eclipse Public License 2.0 which accompanies this
* distribution and is available at http://eclipse.org/legal/epl-2.0
* or the Apache License, Version 2.0 which accompanies this distribution
* and is available at https://www.apache.org/licenses/LICENSE-2.0.
*
* This Source Code may also be made available under the following Secondary
* Licenses when the conditions for such availability set forth in the
* Eclipse Public License, v. 2.0 are satisfied: GNU General Public License,
* version 2 with the GNU Classpath Exception [1] and GNU General Public
* License, version 2 with the OpenJDK Assembly Exception [2].
*
* [1] https://www.gnu.org/software/classpath/license.html
* [2] http://openjdk.java.net/legal/assembly-exception.html
*
* SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception
*******************************************************************************/
#ifndef OMR_Z_CODEGENERATOR_INCL
#define OMR_Z_CODEGENERATOR_INCL
/*
* The following #define and typedef must appear before any #includes in this file
*/
#ifndef OMR_CODEGENERATOR_CONNECTOR
#define OMR_CODEGENERATOR_CONNECTOR
namespace OMR { namespace Z { class CodeGenerator; } }
namespace OMR { typedef OMR::Z::CodeGenerator CodeGeneratorConnector; }
#else
#error OMR::Z::CodeGenerator expected to be a primary connector, but an OMR connector is already defined
#endif
#include "compiler/codegen/OMRCodeGenerator.hpp"
#include <stddef.h>
#include <stdint.h>
#include <string.h>
#include "env/FrontEnd.hpp"
#include "codegen/InstOpCode.hpp"
#include "codegen/LinkageConventionsEnum.hpp"
#include "codegen/Machine.hpp"
#include "codegen/RealRegister.hpp"
#include "codegen/RecognizedMethods.hpp"
#include "codegen/RegisterConstants.hpp"
#include "codegen/ScratchRegisterManager.hpp"
#include "codegen/Snippet.hpp"
#include "codegen/TreeEvaluator.hpp"
#include "compile/Compilation.hpp"
#include "compile/ResolvedMethod.hpp"
#include "control/Options.hpp"
#include "control/Options_inlines.hpp"
#include "cs2/hashtab.h"
#include "env/CompilerEnv.hpp"
#include "env/CPU.hpp"
#include "env/jittypes.h"
#include "env/PersistentInfo.hpp"
#include "env/Processors.hpp"
#include "env/TRMemory.hpp"
#include "il/Block.hpp"
#include "il/DataTypes.hpp"
#include "il/ILOpCodes.hpp"
#include "il/ILOps.hpp"
#include "il/LabelSymbol.hpp"
#include "il/Node.hpp"
#include "il/Node_inlines.hpp"
#include "il/ResolvedMethodSymbol.hpp"
#include "il/TreeTop.hpp"
#include "il/TreeTop_inlines.hpp"
#include "infra/Array.hpp"
#include "infra/Assert.hpp"
#include "infra/BitVector.hpp"
#include "infra/Flags.hpp"
#include "infra/List.hpp"
#include "optimizer/DataFlowAnalysis.hpp"
#include "ras/Debug.hpp"
#include "runtime/Runtime.hpp"
#include "env/IO.hpp"
#include "z/codegen/S390OutOfLineCodeSection.hpp"
#include "codegen/BackingStore.hpp"
#include "codegen/Relocation.hpp"
#include "infra/TRlist.hpp"
class TR_BackingStore;
class TR_GCStackMap;
class TR_OpaquePseudoRegister;
class TR_PseudoRegister;
class TR_RegisterCandidate;
namespace TR { class S390ConstantDataSnippet; }
namespace TR { class S390ConstantInstructionSnippet; }
namespace TR { class S390EyeCatcherDataSnippet; }
namespace TR { class S390ImmInstruction; }
class TR_S390OutOfLineCodeSection;
class TR_S390ScratchRegisterManager;
namespace TR { class S390WritableDataSnippet; }
class TR_StorageReference;
namespace OMR { class Linkage; }
namespace TR { class CodeGenerator; }
namespace TR { class Instruction; }
namespace TR { class LabelSymbol; }
namespace TR { class MemoryReference; }
namespace TR { class Optimizer; }
namespace TR { class RegStarRef; }
namespace TR { class Register; }
namespace TR { class RegisterDependencyConditions; }
namespace TR { class RegisterIterator; }
namespace TR { class RegisterPair; }
namespace TR { class Symbol; }
namespace TR { class SymbolReference; }
namespace TR { class SystemLinkage; }
extern int64_t getIntegralValue(TR::Node* node);
#if defined(TR_TARGET_64BIT)
#define UPPER_4_BYTES(x) ((x) >> 32)
#define LOWER_4_BYTES(x) ((x) & 0xffffffff)
#else
// fake it to allow warning-free compilation on 32 bit systems
#define UPPER_4_BYTES(x) (x)
#define LOWER_4_BYTES(x) (x)
#endif
// Multi Code Cache Routines for checking whether an entry point is within reach of a BASRL.
#define NEEDS_TRAMPOLINE(target, rip, cg) (cg->directCallRequiresTrampoline((intptr_t)target, (intptr_t)rip))
#define TR_MAX_MVC_SIZE 256
#define TR_MAX_CLC_SIZE 256
#define TR_MIN_SS_DISP 0
#define TR_MAX_SS_DISP 4095
#define TR_MIN_RX_DISP 0
#define TR_MAX_RX_DISP 4095
#define TR_MEMCPY_PAD_DST_LEN_INDEX 1
#define TR_MEMCPY_PAD_SRC_LEN_INDEX 3
#define TR_MEMCPY_PAD_MAX_LEN_INDEX 5
#define TR_MEMCPY_PAD_EQU_LEN_INDEX 6
#define MVCL_THRESHOLD 16777216
#define USE_CURRENT_DFP_ROUNDING_MODE (uint8_t)0x0
enum TR_MemCpyPadTypes
{
OneByte,
TwoByte,
ND_OneByte,
ND_TwoByte,
InvalidType
};
struct TR_S390BinaryEncodingData : public TR_BinaryEncodingData
{
int32_t estimate;
TR::Instruction *cursorInstruction;
TR::Instruction *jitTojitStart;
TR::Instruction *preProcInstruction;
int32_t loadArgSize;
};
namespace OMR
{
namespace Z
{
class OMR_EXTENSIBLE CodeGenerator : public OMR::CodeGenerator
{
public:
void preLowerTrees();
struct TR_BranchPreloadCallData
{
TR_ALLOC(TR_Memory::BranchPreloadCallData)
TR::Instruction *_callInstr;
TR::LabelSymbol *_callLabel;
TR::Block *_callBlock;
TR::SymbolReference * _callSymRef;
int32_t _frequency;
TR_BranchPreloadCallData() { _frequency = -1;}
TR_BranchPreloadCallData(TR::Instruction *i,TR::LabelSymbol *l,TR::Block *b,TR::SymbolReference *s, int32_t f)
:_callInstr(i),_callLabel(l),_callBlock(b),_callSymRef(s),_frequency(f){}
};
struct TR_BranchPreloadData
{
TR::Instruction *_returnInstr;
TR::LabelSymbol *_returnLabel;
TR::Block *_returnBlock;
int32_t _frequency;
bool _insertBPPInEpilogue;
TR_BranchPreloadData() { _frequency = -1; _insertBPPInEpilogue = false; }
};
TR_BranchPreloadData _hottestReturn;
TR_BranchPreloadCallData _outlineCall;
TR_BranchPreloadCallData _outlineArrayCall;
TR::list<TR::Register*> *getFirstTimeLiveOOLRegisterList() {return _firstTimeLiveOOLRegisterList;}
TR::list<TR::Register*> *setFirstTimeLiveOOLRegisterList(TR::list<TR::Register*> *r) {return _firstTimeLiveOOLRegisterList = r;}
TR::list<TR_BranchPreloadCallData*> *_callsForPreloadList;
TR::list<TR_BranchPreloadCallData*> * getCallsForPreloadList() { return _callsForPreloadList; }
void createBranchPreloadCallData(TR::LabelSymbol *callLabel, TR::SymbolReference * callSymRef, TR::Instruction * instr);
void insertInstructionPrefetches();
void insertInstructionPrefetchesForCalls(TR_BranchPreloadCallData * data);
bool hasWarmCallsBeforeReturn();
/**
* @brief Answers whether a method call is implemented using an internal runtime
* helper routine (ex. a j2iTransition)
*
* @param[in] sym : The symbol holding the call information
*
* @return : true if the call is represented by a helper; false otherwise.
*/
bool callUsesHelperImplementation(TR::Symbol *sym) { return false; }
/**
* @brief Answers whether a trampoline is required for a direct call instruction to
* reach a target address.
*
* @param[in] targetAddress : the absolute address of the call target
* @param[in] sourceAddress : the absolute address of the call instruction
*
* @return : true if a trampoline is required; false otherwise.
*/
bool directCallRequiresTrampoline(intptr_t targetAddress, intptr_t sourceAddress);
/**
* \brief Tells the optimzers and codegen whether a load constant node should be rematerialized.
*
* \details Large constants should be materialized (constant node should be commoned up)
* because loading them as immediate values is expensive.
*
* A constant is large if it's outside of the range specified by the largest negative
* const and smallest positive const. And the ranges are hardware platform dependent.
*/
bool materializesLargeConstants() { return true; }
bool shouldValueBeInACommonedNode(int64_t value);
int64_t getLargestNegConstThatMustBeMaterialized() {return ((-1ll) << 31) - 1;} // min 32bit signed integer minus 1
int64_t getSmallestPosConstThatMustBeMaterialized() {return ((int64_t)0x000000007FFFFFFF) + 1;} // max 32bit signed integer plus 1
void beginInstructionSelection();
void endInstructionSelection();
void checkIsUnneededIALoad(TR::Node *parent, TR::Node* node, TR::TreeTop *tt);
void lowerTreesWalk(TR::Node * parent, TR::TreeTop * treeTop, vcount_t visitCount);
void lowerTreeIfNeeded(TR::Node *node, int32_t childNumber, TR::Node *parent, TR::TreeTop *tt);
void lowerTreesPropagateBlockToNode(TR::Node *node);
protected:
CodeGenerator(TR::Compilation *comp);
public:
void initialize();
TR::Linkage *createLinkage(TR_LinkageConventions lc);
bool anyNonConstantSnippets();
bool anyLitPoolSnippets();
bool getSupportsEncodeUtf16BigWithSurrogateTest();
TR_S390ScratchRegisterManager* generateScratchRegisterManager(int32_t capacity = 8);
bool canTransformUnsafeCopyToArrayCopy();
bool supportsInliningOfIsInstance();
bool supports32bitAiadd() {return OMR::Z::CodeGenerator::comp()->target().is64Bit();}
void addPICsListForInterfaceSnippet(TR::S390ConstantDataSnippet * ifcSnippet, TR::list<TR_OpaqueClassBlock*> * PICSlist);
TR::list<TR_OpaqueClassBlock*> * getPICsListForInterfaceSnippet(TR::S390ConstantDataSnippet * ifcSnippet);
void doInstructionSelection();
void doRegisterAssignment(TR_RegisterKinds kindsToAssign);
bool loadOrStoreAddressesMatch(TR::Node *node1, TR::Node *node2);
bool reliesOnAParticularSignEncoding(TR::Node *node);
void recordRegisterAssignment(TR::Register *assignedReg, TR::Register *virtualReg);
void doBinaryEncoding();
void AddFoldedMemRefToStack(TR::MemoryReference * mr);
void RemoveMemRefFromStack(TR::MemoryReference * mr);
void StopUsingEscapedMemRefsRegisters(int32_t topOfMemRefStackBeforeEvaluation);
bool supportsNonHelper(TR::SymbolReferenceTable::CommonNonhelperSymbol symbol);
bool supportsDirectJNICallsForAOT() { return true;}
bool shouldYankCompressedRefs() { return true; }
bool supportsJITFreeSystemStackPointer() { return false; }
TR::RegisterIterator *getVRFRegisterIterator() {return _vrfRegisterIterator; }
TR::RegisterIterator *setVRFRegisterIterator(TR::RegisterIterator *iter) {return _vrfRegisterIterator = iter;}
bool supportsLengthMinusOneForMemoryOpts() {return true;}
bool codegenSupportsLoadlessBNDCheck() {return OMR::Z::CodeGenerator::comp()->target().cpu.isAtLeast(OMR_PROCESSOR_S390_ZEC12);}
TR::Register *evaluateLengthMinusOneForMemoryOps(TR::Node *, bool , bool &lenMinusOne);
virtual TR_GlobalRegisterNumber getGlobalRegisterNumber(uint32_t realRegNum);
TR::RegisterDependencyConditions* createDepsForRRMemoryInstructions(TR::Node *node, TR::RegisterPair * sourceReg, TR::RegisterPair * targetReg, uint8_t extraDeps=0);
// Allocate a pair with inherent consecutive association
virtual TR::RegisterPair* allocateConsecutiveRegisterPair();
virtual TR::RegisterPair* allocateConsecutiveRegisterPair(TR::Register* lowRegister, TR::Register* highRegister);
virtual TR::RegisterPair* allocateFPRegisterPair();
virtual TR::RegisterPair* allocateFPRegisterPair(TR::Register* lowRegister, TR::Register* highRegister);
void processUnusedNodeDuringEvaluation(TR::Node *node);
void apply12BitLabelRelativeRelocation(int32_t * cursor, TR::LabelSymbol *, bool isCheckDisp = true);
void apply16BitLabelRelativeRelocation(int32_t * cursor, TR::LabelSymbol *, int8_t addressDifferenceDivisor, bool isInstrOffset = false);
void apply16BitLabelRelativeRelocation(int32_t * cursor, TR::LabelSymbol *);
void apply32BitLabelRelativeRelocation(int32_t * cursor, TR::LabelSymbol *);
void setUnavailableRegisters(TR::Block *b, TR_BitVector &unavailableRegisters);
void resetGlobalRegister(TR::RealRegister::RegNum reg, TR_BitVector &globalRegisters);
void setGlobalRegister(TR::RealRegister::RegNum reg, TR_BitVector &globalRegisters);
void setRegister(TR::RealRegister::RegNum reg, TR_BitVector ®isters);
void removeUnavailableRegisters(TR_RegisterCandidate * rc, TR::Block * * blocks, TR_BitVector & availableRegisters);
void setUnavailableRegistersUsage(TR_Array<TR_BitVector> &_liveOnEntryUsage, TR_Array<TR_BitVector> &_liveOnExitUsage);
void genMemCpy(TR::MemoryReference *targetMR, TR::Node *targetNode, TR::MemoryReference *sourceMR, TR::Node *sourceNode, int64_t copySize);
void genMemClear(TR::MemoryReference *targetMR, TR::Node *targetNode, int64_t clearSize);
void genCopyFromLiteralPool(TR::Node *node, int32_t bytesToCopy, TR::MemoryReference *targetMR, size_t litPoolOffset, TR::InstOpCode::Mnemonic op = TR::InstOpCode::MVC);
bool useMVCLForMemcpyWithPad(TR::Node *node, TR_MemCpyPadTypes type);
bool isValidCompareConst(int64_t compareConst);
bool isIfFoldable(TR::Node *node, int64_t compareConst);
TR::Instruction *genLoadAddressToRegister(TR::Register *reg, TR::MemoryReference *origMR, TR::Node *node, TR::Instruction *preced=NULL);
bool useRippleCopyOrXC(size_t size, char *lit);
bool isCompressedClassPointerOfObjectHeader(TR::Node * node);
/**
* @brief Create a literal pool entry for the given value.
*
* @details
* This function must be implemented and will assert if called.
* See issue eclipse/omr#2180 for details.
*/
size_t findOrCreateLiteral(void *value, size_t len);
bool usesImplicit64BitGPRs(TR::Node *node);
bool nodeMayCauseException(TR::Node *node);
bool nodeRequiresATemporary(TR::Node *node);
bool endHintOnOperation(TR::Node *node);
bool endAccumulatorSearchOnOperation(TR::Node *node);
bool isStorageReferenceType(TR::Node *node);
TR::Register *allocateClobberableRegister(TR::Register *srcRegister);
/** Different from evaluateNode in that it returns a clobberable register */
TR::Register *gprClobberEvaluate(TR::Node *node, bool force_copy=false, bool ignoreRefCount = false);
TR::Register *fprClobberEvaluate(TR::Node *node);
TR_OpaquePseudoRegister *ssrClobberEvaluate(TR::Node *node, TR::MemoryReference *sourceMR);
//Convenience accessor methods
TR::Linkage *getS390Linkage();
TR::RealRegister *getStackPointerRealRegister(TR::Symbol *symbol = NULL);
TR::RealRegister *getEntryPointRealRegister();
TR::RealRegister *getReturnAddressRealRegister();
TR::RealRegister::RegNum getEntryPointRegister();
TR::RealRegister::RegNum getReturnAddressRegister();
TR::RealRegister *getMethodMetaDataRealRegister();
TR::RealRegister *getLitPoolRealRegister();
void buildRegisterMapForInstruction(TR_GCStackMap *map);
// BCDCHK node
TR::Node * _currentCheckNode;
void setCurrentCheckNodeBeingEvaluated(TR::Node * n) { _currentCheckNode = n; }
TR::Node * getCurrentCheckNodeBeingEvaluated(){ return _currentCheckNode; }
// BCDCHK node exception handler label
TR::LabelSymbol* _currentBCDCHKHandlerLabel;
void setCurrentBCDCHKHandlerLabel(TR::LabelSymbol * l) { _currentBCDCHKHandlerLabel = l; }
TR::LabelSymbol* getCurrentBCDCHKHandlerLabel(){ return _currentBCDCHKHandlerLabel; }
TR::RegisterDependencyConditions * _currentBCDRegDeps;
void setCurrentCheckNodeRegDeps(TR::RegisterDependencyConditions * daaDeps) {_currentBCDRegDeps = daaDeps;}
TR::RegisterDependencyConditions * getCurrentCheckNodeRegDeps() {return _currentBCDRegDeps;}
int32_t arrayInitMinimumNumberOfBytes() {return 16;}
bool directLoadAddressMatch(TR::Node *load1, TR::Node *load2, bool trace);
bool isOutOf32BitPositiveRange(int64_t value, bool trace);
int32_t getMaskSize(int32_t leftMostNibble, int32_t nibbleCount);
void setAccumulatorNodeUsage(int32_t n) { _accumulatorNodeUsage = n; }
int32_t getAccumulatorNodeUsage() { return _accumulatorNodeUsage; }
void incAccumulatorNodeUsage() { _accumulatorNodeUsage++; }
bool possiblyConflictingNode(TR::Node *node);
bool foundConflictingNode(TR::Node *node, TR::list<TR::Node*> *conflictingAddressNodes);
void collectConflictingAddressNodes(TR::Node *parent, TR::Node *node, TR::list<TR::Node*> *conflictingAddressNodes);
template <class TR_AliasSetInterface> bool loadAndStoreMayOverlap(TR::Node *store, size_t storeSize, TR::Node *load, size_t loadSize, TR_AliasSetInterface &storeAliases);
bool loadAndStoreMayOverlap(TR::Node *store, size_t storeSize, TR::Node *load, size_t loadSize);
bool checkIfcmpxx(TR::Node *node);
bool checkBitWiseChild(TR::Node *node);
TR_StorageDestructiveOverlapInfo getStorageDestructiveOverlapInfo(TR::Node *src, size_t srcLength, TR::Node *dst, size_t dstLength);
void setBranchOnCountFlag(TR::Node *node, vcount_t visitCount);
bool needs64bitPrecision(TR::Node *node);
virtual bool isUsing32BitEvaluator(TR::Node *node);
virtual bool getSupportsBitPermute();
int32_t getEstimatedExtentOfLitLoop() {return _extentOfLitPool;}
bool supportsBranchPreload() {return _cgFlags.testAny(S390CG_enableBranchPreload);}
void setEnableBranchPreload() {_cgFlags.set(S390CG_enableBranchPreload);}
void setDisableBranchPreload() {_cgFlags.reset(S390CG_enableBranchPreload);}
bool supportsBranchPreloadForCalls() {return _cgFlags.testAny(S390CG_enableBranchPreloadForCalls);}
void setEnableBranchPreloadForCalls() {_cgFlags.set(S390CG_enableBranchPreloadForCalls);}
void setDisableBranchPreloadForCalls() {_cgFlags.reset(S390CG_enableBranchPreloadForCalls);}
bool isOutOfLineHotPath() {return _cgFlags.testAny(S390CG_isOutOfLineHotPath);}
void setIsOutOfLineHotPath(bool val) {_cgFlags.set(S390CG_isOutOfLineHotPath, val);}
bool getExitPointsInMethod() {return _cgFlags.testAny(S390CG_doesExit);}
void setExitPointsInMethod(bool val) {return _cgFlags.set(S390CG_doesExit, val);}
bool isPrefetchNextStackCacheLine() {return _cgFlags.testAny(S390CG_prefetchNextStackCacheLine);}
void setPrefetchNextStackCacheLine(bool val) {return _cgFlags.set(S390CG_prefetchNextStackCacheLine, val);}
// Heap object prefetching
bool enableTLHPrefetching() {return _cgFlags.testAny(S390CG_enableTLHPrefetching);}
void setEnableTLHPrefetching() { _cgFlags.set(S390CG_enableTLHPrefetching);}
// Query to codegen to know if regs are available or not
bool isLitPoolFreeForAssignment();
// REG ASSOCIATION
//
bool enableRegisterAssociations();
bool enableRegisterPairAssociation();
bool canBeAffectedByStoreTagStalls() { return true; }
// Local RA/GRA
TR_RegisterKinds prepareRegistersForAssignment();
// GRA
//
bool prepareForGRA();
TR_GlobalRegisterNumber getLinkageGlobalRegisterNumber(int8_t linkageRegisterIndex, TR::DataType type);
TR_BitVector _globalRegisterBitVectors[TR_numSpillKinds];
virtual TR_BitVector *getGlobalRegisters(TR_SpillKinds kind, TR_LinkageConventions lc){ return &_globalRegisterBitVectors[kind]; }
virtual void simulateNodeEvaluation(TR::Node * node, TR_RegisterPressureState * state, TR_RegisterPressureSummary * summary);
TR_BitVector *getGlobalGPRsPreservedAcrossCalls(){ return &_globalGPRsPreservedAcrossCalls; }
TR_BitVector *getGlobalFPRsPreservedAcrossCalls(){ return &_globalFPRsPreservedAcrossCalls; }
bool considerTypeForGRA(TR::Node *node);
bool considerTypeForGRA(TR::DataType dt);
bool considerTypeForGRA(TR::SymbolReference *symRef);
// Number of assignable GPRs
int32_t getMaximumNumberOfAssignableGPRs();
using OMR::CodeGenerator::getMaximumNumberOfGPRsAllowedAcrossEdge;
int32_t getMaximumNumberOfGPRsAllowedAcrossEdge(TR::Node *);
int32_t getMaximumNumberOfFPRsAllowedAcrossEdge(TR::Node *);
int32_t getMaximumNumberOfVRFsAllowedAcrossEdge(TR::Node *);
int32_t getMaximumNumberOfGPRsAllowedAcrossEdge(TR::Block *);
int32_t getMaximumNumbersOfAssignableGPRs();
int32_t getMaximumNumbersOfAssignableFPRs();
int32_t getMaximumNumbersOfAssignableVRs();
bool allowGlobalRegisterAcrossBranch(TR_RegisterCandidate *, TR::Node *);
void setRealRegisterAssociation(TR::Register *reg,
TR::RealRegister::RegNum realNum);
bool isGlobalRegisterAvailable(TR_GlobalRegisterNumber i, TR::DataType dt);
bool doRematerialization() {return true;}
void dumpDataSnippets(TR::FILE *outFile);
bool getSupportsBitOpCodes() { return true;}
bool getSupportsImplicitNullChecks() { return _cgFlags.testAny(S390CG_implicitNullChecks); }
void setSupportsImplicitNullChecks(bool b) { _cgFlags.set(S390CG_implicitNullChecks, b); }
bool getConditionalMovesEvaluationMode() { return _cgFlags.testAny(S390CG_conditionalMovesEvaluation); }
void setConditionalMovesEvaluationMode(bool b) { _cgFlags.set(S390CG_conditionalMovesEvaluation, b); }
bool getEnableRIOverPrivateLinkage() { return _cgFlags.testAny(S390CG_enableRIOverPrivateLinkage); }
void setEnableRIOverPrivateLinkage(bool b) { _cgFlags.set(S390CG_enableRIOverPrivateLinkage, b); }
bool getCondCodeShouldBePreserved() { return _cgFlags.testAny(S390CG_condCodeShouldBePreserved); }
void setCondCodeShouldBePreserved(bool b) { _cgFlags.set(S390CG_condCodeShouldBePreserved, b); }
uint8_t getFCondMoveBranchOpCond() { return fCondMoveBranchOpCond; }
void setFCondMoveBranchOpCond(TR::InstOpCode::S390BranchCondition b) { fCondMoveBranchOpCond = (getMaskForBranchCondition(b)) & 0xF; }
uint8_t getRCondMoveBranchOpCond() { return 0xF - fCondMoveBranchOpCond; }
bool canUseImmedInstruction(int64_t v);
virtual bool isAddMemoryUpdate(TR::Node * node, TR::Node * valueChild);
bool afterRA() { return _afterRA; }
#ifdef DEBUG
void dumpPreGPRegisterAssignment(TR::Instruction *);
void dumpPostGPRegisterAssignment(TR::Instruction *, TR::Instruction *);
// Internal local RA counters for self evaluation
void clearTotalSpills() {_totalColdSpills=0; _totalHotSpills=0; }
void clearTotalRegisterXfers() {_totalColdRegisterXfers=0; _totalHotRegisterXfers=0;}
void clearTotalRegisterMoves() {_totalColdRegisterMoves=0; _totalHotRegisterMoves=0;}
// current RA block is only valid during register allocation pass and is only used for debug
TR::Block * getCurrentRABlock() { return _curRABlock; }
void setCurrentRABlock(TR::Block * block) { _curRABlock = block; }
void incTotalSpills();
void incTotalRegisterXfers();
void incTotalRegisterMoves();
void printStats(int32_t);
#endif
TR_S390OutOfLineCodeSection *findS390OutOfLineCodeSectionFromLabel(TR::LabelSymbol *label);
TR::Instruction *generateNop(TR::Node *node, TR::Instruction *preced=0, TR_NOPKind nopKind=TR_NOPStandard);
/** \brief
* Inserts padding (NOP) instructions in the instruction stream.
*
* \param node
* The node with which the generated instruction will be associated.
*
* \param cursor
* The instruction following which the padding instructions will be inserted.
*
* \param size
* The size in number of bytes of how much padding to insert. This value can be one of 0, 2, 4, or 6.
*
* \param prependCursor
* Determines whether the padding instructions will be inserted before or after \param cursor.
*
* \return
* The last padding instruction generated, or \param cursor if \param size is zero.
*/
TR::Instruction* insertPad(TR::Node* node, TR::Instruction* cursor, uint32_t size, bool prependCursor);
struct TR_S390ConstantDataSnippetKey
{
void * c;
uint32_t size;
TR::Node *node;
};
struct constantHashInfo
{
static CS2::HashValue Hash(const TR_S390ConstantDataSnippetKey & key, const CS2::HashValue hv = CS2::CS2_FNV_OFFSETBASIS)
{
return CS2::Hash_FNV((const unsigned char*)key.c,key.size, hv);
}
static bool Equal(const TR_S390ConstantDataSnippetKey & key1,const TR_S390ConstantDataSnippetKey & key2)
{
if(key1.size != key2.size)
return false;
if (key1.node != key2.node)
return false;
switch (key1.size)
{
case 4:
return *((int32_t *) key2.c) == *((int32_t *) key1.c);
case 8:
return *((int64_t *)key2.c) == *((int64_t *) key1.c);
case 2:
return *((int16_t *)key2.c) == *((int16_t *)key1.c);
case 256:
return memcmp(key1.c, key2.c, 256) == 0;
}
return false;
}
};
typedef CS2::HashTable<TR_S390ConstantDataSnippetKey,TR::S390ConstantDataSnippet *, TR::Allocator, constantHashInfo> TR_ConstantSnippetHash;
typedef TR_ConstantSnippetHash::Cursor TR_ConstHashCursor;
/** First Snippet (can be AddressSnippet or ConstantSnippet) */
TR::Snippet *getFirstSnippet();
// Constant Data List functions
int32_t setEstimatedOffsetForConstantDataSnippets();
int32_t setEstimatedLocationsForDataSnippetLabels(int32_t estimatedSnippetStart);
void emitDataSnippets();
bool hasDataSnippets() { return (_constantList.empty() && _writableList.empty() && _snippetDataList.empty() && _constantHash.IsEmpty()) ? false : true; }
TR::list<TR::S390ConstantDataSnippet*> &getConstantInstructionSnippets() { return _constantList; }
TR::list<TR::S390ConstantDataSnippet*> &getConstantDataStringSnippets() { return _constantList; }
TR_ConstHashCursor getConstantDataSnippets() { return _constantHashCur;}
TR::S390ConstantDataSnippet * getConstantDataSnippet(CS2::HashIndex hi) { return _constantHash.DataAt(hi);}
TR::S390ConstantDataSnippet * create64BitLiteralPoolSnippet(TR::DataType dt, int64_t value);
TR::S390ConstantDataSnippet * createLiteralPoolSnippet(TR::Node * node);
TR::S390ConstantInstructionSnippet *createConstantInstruction(TR::Node *node, TR::Instruction * instr);
TR::S390ConstantDataSnippet *findOrCreateConstant(TR::Node *, void *c, uint16_t size);
TR::S390ConstantDataSnippet *findOrCreate2ByteConstant(TR::Node *, int16_t c);
TR::S390ConstantDataSnippet *findOrCreate4ByteConstant(TR::Node *, int32_t c);
TR::S390ConstantDataSnippet *findOrCreate8ByteConstant(TR::Node *, int64_t c);
TR::S390ConstantDataSnippet *Create4ByteConstant(TR::Node *, int32_t c, bool writable);
TR::S390ConstantDataSnippet *Create8ByteConstant(TR::Node *, int64_t c, bool writable);
TR::S390ConstantDataSnippet *CreateConstant(TR::Node *, void *c, uint16_t size, bool writable);
TR::S390ConstantDataSnippet *getFirstConstantData();
// Writable Data List functions
bool hasWritableDataSnippets() { return _writableList.empty() ? false : true; }
TR::S390WritableDataSnippet *CreateWritableConstant(TR::Node *);
// OutOfLineCodeSection List functions
TR::list<TR_S390OutOfLineCodeSection*> &getS390OutOfLineCodeSectionList() {return _outOfLineCodeSectionList;}
TR_S390OutOfLineCodeSection *findOutLinedInstructionsFromLabel(TR::LabelSymbol *label);
TR::Instruction *generateDebugCounterBump(TR::Instruction *cursor, TR::DebugCounterBase *counter, int32_t delta, TR::RegisterDependencyConditions *cond);
TR::Instruction *generateDebugCounterBump(TR::Instruction *cursor, TR::DebugCounterBase *counter, TR::Register *deltaReg, TR::RegisterDependencyConditions *cond);
TR::Instruction *generateDebugCounterBump(TR::Instruction *cursor, TR::DebugCounterBase *counter, int32_t delta, TR_ScratchRegisterManager &srm);
TR::Instruction *generateDebugCounterBump(TR::Instruction *cursor, TR::DebugCounterBase *counter, TR::Register *deltaReg, TR_ScratchRegisterManager &srm);
// Snippet Data functions
void addDataConstantSnippet(TR::S390ConstantDataSnippet * snippet);
// Transient Long Registers
TR_Array<TR::Register *> &getTransientLongRegisters() {return _transientLongRegisters;}
void freeAndResetTransientLongs();
uint32_t registerBitMask(int32_t reg)
{
return 1 << (reg-1);
}
bool opCodeIsNoOpOnThisPlatform(TR::ILOpCode &opCode);
bool internalPointerSupportImplemented();
// list of branch unconditional relative instructions used for patching entry point
// need to be updated with correct offset to sampling preprologue
TR::list<TR::Instruction*> _recompPatchInsnList;
bool supportsFusedMultiplyAdd() {return true;}
bool supportsSinglePrecisionSQRT() {return true;}
bool isAddressScaleIndexSupported(int32_t scale) { if (scale <= 2) return true; return false; }
using OMR::CodeGenerator::getSupportsConstantOffsetInAddressing;
bool getSupportsConstantOffsetInAddressing(int64_t value);
void enableLiteralPoolRegisterForGRA ();
void setOnDemandLiteralPoolRun(bool val) { _cgFlags.set(S390CG_literalPoolOnDemandOnRun, val); }
bool isLiteralPoolOnDemandOn () { return _cgFlags.testAny(S390CG_literalPoolOnDemandOnRun); }
virtual void setGlobalStaticBaseRegisterOn(bool val) { _cgFlags.set(S390CG_globalStaticBaseRegisterOn, val); }
virtual bool isGlobalStaticBaseRegisterOn () { return _cgFlags.testAny(S390CG_globalStaticBaseRegisterOn); }
virtual void setGlobalStaticBaseRegisterOnFlag();
virtual void setGlobalPrivateStaticBaseRegisterOn(bool val) { _cgFlags.set(S390CG_globalPrivateStaticBaseRegisterOn, val); }
virtual bool isGlobalPrivateStaticBaseRegisterOn () { return _cgFlags.testAny(S390CG_globalPrivateStaticBaseRegisterOn); }
bool canUseRelativeLongInstructions(int64_t value);
bool supportsOnDemandLiteralPool();
bool supportsDirectIntegralLoadStoresFromLiteralPool();
void setCanExceptByTrap(bool val) { _cgFlags.set(S390CG_canExceptByTrap, val); }
virtual bool canExceptByTrap() { return _cgFlags.testAny(S390CG_canExceptByTrap); }
TR_BackingStore *getLocalF2ISpill();
TR_BackingStore *getLocalD2LSpill();
// The reusable temp slot is an 8-byte scalar temp that gets mapped to the stack
// the first time allocateReusableTempSlot() is called. This temp is meant to
// be used for short periods of time.
TR::SymbolReference* allocateReusableTempSlot();
void freeReusableTempSlot();
bool isActiveCompareCC(TR::InstOpCode::Mnemonic opcd, TR::Register* tReg, TR::Register* sReg);
bool isActiveArithmeticCC(TR::Register* tstReg);
bool isActiveLogicalCC(TR::Node* ccNode, TR::Register* tstReg);
bool mulDecompositionCostIsJustified(int32_t numOfOperations, char bitPosition[], char operationType[], int64_t value);
bool canUseGoldenEagleImmediateInstruction( int32_t value )
{
return true;
};
bool canUseGoldenEagleImmediateInstruction( int64_t value )
{
return value >= GE_MIN_IMMEDIATE_VAL && value <= GE_MAX_IMMEDIATE_VAL;
};
/** Checks if the immediate value can fit in 32-bit immediate field that is unsigned. */
bool canUseGoldenEagleUnsignedImmediateInstruction(int64_t value)
{
return value == (value & GE_MAX_UNSIGNED_IMMEDIATE_VAL);
}
/** LL: Sign extended the specified number of high order bits in the register. */
bool signExtendedHighOrderBits( TR::Node * node, TR::Register * targetRegister, uint32_t numberOfBits );
/** LL: Sign extended the specified number of high order bits in the register, use for 64 bits. */
bool signExtendedHighOrderBits( TR::Node * node, TR::Register * targetRegister, TR::Register * srcRegister, uint32_t numberOfBits );
/** LL: Zero filled the specified number of high order bits in the register. */
bool clearHighOrderBits( TR::Node * node, TR::Register * targetRegister, uint32_t numberOfBits );
/** LL: Zero filled the specified number of high order bits in the register, use for 64 bits. */
bool clearHighOrderBits( TR::Node * node, TR::Register * targetRegister, TR::Register * srcRegister, uint32_t numberOfBits );
void replaceInst(TR::Instruction* old, TR::Instruction* curr);
static bool isILOpCodeSupported(TR::ILOpCodes);
void setUsesZeroBasePtr( bool v = true );
bool getUsesZeroBasePtr();
int16_t getMinShortForLongCompareNarrower() { return 0; }
int8_t getMinByteForLongCompareNarrower() { return 0; }
bool IsInMemoryType(TR::DataType type);
int32_t arrayTranslateMinimumNumberOfElements(bool isByteSource, bool isByteTarget) { if (isByteSource) return 25; else return 5; }
int32_t arrayTranslateAndTestMinimumNumberOfIterations() { return 4; }
/** Yank the scaling opp up a tree in lowerTrees */
bool yankIndexScalingOp() {return true;}
bool excludeInvariantsFromGRAEnabled();
/**
* array translate on TRex and below requires that the translate table be page-aligned
* for TRTO/TRTT and double-word aligned for TROT/TROO
* array translate takes awhile to initialize - for very short translations, the original
* loop of instructions should be driven instead of the translate instruction
* LL: For Golden Eagle, TRTO/TRTT is also double-word aligned.
*/
int32_t arrayTranslateTableRequiresAlignment(bool isByteSource, bool isByteTarget)
{
return 7;
}
uint32_t getJitMethodEntryAlignmentBoundary();
// LL: move to .cpp
bool bitwiseOpNeedsLiteralFromPool(TR::Node *parent, TR::Node *child);
virtual bool isDispInRange(int64_t disp);
bool getSupportsOpCodeForAutoSIMD(TR::ILOpCode, TR::DataType);
TR::Instruction *_ccInstruction;
TR::Instruction* ccInstruction() { return _ccInstruction; }
void setCCInstruction(TR::Instruction* cc) { _ccInstruction = cc; }
#define TR_DEFAULT_DATA_SNIPPET_EXPONENT 7
int32_t constantDataSnippetExponent() { return TR_DEFAULT_DATA_SNIPPET_EXPONENT; } // 1 << 7 = 128 byte max size for each constantDataSnippet
private:
TR_BitVector _globalGPRsPreservedAcrossCalls;
TR_BitVector _globalFPRsPreservedAcrossCalls;
TR::S390ImmInstruction *_returnTypeInfoInstruction;
int32_t _extentOfLitPool; // excludes snippets
protected:
TR::list<TR::S390ConstantDataSnippet*> _constantList;
TR::list<TR::S390ConstantDataSnippet*> _snippetDataList;
TR::list<TR::Register*> *_firstTimeLiveOOLRegisterList;
private:
// TODO: These should move into the base class. There also seems to be a little overlap between these and
// _firstInstruction and _appendInstruction. We should likely expose a getLastInstruction API as well. The former
// API should return _methodBegin and latter _methodEnd always. The append instruction will be the instruction
// preceeding _methodEnd.
TR::Instruction* _methodBegin;
TR::Instruction* _methodEnd;
TR::list<TR::S390WritableDataSnippet*> _writableList;
TR::list<TR_S390OutOfLineCodeSection*> _outOfLineCodeSectionList;
CS2::HashTable<TR::Register *, TR::RealRegister::RegNum, TR::Allocator> _previouslyAssignedTo;
TR_ConstantSnippetHash _constantHash;
TR_ConstHashCursor _constantHashCur;
TR_HashTab * _interfaceSnippetToPICsListHashTab;
TR::RegisterIterator *_vrfRegisterIterator;
TR_Array<TR::Register *> _transientLongRegisters;
/** For aggregate type GRA */
bool considerAggregateSizeForGRA(int32_t size);
#ifdef DEBUG
uint32_t _totalColdSpills;
uint32_t _totalColdRegisterXfers;
uint32_t _totalColdRegisterMoves;
uint32_t _totalHotSpills;
uint32_t _totalHotRegisterXfers;
uint32_t _totalHotRegisterMoves;
TR::Block * _curRABlock;
#endif
bool TR_LiteralPoolOnDemandOnRun;
TR_BackingStore* _localF2ISpill;
TR_BackingStore* _localD2LSpill;
uint8_t fCondMoveBranchOpCond;
TR::SymbolReference* _reusableTempSlot;
CS2::HashTable<ncount_t, bool, TR::Allocator> _nodesToBeEvaluatedInRegPairs;
protected:
bool _afterRA;
flags32_t _cgFlags;
/** Miscellaneous S390CG boolean flags. */
typedef enum
{
// Available = 0x00000001,
// Available = 0x00000002,
// Available = 0x00000004,
S390CG_addStorageReferenceHints = 0x00000008,
S390CG_isOutOfLineHotPath = 0x00000010,
S390CG_literalPoolOnDemandOnRun = 0x00000020,
S390CG_prefetchNextStackCacheLine = 0x00000040,
S390CG_doesExit = 0x00000080,
// Available = 0x00000100,
S390CG_implicitNullChecks = 0x00000200,
S390CG_reusableSlotIsFree = 0x00000400,
S390CG_conditionalMovesEvaluation = 0x00000800,
S390CG_usesZeroBasePtr = 0x00001000,
S390CG_enableRIOverPrivateLinkage = 0x00002000,
S390CG_condCodeShouldBePreserved = 0x00004000,
S390CG_enableBranchPreload = 0x00008000,
S390CG_globalStaticBaseRegisterOn = 0x00010000,
// Available = 0x00020000,
S390CG_canExceptByTrap = 0x00040000,
S390CG_enableTLHPrefetching = 0x00080000,
S390CG_enableBranchPreloadForCalls = 0x00100000,
S390CG_globalPrivateStaticBaseRegisterOn = 0x00200000
} TR_S390CGFlags;
};
}
}
class TR_S390ScratchRegisterManager : public TR_ScratchRegisterManager
{
public:
TR_S390ScratchRegisterManager(int32_t capacity, TR::CodeGenerator *cg) : TR_ScratchRegisterManager(capacity, cg) {}
};
#ifdef J9_PROJECT_SPECIFIC
uint32_t CalcCodeSize(TR::Instruction *start,TR::Instruction *end);
#endif
#endif