riscv64: use bitmanip extension, declare temp regs
This patch converts the VREG accessors to use
the denser SH2ADD from Zba, and converts some
common macros to declare their temporaries at
their call sites.
Test: Run these opcodes against all interpreter
tests on a Linux RISC-V VM.
(1) setup
lunch aosp_riscv64-userdebug
export ART_TEST_SSH_USER=ubuntu
export ART_TEST_SSH_HOST=localhost
export ART_TEST_SSH_PORT=10001
export ART_TEST_ON_VM=true
. art/tools/buildbot-utils.sh
art/tools/buildbot-build.sh --target
# Create, boot and configure the VM.
art/tools/buildbot-vm.sh create
art/tools/buildbot-vm.sh boot
art/tools/buildbot-vm.sh setup-ssh # password: 'ubuntu'
art/tools/buildbot-cleanup-device.sh
art/tools/buildbot-setup-device.sh
art/tools/buildbot-sync.sh
(2) test
art/test.py --target -r --no-prebuild --ndebug --64 -j 12 --cdex-none --interpreter
Bug: 283082047
Change-Id: Id37694761610b6a5bae54d6b244b4e75a4ea5a85
diff --git a/runtime/interpreter/mterp/riscv64/arithmetic.S b/runtime/interpreter/mterp/riscv64/arithmetic.S
index a75a964..e563b20 100644
--- a/runtime/interpreter/mterp/riscv64/arithmetic.S
+++ b/runtime/interpreter/mterp/riscv64/arithmetic.S
@@ -35,7 +35,8 @@
FETCH_ADVANCE_INST 1 // advance xPC, load xINST
and t2, t2, 0xF // t2 := A
GET_INST_OPCODE t3 // t3 holds next opcode
- SET_VREG_WIDE t1, t2 // fp[A:A+1] := t1
+ SET_VREG_WIDE t1, t2, z0=t0
+ // fp[A:A+1] := t1
GOTO_OPCODE t3 // continue to next
// long-to-int vA, vB
@@ -77,7 +78,7 @@
FETCH_ADVANCE_INST 1 // advance xPC, load xINST
$instr // read t1, write result to t1.
// do not clobber t2!
- SET_VREG t1, t2, is_wide=$is_wide
+ SET_VREG t1, t2, z0=t0, is_wide=$is_wide
// fp[A] := t1
GET_INST_OPCODE t0 // t0 holds next opcode
GOTO_OPCODE t0 // continue to next
@@ -236,7 +237,8 @@
$instr // read t1 and t2, write result to t1.
// do not clobber t3!
GET_INST_OPCODE t2 // t2 holds next opcode
- SET_VREG t1, t3, is_wide=$is_wide // fp[AA] := t1
+ SET_VREG t1, t3, z0=t0, is_wide=$is_wide
+ // fp[AA] := t1
GOTO_OPCODE t2 // continue to next
1:
.if $divz_throw
@@ -263,7 +265,8 @@
$instr // read t1 and t2, write result to t1.
// do not clobber t3!
GET_INST_OPCODE t2 // t2 holds next opcode
- SET_VREG_WIDE t1, t3 // fp[AA] := t1
+ SET_VREG_WIDE t1, t3, z0=t0
+ // fp[AA] := t1
GOTO_OPCODE t2 // continue to next
//
@@ -414,7 +417,7 @@
$instr // read t1 and t2, write result to t1.
// do not clobber t3!
GET_INST_OPCODE t2 // t2 holds next opcode
- SET_VREG t1, t3, is_wide=$is_wide
+ SET_VREG t1, t3, z0=t0, is_wide=$is_wide
// fp[A] := t1
GOTO_OPCODE t2 // continue to next
1:
@@ -442,7 +445,8 @@
$instr // read t1 and t2, write result to t1.
// do not clobber t3!
GET_INST_OPCODE t2 // t2 holds next opcode
- SET_VREG_WIDE t1, t3 // fp[A] := t1
+ SET_VREG_WIDE t1, t3, z0=t0
+ // fp[A] := t1
GOTO_OPCODE t2 // continue to next
//
@@ -517,7 +521,7 @@
$instr // read t1 and t2, write result to t1.
// do not clobber t3!
GET_INST_OPCODE t2 // t2 holds next opcode
- SET_VREG t1, t3 // fp[A] := t1
+ SET_VREG t1, t3, z0=t0 // fp[A] := t1
GOTO_OPCODE t2 // continue to next
1:
.if $divz_throw
@@ -613,7 +617,7 @@
$instr // read t1 and t2, write result to t1.
// do not clobber t3!
GET_INST_OPCODE t2 // t2 holds next opcode
- SET_VREG t1, t3 // fp[AA] := t1
+ SET_VREG t1, t3, z0=t0 // fp[AA] := t1
GOTO_OPCODE t2 // continue to next
1:
.if $divz_throw
diff --git a/runtime/interpreter/mterp/riscv64/floating_point.S b/runtime/interpreter/mterp/riscv64/floating_point.S
index dff9e5a..ee73883 100644
--- a/runtime/interpreter/mterp/riscv64/floating_point.S
+++ b/runtime/interpreter/mterp/riscv64/floating_point.S
@@ -151,16 +151,16 @@
1:
.ifc $dst, w
- SET_VREG t1, t2 // fp[A] := t1
+ SET_VREG t1, t2, z0=t0 // fp[A] := t1
.endif
.ifc $dst, l
- SET_VREG_WIDE t1, t2 // fp[A] := t1
+ SET_VREG_WIDE t1, t2, z0=t0 // fp[A] := t1
.endif
.ifc $dst, s
- SET_VREG_FLOAT ft0, t2 // fp[A] := ft0
+ SET_VREG_FLOAT ft0, t2, z0=t0 // fp[A] := ft0
.endif
.ifc $dst, d
- SET_VREG_DOUBLE ft0, t2 // fp[B] := ft0
+ SET_VREG_DOUBLE ft0, t2, z0=t0 // fp[B] := ft0
.endif
GET_INST_OPCODE t0 // t0 holds next opcode
@@ -247,7 +247,7 @@
FETCH_ADVANCE_INST 2 // advance xPC, load xINST
$instr // read fa0 and fa1, write result to fa0.
// instr may be a function call.
- SET_VREG_FLOAT fa0, s11, is_double=$is_double
+ SET_VREG_FLOAT fa0, s11, z0=t0, is_double=$is_double
// fp[AA] := fa0
GET_INST_OPCODE t0 // t0 holds next opcode
GOTO_OPCODE t0 // continue to next
@@ -334,6 +334,6 @@
$instr // read fa0 and f1, write result to fa0.
// instr may be a function call.
GET_INST_OPCODE t1 // t1 holds next opcode
- SET_VREG_FLOAT fa0, s11, is_double=$is_double
+ SET_VREG_FLOAT fa0, s11, z0=t0, is_double=$is_double
// fp[A] := fa0
GOTO_OPCODE t1 // continue to next
diff --git a/runtime/interpreter/mterp/riscv64/main.S b/runtime/interpreter/mterp/riscv64/main.S
index c1e81ab..9d9e30a 100644
--- a/runtime/interpreter/mterp/riscv64/main.S
+++ b/runtime/interpreter/mterp/riscv64/main.S
@@ -47,6 +47,7 @@
// Android references
// Bytecodes: https://source.android.com/docs/core/runtime/dalvik-bytecode
// Instruction formats: https://source.android.com/docs/core/runtime/instruction-formats
+// Shorty: https://source.android.com/docs/core/runtime/dex-format#shortydescriptor
// Fixed register usages in Nterp.
// nickname ABI reg purpose
@@ -57,6 +58,8 @@
#define xIBASE s5 // x21, interpreted instruction base pointer: for computed goto
#define xREFS s6 // x22, base of object references of dex registers
+// DWARF registers reference
+// https://github.com/riscv-non-isa/riscv-elf-psabi-doc/blob/master/riscv-dwarf.adoc
#define CFI_TMP 10 // DWARF register number for a0/x10
#define CFI_DEX 19 // DWARF register number for xPC /s3/x19
#define CFI_REFS 22 // DWARF register number for xREFS/s6/x22
@@ -119,21 +122,22 @@
// Unpack code items from dex format.
// Input: \code_item
// Output:
-// - \registers: register count
+// - \regs: register count
// - \outs: out count
-// - \ins: in count
+// - \ins: in count. If set to register "zero" (x0), load is skipped.
// - \code_item: holds instruction array on exit
-// Clobbers: t0
-.macro FETCH_CODE_ITEM_INFO code_item, registers, outs, ins
+.macro FETCH_CODE_ITEM_INFO code_item, regs, outs, ins
// Check LSB of \code_item. If 1, it's a compact dex file.
- andi t0, \code_item, 0x1
- beqz t0, 1f // Regular dex.
+ bexti \regs, \code_item, 0x0
+ beqz \regs, 1f // Regular dex.
unimp // Compact dex: unimplemented.
1:
// Unpack values from regular dex format.
- lhu \registers, CODE_ITEM_REGISTERS_SIZE_OFFSET(\code_item)
+ lhu \regs, CODE_ITEM_REGISTERS_SIZE_OFFSET(\code_item)
lhu \outs, CODE_ITEM_OUTS_SIZE_OFFSET(\code_item)
- lhu \ins, CODE_ITEM_INS_SIZE_OFFSET(\code_item)
+ .ifnc \ins, zero
+ lhu \ins, CODE_ITEM_INS_SIZE_OFFSET(\code_item)
+ .endif
addi \code_item, \code_item, CODE_ITEM_INSNS_OFFSET
.endm
@@ -238,22 +242,30 @@
// A \width flag allows reading 32 bits (2 units) or 64 bits (4 units) from the offset.
// The RISC-V ISA supports unaligned accesses for these wider loads.
//
+// If \width=8, \byte={0,1} indexes into the code unit at the offset.
+//
// Default behavior loads one code unit with unsigned zext.
// The \signed flag is for signed sext, for shorter loads.
//
// Does not advance xPC.
-.macro FETCH reg, count, signed=0, width=16
- .if \width == 16
+.macro FETCH reg, count, signed=0, width=16, byte=0
+ .if \width == 8
+ .if \signed
+ lb \reg, (\count*2 + \byte)(xPC)
+ .else
+ lbu \reg, (\count*2 + \byte)(xPC)
+ .endif
+ .elseif \width == 16
.if \signed
lh \reg, (\count*2)(xPC)
.else
- lhu \reg, (\count*2)(xPC)
+ lhu \reg, (\count*2)(xPC)
.endif
.elseif \width == 32
.if \signed
lw \reg, (\count*2)(xPC)
.else
- lwu \reg, (\count*2)(xPC)
+ lwu \reg, (\count*2)(xPC)
.endif
.elseif \width == 64
ld \reg, (\count*2)(xPC)
@@ -291,8 +303,7 @@
jr \reg
.endm
-// Clobbers: t0, t1
-.macro FETCH_FROM_THREAD_CACHE reg, miss_label
+.macro FETCH_FROM_THREAD_CACHE reg, miss_label, z0, z1
// See art::InterpreterCache::IndexOf() for computing index of key within cache array.
// Entry address:
// xSELF + OFFSET + ((xPC>>2 & xFF) << 4)
@@ -308,12 +319,12 @@
#if ((THREAD_INTERPRETER_CACHE_OFFSET & 0x3) != 0)
#error Expected interpreter cache offset to be 4-byte aligned
#endif
- andi t0, xPC, 0xFF << 2
- addi t0, t0, THREAD_INTERPRETER_CACHE_OFFSET >> 2
- sh2add t0, t0, xSELF // t0 := entry's address
- ld t1, (t0) // t1 := dex PC
- bne xPC, t1, \miss_label
- ld \reg, 8(t0) // value: depends on context; see call site
+ andi \z0, xPC, 0xFF << 2
+ addi \z0, \z0, THREAD_INTERPRETER_CACHE_OFFSET >> 2
+ sh2add \z0, \z0, xSELF // z0 := entry's address
+ ld \z1, (\z0) // z1 := dex PC
+ bne xPC, \z1, \miss_label
+ ld \reg, 8(\z0) // value: depends on context; see call site
.endm
// Inputs:
@@ -322,9 +333,9 @@
// Clobbers: t0
.macro CHECK_AND_UPDATE_SHARED_MEMORY_METHOD if_hot, if_not_hot
lw t0, ART_METHOD_ACCESS_FLAGS_OFFSET(a0)
- // Send flag bit to MSB, branch if bit is unset.
- sll t0, t0, 63 - ART_METHOD_IS_MEMORY_SHARED_FLAG_BIT
- bgez t0, \if_hot
+ // Extract flag bit, branch if bit is unset.
+ bexti t0, t0, ART_METHOD_IS_MEMORY_SHARED_FLAG_BIT
+ beqz t0, \if_hot
lw t0, THREAD_SHARED_METHOD_HOTNESS_OFFSET(xSELF)
beqz t0, \if_hot
@@ -335,14 +346,16 @@
.endm
// Increase method hotness before starting the method.
-// Clobbers: a0, t0
+// Hardcoded:
+// - a0: ArtMethod*
+// Clobbers: t0
.macro START_EXECUTING_INSTRUCTIONS
ld a0, (sp)
lhu t0, ART_METHOD_HOTNESS_COUNT_OFFSET(a0)
#if (NTERP_HOTNESS_VALUE != 0)
#error Expected 0 for hotness value
#endif
- // If the counter is at zero, handle it in the runtime.
+ // If the counter is at zero (hot), handle it in the runtime.
beqz t0, 3f
addi t0, t0, -1
sh t0, ART_METHOD_HOTNESS_COUNT_OFFSET(a0)
@@ -361,30 +374,28 @@
j 2b
.endm
-// Typed read, defaults to 32-bit read.
-// Clobbers: \reg, \vreg
+// Typed read, defaults to 32-bit read
+// Clobbers: \reg
// Safe if \reg == \vreg.
.macro GET_VREG reg, vreg, is_wide=0
.if \is_wide
GET_VREG_WIDE \reg, \vreg
.else
- slliw \vreg, \vreg, 2 // vreg id to byte offset
- add \vreg, xFP, \vreg // vreg addr in register array
- lw \reg, (\vreg) // reg := fp[vreg]
+ sh2add \reg, \vreg, xFP // vreg addr in register array
+ lw \reg, (\reg) // reg := fp[vreg]
.endif
.endm
// Typed write, defaults to 32-bit write.
-// Clobbers: t0, \reg, \vreg
-.macro SET_VREG reg, vreg, is_wide=0
+// Clobbers: z0
+.macro SET_VREG reg, vreg, z0, is_wide=0
.if \is_wide
- SET_VREG_WIDE \reg, \vreg
+ SET_VREG_WIDE \reg, \vreg, \z0
.else
- slliw \vreg, \vreg, 2 // vreg id to byte offset
- add t0, xFP, \vreg // vreg addr in register array
- sw \reg, (t0) // fp[vreg] := reg
- add t0, xREFS, \vreg // vreg addr in reference array
- sw zero, (t0) // refs[vreg] := null
+ sh2add \z0, \vreg, xFP // vreg addr in register array
+ sw \reg, (\z0) // fp[vreg] := reg
+ sh2add \z0, \vreg, xREFS // vreg addr in reference array
+ sw zero, (\z0) // refs[vreg] := null
.endif
.endm
@@ -392,38 +403,34 @@
// Clobbers: \reg
// Safe if \reg == \vreg.
.macro GET_VREG_WIDE reg, vreg
- slliw \vreg, \vreg, 2 // vreg id to byte offset
- add \vreg, xFP, \vreg // vreg addr in register array
- ld \reg, (\vreg) // reg := fp[vreg](lo) | fp[vreg+1](hi)
+ sh2add \reg, \vreg, xFP // vreg addr in register array
+ ld \reg, (\reg) // reg := fp[vreg](lo) | fp[vreg+1](hi)
.endm
// 64 bit write
-// Clobbers: t0, \vreg
-.macro SET_VREG_WIDE reg, vreg
- slliw \vreg, \vreg, 2 // vreg id to byte offset
- add t0, xFP, \vreg // vreg addr in register array
- sd \reg, (t0) // fp[vreg] := reg(lo) ; fp[vreg+1] := reg(hi)
- add t0, xREFS, \vreg // vreg addr in reference array
- sd zero, (t0) // refs[vreg] := null ; refs[vreg+1] := null
+// Clobbers: z0
+.macro SET_VREG_WIDE reg, vreg, z0
+ sh2add \z0, \vreg, xFP // vreg addr in register array
+ sd \reg, (\z0) // fp[vreg] := reg(lo) ; fp[vreg+1] := reg(hi)
+ sh2add \z0, \vreg, xREFS // vreg addr in reference array
+ sd zero, (\z0) // refs[vreg] := null ; refs[vreg+1] := null
.endm
// Object read
// Clobbers: \reg
// Safe if \reg == \vreg.
.macro GET_VREG_OBJECT reg, vreg
- slliw \vreg, \vreg, 2 // vreg id to byte offset
- add \vreg, xREFS, \vreg // vreg addr in reference array
- lw \reg, (\vreg) // reg := refs[vreg]
+ sh2add \reg, \vreg, xREFS // vreg addr in reference array
+ lwu \reg, (\reg) // reg := refs[vreg]
.endm
// Object write
-// Clobbers: t0, \vreg
-.macro SET_VREG_OBJECT reg, vreg
- slliw \vreg, \vreg, 2 // vreg id to byte offset
- add t0, xFP, \vreg // vreg addr in register array
- sw \reg, (t0) // fp[vreg] := reg
- add t0, xREFS, \vreg // vreg addr in reference array
- sw \reg, (t0) // refs[vreg] := reg
+// Clobbers: z0
+.macro SET_VREG_OBJECT reg, vreg, z0
+ sh2add \z0, \vreg, xFP // vreg addr in register array
+ sw \reg, (\z0) // fp[vreg] := reg
+ sh2add \z0, \vreg, xREFS // vreg addr in reference array
+ sw \reg, (\z0) // refs[vreg] := reg
.endm
// Floating-point read, defaults to 32-bit read.
@@ -432,42 +439,38 @@
.if \is_double
GET_VREG_DOUBLE \reg, \vreg
.else
- slliw \vreg, \vreg, 2 // vreg id to byte offset
- add \vreg, xFP, \vreg // vreg addr in register array
- flw \reg, (\vreg) // reg := fp[vreg]
+ sh2add \vreg, \vreg, xFP // vreg addr in register array
+ flw \reg, (\vreg) // reg := fp[vreg]
.endif
.endm
// Floating-point write, defaults to 32-bit write.
-// Clobbers: t0, \reg, \vreg
-.macro SET_VREG_FLOAT reg, vreg, is_double=0
+// Clobbers: \reg, z0
+.macro SET_VREG_FLOAT reg, vreg, z0, is_double=0
.if \is_double
- SET_VREG_DOUBLE \reg, \vreg
+ SET_VREG_DOUBLE \reg, \vreg, \z0
.else
- slliw \vreg, \vreg, 2 // vreg id to byte offset
- add t0, xFP, \vreg // vreg addr in register array
- fsw \reg, (t0) // fp[vreg] := reg
- add t0, xREFS, \vreg // vreg addr in reference array
- sw zero, (t0) // refs[vreg] := null
+ sh2add \z0, \vreg, xFP // vreg addr in register array
+ fsw \reg, (\z0) // fp[vreg] := reg
+ sh2add \z0, \vreg, xREFS // vreg addr in reference array
+ sw zero, (\z0) // refs[vreg] := null
.endif
.endm
// Floating-point 64 bit read
-// Clobbers: \reg
+// Clobbers: \reg, \vreg
.macro GET_VREG_DOUBLE reg, vreg
- slliw \vreg, \vreg, 2 // vreg id to byte offset
- add \vreg, xFP, \vreg // vreg addr in register array
- fld \reg, (\vreg) // reg := fp[vreg](lo) | fp[vreg+1](hi)
+ sh2add \vreg, \vreg, xFP // vreg addr in register array
+ fld \reg, (\vreg) // reg := fp[vreg](lo) | fp[vreg+1](hi)
.endm
// Floating-point 64 bit write
-// Clobbers: t0, \vreg
-.macro SET_VREG_DOUBLE reg, vreg
- slliw \vreg, \vreg, 2 // vreg id to byte offset
- add t0, xFP, \vreg // vreg addr in register array
- fsd \reg, (t0) // fp[vreg] := reg(lo) ; fp[vreg+1] := reg(hi)
- add t0, xREFS, \vreg // vreg addr in reference array
- sd zero, (t0) // refs[vreg] := null ; refs[vreg+1] := null
+// Clobbers: \reg, z0
+.macro SET_VREG_DOUBLE reg, vreg, z0
+ sh2add \z0, \vreg, xFP // vreg addr in register array
+ fsd \reg, (\z0) // fp[vreg] := reg(lo) ; fp[vreg+1] := reg(hi)
+ sh2add \z0, \vreg, xREFS // vreg addr in reference array
+ sd zero, (\z0) // refs[vreg] := null ; refs[vreg+1] := null
.endm
%def entry():
@@ -553,9 +556,14 @@
common_errDivideByZero:
EXPORT_PC
- // Control doesn't return, but stack walking needs the return address.
+ // CALL preserves RA for stack walking.
call art_quick_throw_div_zero
+// This is the logical end of ExecuteNterpImpl, where the frame info applies.
+.cfi_endproc
+
+NAME_END nterp_helper
+
// EndExecuteNterpImpl includes the methods after .cfi_endproc, as we want the runtime to see them
// as part of the Nterp PCs. This label marks the end of PCs contained by the OatQuickMethodHeader
// created for the interpreter entry point.
@@ -564,10 +572,6 @@
.global EndExecuteNterpImpl
EndExecuteNterpImpl:
-// This is the logical end of ExecuteNterpImpl, where the frame info applies.
-.cfi_endproc
-NAME_END nterp_helper
-
// Entrypoints into runtime.
NTERP_TRAMPOLINE nterp_get_class, NterpGetClass
NTERP_TRAMPOLINE nterp_get_static_field, NterpGetStaticField
diff --git a/runtime/interpreter/mterp/riscv64/object.S b/runtime/interpreter/mterp/riscv64/object.S
index 0713855..8a64f64 100644
--- a/runtime/interpreter/mterp/riscv64/object.S
+++ b/runtime/interpreter/mterp/riscv64/object.S
@@ -109,7 +109,7 @@
// Fast path: NterpGetStaticField's resolved_field from thread-local cache.
// Stores cache value in a0 to match slow path's return from NterpGetStaticField.
// Slow path: updates s7 if is_object, for possible GC movement.
- FETCH_FROM_THREAD_CACHE /*resolved_field*/a0, .L${opcode}_slow
+ FETCH_FROM_THREAD_CACHE /*resolved_field*/a0, .L${opcode}_slow, t0, t1
.L${opcode}_regular_resume:
lw t0, ART_FIELD_OFFSET_OFFSET(a0)
diff --git a/runtime/interpreter/mterp/riscv64/other.S b/runtime/interpreter/mterp/riscv64/other.S
index 8ce2251..6cd507c 100644
--- a/runtime/interpreter/mterp/riscv64/other.S
+++ b/runtime/interpreter/mterp/riscv64/other.S
@@ -19,10 +19,10 @@
FETCH_ADVANCE_INST 1 // advance xPC, load xINST
GET_INST_OPCODE t3 // t3 holds next opcode
.if $is_object
- SET_VREG_OBJECT t1, t2
+ SET_VREG_OBJECT t1, t2, z0=t0
// refs[A] := fp[B]
.else
- SET_VREG t1, t2 is_wide=$is_wide
+ SET_VREG t1, t2, z0=t0, is_wide=$is_wide
// fp[A] := fp[B]
.endif
GOTO_OPCODE t3 // continue to next
@@ -37,10 +37,10 @@
FETCH_ADVANCE_INST 2 // advance xPC, load xINST
GET_INST_OPCODE t3 // t3 := next opcode
.if $is_object
- SET_VREG_OBJECT t1, t2
+ SET_VREG_OBJECT t1, t2, z0=t0
// refs[AA] := fp[BBBB]
.else
- SET_VREG t1, t2, is_wide=$is_wide
+ SET_VREG t1, t2, z0=t0, is_wide=$is_wide
// fp[AA] := fp[BBBB]
.endif
GOTO_OPCODE t3 // continue to next
@@ -55,10 +55,10 @@
FETCH_ADVANCE_INST 3 // advance xPC, load xINST
GET_INST_OPCODE t3 // t3 := next opcode
.if $is_object
- SET_VREG_OBJECT t1, t2
+ SET_VREG_OBJECT t1, t2, z0=t0
// refs[AAAA] := fp[BBBB]
.else
- SET_VREG t1, t2, is_wide=$is_wide
+ SET_VREG t1, t2, z0=t0, is_wide=$is_wide
// fp[AAAA] := fp[BBBB]
.endif
GOTO_OPCODE t3 // continue to next
@@ -103,10 +103,10 @@
FETCH_ADVANCE_INST 1 // advance xPC, load xINST
GET_INST_OPCODE t2 // t2 := next opcode
.if $is_object
- SET_VREG_OBJECT a0, t1
+ SET_VREG_OBJECT a0, t1, z0=t0
// refs[AA] := a0
.else
- SET_VREG a0, t1, is_wide=$is_wide
+ SET_VREG a0, t1, z0=t0, is_wide=$is_wide
// fp[AA] := a0
.endif
GOTO_OPCODE t2 // continue to next
@@ -127,7 +127,7 @@
ld t1, THREAD_EXCEPTION_OFFSET(xSELF) // t1 := exception object
srliw t2, xINST, 8 // t2 := AA
FETCH_ADVANCE_INST 1 // advance xPC, load xINST
- SET_VREG_OBJECT t1, t2 // refs[AA] := exception object
+ SET_VREG_OBJECT t1, t2, z0=t0 // refs[AA] := exception object
GET_INST_OPCODE t3 // t3 := next opcode
sd zero, THREAD_EXCEPTION_OFFSET(xSELF) // clear exception
GOTO_OPCODE t3 // continue to next
@@ -136,14 +136,14 @@
// Format 11n: B|A|12
// Clobbers: t0, t1, t2, t3
%def op_const_4():
- slliw t1, xINST, 16 // B as MSB of word
- sraiw t1, t1, 28 // t1 := sssssssB
- slliw t2, xINST, 20 // A as MSB of word
- srliw t2, t2, 28 // t2 := A
- FETCH_ADVANCE_INST 1 // advance xPC, load xINST
- GET_INST_OPCODE t3 // t3 holds next opcode
- SET_VREG t1, t2 // fp[A] := sssssssB
- GOTO_OPCODE t3 // continue to next
+ slliw t1, xINST, 16 // B as MSB of word
+ sraiw t1, t1, 28 // t1 := sssssssB
+ slliw t2, xINST, 20 // A as MSB of word
+ srliw t2, t2, 28 // t2 := A
+ FETCH_ADVANCE_INST 1 // advance xPC, load xINST
+ GET_INST_OPCODE t3 // t3 holds next opcode
+ SET_VREG t1, t2, z0=t0 // fp[A] := sssssssB
+ GOTO_OPCODE t3 // continue to next
// const/16 vAA, #+BBBB
// Format 21s: AA|13 BBBB
@@ -154,7 +154,7 @@
srliw t2, xINST, 8 // t2 := AA
FETCH_ADVANCE_INST 2 // advance xPC, load xINST
GET_INST_OPCODE t3 // t3 := next opcode
- SET_VREG t1, t2, is_wide=$is_wide
+ SET_VREG t1, t2, z0=t0, is_wide=$is_wide
// fp[AA] := +BBBB
GOTO_OPCODE t3 // continue to next
@@ -167,7 +167,7 @@
srliw t2, xINST, 8 // t2 := AA
FETCH_ADVANCE_INST 3 // advance xPC, load xINST
GET_INST_OPCODE t3 // t3 := next opcode
- SET_VREG t1, t2, is_wide=$is_wide
+ SET_VREG t1, t2, z0=t0, is_wide=$is_wide
// fp[AA] := +BBBBBBBB
GOTO_OPCODE t3 // continue to next
@@ -175,13 +175,13 @@
// Format 21h: AA|15 BBBB
// Clobbers: t0, t1, t2, t3
%def op_const_high16():
- FETCH t1, count=1 // t1 := BBBB
- srliw t2, xINST, 8 // t2 := AA
- slliw t1, t1, 16 // t1 := BBBB0000
- FETCH_ADVANCE_INST 2 // advance xPC, load xINST
- GET_INST_OPCODE t3 // t3 := next opcode
- SET_VREG t1, t2 // fp[AA] := BBBB0000
- GOTO_OPCODE t3 // continue to next
+ FETCH t1, count=1 // t1 := BBBB
+ srliw t2, xINST, 8 // t2 := AA
+ slliw t1, t1, 16 // t1 := BBBB0000
+ FETCH_ADVANCE_INST 2 // advance xPC, load xINST
+ GET_INST_OPCODE t3 // t3 := next opcode
+ SET_VREG t1, t2, z0=t0 // fp[AA] := BBBB0000
+ GOTO_OPCODE t3 // continue to next
// const-wide/16 vAA, #+BBBB
// Format 21s: AA|16 BBBB
@@ -201,7 +201,8 @@
srliw t2, xINST, 8 // t2 := AA
FETCH_ADVANCE_INST 5 // advance xPC, load xINST
GET_INST_OPCODE t3 // t3 := next opcode
- SET_VREG_WIDE t1, t2 // fp[AA] := BBBBBBBBBBBBBBBB
+ SET_VREG_WIDE t1, t2, z0=t0
+ // fp[AA] := BBBBBBBBBBBBBBBB
GOTO_OPCODE t3 // continue to next
// const-wide/high16 vAA, #+BBBB000000000000
@@ -212,7 +213,8 @@
slli t1, t1, 48 // t1 := BBBB000000000000
FETCH_ADVANCE_INST 2 // advance xPC, load xINST
GET_INST_OPCODE t3 // t3 := next opcode
- SET_VREG_WIDE t1, t2 // fp[AA] := BBBB000000000000
+ SET_VREG_WIDE t1, t2, z0=t0
+ // fp[AA] := BBBB000000000000
GOTO_OPCODE t3 // continue to next
// Common helper.