1 /*
2 * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 */
193 }
194 throw GraalError.shouldNotReachHere("Unexpected kind: " + kind.toString());
195 }
196
197 /**
198 * Emit an immediate of this size. Note that immediate {@link #QWORD} operands are encoded
199 * as sign-extended 32-bit values.
200 *
201 * @param asm
202 * @param imm
203 */
204 protected void emitImmediate(AMD64BaseAssembler asm, int imm) {
205 throw new UnsupportedOperationException();
206 }
207
208 protected int immediateSize() {
209 throw new UnsupportedOperationException();
210 }
211 }
212
213 public abstract static class OperandDataAnnotation extends CodeAnnotation {
214 /**
215 * The position (bytes from the beginning of the method) of the operand.
216 */
217 public final int operandPosition;
218 /**
219 * The size of the operand, in bytes.
220 */
221 public final int operandSize;
222 /**
223 * The position (bytes from the beginning of the method) of the next instruction. On AMD64,
224 * RIP-relative operands are relative to this position.
225 */
226 public final int nextInstructionPosition;
227
228 OperandDataAnnotation(int instructionPosition, int operandPosition, int operandSize, int nextInstructionPosition) {
229 super(instructionPosition);
230
231 this.operandPosition = operandPosition;
232 this.operandSize = operandSize;
233 this.nextInstructionPosition = nextInstructionPosition;
234 }
235
236 @Override
237 public String toString() {
238 return getClass().getSimpleName() + " instruction [" + instructionPosition + ", " + nextInstructionPosition + "[ operand at " + operandPosition + " size " + operandSize;
239 }
240 }
241
242 /**
243 * Annotation that stores additional information about the displacement of a
244 * {@link Assembler#getPlaceholder placeholder address} that needs patching.
245 */
246 protected static class AddressDisplacementAnnotation extends OperandDataAnnotation {
247 AddressDisplacementAnnotation(int instructionPosition, int operandPosition, int operandSize, int nextInstructionPosition) {
248 super(instructionPosition, operandPosition, operandSize, nextInstructionPosition);
249 }
250 }
251
252 /**
253 * Annotation that stores additional information about the immediate operand, e.g., of a call
254 * instruction, that needs patching.
255 */
256 protected static class ImmediateOperandAnnotation extends OperandDataAnnotation {
257 ImmediateOperandAnnotation(int instructionPosition, int operandPosition, int operandSize, int nextInstructionPosition) {
258 super(instructionPosition, operandPosition, operandSize, nextInstructionPosition);
259 }
260 }
261
262 protected void annotatePatchingImmediate(int operandOffset, int operandSize) {
263 if (codePatchingAnnotationConsumer != null) {
264 int pos = position();
265 codePatchingAnnotationConsumer.accept(new ImmediateOperandAnnotation(pos, pos + operandOffset, operandSize, pos + operandOffset + operandSize));
266 }
267 }
268
269 public final boolean supports(CPUFeature feature) {
270 return ((AMD64) target.arch).getFeatures().contains(feature);
271 }
272
273 protected static boolean inRC(RegisterCategory rc, Register r) {
274 return r.getRegisterCategory().equals(rc);
275 }
276
277 protected static int encode(Register r) {
278 assert r.encoding >= 0 && (inRC(XMM, r) ? r.encoding < 32 : r.encoding < 16) : "encoding out of range: " + r.encoding;
279 return r.encoding & 0x7;
280 }
281
282 private static final int MinEncodingNeedsRex = 8;
283
284 /**
285 * Constants for X86 prefix bytes.
564 * this instruction has not been completely emitted yet.
565 * @param evexDisp8Scale the scaling factor for computing the compressed displacement of
566 * EVEX-encoded instructions. This scaling factor only matters when the emitted
567 * instruction uses one-byte-displacement form.
568 */
569 private void emitOperandHelper(int reg, AMD64Address addr, boolean force4Byte, int additionalInstructionSize, int evexDisp8Scale) {
570 assert (reg & 0x07) == reg;
571 int regenc = reg << 3;
572
573 Register base = addr.getBase();
574 Register index = addr.getIndex();
575
576 Scale scale = addr.getScale();
577 int disp = addr.getDisplacement();
578
579 if (base.equals(AMD64.rip)) { // also matches addresses returned by getPlaceholder()
580 // [00 000 101] disp32
581 assert index.equals(Register.None) : "cannot use RIP relative addressing with index register";
582 emitByte(0x05 | regenc);
583 if (codePatchingAnnotationConsumer != null && addr.instructionStartPosition >= 0) {
584 codePatchingAnnotationConsumer.accept(new AddressDisplacementAnnotation(addr.instructionStartPosition, position(), 4, position() + 4 + additionalInstructionSize));
585 }
586 emitInt(disp);
587 } else if (base.isValid()) {
588 boolean overriddenForce4Byte = force4Byte;
589 int baseenc = base.isValid() ? encode(base) : 0;
590
591 if (index.isValid()) {
592 int indexenc = encode(index) << 3;
593 // [base + indexscale + disp]
594 if (disp == 0 && !base.equals(rbp) && !base.equals(r13)) {
595 // [base + indexscale]
596 // [00 reg 100][ss index base]
597 assert !index.equals(rsp) : "illegal addressing mode";
598 emitByte(0x04 | regenc);
599 emitByte(scale.log2 << 6 | indexenc | baseenc);
600 } else {
601 if (evexDisp8Scale > 1 && !overriddenForce4Byte) {
602 if (disp % evexDisp8Scale == 0) {
603 int newDisp = disp / evexDisp8Scale;
604 if (isByte(newDisp)) {
|
1 /*
2 * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 */
193 }
194 throw GraalError.shouldNotReachHere("Unexpected kind: " + kind.toString());
195 }
196
197 /**
198 * Emit an immediate of this size. Note that immediate {@link #QWORD} operands are encoded
199 * as sign-extended 32-bit values.
200 *
201 * @param asm
202 * @param imm
203 */
204 protected void emitImmediate(AMD64BaseAssembler asm, int imm) {
205 throw new UnsupportedOperationException();
206 }
207
208 protected int immediateSize() {
209 throw new UnsupportedOperationException();
210 }
211 }
212
213 public static class OperandDataAnnotation extends CodeAnnotation {
214 /**
215 * The position (bytes from the beginning of the method) of the operand.
216 */
217 public final int operandPosition;
218 /**
219 * The size of the operand, in bytes.
220 */
221 public final int operandSize;
222 /**
223 * The position (bytes from the beginning of the method) of the next instruction. On AMD64,
224 * RIP-relative operands are relative to this position.
225 */
226 public final int nextInstructionPosition;
227
228 OperandDataAnnotation(int instructionPosition, int operandPosition, int operandSize, int nextInstructionPosition) {
229 super(instructionPosition);
230
231 this.operandPosition = operandPosition;
232 this.operandSize = operandSize;
233 this.nextInstructionPosition = nextInstructionPosition;
234 }
235
236 @Override
237 public String toString() {
238 return getClass().getSimpleName() + " instruction [" + instructionPosition + ", " + nextInstructionPosition + "[ operand at " + operandPosition + " size " + operandSize;
239 }
240 }
241
242 protected void annotatePatchingImmediate(int operandOffset, int operandSize) {
243 if (codePatchingAnnotationConsumer != null) {
244 int pos = position();
245 codePatchingAnnotationConsumer.accept(new OperandDataAnnotation(pos, pos + operandOffset, operandSize, pos + operandOffset + operandSize));
246 }
247 }
248
249 public final boolean supports(CPUFeature feature) {
250 return ((AMD64) target.arch).getFeatures().contains(feature);
251 }
252
253 protected static boolean inRC(RegisterCategory rc, Register r) {
254 return r.getRegisterCategory().equals(rc);
255 }
256
257 protected static int encode(Register r) {
258 assert r.encoding >= 0 && (inRC(XMM, r) ? r.encoding < 32 : r.encoding < 16) : "encoding out of range: " + r.encoding;
259 return r.encoding & 0x7;
260 }
261
262 private static final int MinEncodingNeedsRex = 8;
263
264 /**
265 * Constants for X86 prefix bytes.
544 * this instruction has not been completely emitted yet.
545 * @param evexDisp8Scale the scaling factor for computing the compressed displacement of
546 * EVEX-encoded instructions. This scaling factor only matters when the emitted
547 * instruction uses one-byte-displacement form.
548 */
549 private void emitOperandHelper(int reg, AMD64Address addr, boolean force4Byte, int additionalInstructionSize, int evexDisp8Scale) {
550 assert (reg & 0x07) == reg;
551 int regenc = reg << 3;
552
553 Register base = addr.getBase();
554 Register index = addr.getIndex();
555
556 Scale scale = addr.getScale();
557 int disp = addr.getDisplacement();
558
559 if (base.equals(AMD64.rip)) { // also matches addresses returned by getPlaceholder()
560 // [00 000 101] disp32
561 assert index.equals(Register.None) : "cannot use RIP relative addressing with index register";
562 emitByte(0x05 | regenc);
563 if (codePatchingAnnotationConsumer != null && addr.instructionStartPosition >= 0) {
564 codePatchingAnnotationConsumer.accept(new OperandDataAnnotation(addr.instructionStartPosition, position(), 4, position() + 4 + additionalInstructionSize));
565 }
566 emitInt(disp);
567 } else if (base.isValid()) {
568 boolean overriddenForce4Byte = force4Byte;
569 int baseenc = base.isValid() ? encode(base) : 0;
570
571 if (index.isValid()) {
572 int indexenc = encode(index) << 3;
573 // [base + indexscale + disp]
574 if (disp == 0 && !base.equals(rbp) && !base.equals(r13)) {
575 // [base + indexscale]
576 // [00 reg 100][ss index base]
577 assert !index.equals(rsp) : "illegal addressing mode";
578 emitByte(0x04 | regenc);
579 emitByte(scale.log2 << 6 | indexenc | baseenc);
580 } else {
581 if (evexDisp8Scale > 1 && !overriddenForce4Byte) {
582 if (disp % evexDisp8Scale == 0) {
583 int newDisp = disp / evexDisp8Scale;
584 if (isByte(newDisp)) {
|