48 public SPARCTestAssembler(CodeCacheProvider codeCache, TestHotSpotVMConfig config) { |
48 public SPARCTestAssembler(CodeCacheProvider codeCache, TestHotSpotVMConfig config) { |
49 super(codeCache, config, 0, 16, SPARCKind.WORD, SPARC.l0, SPARC.l1, SPARC.l2, SPARC.l3, SPARC.l4, SPARC.l5, SPARC.l6, SPARC.l7); |
49 super(codeCache, config, 0, 16, SPARCKind.WORD, SPARC.l0, SPARC.l1, SPARC.l2, SPARC.l3, SPARC.l4, SPARC.l5, SPARC.l6, SPARC.l7); |
50 } |
50 } |
51 |
51 |
52 private void emitOp2(Register rd, int op2, int imm22) { |
52 private void emitOp2(Register rd, int op2, int imm22) { |
|
53 assert isSimm(imm22, 22); |
53 code.emitInt((0b00 << 30) | (rd.encoding << 25) | (op2 << 22) | imm22); |
54 code.emitInt((0b00 << 30) | (rd.encoding << 25) | (op2 << 22) | imm22); |
54 } |
55 } |
55 |
56 |
56 private void emitOp3(int op, Register rd, int op3, Register rs1, Register rs2) { |
57 private void emitOp3(int op, Register rd, int op3, Register rs1, Register rs2) { |
57 code.emitInt((op << 30) | (rd.encoding << 25) | (op3 << 19) | (rs1.encoding << 14) | rs2.encoding); |
58 code.emitInt((op << 30) | (rd.encoding << 25) | (op3 << 19) | (rs1.encoding << 14) | rs2.encoding); |
58 } |
59 } |
59 |
60 |
60 private void emitOp3(int op, Register rd, int op3, Register rs1, int simm13) { |
61 private void emitOp3(int op, Register rd, int op3, Register rs1, int simm13) { |
|
62 assert isSimm(simm13, 13); |
61 code.emitInt((op << 30) | (rd.encoding << 25) | (op3 << 19) | (rs1.encoding << 14) | (1 << 13) | (simm13 & MASK13)); |
63 code.emitInt((op << 30) | (rd.encoding << 25) | (op3 << 19) | (rs1.encoding << 14) | (1 << 13) | (simm13 & MASK13)); |
62 } |
64 } |
63 |
65 |
64 private void emitNop() { |
66 private void emitNop() { |
65 code.emitInt(1 << 24); |
67 code.emitInt(1 << 24); |
|
68 } |
|
69 |
|
70 /** |
|
71 * Minimum value for signed immediate ranges. |
|
72 */ |
|
73 public static long minSimm(long nbits) { |
|
74 return -(1L << (nbits - 1)); |
|
75 } |
|
76 |
|
77 /** |
|
78 * Maximum value for signed immediate ranges. |
|
79 */ |
|
80 public static long maxSimm(long nbits) { |
|
81 return (1L << (nbits - 1)) - 1; |
|
82 } |
|
83 |
|
84 /** |
|
85 * Test if imm is within signed immediate range for nbits. |
|
86 */ |
|
87 public static boolean isSimm(long imm, int nbits) { |
|
88 return minSimm(nbits) <= imm && imm <= maxSimm(nbits); |
66 } |
89 } |
67 |
90 |
68 @Override |
91 @Override |
69 public void emitPrologue() { |
92 public void emitPrologue() { |
70 // SAVE sp, -128, sp |
93 // SAVE sp, -128, sp |
85 return super.finish(method); |
108 return super.finish(method); |
86 } |
109 } |
87 |
110 |
88 @Override |
111 @Override |
89 public void emitGrowStack(int size) { |
112 public void emitGrowStack(int size) { |
90 emitOp3(0b10, SPARC.sp, 0b000100, SPARC.sp, size); // SUB sp, size, sp |
113 frameSize += size; |
|
114 if (isSimm(size, 13)) { |
|
115 emitOp3(0b10, SPARC.sp, 0b000100, SPARC.sp, size); // SUB sp, size, sp |
|
116 } else { |
|
117 Register r = emitLoadInt(size); |
|
118 emitOp3(0b10, SPARC.sp, 0b000100, SPARC.sp, r); // SUB sp, size, sp |
|
119 } |
91 } |
120 } |
92 |
121 |
93 @Override |
122 @Override |
94 public Register emitIntArg0() { |
123 public Register emitIntArg0() { |
95 return codeCache.getRegisterConfig().getCallingConventionRegisters(HotSpotCallingConventionType.JavaCallee, JavaKind.Int)[0]; |
124 return codeCache.getRegisterConfig().getCallingConventionRegisters(HotSpotCallingConventionType.JavaCallee, JavaKind.Int)[0]; |
101 } |
130 } |
102 |
131 |
103 @Override |
132 @Override |
104 public Register emitLoadInt(int c) { |
133 public Register emitLoadInt(int c) { |
105 Register ret = newRegister(); |
134 Register ret = newRegister(); |
|
135 loadIntToRegister(c, ret); |
|
136 return ret; |
|
137 } |
|
138 |
|
139 private void loadIntToRegister(int c, Register ret) { |
106 int hi = c >>> 10; |
140 int hi = c >>> 10; |
107 int lo = c & ((1 << 10) - 1); |
141 int lo = c & ((1 << 10) - 1); |
108 if (hi == 0) { |
142 if (hi == 0) { |
109 emitOp3(0b10, ret, 0b000010, SPARC.g0, lo); // OR g0, lo, ret |
143 emitOp3(0b10, ret, 0b000010, SPARC.g0, lo); // OR g0, lo, ret |
110 } else { |
144 } else { |
111 emitOp2(ret, 0b100, hi); // SETHI hi, ret |
145 emitOp2(ret, 0b100, hi); // SETHI hi, ret |
112 if (lo != 0) { |
146 if (lo != 0) { |
113 emitOp3(0b10, ret, 0b000010, ret, lo); // OR ret, lo, ret |
147 emitOp3(0b10, ret, 0b000010, ret, lo); // OR ret, lo, ret |
114 } |
148 } |
115 } |
149 } |
116 return ret; |
|
117 } |
150 } |
118 |
151 |
119 @Override |
152 @Override |
120 public Register emitLoadLong(long c) { |
153 public Register emitLoadLong(long c) { |
|
154 Register ret = newRegister(); |
|
155 emitLoadLongToRegister(c, ret); |
|
156 return ret; |
|
157 } |
|
158 |
|
159 private void loadLongToRegister(long c, Register ret) { |
|
160 DataSectionReference ref = new DataSectionReference(); |
|
161 data.align(8); |
|
162 ref.setOffset(data.position()); |
|
163 data.emitLong(c); |
|
164 emitLoadPointerToRegister(ref, ret); |
|
165 } |
|
166 |
|
167 public void emitLoadLongToRegister(long c, Register r) { |
121 if ((c & 0xFFFF_FFFFL) == c) { |
168 if ((c & 0xFFFF_FFFFL) == c) { |
122 return emitLoadInt((int) c); |
169 loadIntToRegister((int) c, r); |
123 } else { |
170 } else { |
124 DataSectionReference ref = new DataSectionReference(); |
171 loadLongToRegister(c, r); |
125 data.align(8); |
|
126 ref.setOffset(data.position()); |
|
127 data.emitLong(c); |
|
128 return emitLoadPointer(ref); |
|
129 } |
172 } |
130 } |
173 } |
131 |
174 |
132 private void emitPatchableSethi(Register ret, boolean wide) { |
175 private void emitPatchableSethi(Register ret, boolean wide) { |
133 int startPos = code.position(); |
176 int startPos = code.position(); |
166 } |
209 } |
167 |
210 |
168 @Override |
211 @Override |
169 public Register emitLoadPointer(DataSectionReference ref) { |
212 public Register emitLoadPointer(DataSectionReference ref) { |
170 Register ret = newRegister(); |
213 Register ret = newRegister(); |
|
214 emitLoadPointerToRegister(ref, ret); |
|
215 return ret; |
|
216 } |
|
217 |
|
218 private void emitLoadPointerToRegister(DataSectionReference ref, Register ret) { |
171 recordDataPatchInCode(ref); |
219 recordDataPatchInCode(ref); |
172 emitPatchableSethi(ret, true); |
220 emitPatchableSethi(ret, true); |
173 emitOp3(0b11, ret, 0b001011, ret, 0); // LDX [ret+0], ret |
221 emitOp3(0b11, ret, 0b001011, ret, 0); // LDX [ret+0], ret |
174 return ret; |
|
175 } |
222 } |
176 |
223 |
177 @Override |
224 @Override |
178 public Register emitLoadNarrowPointer(DataSectionReference ref) { |
225 public Register emitLoadNarrowPointer(DataSectionReference ref) { |
179 Register ret = newRegister(); |
226 Register ret = newRegister(); |
192 |
239 |
193 @Override |
240 @Override |
194 public StackSlot emitIntToStack(Register a) { |
241 public StackSlot emitIntToStack(Register a) { |
195 StackSlot ret = newStackSlot(SPARCKind.WORD); |
242 StackSlot ret = newStackSlot(SPARCKind.WORD); |
196 // STW a, [fp+offset] |
243 // STW a, [fp+offset] |
197 emitOp3(0b11, a, 0b000100, SPARC.fp, ret.getRawOffset() + SPARC.STACK_BIAS); |
244 emitStore(0b000100, a, ret); |
198 return ret; |
245 return ret; |
199 } |
246 } |
200 |
247 |
201 @Override |
248 @Override |
202 public StackSlot emitLongToStack(Register a) { |
249 public StackSlot emitLongToStack(Register a) { |
203 StackSlot ret = newStackSlot(SPARCKind.XWORD); |
250 StackSlot ret = newStackSlot(SPARCKind.XWORD); |
204 // STX a, [fp+offset] |
251 // STX a, [sp+offset] |
205 emitOp3(0b11, a, 0b001110, SPARC.fp, ret.getRawOffset() + SPARC.STACK_BIAS); |
252 emitStore(0b001110, a, ret); |
206 return ret; |
253 return ret; |
207 } |
254 } |
208 |
255 |
209 @Override |
256 @Override |
210 public StackSlot emitFloatToStack(Register a) { |
257 public StackSlot emitFloatToStack(Register a) { |
211 StackSlot ret = newStackSlot(SPARCKind.SINGLE); |
258 StackSlot ret = newStackSlot(SPARCKind.SINGLE); |
212 // STF a, [fp+offset] |
259 // STF a, [fp+offset] |
213 emitOp3(0b11, a, 0b100100, SPARC.fp, ret.getRawOffset() + SPARC.STACK_BIAS); |
260 emitStore(0b100100, a, ret); |
214 return ret; |
261 return ret; |
215 } |
262 } |
216 |
263 |
217 @Override |
264 @Override |
218 public StackSlot emitPointerToStack(Register a) { |
265 public StackSlot emitPointerToStack(Register a) { |
219 StackSlot ret = newStackSlot(SPARCKind.XWORD); |
266 StackSlot ret = newStackSlot(SPARCKind.XWORD); |
220 // STX a, [fp+offset] |
267 // STX a, [fp+offset] |
221 emitOp3(0b11, a, 0b001110, SPARC.fp, ret.getRawOffset() + SPARC.STACK_BIAS); |
268 emitStore(0b001110, a, ret); |
222 return ret; |
269 return ret; |
223 } |
270 } |
224 |
271 |
225 @Override |
272 @Override |
226 public StackSlot emitNarrowPointerToStack(Register a) { |
273 public StackSlot emitNarrowPointerToStack(Register a) { |
227 StackSlot ret = newStackSlot(SPARCKind.WORD); |
274 StackSlot ret = newStackSlot(SPARCKind.WORD); |
228 // STW a, [fp+offset] |
275 // STW a, [fp+offset] |
229 emitOp3(0b11, a, 0b000100, SPARC.fp, ret.getRawOffset() + SPARC.STACK_BIAS); |
276 emitStore(0b000100, a, ret); |
230 return ret; |
277 return ret; |
|
278 } |
|
279 |
|
280 private void emitStore(int op3, Register a, StackSlot ret) { |
|
281 int offset = ret.getRawOffset() + SPARC.STACK_BIAS; |
|
282 if (isSimm(offset, 13)) { |
|
283 // op3 a, [sp+offset] |
|
284 emitOp3(0b11, a, op3, SPARC.fp, offset); |
|
285 } else { |
|
286 assert a != SPARC.g3; |
|
287 Register r = SPARC.g3; |
|
288 loadLongToRegister(offset, r); |
|
289 // op3 a, [sp+g3] |
|
290 emitOp3(0b11, a, op3, SPARC.fp, r); |
|
291 } |
231 } |
292 } |
232 |
293 |
233 @Override |
294 @Override |
234 public Register emitUncompressPointer(Register compressed, long base, int shift) { |
295 public Register emitUncompressPointer(Register compressed, long base, int shift) { |
235 Register ret; |
296 Register ret; |