OpenJDK / jdk / jdk
changeset 42127:4842072b76a0
Merge
author | duke |
---|---|
date | Wed, 05 Jul 2017 22:28:55 +0200 |
parents | 17e6a319acd1 e2ab2817173b |
children | fbf1dd26c269 |
files | hotspot/src/share/vm/utilities/quickSort.cpp hotspot/test/compiler/ciReplay/TestSA.sh hotspot/test/compiler/ciReplay/TestVM.sh hotspot/test/compiler/ciReplay/TestVM_no_comp_level.sh hotspot/test/compiler/ciReplay/common.sh jaxp/src/java.xml/share/classes/org/w3c/dom/xpath/COPYRIGHT.html jdk/test/sun/tools/jps/JpsBase.java jdk/test/sun/tools/jps/TestJpsClass.java jdk/test/sun/tools/jps/TestJpsJar.java jdk/test/sun/tools/jps/TestJpsJarRelative.java |
diffstat | 368 files changed, 64835 insertions(+), 3354 deletions(-) [+] |
line wrap: on
line diff
--- a/.hgtags-top-repo Mon Nov 21 18:48:16 2016 +0000 +++ b/.hgtags-top-repo Wed Jul 05 22:28:55 2017 +0200 @@ -387,3 +387,4 @@ 2b3e5caafe3594ea507c37675c4d3086f415dc64 jdk-9+142 1fc62b1c629fb80fdaa639d3b59452a184f0d705 jdk-9+143 8d337fd6333e28c48aa87880144b840aad82baaf jdk-9+144 +ff98aa9ec9fae991e426ce5926fc9036d25f5562 jdk-9+145
--- a/corba/.hgtags Mon Nov 21 18:48:16 2016 +0000 +++ b/corba/.hgtags Wed Jul 05 22:28:55 2017 +0200 @@ -387,3 +387,4 @@ 408c9c621938ca028e20bced0459f815de47eba8 jdk-9+142 6211236ef15ec796806357608b1dd1b70c258ece jdk-9+143 d4f1dae174098e799c48948e866054c52e11a186 jdk-9+144 +a44b156ae7f06bf41b9bece30df7775e482395dd jdk-9+145
--- a/hotspot/.hgtags Mon Nov 21 18:48:16 2016 +0000 +++ b/hotspot/.hgtags Wed Jul 05 22:28:55 2017 +0200 @@ -547,3 +547,4 @@ 7b48d63dfd6b8e2657288de3d7b1f153dee02d7e jdk-9+142 d87d5d430c42342f0320ca7f5cbe0cbd1f9d62ba jdk-9+143 6187b582d02aee38341dc8ce4011906e9b364e9f jdk-9+144 +61e7ea56312351657e69198c503a6f7bf865af83 jdk-9+145
--- a/hotspot/.mx.jvmci/.pydevproject Mon Nov 21 18:48:16 2016 +0000 +++ b/hotspot/.mx.jvmci/.pydevproject Wed Jul 05 22:28:55 2017 +0200 @@ -1,11 +1,9 @@ <?xml version="1.0" encoding="UTF-8" standalone="no"?> -<?eclipse-pydev version="1.0"?> - -<pydev_project> +<?eclipse-pydev version="1.0"?><pydev_project> <pydev_property name="org.python.pydev.PYTHON_PROJECT_INTERPRETER">Default</pydev_property> <pydev_property name="org.python.pydev.PYTHON_PROJECT_VERSION">python 2.7</pydev_property> <pydev_pathproperty name="org.python.pydev.PROJECT_SOURCE_PATH"> -<path>/mx.jvmci</path> +<path>/.mx.jvmci</path> </pydev_pathproperty> <pydev_pathproperty name="org.python.pydev.PROJECT_SOURCE_PATH"> <path>/mx</path>
--- a/hotspot/make/lib/Lib-jdk.hotspot.agent.gmk Mon Nov 21 18:48:16 2016 +0000 +++ b/hotspot/make/lib/Lib-jdk.hotspot.agent.gmk Wed Jul 05 22:28:55 2017 +0200 @@ -61,9 +61,8 @@ else ifeq ($(OPENJDK_TARGET_OS), solaris) SA_TOOLCHAIN := TOOLCHAIN_LINK_CXX - COMMON_CFLAGS := -DSOLARIS_11_B159_OR_LATER - SA_CFLAGS := $(CFLAGS_JDKLIB) $(COMMON_CFLAGS) - SA_CXXFLAGS := $(CXXFLAGS_JDKLIB) $(COMMON_CFLAGS) + SA_CFLAGS := $(CFLAGS_JDKLIB) + SA_CXXFLAGS := $(CXXFLAGS_JDKLIB) SA_LDFLAGS := $(subst -Wl$(COMMA)-z$(COMMA)defs,, $(LDFLAGS_JDKLIB)) \ -mt $(LDFLAGS_CXX_JDK) SA_LIBS := -ldl -ldemangle -lthread -lc @@ -75,7 +74,7 @@ -mstack-alignment=16 -fPIC SA_LDFLAGS := $(LDFLAGS_JDKLIB) SA_LIBS := -framework Foundation -framework JavaNativeFoundation \ - -framework Security -framework CoreFoundation + -framework JavaRuntimeSupport -framework Security -framework CoreFoundation else ifeq ($(OPENJDK_TARGET_OS), windows) SA_NAME := sawindbg
--- a/hotspot/make/test/JtregNative.gmk Mon Nov 21 18:48:16 2016 +0000 +++ b/hotspot/make/test/JtregNative.gmk Wed Jul 05 22:28:55 2017 +0200 @@ -47,11 +47,13 @@ $(HOTSPOT_TOPDIR)/test/runtime/jni/checked \ $(HOTSPOT_TOPDIR)/test/runtime/jni/PrivateInterfaceMethods \ $(HOTSPOT_TOPDIR)/test/runtime/jni/ToStringInInterfaceTest \ + $(HOTSPOT_TOPDIR)/test/runtime/jni/CalleeSavedRegisters \ $(HOTSPOT_TOPDIR)/test/runtime/modules/getModuleJNI \ $(HOTSPOT_TOPDIR)/test/runtime/SameObject \ $(HOTSPOT_TOPDIR)/test/runtime/BoolReturn \ $(HOTSPOT_TOPDIR)/test/compiler/floatingpoint/ \ $(HOTSPOT_TOPDIR)/test/compiler/calls \ + $(HOTSPOT_TOPDIR)/test/compiler/native \ $(HOTSPOT_TOPDIR)/test/serviceability/jvmti/GetNamedModule \ $(HOTSPOT_TOPDIR)/test/testlibrary/jvmti \ $(HOTSPOT_TOPDIR)/test/compiler/jvmci/jdk.vm.ci.code.test \ @@ -89,6 +91,11 @@ BUILD_HOTSPOT_JTREG_LIBRARIES_LDFLAGS_libtest-rwx := -z execstack BUILD_HOTSPOT_JTREG_EXECUTABLES_LIBS_exeinvoke := -ljvm -lpthread BUILD_TEST_invoke_exeinvoke.c_OPTIMIZATION := NONE + BUILD_HOTSPOT_JTREG_EXECUTABLES_LDFLAGS_exeFPRegs := -ldl +endif + +ifeq ($(OPENJDK_TARGET_OS), windows) + BUILD_HOTSPOT_JTREG_EXECUTABLES_CFLAGS_exeFPRegs := -MT endif BUILD_HOTSPOT_JTREG_OUTPUT_DIR := $(BUILD_OUTPUT)/support/test/hotspot/jtreg/native
--- a/hotspot/src/cpu/aarch64/vm/c1_LIRAssembler_aarch64.cpp Mon Nov 21 18:48:16 2016 +0000 +++ b/hotspot/src/cpu/aarch64/vm/c1_LIRAssembler_aarch64.cpp Wed Jul 05 22:28:55 2017 +0200 @@ -2277,14 +2277,6 @@ __ br(Assembler::HI, *stub->entry()); } - // FIXME: The logic in LIRGenerator::arraycopy_helper clears - // length_positive_check if the source of our length operand is an - // arraylength. However, that arraylength might be zero, and the - // stub that we're about to call contains an assertion that count != - // 0 . So we make this check purely in order not to trigger an - // assertion failure. - __ cbzw(length, *stub->continuation()); - if (flags & LIR_OpArrayCopy::type_check) { // We don't know the array types are compatible if (basic_type != T_OBJECT) {
--- a/hotspot/src/cpu/aarch64/vm/c2_globals_aarch64.hpp Mon Nov 21 18:48:16 2016 +0000 +++ b/hotspot/src/cpu/aarch64/vm/c2_globals_aarch64.hpp Wed Jul 05 22:28:55 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2014, Red Hat Inc. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -72,6 +72,7 @@ define_pd_global(bool, OptoBundling, false); define_pd_global(bool, OptoRegScheduling, false); define_pd_global(bool, SuperWordLoopUnrollAnalysis, true); +define_pd_global(bool, IdealizeClearArrayNode, true); define_pd_global(intx, ReservedCodeCacheSize, 48*M); define_pd_global(intx, NonProfiledCodeHeapSize, 21*M);
--- a/hotspot/src/cpu/aarch64/vm/frame_aarch64.cpp Mon Nov 21 18:48:16 2016 +0000 +++ b/hotspot/src/cpu/aarch64/vm/frame_aarch64.cpp Wed Jul 05 22:28:55 2017 +0200 @@ -142,6 +142,10 @@ } sender_sp = _unextended_sp + _cb->frame_size(); + // Is sender_sp safe? + if ((address)sender_sp >= thread->stack_base()) { + return false; + } sender_unextended_sp = sender_sp; sender_pc = (address) *(sender_sp-1); // Note: frame::sender_sp_offset is only valid for compiled frame @@ -200,8 +204,15 @@ } // construct the potential sender + frame sender(sender_sp, sender_unextended_sp, saved_fp, sender_pc); - return sender.is_entry_frame_valid(thread); + + // Validate the JavaCallWrapper an entry frame must have + address jcw = (address)sender.entry_frame_call_wrapper(); + + bool jcw_safe = (jcw < thread->stack_base()) && (jcw > (address)sender.fp()); + + return jcw_safe; } CompiledMethod* nm = sender_blob->as_compiled_method_or_null();
--- a/hotspot/src/cpu/aarch64/vm/globals_aarch64.hpp Mon Nov 21 18:48:16 2016 +0000 +++ b/hotspot/src/cpu/aarch64/vm/globals_aarch64.hpp Wed Jul 05 22:28:55 2017 +0200 @@ -39,6 +39,7 @@ define_pd_global(bool, TrapBasedNullChecks, false); define_pd_global(bool, UncommonNullCast, true); // Uncommon-trap NULLs past to check cast +define_pd_global(uintx, CodeCacheSegmentSize, 64 TIERED_ONLY(+64)); // Tiered compilation has large code-entry alignment. define_pd_global(intx, CodeEntryAlignment, 64); define_pd_global(intx, OptoLoopAlignment, 16); define_pd_global(intx, InlineFrequencyCount, 100);
--- a/hotspot/src/cpu/aarch64/vm/sharedRuntime_aarch64.cpp Mon Nov 21 18:48:16 2016 +0000 +++ b/hotspot/src/cpu/aarch64/vm/sharedRuntime_aarch64.cpp Wed Jul 05 22:28:55 2017 +0200 @@ -1962,6 +1962,8 @@ // due to cache line collision. __ serialize_memory(rthread, r2); } + } else { + __ strw(rscratch1, Address(rthread, JavaThread::thread_state_offset())); } // check for safepoint operation in progress and/or pending suspend requests
--- a/hotspot/src/cpu/aarch64/vm/templateInterpreterGenerator_aarch64.cpp Mon Nov 21 18:48:16 2016 +0000 +++ b/hotspot/src/cpu/aarch64/vm/templateInterpreterGenerator_aarch64.cpp Wed Jul 05 22:28:55 2017 +0200 @@ -476,6 +476,7 @@ } #endif } +#endif // handle exceptions { Label L;
--- a/hotspot/src/cpu/ppc/vm/assembler_ppc.hpp Mon Nov 21 18:48:16 2016 +0000 +++ b/hotspot/src/cpu/ppc/vm/assembler_ppc.hpp Wed Jul 05 22:28:55 2017 +0200 @@ -2102,7 +2102,9 @@ inline void mfvscr( VectorRegister d); // Vector-Scalar (VSX) instructions. + inline void lxvd2x( VectorSRegister d, Register a); inline void lxvd2x( VectorSRegister d, Register a, Register b); + inline void stxvd2x( VectorSRegister d, Register a); inline void stxvd2x( VectorSRegister d, Register a, Register b); inline void mtvrd( VectorRegister d, Register a); inline void mfvrd( Register a, VectorRegister d);
--- a/hotspot/src/cpu/ppc/vm/assembler_ppc.inline.hpp Mon Nov 21 18:48:16 2016 +0000 +++ b/hotspot/src/cpu/ppc/vm/assembler_ppc.inline.hpp Wed Jul 05 22:28:55 2017 +0200 @@ -734,8 +734,10 @@ inline void Assembler::lvsr( VectorRegister d, Register s1, Register s2) { emit_int32( LVSR_OPCODE | vrt(d) | ra0mem(s1) | rb(s2)); } // Vector-Scalar (VSX) instructions. -inline void Assembler::lxvd2x (VectorSRegister d, Register s1, Register s2) { emit_int32( LXVD2X_OPCODE | vsrt(d) | ra(s1) | rb(s2)); } -inline void Assembler::stxvd2x(VectorSRegister d, Register s1, Register s2) { emit_int32( STXVD2X_OPCODE | vsrt(d) | ra(s1) | rb(s2)); } +inline void Assembler::lxvd2x (VectorSRegister d, Register s1) { emit_int32( LXVD2X_OPCODE | vsrt(d) | ra(0) | rb(s1)); } +inline void Assembler::lxvd2x (VectorSRegister d, Register s1, Register s2) { emit_int32( LXVD2X_OPCODE | vsrt(d) | ra0mem(s1) | rb(s2)); } +inline void Assembler::stxvd2x(VectorSRegister d, Register s1) { emit_int32( STXVD2X_OPCODE | vsrt(d) | ra(0) | rb(s1)); } +inline void Assembler::stxvd2x(VectorSRegister d, Register s1, Register s2) { emit_int32( STXVD2X_OPCODE | vsrt(d) | ra0mem(s1) | rb(s2)); } inline void Assembler::mtvrd( VectorRegister d, Register a) { emit_int32( MTVSRD_OPCODE | vrt(d) | ra(a) | 1u); } // 1u: d is treated as Vector (VMX/Altivec). inline void Assembler::mfvrd( Register a, VectorRegister d) { emit_int32( MFVSRD_OPCODE | vrt(d) | ra(a) | 1u); } // 1u: d is treated as Vector (VMX/Altivec).
--- a/hotspot/src/cpu/ppc/vm/c1_LIRAssembler_ppc.cpp Mon Nov 21 18:48:16 2016 +0000 +++ b/hotspot/src/cpu/ppc/vm/c1_LIRAssembler_ppc.cpp Wed Jul 05 22:28:55 2017 +0200 @@ -1894,15 +1894,18 @@ __ beq(combined_check, slow); } + // If the compiler was not able to prove that exact type of the source or the destination + // of the arraycopy is an array type, check at runtime if the source or the destination is + // an instance type. if (flags & LIR_OpArrayCopy::type_check) { - if (!(flags & LIR_OpArrayCopy::LIR_OpArrayCopy::dst_objarray)) { + if (!(flags & LIR_OpArrayCopy::dst_objarray)) { __ load_klass(tmp, dst); __ lwz(tmp2, in_bytes(Klass::layout_helper_offset()), tmp); __ cmpwi(CCR0, tmp2, Klass::_lh_neutral_value); __ bge(CCR0, slow); } - if (!(flags & LIR_OpArrayCopy::LIR_OpArrayCopy::src_objarray)) { + if (!(flags & LIR_OpArrayCopy::src_objarray)) { __ load_klass(tmp, src); __ lwz(tmp2, in_bytes(Klass::layout_helper_offset()), tmp); __ cmpwi(CCR0, tmp2, Klass::_lh_neutral_value);
--- a/hotspot/src/cpu/ppc/vm/c2_globals_ppc.hpp Mon Nov 21 18:48:16 2016 +0000 +++ b/hotspot/src/cpu/ppc/vm/c2_globals_ppc.hpp Wed Jul 05 22:28:55 2017 +0200 @@ -1,6 +1,6 @@ /* - * Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2012, 2015 SAP SE. All rights reserved. + * Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2016 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -80,6 +80,7 @@ // loc = x.f // NullCheck loc define_pd_global(bool, OptoScheduling, false); +define_pd_global(bool, IdealizeClearArrayNode, true); define_pd_global(intx, InitialCodeCacheSize, 2048*K); // Integral multiple of CodeCacheExpansionSize define_pd_global(intx, ReservedCodeCacheSize, 256*M);
--- a/hotspot/src/cpu/ppc/vm/frame_ppc.cpp Mon Nov 21 18:48:16 2016 +0000 +++ b/hotspot/src/cpu/ppc/vm/frame_ppc.cpp Wed Jul 05 22:28:55 2017 +0200 @@ -221,6 +221,7 @@ values.describe(frame_no, (intptr_t*)&(get_ijava_state()->name), #name); DESCRIBE_ADDRESS(method); + DESCRIBE_ADDRESS(mirror); DESCRIBE_ADDRESS(locals); DESCRIBE_ADDRESS(monitors); DESCRIBE_ADDRESS(cpoolCache);
--- a/hotspot/src/cpu/ppc/vm/frame_ppc.hpp Mon Nov 21 18:48:16 2016 +0000 +++ b/hotspot/src/cpu/ppc/vm/frame_ppc.hpp Wed Jul 05 22:28:55 2017 +0200 @@ -257,8 +257,7 @@ struct ijava_state { #ifdef ASSERT - uint64_t ijava_reserved; // Used for assertion. - uint64_t ijava_reserved2; // Inserted for alignment. + uint64_t ijava_reserved; // Used for assertion. #endif uint64_t method; uint64_t mirror; @@ -274,7 +273,6 @@ uint64_t oop_tmp; uint64_t lresult; uint64_t fresult; - // Aligned to frame::alignment_in_bytes (16). }; enum {
--- a/hotspot/src/cpu/ppc/vm/globals_ppc.hpp Mon Nov 21 18:48:16 2016 +0000 +++ b/hotspot/src/cpu/ppc/vm/globals_ppc.hpp Wed Jul 05 22:28:55 2017 +0200 @@ -56,10 +56,11 @@ define_pd_global(intx, StackReservedPages, DEFAULT_STACK_RESERVED_PAGES); // Use large code-entry alignment. -define_pd_global(intx, CodeEntryAlignment, 128); -define_pd_global(intx, OptoLoopAlignment, 16); -define_pd_global(intx, InlineFrequencyCount, 100); -define_pd_global(intx, InlineSmallCode, 1500); +define_pd_global(uintx, CodeCacheSegmentSize, 128); +define_pd_global(intx, CodeEntryAlignment, 128); +define_pd_global(intx, OptoLoopAlignment, 16); +define_pd_global(intx, InlineFrequencyCount, 100); +define_pd_global(intx, InlineSmallCode, 1500); // Flags for template interpreter. define_pd_global(bool, RewriteBytecodes, true);
--- a/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.cpp Mon Nov 21 18:48:16 2016 +0000 +++ b/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.cpp Wed Jul 05 22:28:55 2017 +0200 @@ -1922,7 +1922,7 @@ // Check the supertype display: if (must_load_sco) { // The super check offset is always positive... - lwz(check_cache_offset, sco_offset, super_klass); + lwz(check_cache_offset, sco_offset, super_klass); super_check_offset = RegisterOrConstant(check_cache_offset); // super_check_offset is register. assert_different_registers(sub_klass, super_klass, cached_super, super_check_offset.as_register()); @@ -3325,12 +3325,10 @@ } } -void MacroAssembler::load_mirror(Register mirror, Register method) { - const int mirror_offset = in_bytes(Klass::java_mirror_offset()); - ld(mirror, in_bytes(Method::const_offset()), method); - ld(mirror, in_bytes(ConstMethod::constants_offset()), mirror); +void MacroAssembler::load_mirror_from_const_method(Register mirror, Register const_method) { + ld(mirror, in_bytes(ConstMethod::constants_offset()), const_method); ld(mirror, ConstantPool::pool_holder_offset_in_bytes(), mirror); - ld(mirror, mirror_offset, mirror); + ld(mirror, in_bytes(Klass::java_mirror_offset()), mirror); } // Clear Array @@ -4345,8 +4343,8 @@ * @param t3 volatile register */ void MacroAssembler::kernel_crc32_1word_vpmsumd(Register crc, Register buf, Register len, Register table, - Register constants, Register barretConstants, - Register t0, Register t1, Register t2, Register t3, Register t4) { + Register constants, Register barretConstants, + Register t0, Register t1, Register t2, Register t3, Register t4) { assert_different_registers(crc, buf, len, table); Label L_alignedHead, L_tail, L_alignTail, L_start, L_end;
--- a/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.hpp Mon Nov 21 18:48:16 2016 +0000 +++ b/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.hpp Wed Jul 05 22:28:55 2017 +0200 @@ -723,7 +723,7 @@ void store_klass(Register dst_oop, Register klass, Register tmp = R0); void store_klass_gap(Register dst_oop, Register val = noreg); // Will store 0 if val not specified. - void load_mirror(Register mirror, Register method); + void load_mirror_from_const_method(Register mirror, Register const_method); static int instr_size_for_decode_klass_not_null(); void decode_klass_not_null(Register dst, Register src = noreg);
--- a/hotspot/src/cpu/ppc/vm/ppc.ad Mon Nov 21 18:48:16 2016 +0000 +++ b/hotspot/src/cpu/ppc/vm/ppc.ad Wed Jul 05 22:28:55 2017 +0200 @@ -11237,6 +11237,17 @@ ins_pipe(pipe_class_compare); %} +instruct cmpP_reg_null(flagsReg crx, iRegP_N2P src1, immP_0or1 src2) %{ + match(Set crx (CmpP src1 src2)); + format %{ "CMPLDI $crx, $src1, $src2 \t// ptr" %} + size(4); + ins_encode %{ + // TODO: PPC port $archOpcode(ppc64Opcode_cmpl); + __ cmpldi($crx$$CondRegister, $src1$$Register, (int)((short)($src2$$constant & 0xFFFF))); + %} + ins_pipe(pipe_class_compare); +%} + // Used in postalloc expand. instruct cmpP_reg_imm16(flagsReg crx, iRegPsrc src1, immL16 src2) %{ // This match rule prevents reordering of node before a safepoint.
--- a/hotspot/src/cpu/ppc/vm/stubGenerator_ppc.cpp Mon Nov 21 18:48:16 2016 +0000 +++ b/hotspot/src/cpu/ppc/vm/stubGenerator_ppc.cpp Wed Jul 05 22:28:55 2017 +0200 @@ -1220,8 +1220,8 @@ __ bind(l_10); // Use loop with VSX load/store instructions to // copy 32 elements a time. - __ lxvd2x(tmp_vsr1, 0, R3_ARG1); // Load src - __ stxvd2x(tmp_vsr1, 0, R4_ARG2); // Store to dst + __ lxvd2x(tmp_vsr1, R3_ARG1); // Load src + __ stxvd2x(tmp_vsr1, R4_ARG2); // Store to dst __ lxvd2x(tmp_vsr2, tmp1, R3_ARG1); // Load src + 16 __ stxvd2x(tmp_vsr2, tmp1, R4_ARG2); // Store to dst + 16 __ addi(R3_ARG1, R3_ARG1, 32); // Update src+=32 @@ -1486,8 +1486,8 @@ __ bind(l_9); // Use loop with VSX load/store instructions to // copy 16 elements a time. - __ lxvd2x(tmp_vsr1, 0, R3_ARG1); // Load from src. - __ stxvd2x(tmp_vsr1, 0, R4_ARG2); // Store to dst. + __ lxvd2x(tmp_vsr1, R3_ARG1); // Load from src. + __ stxvd2x(tmp_vsr1, R4_ARG2); // Store to dst. __ lxvd2x(tmp_vsr2, R3_ARG1, tmp1); // Load from src + 16. __ stxvd2x(tmp_vsr2, R4_ARG2, tmp1); // Store to dst + 16. __ addi(R3_ARG1, R3_ARG1, 32); // Update src+=32. @@ -1677,8 +1677,8 @@ __ bind(l_7); // Use loop with VSX load/store instructions to // copy 8 elements a time. - __ lxvd2x(tmp_vsr1, 0, R3_ARG1); // Load src - __ stxvd2x(tmp_vsr1, 0, R4_ARG2); // Store to dst + __ lxvd2x(tmp_vsr1, R3_ARG1); // Load src + __ stxvd2x(tmp_vsr1, R4_ARG2); // Store to dst __ lxvd2x(tmp_vsr2, tmp1, R3_ARG1); // Load src + 16 __ stxvd2x(tmp_vsr2, tmp1, R4_ARG2); // Store to dst + 16 __ addi(R3_ARG1, R3_ARG1, 32); // Update src+=32 @@ -1745,13 +1745,16 @@ // Do reverse copy. We assume the case of actual overlap is rare enough // that we don't have to optimize it. - Label l_1, l_2, l_3, l_4, l_5, l_6; + Label l_1, l_2, l_3, l_4, l_5, l_6, l_7; Register tmp1 = R6_ARG4; Register tmp2 = R7_ARG5; Register tmp3 = R8_ARG6; Register tmp4 = R0; + VectorSRegister tmp_vsr1 = VSR1; + VectorSRegister tmp_vsr2 = VSR2; + { // FasterArrayCopy __ cmpwi(CCR0, R5_ARG3, 0); __ beq(CCR0, l_6); @@ -1761,6 +1764,25 @@ __ add(R4_ARG2, R4_ARG2, R5_ARG3); __ srdi(R5_ARG3, R5_ARG3, 2); + if (!aligned) { + // check if arrays have same alignment mod 8. + __ xorr(tmp1, R3_ARG1, R4_ARG2); + __ andi_(R0, tmp1, 7); + // Not the same alignment, but ld and std just need to be 4 byte aligned. + __ bne(CCR0, l_7); // to OR from is 8 byte aligned -> copy 2 at a time + + // copy 1 element to align to and from on an 8 byte boundary + __ andi_(R0, R3_ARG1, 7); + __ beq(CCR0, l_7); + + __ addi(R3_ARG1, R3_ARG1, -4); + __ addi(R4_ARG2, R4_ARG2, -4); + __ addi(R5_ARG3, R5_ARG3, -1); + __ lwzx(tmp2, R3_ARG1); + __ stwx(tmp2, R4_ARG2); + __ bind(l_7); + } + __ cmpwi(CCR0, R5_ARG3, 7); __ ble(CCR0, l_5); // copy 1 at a time if less than 8 elements remain @@ -1768,6 +1790,7 @@ __ andi(R5_ARG3, R5_ARG3, 7); __ mtctr(tmp1); + if (!VM_Version::has_vsx()) { __ bind(l_4); // Use unrolled version for mass copying (copy 4 elements a time). // Load feeding store gets zero latency on Power6, however not on Power5. @@ -1783,6 +1806,40 @@ __ std(tmp2, 8, R4_ARG2); __ std(tmp1, 0, R4_ARG2); __ bdnz(l_4); + } else { // Processor supports VSX, so use it to mass copy. + // Prefetch the data into the L2 cache. + __ dcbt(R3_ARG1, 0); + + // If supported set DSCR pre-fetch to deepest. + if (VM_Version::has_mfdscr()) { + __ load_const_optimized(tmp2, VM_Version::_dscr_val | 7); + __ mtdscr(tmp2); + } + + __ li(tmp1, 16); + + // Backbranch target aligned to 32-byte. Not 16-byte align as + // loop contains < 8 instructions that fit inside a single + // i-cache sector. + __ align(32); + + __ bind(l_4); + // Use loop with VSX load/store instructions to + // copy 8 elements a time. + __ addi(R3_ARG1, R3_ARG1, -32); // Update src-=32 + __ addi(R4_ARG2, R4_ARG2, -32); // Update dsc-=32 + __ lxvd2x(tmp_vsr2, tmp1, R3_ARG1); // Load src+16 + __ lxvd2x(tmp_vsr1, R3_ARG1); // Load src + __ stxvd2x(tmp_vsr2, tmp1, R4_ARG2); // Store to dst+16 + __ stxvd2x(tmp_vsr1, R4_ARG2); // Store to dst + __ bdnz(l_4); + + // Restore DSCR pre-fetch value. + if (VM_Version::has_mfdscr()) { + __ load_const_optimized(tmp2, VM_Version::_dscr_val); + __ mtdscr(tmp2); + } + } __ cmpwi(CCR0, R5_ARG3, 0); __ beq(CCR0, l_6); @@ -1892,8 +1949,8 @@ __ bind(l_5); // Use loop with VSX load/store instructions to // copy 4 elements a time. - __ lxvd2x(tmp_vsr1, 0, R3_ARG1); // Load src - __ stxvd2x(tmp_vsr1, 0, R4_ARG2); // Store to dst + __ lxvd2x(tmp_vsr1, R3_ARG1); // Load src + __ stxvd2x(tmp_vsr1, R4_ARG2); // Store to dst __ lxvd2x(tmp_vsr2, tmp1, R3_ARG1); // Load src + 16 __ stxvd2x(tmp_vsr2, tmp1, R4_ARG2); // Store to dst + 16 __ addi(R3_ARG1, R3_ARG1, 32); // Update src+=32 @@ -1962,6 +2019,9 @@ Register tmp3 = R8_ARG6; Register tmp4 = R0; + VectorSRegister tmp_vsr1 = VSR1; + VectorSRegister tmp_vsr2 = VSR2; + Label l_1, l_2, l_3, l_4, l_5; __ cmpwi(CCR0, R5_ARG3, 0); @@ -1980,6 +2040,7 @@ __ andi(R5_ARG3, R5_ARG3, 3); __ mtctr(tmp1); + if (!VM_Version::has_vsx()) { __ bind(l_4); // Use unrolled version for mass copying (copy 4 elements a time). // Load feeding store gets zero latency on Power6, however not on Power5. @@ -1995,6 +2056,40 @@ __ std(tmp2, 8, R4_ARG2); __ std(tmp1, 0, R4_ARG2); __ bdnz(l_4); + } else { // Processor supports VSX, so use it to mass copy. + // Prefetch the data into the L2 cache. + __ dcbt(R3_ARG1, 0); + + // If supported set DSCR pre-fetch to deepest. + if (VM_Version::has_mfdscr()) { + __ load_const_optimized(tmp2, VM_Version::_dscr_val | 7); + __ mtdscr(tmp2); + } + + __ li(tmp1, 16); + + // Backbranch target aligned to 32-byte. Not 16-byte align as + // loop contains < 8 instructions that fit inside a single + // i-cache sector. + __ align(32); + + __ bind(l_4); + // Use loop with VSX load/store instructions to + // copy 4 elements a time. + __ addi(R3_ARG1, R3_ARG1, -32); // Update src-=32 + __ addi(R4_ARG2, R4_ARG2, -32); // Update dsc-=32 + __ lxvd2x(tmp_vsr2, tmp1, R3_ARG1); // Load src+16 + __ lxvd2x(tmp_vsr1, R3_ARG1); // Load src + __ stxvd2x(tmp_vsr2, tmp1, R4_ARG2); // Store to dst+16 + __ stxvd2x(tmp_vsr1, R4_ARG2); // Store to dst + __ bdnz(l_4); + + // Restore DSCR pre-fetch value. + if (VM_Version::has_mfdscr()) { + __ load_const_optimized(tmp2, VM_Version::_dscr_val); + __ mtdscr(tmp2); + } + } __ cmpwi(CCR0, R5_ARG3, 0); __ beq(CCR0, l_1);
--- a/hotspot/src/cpu/ppc/vm/templateInterpreterGenerator_ppc.cpp Mon Nov 21 18:48:16 2016 +0000 +++ b/hotspot/src/cpu/ppc/vm/templateInterpreterGenerator_ppc.cpp Wed Jul 05 22:28:55 2017 +0200 @@ -915,7 +915,9 @@ __ b(Ldone); __ bind(Lstatic); // Static case: Lock the java mirror - __ load_mirror(Robj_to_lock, R19_method); + // Load mirror from interpreter frame. + __ ld(Robj_to_lock, _abi(callers_sp), R1_SP); + __ ld(Robj_to_lock, _ijava_state_neg(mirror), Robj_to_lock); __ bind(Ldone); __ verify_oop(Robj_to_lock); @@ -1077,12 +1079,12 @@ __ resize_frame(parent_frame_resize, R11_scratch1); __ std(R12_scratch2, _abi(lr), R1_SP); + // Get mirror and store it in the frame as GC root for this Method*. + __ load_mirror_from_const_method(R12_scratch2, Rconst_method); + __ addi(R26_monitor, R1_SP, - frame::ijava_state_size); __ addi(R15_esp, R26_monitor, - Interpreter::stackElementSize); - // Get mirror and store it in the frame as GC root for this Method*. - __ load_mirror(R12_scratch2, R19_method); - // Store values. // R15_esp, R14_bcp, R26_monitor, R28_mdx are saved at java calls // in InterpreterMacroAssembler::call_from_interpreter. @@ -1380,13 +1382,12 @@ __ testbitdi(CCR0, R0, access_flags, JVM_ACC_STATIC_BIT); __ bfalse(CCR0, method_is_not_static); - __ load_mirror(R12_scratch2, R19_method); - // state->_native_mirror = mirror; - - __ ld(R11_scratch1, 0, R1_SP); - __ std(R12_scratch2/*mirror*/, _ijava_state_neg(oop_tmp), R11_scratch1); + __ ld(R11_scratch1, _abi(callers_sp), R1_SP); + // Load mirror from interpreter frame. + __ ld(R12_scratch2, _ijava_state_neg(mirror), R11_scratch1); // R4_ARG2 = &state->_oop_temp; __ addi(R4_ARG2, R11_scratch1, _ijava_state_neg(oop_tmp)); + __ std(R12_scratch2/*mirror*/, _ijava_state_neg(oop_tmp), R11_scratch1); BIND(method_is_not_static); } @@ -2157,12 +2158,12 @@ // Restoration of lr done by remove_activation. switch (state) { // Narrow result if state is itos but result type is smaller. - case itos: __ narrow(R17_tos); /* fall through */ - case ltos: case btos: case ztos: case ctos: case stos: + case itos: __ narrow(R17_tos); /* fall through */ + case ltos: case atos: __ mr(R3_RET, R17_tos); break; case ftos: case dtos: __ fmr(F1_RET, F15_ftos); break;
--- a/hotspot/src/cpu/ppc/vm/templateTable_ppc_64.cpp Mon Nov 21 18:48:16 2016 +0000 +++ b/hotspot/src/cpu/ppc/vm/templateTable_ppc_64.cpp Wed Jul 05 22:28:55 2017 +0200 @@ -2133,10 +2133,6 @@ // since compiled code callers expect the result to already be narrowed. case itos: __ narrow(R17_tos); /* fall through */ case ltos: - case btos: - case ztos: - case ctos: - case stos: case atos: __ mr(R3_RET, R17_tos); break; case ftos: case dtos: __ fmr(F1_RET, F15_ftos); break; @@ -2548,7 +2544,6 @@ assert(branch_table[ztos] == 0, "can't compute twice"); branch_table[ztos] = __ pc(); // non-volatile_entry point __ lbzx(R17_tos, Rclass_or_obj, Roffset); - __ extsb(R17_tos, R17_tos); __ push(ztos); if (!is_static && rc == may_rewrite) { // use btos rewriting, no truncating to t/f bit is needed for getfield.
--- a/hotspot/src/cpu/ppc/vm/vm_version_ppc.cpp Mon Nov 21 18:48:16 2016 +0000 +++ b/hotspot/src/cpu/ppc/vm/vm_version_ppc.cpp Wed Jul 05 22:28:55 2017 +0200 @@ -656,7 +656,7 @@ a->vpmsumb(VR0, VR1, VR2); // code[11] -> vpmsumb a->tcheck(0); // code[12] -> tcheck a->mfdscr(R0); // code[13] -> mfdscr - a->lxvd2x(VSR0, 0, R3_ARG1); // code[14] -> vsx + a->lxvd2x(VSR0, R3_ARG1); // code[14] -> vsx a->blr(); // Emit function to set one cache line to zero. Emit function descriptor and get pointer to it.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/cpu/s390/vm/abstractInterpreter_s390.cpp Wed Jul 05 22:28:55 2017 +0200 @@ -0,0 +1,210 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016 SAP SE. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#include "precompiled.hpp" +#include "interpreter/interpreter.hpp" +#include "oops/constMethod.hpp" +#include "oops/method.hpp" +#include "runtime/frame.inline.hpp" +#include "utilities/debug.hpp" +#include "utilities/macros.hpp" + +int AbstractInterpreter::BasicType_as_index(BasicType type) { + int i = 0; + switch (type) { + case T_BOOLEAN: i = 0; break; + case T_CHAR : i = 1; break; + case T_BYTE : i = 2; break; + case T_SHORT : i = 3; break; + case T_INT : i = 4; break; + case T_LONG : i = 5; break; + case T_VOID : i = 6; break; + case T_FLOAT : i = 7; break; + case T_DOUBLE : i = 8; break; + case T_OBJECT : i = 9; break; + case T_ARRAY : i = 9; break; + default : ShouldNotReachHere(); + } + assert(0 <= i && i < AbstractInterpreter::number_of_result_handlers, "index out of bounds"); + return i; +} + +bool AbstractInterpreter::can_be_compiled(methodHandle m) { + // No special entry points that preclude compilation. + return true; +} + +// How much stack a method top interpreter activation needs in words. +int AbstractInterpreter::size_top_interpreter_activation(Method* method) { + + // We have to size the following 2 frames: + // + // [TOP_IJAVA_FRAME_ABI] + // [ENTRY_FRAME] + // + // This expands to (see frame_s390.hpp): + // + // [TOP_IJAVA_FRAME_ABI] + // [operand stack] > stack + // [monitors] (optional) > monitors + // [IJAVA_STATE] > interpreter_state + // [PARENT_IJAVA_FRAME_ABI] + // [callee's locals w/o arguments] \ locals + // [outgoing arguments] / + // [ENTRY_FRAME_LOCALS] + + int locals = method->max_locals() * BytesPerWord; + int interpreter_state = frame::z_ijava_state_size; + + int stack = method->max_stack() * BytesPerWord; + int monitors = method->is_synchronized() ? frame::interpreter_frame_monitor_size_in_bytes() : 0; + + int total_bytes = + frame::z_top_ijava_frame_abi_size + + stack + + monitors + + interpreter_state + + frame::z_parent_ijava_frame_abi_size + + locals + + frame::z_entry_frame_locals_size; + + return (total_bytes/BytesPerWord); +} + +// Returns number of stackElementWords needed for the interpreter frame with the +// given sections. +// This overestimates the stack by one slot in case of alignments. +int AbstractInterpreter::size_activation(int max_stack, + int temps, + int extra_args, + int monitors, + int callee_params, + int callee_locals, + bool is_top_frame) { + // Note: This calculation must exactly parallel the frame setup + // in AbstractInterpreterGenerator::generate_method_entry. + + assert((Interpreter::stackElementSize == frame::alignment_in_bytes), "must align frame size"); + const int abi_scratch = is_top_frame ? (frame::z_top_ijava_frame_abi_size / Interpreter::stackElementSize) : + (frame::z_parent_ijava_frame_abi_size / Interpreter::stackElementSize); + + const int size = + max_stack + + (callee_locals - callee_params) + // Already counted in max_stack(). + monitors * frame::interpreter_frame_monitor_size() + + abi_scratch + + frame::z_ijava_state_size / Interpreter::stackElementSize; + + // Fixed size of an interpreter frame. + return size; +} + +// Fills a sceletal interpreter frame generated during deoptimizations. +// +// Parameters: +// +// interpreter_frame != NULL: +// set up the method, locals, and monitors. +// The frame interpreter_frame, if not NULL, is guaranteed to be the +// right size, as determined by a previous call to this method. +// It is also guaranteed to be walkable even though it is in a skeletal state +// +// is_top_frame == true: +// We're processing the *oldest* interpreter frame! +// +// pop_frame_extra_args: +// If this is != 0 we are returning to a deoptimized frame by popping +// off the callee frame. We want to re-execute the call that called the +// callee interpreted, but since the return to the interpreter would pop +// the arguments off advance the esp by dummy popframe_extra_args slots. +// Popping off those will establish the stack layout as it was before the call. +// + +void AbstractInterpreter::layout_activation(Method* method, + int tempcount, + int popframe_extra_args, + int moncount, + int caller_actual_parameters, + int callee_param_count, + int callee_locals_count, + frame* caller, + frame* interpreter_frame, + bool is_top_frame, + bool is_bottom_frame) { + // TOP_IJAVA_FRAME: + // + // 0 [TOP_IJAVA_FRAME_ABI] -+ + // 16 [operand stack] | size + // [monitors] (optional) | + // [IJAVA_STATE] -+ + // Note: own locals are located in the caller frame. + // + // PARENT_IJAVA_FRAME: + // + // 0 [PARENT_IJAVA_FRAME_ABI] -+ + // [callee's locals w/o arguments] | + // [outgoing arguments] | size + // [used part of operand stack w/o arguments] | + // [monitors] (optional) | + // [IJAVA_STATE] -+ + // + + // Now we know our caller, calc the exact frame layout and size + // z_ijava_state->locals - i*BytesPerWord points to i-th Java local (i starts at 0). + intptr_t* locals_base = (caller->is_interpreted_frame()) + ? (caller->interpreter_frame_tos_address() + caller_actual_parameters - 1) + : (caller->sp() + method->max_locals() - 1 + + frame::z_parent_ijava_frame_abi_size / Interpreter::stackElementSize); + + intptr_t* monitor_base = (intptr_t*)((address)interpreter_frame->fp() - frame::z_ijava_state_size); + intptr_t* monitor = monitor_base - (moncount * frame::interpreter_frame_monitor_size()); + intptr_t* operand_stack_base = monitor; + intptr_t* tos = operand_stack_base - tempcount - popframe_extra_args; + intptr_t* top_frame_sp = + operand_stack_base - method->max_stack() - frame::z_top_ijava_frame_abi_size / Interpreter::stackElementSize; + intptr_t* sender_sp; + if (caller->is_interpreted_frame()) { + sender_sp = caller->interpreter_frame_top_frame_sp(); + } else if (caller->is_compiled_frame()) { + sender_sp = caller->fp() - caller->cb()->frame_size(); + // The bottom frame's sender_sp is its caller's unextended_sp. + // It was already set when its skeleton was pushed (see push_skeleton_frames()). + // Note: the unextended_sp is required by nmethod::orig_pc_addr(). + assert(is_bottom_frame && (sender_sp == caller->unextended_sp()), + "must initialize sender_sp of bottom skeleton frame when pushing it"); + } else { + assert(caller->is_entry_frame(), "is there a new frame type??"); + sender_sp = caller->sp(); // Call_stub only uses it's fp. + } + + interpreter_frame->interpreter_frame_set_method(method); + interpreter_frame->interpreter_frame_set_mirror(method->method_holder()->java_mirror()); + interpreter_frame->interpreter_frame_set_locals(locals_base); + interpreter_frame->interpreter_frame_set_monitor_end((BasicObjectLock *)monitor); + *interpreter_frame->interpreter_frame_cache_addr() = method->constants()->cache(); + interpreter_frame->interpreter_frame_set_tos_address(tos); + interpreter_frame->interpreter_frame_set_sender_sp(sender_sp); + interpreter_frame->interpreter_frame_set_top_frame_sp(top_frame_sp); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/cpu/s390/vm/assembler_s390.cpp Wed Jul 05 22:28:55 2017 +0200 @@ -0,0 +1,171 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016 SAP SE. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#include "precompiled.hpp" +#include "asm/assembler.inline.hpp" +#include "compiler/disassembler.hpp" +#include "gc/shared/collectedHeap.inline.hpp" +#include "interpreter/interpreter.hpp" +#include "gc/shared/cardTableModRefBS.hpp" +#include "memory/resourceArea.hpp" +#include "prims/methodHandles.hpp" +#include "runtime/biasedLocking.hpp" +#include "runtime/interfaceSupport.hpp" +#include "runtime/objectMonitor.hpp" +#include "runtime/os.hpp" +#include "runtime/sharedRuntime.hpp" +#include "runtime/stubRoutines.hpp" +#include "utilities/macros.hpp" +#if INCLUDE_ALL_GCS +#include "gc/g1/g1CollectedHeap.inline.hpp" +#include "gc/g1/g1SATBCardTableModRefBS.hpp" +#include "gc/g1/heapRegion.hpp" +#endif + +// Convention: Use Z_R0 and Z_R1 instead of Z_scratch_* in all +// assembler_s390.* files. + +// Convert the raw encoding form into the form expected by the +// constructor for Address. This is called by adlc generated code. +Address Address::make_raw(int base, int index, int scale, int disp, relocInfo::relocType disp_reloc) { + assert(scale == 0, "Scale should not be used on z/Architecture. The call to make_raw is " + "generated by adlc and this must mirror all features of Operands from machnode.hpp."); + assert(disp_reloc == relocInfo::none, "not implemented on z/Architecture."); + + Address madr(as_Register(base), as_Register(index), in_ByteSize(disp)); + return madr; +} + +int AbstractAssembler::code_fill_byte() { + return 0x00; // Illegal instruction 0x00000000. +} + +// Condition code masks. Details see enum branch_condition. +// Although this method is meant for INT CCs, the Overflow/Ordered +// bit in the masks has to be considered. The CC might have been set +// by a float operation, but is evaluated while calculating an integer +// result. See elementary test TestFloat.isNotEqual(FF)Z for example. +Assembler::branch_condition Assembler::inverse_condition(Assembler::branch_condition cc) { + Assembler::branch_condition unordered_bit = (Assembler::branch_condition)(cc & bcondNotOrdered); + Assembler::branch_condition inverse_cc; + + // Some are commented out to avoid duplicate labels. + switch (cc) { + case bcondNever : inverse_cc = bcondAlways; break; // 0 -> 15 + case bcondAlways : inverse_cc = bcondNever; break; // 15 -> 0 + + case bcondOverflow : inverse_cc = bcondNotOverflow; break; // 1 -> 14 + case bcondNotOverflow : inverse_cc = bcondOverflow; break; // 14 -> 1 + + default : + switch ((Assembler::branch_condition)(cc & bcondOrdered)) { + case bcondEqual : inverse_cc = bcondNotEqual; break; // 8 -> 6 + // case bcondZero : + // case bcondAllZero : + + case bcondNotEqual : inverse_cc = bcondEqual; break; // 6 -> 8 + // case bcondNotZero : + // case bcondMixed : + + case bcondLow : inverse_cc = bcondNotLow; break; // 4 -> 10 + // case bcondNegative : + + case bcondNotLow : inverse_cc = bcondLow; break; // 10 -> 4 + // case bcondNotNegative : + + case bcondHigh : inverse_cc = bcondNotHigh; break; // 2 -> 12 + // case bcondPositive : + + case bcondNotHigh : inverse_cc = bcondHigh; break; // 12 -> 2 + // case bcondNotPositive : + + default : + fprintf(stderr, "inverse_condition(%d)\n", (int)cc); + fflush(stderr); + ShouldNotReachHere(); + return bcondNever; + } + // If cc is even, inverse_cc must be odd. + if (!unordered_bit) { + inverse_cc = (Assembler::branch_condition)(inverse_cc | bcondNotOrdered); + } + break; + } + return inverse_cc; +} + +Assembler::branch_condition Assembler::inverse_float_condition(Assembler::branch_condition cc) { + Assembler::branch_condition inverse_cc; + + switch (cc) { + case bcondNever : inverse_cc = bcondAlways; break; // 0 + case bcondAlways : inverse_cc = bcondNever; break; // 15 + + case bcondNotOrdered : inverse_cc = bcondOrdered; break; // 14 + case bcondOrdered : inverse_cc = bcondNotOrdered; break; // 1 + + case bcondEqual : inverse_cc = (branch_condition)(bcondNotEqual + bcondNotOrdered); break; // 8 + case bcondNotEqual + bcondNotOrdered : inverse_cc = bcondEqual; break; // 7 + + case bcondLow + bcondNotOrdered : inverse_cc = (branch_condition)(bcondHigh + bcondEqual); break; // 5 + case bcondNotLow : inverse_cc = (branch_condition)(bcondLow + bcondNotOrdered); break; // 10 + + case bcondHigh : inverse_cc = (branch_condition)(bcondLow + bcondNotOrdered + bcondEqual); break; // 2 + case bcondNotHigh + bcondNotOrdered : inverse_cc = bcondHigh; break; // 13 + + default : + fprintf(stderr, "inverse_float_condition(%d)\n", (int)cc); + fflush(stderr); + ShouldNotReachHere(); + return bcondNever; + } + return inverse_cc; +} + +#ifdef ASSERT +void Assembler::print_dbg_msg(outputStream* out, unsigned long inst, const char* msg, int ilen) { + out->flush(); + switch (ilen) { + case 2: out->print_cr("inst = %4.4x, %s", (unsigned short)inst, msg); break; + case 4: out->print_cr("inst = %8.8x, %s\n", (unsigned int)inst, msg); break; + case 6: out->print_cr("inst = %12.12lx, %s\n", inst, msg); break; + default: out->print_cr("inst = %16.16lx, %s\n", inst, msg); break; + } + out->flush(); +} + +void Assembler::dump_code_range(outputStream* out, address pc, const unsigned int range, const char* msg) { + out->cr(); + out->print_cr("-------------------------------"); + out->print_cr("-- %s", msg); + out->print_cr("-------------------------------"); + out->print_cr("Hex dump of +/-%d bytes around %p, interval [%p,%p)", range, pc, pc-range, pc+range); + os::print_hex_dump(out, pc-range, pc+range, 2); + + out->cr(); + out->print_cr("Disassembly of +/-%d bytes around %p, interval [%p,%p)", range, pc, pc-range, pc+range); + Disassembler::decode(pc, pc + range, out); +} +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/cpu/s390/vm/assembler_s390.hpp Wed Jul 05 22:28:55 2017 +0200 @@ -0,0 +1,2530 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016 SAP SE. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef CPU_S390_VM_ASSEMBLER_S390_HPP +#define CPU_S390_VM_ASSEMBLER_S390_HPP + +#undef LUCY_DBG + +#define NearLabel Label + +// Immediate is an abstraction to represent the various immediate +// operands which exist on z/Architecture. Neither this class nor +// instances hereof have an own state. It consists of methods only. +class Immediate VALUE_OBJ_CLASS_SPEC { + + public: + static bool is_simm(int64_t x, unsigned int nbits) { + // nbits < 2 --> false + // nbits >= 64 --> true + assert(2 <= nbits && nbits < 64, "Don't call, use statically known result."); + const int64_t min = -(1L << (nbits-1)); + const int64_t maxplus1 = (1L << (nbits-1)); + return min <= x && x < maxplus1; + } + static bool is_simm32(int64_t x) { + return is_simm(x, 32); + } + static bool is_simm20(int64_t x) { + return is_simm(x, 20); + } + static bool is_simm16(int64_t x) { + return is_simm(x, 16); + } + static bool is_simm8(int64_t x) { + return is_simm(x, 8); + } + + // Test if x is within signed immediate range for nbits. + static bool is_uimm(int64_t x, unsigned int nbits) { + // nbits == 0 --> false + // nbits >= 64 --> true + assert(1 <= nbits && nbits < 64, "don't call, use statically known result"); + const uint64_t xu = (unsigned long)x; + const uint64_t maxplus1 = 1UL << nbits; + return xu < maxplus1; // Unsigned comparison. Negative inputs appear to be very large. + } + static bool is_uimm32(int64_t x) { + return is_uimm(x, 32); + } + static bool is_uimm16(int64_t x) { + return is_uimm(x, 16); + } + static bool is_uimm12(int64_t x) { + return is_uimm(x, 12); + } + static bool is_uimm8(int64_t x) { + return is_uimm(x, 8); + } +}; + +// Displacement is an abstraction to represent the various +// displacements which exist with addresses on z/ArchiTecture. +// Neither this class nor instances hereof have an own state. It +// consists of methods only. +class Displacement VALUE_OBJ_CLASS_SPEC { + + public: // These tests are used outside the (Macro)Assembler world, e.g. in ad-file. + + static bool is_longDisp(int64_t x) { // Fits in a 20-bit displacement field. + return Immediate::is_simm20(x); + } + static bool is_shortDisp(int64_t x) { // Fits in a 12-bit displacement field. + return Immediate::is_uimm12(x); + } + static bool is_validDisp(int64_t x) { // Is a valid displacement, regardless of length constraints. + return is_longDisp(x); + } +}; + +// RelAddr is an abstraction to represent relative addresses in the +// form they are used on z/Architecture for instructions which access +// their operand with pc-relative addresses. Neither this class nor +// instances hereof have an own state. It consists of methods only. +class RelAddr VALUE_OBJ_CLASS_SPEC { + + private: // No public use at all. Solely for (Macro)Assembler. + + static bool is_in_range_of_RelAddr(address target, address pc, bool shortForm) { + // Guard against illegal branch targets, e.g. -1. Occurrences in + // CompiledStaticCall and ad-file. Do not assert (it's a test + // function!). Just return false in case of illegal operands. + if ((((uint64_t)target) & 0x0001L) != 0) return false; + if ((((uint64_t)pc) & 0x0001L) != 0) return false; + + if (shortForm) { + return Immediate::is_simm((int64_t)(target-pc), 17); // Relative short addresses can reach +/- 2**16 bytes. + } else { + return Immediate::is_simm((int64_t)(target-pc), 33); // Relative long addresses can reach +/- 2**32 bytes. + } + } + + static bool is_in_range_of_RelAddr16(address target, address pc) { + return is_in_range_of_RelAddr(target, pc, true); + } + static bool is_in_range_of_RelAddr16(ptrdiff_t distance) { + return is_in_range_of_RelAddr((address)distance, 0, true); + } + + static bool is_in_range_of_RelAddr32(address target, address pc) { + return is_in_range_of_RelAddr(target, pc, false); + } + static bool is_in_range_of_RelAddr32(ptrdiff_t distance) { + return is_in_range_of_RelAddr((address)distance, 0, false); + } + + static int pcrel_off(address target, address pc, bool shortForm) { + assert(((uint64_t)target & 0x0001L) == 0, "target of a relative address must be aligned"); + assert(((uint64_t)pc & 0x0001L) == 0, "origin of a relative address must be aligned"); + + if ((target == NULL) || (target == pc)) { + return 0; // Yet unknown branch destination. + } else { + guarantee(is_in_range_of_RelAddr(target, pc, shortForm), "target not within reach"); + return (int)((target - pc)>>1); + } + } + + static int pcrel_off16(address target, address pc) { + return pcrel_off(target, pc, true); + } + static int pcrel_off16(ptrdiff_t distance) { + return pcrel_off((address)distance, 0, true); + } + + static int pcrel_off32(address target, address pc) { + return pcrel_off(target, pc, false); + } + static int pcrel_off32(ptrdiff_t distance) { + return pcrel_off((address)distance, 0, false); + } + + static ptrdiff_t inv_pcrel_off16(int offset) { + return ((ptrdiff_t)offset)<<1; + } + + static ptrdiff_t inv_pcrel_off32(int offset) { + return ((ptrdiff_t)offset)<<1; + } + + friend class Assembler; + friend class MacroAssembler; + friend class NativeGeneralJump; +}; + +// Address is an abstraction used to represent a memory location +// as passed to Z assembler instructions. +// +// Note: A register location is represented via a Register, not +// via an address for efficiency & simplicity reasons. +class Address VALUE_OBJ_CLASS_SPEC { + private: + Register _base; // Base register. + Register _index; // Index register + intptr_t _disp; // Constant displacement. + + public: + Address() : + _base(noreg), + _index(noreg), + _disp(0) {} + + Address(Register base, Register index, intptr_t disp = 0) : + _base(base), + _index(index), + _disp(disp) {} + + Address(Register base, intptr_t disp = 0) : + _base(base), + _index(noreg), + _disp(disp) {} + + Address(Register base, RegisterOrConstant roc, intptr_t disp = 0) : + _base(base), + _index(noreg), + _disp(disp) { + if (roc.is_constant()) _disp += roc.as_constant(); else _index = roc.as_register(); + } + +#ifdef ASSERT + // ByteSize is only a class when ASSERT is defined, otherwise it's an int. + Address(Register base, ByteSize disp) : + _base(base), + _index(noreg), + _disp(in_bytes(disp)) {} + + Address(Register base, Register index, ByteSize disp) : + _base(base), + _index(index), + _disp(in_bytes(disp)) {} +#endif + + // Aborts if disp is a register and base and index are set already. + Address plus_disp(RegisterOrConstant disp) const { + Address a = (*this); + a._disp += disp.constant_or_zero(); + if (disp.is_register()) { + if (a._index == noreg) { + a._index = disp.as_register(); + } else { + guarantee(_base == noreg, "can not encode"); a._base = disp.as_register(); + } + } + return a; + } + + // A call to this is generated by adlc for replacement variable $xxx$$Address. + static Address make_raw(int base, int index, int scale, int disp, relocInfo::relocType disp_reloc); + + bool is_same_address(Address a) const { + return _base == a._base && _index == a._index && _disp == a._disp; + } + + // testers + bool has_base() const { return _base != noreg; } + bool has_index() const { return _index != noreg; } + bool has_disp() const { return true; } // There is no "invalid" value. + + bool is_disp12() const { return Immediate::is_uimm12(disp()); } + bool is_disp20() const { return Immediate::is_simm20(disp()); } + bool is_RSform() { return has_base() && !has_index() && is_disp12(); } + bool is_RSYform() { return has_base() && !has_index() && is_disp20(); } + bool is_RXform() { return has_base() && has_index() && is_disp12(); } + bool is_RXEform() { return has_base() && has_index() && is_disp12(); } + bool is_RXYform() { return has_base() && has_index() && is_disp20(); } + + bool uses(Register r) { return _base == r || _index == r; }; + + // accessors + Register base() const { return _base; } + Register baseOrR0() const { assert(_base != Z_R0, ""); return _base == noreg ? Z_R0 : _base; } + Register index() const { return _index; } + Register indexOrR0() const { assert(_index != Z_R0, ""); return _index == noreg ? Z_R0 : _index; } + intptr_t disp() const { return _disp; } + // Specific version for short displacement instructions. + int disp12() const { + assert(is_disp12(), "displacement out of range for uimm12"); + return _disp; + } + // Specific version for long displacement instructions. + int disp20() const { + assert(is_disp20(), "displacement out of range for simm20"); + return _disp; + } + intptr_t value() const { return _disp; } + + friend class Assembler; +}; + +class AddressLiteral VALUE_OBJ_CLASS_SPEC { + private: + address _address; + RelocationHolder _rspec; + + RelocationHolder rspec_from_rtype(relocInfo::relocType rtype, address addr) { + switch (rtype) { + case relocInfo::external_word_type: + return external_word_Relocation::spec(addr); + case relocInfo::internal_word_type: + return internal_word_Relocation::spec(addr); + case relocInfo::opt_virtual_call_type: + return opt_virtual_call_Relocation::spec(); + case relocInfo::static_call_type: + return static_call_Relocation::spec(); + case relocInfo::runtime_call_w_cp_type: + return runtime_call_w_cp_Relocation::spec(); + case relocInfo::none: + return RelocationHolder(); + default: + ShouldNotReachHere(); + return RelocationHolder(); + } + } + + protected: + // creation + AddressLiteral() : _address(NULL), _rspec(NULL) {} + + public: + AddressLiteral(address addr, RelocationHolder const& rspec) + : _address(addr), + _rspec(rspec) {} + + // Some constructors to avoid casting at the call site. + AddressLiteral(jobject obj, RelocationHolder const& rspec) + : _address((address) obj), + _rspec(rspec) {} + + AddressLiteral(intptr_t value, RelocationHolder const& rspec) + : _address((address) value), + _rspec(rspec) {} + + AddressLiteral(address addr, relocInfo::relocType rtype = relocInfo::none) + : _address((address) addr), + _rspec(rspec_from_rtype(rtype, (address) addr)) {} + + // Some constructors to avoid casting at the call site. + AddressLiteral(address* addr, relocInfo::relocType rtype = relocInfo::none) + : _address((address) addr), + _rspec(rspec_from_rtype(rtype, (address) addr)) {} + + AddressLiteral(bool* addr, relocInfo::relocType rtype = relocInfo::none) + : _address((address) addr), + _rspec(rspec_from_rtype(rtype, (address) addr)) {} + + AddressLiteral(const bool* addr, relocInfo::relocType rtype = relocInfo::none) + : _address((address) addr), + _rspec(rspec_from_rtype(rtype, (address) addr)) {} + + AddressLiteral(signed char* addr, relocInfo::relocType rtype = relocInfo::none) + : _address((address) addr), + _rspec(rspec_from_rtype(rtype, (address) addr)) {} + + AddressLiteral(int* addr, relocInfo::relocType rtype = relocInfo::none) + : _address((address) addr), + _rspec(rspec_from_rtype(rtype, (address) addr)) {} + + AddressLiteral(intptr_t addr, relocInfo::relocType rtype = relocInfo::none) + : _address((address) addr), + _rspec(rspec_from_rtype(rtype, (address) addr)) {} + + AddressLiteral(intptr_t* addr, relocInfo::relocType rtype = relocInfo::none) + : _address((address) addr), + _rspec(rspec_from_rtype(rtype, (address) addr)) {} + + AddressLiteral(oop addr, relocInfo::relocType rtype = relocInfo::none) + : _address((address) addr), + _rspec(rspec_from_rtype(rtype, (address) addr)) {} + + AddressLiteral(oop* addr, relocInfo::relocType rtype = relocInfo::none) + : _address((address) addr), + _rspec(rspec_from_rtype(rtype, (address) addr)) {} + + AddressLiteral(float* addr, relocInfo::relocType rtype = relocInfo::none) + : _address((address) addr), + _rspec(rspec_from_rtype(rtype, (address) addr)) {} + + AddressLiteral(double* addr, relocInfo::relocType rtype = relocInfo::none) + : _address((address) addr), + _rspec(rspec_from_rtype(rtype, (address) addr)) {} + + intptr_t value() const { return (intptr_t) _address; } + + const relocInfo::relocType rtype() const { return _rspec.type(); } + const RelocationHolder& rspec() const { return _rspec; } + + RelocationHolder rspec(int offset) const { + return offset == 0 ? _rspec : _rspec.plus(offset); + } +}; + +// Convenience classes +class ExternalAddress: public AddressLiteral { + private: + static relocInfo::relocType reloc_for_target(address target) { + // Sometimes ExternalAddress is used for values which aren't + // exactly addresses, like the card table base. + // External_word_type can't be used for values in the first page + // so just skip the reloc in that case. + return external_word_Relocation::can_be_relocated(target) ? relocInfo::external_word_type : relocInfo::none; + } + + public: + ExternalAddress(address target) : AddressLiteral(target, reloc_for_target( target)) {} + ExternalAddress(oop* target) : AddressLiteral(target, reloc_for_target((address) target)) {} +}; + +// Argument is an abstraction used to represent an outgoing actual +// argument or an incoming formal parameter, whether it resides in +// memory or in a register, in a manner consistent with the +// z/Architecture Application Binary Interface, or ABI. This is often +// referred to as the native or C calling convention. +class Argument VALUE_OBJ_CLASS_SPEC { + private: + int _number; + bool _is_in; + + public: + enum { + // Only 5 registers may contain integer parameters. + n_register_parameters = 5, + // Can have up to 4 floating registers. + n_float_register_parameters = 4 + }; + + // creation + Argument(int number, bool is_in) : _number(number), _is_in(is_in) {} + Argument(int number) : _number(number) {} + + int number() const { return _number; } + + Argument successor() const { return Argument(number() + 1); } + + // Locating register-based arguments: + bool is_register() const { return _number < n_register_parameters; } + + // Locating Floating Point register-based arguments: + bool is_float_register() const { return _number < n_float_register_parameters; } + + FloatRegister as_float_register() const { + assert(is_float_register(), "must be a register argument"); + return as_FloatRegister((number() *2) + 1); + } + + FloatRegister as_double_register() const { + assert(is_float_register(), "must be a register argument"); + return as_FloatRegister((number() *2)); + } + + Register as_register() const { + assert(is_register(), "must be a register argument"); + return as_Register(number() + Z_ARG1->encoding()); + } + + // debugging + const char* name() const; + + friend class Assembler; +}; + + +// The z/Architecture Assembler: Pure assembler doing NO optimizations +// on the instruction level; i.e., what you write is what you get. The +// Assembler is generating code into a CodeBuffer. +class Assembler : public AbstractAssembler { + protected: + + friend class AbstractAssembler; + friend class AddressLiteral; + + // Code patchers need various routines like inv_wdisp(). + friend class NativeInstruction; +#ifndef COMPILER2 + friend class NativeGeneralJump; +#endif + friend class Relocation; + + public: + +// Addressing + +// address calculation +#define LA_ZOPC (unsigned int)(0x41 << 24) +#define LAY_ZOPC (unsigned long)(0xe3L << 40 | 0x71L) +#define LARL_ZOPC (unsigned long)(0xc0L << 40 | 0x00L << 32) + + +// Data Transfer + +// register to register transfer +#define LR_ZOPC (unsigned int)(24 << 8) +#define LBR_ZOPC (unsigned int)(0xb926 << 16) +#define LHR_ZOPC (unsigned int)(0xb927 << 16) +#define LGBR_ZOPC (unsigned int)(0xb906 << 16) +#define LGHR_ZOPC (unsigned int)(0xb907 << 16) +#define LGFR_ZOPC (unsigned int)(0xb914 << 16) +#define LGR_ZOPC (unsigned int)(0xb904 << 16) + +#define LLHR_ZOPC (unsigned int)(0xb995 << 16) +#define LLGCR_ZOPC (unsigned int)(0xb984 << 16) +#define LLGHR_ZOPC (unsigned int)(0xb985 << 16) +#define LLGTR_ZOPC (unsigned int)(185 << 24 | 23 << 16) +#define LLGFR_ZOPC (unsigned int)(185 << 24 | 22 << 16) + +#define LTR_ZOPC (unsigned int)(18 << 8) +#define LTGFR_ZOPC (unsigned int)(185 << 24 | 18 << 16) +#define LTGR_ZOPC (unsigned int)(185 << 24 | 2 << 16) + +#define LER_ZOPC (unsigned int)(56 << 8) +#define LEDBR_ZOPC (unsigned int)(179 << 24 | 68 << 16) +#define LEXBR_ZOPC (unsigned int)(179 << 24 | 70 << 16) +#define LDEBR_ZOPC (unsigned int)(179 << 24 | 4 << 16) +#define LDR_ZOPC (unsigned int)(40 << 8) +#define LDXBR_ZOPC (unsigned int)(179 << 24 | 69 << 16) +#define LXEBR_ZOPC (unsigned int)(179 << 24 | 6 << 16) +#define LXDBR_ZOPC (unsigned int)(179 << 24 | 5 << 16) +#define LXR_ZOPC (unsigned int)(179 << 24 | 101 << 16) +#define LTEBR_ZOPC (unsigned int)(179 << 24 | 2 << 16) +#define LTDBR_ZOPC (unsigned int)(179 << 24 | 18 << 16) +#define LTXBR_ZOPC (unsigned int)(179 << 24 | 66 << 16) + +#define LRVR_ZOPC (unsigned int)(0xb91f << 16) +#define LRVGR_ZOPC (unsigned int)(0xb90f << 16) + +#define LDGR_ZOPC (unsigned int)(0xb3c1 << 16) // z10 +#define LGDR_ZOPC (unsigned int)(0xb3cd << 16) // z10 + +#define LOCR_ZOPC (unsigned int)(0xb9f2 << 16) // z196 +#define LOCGR_ZOPC (unsigned int)(0xb9e2 << 16) // z196 + +// immediate to register transfer +#define IIHH_ZOPC (unsigned int)(165 << 24) +#define IIHL_ZOPC (unsigned int)(165 << 24 | 1 << 16) +#define IILH_ZOPC (unsigned int)(165 << 24 | 2 << 16) +#define IILL_ZOPC (unsigned int)(165 << 24 | 3 << 16) +#define IIHF_ZOPC (unsigned long)(0xc0L << 40 | 8L << 32) +#define IILF_ZOPC (unsigned long)(0xc0L << 40 | 9L << 32) +#define LLIHH_ZOPC (unsigned int)(165 << 24 | 12 << 16) +#define LLIHL_ZOPC (unsigned int)(165 << 24 | 13 << 16) +#define LLILH_ZOPC (unsigned int)(165 << 24 | 14 << 16) +#define LLILL_ZOPC (unsigned int)(165 << 24 | 15 << 16) +#define LLIHF_ZOPC (unsigned long)(0xc0L << 40 | 14L << 32) +#define LLILF_ZOPC (unsigned long)(0xc0L << 40 | 15L << 32) +#define LHI_ZOPC (unsigned int)(167 << 24 | 8 << 16) +#define LGHI_ZOPC (unsigned int)(167 << 24 | 9 << 16) +#define LGFI_ZOPC (unsigned long)(0xc0L << 40 | 1L << 32) + +#define LZER_ZOPC (unsigned int)(0xb374 << 16) +#define LZDR_ZOPC (unsigned int)(0xb375 << 16) + +// LOAD: memory to register transfer +#define LB_ZOPC (unsigned long)(227L << 40 | 118L) +#define LH_ZOPC (unsigned int)(72 << 24) +#define LHY_ZOPC (unsigned long)(227L << 40 | 120L) +#define L_ZOPC (unsigned int)(88 << 24) +#define LY_ZOPC (unsigned long)(227L << 40 | 88L) +#define LT_ZOPC (unsigned long)(0xe3L << 40 | 0x12L) +#define LGB_ZOPC (unsigned long)(227L << 40 | 119L) +#define LGH_ZOPC (unsigned long)(227L << 40 | 21L) +#define LGF_ZOPC (unsigned long)(227L << 40 | 20L) +#define LG_ZOPC (unsigned long)(227L << 40 | 4L) +#define LTG_ZOPC (unsigned long)(0xe3L << 40 | 0x02L) +#define LTGF_ZOPC (unsigned long)(0xe3L << 40 | 0x32L) + +#define LLC_ZOPC (unsigned long)(0xe3L << 40 | 0x94L) +#define LLH_ZOPC (unsigned long)(0xe3L << 40 | 0x95L) +#define LLGT_ZOPC (unsigned long)(227L << 40 | 23L) +#define LLGC_ZOPC (unsigned long)(227L << 40 | 144L) +#define LLGH_ZOPC (unsigned long)(227L << 40 | 145L) +#define LLGF_ZOPC (unsigned long)(227L << 40 | 22L) + +#define IC_ZOPC (unsigned int)(0x43 << 24) +#define ICY_ZOPC (unsigned long)(0xe3L << 40 | 0x73L) +#define ICM_ZOPC (unsigned int)(0xbf << 24) +#define ICMY_ZOPC (unsigned long)(0xebL << 40 | 0x81L) +#define ICMH_ZOPC (unsigned long)(0xebL << 40 | 0x80L) + +#define LRVH_ZOPC (unsigned long)(0xe3L << 40 | 0x1fL) +#define LRV_ZOPC (unsigned long)(0xe3L << 40 | 0x1eL) +#define LRVG_ZOPC (unsigned long)(0xe3L << 40 | 0x0fL) + + +// LOAD relative: memory to register transfer +#define LHRL_ZOPC (unsigned long)(0xc4L << 40 | 0x05L << 32) // z10 +#define LRL_ZOPC (unsigned long)(0xc4L << 40 | 0x0dL << 32) // z10 +#define LGHRL_ZOPC (unsigned long)(0xc4L << 40 | 0x04L << 32) // z10 +#define LGFRL_ZOPC (unsigned long)(0xc4L << 40 | 0x0cL << 32) // z10 +#define LGRL_ZOPC (unsigned long)(0xc4L << 40 | 0x08L << 32) // z10 + +#define LLHRL_ZOPC (unsigned long)(0xc4L << 40 | 0x02L << 32) // z10 +#define LLGHRL_ZOPC (unsigned long)(0xc4L << 40 | 0x06L << 32) // z10 +#define LLGFRL_ZOPC (unsigned long)(0xc4L << 40 | 0x0eL << 32) // z10 + +#define LOC_ZOPC (unsigned long)(0xebL << 40 | 0xf2L) // z196 +#define LOCG_ZOPC (unsigned long)(0xebL << 40 | 0xe2L) // z196 + +#define LMG_ZOPC (unsigned long)(235L << 40 | 4L) + +#define LE_ZOPC (unsigned int)(0x78 << 24) +#define LEY_ZOPC (unsigned long)(237L << 40 | 100L) +#define LDEB_ZOPC (unsigned long)(237L << 40 | 4) +#define LD_ZOPC (unsigned int)(0x68 << 24) +#define LDY_ZOPC (unsigned long)(237L << 40 | 101L) +#define LXEB_ZOPC (unsigned long)(237L << 40 | 6) +#define LXDB_ZOPC (unsigned long)(237L << 40 | 5) + +// STORE: register to memory transfer +#define STC_ZOPC (unsigned int)(0x42 << 24) +#define STCY_ZOPC (unsigned long)(227L << 40 | 114L) +#define STH_ZOPC (unsigned int)(64 << 24) +#define STHY_ZOPC (unsigned long)(227L << 40 | 112L) +#define ST_ZOPC (unsigned int)(80 << 24) +#define STY_ZOPC (unsigned long)(227L << 40 | 80L) +#define STG_ZOPC (unsigned long)(227L << 40 | 36L) + +#define STCM_ZOPC (unsigned long)(0xbeL << 24) +#define STCMY_ZOPC (unsigned long)(0xebL << 40 | 0x2dL) +#define STCMH_ZOPC (unsigned long)(0xebL << 40 | 0x2cL) + +// STORE relative: memory to register transfer +#define STHRL_ZOPC (unsigned long)(0xc4L << 40 | 0x07L << 32) // z10 +#define STRL_ZOPC (unsigned long)(0xc4L << 40 | 0x0fL << 32) // z10 +#define STGRL_ZOPC (unsigned long)(0xc4L << 40 | 0x0bL << 32) // z10 + +#define STOC_ZOPC (unsigned long)(0xebL << 40 | 0xf3L) // z196 +#define STOCG_ZOPC (unsigned long)(0xebL << 40 | 0xe3L) // z196 + +#define STMG_ZOPC (unsigned long)(235L << 40 | 36L) + +#define STE_ZOPC (unsigned int)(0x70 << 24) +#define STEY_ZOPC (unsigned long)(237L << 40 | 102L) +#define STD_ZOPC (unsigned int)(0x60 << 24) +#define STDY_ZOPC (unsigned long)(237L << 40 | 103L) + +// MOVE: immediate to memory transfer +#define MVHHI_ZOPC (unsigned long)(0xe5L << 40 | 0x44L << 32) // z10 +#define MVHI_ZOPC (unsigned long)(0xe5L << 40 | 0x4cL << 32) // z10 +#define MVGHI_ZOPC (unsigned long)(0xe5L << 40 | 0x48L << 32) // z10 + + +// ALU operations + +// Load Positive +#define LPR_ZOPC (unsigned int)(16 << 8) +#define LPGFR_ZOPC (unsigned int)(185 << 24 | 16 << 16) +#define LPGR_ZOPC (unsigned int)(185 << 24) +#define LPEBR_ZOPC (unsigned int)(179 << 24) +#define LPDBR_ZOPC (unsigned int)(179 << 24 | 16 << 16) +#define LPXBR_ZOPC (unsigned int)(179 << 24 | 64 << 16) + +// Load Negative +#define LNR_ZOPC (unsigned int)(17 << 8) +#define LNGFR_ZOPC (unsigned int)(185 << 24 | 17 << 16) +#define LNGR_ZOPC (unsigned int)(185 << 24 | 1 << 16) +#define LNEBR_ZOPC (unsigned int)(179 << 24 | 1 << 16) +#define LNDBR_ZOPC (unsigned int)(179 << 24 | 17 << 16) +#define LNXBR_ZOPC (unsigned int)(179 << 24 | 65 << 16) + +// Load Complement +#define LCR_ZOPC (unsigned int)(19 << 8) +#define LCGFR_ZOPC (unsigned int)(185 << 24 | 19 << 16) +#define LCGR_ZOPC (unsigned int)(185 << 24 | 3 << 16) +#define LCEBR_ZOPC (unsigned int)(179 << 24 | 3 << 16) +#define LCDBR_ZOPC (unsigned int)(179 << 24 | 19 << 16) +#define LCXBR_ZOPC (unsigned int)(179 << 24 | 67 << 16) + +// Add +// RR, signed +#define AR_ZOPC (unsigned int)(26 << 8) +#define AGFR_ZOPC (unsigned int)(0xb9 << 24 | 0x18 << 16) +#define AGR_ZOPC (unsigned int)(0xb9 << 24 | 0x08 << 16) +// RRF, signed +#define ARK_ZOPC (unsigned int)(0xb9 << 24 | 0x00f8 << 16) +#define AGRK_ZOPC (unsigned int)(0xb9 << 24 | 0x00e8 << 16) +// RI, signed +#define AHI_ZOPC (unsigned int)(167 << 24 | 10 << 16) +#define AFI_ZOPC (unsigned long)(0xc2L << 40 | 9L << 32) +#define AGHI_ZOPC (unsigned int)(167 << 24 | 11 << 16) +#define AGFI_ZOPC (unsigned long)(0xc2L << 40 | 8L << 32) +// RIE, signed +#define AHIK_ZOPC (unsigned long)(0xecL << 40 | 0x00d8L) +#define AGHIK_ZOPC (unsigned long)(0xecL << 40 | 0x00d9L) +#define AIH_ZOPC (unsigned long)(0xccL << 40 | 0x08L << 32) +// RM, signed +#define AHY_ZOPC (unsigned long)(227L << 40 | 122L) +#define A_ZOPC (unsigned int)(90 << 24) +#define AY_ZOPC (unsigned long)(227L << 40 | 90L) +#define AGF_ZOPC (unsigned long)(227L << 40 | 24L) +#define AG_ZOPC (unsigned long)(227L << 40 | 8L) +// In-memory arithmetic (add signed, add logical with signed immediate). +// MI, signed +#define ASI_ZOPC (unsigned long)(0xebL << 40 | 0x6aL) +#define AGSI_ZOPC (unsigned long)(0xebL << 40 | 0x7aL) + +// RR, Logical +#define ALR_ZOPC (unsigned int)(30 << 8) +#define ALGFR_ZOPC (unsigned int)(185 << 24 | 26 << 16) +#define ALGR_ZOPC (unsigned int)(185 << 24 | 10 << 16) +#define ALCGR_ZOPC (unsigned int)(185 << 24 | 136 << 16) +// RRF, Logical +#define ALRK_ZOPC (unsigned int)(0xb9 << 24 | 0x00fa << 16) +#define ALGRK_ZOPC (unsigned int)(0xb9 << 24 | 0x00ea << 16) +// RI, Logical +#define ALFI_ZOPC (unsigned long)(0xc2L << 40 | 0x0bL << 32) +#define ALGFI_ZOPC (unsigned long)(0xc2L << 40 | 0x0aL << 32) +// RIE, Logical +#define ALHSIK_ZOPC (unsigned long)(0xecL << 40 | 0x00daL) +#define ALGHSIK_ZOPC (unsigned long)(0xecL << 40 | 0x00dbL) +// RM, Logical +#define AL_ZOPC (unsigned int)(0x5e << 24) +#define ALY_ZOPC (unsigned long)(227L << 40 | 94L) +#define ALGF_ZOPC (unsigned long)(227L << 40 | 26L) +#define ALG_ZOPC (unsigned long)(227L << 40 | 10L) +// In-memory arithmetic (add signed, add logical with signed immediate). +// MI, Logical +#define ALSI_ZOPC (unsigned long)(0xebL << 40 | 0x6eL) +#define ALGSI_ZOPC (unsigned long)(0xebL << 40 | 0x7eL) + +// RR, BFP +#define AEBR_ZOPC (unsigned int)(179 << 24 | 10 << 16) +#define ADBR_ZOPC (unsigned int)(179 << 24 | 26 << 16) +#define AXBR_ZOPC (unsigned int)(179 << 24 | 74 << 16) +// RM, BFP +#define AEB_ZOPC (unsigned long)(237L << 40 | 10) +#define ADB_ZOPC (unsigned long)(237L << 40 | 26) + +// Subtract +// RR, signed +#define SR_ZOPC (unsigned int)(27 << 8) +#define SGFR_ZOPC (unsigned int)(185 << 24 | 25 << 16) +#define SGR_ZOPC (unsigned int)(185 << 24 | 9 << 16) +// RRF, signed +#define SRK_ZOPC (unsigned int)(0xb9 << 24 | 0x00f9 << 16) +#define SGRK_ZOPC (unsigned int)(0xb9 << 24 | 0x00e9 << 16) +// RM, signed +#define SH_ZOPC (unsigned int)(0x4b << 24) +#define SHY_ZOPC (unsigned long)(227L << 40 | 123L) +#define S_ZOPC (unsigned int)(0x5B << 24) +#define SY_ZOPC (unsigned long)(227L << 40 | 91L) +#define SGF_ZOPC (unsigned long)(227L << 40 | 25) +#define SG_ZOPC (unsigned long)(227L << 40 | 9) +// RR, Logical +#define SLR_ZOPC (unsigned int)(31 << 8) +#define SLGFR_ZOPC (unsigned int)(185 << 24 | 27 << 16) +#define SLGR_ZOPC (unsigned int)(185 << 24 | 11 << 16) +// RIL, Logical +#define SLFI_ZOPC (unsigned long)(0xc2L << 40 | 0x05L << 32) +#define SLGFI_ZOPC (unsigned long)(0xc2L << 40 | 0x04L << 32) +// RRF, Logical +#define SLRK_ZOPC (unsigned int)(0xb9 << 24 | 0x00fb << 16) +#define SLGRK_ZOPC (unsigned int)(0xb9 << 24 | 0x00eb << 16) +// RM, Logical +#define SLY_ZOPC (unsigned long)(227L << 40 | 95L) +#define SLGF_ZOPC (unsigned long)(227L << 40 | 27L) +#define SLG_ZOPC (unsigned long)(227L << 40 | 11L) + +// RR, BFP +#define SEBR_ZOPC (unsigned int)(179 << 24 | 11 << 16) +#define SDBR_ZOPC (unsigned int)(179 << 24 | 27 << 16) +#define SXBR_ZOPC (unsigned int)(179 << 24 | 75 << 16) +// RM, BFP +#define SEB_ZOPC (unsigned long)(237L << 40 | 11) +#define SDB_ZOPC (unsigned long)(237L << 40 | 27) + +// Multiply +// RR, signed +#define MR_ZOPC (unsigned int)(28 << 8) +#define MSR_ZOPC (unsigned int)(178 << 24 | 82 << 16) +#define MSGFR_ZOPC (unsigned int)(185 << 24 | 28 << 16) +#define MSGR_ZOPC (unsigned int)(185 << 24 | 12 << 16) +// RI, signed +#define MHI_ZOPC (unsigned int)(167 << 24 | 12 << 16) +#define MGHI_ZOPC (unsigned int)(167 << 24 | 13 << 16) +#define MSFI_ZOPC (unsigned long)(0xc2L << 40 | 0x01L << 32) // z10 +#define MSGFI_ZOPC (unsigned long)(0xc2L << 40 | 0x00L << 32) // z10 +// RM, signed +#define M_ZOPC (unsigned int)(92 << 24) +#define MS_ZOPC (unsigned int)(0x71 << 24) +#define MHY_ZOPC (unsigned long)(0xe3L<< 40 | 0x7cL) +#define MSY_ZOPC (unsigned long)(227L << 40 | 81L) +#define MSGF_ZOPC (unsigned long)(227L << 40 | 28L) +#define MSG_ZOPC (unsigned long)(227L << 40 | 12L) +// RR, unsigned +#define MLR_ZOPC (unsigned int)(185 << 24 | 150 << 16) +#define MLGR_ZOPC (unsigned int)(185 << 24 | 134 << 16) +// RM, unsigned +#define ML_ZOPC (unsigned long)(227L << 40 | 150L) +#define MLG_ZOPC (unsigned long)(227L << 40 | 134L) + +// RR, BFP +#define MEEBR_ZOPC (unsigned int)(179 << 24 | 23 << 16) +#define MDEBR_ZOPC (unsigned int)(179 << 24 | 12 << 16) +#define MDBR_ZOPC (unsigned int)(179 << 24 | 28 << 16) +#define MXDBR_ZOPC (unsigned int)(179 << 24 | 7 << 16) +#define MXBR_ZOPC (unsigned int)(179 << 24 | 76 << 16) +// RM, BFP +#define MEEB_ZOPC (unsigned long)(237L << 40 | 23) +#define MDEB_ZOPC (unsigned long)(237L << 40 | 12) +#define MDB_ZOPC (unsigned long)(237L << 40 | 28) +#define MXDB_ZOPC (unsigned long)(237L << 40 | 7) + +// Divide +// RR, signed +#define DSGFR_ZOPC (unsigned int)(0xb91d << 16) +#define DSGR_ZOPC (unsigned int)(0xb90d << 16) +// RM, signed +#define D_ZOPC (unsigned int)(93 << 24) +#define DSGF_ZOPC (unsigned long)(227L << 40 | 29L) +#define DSG_ZOPC (unsigned long)(227L << 40 | 13L) +// RR, unsigned +#define DLR_ZOPC (unsigned int)(185 << 24 | 151 << 16) +#define DLGR_ZOPC (unsigned int)(185 << 24 | 135 << 16) +// RM, unsigned +#define DL_ZOPC (unsigned long)(227L << 40 | 151L) +#define DLG_ZOPC (unsigned long)(227L << 40 | 135L) + +// RR, BFP +#define DEBR_ZOPC (unsigned int)(179 << 24 | 13 << 16) +#define DDBR_ZOPC (unsigned int)(179 << 24 | 29 << 16) +#define DXBR_ZOPC (unsigned int)(179 << 24 | 77 << 16) +// RM, BFP +#define DEB_ZOPC (unsigned long)(237L << 40 | 13) +#define DDB_ZOPC (unsigned long)(237L << 40 | 29) + +// Square Root +// RR, BFP +#define SQEBR_ZOPC (unsigned int)(0xb314 << 16) +#define SQDBR_ZOPC (unsigned int)(0xb315 << 16) +#define SQXBR_ZOPC (unsigned int)(0xb316 << 16) +// RM, BFP +#define SQEB_ZOPC (unsigned long)(237L << 40 | 20) +#define SQDB_ZOPC (unsigned long)(237L << 40 | 21) + +// Compare and Test +// RR, signed +#define CR_ZOPC (unsigned int)(25 << 8) +#define CGFR_ZOPC (unsigned int)(185 << 24 | 48 << 16) +#define CGR_ZOPC (unsigned int)(185 << 24 | 32 << 16) +// RI, signed +#define CHI_ZOPC (unsigned int)(167 << 24 | 14 << 16) +#define CFI_ZOPC (unsigned long)(0xc2L << 40 | 0xdL << 32) +#define CGHI_ZOPC (unsigned int)(167 << 24 | 15 << 16) +#define CGFI_ZOPC (unsigned long)(0xc2L << 40 | 0xcL << 32) +// RM, signed +#define CH_ZOPC (unsigned int)(0x49 << 24) +#define CHY_ZOPC (unsigned long)(227L << 40 | 121L) +#define C_ZOPC (unsigned int)(0x59 << 24) +#define CY_ZOPC (unsigned long)(227L << 40 | 89L) +#define CGF_ZOPC (unsigned long)(227L << 40 | 48L) +#define CG_ZOPC (unsigned long)(227L << 40 | 32L) +// RR, unsigned +#define CLR_ZOPC (unsigned int)(21 << 8) +#define CLGFR_ZOPC (unsigned int)(185 << 24 | 49 << 16) +#define CLGR_ZOPC (unsigned int)(185 << 24 | 33 << 16) +// RIL, unsigned +#define CLFI_ZOPC (unsigned long)(0xc2L << 40 | 0xfL << 32) +#define CLGFI_ZOPC (unsigned long)(0xc2L << 40 | 0xeL << 32) +// RM, unsigned +#define CL_ZOPC (unsigned int)(0x55 << 24) +#define CLY_ZOPC (unsigned long)(227L << 40 | 85L) +#define CLGF_ZOPC (unsigned long)(227L << 40 | 49L) +#define CLG_ZOPC (unsigned long)(227L << 40 | 33L) +// RI, unsigned +#define TMHH_ZOPC (unsigned int)(167 << 24 | 2 << 16) +#define TMHL_ZOPC (unsigned int)(167 << 24 | 3 << 16) +#define TMLH_ZOPC (unsigned int)(167 << 24) +#define TMLL_ZOPC (unsigned int)(167 << 24 | 1 << 16) + +// RR, BFP +#define CEBR_ZOPC (unsigned int)(179 << 24 | 9 << 16) +#define CDBR_ZOPC (unsigned int)(179 << 24 | 25 << 16) +#define CXBR_ZOPC (unsigned int)(179 << 24 | 73 << 16) +// RM, BFP +#define CEB_ZOPC (unsigned long)(237L << 40 | 9) +#define CDB_ZOPC (unsigned long)(237L << 40 | 25) + +// Shift +// arithmetic +#define SLA_ZOPC (unsigned int)(139 << 24) +#define SLAG_ZOPC (unsigned long)(235L << 40 | 11L) +#define SRA_ZOPC (unsigned int)(138 << 24) +#define SRAG_ZOPC (unsigned long)(235L << 40 | 10L) +// logical +#define SLL_ZOPC (unsigned int)(137 << 24) +#define SLLG_ZOPC (unsigned long)(235L << 40 | 13L) +#define SRL_ZOPC (unsigned int)(136 << 24) +#define SRLG_ZOPC (unsigned long)(235L << 40 | 12L) + +// Rotate, then AND/XOR/OR/insert +// rotate +#define RLL_ZOPC (unsigned long)(0xebL << 40 | 0x1dL) // z10 +#define RLLG_ZOPC (unsigned long)(0xebL << 40 | 0x1cL) // z10 +// rotate and {AND|XOR|OR|INS} +#define RNSBG_ZOPC (unsigned long)(0xecL << 40 | 0x54L) // z196 +#define RXSBG_ZOPC (unsigned long)(0xecL << 40 | 0x57L) // z196 +#define ROSBG_ZOPC (unsigned long)(0xecL << 40 | 0x56L) // z196 +#define RISBG_ZOPC (unsigned long)(0xecL << 40 | 0x55L) // z196 + +// AND +// RR, signed +#define NR_ZOPC (unsigned int)(20 << 8) +#define NGR_ZOPC (unsigned int)(185 << 24 | 128 << 16) +// RRF, signed +#define NRK_ZOPC (unsigned int)(0xb9 << 24 | 0x00f4 << 16) +#define NGRK_ZOPC (unsigned int)(0xb9 << 24 | 0x00e4 << 16) +// RI, signed +#define NIHH_ZOPC (unsigned int)(165 << 24 | 4 << 16) +#define NIHL_ZOPC (unsigned int)(165 << 24 | 5 << 16) +#define NILH_ZOPC (unsigned int)(165 << 24 | 6 << 16) +#define NILL_ZOPC (unsigned int)(165 << 24 | 7 << 16) +#define NIHF_ZOPC (unsigned long)(0xc0L << 40 | 10L << 32) +#define NILF_ZOPC (unsigned long)(0xc0L << 40 | 11L << 32) +// RM, signed +#define N_ZOPC (unsigned int)(0x54 << 24) +#define NY_ZOPC (unsigned long)(227L << 40 | 84L) +#define NG_ZOPC (unsigned long)(227L << 40 | 128L) + +// OR +// RR, signed +#define OR_ZOPC (unsigned int)(22 << 8) +#define OGR_ZOPC (unsigned int)(185 << 24 | 129 << 16) +// RRF, signed +#define ORK_ZOPC (unsigned int)(0xb9 << 24 | 0x00f6 << 16) +#define OGRK_ZOPC (unsigned int)(0xb9 << 24 | 0x00e6 << 16) +// RI, signed +#define OIHH_ZOPC (unsigned int)(165 << 24 | 8 << 16) +#define OIHL_ZOPC (unsigned int)(165 << 24 | 9 << 16) +#define OILH_ZOPC (unsigned int)(165 << 24 | 10 << 16) +#define OILL_ZOPC (unsigned int)(165 << 24 | 11 << 16) +#define OIHF_ZOPC (unsigned long)(0xc0L << 40 | 12L << 32) +#define OILF_ZOPC (unsigned long)(0xc0L << 40 | 13L << 32) +// RM, signed +#define O_ZOPC (unsigned int)(0x56 << 24) +#define OY_ZOPC (unsigned long)(227L << 40 | 86L) +#define OG_ZOPC (unsigned long)(227L << 40 | 129L) + +// XOR +// RR, signed +#define XR_ZOPC (unsigned int)(23 << 8) +#define XGR_ZOPC (unsigned int)(185 << 24 | 130 << 16) +// RRF, signed +#define XRK_ZOPC (unsigned int)(0xb9 << 24 | 0x00f7 << 16) +#define XGRK_ZOPC (unsigned int)(0xb9 << 24 | 0x00e7 << 16) +// RI, signed +#define XIHF_ZOPC (unsigned long)(0xc0L << 40 | 6L << 32) +#define XILF_ZOPC (unsigned long)(0xc0L << 40 | 7L << 32) +// RM, signed +#define X_ZOPC (unsigned int)(0x57 << 24) +#define XY_ZOPC (unsigned long)(227L << 40 | 87L) +#define XG_ZOPC (unsigned long)(227L << 40 | 130L) + + +// Data Conversion + +// INT to BFP +#define CEFBR_ZOPC (unsigned int)(179 << 24 | 148 << 16) +#define CDFBR_ZOPC (unsigned int)(179 << 24 | 149 << 16) +#define CXFBR_ZOPC (unsigned int)(179 << 24 | 150 << 16) +#define CEGBR_ZOPC (unsigned int)(179 << 24 | 164 << 16) +#define CDGBR_ZOPC (unsigned int)(179 << 24 | 165 << 16) +#define CXGBR_ZOPC (unsigned int)(179 << 24 | 166 << 16) +// BFP to INT +#define CFEBR_ZOPC (unsigned int)(179 << 24 | 152 << 16) +#define CFDBR_ZOPC (unsigned int)(179 << 24 | 153 << 16) +#define CFXBR_ZOPC (unsigned int)(179 << 24 | 154 << 16) +#define CGEBR_ZOPC (unsigned int)(179 << 24 | 168 << 16) +#define CGDBR_ZOPC (unsigned int)(179 << 24 | 169 << 16) +#define CGXBR_ZOPC (unsigned int)(179 << 24 | 170 << 16) +// INT to DEC +#define CVD_ZOPC (unsigned int)(0x4e << 24) +#define CVDY_ZOPC (unsigned long)(0xe3L << 40 | 0x26L) +#define CVDG_ZOPC (unsigned long)(0xe3L << 40 | 0x2eL) + + +// BFP Control + +#define SRNM_ZOPC (unsigned int)(178 << 24 | 153 << 16) +#define EFPC_ZOPC (unsigned int)(179 << 24 | 140 << 16) +#define SFPC_ZOPC (unsigned int)(179 << 24 | 132 << 16) +#define STFPC_ZOPC (unsigned int)(178 << 24 | 156 << 16) +#define LFPC_ZOPC (unsigned int)(178 << 24 | 157 << 16) + + +// Branch Instructions + +// Register +#define BCR_ZOPC (unsigned int)(7 << 8) +#define BALR_ZOPC (unsigned int)(5 << 8) +#define BASR_ZOPC (unsigned int)(13 << 8) +#define BCTGR_ZOPC (unsigned long)(0xb946 << 16) +// Absolute +#define BC_ZOPC (unsigned int)(71 << 24) +#define BAL_ZOPC (unsigned int)(69 << 24) +#define BAS_ZOPC (unsigned int)(77 << 24) +#define BXH_ZOPC (unsigned int)(134 << 24) +#define BXHG_ZOPC (unsigned long)(235L << 40 | 68) +// Relative +#define BRC_ZOPC (unsigned int)(167 << 24 | 4 << 16) +#define BRCL_ZOPC (unsigned long)(192L << 40 | 4L << 32) +#define BRAS_ZOPC (unsigned int)(167 << 24 | 5 << 16) +#define BRASL_ZOPC (unsigned long)(192L << 40 | 5L << 32) +#define BRCT_ZOPC (unsigned int)(167 << 24 | 6 << 16) +#define BRCTG_ZOPC (unsigned int)(167 << 24 | 7 << 16) +#define BRXH_ZOPC (unsigned int)(132 << 24) +#define BRXHG_ZOPC (unsigned long)(236L << 40 | 68) +#define BRXLE_ZOPC (unsigned int)(133 << 24) +#define BRXLG_ZOPC (unsigned long)(236L << 40 | 69) + + +// Compare and Branch Instructions + +// signed comp reg/reg, branch Absolute +#define CRB_ZOPC (unsigned long)(0xecL << 40 | 0xf6L) // z10 +#define CGRB_ZOPC (unsigned long)(0xecL << 40 | 0xe4L) // z10 +// signed comp reg/reg, branch Relative +#define CRJ_ZOPC (unsigned long)(0xecL << 40 | 0x76L) // z10 +#define CGRJ_ZOPC (unsigned long)(0xecL << 40 | 0x64L) // z10 +// signed comp reg/imm, branch absolute +#define CIB_ZOPC (unsigned long)(0xecL << 40 | 0xfeL) // z10 +#define CGIB_ZOPC (unsigned long)(0xecL << 40 | 0xfcL) // z10 +// signed comp reg/imm, branch relative +#define CIJ_ZOPC (unsigned long)(0xecL << 40 | 0x7eL) // z10 +#define CGIJ_ZOPC (unsigned long)(0xecL << 40 | 0x7cL) // z10 + +// unsigned comp reg/reg, branch Absolute +#define CLRB_ZOPC (unsigned long)(0xecL << 40 | 0xf7L) // z10 +#define CLGRB_ZOPC (unsigned long)(0xecL << 40 | 0xe5L) // z10 +// unsigned comp reg/reg, branch Relative +#define CLRJ_ZOPC (unsigned long)(0xecL << 40 | 0x77L) // z10 +#define CLGRJ_ZOPC (unsigned long)(0xecL << 40 | 0x65L) // z10 +// unsigned comp reg/imm, branch absolute +#define CLIB_ZOPC (unsigned long)(0xecL << 40 | 0xffL) // z10 +#define CLGIB_ZOPC (unsigned long)(0xecL << 40 | 0xfdL) // z10 +// unsigned comp reg/imm, branch relative +#define CLIJ_ZOPC (unsigned long)(0xecL << 40 | 0x7fL) // z10 +#define CLGIJ_ZOPC (unsigned long)(0xecL << 40 | 0x7dL) // z10 + +// comp reg/reg, trap +#define CRT_ZOPC (unsigned int)(0xb972 << 16) // z10 +#define CGRT_ZOPC (unsigned int)(0xb960 << 16) // z10 +#define CLRT_ZOPC (unsigned int)(0xb973 << 16) // z10 +#define CLGRT_ZOPC (unsigned int)(0xb961 << 16) // z10 +// comp reg/imm, trap +#define CIT_ZOPC (unsigned long)(0xecL << 40 | 0x72L) // z10 +#define CGIT_ZOPC (unsigned long)(0xecL << 40 | 0x70L) // z10 +#define CLFIT_ZOPC (unsigned long)(0xecL << 40 | 0x73L) // z10 +#define CLGIT_ZOPC (unsigned long)(0xecL << 40 | 0x71L) // z10 + + +// Direct Memory Operations + +// Compare +#define CLI_ZOPC (unsigned int)(0x95 << 24) +#define CLIY_ZOPC (unsigned long)(0xebL << 40 | 0x55L) +#define CLC_ZOPC (unsigned long)(0xd5L << 40) +#define CLCL_ZOPC (unsigned int)(0x0f << 8) +#define CLCLE_ZOPC (unsigned int)(0xa9 << 24) +#define CLCLU_ZOPC (unsigned long)(0xebL << 40 | 0x8fL) + +// Move +#define MVI_ZOPC (unsigned int)(0x92 << 24) +#define MVIY_ZOPC (unsigned long)(0xebL << 40 | 0x52L) +#define MVC_ZOPC (unsigned long)(0xd2L << 40) +#define MVCL_ZOPC (unsigned int)(0x0e << 8) +#define MVCLE_ZOPC (unsigned int)(0xa8 << 24) + +// Test +#define TM_ZOPC (unsigned int)(0x91 << 24) +#define TMY_ZOPC (unsigned long)(0xebL << 40 | 0x51L) + +// AND +#define NI_ZOPC (unsigned int)(0x94 << 24) +#define NIY_ZOPC (unsigned long)(0xebL << 40 | 0x54L) +#define NC_ZOPC (unsigned long)(0xd4L << 40) + +// OR +#define OI_ZOPC (unsigned int)(0x96 << 24) +#define OIY_ZOPC (unsigned long)(0xebL << 40 | 0x56L) +#define OC_ZOPC (unsigned long)(0xd6L << 40) + +// XOR +#define XI_ZOPC (unsigned int)(0x97 << 24) +#define XIY_ZOPC (unsigned long)(0xebL << 40 | 0x57L) +#define XC_ZOPC (unsigned long)(0xd7L << 40) + +// Search String +#define SRST_ZOPC (unsigned int)(178 << 24 | 94 << 16) +#define SRSTU_ZOPC (unsigned int)(185 << 24 | 190 << 16) + +// Translate characters +#define TROO_ZOPC (unsigned int)(0xb9 << 24 | 0x93 << 16) +#define TROT_ZOPC (unsigned int)(0xb9 << 24 | 0x92 << 16) +#define TRTO_ZOPC (unsigned int)(0xb9 << 24 | 0x91 << 16) +#define TRTT_ZOPC (unsigned int)(0xb9 << 24 | 0x90 << 16) + + +// Miscellaneous Operations + +// Execute +#define EX_ZOPC (unsigned int)(68L << 24) +#define EXRL_ZOPC (unsigned long)(0xc6L << 40 | 0x00L << 32) // z10 + +// Compare and Swap +#define CS_ZOPC (unsigned int)(0xba << 24) +#define CSY_ZOPC (unsigned long)(0xebL << 40 | 0x14L) +#define CSG_ZOPC (unsigned long)(0xebL << 40 | 0x30L) + +// Interlocked-Update +#define LAA_ZOPC (unsigned long)(0xebL << 40 | 0xf8L) // z196 +#define LAAG_ZOPC (unsigned long)(0xebL << 40 | 0xe8L) // z196 +#define LAAL_ZOPC (unsigned long)(0xebL << 40 | 0xfaL) // z196 +#define LAALG_ZOPC (unsigned long)(0xebL << 40 | 0xeaL) // z196 +#define LAN_ZOPC (unsigned long)(0xebL << 40 | 0xf4L) // z196 +#define LANG_ZOPC (unsigned long)(0xebL << 40 | 0xe4L) // z196 +#define LAX_ZOPC (unsigned long)(0xebL << 40 | 0xf7L) // z196 +#define LAXG_ZOPC (unsigned long)(0xebL << 40 | 0xe7L) // z196 +#define LAO_ZOPC (unsigned long)(0xebL << 40 | 0xf6L) // z196 +#define LAOG_ZOPC (unsigned long)(0xebL << 40 | 0xe6L) // z196 + +// System Functions +#define STCK_ZOPC (unsigned int)(0xb2 << 24 | 0x05 << 16) +#define STCKF_ZOPC (unsigned int)(0xb2 << 24 | 0x7c << 16) +#define STFLE_ZOPC (unsigned int)(0xb2 << 24 | 0xb0 << 16) +#define ECTG_ZOPC (unsigned long)(0xc8L <<40 | 0x01L << 32) // z10 +#define ECAG_ZOPC (unsigned long)(0xebL <<40 | 0x4cL) // z10 + +// Execution Prediction +#define PFD_ZOPC (unsigned long)(0xe3L <<40 | 0x36L) // z10 +#define PFDRL_ZOPC (unsigned long)(0xc6L <<40 | 0x02L << 32) // z10 +#define BPP_ZOPC (unsigned long)(0xc7L <<40) // branch prediction preload -- EC12 +#define BPRP_ZOPC (unsigned long)(0xc5L <<40) // branch prediction preload -- EC12 + +// Transaction Control +#define TBEGIN_ZOPC (unsigned long)(0xe560L << 32) // tx begin -- EC12 +#define TBEGINC_ZOPC (unsigned long)(0xe561L << 32) // tx begin (constrained) -- EC12 +#define TEND_ZOPC (unsigned int)(0xb2f8 << 16) // tx end -- EC12 +#define TABORT_ZOPC (unsigned int)(0xb2fc << 16) // tx abort -- EC12 +#define ETND_ZOPC (unsigned int)(0xb2ec << 16) // tx nesting depth -- EC12 +#define PPA_ZOPC (unsigned int)(0xb2e8 << 16) // tx processor assist -- EC12 + +// Crypto and Checksum +#define CKSM_ZOPC (unsigned int)(0xb2 << 24 | 0x41 << 16) // checksum. This is NOT CRC32 +#define KM_ZOPC (unsigned int)(0xb9 << 24 | 0x2e << 16) // cipher +#define KMC_ZOPC (unsigned int)(0xb9 << 24 | 0x2f << 16) // cipher +#define KIMD_ZOPC (unsigned int)(0xb9 << 24 | 0x3e << 16) // SHA (msg digest) +#define KLMD_ZOPC (unsigned int)(0xb9 << 24 | 0x3f << 16) // SHA (msg digest) +#define KMAC_ZOPC (unsigned int)(0xb9 << 24 | 0x1e << 16) // Message Authentication Code + +// Various +#define TCEB_ZOPC (unsigned long)(237L << 40 | 16) +#define TCDB_ZOPC (unsigned long)(237L << 40 | 17) +#define TAM_ZOPC (unsigned long)(267) + +#define FLOGR_ZOPC (unsigned int)(0xb9 << 24 | 0x83 << 16) +#define POPCNT_ZOPC (unsigned int)(0xb9e1 << 16) +#define AHHHR_ZOPC (unsigned int)(0xb9c8 << 16) +#define AHHLR_ZOPC (unsigned int)(0xb9d8 << 16) + + +// OpCode field masks + +#define RI_MASK (unsigned int)(0xff << 24 | 0x0f << 16) +#define RRE_MASK (unsigned int)(0xff << 24 | 0xff << 16) +#define RSI_MASK (unsigned int)(0xff << 24) +#define RIE_MASK (unsigned long)(0xffL << 40 | 0xffL) +#define RIL_MASK (unsigned long)(0xffL << 40 | 0x0fL << 32) + +#define BASR_MASK (unsigned int)(0xff << 8) +#define BCR_MASK (unsigned int)(0xff << 8) +#define BRC_MASK (unsigned int)(0xff << 24 | 0x0f << 16) +#define LGHI_MASK (unsigned int)(0xff << 24 | 0x0f << 16) +#define LLI_MASK (unsigned int)(0xff << 24 | 0x0f << 16) +#define II_MASK (unsigned int)(0xff << 24 | 0x0f << 16) +#define LLIF_MASK (unsigned long)(0xffL << 40 | 0x0fL << 32) +#define IIF_MASK (unsigned long)(0xffL << 40 | 0x0fL << 32) +#define BRASL_MASK (unsigned long)(0xffL << 40 | 0x0fL << 32) +#define TM_MASK (unsigned int)(0xff << 24) +#define TMY_MASK (unsigned long)(0xffL << 40 | 0xffL) +#define LB_MASK (unsigned long)(0xffL << 40 | 0xffL) +#define LH_MASK (unsigned int)(0xff << 24) +#define L_MASK (unsigned int)(0xff << 24) +#define LY_MASK (unsigned long)(0xffL << 40 | 0xffL) +#define LG_MASK (unsigned long)(0xffL << 40 | 0xffL) +#define LLGH_MASK (unsigned long)(0xffL << 40 | 0xffL) +#define LLGF_MASK (unsigned long)(0xffL << 40 | 0xffL) +#define SLAG_MASK (unsigned long)(0xffL << 40 | 0xffL) +#define LARL_MASK (unsigned long)(0xff0fL << 32) +#define LGRL_MASK (unsigned long)(0xff0fL << 32) +#define LE_MASK (unsigned int)(0xff << 24) +#define LD_MASK (unsigned int)(0xff << 24) +#define ST_MASK (unsigned int)(0xff << 24) +#define STC_MASK (unsigned int)(0xff << 24) +#define STG_MASK (unsigned long)(0xffL << 40 | 0xffL) +#define STH_MASK (unsigned int)(0xff << 24) +#define STE_MASK (unsigned int)(0xff << 24) +#define STD_MASK (unsigned int)(0xff << 24) +#define CMPBRANCH_MASK (unsigned long)(0xffL << 40 | 0xffL) +#define REL_LONG_MASK (unsigned long)(0xff0fL << 32) + + public: + // Condition code masks. Details: + // - Mask bit#3 must be zero for all compare and branch/trap instructions to ensure + // future compatibility. + // - For all arithmetic instructions which set the condition code, mask bit#3 + // indicates overflow ("unordered" in float operations). + // - "unordered" float comparison results have to be treated as low. + // - When overflow/unordered is detected, none of the branch conditions is true, + // except for bcondOverflow/bcondNotOrdered and bcondAlways. + // - For INT comparisons, the inverse condition can be calculated as (14-cond). + // - For FLOAT comparisons, the inverse condition can be calculated as (15-cond). + enum branch_condition { + bcondNever = 0, + bcondAlways = 15, + + // Specific names. Make use of lightweight sync. + // Full and lightweight sync operation. + bcondFullSync = 15, + bcondLightSync = 14, + bcondNop = 0, + + // arithmetic compare instructions + // arithmetic load and test, insert instructions + // Mask bit#3 must be zero for future compatibility. + bcondEqual = 8, + bcondNotEqual = 6, + bcondLow = 4, + bcondNotLow = 10, + bcondHigh = 2, + bcondNotHigh = 12, + // arithmetic calculation instructions + // Mask bit#3 indicates overflow if detected by instr. + // Mask bit#3 = 0 (overflow is not handled by compiler). + bcondOverflow = 1, + bcondNotOverflow = 14, + bcondZero = bcondEqual, + bcondNotZero = bcondNotEqual, + bcondNegative = bcondLow, + bcondNotNegative = bcondNotLow, + bcondPositive = bcondHigh, + bcondNotPositive = bcondNotHigh, + bcondNotOrdered = 1, // float comparisons + bcondOrdered = 14, // float comparisons + bcondLowOrNotOrdered = bcondLow|bcondNotOrdered, // float comparisons + bcondHighOrNotOrdered = bcondHigh|bcondNotOrdered, // float comparisons + // unsigned arithmetic calculation instructions + // Mask bit#0 is not used by these instructions. + // There is no indication of overflow for these instr. + bcondLogZero = 2, + bcondLogNotZero = 5, + bcondLogNotZero_Borrow = 4, + bcondLogNotZero_NoBorrow = 1, + // string search instructions + bcondFound = 4, + bcondNotFound = 2, + bcondInterrupted = 1, + // bit test instructions + bcondAllZero = 8, + bcondMixed = 6, + bcondAllOne = 1, + bcondNotAllZero = 7 // for tmll + }; + + enum Condition { + // z/Architecture + negative = 0, + less = 0, + positive = 1, + greater = 1, + zero = 2, + equal = 2, + summary_overflow = 3, + }; + + // Rounding mode for float-2-int conversions. + enum RoundingMode { + current_mode = 0, // Mode taken from FPC register. + biased_to_nearest = 1, + to_nearest = 4, + to_zero = 5, + to_plus_infinity = 6, + to_minus_infinity = 7 + }; + + // Inverse condition code, i.e. determine "15 - cc" for a given condition code cc. + static branch_condition inverse_condition(branch_condition cc); + static branch_condition inverse_float_condition(branch_condition cc); + + + //----------------------------------------------- + // instruction property getter methods + //----------------------------------------------- + + // Calculate length of instruction. + static int instr_len(unsigned char *instr); + + // Longest instructions are 6 bytes on z/Architecture. + static int instr_maxlen() { return 6; } + + // Average instruction is 4 bytes on z/Architecture (just a guess). + static int instr_avglen() { return 4; } + + // Shortest instructions are 2 bytes on z/Architecture. + static int instr_minlen() { return 2; } + + // Move instruction at pc right-justified into passed long int. + // Return instr len in bytes as function result. + static unsigned int get_instruction(unsigned char *pc, unsigned long *instr); + + // Move instruction in passed (long int) into storage at pc. + // This code is _NOT_ MT-safe!! + static void set_instruction(unsigned char *pc, unsigned long instr, unsigned int len) { + memcpy(pc, ((unsigned char *)&instr)+sizeof(unsigned long)-len, len); + } + + + //------------------------------------------ + // instruction field test methods + //------------------------------------------ + + // Only used once in s390.ad to implement Matcher::is_short_branch_offset(). + static bool is_within_range_of_RelAddr16(address target, address origin) { + return RelAddr::is_in_range_of_RelAddr16(target, origin); + } + + + //---------------------------------- + // some diagnostic output + //---------------------------------- + + static void print_dbg_msg(outputStream* out, unsigned long inst, const char* msg, int ilen) PRODUCT_RETURN; + static void dump_code_range(outputStream* out, address pc, const unsigned int range, const char* msg = " ") PRODUCT_RETURN; + + protected: + + //------------------------------------------------------- + // instruction field helper methods (internal) + //------------------------------------------------------- + + // Return a mask of 1s between hi_bit and lo_bit (inclusive). + static long fmask(unsigned int hi_bit, unsigned int lo_bit) { + assert(hi_bit >= lo_bit && hi_bit < 48, "bad bits"); + return ((1L<<(hi_bit-lo_bit+1)) - 1) << lo_bit; + } + + // extract u_field + // unsigned value + static long inv_u_field(long x, int hi_bit, int lo_bit) { + return (x & fmask(hi_bit, lo_bit)) >> lo_bit; + } + + // extract s_field + // Signed value, may need sign extension. + static long inv_s_field(long x, int hi_bit, int lo_bit) { + x = inv_u_field(x, hi_bit, lo_bit); + // Highest extracted bit set -> sign extension. + return (x >= (1L<<(hi_bit-lo_bit)) ? x | ((-1L)<<(hi_bit-lo_bit)) : x); + } + + // Extract primary opcode from instruction. + static int z_inv_op(int x) { return inv_u_field(x, 31, 24); } + static int z_inv_op(long x) { return inv_u_field(x, 47, 40); } + + static int inv_reg( long x, int s, int len) { return inv_u_field(x, (len-s)-1, (len-s)-4); } // Regs are encoded in 4 bits. + static int inv_mask(long x, int s, int len) { return inv_u_field(x, (len-s)-1, (len-s)-8); } // Mask is 8 bits long. + static int inv_simm16_48(long x) { return (inv_s_field(x, 31, 16)); } // 6-byte instructions only + static int inv_simm16(long x) { return (inv_s_field(x, 15, 0)); } // 4-byte instructions only + static int inv_simm20(long x) { return (inv_u_field(x, 27, 16) | // 6-byte instructions only + inv_s_field(x, 15, 8)<<12); } + static int inv_simm32(long x) { return (inv_s_field(x, 31, 0)); } // 6-byte instructions only + static int inv_uimm12(long x) { return (inv_u_field(x, 11, 0)); } // 4-byte instructions only + + // Encode u_field from long value. + static long u_field(long x, int hi_bit, int lo_bit) { + long r = x << lo_bit; + assert((r & ~fmask(hi_bit, lo_bit)) == 0, "value out of range"); + assert(inv_u_field(r, hi_bit, lo_bit) == x, "just checking"); + return r; + } + + public: + + //-------------------------------------------------- + // instruction field construction methods + //-------------------------------------------------- + + // Compute relative address (32 bit) for branch. + // Only used once in nativeInst_s390.cpp. + static intptr_t z_pcrel_off(address dest, address pc) { + return RelAddr::pcrel_off32(dest, pc); + } + + // Extract 20-bit signed displacement. + // Only used in disassembler_s390.cpp for temp enhancements. + static int inv_simm20_xx(address iLoc) { + unsigned long instr = 0; + unsigned long iLen = get_instruction(iLoc, &instr); + return inv_simm20(instr); + } + + // unsigned immediate, in low bits, nbits long + static long uimm(long x, int nbits) { + assert(Immediate::is_uimm(x, nbits), "unsigned constant out of range"); + return x & fmask(nbits - 1, 0); + } + + // Cast '1' to long to avoid sign extension if nbits = 32. + // signed immediate, in low bits, nbits long + static long simm(long x, int nbits) { + assert(Immediate::is_simm(x, nbits), "value out of range"); + return x & fmask(nbits - 1, 0); + } + + static long imm(int64_t x, int nbits) { + // Assert that x can be represented with nbits bits ignoring the sign bits, + // i.e. the more higher bits should all be 0 or 1. + assert((x >> nbits) == 0 || (x >> nbits) == -1, "value out of range"); + return x & fmask(nbits-1, 0); + } + + // A 20-bit displacement is only in instructions of the + // RSY, RXY, or SIY format. In these instructions, the D + // field consists of a DL (low) field in bit positions 20-31 + // and of a DH (high) field in bit positions 32-39. The + // value of the displacement is formed by appending the + // contents of the DH field to the left of the contents of + // the DL field. + static long simm20(int64_t ui20) { + assert(Immediate::is_simm(ui20, 20), "value out of range"); + return ( ((ui20 & 0xfffL) << (48-32)) | // DL + (((ui20 >> 12) & 0xffL) << (48-40))); // DH + } + + static long reg(Register r, int s, int len) { return u_field(r->encoding(), (len-s)-1, (len-s)-4); } + static long reg(int r, int s, int len) { return u_field(r, (len-s)-1, (len-s)-4); } + static long regt(Register r, int s, int len) { return reg(r, s, len); } + static long regz(Register r, int s, int len) { assert(r != Z_R0, "cannot use register R0 in memory access"); return reg(r, s, len); } + + static long uimm4( int64_t ui4, int s, int len) { return uimm(ui4, 4) << (len-s-4); } + static long uimm6( int64_t ui6, int s, int len) { return uimm(ui6, 6) << (len-s-6); } + static long uimm8( int64_t ui8, int s, int len) { return uimm(ui8, 8) << (len-s-8); } + static long uimm12(int64_t ui12, int s, int len) { return uimm(ui12, 12) << (len-s-12); } + static long uimm16(int64_t ui16, int s, int len) { return uimm(ui16, 16) << (len-s-16); } + static long uimm32(int64_t ui32, int s, int len) { return uimm((unsigned)ui32, 32) << (len-s-32); } // prevent sign extension + + static long simm8( int64_t si8, int s, int len) { return simm(si8, 8) << (len-s-8); } + static long simm12(int64_t si12, int s, int len) { return simm(si12, 12) << (len-s-12); } + static long simm16(int64_t si16, int s, int len) { return simm(si16, 16) << (len-s-16); } + static long simm24(int64_t si24, int s, int len) { return simm(si24, 24) << (len-s-24); } + static long simm32(int64_t si32, int s, int len) { return simm(si32, 32) << (len-s-32); } + + static long imm8( int64_t i8, int s, int len) { return imm(i8, 8) << (len-s-8); } + static long imm12(int64_t i12, int s, int len) { return imm(i12, 12) << (len-s-12); } + static long imm16(int64_t i16, int s, int len) { return imm(i16, 16) << (len-s-16); } + static long imm24(int64_t i24, int s, int len) { return imm(i24, 24) << (len-s-24); } + static long imm32(int64_t i32, int s, int len) { return imm(i32, 32) << (len-s-32); } + + static long fregt(FloatRegister r, int s, int len) { return freg(r,s,len); } + static long freg( FloatRegister r, int s, int len) { return u_field(r->encoding(), (len-s)-1, (len-s)-4); } + + // Rounding mode for float-2-int conversions. + static long rounding_mode(RoundingMode m, int s, int len) { + assert(m != 2 && m != 3, "invalid mode"); + return uimm(m, 4) << (len-s-4); + } + + //-------------------------------------------- + // instruction field getter methods + //-------------------------------------------- + + static int get_imm32(address a, int instruction_number) { + int imm; + int *p =((int *)(a + 2 + 6 * instruction_number)); + imm = *p; + return imm; + } + + static short get_imm16(address a, int instruction_number) { + short imm; + short *p =((short *)a) + 2 * instruction_number + 1; + imm = *p; + return imm; + } + + + //-------------------------------------------- + // instruction field setter methods + //-------------------------------------------- + + static void set_imm32(address a, int64_t s) { + assert(Immediate::is_simm32(s) || Immediate::is_uimm32(s), "to big"); + int* p = (int *) (a + 2); + *p = s; + } + + static void set_imm16(int* instr, int64_t s) { + assert(Immediate::is_simm16(s) || Immediate::is_uimm16(s), "to big"); + short* p = ((short *)instr) + 1; + *p = s; + } + + public: + + static unsigned int align(unsigned int x, unsigned int a) { return ((x + (a - 1)) & ~(a - 1)); } + static bool is_aligned(unsigned int x, unsigned int a) { return (0 == x % a); } + + inline void emit_16(int x); + inline void emit_32(int x); + inline void emit_48(long x); + + // Compare and control flow instructions + // ===================================== + + // See also commodity routines compare64_and_branch(), compare32_and_branch(). + + // compare instructions + // compare register + inline void z_cr( Register r1, Register r2); // compare (r1, r2) ; int32 + inline void z_cgr( Register r1, Register r2); // compare (r1, r2) ; int64 + inline void z_cgfr(Register r1, Register r2); // compare (r1, r2) ; int64 <--> int32 + // compare immediate + inline void z_chi( Register r1, int64_t i2); // compare (r1, i2_imm16) ; int32 + inline void z_cfi( Register r1, int64_t i2); // compare (r1, i2_imm32) ; int32 + inline void z_cghi(Register r1, int64_t i2); // compare (r1, i2_imm16) ; int64 + inline void z_cgfi(Register r1, int64_t i2); // compare (r1, i2_imm32) ; int64 + // compare memory + inline void z_ch( Register r1, const Address &a); // compare (r1, *(a)) ; int32 <--> int16 + inline void z_ch( Register r1, int64_t d2, Register x2, Register b2); // compare (r1, *(d2_uimm12+x2+b2)) ; int32 <--> int16 + inline void z_c( Register r1, const Address &a); // compare (r1, *(a)) ; int32 + inline void z_c( Register r1, int64_t d2, Register x2, Register b2); // compare (r1, *(d2_uimm12+x2+b2)) ; int32 + inline void z_cy( Register r1, int64_t d2, Register x2, Register b2); // compare (r1, *(d2_uimm20+x2+b2)) ; int32 + inline void z_cy( Register r1, int64_t d2, Register b2); // compare (r1, *(d2_uimm20+x2+b2)) ; int32 + inline void z_cy( Register r1, const Address& a); // compare (r1, *(a)) ; int32 + //inline void z_cgf(Register r1,const Address &a); // compare (r1, *(a)) ; int64 <--> int32 + //inline void z_cgf(Register r1,int64_t d2, Register x2, Register b2);// compare (r1, *(d2_uimm12+x2+b2)) ; int64 <--> int32 + inline void z_cg( Register r1, const Address &a); // compare (r1, *(a)) ; int64 + inline void z_cg( Register r1, int64_t d2, Register x2, Register b2); // compare (r1, *(d2_imm20+x2+b2)) ; int64 + + // compare logical instructions + // compare register + inline void z_clr( Register r1, Register r2); // compare (r1, r2) ; uint32 + inline void z_clgr( Register r1, Register r2); // compare (r1, r2) ; uint64 + // compare immediate + inline void z_clfi( Register r1, int64_t i2); // compare (r1, i2_uimm32) ; uint32 + inline void z_clgfi(Register r1, int64_t i2); // compare (r1, i2_uimm32) ; uint64 + inline void z_cl( Register r1, const Address &a); // compare (r1, *(a) ; uint32 + inline void z_cl( Register r1, int64_t d2, Register x2, Register b2);// compare (r1, *(d2_uimm12+x2+b2) ; uint32 + inline void z_cly( Register r1, int64_t d2, Register x2, Register b2);// compare (r1, *(d2_uimm20+x2+b2)) ; uint32 + inline void z_cly( Register r1, int64_t d2, Register b2); // compare (r1, *(d2_uimm20+x2+b2)) ; uint32 + inline void z_cly( Register r1, const Address& a); // compare (r1, *(a)) ; uint32 + inline void z_clg( Register r1, const Address &a); // compare (r1, *(a) ; uint64 + inline void z_clg( Register r1, int64_t d2, Register x2, Register b2);// compare (r1, *(d2_imm20+x2+b2) ; uint64 + + // test under mask + inline void z_tmll(Register r1, int64_t i2); // test under mask, see docu + inline void z_tmlh(Register r1, int64_t i2); // test under mask, see docu + inline void z_tmhl(Register r1, int64_t i2); // test under mask, see docu + inline void z_tmhh(Register r1, int64_t i2); // test under mask, see docu + + // branch instructions + inline void z_bc( branch_condition m1, int64_t d2, Register x2, Register b2);// branch m1 ? pc = (d2_uimm12+x2+b2) + inline void z_bcr( branch_condition m1, Register r2); // branch (m1 && r2!=R0) ? pc = r2 + inline void z_brc( branch_condition i1, int64_t i2); // branch i1 ? pc = pc + i2_imm16 + inline void z_brc( branch_condition i1, address a); // branch i1 ? pc = a + inline void z_brc( branch_condition i1, Label& L); // branch i1 ? pc = Label + //inline void z_brcl(branch_condition i1, int64_t i2); // branch i1 ? pc = pc + i2_imm32 + inline void z_brcl(branch_condition i1, address a); // branch i1 ? pc = a + inline void z_brcl(branch_condition i1, Label& L); // branch i1 ? pc = Label + inline void z_bctgr(Register r1, Register r2); // branch on count r1 -= 1; (r1!=0) ? pc = r2 ; r1 is int64 + + // branch unconditional / always + inline void z_br(Register r2); // branch to r2, nop if r2 == Z_R0 + + + // See also commodity routines compare64_and_branch(), compare32_and_branch(). + // signed comparison and branch + inline void z_crb( Register r1, Register r2, branch_condition m3, int64_t d4, Register b4); // (r1 m3 r2) ? goto b4+d4 ; int32 -- z10 + inline void z_cgrb(Register r1, Register r2, branch_condition m3, int64_t d4, Register b4); // (r1 m3 r2) ? goto b4+d4 ; int64 -- z10 + inline void z_crj( Register r1, Register r2, branch_condition m3, Label& L); // (r1 m3 r2) ? goto L ; int32 -- z10 + inline void z_crj( Register r1, Register r2, branch_condition m3, address a4); // (r1 m3 r2) ? goto (pc+a4<<1) ; int32 -- z10 + inline void z_cgrj(Register r1, Register r2, branch_condition m3, Label& L); // (r1 m3 r2) ? goto L ; int64 -- z10 + inline void z_cgrj(Register r1, Register r2, branch_condition m3, address a4); // (r1 m3 r2) ? goto (pc+a4<<1) ; int64 -- z10 + inline void z_cib( Register r1, int64_t i2, branch_condition m3, int64_t d4, Register b4); // (r1 m3 i2_imm8) ? goto b4+d4 ; int32 -- z10 + inline void z_cgib(Register r1, int64_t i2, branch_condition m3, int64_t d4, Register b4); // (r1 m3 i2_imm8) ? goto b4+d4 ; int64 -- z10 + inline void z_cij( Register r1, int64_t i2, branch_condition m3, Label& L); // (r1 m3 i2_imm8) ? goto L ; int32 -- z10 + inline void z_cij( Register r1, int64_t i2, branch_condition m3, address a4); // (r1 m3 i2_imm8) ? goto (pc+a4<<1) ; int32 -- z10 + inline void z_cgij(Register r1, int64_t i2, branch_condition m3, Label& L); // (r1 m3 i2_imm8) ? goto L ; int64 -- z10 + inline void z_cgij(Register r1, int64_t i2, branch_condition m3, address a4); // (r1 m3 i2_imm8) ? goto (pc+a4<<1) ; int64 -- z10 + // unsigned comparison and branch + inline void z_clrb( Register r1, Register r2, branch_condition m3, int64_t d4, Register b4);// (r1 m3 r2) ? goto b4+d4 ; uint32 -- z10 + inline void z_clgrb(Register r1, Register r2, branch_condition m3, int64_t d4, Register b4);// (r1 m3 r2) ? goto b4+d4 ; uint64 -- z10 + inline void z_clrj( Register r1, Register r2, branch_condition m3, Label& L); // (r1 m3 r2) ? goto L ; uint32 -- z10 + inline void z_clrj( Register r1, Register r2, branch_condition m3, address a4); // (r1 m3 r2) ? goto (pc+a4<<1) ; uint32 -- z10 + inline void z_clgrj(Register r1, Register r2, branch_condition m3, Label& L); // (r1 m3 r2) ? goto L ; uint64 -- z10 + inline void z_clgrj(Register r1, Register r2, branch_condition m3, address a4); // (r1 m3 r2) ? goto (pc+a4<<1) ; uint64 -- z10 + inline void z_clib( Register r1, int64_t i2, branch_condition m3, int64_t d4, Register b4); // (r1 m3 i2_uimm8) ? goto b4+d4 ; uint32 -- z10 + inline void z_clgib(Register r1, int64_t i2, branch_condition m3, int64_t d4, Register b4); // (r1 m3 i2_uimm8) ? goto b4+d4 ; uint64 -- z10 + inline void z_clij( Register r1, int64_t i2, branch_condition m3, Label& L); // (r1 m3 i2_uimm8) ? goto L ; uint32 -- z10 + inline void z_clij( Register r1, int64_t i2, branch_condition m3, address a4); // (r1 m3 i2_uimm8) ? goto (pc+a4<<1) ; uint32 -- z10 + inline void z_clgij(Register r1, int64_t i2, branch_condition m3, Label& L); // (r1 m3 i2_uimm8) ? goto L ; uint64 -- z10 + inline void z_clgij(Register r1, int64_t i2, branch_condition m3, address a4); // (r1 m3 i2_uimm8) ? goto (pc+a4<<1) ; uint64 -- z10 + + // Compare and trap instructions. + // signed comparison + inline void z_crt(Register r1, Register r2, int64_t m3); // (r1 m3 r2) ? trap ; int32 -- z10 + inline void z_cgrt(Register r1, Register r2, int64_t m3); // (r1 m3 r2) ? trap ; int64 -- z10 + inline void z_cit(Register r1, int64_t i2, int64_t m3); // (r1 m3 i2_imm16) ? trap ; int32 -- z10 + inline void z_cgit(Register r1, int64_t i2, int64_t m3); // (r1 m3 i2_imm16) ? trap ; int64 -- z10 + // unsigned comparison + inline void z_clrt(Register r1, Register r2, int64_t m3); // (r1 m3 r2) ? trap ; uint32 -- z10 + inline void z_clgrt(Register r1, Register r2, int64_t m3); // (r1 m3 r2) ? trap ; uint64 -- z10 + inline void z_clfit(Register r1, int64_t i2, int64_t m3); // (r1 m3 i2_uimm16) ? trap ; uint32 -- z10 + inline void z_clgit(Register r1, int64_t i2, int64_t m3); // (r1 m3 i2_uimm16) ? trap ; uint64 -- z10 + + inline void z_illtrap(); + inline void z_illtrap(int id); + inline void z_illtrap_eyecatcher(unsigned short xpattern, unsigned short pattern); + + + // load address, add for addresses + // =============================== + + // The versions without suffix z assert that the base reg is != Z_R0. + // Z_R0 is interpreted as constant '0'. The variants with Address operand + // check this automatically, so no two versions are needed. + inline void z_layz(Register r1, int64_t d2, Register x2, Register b2); // Special version. Allows Z_R0 as base reg. + inline void z_lay(Register r1, const Address &a); // r1 = a + inline void z_lay(Register r1, int64_t d2, Register x2, Register b2); // r1 = d2_imm20+x2+b2 + inline void z_laz(Register r1, int64_t d2, Register x2, Register b2); // Special version. Allows Z_R0 as base reg. + inline void z_la(Register r1, const Address &a); // r1 = a ; unsigned immediate! + inline void z_la(Register r1, int64_t d2, Register x2, Register b2); // r1 = d2_uimm12+x2+b2 ; unsigned immediate! + inline void z_larl(Register r1, int64_t i2); // r1 = pc + i2_imm32<<1; + inline void z_larl(Register r1, address a2); // r1 = pc + i2_imm32<<1; + + // Load instructions for integers + // ============================== + + // Address as base + index + offset + inline void z_lb( Register r1, const Address &a); // load r1 = *(a) ; int32 <- int8 + inline void z_lb( Register r1, int64_t d2, Register x2, Register b2); // load r1 = *(d2_imm20+x2+b2) ; int32 <- int8 + inline void z_lh( Register r1, const Address &a); // load r1 = *(a) ; int32 <- int16 + inline void z_lh( Register r1, int64_t d2, Register x2, Register b2); // load r1 = *(d2_uimm12+x2+b2); int32 <- int16 + inline void z_lhy(Register r1, const Address &a); // load r1 = *(a) ; int32 <- int16 + inline void z_lhy(Register r1, int64_t d2, Register x2, Register b2); // load r1 = *(d2_imm20+x2+b2) ; int32 <- int16 + inline void z_l( Register r1, const Address& a); // load r1 = *(a) ; int32 + inline void z_l( Register r1, int64_t d2, Register x2, Register b2); // load r1 = *(d2_uimm12+x2+b2); int32 + inline void z_ly( Register r1, const Address& a); // load r1 = *(a) ; int32 + inline void z_ly( Register r1, int64_t d2, Register x2, Register b2); // load r1 = *(d2_imm20+x2+b2) ; int32 + + inline void z_lgb(Register r1, const Address &a); // load r1 = *(a) ; int64 <- int8 + inline void z_lgb(Register r1, int64_t d2, Register x2, Register b2); // load r1 = *(d2_imm20+x2+b2) ; int64 <- int8 + inline void z_lgh(Register r1, const Address &a); // load r1 = *(a) ; int64 <- int16 + inline void z_lgh(Register r1, int64_t d2, Register x2, Register b2); // load r1 = *(d2_imm12+x2+b2) ; int64 <- int16 + inline void z_lgf(Register r1, const Address &a); // load r1 = *(a) ; int64 <- int32 + inline void z_lgf(Register r1, int64_t d2, Register x2, Register b2); // load r1 = *(d2_imm20+x2+b2) ; int64 <- int32 + inline void z_lg( Register r1, const Address& a); // load r1 = *(a) ; int64 <- int64 + inline void z_lg( Register r1, int64_t d2, Register x2, Register b2); // load r1 = *(d2_imm20+x2+b2) ; int64 <- int64 + + // load and test + inline void z_lt( Register r1, const Address &a); // load and test r1 = *(a) ; int32 + inline void z_lt( Register r1, int64_t d2, Register x2, Register b2);// load and test r1 = *(d2_imm20+x2+b2) ; int32 + inline void z_ltg( Register r1, const Address &a); // load and test r1 = *(a) ; int64 + inline void z_ltg( Register r1, int64_t d2, Register x2, Register b2);// load and test r1 = *(d2_imm20+x2+b2) ; int64 + inline void z_ltgf(Register r1, const Address &a); // load and test r1 = *(a) ; int64 <- int32 + inline void z_ltgf(Register r1, int64_t d2, Register x2, Register b2);// load and test r1 = *(d2_imm20+x2+b2) ; int64 <- int32 + + // load unsigned integer - zero extended + inline void z_llc( Register r1, const Address& a); // load r1 = *(a) ; uint32 <- uint8 + inline void z_llc( Register r1, int64_t d2, Register x2, Register b2);// load r1 = *(d2_imm20+x2+b2) ; uint32 <- uint8 + inline void z_llh( Register r1, const Address& a); // load r1 = *(a) ; uint32 <- uint16 + inline void z_llh( Register r1, int64_t d2, Register x2, Register b2);// load r1 = *(d2_imm20+x2+b2) ; uint32 <- uint16 + inline void z_llgc(Register r1, const Address& a); // load r1 = *(a) ; uint64 <- uint8 + inline void z_llgc(Register r1, int64_t d2, Register x2, Register b2);// load r1 = *(d2_imm20+x2+b2) ; uint64 <- uint8 + inline void z_llgc( Register r1, int64_t d2, Register b2); // load r1 = *(d2_imm20+b2) ; uint64 <- uint8 + inline void z_llgh(Register r1, const Address& a); // load r1 = *(a) ; uint64 <- uint16 + inline void z_llgh(Register r1, int64_t d2, Register x2, Register b2);// load r1 = *(d2_imm20+x2+b2) ; uint64 <- uint16 + inline void z_llgf(Register r1, const Address& a); // load r1 = *(a) ; uint64 <- uint32 + inline void z_llgf(Register r1, int64_t d2, Register x2, Register b2);// load r1 = *(d2_imm20+x2+b2) ; uint64 <- uint32 + + // pc relative addressing + inline void z_lhrl( Register r1, int64_t i2); // load r1 = *(pc + i2_imm32<<1) ; int32 <- int16 -- z10 + inline void z_lrl( Register r1, int64_t i2); // load r1 = *(pc + i2_imm32<<1) ; int32 -- z10 + inline void z_lghrl(Register r1, int64_t i2); // load r1 = *(pc + i2_imm32<<1) ; int64 <- int16 -- z10 + inline void z_lgfrl(Register r1, int64_t i2); // load r1 = *(pc + i2_imm32<<1) ; int64 <- int32 -- z10 + inline void z_lgrl( Register r1, int64_t i2); // load r1 = *(pc + i2_imm32<<1) ; int64 -- z10 + + inline void z_llhrl( Register r1, int64_t i2); // load r1 = *(pc + i2_imm32<<1) ; uint32 <- uint16 -- z10 + inline void z_llghrl(Register r1, int64_t i2); // load r1 = *(pc + i2_imm32<<1) ; uint64 <- uint16 -- z10 + inline void z_llgfrl(Register r1, int64_t i2); // load r1 = *(pc + i2_imm32<<1) ; uint64 <- uint32 -- z10 + + // Store instructions for integers + // =============================== + + // Address as base + index + offset + inline void z_stc( Register r1, const Address &d); // store *(a) = r1 ; int8 + inline void z_stc( Register r1, int64_t d2, Register x2, Register b2); // store *(d2_uimm12+x2+b2) = r1 ; int8 + inline void z_stcy(Register r1, const Address &d); // store *(a) = r1 ; int8 + inline void z_stcy(Register r1, int64_t d2, Register x2, Register b2); // store *(d2_imm20+x2+b2) = r1 ; int8 + inline void z_sth( Register r1, const Address &d); // store *(a) = r1 ; int16 + inline void z_sth( Register r1, int64_t d2, Register x2, Register b2); // store *(d2_uimm12+x2+b2) = r1 ; int16 + inline void z_sthy(Register r1, const Address &d); // store *(a) = r1 ; int16 + inline void z_sthy(Register r1, int64_t d2, Register x2, Register b2); // store *(d2_imm20+x2+b2) = r1 ; int16 + inline void z_st( Register r1, const Address &d); // store *(a) = r1 ; int32 + inline void z_st( Register r1, int64_t d2, Register x2, Register b2); // store *(d2_uimm12+x2+b2) = r1 ; int32 + inline void z_sty( Register r1, const Address &d); // store *(a) = r1 ; int32 + inline void z_sty( Register r1, int64_t d2, Register x2, Register b2); // store *(d2_imm20+x2+b2) = r1 ; int32 + inline void z_stg( Register r1, const Address &d); // store *(a) = r1 ; int64 + inline void z_stg( Register r1, int64_t d2, Register x2, Register b2); // store *(d2_uimm12+x2+b2) = r1 ; int64 + + inline void z_stcm( Register r1, int64_t m3, int64_t d2, Register b2); // store character under mask + inline void z_stcmy(Register r1, int64_t m3, int64_t d2, Register b2); // store character under mask + inline void z_stcmh(Register r1, int64_t m3, int64_t d2, Register b2); // store character under mask + + // pc relative addressing + inline void z_sthrl(Register r1, int64_t i2); // store *(pc + i2_imm32<<1) = r1 ; int16 -- z10 + inline void z_strl( Register r1, int64_t i2); // store *(pc + i2_imm32<<1) = r1 ; int32 -- z10 + inline void z_stgrl(Register r1, int64_t i2); // store *(pc + i2_imm32<<1) = r1 ; int64 -- z10 + + + // Load and store immediates + // ========================= + + // load immediate + inline void z_lhi( Register r1, int64_t i2); // r1 = i2_imm16 ; int32 <- int16 + inline void z_lghi(Register r1, int64_t i2); // r1 = i2_imm16 ; int64 <- int16 + inline void z_lgfi(Register r1, int64_t i2); // r1 = i2_imm32 ; int64 <- int32 + + inline void z_llihf(Register r1, int64_t i2); // r1 = i2_imm32 ; uint64 <- (uint32<<32) + inline void z_llilf(Register r1, int64_t i2); // r1 = i2_imm32 ; uint64 <- uint32 + inline void z_llihh(Register r1, int64_t i2); // r1 = i2_imm16 ; uint64 <- (uint16<<48) + inline void z_llihl(Register r1, int64_t i2); // r1 = i2_imm16 ; uint64 <- (uint16<<32) + inline void z_llilh(Register r1, int64_t i2); // r1 = i2_imm16 ; uint64 <- (uint16<<16) + inline void z_llill(Register r1, int64_t i2); // r1 = i2_imm16 ; uint64 <- uint16 + + // insert immediate + inline void z_ic( Register r1, int64_t d2, Register x2, Register b2); // insert character + inline void z_icy( Register r1, int64_t d2, Register x2, Register b2); // insert character + inline void z_icm( Register r1, int64_t m3, int64_t d2, Register b2); // insert character under mask + inline void z_icmy(Register r1, int64_t m3, int64_t d2, Register b2); // insert character under mask + inline void z_icmh(Register r1, int64_t m3, int64_t d2, Register b2); // insert character under mask + + inline void z_iihh(Register r1, int64_t i2); // insert immediate r1[ 0-15] = i2_imm16 + inline void z_iihl(Register r1, int64_t i2); // insert immediate r1[16-31] = i2_imm16 + inline void z_iilh(Register r1, int64_t i2); // insert immediate r1[32-47] = i2_imm16 + inline void z_iill(Register r1, int64_t i2); // insert immediate r1[48-63] = i2_imm16 + inline void z_iihf(Register r1, int64_t i2); // insert immediate r1[32-63] = i2_imm32 + inline void z_iilf(Register r1, int64_t i2); // insert immediate r1[ 0-31] = i2_imm32 + + // store immediate + inline void z_mvhhi(const Address &d, int64_t i2); // store *(d) = i2_imm16 ; int16 + inline void z_mvhhi(int64_t d1, Register b1, int64_t i2); // store *(d1_imm12+b1) = i2_imm16 ; int16 + inline void z_mvhi( const Address &d, int64_t i2); // store *(d) = i2_imm16 ; int32 + inline void z_mvhi( int64_t d1, Register b1, int64_t i2); // store *(d1_imm12+b1) = i2_imm16 ; int32 + inline void z_mvghi(const Address &d, int64_t i2); // store *(d) = i2_imm16 ; int64 + inline void z_mvghi(int64_t d1, Register b1, int64_t i2); // store *(d1_imm12+b1) = i2_imm16 ; int64 + + // Move and Convert instructions + // ============================= + + // move, sign extend + inline void z_lbr(Register r1, Register r2); // move r1 = r2 ; int32 <- int8 + inline void z_lhr( Register r1, Register r2); // move r1 = r2 ; int32 <- int16 + inline void z_lr(Register r1, Register r2); // move r1 = r2 ; int32, no sign extension + inline void z_lgbr(Register r1, Register r2); // move r1 = r2 ; int64 <- int8 + inline void z_lghr(Register r1, Register r2); // move r1 = r2 ; int64 <- int16 + inline void z_lgfr(Register r1, Register r2); // move r1 = r2 ; int64 <- int32 + inline void z_lgr(Register r1, Register r2); // move r1 = r2 ; int64 + // move, zero extend + inline void z_llhr( Register r1, Register r2); // move r1 = r2 ; uint32 <- uint16 + inline void z_llgcr(Register r1, Register r2); // move r1 = r2 ; uint64 <- uint8 + inline void z_llghr(Register r1, Register r2); // move r1 = r2 ; uint64 <- uint16 + inline void z_llgfr(Register r1, Register r2); // move r1 = r2 ; uint64 <- uint32 + + // move and test register + inline void z_ltr(Register r1, Register r2); // load/move and test r1 = r2; int32 + inline void z_ltgr(Register r1, Register r2); // load/move and test r1 = r2; int64 + inline void z_ltgfr(Register r1, Register r2); // load/move and test r1 = r2; int64 <-- int32 + + // move and byte-reverse + inline void z_lrvr( Register r1, Register r2); // move and reverse byte order r1 = r2; int32 + inline void z_lrvgr(Register r1, Register r2); // move and reverse byte order r1 = r2; int64 + + + // Arithmetic instructions (Integer only) + // ====================================== + // For float arithmetic instructions scroll further down + // Add logical differs in the condition codes set! + + // add registers + inline void z_ar( Register r1, Register r2); // add r1 = r1 + r2 ; int32 + inline void z_agr( Register r1, Register r2); // add r1 = r1 + r2 ; int64 + inline void z_agfr( Register r1, Register r2); // add r1 = r1 + r2 ; int64 <- int32 + inline void z_ark( Register r1, Register r2, Register r3); // add r1 = r2 + r3 ; int32 + inline void z_agrk( Register r1, Register r2, Register r3); // add r1 = r2 + r3 ; int64 + + inline void z_alr( Register r1, Register r2); // add logical r1 = r1 + r2 ; int32 + inline void z_algr( Register r1, Register r2); // add logical r1 = r1 + r2 ; int64 + inline void z_algfr(Register r1, Register r2); // add logical r1 = r1 + r2 ; int64 <- int32 + inline void z_alrk( Register r1, Register r2, Register r3); // add logical r1 = r2 + r3 ; int32 + inline void z_algrk(Register r1, Register r2, Register r3); // add logical r1 = r2 + r3 ; int64 + inline void z_alcgr(Register r1, Register r2); // add logical with carry r1 = r1 + r2 + c ; int64 + + // add immediate + inline void z_ahi( Register r1, int64_t i2); // add r1 = r1 + i2_imm16 ; int32 + inline void z_afi( Register r1, int64_t i2); // add r1 = r1 + i2_imm32 ; int32 + inline void z_alfi( Register r1, int64_t i2); // add r1 = r1 + i2_imm32 ; int32 + inline void z_aghi( Register r1, int64_t i2); // add logical r1 = r1 + i2_imm16 ; int64 + inline void z_agfi( Register r1, int64_t i2); // add r1 = r1 + i2_imm32 ; int64 + inline void z_algfi(Register r1, int64_t i2); // add logical r1 = r1 + i2_imm32 ; int64 + inline void z_ahik( Register r1, Register r3, int64_t i2); // add r1 = r3 + i2_imm16 ; int32 + inline void z_aghik(Register r1, Register r3, int64_t i2); // add r1 = r3 + i2_imm16 ; int64 + inline void z_aih( Register r1, int64_t i2); // add r1 = r1 + i2_imm32 ; int32 (HiWord) + + // add memory + inline void z_a( Register r1, int64_t d2, Register x2, Register b2); // add r1 = r1 + *(d2_uimm12+s2+b2) ; int32 + inline void z_ay( Register r1, int64_t d2, Register x2, Register b2);// add r1 = r1 + *(d2_imm20+s2+b2) ; int32 + inline void z_ag( Register r1, int64_t d2, Register x2, Register b2);// add r1 = r1 + *(d2_imm20+s2+b2) ; int64 + inline void z_agf( Register r1, int64_t d2, Register x2, Register b2);// add r1 = r1 + *(d2_imm20+x2+b2) ; int64 <- int32 + inline void z_al( Register r1, int64_t d2, Register x2, Register b2);// add r1 = r1 + *(d2_uimm12+x2+b2) ; int32 + inline void z_aly( Register r1, int64_t d2, Register x2, Register b2);// add r1 = r1 + *(d2_imm20+x2+b2) ; int32 + inline void z_alg( Register r1, int64_t d2, Register x2, Register b2);// add r1 = r1 + *(d2_imm20+x2+b2) ; int64 + inline void z_algf(Register r1, int64_t d2, Register x2, Register b2);// add r1 = r1 + *(d2_imm20+x2+b2) ; int64 <- int32 + inline void z_a( Register r1, const Address& a); // add r1 = r1 + *(a) ; int32 + inline void z_ay( Register r1, const Address& a); // add r1 = r1 + *(a) ; int32 + inline void z_al( Register r1, const Address& a); // add r1 = r1 + *(a) ; int32 + inline void z_aly( Register r1, const Address& a); // add r1 = r1 + *(a) ; int32 + inline void z_ag( Register r1, const Address& a); // add r1 = r1 + *(a) ; int64 + inline void z_agf( Register r1, const Address& a); // add r1 = r1 + *(a) ; int64 <- int32 + inline void z_alg( Register r1, const Address& a); // add r1 = r1 + *(a) ; int64 + inline void z_algf(Register r1, const Address& a); // add r1 = r1 + *(a) ; int64 <- int32 + + + inline void z_alhsik( Register r1, Register r3, int64_t i2); // add logical r1 = r3 + i2_imm16 ; int32 + inline void z_alghsik(Register r1, Register r3, int64_t i2); // add logical r1 = r3 + i2_imm16 ; int64 + + inline void z_asi( int64_t d1, Register b1, int64_t i2); // add *(d1_imm20+b1) += i2_imm8 ; int32 -- z10 + inline void z_agsi( int64_t d1, Register b1, int64_t i2); // add *(d1_imm20+b1) += i2_imm8 ; int64 -- z10 + inline void z_alsi( int64_t d1, Register b1, int64_t i2); // add logical *(d1_imm20+b1) += i2_imm8 ; uint32 -- z10 + inline void z_algsi(int64_t d1, Register b1, int64_t i2); // add logical *(d1_imm20+b1) += i2_imm8 ; uint64 -- z10 + inline void z_asi( const Address& d, int64_t i2); // add *(d) += i2_imm8 ; int32 -- z10 + inline void z_agsi( const Address& d, int64_t i2); // add *(d) += i2_imm8 ; int64 -- z10 + inline void z_alsi( const Address& d, int64_t i2); // add logical *(d) += i2_imm8 ; uint32 -- z10 + inline void z_algsi(const Address& d, int64_t i2); // add logical *(d) += i2_imm8 ; uint64 -- z10 + + // negate + inline void z_lcr( Register r1, Register r2 = noreg); // neg r1 = -r2 ; int32 + inline void z_lcgr( Register r1, Register r2 = noreg); // neg r1 = -r2 ; int64 + inline void z_lcgfr(Register r1, Register r2); // neg r1 = -r2 ; int64 <- int32 + inline void z_lnr( Register r1, Register r2 = noreg); // neg r1 = -|r2| ; int32 + inline void z_lngr( Register r1, Register r2 = noreg); // neg r1 = -|r2| ; int64 + inline void z_lngfr(Register r1, Register r2); // neg r1 = -|r2| ; int64 <- int32 + + // subtract intstructions + // sub registers + inline void z_sr( Register r1, Register r2); // sub r1 = r1 - r2 ; int32 + inline void z_sgr( Register r1, Register r2); // sub r1 = r1 - r2 ; int64 + inline void z_sgfr( Register r1, Register r2); // sub r1 = r1 - r2 ; int64 <- int32 + inline void z_srk( Register r1, Register r2, Register r3); // sub r1 = r2 - r3 ; int32 + inline void z_sgrk( Register r1, Register r2, Register r3); // sub r1 = r2 - r3 ; int64 + + inline void z_slr( Register r1, Register r2); // sub logical r1 = r1 - r2 ; int32 + inline void z_slgr( Register r1, Register r2); // sub logical r1 = r1 - r2 ; int64 + inline void z_slgfr(Register r1, Register r2); // sub logical r1 = r1 - r2 ; int64 <- int32 + inline void z_slrk( Register r1, Register r2, Register r3); // sub logical r1 = r2 - r3 ; int32 + inline void z_slgrk(Register r1, Register r2, Register r3); // sub logical r1 = r2 - r3 ; int64 + inline void z_slfi( Register r1, int64_t i2); // sub logical r1 = r1 - i2_uimm32 ; int32 + inline void z_slgfi(Register r1, int64_t i2); // add logical r1 = r1 - i2_uimm32 ; int64 + + // sub memory + inline void z_s( Register r1, int64_t d2, Register x2, Register b2); // sub r1 = r1 - *(d2_imm12+x2+b2) ; int32 + inline void z_sy( Register r1, int64_t d2, Register x2, Register b2); // sub r1 = r1 + *(d2_imm20+s2+b2) ; int32 + inline void z_sg( Register r1, int64_t d2, Register x2, Register b2); // sub r1 = r1 - *(d2_imm12+x2+b2) ; int64 + inline void z_sgf( Register r1, int64_t d2, Register x2, Register b2); // sub r1 = r1 - *(d2_imm12+x2+b2) ; int64 - int32 + inline void z_slg( Register r1, int64_t d2, Register x2, Register b2); // sub logical r1 = r1 - *(d2_imm20+x2+b2) ; uint64 + inline void z_slgf(Register r1, int64_t d2, Register x2, Register b2); // sub logical r1 = r1 - *(d2_imm20+x2+b2) ; uint64 - uint32 + inline void z_s( Register r1, const Address& a); // sub r1 = r1 - *(a) ; int32 + inline void z_sy( Register r1, const Address& a); // sub r1 = r1 - *(a) ; int32 + inline void z_sg( Register r1, const Address& a); // sub r1 = r1 - *(a) ; int64 + inline void z_sgf( Register r1, const Address& a); // sub r1 = r1 - *(a) ; int64 - int32 + inline void z_slg( Register r1, const Address& a); // sub r1 = r1 - *(a) ; uint64 + inline void z_slgf(Register r1, const Address& a); // sub r1 = r1 - *(a) ; uint64 - uint32 + + inline void z_sh( Register r1, int64_t d2, Register x2, Register b2); // sub r1 = r1 - *(d2_imm12+x2+b2) ; int32 - int16 + inline void z_shy( Register r1, int64_t d2, Register x2, Register b2); // sub r1 = r1 - *(d2_imm20+x2+b2) ; int32 - int16 + inline void z_sh( Register r1, const Address &a); // sub r1 = r1 - *(d2_imm12+x2+b2) ; int32 - int16 + inline void z_shy( Register r1, const Address &a); // sub r1 = r1 - *(d2_imm20+x2+b2) ; int32 - int16 + + // Multiplication instructions + // mul registers + inline void z_msr( Register r1, Register r2); // mul r1 = r1 * r2 ; int32 + inline void z_msgr( Register r1, Register r2); // mul r1 = r1 * r2 ; int64 + inline void z_msgfr(Register r1, Register r2); // mul r1 = r1 * r2 ; int64 <- int32 + inline void z_mlr( Register r1, Register r2); // mul r1 = r1 * r2 ; int32 unsigned + inline void z_mlgr( Register r1, Register r2); // mul r1 = r1 * r2 ; int64 unsigned + // mul register - memory + inline void z_mhy( Register r1, int64_t d2, Register x2, Register b2); // mul r1 = r1 * *(d2+x2+b2) + inline void z_msy( Register r1, int64_t d2, Register x2, Register b2); // mul r1 = r1 * *(d2+x2+b2) + inline void z_msg( Register r1, int64_t d2, Register x2, Register b2); // mul r1 = r1 * *(d2+x2+b2) + inline void z_msgf(Register r1, int64_t d2, Register x2, Register b2); // mul r1 = r1 * *(d2+x2+b2) + inline void z_ml( Register r1, int64_t d2, Register x2, Register b2); // mul r1 = r1 * *(d2+x2+b2) + inline void z_mlg( Register r1, int64_t d2, Register x2, Register b2); // mul r1 = r1 * *(d2+x2+b2) + inline void z_mhy( Register r1, const Address& a); // mul r1 = r1 * *(a) + inline void z_msy( Register r1, const Address& a); // mul r1 = r1 * *(a) + inline void z_msg( Register r1, const Address& a); // mul r1 = r1 * *(a) + inline void z_msgf(Register r1, const Address& a); // mul r1 = r1 * *(a) + inline void z_ml( Register r1, const Address& a); // mul r1 = r1 * *(a) + inline void z_mlg( Register r1, const Address& a); // mul r1 = r1 * *(a) + + inline void z_msfi( Register r1, int64_t i2); // mult r1 = r1 * i2_imm32; int32 -- z10 + inline void z_msgfi(Register r1, int64_t i2); // mult r1 = r1 * i2_imm32; int64 -- z10 + inline void z_mhi( Register r1, int64_t i2); // mult r1 = r1 * i2_imm16; int32 + inline void z_mghi( Register r1, int64_t i2); // mult r1 = r1 * i2_imm16; int64 + + // Division instructions + inline void z_dsgr( Register r1, Register r2); // div r1 = r1 / r2 ; int64/int32 needs reg pair! + inline void z_dsgfr(Register r1, Register r2); // div r1 = r1 / r2 ; int64/int32 needs reg pair! + + + // Logic instructions + // =================== + + // and + inline void z_n( Register r1, int64_t d2, Register x2, Register b2); + inline void z_ny( Register r1, int64_t d2, Register x2, Register b2); + inline void z_ng( Register r1, int64_t d2, Register x2, Register b2); + inline void z_n( Register r1, const Address& a); + inline void z_ny( Register r1, const Address& a); + inline void z_ng( Register r1, const Address& a); + + inline void z_nr( Register r1, Register r2); // and r1 = r1 & r2 ; int32 + inline void z_ngr( Register r1, Register r2); // and r1 = r1 & r2 ; int64 + inline void z_nrk( Register r1, Register r2, Register r3); // and r1 = r2 & r3 ; int32 + inline void z_ngrk(Register r1, Register r2, Register r3); // and r1 = r2 & r3 ; int64 + + inline void z_nihh(Register r1, int64_t i2); // and r1 = r1 & i2_imm16 ; and only for bits 0-15 + inline void z_nihl(Register r1, int64_t i2); // and r1 = r1 & i2_imm16 ; and only for bits 16-31 + inline void z_nilh(Register r1, int64_t i2); // and r1 = r1 & i2_imm16 ; and only for bits 32-47 + inline void z_nill(Register r1, int64_t i2); // and r1 = r1 & i2_imm16 ; and only for bits 48-63 + inline void z_nihf(Register r1, int64_t i2); // and r1 = r1 & i2_imm32 ; and only for bits 0-31 + inline void z_nilf(Register r1, int64_t i2); // and r1 = r1 & i2_imm32 ; and only for bits 32-63 see also MacroAssembler::nilf. + + // or + inline void z_o( Register r1, int64_t d2, Register x2, Register b2); + inline void z_oy( Register r1, int64_t d2, Register x2, Register b2); + inline void z_og( Register r1, int64_t d2, Register x2, Register b2); + inline void z_o( Register r1, const Address& a); + inline void z_oy( Register r1, const Address& a); + inline void z_og( Register r1, const Address& a); + + inline void z_or( Register r1, Register r2); // or r1 = r1 | r2; int32 + inline void z_ogr( Register r1, Register r2); // or r1 = r1 | r2; int64 + inline void z_ork( Register r1, Register r2, Register r3); // or r1 = r2 | r3 ; int32 + inline void z_ogrk(Register r1, Register r2, Register r3); // or r1 = r2 | r3 ; int64 + + inline void z_oihh(Register r1, int64_t i2); // or r1 = r1 | i2_imm16 ; or only for bits 0-15 + inline void z_oihl(Register r1, int64_t i2); // or r1 = r1 | i2_imm16 ; or only for bits 16-31 + inline void z_oilh(Register r1, int64_t i2); // or r1 = r1 | i2_imm16 ; or only for bits 32-47 + inline void z_oill(Register r1, int64_t i2); // or r1 = r1 | i2_imm16 ; or only for bits 48-63 + inline void z_oihf(Register r1, int64_t i2); // or r1 = r1 | i2_imm32 ; or only for bits 0-31 + inline void z_oilf(Register r1, int64_t i2); // or r1 = r1 | i2_imm32 ; or only for bits 32-63 + + // xor + inline void z_x( Register r1, int64_t d2, Register x2, Register b2); + inline void z_xy( Register r1, int64_t d2, Register x2, Register b2); + inline void z_xg( Register r1, int64_t d2, Register x2, Register b2); + inline void z_x( Register r1, const Address& a); + inline void z_xy( Register r1, const Address& a); + inline void z_xg( Register r1, const Address& a); + + inline void z_xr( Register r1, Register r2); // xor r1 = r1 ^ r2 ; int32 + inline void z_xgr( Register r1, Register r2); // xor r1 = r1 ^ r2 ; int64 + inline void z_xrk( Register r1, Register r2, Register r3); // xor r1 = r2 ^ r3 ; int32 + inline void z_xgrk(Register r1, Register r2, Register r3); // xor r1 = r2 ^ r3 ; int64 + + inline void z_xihf(Register r1, int64_t i2); // xor r1 = r1 ^ i2_imm32 ; or only for bits 0-31 + inline void z_xilf(Register r1, int64_t i2); // xor r1 = r1 ^ i2_imm32 ; or only for bits 32-63 + + // shift + inline void z_sla( Register r1, int64_t d2, Register b2=Z_R0); // shift left r1 = r1 << ((d2+b2)&0x3f) ; int32, only 31 bits shifted, sign preserved! + inline void z_slag(Register r1, Register r3, int64_t d2, Register b2=Z_R0); // shift left r1 = r3 << ((d2+b2)&0x3f) ; int64, only 63 bits shifted, sign preserved! + inline void z_sra( Register r1, int64_t d2, Register b2=Z_R0); // shift right r1 = r1 >> ((d2+b2)&0x3f) ; int32, sign extended + inline void z_srag(Register r1, Register r3, int64_t d2, Register b2=Z_R0); // shift right r1 = r3 >> ((d2+b2)&0x3f) ; int64, sign extended + inline void z_sll( Register r1, int64_t d2, Register b2=Z_R0); // shift left r1 = r1 << ((d2+b2)&0x3f) ; int32, zeros added + inline void z_sllg(Register r1, Register r3, int64_t d2, Register b2=Z_R0); // shift left r1 = r3 << ((d2+b2)&0x3f) ; int64, zeros added + inline void z_srl( Register r1, int64_t d2, Register b2=Z_R0); // shift right r1 = r1 >> ((d2+b2)&0x3f) ; int32, zero extended + inline void z_srlg(Register r1, Register r3, int64_t d2, Register b2=Z_R0); // shift right r1 = r3 >> ((d2+b2)&0x3f) ; int64, zero extended + + // rotate + inline void z_rll( Register r1, Register r3, int64_t d2, Register b2=Z_R0); // rot r1 = r3 << (d2+b2 & 0x3f) ; int32 -- z10 + inline void z_rllg(Register r1, Register r3, int64_t d2, Register b2=Z_R0); // rot r1 = r3 << (d2+b2 & 0x3f) ; int64 -- z10 + + // rotate the AND/XOR/OR/insert + inline void z_rnsbg( Register r1, Register r2, int64_t spos3, int64_t epos4, int64_t nrot5, bool test_only = false); // rotate then AND selected bits -- z196 + inline void z_rxsbg( Register r1, Register r2, int64_t spos3, int64_t epos4, int64_t nrot5, bool test_only = false); // rotate then XOR selected bits -- z196 + inline void z_rosbg( Register r1, Register r2, int64_t spos3, int64_t epos4, int64_t nrot5, bool test_only = false); // rotate then OR selected bits -- z196 + inline void z_risbg( Register r1, Register r2, int64_t spos3, int64_t epos4, int64_t nrot5, bool zero_rest = false); // rotate then INS selected bits -- z196 + + + // memory-immediate instructions (8-bit immediate) + // =============================================== + + inline void z_cli( int64_t d1, Register b1, int64_t i2); // compare *(d1_imm12+b1) ^= i2_imm8 ; int8 + inline void z_mvi( int64_t d1, Register b1, int64_t i2); // store *(d1_imm12+b1) = i2_imm8 ; int8 + inline void z_tm( int64_t d1, Register b1, int64_t i2); // test *(d1_imm12+b1) against mask i2_imm8 ; int8 + inline void z_ni( int64_t d1, Register b1, int64_t i2); // store *(d1_imm12+b1) &= i2_imm8 ; int8 + inline void z_oi( int64_t d1, Register b1, int64_t i2); // store *(d1_imm12+b1) |= i2_imm8 ; int8 + inline void z_xi( int64_t d1, Register b1, int64_t i2); // store *(d1_imm12+b1) ^= i2_imm8 ; int8 + inline void z_cliy(int64_t d1, Register b1, int64_t i2); // compare *(d1_imm12+b1) ^= i2_imm8 ; int8 + inline void z_mviy(int64_t d1, Register b1, int64_t i2); // store *(d1_imm12+b1) = i2_imm8 ; int8 + inline void z_tmy( int64_t d1, Register b1, int64_t i2); // test *(d1_imm12+b1) against mask i2_imm8 ; int8 + inline void z_niy( int64_t d1, Register b1, int64_t i2); // store *(d1_imm12+b1) &= i2_imm8 ; int8 + inline void z_oiy( int64_t d1, Register b1, int64_t i2); // store *(d1_imm12+b1) |= i2_imm8 ; int8 + inline void z_xiy( int64_t d1, Register b1, int64_t i2); // store *(d1_imm12+b1) ^= i2_imm8 ; int8 + inline void z_cli( const Address& a, int64_t imm8); // compare *(a) ^= imm8 ; int8 + inline void z_mvi( const Address& a, int64_t imm8); // store *(a) = imm8 ; int8 + inline void z_tm( const Address& a, int64_t imm8); // test *(a) against mask imm8 ; int8 + inline void z_ni( const Address& a, int64_t imm8); // store *(a) &= imm8 ; int8 + inline void z_oi( const Address& a, int64_t imm8); // store *(a) |= imm8 ; int8 + inline void z_xi( const Address& a, int64_t imm8); // store *(a) ^= imm8 ; int8 + inline void z_cliy(const Address& a, int64_t imm8); // compare *(a) ^= imm8 ; int8 + inline void z_mviy(const Address& a, int64_t imm8); // store *(a) = imm8 ; int8 + inline void z_tmy( const Address& a, int64_t imm8); // test *(a) against mask imm8 ; int8 + inline void z_niy( const Address& a, int64_t imm8); // store *(a) &= imm8 ; int8 + inline void z_oiy( const Address& a, int64_t imm8); // store *(a) |= imm8 ; int8 + inline void z_xiy( const Address& a, int64_t imm8); // store *(a) ^= imm8 ; int8 + + + //------------------------------ + // Interlocked-Update + //------------------------------ + inline void z_laa( Register r1, Register r3, int64_t d2, Register b2); // load and add int32, signed -- z196 + inline void z_laag( Register r1, Register r3, int64_t d2, Register b2); // load and add int64, signed -- z196 + inline void z_laal( Register r1, Register r3, int64_t d2, Register b2); // load and add int32, unsigned -- z196 + inline void z_laalg(Register r1, Register r3, int64_t d2, Register b2); // load and add int64, unsigned -- z196 + inline void z_lan( Register r1, Register r3, int64_t d2, Register b2); // load and and int32 -- z196 + inline void z_lang( Register r1, Register r3, int64_t d2, Register b2); // load and and int64 -- z196 + inline void z_lax( Register r1, Register r3, int64_t d2, Register b2); // load and xor int32 -- z196 + inline void z_laxg( Register r1, Register r3, int64_t d2, Register b2); // load and xor int64 -- z196 + inline void z_lao( Register r1, Register r3, int64_t d2, Register b2); // load and or int32 -- z196 + inline void z_laog( Register r1, Register r3, int64_t d2, Register b2); // load and or int64 -- z196 + + inline void z_laa( Register r1, Register r3, const Address& a); // load and add int32, signed -- z196 + inline void z_laag( Register r1, Register r3, const Address& a); // load and add int64, signed -- z196 + inline void z_laal( Register r1, Register r3, const Address& a); // load and add int32, unsigned -- z196 + inline void z_laalg(Register r1, Register r3, const Address& a); // load and add int64, unsigned -- z196 + inline void z_lan( Register r1, Register r3, const Address& a); // load and and int32 -- z196 + inline void z_lang( Register r1, Register r3, const Address& a); // load and and int64 -- z196 + inline void z_lax( Register r1, Register r3, const Address& a); // load and xor int32 -- z196 + inline void z_laxg( Register r1, Register r3, const Address& a); // load and xor int64 -- z196 + inline void z_lao( Register r1, Register r3, const Address& a); // load and or int32 -- z196 + inline void z_laog( Register r1, Register r3, const Address& a); // load and or int64 -- z196 + + //-------------------------------- + // Execution Prediction + //-------------------------------- + inline void z_pfd( int64_t m1, int64_t d2, Register x2, Register b2); // prefetch + inline void z_pfd( int64_t m1, Address a); + inline void z_pfdrl(int64_t m1, int64_t i2); // prefetch + inline void z_bpp( int64_t m1, int64_t i2, int64_t d3, Register b3); // branch prediction -- EC12 + inline void z_bprp( int64_t m1, int64_t i2, int64_t i3); // branch prediction -- EC12 + + //------------------------------- + // Transaction Control + //------------------------------- + inline void z_tbegin(int64_t d1, Register b1, int64_t i2); // begin transaction -- EC12 + inline void z_tbeginc(int64_t d1, Register b1, int64_t i2); // begin transaction (constrained) -- EC12 + inline void z_tend(); // end transaction -- EC12 + inline void z_tabort(int64_t d2, Register b2); // abort transaction -- EC12 + inline void z_etnd(Register r1); // extract tx nesting depth -- EC12 + inline void z_ppa(Register r1, Register r2, int64_t m3); // perform processor assist -- EC12 + + //--------------------------------- + // Conditional Execution + //--------------------------------- + inline void z_locr( Register r1, Register r2, branch_condition cc); // if (cc) load r1 = r2 ; int32 -- z196 + inline void z_locgr(Register r1, Register r2, branch_condition cc); // if (cc) load r1 = r2 ; int64 -- z196 + inline void z_loc( Register r1, int64_t d2, Register b2, branch_condition cc); // if (cc) load r1 = *(d2_simm20+b2) ; int32 -- z196 + inline void z_locg( Register r1, int64_t d2, Register b2, branch_condition cc); // if (cc) load r1 = *(d2_simm20+b2) ; int64 -- z196 + inline void z_loc( Register r1, const Address& a, branch_condition cc); // if (cc) load r1 = *(a) ; int32 -- z196 + inline void z_locg( Register r1, const Address& a, branch_condition cc); // if (cc) load r1 = *(a) ; int64 -- z196 + inline void z_stoc( Register r1, int64_t d2, Register b2, branch_condition cc); // if (cc) store *(d2_simm20+b2) = r1 ; int32 -- z196 + inline void z_stocg(Register r1, int64_t d2, Register b2, branch_condition cc); // if (cc) store *(d2_simm20+b2) = r1 ; int64 -- z196 + + + // Complex CISC instructions + // ========================== + + inline void z_cksm(Register r1, Register r2); // checksum. This is NOT CRC32 + inline void z_km( Register r1, Register r2); // cipher message + inline void z_kmc( Register r1, Register r2); // cipher message with chaining + inline void z_kimd(Register r1, Register r2); // msg digest (SHA) + inline void z_klmd(Register r1, Register r2); // msg digest (SHA) + inline void z_kmac(Register r1, Register r2); // msg authentication code + + inline void z_ex(Register r1, int64_t d2, Register x2, Register b2);// execute + inline void z_exrl(Register r1, int64_t i2); // execute relative long -- z10 + inline void z_exrl(Register r1, address a2); // execute relative long -- z10 + + inline void z_ectg(int64_t d1, Register b1, int64_t d2, Register b2, Register r3); // extract cpu time + inline void z_ecag(Register r1, Register r3, int64_t d2, Register b2); // extract CPU attribute + + inline void z_srst(Register r1, Register r2); // search string + inline void z_srstu(Register r1, Register r2); // search string unicode + + inline void z_mvc(const Address& d, const Address& s, int64_t l); // move l bytes + inline void z_mvc(int64_t d1, int64_t l, Register b1, int64_t d2, Register b2); // move l+1 bytes + inline void z_mvcle(Register r1, Register r3, int64_t d2, Register b2=Z_R0); // move region of memory + + inline void z_stfle(int64_t d2, Register b2); // store facility list extended + + inline void z_nc(int64_t d1, int64_t l, Register b1, int64_t d2, Register b2);// and *(d1+b1) = *(d1+l+b1) & *(d2+b2) ; d1, d2: uimm12, ands l+1 bytes + inline void z_oc(int64_t d1, int64_t l, Register b1, int64_t d2, Register b2);// or *(d1+b1) = *(d1+l+b1) | *(d2+b2) ; d1, d2: uimm12, ors l+1 bytes + inline void z_xc(int64_t d1, int64_t l, Register b1, int64_t d2, Register b2);// xor *(d1+b1) = *(d1+l+b1) ^ *(d2+b2) ; d1, d2: uimm12, xors l+1 bytes + inline void z_nc(Address dst, int64_t len, Address src2); // and *dst = *dst & *src2, ands len bytes in memory + inline void z_oc(Address dst, int64_t len, Address src2); // or *dst = *dst | *src2, ors len bytes in memory + inline void z_xc(Address dst, int64_t len, Address src2); // xor *dst = *dst ^ *src2, xors len bytes in memory + + // compare instructions + inline void z_clc(int64_t d1, int64_t l, Register b1, int64_t d2, Register b2); // compare (*(d1_uimm12+b1), *(d1_uimm12+b1)) ; compare l bytes + inline void z_clcle(Register r1, Register r3, int64_t d2, Register b2); // compare logical long extended, see docu + inline void z_clclu(Register r1, Register r3, int64_t d2, Register b2); // compare logical long unicode, see docu + + // Translate characters + inline void z_troo(Register r1, Register r2, int64_t m3); + inline void z_trot(Register r1, Register r2, int64_t m3); + inline void z_trto(Register r1, Register r2, int64_t m3); + inline void z_trtt(Register r1, Register r2, int64_t m3); + + + // Floatingpoint instructions + // ========================== + + // compare instructions + inline void z_cebr(FloatRegister r1, FloatRegister r2); // compare (r1, r2) ; float + inline void z_ceb(FloatRegister r1, int64_t d2, Register x2, Register b2); // compare (r1, *(d2_imm12+x2+b2)) ; float + inline void z_ceb(FloatRegister r1, const Address &a); // compare (r1, *(d2_imm12+x2+b2)) ; float + inline void z_cdbr(FloatRegister r1, FloatRegister r2); // compare (r1, r2) ; double + inline void z_cdb(FloatRegister r1, int64_t d2, Register x2, Register b2); // compare (r1, *(d2_imm12+x2+b2)) ; double + inline void z_cdb(FloatRegister r1, const Address &a); // compare (r1, *(d2_imm12+x2+b2)) ; double + + // load instructions + inline void z_le( FloatRegister r1, int64_t d2, Register x2, Register b2); // load r1 = *(d2_uimm12+x2+b2) ; float + inline void z_ley(FloatRegister r1, int64_t d2, Register x2, Register b2); // load r1 = *(d2_imm20+x2+b2) ; float + inline void z_ld( FloatRegister r1, int64_t d2, Register x2, Register b2); // load r1 = *(d2_uimm12+x2+b2) ; double + inline void z_ldy(FloatRegister r1, int64_t d2, Register x2, Register b2); // load r1 = *(d2_imm20+x2+b2) ; double + inline void z_le( FloatRegister r1, const Address &a); // load r1 = *(a) ; float + inline void z_ley(FloatRegister r1, const Address &a); // load r1 = *(a) ; float + inline void z_ld( FloatRegister r1, const Address &a); // load r1 = *(a) ; double + inline void z_ldy(FloatRegister r1, const Address &a); // load r1 = *(a) ; double + + // store instructions + inline void z_ste( FloatRegister r1, int64_t d2, Register x2, Register b2); // store *(d2_uimm12+x2+b2) = r1 ; float + inline void z_stey(FloatRegister r1, int64_t d2, Register x2, Register b2); // store *(d2_imm20+x2+b2) = r1 ; float + inline void z_std( FloatRegister r1, int64_t d2, Register x2, Register b2); // store *(d2_uimm12+x2+b2) = r1 ; double + inline void z_stdy(FloatRegister r1, int64_t d2, Register x2, Register b2); // store *(d2_imm20+x2+b2) = r1 ; double + inline void z_ste( FloatRegister r1, const Address &a); // store *(a) = r1 ; float + inline void z_stey(FloatRegister r1, const Address &a); // store *(a) = r1 ; float + inline void z_std( FloatRegister r1, const Address &a); // store *(a) = r1 ; double + inline void z_stdy(FloatRegister r1, const Address &a); // store *(a) = r1 ; double + + // load and store immediates + inline void z_lzer(FloatRegister r1); // r1 = 0 ; single + inline void z_lzdr(FloatRegister r1); // r1 = 0 ; double + + // Move and Convert instructions + inline void z_ler(FloatRegister r1, FloatRegister r2); // move r1 = r2 ; float + inline void z_ldr(FloatRegister r1, FloatRegister r2); // move r1 = r2 ; double + inline void z_ledbr(FloatRegister r1, FloatRegister r2); // conv / round r1 = r2 ; float <- double + inline void z_ldebr(FloatRegister r1, FloatRegister r2); // conv r1 = r2 ; double <- float + + // move between integer and float registers + inline void z_cefbr( FloatRegister r1, Register r2); // r1 = r2; float <-- int32 + inline void z_cdfbr( FloatRegister r1, Register r2); // r1 = r2; double <-- int32 + inline void z_cegbr( FloatRegister r1, Register r2); // r1 = r2; float <-- int64 + inline void z_cdgbr( FloatRegister r1, Register r2); // r1 = r2; double <-- int64 + + // rounding mode for float-2-int conversions + inline void z_cfebr(Register r1, FloatRegister r2, RoundingMode m); // conv r1 = r2 ; int32 <-- float + inline void z_cfdbr(Register r1, FloatRegister r2, RoundingMode m); // conv r1 = r2 ; int32 <-- double + inline void z_cgebr(Register r1, FloatRegister r2, RoundingMode m); // conv r1 = r2 ; int64 <-- float + inline void z_cgdbr(Register r1, FloatRegister r2, RoundingMode m); // conv r1 = r2 ; int64 <-- double + + inline void z_ldgr(FloatRegister r1, Register r2); // fr1 = r2 ; what kind of conversion? -- z10 + inline void z_lgdr(Register r1, FloatRegister r2); // r1 = fr2 ; what kind of conversion? -- z10 + + + // ADD + inline void z_aebr(FloatRegister f1, FloatRegister f2); // f1 = f1 + f2 ; float + inline void z_adbr(FloatRegister f1, FloatRegister f2); // f1 = f1 + f2 ; double + inline void z_aeb( FloatRegister f1, int64_t d2, Register x2, Register b2); // f1 = f1 + *(d2+x2+b2) ; float + inline void z_adb( FloatRegister f1, int64_t d2, Register x2, Register b2); // f1 = f1 + *(d2+x2+b2) ; double + inline void z_aeb( FloatRegister f1, const Address& a); // f1 = f1 + *(a) ; float + inline void z_adb( FloatRegister f1, const Address& a); // f1 = f1 + *(a) ; double + + // SUB + inline void z_sebr(FloatRegister f1, FloatRegister f2); // f1 = f1 - f2 ; float + inline void z_sdbr(FloatRegister f1, FloatRegister f2); // f1 = f1 - f2 ; double + inline void z_seb( FloatRegister f1, int64_t d2, Register x2, Register b2); // f1 = f1 - *(d2+x2+b2) ; float + inline void z_sdb( FloatRegister f1, int64_t d2, Register x2, Register b2); // f1 = f1 - *(d2+x2+b2) ; double + inline void z_seb( FloatRegister f1, const Address& a); // f1 = f1 - *(a) ; float + inline void z_sdb( FloatRegister f1, const Address& a); // f1 = f1 - *(a) ; double + // negate + inline void z_lcebr(FloatRegister r1, FloatRegister r2); // neg r1 = -r2 ; float + inline void z_lcdbr(FloatRegister r1, FloatRegister r2); // neg r1 = -r2 ; double + + // Absolute value, monadic if fr2 == noreg. + inline void z_lpdbr( FloatRegister fr1, FloatRegister fr2 = fnoreg); // fr1 = |fr2| + + + // MUL + inline void z_meebr(FloatRegister f1, FloatRegister f2); // f1 = f1 * f2 ; float + inline void z_mdbr( FloatRegister f1, FloatRegister f2); // f1 = f1 * f2 ; double + inline void z_meeb( FloatRegister f1, int64_t d2, Register x2, Register b2); // f1 = f1 * *(d2+x2+b2) ; float + inline void z_mdb( FloatRegister f1, int64_t d2, Register x2, Register b2); // f1 = f1 * *(d2+x2+b2) ; double + inline void z_meeb( FloatRegister f1, const Address& a); + inline void z_mdb( FloatRegister f1, const Address& a); + + // DIV + inline void z_debr( FloatRegister f1, FloatRegister f2); // f1 = f1 / f2 ; float + inline void z_ddbr( FloatRegister f1, FloatRegister f2); // f1 = f1 / f2 ; double + inline void z_deb( FloatRegister f1, int64_t d2, Register x2, Register b2); // f1 = f1 / *(d2+x2+b2) ; float + inline void z_ddb( FloatRegister f1, int64_t d2, Register x2, Register b2); // f1 = f1 / *(d2+x2+b2) ; double + inline void z_deb( FloatRegister f1, const Address& a); // f1 = f1 / *(a) ; float + inline void z_ddb( FloatRegister f1, const Address& a); // f1 = f1 / *(a) ; double + + // square root + inline void z_sqdbr(FloatRegister fr1, FloatRegister fr2); // fr1 = sqrt(fr2) ; double + inline void z_sqdb( FloatRegister fr1, int64_t d2, Register x2, Register b2); // fr1 = srqt( *(d2+x2+b2) + inline void z_sqdb( FloatRegister fr1, int64_t d2, Register b2); // fr1 = srqt( *(d2+b2) + + // Nop instruction + // =============== + + // branch never (nop) + inline void z_nop(); + + // =============================================================================================== + + // Simplified emitters: + // ==================== + + + // Some memory instructions without index register (just convenience). + inline void z_layz(Register r1, int64_t d2, Register b2 = Z_R0); + inline void z_lay(Register r1, int64_t d2, Register b2); + inline void z_laz(Register r1, int64_t d2, Register b2); + inline void z_la(Register r1, int64_t d2, Register b2); + inline void z_l(Register r1, int64_t d2, Register b2); + inline void z_ly(Register r1, int64_t d2, Register b2); + inline void z_lg(Register r1, int64_t d2, Register b2); + inline void z_st(Register r1, int64_t d2, Register b2); + inline void z_sty(Register r1, int64_t d2, Register b2); + inline void z_stg(Register r1, int64_t d2, Register b2); + inline void z_lgf(Register r1, int64_t d2, Register b2); + inline void z_lgh(Register r1, int64_t d2, Register b2); + inline void z_llgh(Register r1, int64_t d2, Register b2); + inline void z_llgf(Register r1, int64_t d2, Register b2); + inline void z_lgb(Register r1, int64_t d2, Register b2); + inline void z_cl( Register r1, int64_t d2, Register b2); + inline void z_c(Register r1, int64_t d2, Register b2); + inline void z_cg(Register r1, int64_t d2, Register b2); + inline void z_sh(Register r1, int64_t d2, Register b2); + inline void z_shy(Register r1, int64_t d2, Register b2); + inline void z_ste(FloatRegister r1, int64_t d2, Register b2); + inline void z_std(FloatRegister r1, int64_t d2, Register b2); + inline void z_stdy(FloatRegister r1, int64_t d2, Register b2); + inline void z_stey(FloatRegister r1, int64_t d2, Register b2); + inline void z_ld(FloatRegister r1, int64_t d2, Register b2); + inline void z_ldy(FloatRegister r1, int64_t d2, Register b2); + inline void z_le(FloatRegister r1, int64_t d2, Register b2); + inline void z_ley(FloatRegister r1, int64_t d2, Register b2); + + inline void z_agf(Register r1, int64_t d2, Register b2); + + inline void z_exrl(Register r1, Label& L); + inline void z_larl(Register r1, Label& L); + inline void z_bru( Label& L); + inline void z_brul(Label& L); + inline void z_brul(address a); + inline void z_brh( Label& L); + inline void z_brl( Label& L); + inline void z_bre( Label& L); + inline void z_brnh(Label& L); + inline void z_brnl(Label& L); + inline void z_brne(Label& L); + inline void z_brz( Label& L); + inline void z_brnz(Label& L); + inline void z_brnaz(Label& L); + inline void z_braz(Label& L); + inline void z_brnp(Label& L); + + inline void z_btrue( Label& L); + inline void z_bfalse(Label& L); + + inline void z_brno( Label& L); + + + inline void z_basr(Register r1, Register r2); + inline void z_brasl(Register r1, address a); + inline void z_brct(Register r1, address a); + inline void z_brct(Register r1, Label& L); + + inline void z_brxh(Register r1, Register r3, address a); + inline void z_brxh(Register r1, Register r3, Label& L); + + inline void z_brxle(Register r1, Register r3, address a); + inline void z_brxle(Register r1, Register r3, Label& L); + + inline void z_brxhg(Register r1, Register r3, address a); + inline void z_brxhg(Register r1, Register r3, Label& L); + + inline void z_brxlg(Register r1, Register r3, address a); + inline void z_brxlg(Register r1, Register r3, Label& L); + + // Ppopulation count intrinsics. + inline void z_flogr(Register r1, Register r2); // find leftmost one + inline void z_popcnt(Register r1, Register r2); // population count + inline void z_ahhhr(Register r1, Register r2, Register r3); // ADD halfword high high + inline void z_ahhlr(Register r1, Register r2, Register r3); // ADD halfword high low + + inline void z_tam(); + inline void z_stck(int64_t d2, Register b2); + inline void z_stckf(int64_t d2, Register b2); + inline void z_stmg(Register r1, Register r3, int64_t d2, Register b2); + inline void z_lmg(Register r1, Register r3, int64_t d2, Register b2); + + inline void z_cs( Register r1, Register r3, int64_t d2, Register b2); + inline void z_csy(Register r1, Register r3, int64_t d2, Register b2); + inline void z_csg(Register r1, Register r3, int64_t d2, Register b2); + inline void z_cs( Register r1, Register r3, const Address& a); + inline void z_csy(Register r1, Register r3, const Address& a); + inline void z_csg(Register r1, Register r3, const Address& a); + + inline void z_cvd(Register r1, int64_t d2, Register x2, Register b2); + inline void z_cvdg(Register r1, int64_t d2, Register x2, Register b2); + inline void z_cvd(Register r1, int64_t d2, Register b2); + inline void z_cvdg(Register r1, int64_t d2, Register b2); + + // Instruction queries: + // instruction properties and recognize emitted instructions + // =========================================================== + + static int nop_size() { return 2; } + + static int z_brul_size() { return 6; } + + static bool is_z_basr(short x) { + return (BASR_ZOPC == (x & BASR_MASK)); + } + static bool is_z_algr(long x) { + return (ALGR_ZOPC == (x & RRE_MASK)); + } + static bool is_z_lb(long x) { + return (LB_ZOPC == (x & LB_MASK)); + } + static bool is_z_lh(int x) { + return (LH_ZOPC == (x & LH_MASK)); + } + static bool is_z_l(int x) { + return (L_ZOPC == (x & L_MASK)); + } + static bool is_z_lgr(long x) { + return (LGR_ZOPC == (x & RRE_MASK)); + } + static bool is_z_ly(long x) { + return (LY_ZOPC == (x & LY_MASK)); + } + static bool is_z_lg(long x) { + return (LG_ZOPC == (x & LG_MASK)); + } + static bool is_z_llgh(long x) { + return (LLGH_ZOPC == (x & LLGH_MASK)); + } + static bool is_z_llgf(long x) { + return (LLGF_ZOPC == (x & LLGF_MASK)); + } + static bool is_z_le(int x) { + return (LE_ZOPC == (x & LE_MASK)); + } + static bool is_z_ld(int x) { + return (LD_ZOPC == (x & LD_MASK)); + } + static bool is_z_st(int x) { + return (ST_ZOPC == (x & ST_MASK)); + } + static bool is_z_stc(int x) { + return (STC_ZOPC == (x & STC_MASK)); + } + static bool is_z_stg(long x) { + return (STG_ZOPC == (x & STG_MASK)); + } + static bool is_z_sth(int x) { + return (STH_ZOPC == (x & STH_MASK)); + } + static bool is_z_ste(int x) { + return (STE_ZOPC == (x & STE_MASK)); + } + static bool is_z_std(int x) { + return (STD_ZOPC == (x & STD_MASK)); + } + static bool is_z_slag(long x) { + return (SLAG_ZOPC == (x & SLAG_MASK)); + } + static bool is_z_tmy(long x) { + return (TMY_ZOPC == (x & TMY_MASK)); + } + static bool is_z_tm(long x) { + return ((unsigned int)TM_ZOPC == (x & (unsigned int)TM_MASK)); + } + static bool is_z_bcr(long x) { + return (BCR_ZOPC == (x & BCR_MASK)); + } + static bool is_z_nop(long x) { + return is_z_bcr(x) && ((x & 0x00ff) == 0); + } + static bool is_z_nop(address x) { + return is_z_nop(* (short *) x); + } + static bool is_z_br(long x) { + return is_z_bcr(x) && ((x & 0x00f0) == 0x00f0); + } + static bool is_z_brc(long x, int cond) { + return ((unsigned int)BRC_ZOPC == (x & BRC_MASK)) && ((cond<<20) == (x & 0x00f00000U)); + } + // Make use of lightweight sync. + static bool is_z_sync_full(long x) { + return is_z_bcr(x) && (((x & 0x00f0)>>4)==bcondFullSync) && ((x & 0x000f)==0x0000); + } + static bool is_z_sync_light(long x) { + return is_z_bcr(x) && (((x & 0x00f0)>>4)==bcondLightSync) && ((x & 0x000f)==0x0000); + } + static bool is_z_sync(long x) { + return is_z_sync_full(x) || is_z_sync_light(x); + } + + static bool is_z_brasl(long x) { + return (BRASL_ZOPC == (x & BRASL_MASK)); + } + static bool is_z_brasl(address a) { + long x = (*((long *)a))>>16; + return is_z_brasl(x); + } + static bool is_z_larl(long x) { + return (LARL_ZOPC == (x & LARL_MASK)); + } + static bool is_z_lgrl(long x) { + return (LGRL_ZOPC == (x & LGRL_MASK)); + } + static bool is_z_lgrl(address a) { + long x = (*((long *)a))>>16; + return is_z_lgrl(x); + } + + static bool is_z_lghi(unsigned long x) { + return (unsigned int)LGHI_ZOPC == (x & (unsigned int)LGHI_MASK); + } + + static bool is_z_llill(unsigned long x) { + return (unsigned int)LLILL_ZOPC == (x & (unsigned int)LLI_MASK); + } + static bool is_z_llilh(unsigned long x) { + return (unsigned int)LLILH_ZOPC == (x & (unsigned int)LLI_MASK); + } + static bool is_z_llihl(unsigned long x) { + return (unsigned int)LLIHL_ZOPC == (x & (unsigned int)LLI_MASK); + } + static bool is_z_llihh(unsigned long x) { + return (unsigned int)LLIHH_ZOPC == (x & (unsigned int)LLI_MASK); + } + static bool is_z_llilf(unsigned long x) { + return LLILF_ZOPC == (x & LLIF_MASK); + } + static bool is_z_llihf(unsigned long x) { + return LLIHF_ZOPC == (x & LLIF_MASK); + } + + static bool is_z_iill(unsigned long x) { + return (unsigned int)IILL_ZOPC == (x & (unsigned int)II_MASK); + } + static bool is_z_iilh(unsigned long x) { + return (unsigned int)IILH_ZOPC == (x & (unsigned int)II_MASK); + } + static bool is_z_iihl(unsigned long x) { + return (unsigned int)IIHL_ZOPC == (x & (unsigned int)II_MASK); + } + static bool is_z_iihh(unsigned long x) { + return (unsigned int)IIHH_ZOPC == (x & (unsigned int)II_MASK); + } + static bool is_z_iilf(unsigned long x) { + return IILF_ZOPC == (x & IIF_MASK); + } + static bool is_z_iihf(unsigned long x) { + return IIHF_ZOPC == (x & IIF_MASK); + } + + static inline bool is_equal(unsigned long inst, unsigned long idef); + static inline bool is_equal(unsigned long inst, unsigned long idef, unsigned long imask); + static inline bool is_equal(address iloc, unsigned long idef); + static inline bool is_equal(address iloc, unsigned long idef, unsigned long imask); + + static inline bool is_sigtrap_range_check(address pc); + static inline bool is_sigtrap_zero_check(address pc); + + //----------------- + // memory barriers + //----------------- + // machine barrier instructions: + // + // - z_sync Two-way memory barrier, aka fence. + // Only load-after-store-order is not guaranteed in the + // z/Architecture memory model, i.e. only 'fence' is needed. + // + // semantic barrier instructions: + // (as defined in orderAccess.hpp) + // + // - z_release orders Store|Store, empty implementation + // Load|Store + // - z_acquire orders Load|Store, empty implementation + // Load|Load + // - z_fence orders Store|Store, implemented as z_sync. + // Load|Store, + // Load|Load, + // Store|Load + // + // For this implementation to be correct, we need H/W fixes on (very) old H/W: + // For z990, it is Driver-55: MCL232 in the J13484 (i390/ML) Stream. + // For z9, it is Driver-67: MCL065 in the G40963 (i390/ML) Stream. + // These drivers are a prereq. Otherwise, memory synchronization will not work. + + inline void z_sync(); + inline void z_release(); + inline void z_acquire(); + inline void z_fence(); + + // Creation + Assembler(CodeBuffer* code) : AbstractAssembler(code) { } + +}; + +#endif // CPU_S390_VM_ASSEMBLER_S390_HPP
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/cpu/s390/vm/assembler_s390.inline.hpp Wed Jul 05 22:28:55 2017 +0200 @@ -0,0 +1,1015 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016 SAP SE. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef CPU_S390_VM_ASSEMBLER_S390_INLINE_HPP +#define CPU_S390_VM_ASSEMBLER_S390_INLINE_HPP + +#include "asm/assembler.inline.hpp" +#include "asm/codeBuffer.hpp" +#include "code/codeCache.hpp" + +// Convention: Use Z_R0 and Z_R1 instead of Z_scratch_* in all +// assembler_s390.* files. + +// Local implementation of byte emitters to help inlining. +inline void Assembler::emit_16(int x) { + CodeSection* cs = code_section(); + address code_pos = pc(); + *(unsigned short*)code_pos = (unsigned short)x; + cs->set_end( code_pos + sizeof(unsigned short)); +} + +inline void Assembler::emit_32(int x) { + CodeSection* cs = code_section(); + address code_pos = pc(); + *(jint*)code_pos = (jint)x; + cs->set_end( code_pos + sizeof( jint)); +} + +inline void Assembler::emit_48(long x) { + CodeSection* cs = code_section(); + address code_pos = pc(); + *(unsigned short*)code_pos = (unsigned short)(x>>32); + *(jint*)(code_pos+sizeof(unsigned short)) = (jint)x; + cs->set_end( code_pos + sizeof( jint) + sizeof( unsigned short)); +} + +// Support lightweight sync (from z196). Experimental as of now. For explanation see *.hpp file. +inline void Assembler::z_sync() { + if (VM_Version::has_FastSync()) { + z_bcr(bcondLightSync, Z_R0); + } else { + z_bcr(bcondFullSync, Z_R0); + } +} +inline void Assembler::z_release() { } +inline void Assembler::z_acquire() { } +inline void Assembler::z_fence() { z_sync(); } + +inline void Assembler::z_illtrap() { + emit_16(0); +} +inline void Assembler::z_illtrap(int id) { + emit_16(id & 0x00ff); +} +inline void Assembler::z_illtrap_eyecatcher(unsigned short xpattern, unsigned short pattern) { + z_llill(Z_R0, xpattern); + z_iilh(Z_R0, pattern); + z_illtrap((unsigned int)xpattern); +} + +inline void Assembler::z_lhrl(Register r1, int64_t i2) { emit_48( LHRL_ZOPC | regt(r1, 8, 48) | simm32(i2, 16, 48)); } +inline void Assembler::z_lrl(Register r1, int64_t i2) { emit_48( LRL_ZOPC | regt(r1, 8, 48) | simm32(i2, 16, 48)); } +inline void Assembler::z_lghrl(Register r1, int64_t i2) { emit_48( LGHRL_ZOPC | regt(r1, 8, 48) | simm32(i2, 16, 48)); } +inline void Assembler::z_lgfrl(Register r1, int64_t i2) { emit_48( LGFRL_ZOPC | regt(r1, 8, 48) | simm32(i2, 16, 48)); } +inline void Assembler::z_lgrl(Register r1, int64_t i2) { emit_48( LGRL_ZOPC | regt(r1, 8, 48) | simm32(i2, 16, 48)); } +inline void Assembler::z_llhrl(Register r1, int64_t i2) { emit_48( LLHRL_ZOPC | regt(r1, 8, 48) | simm32(i2, 16, 48)); } +inline void Assembler::z_llghrl(Register r1, int64_t i2){ emit_48( LLGHRL_ZOPC | regt(r1, 8, 48) | simm32(i2, 16, 48)); } +inline void Assembler::z_llgfrl(Register r1, int64_t i2){ emit_48( LLGFRL_ZOPC | regt(r1, 8, 48) | simm32(i2, 16, 48)); } + +inline void Assembler::z_sthrl(Register r1, int64_t i2) { emit_48( STHRL_ZOPC | regt(r1, 8, 48) | simm32(i2, 16, 48)); } +inline void Assembler::z_strl(Register r1, int64_t i2) { emit_48( STRL_ZOPC | regt(r1, 8, 48) | simm32(i2, 16, 48)); } +inline void Assembler::z_stgrl(Register r1, int64_t i2) { emit_48( STGRL_ZOPC | regt(r1, 8, 48) | simm32(i2, 16, 48)); } + +inline void Assembler::z_cksm(Register r1, Register r2) { emit_32( CKSM_ZOPC | regt(r1, 24, 32) | regt(r2, 28, 32)); } +inline void Assembler::z_km( Register r1, Register r2) { emit_32( KM_ZOPC | regt(r1, 24, 32) | regt(r2, 28, 32)); } +inline void Assembler::z_kmc( Register r1, Register r2) { emit_32( KMC_ZOPC | regt(r1, 24, 32) | regt(r2, 28, 32)); } +inline void Assembler::z_kimd(Register r1, Register r2) { emit_32( KIMD_ZOPC | regt(r1, 24, 32) | regt(r2, 28, 32)); } +inline void Assembler::z_klmd(Register r1, Register r2) { emit_32( KLMD_ZOPC | regt(r1, 24, 32) | regt(r2, 28, 32)); } +inline void Assembler::z_kmac(Register r1, Register r2) { emit_32( KMAC_ZOPC | regt(r1, 24, 32) | regt(r2, 28, 32)); } + +inline void Assembler::z_exrl(Register r1, int64_t i2) { emit_48( EXRL_ZOPC | regt(r1, 8, 48) | simm32(i2, 16, 48)); } // z10 +inline void Assembler::z_exrl(Register r1, address a2) { emit_48( EXRL_ZOPC | regt(r1, 8, 48) | simm32(RelAddr::pcrel_off32(a2, pc()), 16, 48)); } // z10 + +inline void Assembler::z_ectg(int64_t d1, Register b1, int64_t d2, Register b2, Register r3) { emit_48( ECTG_ZOPC | reg(r3, 8, 48) | uimm12(d1, 20, 48) | reg(b1, 16, 48) | uimm12(d2, 36, 48) | reg(b2, 32, 48)); } +inline void Assembler::z_ecag(Register r1, Register r3, int64_t d2, Register b2) { emit_48( ECAG_ZOPC | reg(r1, 8, 48) | reg(r3, 12, 48) | simm20(d2) | reg(b2, 16, 48)); } + + +//------------------------------ +// Interlocked-Update +//------------------------------ +inline void Assembler::z_laa( Register r1, Register r3, int64_t d2, Register b2) { emit_48( LAA_ZOPC | regt(r1, 8, 48) | reg(r3, 12, 48) | simm20(d2) | regz(b2, 16, 48)); } +inline void Assembler::z_laag( Register r1, Register r3, int64_t d2, Register b2) { emit_48( LAAG_ZOPC | regt(r1, 8, 48) | reg(r3, 12, 48) | simm20(d2) | regz(b2, 16, 48)); } +inline void Assembler::z_laal( Register r1, Register r3, int64_t d2, Register b2) { emit_48( LAAL_ZOPC | regt(r1, 8, 48) | reg(r3, 12, 48) | simm20(d2) | regz(b2, 16, 48)); } +inline void Assembler::z_laalg(Register r1, Register r3, int64_t d2, Register b2) { emit_48( LAALG_ZOPC | regt(r1, 8, 48) | reg(r3, 12, 48) | simm20(d2) | regz(b2, 16, 48)); } +inline void Assembler::z_lan( Register r1, Register r3, int64_t d2, Register b2) { emit_48( LAN_ZOPC | regt(r1, 8, 48) | reg(r3, 12, 48) | simm20(d2) | regz(b2, 16, 48)); } +inline void Assembler::z_lang( Register r1, Register r3, int64_t d2, Register b2) { emit_48( LANG_ZOPC | regt(r1, 8, 48) | reg(r3, 12, 48) | simm20(d2) | regz(b2, 16, 48)); } +inline void Assembler::z_lax( Register r1, Register r3, int64_t d2, Register b2) { emit_48( LAX_ZOPC | regt(r1, 8, 48) | reg(r3, 12, 48) | simm20(d2) | regz(b2, 16, 48)); } +inline void Assembler::z_laxg( Register r1, Register r3, int64_t d2, Register b2) { emit_48( LAXG_ZOPC | regt(r1, 8, 48) | reg(r3, 12, 48) | simm20(d2) | regz(b2, 16, 48)); } +inline void Assembler::z_lao( Register r1, Register r3, int64_t d2, Register b2) { emit_48( LAO_ZOPC | regt(r1, 8, 48) | reg(r3, 12, 48) | simm20(d2) | regz(b2, 16, 48)); } +inline void Assembler::z_laog( Register r1, Register r3, int64_t d2, Register b2) { emit_48( LAOG_ZOPC | regt(r1, 8, 48) | reg(r3, 12, 48) | simm20(d2) | regz(b2, 16, 48)); } + +inline void Assembler::z_laa( Register r1, Register r3, const Address& a) { assert(!a.has_index(), " no index reg allowed"); z_laa( r1, r3, a.disp12(), a.base()); } +inline void Assembler::z_laag( Register r1, Register r3, const Address& a) { assert(!a.has_index(), " no index reg allowed"); z_laag( r1, r3, a.disp12(), a.base()); } +inline void Assembler::z_laal( Register r1, Register r3, const Address& a) { assert(!a.has_index(), " no index reg allowed"); z_laal( r1, r3, a.disp12(), a.base()); } +inline void Assembler::z_laalg(Register r1, Register r3, const Address& a) { assert(!a.has_index(), " no index reg allowed"); z_laalg(r1, r3, a.disp12(), a.base()); } +inline void Assembler::z_lan( Register r1, Register r3, const Address& a) { assert(!a.has_index(), " no index reg allowed"); z_lan( r1, r3, a.disp12(), a.base()); } +inline void Assembler::z_lang( Register r1, Register r3, const Address& a) { assert(!a.has_index(), " no index reg allowed"); z_lang( r1, r3, a.disp12(), a.base()); } +inline void Assembler::z_lax( Register r1, Register r3, const Address& a) { assert(!a.has_index(), " no index reg allowed"); z_lax( r1, r3, a.disp12(), a.base()); } +inline void Assembler::z_laxg( Register r1, Register r3, const Address& a) { assert(!a.has_index(), " no index reg allowed"); z_laxg( r1, r3, a.disp12(), a.base()); } +inline void Assembler::z_lao( Register r1, Register r3, const Address& a) { assert(!a.has_index(), " no index reg allowed"); z_lao( r1, r3, a.disp12(), a.base()); } +inline void Assembler::z_laog( Register r1, Register r3, const Address& a) { assert(!a.has_index(), " no index reg allowed"); z_laog( r1, r3, a.disp12(), a.base()); } + +//-------------------------------- +// Execution Prediction +//-------------------------------- +inline void Assembler::z_pfd( int64_t m1, int64_t d2, Register x2, Register b2) { emit_48( PFD_ZOPC | uimm4(m1, 8, 48) | simm20(d2) | reg(x2, 12, 48) | regz(b2, 16, 48)); } +inline void Assembler::z_pfd( int64_t m1, Address a) { z_pfd(m1, a.disp(), a.indexOrR0(), a.base()); } +inline void Assembler::z_pfdrl(int64_t m1, int64_t i2) { emit_48( PFDRL_ZOPC | uimm4(m1, 8, 48) | simm32(i2, 16, 48)); } +inline void Assembler::z_bpp( int64_t m1, int64_t i2, int64_t d3, Register b3) { emit_48( BPP_ZOPC | uimm4(m1, 8, 48) | uimm12(d3, 20, 48) | reg(b3, 16, 48) | simm16(i2, 32, 48)); } +inline void Assembler::z_bprp( int64_t m1, int64_t i2, int64_t i3) { emit_48( BPRP_ZOPC | uimm4(m1, 8, 48) | simm12(i2, 12, 48) | simm24(i3, 24, 48)); } + +//------------------------------- +// Transaction Control +//------------------------------- +inline void Assembler::z_tbegin( int64_t d1, Register b1, int64_t i2) { emit_48( TBEGIN_ZOPC | uimm12(d1, 20, 48) | reg(b1, 16, 48) | uimm16(i2, 32, 48)); } +inline void Assembler::z_tbeginc(int64_t d1, Register b1, int64_t i2) { emit_48( TBEGINC_ZOPC | uimm12(d1, 20, 48) | reg(b1, 16, 48) | uimm16(i2, 32, 48)); } +inline void Assembler::z_tend() { emit_32( TEND_ZOPC); } +inline void Assembler::z_tabort( int64_t d2, Register b2) { emit_32( TABORT_ZOPC | uimm12(d2, 20, 32) | reg(b2, 16, 32)); } +inline void Assembler::z_etnd(Register r1) { emit_32( ETND_ZOPC | regt(r1, 24, 32)); } +inline void Assembler::z_ppa(Register r1, Register r2, int64_t m3) { emit_32( PPA_ZOPC | reg(r1, 24, 32) | reg(r2, 28, 32) | uimm4(m3, 16, 32)); } + +//--------------------------------- +// Conditional Execution +//--------------------------------- +inline void Assembler::z_locr( Register r1, Register r2, branch_condition cc) { emit_32( LOCR_ZOPC | regt(r1, 24, 32) | reg(r2, 28, 32) | uimm4(cc, 16, 32)); } // z196 +inline void Assembler::z_locgr( Register r1, Register r2, branch_condition cc) { emit_32( LOCGR_ZOPC | regt(r1, 24, 32) | reg(r2, 28, 32) | uimm4(cc, 16, 32)); } // z196 +inline void Assembler::z_loc( Register r1, int64_t d2, Register b2, branch_condition cc) { emit_48( LOC_ZOPC | regt(r1, 8, 48) | simm20(d2) | regz(b2, 16, 48) | uimm4(cc, 12, 48)); } // z196 +inline void Assembler::z_locg( Register r1, int64_t d2, Register b2, branch_condition cc) { emit_48( LOCG_ZOPC | regt(r1, 8, 48) | simm20(d2) | regz(b2, 16, 48) | uimm4(cc, 12, 48)); } // z196 +inline void Assembler::z_loc( Register r1, const Address &a, branch_condition cc) { z_loc(r1, a.disp(), a.base(), cc); } +inline void Assembler::z_locg( Register r1, const Address &a, branch_condition cc) { z_locg(r1, a.disp(), a.base(), cc); } +inline void Assembler::z_stoc( Register r1, int64_t d2, Register b2, branch_condition cc) { emit_48( STOC_ZOPC | regt(r1, 8, 48) | simm20(d2) | regz(b2, 16, 48) | uimm4(cc, 12, 48)); } // z196 +inline void Assembler::z_stocg( Register r1, int64_t d2, Register b2, branch_condition cc) { emit_48( STOCG_ZOPC | regt(r1, 8, 48) | simm20(d2) | regz(b2, 16, 48) | uimm4(cc, 12, 48)); } // z196 + +inline void Assembler::z_srst( Register r1, Register r2) { emit_32( SRST_ZOPC | regt(r1, 24, 32) | reg(r2, 28, 32)); } +inline void Assembler::z_srstu(Register r1, Register r2) { emit_32( SRSTU_ZOPC | regt(r1, 24, 32) | reg(r2, 28, 32)); } + +//--------------------------------- +// Address calculation +//--------------------------------- +inline void Assembler::z_layz(Register r1, int64_t d2, Register x2, Register b2) { emit_48( LAY_ZOPC | regt(r1, 8, 48) | simm20(d2) | reg(x2, 12, 48) | reg(b2, 16, 48)); } +inline void Assembler::z_lay( Register r1, const Address &a) { z_layz(r1, a.disp(), a.indexOrR0(), a.baseOrR0()); } +inline void Assembler::z_lay( Register r1, int64_t d2, Register x2, Register b2) { emit_48( LAY_ZOPC | regt(r1, 8, 48) | simm20(d2) | reg(x2, 12, 48) | regz(b2, 16, 48)); } +inline void Assembler::z_laz( Register r1, int64_t d2, Register x2, Register b2) { emit_32( LA_ZOPC | regt(r1, 8, 32) | uimm12(d2, 20, 32) | reg(x2, 12, 32) | reg(b2, 16, 32)); } +inline void Assembler::z_la( Register r1, const Address &a) { z_laz(r1, a.disp(), a.indexOrR0(), a.baseOrR0()); } +inline void Assembler::z_la( Register r1, int64_t d2, Register x2, Register b2) { emit_32( LA_ZOPC | regt(r1, 8, 32) | uimm12(d2, 20, 32) | reg(x2, 12, 32) | regz(b2, 16, 32));} +inline void Assembler::z_larl(Register r1, int64_t i2) { emit_48( LARL_ZOPC | regt(r1, 8, 48) | simm32(i2, 16, 48)); } +inline void Assembler::z_larl(Register r1, address a) { emit_48( LARL_ZOPC | regt(r1, 8, 48) | simm32(RelAddr::pcrel_off32(a, pc()), 16, 48)); } + +inline void Assembler::z_lr(Register r1, Register r2) { emit_16( LR_ZOPC | regt(r1,8,16) | reg(r2,12,16)); } +inline void Assembler::z_lgr(Register r1, Register r2) { emit_32( LGR_ZOPC | regt(r1, 24, 32) | reg(r2, 28, 32)); } +inline void Assembler::z_lh(Register r1, int64_t d2, Register x2, Register b2) { emit_32( LH_ZOPC | 0 << 16 | regt(r1, 8, 32) | uimm12(d2, 20, 32) | reg(x2, 12, 32) | regz(b2, 16, 32)); } +inline void Assembler::z_lh(Register r1, const Address &a) { z_lh(r1, a.disp(), a.indexOrR0(), a.baseOrR0()); } +inline void Assembler::z_l(Register r1, int64_t d2, Register x2, Register b2) { emit_32( L_ZOPC | 0 << 16 | regt(r1, 8, 32) | uimm12(d2, 20, 32) | reg(x2, 12, 32) | regz(b2, 16, 32)); } +inline void Assembler::z_l(Register r1, const Address &a) { z_l(r1, a.disp(), a.indexOrR0(), a.baseOrR0()); } +inline void Assembler::z_lg(Register r1, int64_t d2, Register x2, Register b2) { emit_48( LG_ZOPC | regt(r1, 8, 48) | simm20(d2) | reg(x2, 12, 48) | regz(b2, 16, 48)); } +inline void Assembler::z_lg(Register r1, const Address &a) { z_lg(r1, a.disp(), a.indexOrR0(), a.baseOrR0()); } + +inline void Assembler::z_lbr( Register r1, Register r2) { emit_32( LBR_ZOPC | regt(r1, 24, 32) | reg( r2, 28, 32)); } +inline void Assembler::z_lhr( Register r1, Register r2) { emit_32( LHR_ZOPC | regt(r1, 24, 32) | reg( r2, 28, 32)); } +inline void Assembler::z_lgbr( Register r1, Register r2) { emit_32( LGBR_ZOPC | regt(r1, 24, 32) | reg(r2, 28, 32)); } +inline void Assembler::z_lghr( Register r1, Register r2) { emit_32( LGHR_ZOPC | regt(r1, 24, 32) | reg(r2, 28, 32)); } +inline void Assembler::z_lgfr( Register r1, Register r2) { emit_32( LGFR_ZOPC | regt(r1, 24, 32) | reg(r2, 28, 32)); } +inline void Assembler::z_llhr( Register r1, Register r2) { emit_32( LLHR_ZOPC | regt(r1, 24, 32) | reg(r2, 28, 32)); } +inline void Assembler::z_llgcr(Register r1, Register r2) { emit_32( LLGCR_ZOPC | regt(r1, 24, 32) | reg(r2, 28, 32)); } +inline void Assembler::z_llghr(Register r1, Register r2) { emit_32( LLGHR_ZOPC | regt(r1, 24, 32) | reg(r2, 28, 32)); } +inline void Assembler::z_llgfr(Register r1, Register r2) { emit_32( LLGFR_ZOPC | regt(r1, 24, 32) | reg(r2, 28, 32)); } + +inline void Assembler::z_sth(Register r1, const Address &a) { z_sth(r1, a.disp(), a.indexOrR0(), a.baseOrR0()); } +inline void Assembler::z_sth(Register r1, int64_t d2, Register x2, Register b2) { emit_32( STH_ZOPC | reg(r1, 8, 32) | uimm12(d2, 20, 32) | reg(x2, 12, 32) | regz(b2, 16, 32)); } +inline void Assembler::z_st( Register r1, const Address& d) { z_st(r1, d.disp(), d.indexOrR0(), d.base()); } +inline void Assembler::z_st( Register r1, int64_t d2, Register x2, Register b2) { emit_32( ST_ZOPC | reg(r1, 8, 32) | uimm12(d2, 20, 32) | reg(x2, 12, 32) | regz(b2, 16, 32)); } +inline void Assembler::z_stg(Register r1, const Address& d) { z_stg(r1, d.disp(), d.indexOrR0(), d.base()); } +inline void Assembler::z_stg(Register r1, int64_t d2, Register x2, Register b2) { emit_48( STG_ZOPC | reg(r1, 8, 48) | simm20(d2) | reg(x2, 12, 48) | regz(b2, 16, 48)); } + +inline void Assembler::z_stcm (Register r1, int64_t m3, int64_t d2, Register b2) { emit_32( STCM_ZOPC | regt(r1, 8, 32) | uimm4(m3, 12, 32) | uimm12(d2, 20, 32) | regz(b2, 16, 32)); } +inline void Assembler::z_stcmy(Register r1, int64_t m3, int64_t d2, Register b2) { emit_48( STCMY_ZOPC | regt(r1, 8, 48) | uimm4(m3, 12, 48) | simm20(d2) | regz(b2, 16, 48)); } +inline void Assembler::z_stcmh(Register r1, int64_t m3, int64_t d2, Register b2) { emit_48( STCMH_ZOPC | regt(r1, 8, 48) | uimm4(m3, 12, 48) | simm20(d2) | regz(b2, 16, 48)); } + +// memory-immediate instructions (8-bit immediate) +inline void Assembler::z_cli( int64_t d1, Register b1, int64_t i2) { emit_32( CLI_ZOPC | uimm12(d1, 20, 32) | regz(b1, 16, 32) | uimm8(i2, 8, 32)); } +inline void Assembler::z_mvi( int64_t d1, Register b1, int64_t i2) { emit_32( MVI_ZOPC | uimm12(d1, 20, 32) | regz(b1, 16, 32) | imm8(i2, 8, 32)); } +inline void Assembler::z_tm( int64_t d1, Register b1, int64_t i2) { emit_32( TM_ZOPC | uimm12(d1, 20, 32) | regz(b1, 16, 32) | imm8(i2, 8, 32)); } +inline void Assembler::z_ni( int64_t d1, Register b1, int64_t i2) { emit_32( NI_ZOPC | uimm12(d1, 20, 32) | regz(b1, 16, 32) | imm8(i2, 8, 32)); } +inline void Assembler::z_oi( int64_t d1, Register b1, int64_t i2) { emit_32( OI_ZOPC | uimm12(d1, 20, 32) | regz(b1, 16, 32) | imm8(i2, 8, 32)); } +inline void Assembler::z_xi( int64_t d1, Register b1, int64_t i2) { emit_32( XI_ZOPC | uimm12(d1, 20, 32) | regz(b1, 16, 32) | imm8(i2, 8, 32)); } +inline void Assembler::z_cliy(int64_t d1, Register b1, int64_t i2) { emit_48( CLIY_ZOPC | simm20(d1) | regz(b1, 16, 48) | uimm8(i2, 8, 48)); } +inline void Assembler::z_mviy(int64_t d1, Register b1, int64_t i2) { emit_48( MVIY_ZOPC | simm20(d1) | regz(b1, 16, 48) | imm8(i2, 8, 48)); } +inline void Assembler::z_tmy( int64_t d1, Register b1, int64_t i2) { emit_48( TMY_ZOPC | simm20(d1) | regz(b1, 16, 48) | imm8(i2, 8, 48)); } +inline void Assembler::z_niy( int64_t d1, Register b1, int64_t i2) { emit_48( NIY_ZOPC | simm20(d1) | regz(b1, 16, 48) | imm8(i2, 8, 48)); } +inline void Assembler::z_oiy( int64_t d1, Register b1, int64_t i2) { emit_48( OIY_ZOPC | simm20(d1) | regz(b1, 16, 48) | imm8(i2, 8, 48)); } +inline void Assembler::z_xiy( int64_t d1, Register b1, int64_t i2) { emit_48( XIY_ZOPC | simm20(d1) | regz(b1, 16, 48) | imm8(i2, 8, 48)); } + +inline void Assembler::z_cli( const Address& a, int64_t imm) { assert(!a.has_index(), " no index reg allowed in CLI"); z_cli( a.disp12(), a.base(), imm); } +inline void Assembler::z_mvi( const Address& a, int64_t imm) { assert(!a.has_index(), " no index reg allowed in CLI"); z_mvi( a.disp12(), a.base(), imm); } +inline void Assembler::z_tm( const Address& a, int64_t imm) { assert(!a.has_index(), " no index reg allowed in CLI"); z_tm( a.disp12(), a.base(), imm); } +inline void Assembler::z_ni( const Address& a, int64_t imm) { assert(!a.has_index(), " no index reg allowed in CLI"); z_ni( a.disp12(), a.base(), imm); } +inline void Assembler::z_oi( const Address& a, int64_t imm) { assert(!a.has_index(), " no index reg allowed in CLI"); z_oi( a.disp12(), a.base(), imm); } +inline void Assembler::z_xi( const Address& a, int64_t imm) { assert(!a.has_index(), " no index reg allowed in CLI"); z_xi( a.disp12(), a.base(), imm); } +inline void Assembler::z_cliy(const Address& a, int64_t imm) { assert(!a.has_index(), " no index reg allowed in CLIY"); z_cliy(a.disp20(), a.base(), imm); } +inline void Assembler::z_mviy(const Address& a, int64_t imm) { assert(!a.has_index(), " no index reg allowed in MVIY"); z_mviy(a.disp20(), a.base(), imm); } +inline void Assembler::z_tmy( const Address& a, int64_t imm) { assert(!a.has_index(), " no index reg allowed in TMY"); z_tmy( a.disp20(), a.base(), imm); } +inline void Assembler::z_niy( const Address& a, int64_t imm) { assert(!a.has_index(), " no index reg allowed in NIY"); z_niy( a.disp20(), a.base(), imm); } +inline void Assembler::z_oiy( const Address& a, int64_t imm) { assert(!a.has_index(), " no index reg allowed in OIY"); z_oiy( a.disp20(), a.base(), imm); } +inline void Assembler::z_xiy( const Address& a, int64_t imm) { assert(!a.has_index(), " no index reg allowed in XIY"); z_xiy( a.disp20(), a.base(), imm); } + + +inline void Assembler::z_mvc(const Address& d, const Address& s, int64_t l) { + assert(!d.has_index() && !s.has_index(), "Address operand can not be encoded."); + z_mvc(d.disp(), l-1, d.base(), s.disp(), s.base()); +} +inline void Assembler::z_mvc(int64_t d1, int64_t l, Register b1, int64_t d2, Register b2) { emit_48( MVC_ZOPC | uimm12(d1, 20, 48) | uimm8(l, 8, 48) | regz(b1, 16, 48) | uimm12(d2, 36, 48) | regz(b2, 32, 48)); } +inline void Assembler::z_mvcle(Register r1, Register r3, int64_t d2, Register b2) { emit_32( MVCLE_ZOPC | reg(r1, 8, 32) | reg(r3, 12, 32) | uimm12(d2, 20, 32) | reg(b2, 16, 32)); } + +inline void Assembler::z_mvhhi( int64_t d1, Register b1, int64_t i2) { emit_48( MVHHI_ZOPC | uimm12( d1, 20, 48) | regz(b1, 16, 48) | simm16(i2, 32, 48)); } +inline void Assembler::z_mvhi ( int64_t d1, Register b1, int64_t i2) { emit_48( MVHI_ZOPC | uimm12( d1, 20, 48) | regz(b1, 16, 48) | simm16(i2, 32, 48)); } +inline void Assembler::z_mvghi( int64_t d1, Register b1, int64_t i2) { emit_48( MVGHI_ZOPC | uimm12( d1, 20, 48) | regz(b1, 16, 48) | simm16(i2, 32, 48)); } +inline void Assembler::z_mvhhi( const Address &d, int64_t i2) { assert(!d.has_index(), " no index reg allowed in MVHHI"); z_mvghi( d.disp(), d.baseOrR0(), i2); } +inline void Assembler::z_mvhi ( const Address &d, int64_t i2) { assert(!d.has_index(), " no index reg allowed in MVHI"); z_mvghi( d.disp(), d.baseOrR0(), i2); } +inline void Assembler::z_mvghi( const Address &d, int64_t i2) { assert(!d.has_index(), " no index reg allowed in MVGHI"); z_mvghi( d.disp(), d.baseOrR0(), i2); } + +inline void Assembler::z_ex(Register r1, int64_t d2, Register x2, Register b2) { emit_32( EX_ZOPC | regz(r1, 8, 32) | uimm12(d2, 20, 32) | reg(x2, 12, 32) | regz(b2, 16, 32)); } + +inline void Assembler::z_ic (Register r1, int64_t d2, Register x2, Register b2) { emit_32( IC_ZOPC | regt(r1, 8, 32) | uimm12(d2, 20, 32) | reg(x2, 12, 32) | regz(b2, 16, 32)); } +inline void Assembler::z_icy (Register r1, int64_t d2, Register x2, Register b2) { emit_48( ICY_ZOPC | regt(r1, 8, 48) | simm20(d2) | reg(x2, 12, 48) | regz(b2, 16, 48)); } +inline void Assembler::z_icm (Register r1, int64_t m3, int64_t d2, Register b2) { emit_32( ICM_ZOPC | regt(r1, 8, 32) | uimm4(m3, 12, 32) | uimm12(d2, 20, 32) | regz(b2, 16, 32)); } +inline void Assembler::z_icmy(Register r1, int64_t m3, int64_t d2, Register b2) { emit_48( ICMY_ZOPC | regt(r1, 8, 48) | uimm4(m3, 12, 48) | simm20(d2) | regz(b2, 16, 48)); } +inline void Assembler::z_icmh(Register r1, int64_t m3, int64_t d2, Register b2) { emit_48( ICMH_ZOPC | regt(r1, 8, 48) | uimm4(m3, 12, 48) | simm20(d2) | regz(b2, 16, 48)); } +inline void Assembler::z_iihh(Register r1, int64_t i2) { emit_32( IIHH_ZOPC | regt(r1, 8, 32) | imm16(i2, 16, 32)); } +inline void Assembler::z_iihl(Register r1, int64_t i2) { emit_32( IIHL_ZOPC | regt(r1, 8, 32) | imm16(i2, 16, 32)); } +inline void Assembler::z_iilh(Register r1, int64_t i2) { emit_32( IILH_ZOPC | regt(r1, 8, 32) | imm16(i2, 16, 32)); } +inline void Assembler::z_iill(Register r1, int64_t i2) { emit_32( IILL_ZOPC | regt(r1, 8, 32) | imm16(i2, 16, 32)); } +inline void Assembler::z_iihf(Register r1, int64_t i2) { emit_48( IIHF_ZOPC | regt(r1, 8, 48) | imm32(i2, 16, 48)); } +inline void Assembler::z_iilf(Register r1, int64_t i2) { emit_48( IILF_ZOPC | regt(r1, 8, 48) | imm32(i2, 16, 48)); } +inline void Assembler::z_lgf(Register r1, const Address& a) { z_lgf(r1, a.disp(), a.indexOrR0(), a.baseOrR0()); } +inline void Assembler::z_lgf(Register r1, int64_t d2, Register x2, Register b2) { emit_48( LGF_ZOPC | regt(r1, 8, 48) | simm20(d2) | reg(x2, 12, 48) | regz(b2, 16, 48)); } +inline void Assembler::z_lhy(Register r1, const Address &a) { z_lhy(r1, a.disp(), a.indexOrR0(), a.baseOrR0()); } +inline void Assembler::z_lhy(Register r1, int64_t d2, Register x2, Register b2) { emit_48( LHY_ZOPC | regt(r1, 8, 48) | simm20(d2) | reg(x2, 12, 48) | regz(b2, 16, 48)); } +inline void Assembler::z_lgh(Register r1, const Address &a) { z_lgh(r1, a.disp(), a.indexOrR0(), a.baseOrR0()); } +inline void Assembler::z_lgh(Register r1, int64_t d2, Register x2, Register b2) { emit_48( LGH_ZOPC | regt(r1, 8, 48) | simm20(d2) | reg(x2, 12, 48) | regz(b2, 16, 48)); } +inline void Assembler::z_lt(Register r1, const Address &a) { z_lt(r1, a.disp(), a.indexOrR0(), a.baseOrR0()); } +inline void Assembler::z_lt (Register r1, int64_t d2, Register x2, Register b2) { emit_48( LT_ZOPC | regt(r1, 8, 48) | simm20(d2) | reg(x2, 12, 48) | regz(b2, 16, 48)); } +inline void Assembler::z_ltg(Register r1, const Address &a) { z_ltg(r1, a.disp(), a.indexOrR0(), a.baseOrR0()); } +inline void Assembler::z_ltg(Register r1, int64_t d2, Register x2, Register b2) { emit_48( LTG_ZOPC | regt(r1, 8, 48) | simm20(d2) | reg(x2, 12, 48) | regz(b2, 16, 48)); } +inline void Assembler::z_ltgf(Register r1, const Address &a) { z_ltgf(r1, a.disp(), a.indexOrR0(), a.baseOrR0()); } +inline void Assembler::z_ltgf(Register r1, int64_t d2, Register x2, Register b2) { emit_48( LTGF_ZOPC| regt(r1, 8, 48) | simm20(d2) | reg(x2, 12, 48) | regz(b2, 16, 48)); } +inline void Assembler::z_lb(Register r1, const Address &a) { z_lb(r1, a.disp(), a.indexOrR0(), a.baseOrR0()); } +inline void Assembler::z_lb (Register r1, int64_t d2, Register x2, Register b2) { emit_48( LB_ZOPC | regt(r1, 8, 48) | simm20(d2) | reg(x2, 12, 48) | regz(b2, 16, 48)); } +inline void Assembler::z_lgb(Register r1, const Address &a) { z_lgb(r1, a.disp(), a.indexOrR0(), a.baseOrR0()); } +inline void Assembler::z_lgb(Register r1, int64_t d2, Register x2, Register b2) { emit_48( LGB_ZOPC | regt(r1, 8, 48) | simm20(d2) | reg(x2, 12, 48) | regz(b2, 16, 48)); } +inline void Assembler::z_ly(Register r1, const Address &a) { z_ly(r1, a.disp(), a.indexOrR0(), a.baseOrR0()); } +inline void Assembler::z_ly(Register r1, int64_t d2, Register x2, Register b2) { emit_48( LY_ZOPC | regt(r1, 8, 48) | simm20(d2) | reg(x2, 12, 48) | regz(b2, 16, 48)); } +inline void Assembler::z_llc(Register r1, const Address& a) { z_llc(r1, a.disp(), a.indexOrR0(), a.baseOrR0()); } +inline void Assembler::z_llc(Register r1, int64_t d2, Register x2, Register b2) { emit_48( LLC_ZOPC | regt(r1, 8, 48) | simm20(d2) | reg(x2, 12, 48) | regz(b2, 16, 48)); } +inline void Assembler::z_llh(Register r1, const Address &a) { z_llh(r1, a.disp(), a.indexOrR0(), a.baseOrR0()); } +inline void Assembler::z_llh(Register r1, int64_t d2, Register x2, Register b2) { emit_48( LLH_ZOPC | regt(r1, 8, 48) | simm20(d2) | reg(x2, 12, 48) | regz(b2, 16, 48)); } +inline void Assembler::z_llgf(Register r1, const Address &a) { z_llgf(r1, a.disp(), a.indexOrR0(), a.baseOrR0()); } +inline void Assembler::z_llgf(Register r1, int64_t d2, Register x2, Register b2) { emit_48( LLGF_ZOPC | regt(r1, 8, 48) | simm20(d2) | reg(x2, 12, 48) | regz(b2, 16, 48)); } +inline void Assembler::z_llgh(Register r1, const Address &a) { z_llgh(r1, a.disp(), a.indexOrR0(), a.baseOrR0()); } +inline void Assembler::z_llgh(Register r1, int64_t d2, Register x2, Register b2) { emit_48( LLGH_ZOPC | regt(r1, 8, 48) | simm20(d2) | reg(x2, 12, 48) | regz(b2, 16, 48)); } +inline void Assembler::z_llgc(Register r1, const Address &a) { z_llgc(r1, a.disp(), a.indexOrR0(), a.baseOrR0()); } +inline void Assembler::z_llgc(Register r1, int64_t d2, Register x2, Register b2) { emit_48( LLGC_ZOPC | regt(r1, 8, 48) | simm20(d2) | reg(x2, 12, 48) | regz(b2, 16, 48)); } +inline void Assembler::z_llgc(Register r1, int64_t d2, Register b2) { z_llgc( r1, d2, Z_R0, b2); } +inline void Assembler::z_lhi(Register r1, int64_t i2) { emit_32( LHI_ZOPC | regt(r1, 8, 32) | simm16(i2, 16, 32)); } +inline void Assembler::z_lghi(Register r1, int64_t i2) { emit_32( LGHI_ZOPC | regt(r1, 8, 32) | simm16(i2, 16, 32)); } +inline void Assembler::z_lgfi(Register r1, int64_t i2) { emit_48( LGFI_ZOPC | regt(r1, 8, 48) | simm32(i2, 16, 48)); } +inline void Assembler::z_llihf(Register r1, int64_t i2) { emit_48( LLIHF_ZOPC | regt(r1, 8, 48) | imm32(i2, 16, 48)); } +inline void Assembler::z_llilf(Register r1, int64_t i2) { emit_48( LLILF_ZOPC | regt(r1, 8, 48) | imm32(i2, 16, 48)); } +inline void Assembler::z_llihh(Register r1, int64_t i2) { emit_32( LLIHH_ZOPC | regt(r1, 8, 32) | imm16(i2, 16, 32)); } +inline void Assembler::z_llihl(Register r1, int64_t i2) { emit_32( LLIHL_ZOPC | regt(r1, 8, 32) | imm16(i2, 16, 32)); } +inline void Assembler::z_llilh(Register r1, int64_t i2) { emit_32( LLILH_ZOPC | regt(r1, 8, 32) | imm16(i2, 16, 32)); } +inline void Assembler::z_llill(Register r1, int64_t i2) { emit_32( LLILL_ZOPC | regt(r1, 8, 32) | imm16(i2, 16, 32)); } + +// allow "monadic" use +inline void Assembler::z_lcr( Register r1, Register r2) { emit_16( LCR_ZOPC | regt( r1, 8, 16) | reg((r2 == noreg) ? r1:r2, 12, 16)); } +inline void Assembler::z_lcgr( Register r1, Register r2) { emit_32( LCGR_ZOPC | regt( r1, 24, 32) | reg((r2 == noreg) ? r1:r2, 28, 32)); } +inline void Assembler::z_lcgfr(Register r1, Register r2) { emit_32( LCGFR_ZOPC | regt( r1, 24, 32) | reg((r2 == noreg) ? r1:r2, 28, 32)); } +inline void Assembler::z_lnr( Register r1, Register r2) { emit_16( LNR_ZOPC | regt( r1, 8, 16) | reg((r2 == noreg) ? r1:r2, 12, 16)); } +inline void Assembler::z_lngr( Register r1, Register r2) { emit_32( LNGR_ZOPC | regt( r1, 24, 32) | reg((r2 == noreg) ? r1:r2, 28, 32)); } +inline void Assembler::z_lngfr(Register r1, Register r2) { emit_32( LNGFR_ZOPC | regt( r1, 24, 32) | reg((r2 == noreg) ? r1:r2, 28, 32)); } + +inline void Assembler::z_lrvr( Register r1, Register r2) { emit_32( LRVR_ZOPC | regt(r1, 24, 32) | reg(r2, 28, 32)); } +inline void Assembler::z_lrvgr(Register r1, Register r2) { emit_32( LRVGR_ZOPC | regt(r1, 24, 32) | reg(r2, 28, 32)); } + +inline void Assembler::z_ltr( Register r1, Register r2) { emit_16( LTR_ZOPC | regt(r1, 8, 16) | reg(r2, 12, 16)); } +inline void Assembler::z_ltgr( Register r1, Register r2) { emit_32( LTGR_ZOPC | regt(r1, 24, 32) | reg(r2, 28, 32)); } +inline void Assembler::z_ltgfr(Register r1, Register r2) { emit_32( LTGFR_ZOPC | regt(r1, 24, 32) | reg(r2, 28, 32)); } +inline void Assembler::z_stc( Register r1, const Address &a) { z_stc(r1, a.disp(), a.indexOrR0(), a.baseOrR0()); } +inline void Assembler::z_stc( Register r1, int64_t d2, Register x2, Register b2) { emit_32( STC_ZOPC | regt(r1, 8, 32) | uimm12(d2, 20, 32) | reg(x2, 12, 32) | regz(b2, 16, 32)); } +inline void Assembler::z_stcy( Register r1, const Address &a) { z_stcy(r1, a.disp(), a.indexOrR0(), a.baseOrR0()); } +inline void Assembler::z_stcy( Register r1, int64_t d2, Register x2, Register b2) { emit_48( STCY_ZOPC | regt(r1, 8, 48) | simm20(d2) | reg(x2, 12, 48) | regz(b2, 16, 48)); } +inline void Assembler::z_sthy( Register r1, const Address &a) { z_sthy(r1, a.disp(), a.indexOrR0(), a.baseOrR0()); } +inline void Assembler::z_sthy( Register r1, int64_t d2, Register x2, Register b2) { emit_48( STHY_ZOPC | regt(r1, 8, 48) | simm20(d2) | reg(x2, 12, 48) | regz(b2, 16, 48)); } +inline void Assembler::z_sty( Register r1, const Address &a) { z_sty(r1, a.disp(), a.indexOrR0(), a.baseOrR0()); } +inline void Assembler::z_sty( Register r1, int64_t d2, Register x2, Register b2) { emit_48( STY_ZOPC | regt(r1, 8, 48) | simm20(d2) | reg(x2, 12, 48) | regz(b2, 16, 48)); } +inline void Assembler::z_stfle(int64_t d2, Register b2) { emit_32(STFLE_ZOPC | uimm12(d2,20,32) | regz(b2,16,32)); } + + +//----------------------------------- +// SHIFT/RORATE OPERATIONS +//----------------------------------- +inline void Assembler::z_sla( Register r1, int64_t d2, Register b2) { emit_32( SLA_ZOPC | regt(r1, 8, 32) | uimm12(d2, 20, 32) | reg(b2, 16, 32)); } +inline void Assembler::z_slag(Register r1, Register r3, int64_t d2, Register b2) { emit_48( SLAG_ZOPC | regt(r1, 8, 48) | simm20(d2) | reg(b2, 16, 48) | reg(r3, 12, 48)); } +inline void Assembler::z_sra( Register r1, int64_t d2, Register b2) { emit_32( SRA_ZOPC | regt(r1, 8, 32) | uimm12(d2, 20, 32) | reg(b2, 16, 32)); } +inline void Assembler::z_srag(Register r1, Register r3, int64_t d2, Register b2) { emit_48( SRAG_ZOPC | regt(r1, 8, 48) | simm20(d2) | reg(b2, 16, 48) | reg(r3, 12, 48)); } +inline void Assembler::z_sll( Register r1, int64_t d2, Register b2) { emit_32( SLL_ZOPC | regt(r1, 8, 32) | uimm12(d2, 20, 32) | reg(b2, 16, 32)); } +inline void Assembler::z_sllg(Register r1, Register r3, int64_t d2, Register b2) { emit_48( SLLG_ZOPC | regt(r1, 8, 48) | simm20(d2) | reg(b2, 16, 48) | reg(r3, 12, 48)); } +inline void Assembler::z_srl( Register r1, int64_t d2, Register b2) { emit_32( SRL_ZOPC | regt(r1, 8, 32) | uimm12(d2, 20, 32) | reg(b2, 16, 32)); } +inline void Assembler::z_srlg(Register r1, Register r3, int64_t d2, Register b2) { emit_48( SRLG_ZOPC | regt(r1, 8, 48) | simm20(d2) | reg(b2, 16, 48) | reg(r3, 12, 48)); } + +// rotate left +inline void Assembler::z_rll( Register r1, Register r3, int64_t d2, Register b2) { emit_48( RLL_ZOPC | regt(r1, 8, 48) | reg(r3, 12, 48) | simm20(d2) | reg(b2, 16, 48)); } +inline void Assembler::z_rllg(Register r1, Register r3, int64_t d2, Register b2) { emit_48( RLLG_ZOPC | regt(r1, 8, 48) | reg(r3, 12, 48) | simm20(d2) | reg(b2, 16, 48)); } + +// Rotate the AND/XOR/OR/insert +inline void Assembler::z_rnsbg( Register r1, Register r2, int64_t spos3, int64_t epos4, int64_t nrot5, bool test_only) { // Rotate then AND selected bits. -- z196 + const int64_t len = 48; + assert(Immediate::is_uimm(spos3, 6), "range start out of range"); // Could just trim to 6bits wide w/o assertion. + assert(Immediate::is_uimm(epos4, 6), "range end out of range"); // Could just trim to 6bits wide w/o assertion. + assert(Immediate::is_uimm(nrot5, 6), "rotate amount out of range"); // Could just leave it as is. leftmost 2 bits are ignored by instruction. + emit_48( RNSBG_ZOPC | regt(r1, 8, len) | regt(r2, 12, len) | uimm6(spos3, 16+2, len) | uimm6(epos4, 24+2, len) | uimm6(nrot5, 32+2, len) | u_field(test_only ? 1 : 0, len-16-1, len-16-1)); +} +inline void Assembler::z_rxsbg( Register r1, Register r2, int64_t spos3, int64_t epos4, int64_t nrot5, bool test_only) { // Rotate then XOR selected bits. -- z196 + const int64_t len = 48; + assert(Immediate::is_uimm(spos3, 6), "range start out of range"); // Could just trim to 6bits wide w/o assertion. + assert(Immediate::is_uimm(epos4, 6), "range end out of range"); // Could just trim to 6bits wide w/o assertion. + assert(Immediate::is_uimm(nrot5, 6), "rotate amount out of range"); // Could just leave it as is. leftmost 2 bits are ignored by instruction. + emit_48( RXSBG_ZOPC | regt(r1, 8, len) | regt(r2, 12, len) | uimm6(spos3, 16+2, len) | uimm6(epos4, 24+2, len) | uimm6(nrot5, 32+2, len) | u_field(test_only ? 1 : 0, len-16-1, len-16-1)); +} +inline void Assembler::z_rosbg( Register r1, Register r2, int64_t spos3, int64_t epos4, int64_t nrot5, bool test_only) { // Rotate then OR selected bits. -- z196 + const int64_t len = 48; + assert(Immediate::is_uimm(spos3, 6), "range start out of range"); // Could just trim to 6bits wide w/o assertion. + assert(Immediate::is_uimm(epos4, 6), "range end out of range"); // Could just trim to 6bits wide w/o assertion. + assert(Immediate::is_uimm(nrot5, 6), "rotate amount out of range"); // Could just leave it as is. leftmost 2 bits are ignored by instruction. + emit_48( ROSBG_ZOPC | regt(r1, 8, len) | regt(r2, 12, len) | uimm6(spos3, 16+2, len) | uimm6(epos4, 24+2, len) | uimm6(nrot5, 32+2, len) | u_field(test_only ? 1 : 0, len-16-1, len-16-1)); +} +inline void Assembler::z_risbg( Register r1, Register r2, int64_t spos3, int64_t epos4, int64_t nrot5, bool zero_rest) { // Rotate then INS selected bits. -- z196 + const int64_t len = 48; + assert(Immediate::is_uimm(spos3, 6), "range start out of range"); // Could just trim to 6bits wide w/o assertion. + assert(Immediate::is_uimm(epos4, 6), "range end out of range"); // Could just trim to 6bits wide w/o assertion. + assert(Immediate::is_uimm(nrot5, 6), "rotate amount out of range"); // Could just leave it as is. leftmost 2 bits are ignored by instruction. + emit_48( RISBG_ZOPC | regt(r1, 8, len) | regt(r2, 12, len) | uimm6(spos3, 16+2, len) | uimm6(epos4, 24+2, len) | uimm6(nrot5, 32+2, len) | u_field(zero_rest ? 1 : 0, len-24-1, len-24-1)); +} + + +//------------------------------ +// LOGICAL OPERATIONS +//------------------------------ +inline void Assembler::z_n( Register r1, int64_t d2, Register x2, Register b2) { emit_32( N_ZOPC | regt(r1, 8, 32) | uimm12(d2, 20, 32) | reg(x2, 12, 32) | regz(b2, 16, 32)); } +inline void Assembler::z_ny( Register r1, int64_t d2, Register x2, Register b2) { emit_48( NY_ZOPC | regt(r1, 8, 48) | simm20(d2) | reg(x2, 12, 48) | regz(b2, 16, 48)); } +inline void Assembler::z_ng( Register r1, int64_t d2, Register x2, Register b2) { emit_48( NG_ZOPC | regt(r1, 8, 48) | simm20(d2) | reg(x2, 12, 48) | regz(b2, 16, 48)); } +inline void Assembler::z_n( Register r1, const Address& a) { z_n( r1, a.disp(), a.indexOrR0(), a.baseOrR0()); } +inline void Assembler::z_ny( Register r1, const Address& a) { z_ny(r1, a.disp(), a.indexOrR0(), a.baseOrR0()); } +inline void Assembler::z_ng( Register r1, const Address& a) { z_ng(r1, a.disp(), a.indexOrR0(), a.baseOrR0()); } + +inline void Assembler::z_nr( Register r1, Register r2) { emit_16( NR_ZOPC | regt(r1, 8, 16) | reg(r2, 12, 16)); } +inline void Assembler::z_ngr( Register r1, Register r2) { emit_32( NGR_ZOPC | regt(r1, 24, 32) | reg(r2, 28, 32)); } +inline void Assembler::z_nrk( Register r1, Register r2, Register r3) { emit_32( NRK_ZOPC | regt(r1, 24, 32) | reg(r2, 28, 32) | reg(r3, 16, 32)); } +inline void Assembler::z_ngrk(Register r1, Register r2, Register r3) { emit_32( NGRK_ZOPC | regt(r1, 24, 32) | reg(r2, 28, 32) | reg(r3, 16, 32)); } + +inline void Assembler::z_nihh(Register r1, int64_t i2) { emit_32( NIHH_ZOPC | regt(r1, 8, 32) | imm16(i2, 16, 32)); } +inline void Assembler::z_nihl(Register r1, int64_t i2) { emit_32( NIHL_ZOPC | regt(r1, 8, 32) | imm16(i2, 16, 32)); } +inline void Assembler::z_nilh(Register r1, int64_t i2) { emit_32( NILH_ZOPC | regt(r1, 8, 32) | imm16(i2, 16, 32)); } +inline void Assembler::z_nill(Register r1, int64_t i2) { emit_32( NILL_ZOPC | regt(r1, 8, 32) | imm16(i2, 16, 32)); } +inline void Assembler::z_nihf(Register r1, int64_t i2) { emit_48( NIHF_ZOPC | regt(r1, 8, 48) | imm32(i2, 16, 48)); } +inline void Assembler::z_nilf(Register r1, int64_t i2) { emit_48( NILF_ZOPC | regt(r1, 8, 48) | imm32(i2, 16, 48)); } + +inline void Assembler::z_o( Register r1, int64_t d2, Register x2, Register b2) { emit_32( O_ZOPC | regt(r1, 8, 32) | uimm12(d2, 20, 32) | reg(x2, 12, 32) | regz(b2, 16, 32)); } +inline void Assembler::z_oy( Register r1, int64_t d2, Register x2, Register b2) { emit_48( OY_ZOPC | regt(r1, 8, 48) | simm20(d2) | reg(x2, 12, 48) | regz(b2, 16, 48)); } +inline void Assembler::z_og( Register r1, int64_t d2, Register x2, Register b2) { emit_48( OG_ZOPC | regt(r1, 8, 48) | simm20(d2) | reg(x2, 12, 48) | regz(b2, 16, 48)); } +inline void Assembler::z_o( Register r1, const Address& a) { z_o( r1, a.disp(), a.indexOrR0(), a.baseOrR0()); } +inline void Assembler::z_oy( Register r1, const Address& a) { z_oy(r1, a.disp(), a.indexOrR0(), a.baseOrR0()); } +inline void Assembler::z_og( Register r1, const Address& a) { z_og(r1, a.disp(), a.indexOrR0(), a.baseOrR0()); } + +inline void Assembler::z_or( Register r1, Register r2) { emit_16( OR_ZOPC | regt(r1, 8, 16) | reg(r2, 12, 16)); } +inline void Assembler::z_ogr( Register r1, Register r2) { emit_32( OGR_ZOPC | regt(r1, 24, 32) | reg(r2, 28, 32)); } +inline void Assembler::z_ork( Register r1, Register r2, Register r3) { emit_32( ORK_ZOPC | regt(r1, 24, 32) | reg(r2, 28, 32) | reg(r3, 16, 32)); } +inline void Assembler::z_ogrk(Register r1, Register r2, Register r3) { emit_32( OGRK_ZOPC | regt(r1, 24, 32) | reg(r2, 28, 32) | reg(r3, 16, 32)); } + +inline void Assembler::z_oihh(Register r1, int64_t i2) { emit_32( OIHH_ZOPC | regt(r1, 8, 32) | imm16(i2, 16, 32)); } +inline void Assembler::z_oihl(Register r1, int64_t i2) { emit_32( OIHL_ZOPC | regt(r1, 8, 32) | imm16(i2, 16, 32)); } +inline void Assembler::z_oilh(Register r1, int64_t i2) { emit_32( OILH_ZOPC | regt(r1, 8, 32) | imm16(i2, 16, 32)); } +inline void Assembler::z_oill(Register r1, int64_t i2) { emit_32( OILL_ZOPC | regt(r1, 8, 32) | imm16(i2, 16, 32)); } +inline void Assembler::z_oihf(Register r1, int64_t i2) { emit_48( OIHF_ZOPC | regt(r1, 8, 48) | imm32(i2, 16, 48)); } +inline void Assembler::z_oilf(Register r1, int64_t i2) { emit_48( OILF_ZOPC | regt(r1, 8, 48) | imm32(i2, 16, 48)); } + +inline void Assembler::z_x( Register r1, int64_t d2, Register x2, Register b2) { emit_32( X_ZOPC | regt(r1, 8, 32) | uimm12(d2, 20, 32) | reg(x2, 12, 32) | regz(b2, 16, 32)); } +inline void Assembler::z_xy( Register r1, int64_t d2, Register x2, Register b2) { emit_48( XY_ZOPC | regt(r1, 8, 48) | simm20(d2) | reg(x2, 12, 48) | regz(b2, 16, 48)); } +inline void Assembler::z_xg( Register r1, int64_t d2, Register x2, Register b2) { emit_48( XG_ZOPC | regt(r1, 8, 48) | simm20(d2) | reg(x2, 12, 48) | regz(b2, 16, 48)); } +inline void Assembler::z_x( Register r1, const Address& a) { z_x( r1, a.disp(), a.indexOrR0(), a.baseOrR0()); } +inline void Assembler::z_xy( Register r1, const Address& a) { z_xy(r1, a.disp(), a.indexOrR0(), a.baseOrR0()); } +inline void Assembler::z_xg( Register r1, const Address& a) { z_xg(r1, a.disp(), a.indexOrR0(), a.baseOrR0()); } + +inline void Assembler::z_xr( Register r1, Register r2) { emit_16( XR_ZOPC | regt(r1, 8, 16) | reg(r2, 12, 16)); } +inline void Assembler::z_xgr( Register r1, Register r2) { emit_32( XGR_ZOPC | regt(r1, 24, 32) | reg(r2, 28, 32)); } +inline void Assembler::z_xrk( Register r1, Register r2, Register r3) { emit_32( XRK_ZOPC | regt(r1, 24, 32) | reg(r2, 28, 32) | reg(r3, 16, 32)); } +inline void Assembler::z_xgrk(Register r1, Register r2, Register r3) { emit_32( XGRK_ZOPC | regt(r1, 24, 32) | reg(r2, 28, 32) | reg(r3, 16, 32)); } + +inline void Assembler::z_xihf(Register r1, int64_t i2) { emit_48( XIHF_ZOPC | regt(r1, 8, 48) | imm32(i2, 16, 48)); } +inline void Assembler::z_xilf(Register r1, int64_t i2) { emit_48( XILF_ZOPC | regt(r1, 8, 48) | imm32(i2, 16, 48)); } + +inline void Assembler::z_nc(int64_t d1, int64_t l, Register b1, int64_t d2, Register b2) { emit_48( NC_ZOPC | uimm12(d1, 20, 48) | uimm8(l, 8, 48) | regz(b1, 16, 48) | uimm12(d2, 36, 48) | regz(b2, 32, 48)); } +inline void Assembler::z_oc(int64_t d1, int64_t l, Register b1, int64_t d2, Register b2) { emit_48( OC_ZOPC | uimm12(d1, 20, 48) | uimm8(l, 8, 48) | regz(b1, 16, 48) | uimm12(d2, 36, 48) | regz(b2, 32, 48)); } +inline void Assembler::z_xc(int64_t d1, int64_t l, Register b1, int64_t d2, Register b2) { emit_48( XC_ZOPC | uimm12(d1, 20, 48) | uimm8(l, 8, 48) | regz(b1, 16, 48) | uimm12(d2, 36, 48) | regz(b2, 32, 48)); } +inline void Assembler::z_nc(Address dst, int64_t len, Address src2) { assert(!dst.has_index() && !src2.has_index(), "Cannot encode index"); z_nc(dst.disp12(), len-1, dst.base(), src2.disp12(), src2.base()); } +inline void Assembler::z_oc(Address dst, int64_t len, Address src2) { assert(!dst.has_index() && !src2.has_index(), "Cannot encode index"); z_oc(dst.disp12(), len-1, dst.base(), src2.disp12(), src2.base()); } +inline void Assembler::z_xc(Address dst, int64_t len, Address src2) { assert(!dst.has_index() && !src2.has_index(), "Cannot encode index"); z_xc(dst.disp12(), len-1, dst.base(), src2.disp12(), src2.base()); } + + +//--------------- +// ADD +//--------------- +inline void Assembler::z_a( Register r1, int64_t d2, Register x2, Register b2) { emit_32( A_ZOPC | regt(r1, 8, 32) | uimm12(d2, 20, 32) | reg(x2, 12, 32) | regz(b2, 16, 32)); } +inline void Assembler::z_ay( Register r1, int64_t d2, Register x2, Register b2) { emit_48( AY_ZOPC | regt(r1, 8, 48) | simm20(d2) | reg(x2, 12, 48) | regz(b2, 16, 48)); } +inline void Assembler::z_al( Register r1, int64_t d2, Register x2, Register b2) { emit_32( AL_ZOPC | regt(r1, 8, 32) | uimm12(d2, 20, 32) | reg(x2, 12, 32) | regz(b2, 16, 32)); } +inline void Assembler::z_aly( Register r1, int64_t d2, Register x2, Register b2) { emit_48( ALY_ZOPC | regt(r1, 8, 48) | simm20(d2) | reg(x2, 12, 48) | regz(b2, 16, 48)); } +inline void Assembler::z_ag( Register r1, int64_t d2, Register x2, Register b2) { emit_48( AG_ZOPC | regt(r1, 8, 48) | simm20(d2) | reg(x2, 12, 48) | regz(b2, 16, 48)); } +inline void Assembler::z_agf( Register r1, int64_t d2, Register x2, Register b2) { emit_48( AGF_ZOPC | regt(r1, 8, 48) | simm20(d2) | reg(x2, 12, 48) | regz(b2, 16, 48)); } +inline void Assembler::z_alg( Register r1, int64_t d2, Register x2, Register b2) { emit_48( ALG_ZOPC | regt(r1, 8, 48) | simm20(d2) | reg(x2, 12, 48) | regz(b2, 16, 48)); } +inline void Assembler::z_algf(Register r1, int64_t d2, Register x2, Register b2) { emit_48( ALGF_ZOPC | regt(r1, 8, 48) | simm20(d2) | reg(x2, 12, 48) | regz(b2, 16, 48)); } +inline void Assembler::z_a( Register r1, const Address& a) { z_a( r1, a.disp(), a.indexOrR0(), a.baseOrR0()); } +inline void Assembler::z_ay( Register r1, const Address& a) { z_ay( r1, a.disp(), a.indexOrR0(), a.baseOrR0()); } +inline void Assembler::z_al( Register r1, const Address& a) { z_al( r1, a.disp(), a.indexOrR0(), a.baseOrR0()); } +inline void Assembler::z_aly( Register r1, const Address& a) { z_aly( r1, a.disp(), a.indexOrR0(), a.baseOrR0()); } +inline void Assembler::z_ag( Register r1, const Address& a) { z_ag( r1, a.disp(), a.indexOrR0(), a.baseOrR0()); } +inline void Assembler::z_agf( Register r1, const Address& a) { z_agf( r1, a.disp(), a.indexOrR0(), a.baseOrR0()); } +inline void Assembler::z_alg( Register r1, const Address& a) { z_alg( r1, a.disp(), a.indexOrR0(), a.baseOrR0()); } +inline void Assembler::z_algf(Register r1, const Address& a) { z_algf(r1, a.disp(), a.indexOrR0(), a.baseOrR0()); } + +inline void Assembler::z_ar( Register r1, Register r2) { emit_16( AR_ZOPC | regt(r1, 8, 16) | reg(r2, 12, 16)); } +inline void Assembler::z_agr( Register r1, Register r2) { emit_32( AGR_ZOPC | regt(r1, 24, 32) | reg(r2, 28, 32)); } +inline void Assembler::z_agfr(Register r1, Register r2) { emit_32( AGFR_ZOPC | regt(r1, 24, 32) | reg(r2, 28, 32)); } +inline void Assembler::z_ark( Register r1, Register r2, Register r3) { emit_32( ARK_ZOPC | regt(r1, 24, 32) | reg(r2, 28, 32) | reg(r3, 16, 32)); } +inline void Assembler::z_agrk(Register r1, Register r2, Register r3) { emit_32( AGRK_ZOPC | regt(r1, 24, 32) | reg(r2, 28, 32) | reg(r3, 16, 32)); } + +inline void Assembler::z_ahi( Register r1, int64_t i2) { emit_32( AHI_ZOPC | regt(r1, 8, 32) | simm16(i2, 16, 32)); } +inline void Assembler::z_afi( Register r1, int64_t i2) { emit_48( AFI_ZOPC | regt(r1, 8, 48) | simm32(i2, 16, 48)); } +inline void Assembler::z_aghi( Register r1, int64_t i2) { emit_32( AGHI_ZOPC | regt(r1, 8, 32) | simm16(i2, 16, 32)); } +inline void Assembler::z_agfi( Register r1, int64_t i2) { emit_48( AGFI_ZOPC | regt(r1, 8, 48) | simm32(i2, 16, 48)); } +inline void Assembler::z_aih( Register r1, int64_t i2) { emit_48( AIH_ZOPC | regt(r1, 8, 48) | simm32(i2, 16, 48)); } +inline void Assembler::z_ahik( Register r1, Register r3, int64_t i2) { emit_48( AHIK_ZOPC | regt(r1, 8, 48) | reg(r3, 12, 48) | simm16(i2, 16, 48)); } +inline void Assembler::z_aghik(Register r1, Register r3, int64_t i2) { emit_48( AGHIK_ZOPC | regt(r1, 8, 48) | reg(r3, 12, 48) | simm16(i2, 16, 48)); } + + +//----------------------- +// ADD LOGICAL +//----------------------- +inline void Assembler::z_alr( Register r1, Register r2) { emit_16( ALR_ZOPC | regt(r1, 8, 16) | reg(r2, 12, 16)); } +inline void Assembler::z_algr( Register r1, Register r2) { emit_32( ALGR_ZOPC | regt(r1, 24, 32) | reg(r2, 28, 32)); } +inline void Assembler::z_algfr(Register r1, Register r2) { emit_32( ALGFR_ZOPC | regt(r1, 24, 32) | reg(r2, 28, 32)); } +inline void Assembler::z_alrk( Register r1, Register r2, Register r3) { emit_32( ALRK_ZOPC | regt(r1, 24, 32) | reg(r2, 28, 32) | reg(r3, 16, 32)); } +inline void Assembler::z_algrk(Register r1, Register r2, Register r3) { emit_32( ALGRK_ZOPC | regt(r1, 24, 32) | reg(r2, 28, 32) | reg(r3, 16, 32)); } +inline void Assembler::z_alcgr(Register r1, Register r2) { emit_32( ALCGR_ZOPC | regt(r1, 24, 32) | reg(r2, 28, 32)); } + +inline void Assembler::z_alfi( Register r1, int64_t i2) { emit_48( ALFI_ZOPC | regt(r1, 8, 48) | uimm32(i2, 16, 48)); } +inline void Assembler::z_algfi(Register r1, int64_t i2) { emit_48( ALGFI_ZOPC | regt(r1, 8, 48) | uimm32(i2, 16, 48)); } + +inline void Assembler::z_alhsik( Register r1, Register r3, int64_t i2) { emit_48( ALHSIK_ZOPC | regt(r1, 8, 48) | reg(r3, 12, 48) | simm16(i2, 16, 48)); } +inline void Assembler::z_alghsik(Register r1, Register r3, int64_t i2) { emit_48( ALGHSIK_ZOPC | regt(r1, 8, 48) | reg(r3, 12, 48) | simm16(i2, 16, 48)); } + +// In-memory arithmetic (add signed, add logical with signed immediate) +inline void Assembler::z_asi( int64_t d1, Register b1, int64_t i2) { emit_48( ASI_ZOPC | simm8(i2, 8, 48) | simm20(d1) | regz(b1, 16, 48)); } +inline void Assembler::z_agsi( int64_t d1, Register b1, int64_t i2) { emit_48( AGSI_ZOPC | simm8(i2, 8, 48) | simm20(d1) | regz(b1, 16, 48)); } +inline void Assembler::z_alsi( int64_t d1, Register b1, int64_t i2) { emit_48( ALSI_ZOPC | simm8(i2, 8, 48) | simm20(d1) | regz(b1, 16, 48)); } +inline void Assembler::z_algsi(int64_t d1, Register b1, int64_t i2) { emit_48( ALGSI_ZOPC | simm8(i2, 8, 48) | simm20(d1) | regz(b1, 16, 48)); } +inline void Assembler::z_asi( const Address& d, int64_t i2) { assert(!d.has_index(), "No index in ASI"); z_asi( d.disp(), d.base(), i2); } +inline void Assembler::z_agsi( const Address& d, int64_t i2) { assert(!d.has_index(), "No index in AGSI"); z_agsi( d.disp(), d.base(), i2); } +inline void Assembler::z_alsi( const Address& d, int64_t i2) { assert(!d.has_index(), "No index in ALSI"); z_alsi( d.disp(), d.base(), i2); } +inline void Assembler::z_algsi(const Address& d, int64_t i2) { assert(!d.has_index(), "No index in ALGSI"); z_algsi(d.disp(), d.base(), i2); } + + +//-------------------- +// SUBTRACT +//-------------------- +inline void Assembler::z_s( Register r1, int64_t d2, Register x2, Register b2) { emit_32( S_ZOPC | regt(r1, 8, 32) | uimm12(d2, 20, 32) | reg(x2, 12, 32) | regz(b2, 16, 32)); } +inline void Assembler::z_sy( Register r1, int64_t d2, Register x2, Register b2) { emit_48( SY_ZOPC | regt(r1, 8, 48) | simm20(d2) | reg(x2, 12, 48) | regz(b2, 16, 48)); } +inline void Assembler::z_sg( Register r1, int64_t d2, Register x2, Register b2) { emit_48( SG_ZOPC | regt(r1, 8, 48) | simm20(d2) | reg(x2, 12, 48) | regz(b2, 16, 48)); } +inline void Assembler::z_sgf( Register r1, int64_t d2, Register x2, Register b2) { emit_48( SGF_ZOPC | regt(r1, 8, 48) | simm20(d2) | reg(x2, 12, 48) | regz(b2, 16, 48)); } +inline void Assembler::z_slg( Register r1, int64_t d2, Register x2, Register b2) { emit_48( SLG_ZOPC | regt(r1, 8, 48) | simm20(d2) | reg(x2, 12, 48) | regz(b2, 16, 48)); } +inline void Assembler::z_slgf(Register r1, int64_t d2, Register x2, Register b2) { emit_48( SLGF_ZOPC | regt(r1, 8, 48) | simm20(d2) | reg(x2, 12, 48) | regz(b2, 16, 48)); } +inline void Assembler::z_s( Register r1, const Address& a) { z_s( r1, a.disp(), a.indexOrR0(), a.baseOrR0()); } +inline void Assembler::z_sy( Register r1, const Address& a) { z_sy( r1, a.disp(), a.indexOrR0(), a.baseOrR0()); } +inline void Assembler::z_sg( Register r1, const Address& a) { z_sg( r1, a.disp(), a.indexOrR0(), a.baseOrR0()); } +inline void Assembler::z_sgf( Register r1, const Address& a) { z_sgf( r1, a.disp(), a.indexOrR0(), a.baseOrR0()); } +inline void Assembler::z_slg( Register r1, const Address& a) { z_slg( r1, a.disp(), a.indexOrR0(), a.baseOrR0()); } +inline void Assembler::z_slgf(Register r1, const Address& a) { z_slgf(r1, a.disp(), a.indexOrR0(), a.baseOrR0()); } + +inline void Assembler::z_sr( Register r1, Register r2) { emit_16( SR_ZOPC | regt(r1, 8, 16) | reg(r2, 12, 16)); } +inline void Assembler::z_sgr( Register r1, Register r2) { emit_32( SGR_ZOPC | regt(r1, 24, 32) | reg(r2, 28, 32)); } +inline void Assembler::z_sgfr(Register r1, Register r2) { emit_32( SGFR_ZOPC | regt(r1, 24, 32) | reg(r2, 28, 32)); } +inline void Assembler::z_srk( Register r1, Register r2, Register r3) { emit_32( SRK_ZOPC | regt(r1, 24, 32) | reg(r2, 28, 32) | reg(r3, 16, 32)); } +inline void Assembler::z_sgrk(Register r1, Register r2, Register r3) { emit_32( SGRK_ZOPC | regt(r1, 24, 32) | reg(r2, 28, 32) | reg(r3, 16, 32)); } + +inline void Assembler::z_sh( Register r1, int64_t d2, Register x2, Register b2) { emit_32( SH_ZOPC | regt(r1, 8, 32) | uimm12(d2, 20, 32) | reg(x2, 12, 32) | regz(b2, 16, 32)); } +inline void Assembler::z_shy( Register r1, int64_t d2, Register x2, Register b2) { emit_48( SHY_ZOPC | regt(r1, 8, 48) | simm20(d2) | reg(x2, 12, 48) | regz(b2, 16, 48)); } +inline void Assembler::z_sh( Register r1, const Address &a) { z_sh( r1, a.disp(), a.indexOrR0(), a.base()); } +inline void Assembler::z_shy( Register r1, const Address &a) { z_shy(r1, a.disp(), a.indexOrR0(), a.base()); } + + +//---------------------------- +// SUBTRACT LOGICAL +//---------------------------- +inline void Assembler::z_slr( Register r1, Register r2) { emit_16( SLR_ZOPC | regt(r1, 8, 16) | reg(r2, 12, 16)); } +inline void Assembler::z_slgr( Register r1, Register r2) { emit_32( SLGR_ZOPC | regt(r1, 24, 32) | reg(r2, 28, 32)); } +inline void Assembler::z_slgfr(Register r1, Register r2) { emit_32( SLGFR_ZOPC | regt(r1, 24, 32) | reg(r2, 28, 32)); } +inline void Assembler::z_slrk( Register r1, Register r2, Register r3) { emit_32(SLRK_ZOPC | regt(r1, 24, 32) | reg(r2, 28, 32) | reg(r3, 16, 32)); } +inline void Assembler::z_slgrk(Register r1, Register r2, Register r3) { emit_32(SLGRK_ZOPC | regt(r1, 24, 32) | reg(r2, 28, 32) | reg(r3, 16, 32)); } +inline void Assembler::z_slfi( Register r1, int64_t i2) { emit_48( SLFI_ZOPC | regt(r1, 8, 48) | uimm32(i2, 16, 48)); } +inline void Assembler::z_slgfi(Register r1, int64_t i2) { emit_48( SLGFI_ZOPC | regt(r1, 8, 48) | uimm32(i2, 16, 48)); } + + +//-------------------- +// MULTIPLY +//-------------------- +inline void Assembler::z_msr( Register r1, Register r2) { emit_32( MSR_ZOPC | regt(r1, 24, 32) | reg(r2, 28, 32)); } +inline void Assembler::z_msgr( Register r1, Register r2) { emit_32( MSGR_ZOPC | regt(r1, 24, 32) | reg(r2, 28, 32)); } +inline void Assembler::z_msgfr(Register r1, Register r2) { emit_32( MSGFR_ZOPC | regt(r1, 24, 32) | reg(r2, 28, 32)); } +inline void Assembler::z_mlr( Register r1, Register r2) { emit_32( MLR_ZOPC | regt(r1, 24, 32) | reg(r2, 28, 32)); } +inline void Assembler::z_mlgr( Register r1, Register r2) { emit_32( MLGR_ZOPC | regt(r1, 24, 32) | reg(r2, 28, 32)); } + +inline void Assembler::z_mhy( Register r1, int64_t d2, Register x2, Register b2) { emit_48( MHY_ZOPC | regt(r1, 8, 48) | simm20(d2) | reg(x2, 12, 48) | regz(b2, 16, 48)); } +inline void Assembler::z_msy( Register r1, int64_t d2, Register x2, Register b2) { emit_48( MSY_ZOPC | regt(r1, 8, 48) | simm20(d2) | reg(x2, 12, 48) | regz(b2, 16, 48)); } +inline void Assembler::z_msg( Register r1, int64_t d2, Register x2, Register b2) { emit_48( MSG_ZOPC | regt(r1, 8, 48) | simm20(d2) | reg(x2, 12, 48) | regz(b2, 16, 48)); } +inline void Assembler::z_msgf(Register r1, int64_t d2, Register x2, Register b2) { emit_48( MSGF_ZOPC | regt(r1, 8, 48) | simm20(d2) | reg(x2, 12, 48) | regz(b2, 16, 48)); } +inline void Assembler::z_ml( Register r1, int64_t d2, Register x2, Register b2) { emit_48( ML_ZOPC | regt(r1, 8, 48) | simm20(d2) | reg(x2, 12, 48) | regz(b2, 16, 48)); } +inline void Assembler::z_mlg( Register r1, int64_t d2, Register x2, Register b2) { emit_48( MLG_ZOPC | regt(r1, 8, 48) | simm20(d2) | reg(x2, 12, 48) | regz(b2, 16, 48)); } + +inline void Assembler::z_mhy( Register r1, const Address& a) { z_mhy( r1, a.disp(), a.indexOrR0(), a.baseOrR0()); } +inline void Assembler::z_msy( Register r1, const Address& a) { z_msy( r1, a.disp(), a.indexOrR0(), a.baseOrR0()); } +inline void Assembler::z_msg( Register r1, const Address& a) { z_msg( r1, a.disp(), a.indexOrR0(), a.baseOrR0()); } +inline void Assembler::z_msgf(Register r1, const Address& a) { z_msgf(r1, a.disp(), a.indexOrR0(), a.baseOrR0()); } +inline void Assembler::z_ml( Register r1, const Address& a) { z_ml( r1, a.disp(), a.indexOrR0(), a.baseOrR0()); } +inline void Assembler::z_mlg( Register r1, const Address& a) { z_mlg( r1, a.disp(), a.indexOrR0(), a.baseOrR0()); } + +inline void Assembler::z_msfi( Register r1, int64_t i2) { emit_48( MSFI_ZOPC | regt(r1, 8, 48) | simm32(i2, 16, 48)); } +inline void Assembler::z_msgfi(Register r1, int64_t i2) { emit_48( MSGFI_ZOPC | regt(r1, 8, 48) | simm32(i2, 16, 48)); } +inline void Assembler::z_mhi( Register r1, int64_t i2) { emit_32( MHI_ZOPC | regt(r1, 8, 32) | simm16(i2, 16, 32)); } +inline void Assembler::z_mghi( Register r1, int64_t i2) { emit_32( MGHI_ZOPC | regt(r1, 8, 32) | simm16(i2, 16, 32)); } + + +//------------------ +// DIVIDE +//------------------ +inline void Assembler::z_dsgr( Register r1, Register r2) { emit_32( DSGR_ZOPC | regt(r1, 24, 32) | reg(r2, 28, 32)); } +inline void Assembler::z_dsgfr(Register r1, Register r2) { emit_32( DSGFR_ZOPC | regt(r1, 24, 32) | reg(r2, 28, 32)); } + + +//------------------- +// COMPARE +//------------------- +inline void Assembler::z_cr( Register r1, Register r2) { emit_16( CR_ZOPC | reg(r1, 8, 16) | reg(r2,12,16)); } +inline void Assembler::z_cgr( Register r1, Register r2) { emit_32( CGR_ZOPC | reg(r1, 24, 32) | reg(r2, 28, 32)); } +inline void Assembler::z_cgfr(Register r1, Register r2) { emit_32( CGFR_ZOPC | reg(r1, 24, 32) | reg(r2, 28, 32)); } +inline void Assembler::z_chi( Register r1, int64_t i2) { emit_32( CHI_ZOPC | reg(r1, 8, 32) | simm16(i2, 16, 32)); } +inline void Assembler::z_cghi(Register r1, int64_t i2) { emit_32( CGHI_ZOPC | reg(r1, 8, 32) | simm16(i2, 16, 32)); } +inline void Assembler::z_cfi( Register r1, int64_t i2) { emit_48( CFI_ZOPC | regt(r1, 8, 48) | uimm32(i2, 16, 48)); } +inline void Assembler::z_cgfi(Register r1, int64_t i2) { emit_48( CGFI_ZOPC | regt(r1, 8, 48) | uimm32(i2, 16, 48)); } +inline void Assembler::z_ch(Register r1, const Address &a) { z_ch(r1, a.disp(), a.indexOrR0(), a.baseOrR0()); } +inline void Assembler::z_ch(Register r1, int64_t d2, Register x2, Register b2) { emit_32( CH_ZOPC | reg(r1, 8, 32) | uimm12(d2, 20, 32) | reg(x2, 12, 32) | regz(b2, 16, 32)); } +inline void Assembler::z_c(Register r1, const Address &a) { z_c(r1, a.disp(), a.indexOrR0(), a.baseOrR0()); } +inline void Assembler::z_c(Register r1, int64_t d2, Register x2, Register b2) { emit_32( C_ZOPC | reg(r1, 8, 32) | uimm12(d2, 20, 32) | reg(x2, 12, 32) | regz(b2, 16, 32)); } +inline void Assembler::z_cy(Register r1, const Address &a) { z_cy(r1, a.disp(), a.indexOrR0(), a.baseOrR0()); } +inline void Assembler::z_cy(Register r1, int64_t d2, Register x2, Register b2) { emit_48( CY_ZOPC | regt(r1, 8, 48) | simm20(d2) | reg(x2, 12, 48) | regz(b2, 16, 48)); } +inline void Assembler::z_cy(Register r1, int64_t d2, Register b2) { z_cy(r1, d2, Z_R0, b2); } +inline void Assembler::z_cg(Register r1, const Address &a) { z_cg(r1, a.disp(), a.indexOrR0(), a.baseOrR0()); } +inline void Assembler::z_cg(Register r1, int64_t d2, Register x2, Register b2) { emit_48( CG_ZOPC | reg(r1, 8, 48) | simm20(d2) | reg(x2, 12, 48) | regz(b2, 16, 48)); } +inline void Assembler::z_clr(Register r1, Register r2) { emit_16( CLR_ZOPC | reg(r1,8,16) | reg(r2,12,16)); } +inline void Assembler::z_clgr(Register r1, Register r2) { emit_32( CLGR_ZOPC | regt(r1, 24, 32) | reg(r2, 28, 32)); } + + +inline void Assembler::z_clfi(Register r1, int64_t i2) { emit_48( CLFI_ZOPC | regt(r1, 8, 48) | uimm32(i2, 16, 48)); } +inline void Assembler::z_clgfi(Register r1, int64_t i2) { emit_48( CLGFI_ZOPC | regt(r1, 8, 48) | uimm32(i2, 16, 48)); } +inline void Assembler::z_cl(Register r1, const Address &a) { z_cl(r1, a.disp(), a.indexOrR0(), a.baseOrR0()); } +inline void Assembler::z_cl(Register r1, int64_t d2, Register x2, Register b2) { emit_32( CL_ZOPC | regt(r1, 8, 32) | uimm12(d2,20,32) | reg(x2, 12, 32) | regz(b2, 16, 32)); } +inline void Assembler::z_cly(Register r1, const Address &a) { z_cly(r1, a.disp(), a.indexOrR0(), a.baseOrR0()); } +inline void Assembler::z_cly(Register r1, int64_t d2, Register x2, Register b2) { emit_48( CLY_ZOPC | regt(r1, 8, 48) | simm20(d2) | reg(x2, 12, 48) | regz(b2, 16, 48)); } +inline void Assembler::z_cly(Register r1, int64_t d2, Register b2) { z_cly(r1, d2, Z_R0, b2); } +inline void Assembler::z_clg(Register r1, const Address &a) { z_clg(r1, a.disp(), a.indexOrR0(), a.baseOrR0()); } +inline void Assembler::z_clg(Register r1, int64_t d2, Register x2, Register b2) { emit_48( CLG_ZOPC | reg(r1, 8, 48) | simm20(d2) | reg(x2, 12, 48) | regz(b2, 16, 48)); } +inline void Assembler::z_clc(int64_t d1, int64_t l, Register b1, int64_t d2, Register b2) { emit_48( CLC_ZOPC | uimm12(d1, 20, 48) | uimm8(l, 8, 48) | regz(b1, 16, 48) | uimm12(d2, 36, 48) | regz(b2, 32, 48)); } +inline void Assembler::z_clcle(Register r1, Register r3, int64_t d2, Register b2) { emit_32( CLCLE_ZOPC | reg(r1, 8, 32) | reg(r3, 12, 32) | uimm12(d2, 20, 32) | reg(b2, 16, 32)); } +inline void Assembler::z_clclu(Register r1, Register r3, int64_t d2, Register b2) { emit_48( CLCLU_ZOPC | reg(r1, 8, 48) | reg(r3, 12, 48) | uimm12(d2, 20, 48) | reg(b2, 16, 48)); } + +inline void Assembler::z_tmll(Register r1, int64_t i2) { emit_32( TMLL_ZOPC | regt(r1, 8, 32) | imm16(i2, 16, 32)); } +inline void Assembler::z_tmlh(Register r1, int64_t i2) { emit_32( TMLH_ZOPC | regt(r1, 8, 32) | imm16(i2, 16, 32)); } +inline void Assembler::z_tmhl(Register r1, int64_t i2) { emit_32( TMHL_ZOPC | regt(r1, 8, 32) | imm16(i2, 16, 32)); } +inline void Assembler::z_tmhh(Register r1, int64_t i2) { emit_32( TMHH_ZOPC | regt(r1, 8, 32) | imm16(i2, 16, 32)); } + +// translate characters +inline void Assembler::z_troo(Register r1, Register r2, int64_t m3) { emit_32( TROO_ZOPC | reg(r1, 24, 32) | reg(r2, 28, 32) | uimm4(m3, 16, 32)); } +inline void Assembler::z_trot(Register r1, Register r2, int64_t m3) { emit_32( TROT_ZOPC | reg(r1, 24, 32) | reg(r2, 28, 32) | uimm4(m3, 16, 32)); } +inline void Assembler::z_trto(Register r1, Register r2, int64_t m3) { emit_32( TRTO_ZOPC | reg(r1, 24, 32) | reg(r2, 28, 32) | uimm4(m3, 16, 32)); } +inline void Assembler::z_trtt(Register r1, Register r2, int64_t m3) { emit_32( TRTT_ZOPC | reg(r1, 24, 32) | reg(r2, 28, 32) | uimm4(m3, 16, 32)); } + +// signed comparison +inline void Assembler::z_crb(Register r1, Register r2, branch_condition m3, int64_t d4, Register b4) { emit_48( CRB_ZOPC | reg(r1, 8, 48) | reg(r2, 12, 48) | uimm12(d4, 20, 48) | reg(b4, 16, 48) | uimm4(m3, 32, 48)); } +inline void Assembler::z_cgrb(Register r1, Register r2, branch_condition m3, int64_t d4, Register b4) { emit_48( CGRB_ZOPC | reg(r1, 8, 48) | reg(r2, 12, 48) | uimm12(d4, 20, 48) | reg(b4, 16, 48) | uimm4(m3, 32, 48)); } +inline void Assembler::z_crj(Register r1, Register r2, branch_condition m3, address a4) { emit_48( CRJ_ZOPC | reg(r1, 8, 48) | reg(r2, 12, 48) | simm16(RelAddr::pcrel_off16(a4, pc()), 16, 48) | uimm4(m3, 32, 48)); } +inline void Assembler::z_cgrj(Register r1, Register r2, branch_condition m3, address a4) { emit_48( CGRJ_ZOPC | reg(r1, 8, 48) | reg(r2, 12, 48) | simm16(RelAddr::pcrel_off16(a4, pc()), 16, 48) | uimm4(m3, 32, 48)); } +inline void Assembler::z_cib(Register r1, int64_t i2, branch_condition m3, int64_t d4, Register b4) { emit_48( CIB_ZOPC | reg(r1, 8, 48) | uimm4(m3, 12, 48) | uimm12(d4, 20, 48) | reg(b4, 16, 48) | simm8(i2, 32, 48)); } +inline void Assembler::z_cgib(Register r1, int64_t i2, branch_condition m3, int64_t d4, Register b4) { emit_48( CGIB_ZOPC | reg(r1, 8, 48) | uimm4(m3, 12, 48) | uimm12(d4, 20, 48) | reg(b4, 16, 48) | simm8(i2, 32, 48)); } +inline void Assembler::z_cij(Register r1, int64_t i2, branch_condition m3, address a4) { emit_48( CIJ_ZOPC | reg(r1, 8, 48) | uimm4(m3, 12, 48) | simm16(RelAddr::pcrel_off16(a4, pc()), 16, 48) | simm8(i2, 32, 48)); } +inline void Assembler::z_cgij(Register r1, int64_t i2, branch_condition m3, address a4) { emit_48( CGIJ_ZOPC | reg(r1, 8, 48) | uimm4(m3, 12, 48) | simm16(RelAddr::pcrel_off16(a4, pc()), 16, 48) | simm8(i2, 32, 48)); } +// unsigned comparison +inline void Assembler::z_clrb(Register r1, Register r2, branch_condition m3, int64_t d4, Register b4) { emit_48( CLRB_ZOPC | reg(r1, 8, 48) | reg(r2, 12, 48) | uimm12(d4, 20, 48) | reg(b4, 16, 48) | uimm4(m3, 32, 48)); } +inline void Assembler::z_clgrb(Register r1, Register r2, branch_condition m3, int64_t d4, Register b4) { emit_48( CLGRB_ZOPC | reg(r1, 8, 48) | reg(r2, 12, 48) | uimm12(d4, 20, 48) | reg(b4, 16, 48) | uimm4(m3, 32, 48)); } +inline void Assembler::z_clrj(Register r1, Register r2, branch_condition m3, address a4) { emit_48( CLRJ_ZOPC | reg(r1, 8, 48) | reg(r2, 12, 48) | simm16(RelAddr::pcrel_off16(a4, pc()), 16, 48) | uimm4(m3, 32, 48)); } +inline void Assembler::z_clgrj(Register r1, Register r2, branch_condition m3, address a4) { emit_48( CLGRJ_ZOPC | reg(r1, 8, 48) | reg(r2, 12, 48) | simm16(RelAddr::pcrel_off16(a4, pc()), 16, 48) | uimm4(m3, 32, 48)); } +inline void Assembler::z_clib(Register r1, int64_t i2, branch_condition m3, int64_t d4, Register b4) { emit_48( CLIB_ZOPC | reg(r1, 8, 48) | uimm4(m3, 12, 48) | uimm12(d4, 20, 48) | reg(b4, 16, 48) | uimm8(i2, 32, 48)); } +inline void Assembler::z_clgib(Register r1, int64_t i2, branch_condition m3, int64_t d4, Register b4) { emit_48( CLGIB_ZOPC | reg(r1, 8, 48) | uimm4(m3, 12, 48) | uimm12(d4, 20, 48) | reg(b4, 16, 48) | uimm8(i2, 32, 48)); } +inline void Assembler::z_clij(Register r1, int64_t i2, branch_condition m3, address a4) { emit_48( CLIJ_ZOPC | reg(r1, 8, 48) | uimm4(m3, 12, 48) | simm16(RelAddr::pcrel_off16(a4, pc()), 16, 48) | uimm8(i2, 32, 48)); } +inline void Assembler::z_clgij(Register r1, int64_t i2, branch_condition m3, address a4) { emit_48( CLGIJ_ZOPC | reg(r1, 8, 48) | uimm4(m3, 12, 48) | simm16(RelAddr::pcrel_off16(a4, pc()), 16, 48) | uimm8(i2, 32, 48)); } + +// Compare and trap instructions (signed). +inline void Assembler::z_crt(Register r1, Register r2, int64_t m3) { emit_32( CRT_ZOPC | reg(r1, 24, 32) | reg(r2, 28, 32) | uimm4(m3, 16, 32)); } +inline void Assembler::z_cgrt(Register r1, Register r2, int64_t m3) { emit_32( CGRT_ZOPC | reg(r1, 24, 32) | reg(r2, 28, 32) | uimm4(m3, 16, 32)); } +inline void Assembler::z_cit(Register r1, int64_t i2, int64_t m3) { emit_48( CIT_ZOPC | reg(r1, 8, 48) | simm16(i2, 16, 48) | uimm4(m3, 32, 48)); } +inline void Assembler::z_cgit(Register r1, int64_t i2, int64_t m3) { emit_48( CGIT_ZOPC | reg(r1, 8, 48) | simm16(i2, 16, 48) | uimm4(m3, 32, 48)); } + +// Compare and trap instructions (unsigned). +inline void Assembler::z_clrt(Register r1, Register r2, int64_t m3) { emit_32( CLRT_ZOPC | reg(r1, 24, 32) | reg(r2, 28, 32) | uimm4(m3, 16, 32)); } +inline void Assembler::z_clgrt(Register r1, Register r2, int64_t m3) { emit_32( CLGRT_ZOPC | reg(r1, 24, 32) | reg(r2, 28, 32) | uimm4(m3, 16, 32)); } +inline void Assembler::z_clfit(Register r1, int64_t i2, int64_t m3) { emit_48( CLFIT_ZOPC | reg(r1, 8, 48) | uimm16(i2, 16, 48) | uimm4(m3, 32, 48)); } +inline void Assembler::z_clgit(Register r1, int64_t i2, int64_t m3) { emit_48( CLGIT_ZOPC | reg(r1, 8, 48) | uimm16(i2, 16, 48) | uimm4(m3, 32, 48)); } + +inline void Assembler::z_bc( branch_condition m1, int64_t d2, Register x2, Register b2) { emit_32( BC_ZOPC | 0 << 16 | uimm4(m1, 8, 32) | uimm12(d2, 20, 32) | reg(x2, 12, 32) | regz(b2, 16, 32)); } +inline void Assembler::z_bcr( branch_condition m1, Register r2) { emit_16( BCR_ZOPC | uimm4(m1,8,16) | reg(r2,12,16)); } +inline void Assembler::z_brc( branch_condition i1, int64_t i2) { emit_32( BRC_ZOPC | uimm4(i1, 8, 32) | simm16(i2, 16, 32)); } +inline void Assembler::z_brc( branch_condition i1, address a) { emit_32( BRC_ZOPC | uimm4(i1, 8, 32) | simm16(RelAddr::pcrel_off16(a, pc()), 16, 32)); } +inline void Assembler::z_brcl(branch_condition i1, address a) { emit_48( BRCL_ZOPC | uimm4(i1, 8, 48)| simm32(RelAddr::pcrel_off32(a, pc()), 16, 48)); } +inline void Assembler::z_bctgr(Register r1, Register r2) { emit_32( BCTGR_ZOPC | reg( r1, 24, 32) | reg( r2, 28, 32)); }; + +inline void Assembler::z_basr(Register r1, Register r2) { emit_16( BASR_ZOPC | regt(r1,8,16) | reg(r2,12,16)); } + +inline void Assembler::z_brasl(Register r1, address a) { emit_48( BRASL_ZOPC | regt(r1, 8, 48) | simm32(RelAddr::pcrel_off32(a, pc()), 16, 48)); } + +inline void Assembler::z_brct(Register r1, address a) { emit_32( BRCT_ZOPC | regt(r1, 8, 32) | simm16(RelAddr::pcrel_off16(a, pc()), 16, 32)); } +inline void Assembler::z_brct(Register r1, Label& L) {z_brct(r1, target(L)); } + +inline void Assembler::z_brxh(Register r1, Register r3, address a) {emit_32( BRXH_ZOPC | reg(r1, 8, 32) | reg(r3, 12, 32) | simm16(RelAddr::pcrel_off16(a, pc()), 16, 32));} +inline void Assembler::z_brxh(Register r1, Register r3, Label& L) {z_brxh(r1, r3, target(L)); } + +inline void Assembler::z_brxle(Register r1, Register r3, address a) {emit_32( BRXLE_ZOPC | reg(r1, 8, 32) | reg(r3, 12, 32) | simm16(RelAddr::pcrel_off16(a, pc()), 16, 32));} +inline void Assembler::z_brxle(Register r1, Register r3, Label& L) {z_brxle(r1, r3, target(L)); } + +inline void Assembler::z_brxhg(Register r1, Register r3, address a) {emit_48( BRXHG_ZOPC | reg(r1, 8, 48) | reg(r3, 12, 48) | simm16(RelAddr::pcrel_off16(a, pc()), 16, 48));} +inline void Assembler::z_brxhg(Register r1, Register r3, Label& L) {z_brxhg(r1, r3, target(L)); } + +inline void Assembler::z_brxlg(Register r1, Register r3, address a) {emit_48( BRXLG_ZOPC | reg(r1, 8, 48) | reg(r3, 12, 48) | simm16(RelAddr::pcrel_off16(a, pc()), 16, 48));} +inline void Assembler::z_brxlg(Register r1, Register r3, Label& L) {z_brxlg(r1, r3, target(L)); } + +inline void Assembler::z_flogr(Register r1, Register r2) { emit_32( FLOGR_ZOPC | reg(r1, 24, 32) | reg(r2, 28, 32)); } +inline void Assembler::z_popcnt(Register r1, Register r2) { emit_32( POPCNT_ZOPC | reg(r1, 24, 32) | reg(r2, 28, 32)); } +inline void Assembler::z_ahhhr(Register r1, Register r2, Register r3) { emit_32( AHHHR_ZOPC | reg(r3, 16, 32) | reg(r1, 24, 32) | reg(r2, 28, 32)); } +inline void Assembler::z_ahhlr(Register r1, Register r2, Register r3) { emit_32( AHHLR_ZOPC | reg(r3, 16, 32) | reg(r1, 24, 32) | reg(r2, 28, 32)); } + +inline void Assembler::z_tam() { emit_16( TAM_ZOPC); } +inline void Assembler::z_stck(int64_t d2, Register b2) { emit_32( STCK_ZOPC | uimm12(d2, 20, 32) | regz(b2, 16, 32)); } +inline void Assembler::z_stckf(int64_t d2, Register b2) { emit_32( STCKF_ZOPC | uimm12(d2, 20, 32) | regz(b2, 16, 32)); } +inline void Assembler::z_stmg(Register r1, Register r3, int64_t d2, Register b2) { emit_48( STMG_ZOPC | simm20(d2) | reg(r1, 8, 48) | reg(r3,12,48)| reg(b2,16,48) ); } +inline void Assembler::z_lmg(Register r1, Register r3, int64_t d2, Register b2) { emit_48( LMG_ZOPC | simm20(d2) | reg(r1, 8, 48) | reg(r3,12,48)| reg(b2,16,48) ); } + +inline void Assembler::z_cs(Register r1, Register r3, int64_t d2, Register b2) { emit_32( CS_ZOPC | regt(r1, 8, 32) | reg(r3, 12, 32) | reg(b2, 16, 32) | uimm12(d2, 20, 32)); } +inline void Assembler::z_csy(Register r1, Register r3, int64_t d2, Register b2) { emit_48( CSY_ZOPC | regt(r1, 8, 48) | reg(r3, 12, 48) | reg(b2, 16, 48) | simm20(d2)); } +inline void Assembler::z_csg(Register r1, Register r3, int64_t d2, Register b2) { emit_48( CSG_ZOPC | regt(r1, 8, 48) | reg(r3, 12, 48) | reg(b2, 16, 48) | simm20(d2)); } +inline void Assembler::z_cs( Register r1, Register r3, const Address& a) { assert(!a.has_index(), "Cannot encode index"); z_cs( r1, r3, a.disp(), a.baseOrR0()); } +inline void Assembler::z_csy(Register r1, Register r3, const Address& a) { assert(!a.has_index(), "Cannot encode index"); z_csy(r1, r3, a.disp(), a.baseOrR0()); } +inline void Assembler::z_csg(Register r1, Register r3, const Address& a) { assert(!a.has_index(), "Cannot encode index"); z_csg(r1, r3, a.disp(), a.baseOrR0()); } + +inline void Assembler::z_cvd(Register r1, int64_t d2, Register x2, Register b2) { emit_32( CVD_ZOPC | regt(r1, 8, 32) | reg(x2, 12, 32) | reg(b2, 16, 32) | uimm12(d2, 20, 32)); } +inline void Assembler::z_cvdg(Register r1, int64_t d2, Register x2, Register b2) { emit_48( CVDG_ZOPC | regt(r1, 8, 48) | reg(x2, 12, 48) | reg(b2, 16, 48) | simm20(d2)); } + + +//------------------------------- +// FLOAT INSTRUCTIONS +//------------------------------- + +//---------------- +// LOAD +//---------------- +inline void Assembler::z_ler( FloatRegister r1, FloatRegister r2) { emit_16( LER_ZOPC | fregt(r1,8,16) | freg(r2,12,16)); } +inline void Assembler::z_ldr( FloatRegister r1, FloatRegister r2) { emit_16( LDR_ZOPC | fregt(r1,8,16) | freg(r2,12,16)); } +inline void Assembler::z_ldebr(FloatRegister r1, FloatRegister r2) { emit_32( LDEBR_ZOPC | fregt(r1, 24, 32) | freg(r2, 28, 32)); } +inline void Assembler::z_ledbr(FloatRegister r1, FloatRegister r2) { emit_32( LEDBR_ZOPC | fregt(r1, 24, 32) | freg(r2, 28, 32)); } +inline void Assembler::z_le( FloatRegister r1, int64_t d2, Register x2, Register b2) { emit_32( LE_ZOPC | fregt(r1, 8, 32) | uimm12(d2, 20, 32) | reg(x2, 12, 32) | regz(b2, 16, 32)); } +inline void Assembler::z_ley(FloatRegister r1, int64_t d2, Register x2, Register b2) { emit_48( LEY_ZOPC | fregt(r1, 8, 48) | simm20(d2) | reg(x2, 12, 48) | regz(b2, 16, 48)); } +inline void Assembler::z_ld( FloatRegister r1, int64_t d2, Register x2, Register b2) { emit_32( LD_ZOPC | fregt(r1, 8, 32) | uimm12(d2, 20, 32) | reg(x2, 12, 32) | regz(b2, 16, 32)); } +inline void Assembler::z_ldy(FloatRegister r1, int64_t d2, Register x2, Register b2) { emit_48( LDY_ZOPC | fregt(r1, 8, 48) | simm20(d2) | reg(x2, 12, 48) | regz(b2, 16, 48)); } +inline void Assembler::z_le( FloatRegister r1, const Address &a) { z_le( r1, a.disp(), a.indexOrR0(), a.baseOrR0()); } +inline void Assembler::z_ley(FloatRegister r1, const Address &a) { z_ley(r1, a.disp(), a.indexOrR0(), a.baseOrR0()); } +inline void Assembler::z_ld( FloatRegister r1, const Address &a) { z_ld( r1, a.disp(), a.indexOrR0(), a.baseOrR0()); } +inline void Assembler::z_ldy(FloatRegister r1, const Address &a) { z_ldy(r1, a.disp(), a.indexOrR0(), a.baseOrR0()); } + +inline void Assembler::z_lzdr(FloatRegister r1) { emit_32( LZDR_ZOPC | fregt(r1, 24, 32)); } +inline void Assembler::z_lzer(FloatRegister f1) { emit_32( LZER_ZOPC | fregt(f1, 24, 32)); } + + +//----------------- +// STORE +//----------------- +inline void Assembler::z_ste( FloatRegister r1, int64_t d2, Register x2, Register b2) { emit_32( STE_ZOPC | freg(r1, 8, 32) | uimm12(d2, 20, 32) | reg(x2, 12, 32) | regz(b2, 16, 32)); } +inline void Assembler::z_stey(FloatRegister r1, int64_t d2, Register x2, Register b2) { emit_48( STEY_ZOPC | freg(r1, 8, 48) | simm20(d2) | reg(x2, 12, 48) | regz(b2, 16, 48)); } +inline void Assembler::z_std( FloatRegister r1, int64_t d2, Register x2, Register b2) { emit_32( STD_ZOPC | freg(r1, 8, 32) | uimm12(d2, 20, 32) | reg(x2, 12, 32) | regz(b2, 16, 32)); } +inline void Assembler::z_stdy(FloatRegister r1, int64_t d2, Register x2, Register b2) { emit_48( STDY_ZOPC | freg(r1, 8, 48) | simm20(d2) | reg(x2, 12, 48) | regz(b2, 16, 48)); } +inline void Assembler::z_ste( FloatRegister r1, const Address &a) { z_ste( r1, a.disp(), a.indexOrR0(), a.baseOrR0()); } +inline void Assembler::z_stey(FloatRegister r1, const Address &a) { z_stey(r1, a.disp(), a.indexOrR0(), a.baseOrR0()); } +inline void Assembler::z_std( FloatRegister r1, const Address &a) { z_std( r1, a.disp(), a.indexOrR0(), a.baseOrR0()); } +inline void Assembler::z_stdy(FloatRegister r1, const Address &a) { z_stdy(r1, a.disp(), a.indexOrR0(), a.baseOrR0()); } + + +//--------------- +// ADD +//--------------- +inline void Assembler::z_aebr( FloatRegister f1, FloatRegister f2) { emit_32( AEBR_ZOPC | fregt( f1, 24, 32) | freg( f2, 28, 32));} +inline void Assembler::z_adbr( FloatRegister f1, FloatRegister f2) { emit_32( ADBR_ZOPC | fregt( f1, 24, 32) | freg( f2, 28, 32));} +inline void Assembler::z_aeb( FloatRegister f1, int64_t d2, Register x2, Register b2 ) { emit_48( AEB_ZOPC | fregt( f1, 8, 48) | uimm12( d2, 20, 48) | reg( x2, 12, 48) | regz( b2, 16, 48));} +inline void Assembler::z_adb( FloatRegister f1, int64_t d2, Register x2, Register b2 ) { emit_48( ADB_ZOPC | fregt( f1, 8, 48) | uimm12( d2, 20, 48) | reg( x2, 12, 48) | regz( b2, 16, 48));} +inline void Assembler::z_aeb( FloatRegister r1, const Address& a) { z_aeb(r1, a.disp(), a.indexOrR0(), a.baseOrR0()); } +inline void Assembler::z_adb( FloatRegister r1, const Address& a) { z_adb(r1, a.disp(), a.indexOrR0(), a.baseOrR0()); } + + +//--------------- +// SUB +//--------------- +inline void Assembler::z_sebr( FloatRegister f1, FloatRegister f2) { emit_32( SEBR_ZOPC | fregt( f1, 24, 32) | freg( f2, 28, 32));} +inline void Assembler::z_sdbr( FloatRegister f1, FloatRegister f2) { emit_32( SDBR_ZOPC | fregt( f1, 24, 32) | freg( f2, 28, 32));} +inline void Assembler::z_seb( FloatRegister f1, int64_t d2, Register x2, Register b2 ) { emit_48( SEB_ZOPC | fregt( f1, 8, 48) | uimm12( d2, 20, 48) | reg( x2, 12, 48) | regz( b2, 16, 48));} +inline void Assembler::z_sdb( FloatRegister f1, int64_t d2, Register x2, Register b2 ) { emit_48( SDB_ZOPC | fregt( f1, 8, 48) | uimm12( d2, 20, 48) | reg( x2, 12, 48) | regz( b2, 16, 48));} +inline void Assembler::z_seb( FloatRegister r1, const Address& a) { z_seb(r1, a.disp(), a.indexOrR0(), a.baseOrR0()); } +inline void Assembler::z_sdb( FloatRegister r1, const Address& a) { z_sdb(r1, a.disp(), a.indexOrR0(), a.baseOrR0()); } + +inline void Assembler::z_lcebr(FloatRegister r1, FloatRegister r2) { emit_32( LCEBR_ZOPC | fregt(r1, 24, 32) | freg(r2, 28, 32)); } +inline void Assembler::z_lcdbr(FloatRegister r1, FloatRegister r2) { emit_32( LCDBR_ZOPC | fregt(r1, 24, 32) | freg(r2, 28, 32)); } + +inline void Assembler::z_lpdbr( FloatRegister fr1, FloatRegister fr2) { emit_32( LPDBR_ZOPC | fregt( fr1, 24,32) | freg((fr2 == fnoreg) ? fr1:fr2, 28, 32)); } + + +//--------------- +// MUL +//--------------- +inline void Assembler::z_meebr(FloatRegister f1, FloatRegister f2) { emit_32( MEEBR_ZOPC | fregt( f1, 24, 32) | freg( f2, 28, 32));} +inline void Assembler::z_mdbr( FloatRegister f1, FloatRegister f2) { emit_32( MDBR_ZOPC | fregt( f1, 24, 32) | freg( f2, 28, 32));} +inline void Assembler::z_meeb( FloatRegister f1, int64_t d2, Register x2, Register b2 ) { emit_48( MEEB_ZOPC | fregt( f1, 8, 48) | uimm12( d2, 20, 48) | reg( x2, 12, 48) | regz( b2, 16, 48));} +inline void Assembler::z_mdb( FloatRegister f1, int64_t d2, Register x2, Register b2 ) { emit_48( MDB_ZOPC | fregt( f1, 8, 48) | uimm12( d2, 20, 48) | reg( x2, 12, 48) | regz( b2, 16, 48));} +inline void Assembler::z_meeb( FloatRegister r1, const Address& a) { z_meeb( r1, a.disp(), a.indexOrR0(), a.baseOrR0()); } +inline void Assembler::z_mdb( FloatRegister r1, const Address& a) { z_mdb( r1, a.disp(), a.indexOrR0(), a.baseOrR0()); } + + +//--------------- +// DIV +//--------------- +inline void Assembler::z_debr( FloatRegister f1, FloatRegister f2) { emit_32( DEBR_ZOPC | fregt( f1, 24, 32) | freg( f2, 28, 32));} +inline void Assembler::z_ddbr( FloatRegister f1, FloatRegister f2) { emit_32( DDBR_ZOPC | fregt( f1, 24, 32) | freg( f2, 28, 32));} +inline void Assembler::z_deb( FloatRegister f1, int64_t d2, Register x2, Register b2 ) { emit_48( DEB_ZOPC | fregt( f1, 8, 48) | uimm12( d2, 20, 48) | reg( x2, 12, 48) | regz( b2, 16, 48));} +inline void Assembler::z_ddb( FloatRegister f1, int64_t d2, Register x2, Register b2 ) { emit_48( DDB_ZOPC | fregt( f1, 8, 48) | uimm12( d2, 20, 48) | reg( x2, 12, 48) | regz( b2, 16, 48));} +inline void Assembler::z_deb( FloatRegister r1, const Address& a) { z_deb( r1, a.disp(), a.indexOrR0(), a.baseOrR0()); } +inline void Assembler::z_ddb( FloatRegister r1, const Address& a) { z_ddb( r1, a.disp(), a.indexOrR0(), a.baseOrR0()); } + + +//--------------- +// square root +//--------------- +inline void Assembler::z_sqdbr(FloatRegister f1, FloatRegister f2) { emit_32(SQDBR_ZOPC | fregt(f1, 24, 32) | freg(f2, 28, 32)); } +inline void Assembler::z_sqdb( FloatRegister fr1, int64_t d2, Register x2, Register b2 ) { emit_48( SQDB_ZOPC | fregt( fr1, 8, 48) | uimm12( d2, 20, 48) | reg( x2, 12, 48) | regz( b2, 16, 48));} +inline void Assembler::z_sqdb( FloatRegister fr1, int64_t d2, Register b2) { z_sqdb( fr1, d2, Z_R0, b2);} + + +//--------------- +// CMP +//--------------- +inline void Assembler::z_cebr(FloatRegister r1, FloatRegister r2) { emit_32( CEBR_ZOPC | fregt(r1, 24, 32) | freg(r2, 28, 32)); } +inline void Assembler::z_ceb(FloatRegister r1, int64_t d2, Register x2, Register b2) { emit_48( CEB_ZOPC | fregt(r1, 8, 48) | uimm12(d2, 20, 48) | reg(x2, 12, 48) | regz(b2, 16, 48)); } +inline void Assembler::z_ceb(FloatRegister r1, const Address &a) { z_ceb(r1, a.disp(), a.indexOrR0(), a.baseOrR0()); } +inline void Assembler::z_cdbr(FloatRegister r1, FloatRegister r2) { emit_32( CDBR_ZOPC | fregt(r1, 24, 32) | freg(r2, 28, 32)); } +inline void Assembler::z_cdb(FloatRegister r1, int64_t d2, Register x2, Register b2) { emit_48( CDB_ZOPC | fregt(r1, 8, 48) | uimm12(d2, 20, 48) | reg(x2, 12, 48) | regz(b2, 16, 48)); } +inline void Assembler::z_cdb(FloatRegister r1, const Address &a) { z_cdb(r1, a.disp(), a.indexOrR0(), a.baseOrR0()); } + + +//------------------------------------ +// FLOAT <-> INT conversion +//------------------------------------ +inline void Assembler::z_ldgr(FloatRegister r1, Register r2) { emit_32( LDGR_ZOPC | fregt(r1, 24, 32) | reg(r2, 28, 32)); } +inline void Assembler::z_lgdr(Register r1, FloatRegister r2) { emit_32( LGDR_ZOPC | regt( r1, 24, 32) | freg(r2, 28, 32)); } + +inline void Assembler::z_cefbr( FloatRegister r1, Register r2) { emit_32( CEFBR_ZOPC | fregt( r1, 24, 32) | reg( r2, 28, 32)); } +inline void Assembler::z_cdfbr( FloatRegister r1, Register r2) { emit_32( CDFBR_ZOPC | fregt( r1, 24, 32) | reg( r2, 28, 32)); } +inline void Assembler::z_cegbr( FloatRegister r1, Register r2) { emit_32( CEGBR_ZOPC | fregt( r1, 24, 32) | reg( r2, 28, 32)); } +inline void Assembler::z_cdgbr( FloatRegister r1, Register r2) { emit_32( CDGBR_ZOPC | fregt( r1, 24, 32) | reg( r2, 28, 32)); } + +inline void Assembler::z_cfebr(Register r1, FloatRegister r2, RoundingMode m) { emit_32( CFEBR_ZOPC | regt(r1, 24, 32) | rounding_mode(m, 16, 32) | freg(r2, 28, 32)); } +inline void Assembler::z_cfdbr(Register r1, FloatRegister r2, RoundingMode m) { emit_32( CFDBR_ZOPC | regt(r1, 24, 32) | rounding_mode(m, 16, 32) | freg(r2, 28, 32)); } +inline void Assembler::z_cgebr(Register r1, FloatRegister r2, RoundingMode m) { emit_32( CGEBR_ZOPC | regt(r1, 24, 32) | rounding_mode(m, 16, 32) | freg(r2, 28, 32)); } +inline void Assembler::z_cgdbr(Register r1, FloatRegister r2, RoundingMode m) { emit_32( CGDBR_ZOPC | regt(r1, 24, 32) | rounding_mode(m, 16, 32) | freg(r2, 28, 32)); } + + + inline void Assembler::z_layz(Register r1, int64_t d2, Register b2) { z_layz(r1, d2, Z_R0, b2); } + inline void Assembler::z_lay(Register r1, int64_t d2, Register b2) { z_lay( r1, d2, Z_R0, b2); } + inline void Assembler::z_laz(Register r1, int64_t d2, Register b2) { z_laz( r1, d2, Z_R0, b2); } + inline void Assembler::z_la(Register r1, int64_t d2, Register b2) { z_la( r1, d2, Z_R0, b2); } + inline void Assembler::z_l(Register r1, int64_t d2, Register b2) { z_l( r1, d2, Z_R0, b2); } + inline void Assembler::z_ly(Register r1, int64_t d2, Register b2) { z_ly( r1, d2, Z_R0, b2); } + inline void Assembler::z_lg(Register r1, int64_t d2, Register b2) { z_lg( r1, d2, Z_R0, b2); } + inline void Assembler::z_st(Register r1, int64_t d2, Register b2) { z_st( r1, d2, Z_R0, b2); } + inline void Assembler::z_sty(Register r1, int64_t d2, Register b2) { z_sty( r1, d2, Z_R0, b2); } + inline void Assembler::z_stg(Register r1, int64_t d2, Register b2) { z_stg( r1, d2, Z_R0, b2); } + inline void Assembler::z_lgf(Register r1, int64_t d2, Register b2) { z_lgf( r1, d2, Z_R0, b2); } + inline void Assembler::z_lgh(Register r1, int64_t d2, Register b2) { z_lgh( r1, d2, Z_R0, b2); } + inline void Assembler::z_llgh(Register r1, int64_t d2, Register b2) { z_llgh(r1, d2, Z_R0, b2); } + inline void Assembler::z_llgf(Register r1, int64_t d2, Register b2) { z_llgf(r1, d2, Z_R0, b2); } + inline void Assembler::z_lgb(Register r1, int64_t d2, Register b2) { z_lgb( r1, d2, Z_R0, b2); } + inline void Assembler::z_cl( Register r1, int64_t d2, Register b2) { z_cl( r1, d2, Z_R0, b2); } + inline void Assembler::z_c(Register r1, int64_t d2, Register b2) { z_c( r1, d2, Z_R0, b2); } + inline void Assembler::z_cg(Register r1, int64_t d2, Register b2) { z_cg( r1, d2, Z_R0, b2); } + inline void Assembler::z_sh(Register r1, int64_t d2, Register b2) { z_sh( r1, d2, Z_R0, b2); } + inline void Assembler::z_shy(Register r1, int64_t d2, Register b2) { z_shy( r1, d2, Z_R0, b2); } + inline void Assembler::z_ste(FloatRegister r1, int64_t d2, Register b2) { z_ste( r1, d2, Z_R0, b2); } + inline void Assembler::z_std(FloatRegister r1, int64_t d2, Register b2) { z_std( r1, d2, Z_R0, b2); } + inline void Assembler::z_stdy(FloatRegister r1, int64_t d2, Register b2) { z_stdy(r1, d2, Z_R0, b2); } + inline void Assembler::z_stey(FloatRegister r1, int64_t d2, Register b2) { z_stey(r1, d2, Z_R0, b2); } + inline void Assembler::z_ld(FloatRegister r1, int64_t d2, Register b2) { z_ld( r1, d2, Z_R0, b2); } + inline void Assembler::z_ldy(FloatRegister r1, int64_t d2, Register b2) { z_ldy( r1, d2, Z_R0, b2); } + inline void Assembler::z_le(FloatRegister r1, int64_t d2, Register b2) { z_le( r1, d2, Z_R0, b2); } + inline void Assembler::z_ley(FloatRegister r1, int64_t d2, Register b2) { z_ley( r1, d2, Z_R0, b2); } + inline void Assembler::z_agf(Register r1, int64_t d2, Register b2) { z_agf( r1, d2, Z_R0, b2); } + inline void Assembler::z_cvd(Register r1, int64_t d2, Register b2) { z_cvd( r1, d2, Z_R0, b2); } + inline void Assembler::z_cvdg(Register r1, int64_t d2, Register b2) { z_cvdg(r1, d2, Z_R0, b2); } + +// signed comparison +inline void Assembler::z_crj(Register r1, Register r2, branch_condition m3, Label& L) { z_crj( r1, r2, m3, target(L)); } +inline void Assembler::z_cgrj(Register r1, Register r2, branch_condition m3, Label& L) { z_cgrj( r1, r2, m3, target(L)); } +inline void Assembler::z_cij(Register r1, int64_t i2, branch_condition m3, Label& L) { z_cij( r1, i2, m3, target(L)); } +inline void Assembler::z_cgij(Register r1, int64_t i2, branch_condition m3, Label& L) { z_cgij( r1, i2, m3, target(L)); } +// unsigned comparison +inline void Assembler::z_clrj(Register r1, Register r2, branch_condition m3, Label& L) { z_clrj( r1, r2, m3, target(L)); } +inline void Assembler::z_clgrj(Register r1, Register r2, branch_condition m3, Label& L) { z_clgrj(r1, r2, m3, target(L)); } +inline void Assembler::z_clij(Register r1, int64_t i2, branch_condition m3, Label& L) { z_clij( r1, i2, m3, target(L)); } +inline void Assembler::z_clgij(Register r1, int64_t i2, branch_condition m3, Label& L) { z_clgij(r1, i2, m3, target(L)); } + +// branch never (nop), branch always +inline void Assembler::z_nop() { z_bcr(bcondNop, Z_R0); } +inline void Assembler::z_br(Register r2) { assert(r2 != Z_R0, "nop if target is Z_R0, use z_nop() instead"); z_bcr(bcondAlways, r2 ); } + +inline void Assembler::z_exrl(Register r1, Label& L) { z_exrl(r1, target(L)); } // z10 +inline void Assembler::z_larl(Register r1, Label& L) { z_larl(r1, target(L)); } +inline void Assembler::z_bru( Label& L) { z_brc(bcondAlways,target(L)); } +inline void Assembler::z_brul( Label& L) { z_brcl(bcondAlways,target(L)); } +inline void Assembler::z_brul( address a) { z_brcl(bcondAlways,a); } +inline void Assembler::z_brh( Label& L) { z_brc(bcondHigh,target(L)); } +inline void Assembler::z_brl( Label& L) { z_brc(bcondLow,target(L)); } +inline void Assembler::z_bre( Label& L) { z_brc(bcondEqual,target(L)); } +inline void Assembler::z_brnh( Label& L) { z_brc(bcondNotHigh,target(L)); } +inline void Assembler::z_brnl( Label& L) { z_brc(bcondNotLow,target(L)); } +inline void Assembler::z_brne( Label& L) { z_brc(bcondNotEqual,target(L)); } +inline void Assembler::z_brz( Label& L) { z_brc(bcondZero,target(L)); } +inline void Assembler::z_brnz( Label& L) { z_brc(bcondNotZero,target(L)); } +inline void Assembler::z_braz( Label& L) { z_brc(bcondAllZero,target(L)); } +inline void Assembler::z_brnaz( Label& L) { z_brc(bcondNotAllZero,target(L)); } +inline void Assembler::z_brnp( Label& L) { z_brc( bcondNotPositive, target( L)); } +inline void Assembler::z_btrue( Label& L) { z_brc(bcondAllOne,target(L)); } +inline void Assembler::z_bfalse(Label& L) { z_brc(bcondAllZero,target(L)); } +inline void Assembler::z_brno( Label& L) { z_brc(bcondNotOrdered,target(L)); } +inline void Assembler::z_brc( branch_condition m, Label& L) { z_brc(m, target(L)); } +inline void Assembler::z_brcl(branch_condition m, Label& L) { z_brcl(m, target(L)); } + + +// Instruction must start at passed address. +// Extra check for illtraps with ID. +inline int Assembler::instr_len(unsigned char *instr) { + switch ((*instr) >> 6) { + case 0: return 2; + case 1: // fallthru + case 2: return 4; + case 3: return 6; + default: + // Control can't reach here. + // The switch expression examines just the leftmost two bytes + // of the main opcode. So the range of values is just [0..3]. + // Having a default clause makes the compiler happy. + ShouldNotReachHere(); + return 0; + } +} + +// Move instr at pc right-justified into passed long int. +// Return instr len in bytes as function result. +// Note: 2-byte instr don't really need to be accessed unsigned +// because leftmost two bits are always zero. We use +// unsigned here for reasons of uniformity. +inline unsigned int Assembler::get_instruction(unsigned char *pc, unsigned long *instr) { + unsigned int len = instr_len(pc); + switch (len) { + case 2: + *instr = *(unsigned short*) pc; break; + case 4: + *instr = *(unsigned int*) pc; break; + case 6: + // Must compose this case. Can't read 8 bytes and then cut off + // the rightmost two bytes. Could potentially access + // unallocated storage. + *instr = ((unsigned long)(*(unsigned int*) pc)) << 16 | + ((unsigned long)*(unsigned short*) (pc + 4)); break; + default: + // Control can't reach here. + // The length as returned from instr_len() can only be 2, 4, or 6 bytes. + // Having a default clause makes the compiler happy. + ShouldNotReachHere(); + break; + } + return len; +} + +// Check if instruction is the expected one. +// Instruction is passed right-justified in inst. +inline bool Assembler::is_equal(unsigned long inst, unsigned long idef) { + unsigned long imask; + + if ((idef >> 32) != 0) { // 6byte instructions + switch (idef >> 40) { // select mask by main opcode + case 0xc0: + case 0xc2: + case 0xc4: + case 0xc6: imask = RIL_MASK; break; + case 0xec: + if ((idef & 0x00ffL) < 0x0080L) { + imask = RIE_MASK; + break; + } + // Fallthru for other sub opcodes. + default: +#ifdef ASSERT + tty->print_cr("inst = %16.16lx, idef = %16.16lx, imask unspecified\n", inst, idef); + tty->flush(); +#endif + ShouldNotReachHere(); + return 0; + } + } else { // 4-byte instructions + switch (idef >> 24) { // Select mask by main opcode. + case 0x84: + case 0x85: imask = RSI_MASK; break; + case 0xa5: + case 0xa7: imask = RI_MASK; break; + case 0xb9: imask = RRE_MASK; break; // RRE_MASK or RRF_MASK. Opcode fields are at same bit positions. + default: { +#ifdef ASSERT + tty->print_cr("inst = %16.16lx, idef = %16.16lx, imask unspecified\n", inst, idef); + tty->flush(); +#endif + ShouldNotReachHere(); + return 0; + } + } + } + return (inst & imask) == idef; +} + +inline bool Assembler::is_equal(unsigned long inst, unsigned long idef, unsigned long imask) { + assert(imask != 0, "valid instruction mask required"); + return (inst & imask) == idef; +} + +// Check if instruction is the expected one. +// Instruction is passed left-justified at inst. +inline bool Assembler::is_equal(address iloc, unsigned long idef) { + unsigned long inst; + get_instruction(iloc, &inst); + return is_equal(inst, idef); +} + +inline bool Assembler::is_equal(address iloc, unsigned long idef, unsigned long imask) { + unsigned long inst; + get_instruction(iloc, &inst); + return is_equal(inst, idef, imask); +} + +inline bool Assembler::is_sigtrap_range_check(address pc) { + return (is_equal(pc, CLFIT_ZOPC, RIE_MASK) || is_equal(pc, CLRT_ZOPC, RRE_MASK)); +} + +inline bool Assembler::is_sigtrap_zero_check(address pc) { + return (is_equal(pc, CGIT_ZOPC, RIE_MASK) || is_equal(pc, CIT_ZOPC, RIE_MASK)); +} + +#endif // CPU_S390_VM_ASSEMBLER_S390_INLINE_HPP
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/cpu/s390/vm/bytes_s390.hpp Wed Jul 05 22:28:55 2017 +0200 @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016 SAP SE. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef CPU_S390_VM_BYTES_S390_HPP +#define CPU_S390_VM_BYTES_S390_HPP + +#include "memory/allocation.hpp" + +class Bytes: AllStatic { + public: + // Efficient reading and writing of unaligned unsigned data in + // platform-specific byte ordering. + + // Use regular load and store for unaligned access. + // + // On z/Architecture, unaligned loads and stores are supported when using the + // "traditional" load (LH, L/LY, LG) and store (STH, ST/STY, STG) instructions. + // The penalty for unaligned access is just very few (two or three) ticks, + // plus another few (two or three) ticks if the access crosses a cache line boundary. + // + // In short, it makes no sense on z/Architecture to piecemeal get or put unaligned data. + + // Returns true if the byte ordering used by Java is different from + // the native byte ordering of the underlying machine. + // z/Arch is big endian, thus, a swap between native and Java ordering + // is always a no-op. + static inline bool is_Java_byte_ordering_different() { return false; } + + // Only swap on little endian machines => suffix `_le'. + static inline u2 swap_u2_le(u2 x) { return x; } + static inline u4 swap_u4_le(u4 x) { return x; } + static inline u8 swap_u8_le(u8 x) { return x; } + + static inline u2 get_native_u2(address p) { return *(u2*)p; } + static inline u4 get_native_u4(address p) { return *(u4*)p; } + static inline u8 get_native_u8(address p) { return *(u8*)p; } + + static inline void put_native_u2(address p, u2 x) { *(u2*)p = x; } + static inline void put_native_u4(address p, u4 x) { *(u4*)p = x; } + static inline void put_native_u8(address p, u8 x) { *(u8*)p = x; } + +#include "bytes_linux_s390.inline.hpp" + + // Efficient reading and writing of unaligned unsigned data in Java byte ordering (i.e. big-endian ordering) + static inline u2 get_Java_u2(address p) { return get_native_u2(p); } + static inline u4 get_Java_u4(address p) { return get_native_u4(p); } + static inline u8 get_Java_u8(address p) { return get_native_u8(p); } + + static inline void put_Java_u2(address p, u2 x) { put_native_u2(p, x); } + static inline void put_Java_u4(address p, u4 x) { put_native_u4(p, x); } + static inline void put_Java_u8(address p, u8 x) { put_native_u8(p, x); } +}; + +#endif // CPU_S390_VM_BYTES_S390_HPP
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/cpu/s390/vm/c1_CodeStubs_s390.cpp Wed Jul 05 22:28:55 2017 +0200 @@ -0,0 +1,497 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016 SAP SE. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#include "precompiled.hpp" +#include "c1/c1_CodeStubs.hpp" +#include "c1/c1_FrameMap.hpp" +#include "c1/c1_LIRAssembler.hpp" +#include "c1/c1_MacroAssembler.hpp" +#include "c1/c1_Runtime1.hpp" +#include "nativeInst_s390.hpp" +#include "runtime/sharedRuntime.hpp" +#include "utilities/macros.hpp" +#include "vmreg_s390.inline.hpp" +#if INCLUDE_ALL_GCS +#include "gc/g1/g1SATBCardTableModRefBS.hpp" +#endif // INCLUDE_ALL_GCS + +#define __ ce->masm()-> +#undef CHECK_BAILOUT +#define CHECK_BAILOUT() { if (ce->compilation()->bailed_out()) return; } + +RangeCheckStub::RangeCheckStub(CodeEmitInfo* info, LIR_Opr index, + bool throw_index_out_of_bounds_exception) : + _throw_index_out_of_bounds_exception(throw_index_out_of_bounds_exception), + _index(index) { + assert(info != NULL, "must have info"); + _info = new CodeEmitInfo(info); +} + +void RangeCheckStub::emit_code(LIR_Assembler* ce) { + __ bind(_entry); + if (_info->deoptimize_on_exception()) { + address a = Runtime1::entry_for (Runtime1::predicate_failed_trap_id); + ce->emit_call_c(a); + CHECK_BAILOUT(); + ce->add_call_info_here(_info); + ce->verify_oop_map(_info); + debug_only(__ should_not_reach_here()); + return; + } + + // Pass the array index in Z_R1_scratch which is not managed by linear scan. + if (_index->is_cpu_register()) { + __ lgr_if_needed(Z_R1_scratch, _index->as_register()); + } else { + __ load_const_optimized(Z_R1_scratch, _index->as_jint()); + } + + Runtime1::StubID stub_id; + if (_throw_index_out_of_bounds_exception) { + stub_id = Runtime1::throw_index_exception_id; + } else { + stub_id = Runtime1::throw_range_check_failed_id; + } + ce->emit_call_c(Runtime1::entry_for (stub_id)); + CHECK_BAILOUT(); + ce->add_call_info_here(_info); + ce->verify_oop_map(_info); + debug_only(__ should_not_reach_here()); +} + +PredicateFailedStub::PredicateFailedStub(CodeEmitInfo* info) { + _info = new CodeEmitInfo(info); +} + +void PredicateFailedStub::emit_code(LIR_Assembler* ce) { + __ bind(_entry); + address a = Runtime1::entry_for (Runtime1::predicate_failed_trap_id); + ce->emit_call_c(a); + CHECK_BAILOUT(); + ce->add_call_info_here(_info); + ce->verify_oop_map(_info); + debug_only(__ should_not_reach_here()); +} + +void CounterOverflowStub::emit_code(LIR_Assembler* ce) { + __ bind(_entry); + Metadata *m = _method->as_constant_ptr()->as_metadata(); + bool success = __ set_metadata_constant(m, Z_R1_scratch); + if (!success) { + ce->compilation()->bailout("const section overflow"); + return; + } + ce->store_parameter(/*_method->as_register()*/ Z_R1_scratch, 1); + ce->store_parameter(_bci, 0); + ce->emit_call_c(Runtime1::entry_for (Runtime1::counter_overflow_id)); + CHECK_BAILOUT(); + ce->add_call_info_here(_info); + ce->verify_oop_map(_info); + __ branch_optimized(Assembler::bcondAlways, _continuation); +} + +void DivByZeroStub::emit_code(LIR_Assembler* ce) { + if (_offset != -1) { + ce->compilation()->implicit_exception_table()->append(_offset, __ offset()); + } + __ bind(_entry); + ce->emit_call_c(Runtime1::entry_for (Runtime1::throw_div0_exception_id)); + CHECK_BAILOUT(); + ce->add_call_info_here(_info); + debug_only(__ should_not_reach_here()); +} + +void ImplicitNullCheckStub::emit_code(LIR_Assembler* ce) { + address a; + if (_info->deoptimize_on_exception()) { + // Deoptimize, do not throw the exception, because it is probably wrong to do it here. + a = Runtime1::entry_for (Runtime1::predicate_failed_trap_id); + } else { + a = Runtime1::entry_for (Runtime1::throw_null_pointer_exception_id); + } + + ce->compilation()->implicit_exception_table()->append(_offset, __ offset()); + __ bind(_entry); + ce->emit_call_c(a); + CHECK_BAILOUT(); + ce->add_call_info_here(_info); + ce->verify_oop_map(_info); + debug_only(__ should_not_reach_here()); +} + +// Note: pass object in Z_R1_scratch +void SimpleExceptionStub::emit_code(LIR_Assembler* ce) { + __ bind(_entry); + if (_obj->is_valid()) { + __ z_lgr(Z_R1_scratch, _obj->as_register()); // _obj contains the optional argument to the stub + } + address a = Runtime1::entry_for (_stub); + ce->emit_call_c(a); + CHECK_BAILOUT(); + ce->add_call_info_here(_info); + debug_only(__ should_not_reach_here()); +} + +NewInstanceStub::NewInstanceStub(LIR_Opr klass_reg, LIR_Opr result, ciInstanceKlass* klass, CodeEmitInfo* info, Runtime1::StubID stub_id) { + _result = result; + _klass = klass; + _klass_reg = klass_reg; + _info = new CodeEmitInfo(info); + assert(stub_id == Runtime1::new_instance_id || + stub_id == Runtime1::fast_new_instance_id || + stub_id == Runtime1::fast_new_instance_init_check_id, + "need new_instance id"); + _stub_id = stub_id; +} + +void NewInstanceStub::emit_code(LIR_Assembler* ce) { + __ bind(_entry); + assert(_klass_reg->as_register() == Z_R11, "call target expects klass in Z_R11"); + address a = Runtime1::entry_for (_stub_id); + ce->emit_call_c(a); + CHECK_BAILOUT(); + ce->add_call_info_here(_info); + ce->verify_oop_map(_info); + assert(_result->as_register() == Z_R2, "callee returns result in Z_R2,"); + __ z_brul(_continuation); +} + +NewTypeArrayStub::NewTypeArrayStub(LIR_Opr klass_reg, LIR_Opr length, LIR_Opr result, CodeEmitInfo* info) { + _klass_reg = klass_reg; + _length = length; + _result = result; + _info = new CodeEmitInfo(info); +} + +void NewTypeArrayStub::emit_code(LIR_Assembler* ce) { + __ bind(_entry); + assert(_klass_reg->as_register() == Z_R11, "call target expects klass in Z_R11"); + __ lgr_if_needed(Z_R13, _length->as_register()); + address a = Runtime1::entry_for (Runtime1::new_type_array_id); + ce->emit_call_c(a); + CHECK_BAILOUT(); + ce->add_call_info_here(_info); + ce->verify_oop_map(_info); + assert(_result->as_register() == Z_R2, "callee returns result in Z_R2,"); + __ z_brul(_continuation); +} + +NewObjectArrayStub::NewObjectArrayStub(LIR_Opr klass_reg, LIR_Opr length, LIR_Opr result, CodeEmitInfo* info) { + _klass_reg = klass_reg; + _length = length; + _result = result; + _info = new CodeEmitInfo(info); +} + +void NewObjectArrayStub::emit_code(LIR_Assembler* ce) { + __ bind(_entry); + assert(_klass_reg->as_register() == Z_R11, "call target expects klass in Z_R11"); + __ lgr_if_needed(Z_R13, _length->as_register()); + address a = Runtime1::entry_for (Runtime1::new_object_array_id); + ce->emit_call_c(a); + CHECK_BAILOUT(); + ce->add_call_info_here(_info); + ce->verify_oop_map(_info); + assert(_result->as_register() == Z_R2, "callee returns result in Z_R2,"); + __ z_brul(_continuation); +} + +MonitorEnterStub::MonitorEnterStub(LIR_Opr obj_reg, LIR_Opr lock_reg, CodeEmitInfo* info) + : MonitorAccessStub(obj_reg, lock_reg) { + _info = new CodeEmitInfo(info); +} + +void MonitorEnterStub::emit_code(LIR_Assembler* ce) { + __ bind(_entry); + Runtime1::StubID enter_id; + if (ce->compilation()->has_fpu_code()) { + enter_id = Runtime1::monitorenter_id; + } else { + enter_id = Runtime1::monitorenter_nofpu_id; + } + __ lgr_if_needed(Z_R1_scratch, _obj_reg->as_register()); + __ lgr_if_needed(Z_R13, _lock_reg->as_register()); // See LIRGenerator::syncTempOpr(). + ce->emit_call_c(Runtime1::entry_for (enter_id)); + CHECK_BAILOUT(); + ce->add_call_info_here(_info); + ce->verify_oop_map(_info); + __ branch_optimized(Assembler::bcondAlways, _continuation); +} + +void MonitorExitStub::emit_code(LIR_Assembler* ce) { + __ bind(_entry); + // Move address of the BasicObjectLock into Z_R1_scratch. + if (_compute_lock) { + // Lock_reg was destroyed by fast unlocking attempt => recompute it. + ce->monitor_address(_monitor_ix, FrameMap::as_opr(Z_R1_scratch)); + } else { + __ lgr_if_needed(Z_R1_scratch, _lock_reg->as_register()); + } + // Note: non-blocking leaf routine => no call info needed. + Runtime1::StubID exit_id; + if (ce->compilation()->has_fpu_code()) { + exit_id = Runtime1::monitorexit_id; + } else { + exit_id = Runtime1::monitorexit_nofpu_id; + } + ce->emit_call_c(Runtime1::entry_for (exit_id)); + CHECK_BAILOUT(); + __ branch_optimized(Assembler::bcondAlways, _continuation); +} + +// Implementation of patching: +// - Copy the code at given offset to an inlined buffer (first the bytes, then the number of bytes). +// - Replace original code with a call to the stub. +// At Runtime: +// - call to stub, jump to runtime. +// - in runtime: Preserve all registers (especially objects, i.e., source and destination object). +// - in runtime: After initializing class, restore original code, reexecute instruction. + +int PatchingStub::_patch_info_offset = - (12 /* load const */ + 2 /*BASR*/); + +void PatchingStub::align_patch_site(MacroAssembler* masm) { +#ifndef PRODUCT + const char* bc; + switch (_id) { + case access_field_id: bc = "patch site (access_field)"; break; + case load_klass_id: bc = "patch site (load_klass)"; break; + case load_mirror_id: bc = "patch site (load_mirror)"; break; + case load_appendix_id: bc = "patch site (load_appendix)"; break; + default: bc = "patch site (unknown patch id)"; break; + } + masm->block_comment(bc); +#endif + + masm->align(round_to(NativeGeneralJump::instruction_size, wordSize)); +} + +void PatchingStub::emit_code(LIR_Assembler* ce) { + // Copy original code here. + assert(NativeGeneralJump::instruction_size <= _bytes_to_copy && _bytes_to_copy <= 0xFF, + "not enough room for call"); + + NearLabel call_patch; + + int being_initialized_entry = __ offset(); + + if (_id == load_klass_id) { + // Produce a copy of the load klass instruction for use by the case being initialized. +#ifdef ASSERT + address start = __ pc(); +#endif + AddressLiteral addrlit((intptr_t)0, metadata_Relocation::spec(_index)); + __ load_const(_obj, addrlit); + +#ifdef ASSERT + for (int i = 0; i < _bytes_to_copy; i++) { + address ptr = (address)(_pc_start + i); + int a_byte = (*ptr) & 0xFF; + assert(a_byte == *start++, "should be the same code"); + } +#endif + } else if (_id == load_mirror_id || _id == load_appendix_id) { + // Produce a copy of the load mirror instruction for use by the case being initialized. +#ifdef ASSERT + address start = __ pc(); +#endif + AddressLiteral addrlit((intptr_t)0, oop_Relocation::spec(_index)); + __ load_const(_obj, addrlit); + +#ifdef ASSERT + for (int i = 0; i < _bytes_to_copy; i++) { + address ptr = (address)(_pc_start + i); + int a_byte = (*ptr) & 0xFF; + assert(a_byte == *start++, "should be the same code"); + } +#endif + } else { + // Make a copy the code which is going to be patched. + for (int i = 0; i < _bytes_to_copy; i++) { + address ptr = (address)(_pc_start + i); + int a_byte = (*ptr) & 0xFF; + __ emit_int8 (a_byte); + } + } + + address end_of_patch = __ pc(); + int bytes_to_skip = 0; + if (_id == load_mirror_id) { + int offset = __ offset(); + if (CommentedAssembly) { + __ block_comment(" being_initialized check"); + } + + // Static field accesses have special semantics while the class + // initializer is being run, so we emit a test which can be used to + // check that this code is being executed by the initializing + // thread. + assert(_obj != noreg, "must be a valid register"); + assert(_index >= 0, "must have oop index"); + __ z_lg(Z_R1_scratch, java_lang_Class::klass_offset_in_bytes(), _obj); + __ z_cg(Z_thread, Address(Z_R1_scratch, InstanceKlass::init_thread_offset())); + __ branch_optimized(Assembler::bcondNotEqual, call_patch); + + // Load_klass patches may execute the patched code before it's + // copied back into place so we need to jump back into the main + // code of the nmethod to continue execution. + __ branch_optimized(Assembler::bcondAlways, _patch_site_continuation); + + // Make sure this extra code gets skipped. + bytes_to_skip += __ offset() - offset; + } + + // Now emit the patch record telling the runtime how to find the + // pieces of the patch. We only need 3 bytes but to help the disassembler + // we make the data look like a the following add instruction: + // A R1, D2(X2, B2) + // which requires 4 bytes. + int sizeof_patch_record = 4; + bytes_to_skip += sizeof_patch_record; + + // Emit the offsets needed to find the code to patch. + int being_initialized_entry_offset = __ offset() - being_initialized_entry + sizeof_patch_record; + + // Emit the patch record: opcode of the add followed by 3 bytes patch record data. + __ emit_int8((int8_t)(A_ZOPC>>24)); + __ emit_int8(being_initialized_entry_offset); + __ emit_int8(bytes_to_skip); + __ emit_int8(_bytes_to_copy); + address patch_info_pc = __ pc(); + assert(patch_info_pc - end_of_patch == bytes_to_skip, "incorrect patch info"); + + address entry = __ pc(); + NativeGeneralJump::insert_unconditional((address)_pc_start, entry); + address target = NULL; + relocInfo::relocType reloc_type = relocInfo::none; + switch (_id) { + case access_field_id: target = Runtime1::entry_for (Runtime1::access_field_patching_id); break; + case load_klass_id: target = Runtime1::entry_for (Runtime1::load_klass_patching_id); reloc_type = relocInfo::metadata_type; break; + case load_mirror_id: target = Runtime1::entry_for (Runtime1::load_mirror_patching_id); reloc_type = relocInfo::oop_type; break; + case load_appendix_id: target = Runtime1::entry_for (Runtime1::load_appendix_patching_id); reloc_type = relocInfo::oop_type; break; + default: ShouldNotReachHere(); + } + __ bind(call_patch); + + if (CommentedAssembly) { + __ block_comment("patch entry point"); + } + // Cannot use call_c_opt() because its size is not constant. + __ load_const(Z_R1_scratch, target); // Must not optimize in order to keep constant _patch_info_offset constant. + __ z_basr(Z_R14, Z_R1_scratch); + assert(_patch_info_offset == (patch_info_pc - __ pc()), "must not change"); + ce->add_call_info_here(_info); + __ z_brcl(Assembler::bcondAlways, _patch_site_entry); + if (_id == load_klass_id || _id == load_mirror_id || _id == load_appendix_id) { + CodeSection* cs = __ code_section(); + address pc = (address)_pc_start; + RelocIterator iter(cs, pc, pc + 1); + relocInfo::change_reloc_info_for_address(&iter, (address) pc, reloc_type, relocInfo::none); + } +} + +void DeoptimizeStub::emit_code(LIR_Assembler* ce) { + __ bind(_entry); + __ load_const_optimized(Z_R1_scratch, _trap_request); // Pass trap request in Z_R1_scratch. + ce->emit_call_c(Runtime1::entry_for (Runtime1::deoptimize_id)); + CHECK_BAILOUT(); + ce->add_call_info_here(_info); + DEBUG_ONLY(__ should_not_reach_here()); +} + +void ArrayCopyStub::emit_code(LIR_Assembler* ce) { + // Slow case: call to native. + __ bind(_entry); + __ lgr_if_needed(Z_ARG1, src()->as_register()); + __ lgr_if_needed(Z_ARG2, src_pos()->as_register()); + __ lgr_if_needed(Z_ARG3, dst()->as_register()); + __ lgr_if_needed(Z_ARG4, dst_pos()->as_register()); + __ lgr_if_needed(Z_ARG5, length()->as_register()); + + // Must align calls sites, otherwise they can't be updated atomically on MP hardware. + ce->align_call(lir_static_call); + + assert((__ offset() + NativeCall::call_far_pcrelative_displacement_offset) % NativeCall::call_far_pcrelative_displacement_alignment == 0, + "must be aligned"); + + ce->emit_static_call_stub(); + + // Prepend each BRASL with a nop. + __ relocate(relocInfo::static_call_type); + __ z_nop(); + __ z_brasl(Z_R14, SharedRuntime::get_resolve_static_call_stub()); + ce->add_call_info_here(info()); + ce->verify_oop_map(info()); + +#ifndef PRODUCT + __ load_const_optimized(Z_R1_scratch, (address)&Runtime1::_arraycopy_slowcase_cnt); + __ add2mem_32(Address(Z_R1_scratch), 1, Z_R0_scratch); +#endif + + __ branch_optimized(Assembler::bcondAlways, _continuation); +} + + +/////////////////////////////////////////////////////////////////////////////////// +#if INCLUDE_ALL_GCS + +void G1PreBarrierStub::emit_code(LIR_Assembler* ce) { + // At this point we know that marking is in progress. + // If do_load() is true then we have to emit the + // load of the previous value; otherwise it has already + // been loaded into _pre_val. + __ bind(_entry); + ce->check_reserved_argument_area(16); // RT stub needs 2 spill slots. + assert(pre_val()->is_register(), "Precondition."); + + Register pre_val_reg = pre_val()->as_register(); + + if (do_load()) { + ce->mem2reg(addr(), pre_val(), T_OBJECT, patch_code(), info(), false /*wide*/, false /*unaligned*/); + } + + __ z_ltgr(Z_R1_scratch, pre_val_reg); // Pass oop in Z_R1_scratch to Runtime1::g1_pre_barrier_slow_id. + __ branch_optimized(Assembler::bcondZero, _continuation); + ce->emit_call_c(Runtime1::entry_for (Runtime1::g1_pre_barrier_slow_id)); + CHECK_BAILOUT(); + __ branch_optimized(Assembler::bcondAlways, _continuation); +} + +void G1PostBarrierStub::emit_code(LIR_Assembler* ce) { + __ bind(_entry); + ce->check_reserved_argument_area(16); // RT stub needs 2 spill slots. + assert(addr()->is_register(), "Precondition."); + assert(new_val()->is_register(), "Precondition."); + Register new_val_reg = new_val()->as_register(); + __ z_ltgr(new_val_reg, new_val_reg); + __ branch_optimized(Assembler::bcondZero, _continuation); + __ z_lgr(Z_R1_scratch, addr()->as_pointer_register()); + ce->emit_call_c(Runtime1::entry_for (Runtime1::g1_post_barrier_slow_id)); + CHECK_BAILOUT(); + __ branch_optimized(Assembler::bcondAlways, _continuation); +} + +#endif // INCLUDE_ALL_GCS + +#undef __
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/cpu/s390/vm/c1_Defs_s390.hpp Wed Jul 05 22:28:55 2017 +0200 @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016 SAP SE. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef CPU_S390_VM_C1_DEFS_S390_HPP +#define CPU_S390_VM_C1_DEFS_S390_HPP + +// Native word offsets from memory address (big endian). +enum { + pd_lo_word_offset_in_bytes = BytesPerInt, + pd_hi_word_offset_in_bytes = 0 +}; + +// Explicit rounding operations are not required to implement the strictFP mode. +enum { + pd_strict_fp_requires_explicit_rounding = false +}; + +// registers +enum { + pd_nof_cpu_regs_frame_map = 16, // Number of registers used during code emission. + // Treat all registers as caller save (values of callee save are hard to find if caller is in runtime). + // unallocated: Z_thread, Z_fp, Z_SP, Z_R0_scratch, Z_R1_scratch, Z_R14 + pd_nof_cpu_regs_unallocated = 6, + pd_nof_caller_save_cpu_regs_frame_map = pd_nof_cpu_regs_frame_map - pd_nof_cpu_regs_unallocated, // Number of cpu registers killed by calls. + pd_nof_cpu_regs_reg_alloc = pd_nof_caller_save_cpu_regs_frame_map, // Number of registers that are visible to register allocator. + pd_nof_cpu_regs_linearscan = pd_nof_cpu_regs_frame_map,// Number of registers visible linear scan. + pd_first_cpu_reg = 0, + pd_last_cpu_reg = 9, // Others are unallocated (see FrameMap::initialize()). + + pd_nof_fpu_regs_frame_map = 16, // Number of registers used during code emission. + pd_nof_fcpu_regs_unallocated = 1, // Leave Z_F15 unallocated and use it as scratch register. + pd_nof_caller_save_fpu_regs_frame_map = pd_nof_fpu_regs_frame_map - pd_nof_fcpu_regs_unallocated, // Number of fpu registers killed by calls. + pd_nof_fpu_regs_reg_alloc = pd_nof_caller_save_fpu_regs_frame_map, // Number of registers that are visible to register allocator. + pd_nof_fpu_regs_linearscan = pd_nof_fpu_regs_frame_map, // Number of registers visible to linear scan. + pd_first_fpu_reg = pd_nof_cpu_regs_frame_map, + pd_last_fpu_reg = pd_first_fpu_reg + pd_nof_fpu_regs_frame_map - pd_nof_fcpu_regs_unallocated - 1, + + pd_nof_xmm_regs_linearscan = 0, + pd_nof_caller_save_xmm_regs = 0, + pd_first_xmm_reg = -1, + pd_last_xmm_reg = -1 +}; + +// For debug info: a float value in a register is saved in single precision by runtime stubs. +enum { + pd_float_saved_as_double = false +}; + +#endif // CPU_S390_VM_C1_DEFS_S390_HPP
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/cpu/s390/vm/c1_FpuStackSim_s390.hpp Wed Jul 05 22:28:55 2017 +0200 @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016 SAP SE. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef CPU_S390_VM_C1_FPUSTACKSIM_S390_HPP +#define CPU_S390_VM_C1_FPUSTACKSIM_S390_HPP + +// No FPU stack on ZARCH_64 +class FpuStackSim; + +#endif // CPU_S390_VM_C1_FPUSTACKSIM_S390_HPP
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/cpu/s390/vm/c1_FrameMap_s390.cpp Wed Jul 05 22:28:55 2017 +0200 @@ -0,0 +1,293 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016 SAP SE. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#include "precompiled.hpp" +#include "c1/c1_FrameMap.hpp" +#include "c1/c1_LIR.hpp" +#include "runtime/sharedRuntime.hpp" +#include "vmreg_s390.inline.hpp" + + +const int FrameMap::pd_c_runtime_reserved_arg_size = 7; + +LIR_Opr FrameMap::map_to_opr(BasicType type, VMRegPair* reg, bool outgoing) { + LIR_Opr opr = LIR_OprFact::illegalOpr; + VMReg r_1 = reg->first(); + VMReg r_2 = reg->second(); + if (r_1->is_stack()) { + // Convert stack slot to an SP offset. + // The calling convention does not count the SharedRuntime::out_preserve_stack_slots() value + // so we must add it in here. + int st_off = (r_1->reg2stack() + SharedRuntime::out_preserve_stack_slots()) * VMRegImpl::stack_slot_size; + opr = LIR_OprFact::address(new LIR_Address(Z_SP_opr, st_off, type)); + } else if (r_1->is_Register()) { + Register reg = r_1->as_Register(); + if (r_2->is_Register() && (type == T_LONG || type == T_DOUBLE)) { + opr = as_long_opr(reg); + } else if (type == T_OBJECT || type == T_ARRAY) { + opr = as_oop_opr(reg); + } else if (type == T_METADATA) { + opr = as_metadata_opr(reg); + } else { + opr = as_opr(reg); + } + } else if (r_1->is_FloatRegister()) { + assert(type == T_DOUBLE || type == T_FLOAT, "wrong type"); + FloatRegister f = r_1->as_FloatRegister(); + if (type == T_FLOAT) { + opr = as_float_opr(f); + } else { + opr = as_double_opr(f); + } + } else { + ShouldNotReachHere(); + } + return opr; +} + +// FrameMap +//-------------------------------------------------------- + +FloatRegister FrameMap::_fpu_rnr2reg [FrameMap::nof_fpu_regs]; // mapping c1 regnr. -> FloatRegister +int FrameMap::_fpu_reg2rnr [FrameMap::nof_fpu_regs]; // mapping assembler encoding -> c1 regnr. + +// Some useful constant RInfo's: +LIR_Opr FrameMap::Z_R0_opr; +LIR_Opr FrameMap::Z_R1_opr; +LIR_Opr FrameMap::Z_R2_opr; +LIR_Opr FrameMap::Z_R3_opr; +LIR_Opr FrameMap::Z_R4_opr; +LIR_Opr FrameMap::Z_R5_opr; +LIR_Opr FrameMap::Z_R6_opr; +LIR_Opr FrameMap::Z_R7_opr; +LIR_Opr FrameMap::Z_R8_opr; +LIR_Opr FrameMap::Z_R9_opr; +LIR_Opr FrameMap::Z_R10_opr; +LIR_Opr FrameMap::Z_R11_opr; +LIR_Opr FrameMap::Z_R12_opr; +LIR_Opr FrameMap::Z_R13_opr; +LIR_Opr FrameMap::Z_R14_opr; +LIR_Opr FrameMap::Z_R15_opr; + +LIR_Opr FrameMap::Z_R0_oop_opr; +LIR_Opr FrameMap::Z_R1_oop_opr; +LIR_Opr FrameMap::Z_R2_oop_opr; +LIR_Opr FrameMap::Z_R3_oop_opr; +LIR_Opr FrameMap::Z_R4_oop_opr; +LIR_Opr FrameMap::Z_R5_oop_opr; +LIR_Opr FrameMap::Z_R6_oop_opr; +LIR_Opr FrameMap::Z_R7_oop_opr; +LIR_Opr FrameMap::Z_R8_oop_opr; +LIR_Opr FrameMap::Z_R9_oop_opr; +LIR_Opr FrameMap::Z_R10_oop_opr; +LIR_Opr FrameMap::Z_R11_oop_opr; +LIR_Opr FrameMap::Z_R12_oop_opr; +LIR_Opr FrameMap::Z_R13_oop_opr; +LIR_Opr FrameMap::Z_R14_oop_opr; +LIR_Opr FrameMap::Z_R15_oop_opr; + +LIR_Opr FrameMap::Z_R0_metadata_opr; +LIR_Opr FrameMap::Z_R1_metadata_opr; +LIR_Opr FrameMap::Z_R2_metadata_opr; +LIR_Opr FrameMap::Z_R3_metadata_opr; +LIR_Opr FrameMap::Z_R4_metadata_opr; +LIR_Opr FrameMap::Z_R5_metadata_opr; +LIR_Opr FrameMap::Z_R6_metadata_opr; +LIR_Opr FrameMap::Z_R7_metadata_opr; +LIR_Opr FrameMap::Z_R8_metadata_opr; +LIR_Opr FrameMap::Z_R9_metadata_opr; +LIR_Opr FrameMap::Z_R10_metadata_opr; +LIR_Opr FrameMap::Z_R11_metadata_opr; +LIR_Opr FrameMap::Z_R12_metadata_opr; +LIR_Opr FrameMap::Z_R13_metadata_opr; +LIR_Opr FrameMap::Z_R14_metadata_opr; +LIR_Opr FrameMap::Z_R15_metadata_opr; + +LIR_Opr FrameMap::Z_SP_opr; +LIR_Opr FrameMap::Z_FP_opr; + +LIR_Opr FrameMap::Z_R2_long_opr; +LIR_Opr FrameMap::Z_R10_long_opr; +LIR_Opr FrameMap::Z_R11_long_opr; + +LIR_Opr FrameMap::Z_F0_opr; +LIR_Opr FrameMap::Z_F0_double_opr; + + +LIR_Opr FrameMap::_caller_save_cpu_regs[] = { 0, }; +LIR_Opr FrameMap::_caller_save_fpu_regs[] = { 0, }; + + +// c1 rnr -> FloatRegister +FloatRegister FrameMap::nr2floatreg (int rnr) { + assert(_init_done, "tables not initialized"); + debug_only(fpu_range_check(rnr);) + return _fpu_rnr2reg[rnr]; +} + +void FrameMap::map_float_register(int rnr, FloatRegister reg) { + debug_only(fpu_range_check(rnr);) + debug_only(fpu_range_check(reg->encoding());) + _fpu_rnr2reg[rnr] = reg; // mapping c1 regnr. -> FloatRegister + _fpu_reg2rnr[reg->encoding()] = rnr; // mapping assembler encoding -> c1 regnr. +} + +void FrameMap::initialize() { + assert(!_init_done, "once"); + + DEBUG_ONLY(int allocated = 0;) + DEBUG_ONLY(int unallocated = 0;) + + // Register usage: + // Z_thread (Z_R8) + // Z_fp (Z_R9) + // Z_SP (Z_R15) + DEBUG_ONLY(allocated++); map_register(0, Z_R2); + DEBUG_ONLY(allocated++); map_register(1, Z_R3); + DEBUG_ONLY(allocated++); map_register(2, Z_R4); + DEBUG_ONLY(allocated++); map_register(3, Z_R5); + DEBUG_ONLY(allocated++); map_register(4, Z_R6); + DEBUG_ONLY(allocated++); map_register(5, Z_R7); + DEBUG_ONLY(allocated++); map_register(6, Z_R10); + DEBUG_ONLY(allocated++); map_register(7, Z_R11); + DEBUG_ONLY(allocated++); map_register(8, Z_R12); + DEBUG_ONLY(allocated++); map_register(9, Z_R13); // <- last register visible in RegAlloc + DEBUG_ONLY(unallocated++); map_register(11, Z_R0); // Z_R0_scratch + DEBUG_ONLY(unallocated++); map_register(12, Z_R1); // Z_R1_scratch + DEBUG_ONLY(unallocated++); map_register(10, Z_R14); // return pc; TODO: Try to let c1/c2 allocate R14. + + // The following registers are usually unavailable. + DEBUG_ONLY(unallocated++); map_register(13, Z_R8); + DEBUG_ONLY(unallocated++); map_register(14, Z_R9); + DEBUG_ONLY(unallocated++); map_register(15, Z_R15); + assert(allocated-1 == pd_last_cpu_reg, "wrong number/mapping of allocated CPU registers"); + assert(unallocated == pd_nof_cpu_regs_unallocated, "wrong number of unallocated CPU registers"); + assert(nof_cpu_regs == allocated+unallocated, "wrong number of CPU registers"); + + int j = 0; + for (int i = 0; i < nof_fpu_regs; i++) { + if (as_FloatRegister(i) == Z_fscratch_1) continue; // unallocated + map_float_register(j++, as_FloatRegister(i)); + } + assert(j == nof_fpu_regs-1, "missed one fpu reg?"); + map_float_register(j++, Z_fscratch_1); + + _init_done = true; + + Z_R0_opr = as_opr(Z_R0); + Z_R1_opr = as_opr(Z_R1); + Z_R2_opr = as_opr(Z_R2); + Z_R3_opr = as_opr(Z_R3); + Z_R4_opr = as_opr(Z_R4); + Z_R5_opr = as_opr(Z_R5); + Z_R6_opr = as_opr(Z_R6); + Z_R7_opr = as_opr(Z_R7); + Z_R8_opr = as_opr(Z_R8); + Z_R9_opr = as_opr(Z_R9); + Z_R10_opr = as_opr(Z_R10); + Z_R11_opr = as_opr(Z_R11); + Z_R12_opr = as_opr(Z_R12); + Z_R13_opr = as_opr(Z_R13); + Z_R14_opr = as_opr(Z_R14); + Z_R15_opr = as_opr(Z_R15); + + Z_R0_oop_opr = as_oop_opr(Z_R0); + Z_R1_oop_opr = as_oop_opr(Z_R1); + Z_R2_oop_opr = as_oop_opr(Z_R2); + Z_R3_oop_opr = as_oop_opr(Z_R3); + Z_R4_oop_opr = as_oop_opr(Z_R4); + Z_R5_oop_opr = as_oop_opr(Z_R5); + Z_R6_oop_opr = as_oop_opr(Z_R6); + Z_R7_oop_opr = as_oop_opr(Z_R7); + Z_R8_oop_opr = as_oop_opr(Z_R8); + Z_R9_oop_opr = as_oop_opr(Z_R9); + Z_R10_oop_opr = as_oop_opr(Z_R10); + Z_R11_oop_opr = as_oop_opr(Z_R11); + Z_R12_oop_opr = as_oop_opr(Z_R12); + Z_R13_oop_opr = as_oop_opr(Z_R13); + Z_R14_oop_opr = as_oop_opr(Z_R14); + Z_R15_oop_opr = as_oop_opr(Z_R15); + + Z_R0_metadata_opr = as_metadata_opr(Z_R0); + Z_R1_metadata_opr = as_metadata_opr(Z_R1); + Z_R2_metadata_opr = as_metadata_opr(Z_R2); + Z_R3_metadata_opr = as_metadata_opr(Z_R3); + Z_R4_metadata_opr = as_metadata_opr(Z_R4); + Z_R5_metadata_opr = as_metadata_opr(Z_R5); + Z_R6_metadata_opr = as_metadata_opr(Z_R6); + Z_R7_metadata_opr = as_metadata_opr(Z_R7); + Z_R8_metadata_opr = as_metadata_opr(Z_R8); + Z_R9_metadata_opr = as_metadata_opr(Z_R9); + Z_R10_metadata_opr = as_metadata_opr(Z_R10); + Z_R11_metadata_opr = as_metadata_opr(Z_R11); + Z_R12_metadata_opr = as_metadata_opr(Z_R12); + Z_R13_metadata_opr = as_metadata_opr(Z_R13); + Z_R14_metadata_opr = as_metadata_opr(Z_R14); + Z_R15_metadata_opr = as_metadata_opr(Z_R15); + + // TODO: needed? Or can we make Z_R9 available for linear scan allocation. + Z_FP_opr = as_pointer_opr(Z_fp); + Z_SP_opr = as_pointer_opr(Z_SP); + + Z_R2_long_opr = LIR_OprFact::double_cpu(cpu_reg2rnr(Z_R2), cpu_reg2rnr(Z_R2)); + Z_R10_long_opr = LIR_OprFact::double_cpu(cpu_reg2rnr(Z_R10), cpu_reg2rnr(Z_R10)); + Z_R11_long_opr = LIR_OprFact::double_cpu(cpu_reg2rnr(Z_R11), cpu_reg2rnr(Z_R11)); + + Z_F0_opr = as_float_opr(Z_F0); + Z_F0_double_opr = as_double_opr(Z_F0); + + // All allocated cpu regs are caller saved. + for (int c1rnr = 0; c1rnr < max_nof_caller_save_cpu_regs; c1rnr++) { + _caller_save_cpu_regs[c1rnr] = as_opr(cpu_rnr2reg(c1rnr)); + } + + // All allocated fpu regs are caller saved. + for (int c1rnr = 0; c1rnr < nof_caller_save_fpu_regs; c1rnr++) { + _caller_save_fpu_regs[c1rnr] = as_float_opr(nr2floatreg(c1rnr)); + } +} + +Address FrameMap::make_new_address(ByteSize sp_offset) const { + return Address(Z_SP, sp_offset); +} + +VMReg FrameMap::fpu_regname (int n) { + return nr2floatreg(n)->as_VMReg(); +} + +LIR_Opr FrameMap::stack_pointer() { + return Z_SP_opr; +} + +// JSR 292 +// On ZARCH_64, there is no need to save the SP, because neither +// method handle intrinsics nor compiled lambda forms modify it. +LIR_Opr FrameMap::method_handle_invoke_SP_save_opr() { + return LIR_OprFact::illegalOpr; +} + +bool FrameMap::validate_frame() { + return true; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/cpu/s390/vm/c1_FrameMap_s390.hpp Wed Jul 05 22:28:55 2017 +0200 @@ -0,0 +1,141 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016 SAP SE. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef CPU_S390_VM_C1_FRAMEMAP_S390_HPP +#define CPU_S390_VM_C1_FRAMEMAP_S390_HPP + + public: + + enum { + nof_reg_args = 5, // Registers Z_ARG1 - Z_ARG5 are available for parameter passing. + first_available_sp_in_frame = frame::z_abi_16_size, + frame_pad_in_bytes = 0 + }; + + static const int pd_c_runtime_reserved_arg_size; + + static LIR_Opr Z_R0_opr; + static LIR_Opr Z_R1_opr; + static LIR_Opr Z_R2_opr; + static LIR_Opr Z_R3_opr; + static LIR_Opr Z_R4_opr; + static LIR_Opr Z_R5_opr; + static LIR_Opr Z_R6_opr; + static LIR_Opr Z_R7_opr; + static LIR_Opr Z_R8_opr; + static LIR_Opr Z_R9_opr; + static LIR_Opr Z_R10_opr; + static LIR_Opr Z_R11_opr; + static LIR_Opr Z_R12_opr; + static LIR_Opr Z_R13_opr; + static LIR_Opr Z_R14_opr; + static LIR_Opr Z_R15_opr; + + static LIR_Opr Z_R0_oop_opr; + static LIR_Opr Z_R1_oop_opr; + static LIR_Opr Z_R2_oop_opr; + static LIR_Opr Z_R3_oop_opr; + static LIR_Opr Z_R4_oop_opr; + static LIR_Opr Z_R5_oop_opr; + static LIR_Opr Z_R6_oop_opr; + static LIR_Opr Z_R7_oop_opr; + static LIR_Opr Z_R8_oop_opr; + static LIR_Opr Z_R9_oop_opr; + static LIR_Opr Z_R10_oop_opr; + static LIR_Opr Z_R11_oop_opr; + static LIR_Opr Z_R12_oop_opr; + static LIR_Opr Z_R13_oop_opr; + static LIR_Opr Z_R14_oop_opr; + static LIR_Opr Z_R15_oop_opr; + + static LIR_Opr Z_R0_metadata_opr; + static LIR_Opr Z_R1_metadata_opr; + static LIR_Opr Z_R2_metadata_opr; + static LIR_Opr Z_R3_metadata_opr; + static LIR_Opr Z_R4_metadata_opr; + static LIR_Opr Z_R5_metadata_opr; + static LIR_Opr Z_R6_metadata_opr; + static LIR_Opr Z_R7_metadata_opr; + static LIR_Opr Z_R8_metadata_opr; + static LIR_Opr Z_R9_metadata_opr; + static LIR_Opr Z_R10_metadata_opr; + static LIR_Opr Z_R11_metadata_opr; + static LIR_Opr Z_R12_metadata_opr; + static LIR_Opr Z_R13_metadata_opr; + static LIR_Opr Z_R14_metadata_opr; + static LIR_Opr Z_R15_metadata_opr; + + static LIR_Opr Z_SP_opr; + static LIR_Opr Z_FP_opr; + + static LIR_Opr Z_R2_long_opr; + static LIR_Opr Z_R10_long_opr; + static LIR_Opr Z_R11_long_opr; + + static LIR_Opr Z_F0_opr; + static LIR_Opr Z_F0_double_opr; + + private: + static FloatRegister _fpu_rnr2reg [FrameMap::nof_fpu_regs]; // mapping c1 regnr. -> FloatRegister + static int _fpu_reg2rnr [FrameMap::nof_fpu_regs]; // mapping assembler encoding -> c1 regnr. + + static void map_float_register(int rnr, FloatRegister reg); + + // FloatRegister -> c1 rnr + static int fpu_reg2rnr (FloatRegister reg) { + assert(_init_done, "tables not initialized"); + int c1rnr = _fpu_reg2rnr[reg->encoding()]; + debug_only(fpu_range_check(c1rnr);) + return c1rnr; + } + + public: + + static LIR_Opr as_long_opr(Register r) { + return LIR_OprFact::double_cpu(cpu_reg2rnr(r), cpu_reg2rnr(r)); + } + static LIR_Opr as_pointer_opr(Register r) { + return LIR_OprFact::double_cpu(cpu_reg2rnr(r), cpu_reg2rnr(r)); + } + + static LIR_Opr as_float_opr(FloatRegister r) { + return LIR_OprFact::single_fpu(fpu_reg2rnr(r)); + } + static LIR_Opr as_double_opr(FloatRegister r) { + return LIR_OprFact::double_fpu(fpu_reg2rnr(r)); + } + + static FloatRegister nr2floatreg (int rnr); + + static VMReg fpu_regname (int n); + + // No callee saved registers (saved values are not accessible if callee is in runtime). + static bool is_caller_save_register (LIR_Opr opr) { return true; } + static bool is_caller_save_register (Register r) { return true; } + + static int nof_caller_save_cpu_regs() { return pd_nof_caller_save_cpu_regs_frame_map; } + static int last_cpu_reg() { return pd_last_cpu_reg; } + +#endif // CPU_S390_VM_C1_FRAMEMAP_S390_HPP
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/cpu/s390/vm/c1_LIRAssembler_s390.cpp Wed Jul 05 22:28:55 2017 +0200 @@ -0,0 +1,3037 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016 SAP SE. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#include "precompiled.hpp" +#include "c1/c1_Compilation.hpp" +#include "c1/c1_LIRAssembler.hpp" +#include "c1/c1_MacroAssembler.hpp" +#include "c1/c1_Runtime1.hpp" +#include "c1/c1_ValueStack.hpp" +#include "ci/ciArrayKlass.hpp" +#include "ci/ciInstance.hpp" +#include "gc/shared/collectedHeap.hpp" +#include "gc/shared/barrierSet.hpp" +#include "gc/shared/cardTableModRefBS.hpp" +#include "nativeInst_s390.hpp" +#include "oops/objArrayKlass.hpp" +#include "runtime/sharedRuntime.hpp" +#include "vmreg_s390.inline.hpp" + +#define __ _masm-> + +#ifndef PRODUCT +#undef __ +#define __ (Verbose ? (_masm->block_comment(FILE_AND_LINE),_masm) : _masm)-> +#endif + +//------------------------------------------------------------ + +bool LIR_Assembler::is_small_constant(LIR_Opr opr) { + // Not used on ZARCH_64 + ShouldNotCallThis(); + return false; +} + +LIR_Opr LIR_Assembler::receiverOpr() { + return FrameMap::Z_R2_oop_opr; +} + +LIR_Opr LIR_Assembler::osrBufferPointer() { + return FrameMap::Z_R2_opr; +} + +int LIR_Assembler::initial_frame_size_in_bytes() const { + return in_bytes(frame_map()->framesize_in_bytes()); +} + +// Inline cache check: done before the frame is built. +// The inline cached class is in Z_inline_cache(Z_R9). +// We fetch the class of the receiver and compare it with the cached class. +// If they do not match we jump to the slow case. +int LIR_Assembler::check_icache() { + Register receiver = receiverOpr()->as_register(); + int offset = __ offset(); + __ inline_cache_check(receiver, Z_inline_cache); + return offset; +} + +void LIR_Assembler::osr_entry() { + // On-stack-replacement entry sequence (interpreter frame layout described in interpreter_sparc.cpp): + // + // 1. Create a new compiled activation. + // 2. Initialize local variables in the compiled activation. The expression stack must be empty + // at the osr_bci; it is not initialized. + // 3. Jump to the continuation address in compiled code to resume execution. + + // OSR entry point + offsets()->set_value(CodeOffsets::OSR_Entry, code_offset()); + BlockBegin* osr_entry = compilation()->hir()->osr_entry(); + ValueStack* entry_state = osr_entry->end()->state(); + int number_of_locks = entry_state->locks_size(); + + // Create a frame for the compiled activation. + __ build_frame(initial_frame_size_in_bytes(), bang_size_in_bytes()); + + // OSR buffer is + // + // locals[nlocals-1..0] + // monitors[number_of_locks-1..0] + // + // Locals is a direct copy of the interpreter frame so in the osr buffer + // the first slot in the local array is the last local from the interpreter + // and the last slot is local[0] (receiver) from the interpreter + // + // Similarly with locks. The first lock slot in the osr buffer is the nth lock + // from the interpreter frame, the nth lock slot in the osr buffer is 0th lock + // in the interpreter frame (the method lock if a sync method) + + // Initialize monitors in the compiled activation. + // I0: pointer to osr buffer + // + // All other registers are dead at this point and the locals will be + // copied into place by code emitted in the IR. + + Register OSR_buf = osrBufferPointer()->as_register(); + { assert(frame::interpreter_frame_monitor_size() == BasicObjectLock::size(), "adjust code below"); + int monitor_offset = BytesPerWord * method()->max_locals() + + (2 * BytesPerWord) * (number_of_locks - 1); + // SharedRuntime::OSR_migration_begin() packs BasicObjectLocks in + // the OSR buffer using 2 word entries: first the lock and then + // the oop. + for (int i = 0; i < number_of_locks; i++) { + int slot_offset = monitor_offset - ((i * 2) * BytesPerWord); + // Verify the interpreter's monitor has a non-null object. + __ asm_assert_mem8_isnot_zero(slot_offset + 1*BytesPerWord, OSR_buf, "locked object is NULL", __LINE__); + // Copy the lock field into the compiled activation. + __ z_lg(Z_R1_scratch, slot_offset + 0, OSR_buf); + __ z_stg(Z_R1_scratch, frame_map()->address_for_monitor_lock(i)); + __ z_lg(Z_R1_scratch, slot_offset + 1*BytesPerWord, OSR_buf); + __ z_stg(Z_R1_scratch, frame_map()->address_for_monitor_object(i)); + } + } +} + +// -------------------------------------------------------------------------------------------- + +address LIR_Assembler::emit_call_c(address a) { + __ align_call_far_patchable(__ pc()); + address call_addr = __ call_c_opt(a); + if (call_addr == NULL) { + bailout("const section overflow"); + } + return call_addr; +} + +int LIR_Assembler::emit_exception_handler() { + // If the last instruction is a call (typically to do a throw which + // is coming at the end after block reordering) the return address + // must still point into the code area in order to avoid assertion + // failures when searching for the corresponding bci. => Add a nop. + // (was bug 5/14/1999 - gri) + __ nop(); + + // Generate code for exception handler. + address handler_base = __ start_a_stub(exception_handler_size); + if (handler_base == NULL) { + // Not enough space left for the handler. + bailout("exception handler overflow"); + return -1; + } + + int offset = code_offset(); + + address a = Runtime1::entry_for (Runtime1::handle_exception_from_callee_id); + address call_addr = emit_call_c(a); + CHECK_BAILOUT_(-1); + __ should_not_reach_here(); + guarantee(code_offset() - offset <= exception_handler_size, "overflow"); + __ end_a_stub(); + + return offset; +} + +// Emit the code to remove the frame from the stack in the exception +// unwind path. +int LIR_Assembler::emit_unwind_handler() { +#ifndef PRODUCT + if (CommentedAssembly) { + _masm->block_comment("Unwind handler"); + } +#endif + + int offset = code_offset(); + Register exception_oop_callee_saved = Z_R10; // Z_R10 is callee-saved. + Register Rtmp1 = Z_R11; + Register Rtmp2 = Z_R12; + + // Fetch the exception from TLS and clear out exception related thread state. + Address exc_oop_addr = Address(Z_thread, JavaThread::exception_oop_offset()); + Address exc_pc_addr = Address(Z_thread, JavaThread::exception_pc_offset()); + __ z_lg(Z_EXC_OOP, exc_oop_addr); + __ clear_mem(exc_oop_addr, sizeof(oop)); + __ clear_mem(exc_pc_addr, sizeof(intptr_t)); + + __ bind(_unwind_handler_entry); + __ verify_not_null_oop(Z_EXC_OOP); + if (method()->is_synchronized() || compilation()->env()->dtrace_method_probes()) { + __ lgr_if_needed(exception_oop_callee_saved, Z_EXC_OOP); // Preserve the exception. + } + + // Preform needed unlocking. + MonitorExitStub* stub = NULL; + if (method()->is_synchronized()) { + // Runtime1::monitorexit_id expects lock address in Z_R1_scratch. + LIR_Opr lock = FrameMap::as_opr(Z_R1_scratch); + monitor_address(0, lock); + stub = new MonitorExitStub(lock, true, 0); + __ unlock_object(Rtmp1, Rtmp2, lock->as_register(), *stub->entry()); + __ bind(*stub->continuation()); + } + + if (compilation()->env()->dtrace_method_probes()) { + ShouldNotReachHere(); // Not supported. +#if 0 + __ mov(rdi, r15_thread); + __ mov_metadata(rsi, method()->constant_encoding()); + __ call(RuntimeAddress(CAST_FROM_FN_PTR(address, SharedRuntime::dtrace_method_exit))); +#endif + } + + if (method()->is_synchronized() || compilation()->env()->dtrace_method_probes()) { + __ lgr_if_needed(Z_EXC_OOP, exception_oop_callee_saved); // Restore the exception. + } + + // Remove the activation and dispatch to the unwind handler. + __ pop_frame(); + __ z_lg(Z_EXC_PC, _z_abi16(return_pc), Z_SP); + + // Z_EXC_OOP: exception oop + // Z_EXC_PC: exception pc + + // Dispatch to the unwind logic. + __ load_const_optimized(Z_R5, Runtime1::entry_for (Runtime1::unwind_exception_id)); + __ z_br(Z_R5); + + // Emit the slow path assembly. + if (stub != NULL) { + stub->emit_code(this); + } + + return offset; +} + +int LIR_Assembler::emit_deopt_handler() { + // If the last instruction is a call (typically to do a throw which + // is coming at the end after block reordering) the return address + // must still point into the code area in order to avoid assertion + // failures when searching for the corresponding bci. => Add a nop. + // (was bug 5/14/1999 - gri) + __ nop(); + + // Generate code for exception handler. + address handler_base = __ start_a_stub(deopt_handler_size); + if (handler_base == NULL) { + // Not enough space left for the handler. + bailout("deopt handler overflow"); + return -1; + } int offset = code_offset(); + // Size must be constant (see HandlerImpl::emit_deopt_handler). + __ load_const(Z_R1_scratch, SharedRuntime::deopt_blob()->unpack()); + __ call(Z_R1_scratch); + guarantee(code_offset() - offset <= deopt_handler_size, "overflow"); + __ end_a_stub(); + + return offset; +} + +void LIR_Assembler::jobject2reg(jobject o, Register reg) { + if (o == NULL) { + __ clear_reg(reg, true/*64bit*/, false/*set cc*/); // Must not kill cc set by cmove. + } else { + AddressLiteral a = __ allocate_oop_address(o); + bool success = __ load_oop_from_toc(reg, a, reg); + if (!success) { + bailout("const section overflow"); + } + } +} + +void LIR_Assembler::jobject2reg_with_patching(Register reg, CodeEmitInfo *info) { + // Allocate a new index in table to hold the object once it's been patched. + int oop_index = __ oop_recorder()->allocate_oop_index(NULL); + PatchingStub* patch = new PatchingStub(_masm, patching_id(info), oop_index); + + AddressLiteral addrlit((intptr_t)0, oop_Relocation::spec(oop_index)); + assert(addrlit.rspec().type() == relocInfo::oop_type, "must be an oop reloc"); + // The NULL will be dynamically patched later so the sequence to + // load the address literal must not be optimized. + __ load_const(reg, addrlit); + + patching_epilog(patch, lir_patch_normal, reg, info); +} + +void LIR_Assembler::metadata2reg(Metadata* md, Register reg) { + bool success = __ set_metadata_constant(md, reg); + if (!success) { + bailout("const section overflow"); + return; + } +} + +void LIR_Assembler::klass2reg_with_patching(Register reg, CodeEmitInfo *info) { + // Allocate a new index in table to hold the klass once it's been patched. + int index = __ oop_recorder()->allocate_metadata_index(NULL); + PatchingStub* patch = new PatchingStub(_masm, PatchingStub::load_klass_id, index); + AddressLiteral addrlit((intptr_t)0, metadata_Relocation::spec(index)); + assert(addrlit.rspec().type() == relocInfo::metadata_type, "must be an metadata reloc"); + // The NULL will be dynamically patched later so the sequence to + // load the address literal must not be optimized. + __ load_const(reg, addrlit); + + patching_epilog(patch, lir_patch_normal, reg, info); +} + +void LIR_Assembler::emit_op3(LIR_Op3* op) { + switch (op->code()) { + case lir_idiv: + case lir_irem: + arithmetic_idiv(op->code(), + op->in_opr1(), + op->in_opr2(), + op->in_opr3(), + op->result_opr(), + op->info()); + break; + default: ShouldNotReachHere(); break; + } +} + + +void LIR_Assembler::emit_opBranch(LIR_OpBranch* op) { +#ifdef ASSERT + assert(op->block() == NULL || op->block()->label() == op->label(), "wrong label"); + if (op->block() != NULL) { _branch_target_blocks.append(op->block()); } + if (op->ublock() != NULL) { _branch_target_blocks.append(op->ublock()); } +#endif + + if (op->cond() == lir_cond_always) { + if (op->info() != NULL) { add_debug_info_for_branch(op->info()); } + __ branch_optimized(Assembler::bcondAlways, *(op->label())); + } else { + Assembler::branch_condition acond = Assembler::bcondZero; + if (op->code() == lir_cond_float_branch) { + assert(op->ublock() != NULL, "must have unordered successor"); + __ branch_optimized(Assembler::bcondNotOrdered, *(op->ublock()->label())); + } + switch (op->cond()) { + case lir_cond_equal: acond = Assembler::bcondEqual; break; + case lir_cond_notEqual: acond = Assembler::bcondNotEqual; break; + case lir_cond_less: acond = Assembler::bcondLow; break; + case lir_cond_lessEqual: acond = Assembler::bcondNotHigh; break; + case lir_cond_greaterEqual: acond = Assembler::bcondNotLow; break; + case lir_cond_greater: acond = Assembler::bcondHigh; break; + case lir_cond_belowEqual: acond = Assembler::bcondNotHigh; break; + case lir_cond_aboveEqual: acond = Assembler::bcondNotLow; break; + default: ShouldNotReachHere(); + } + __ branch_optimized(acond,*(op->label())); + } +} + + +void LIR_Assembler::emit_opConvert(LIR_OpConvert* op) { + LIR_Opr src = op->in_opr(); + LIR_Opr dest = op->result_opr(); + + switch (op->bytecode()) { + case Bytecodes::_i2l: + __ move_reg_if_needed(dest->as_register_lo(), T_LONG, src->as_register(), T_INT); + break; + + case Bytecodes::_l2i: + __ move_reg_if_needed(dest->as_register(), T_INT, src->as_register_lo(), T_LONG); + break; + + case Bytecodes::_i2b: + __ move_reg_if_needed(dest->as_register(), T_BYTE, src->as_register(), T_INT); + break; + + case Bytecodes::_i2c: + __ move_reg_if_needed(dest->as_register(), T_CHAR, src->as_register(), T_INT); + break; + + case Bytecodes::_i2s: + __ move_reg_if_needed(dest->as_register(), T_SHORT, src->as_register(), T_INT); + break; + + case Bytecodes::_f2d: + assert(dest->is_double_fpu(), "check"); + __ move_freg_if_needed(dest->as_double_reg(), T_DOUBLE, src->as_float_reg(), T_FLOAT); + break; + + case Bytecodes::_d2f: + assert(dest->is_single_fpu(), "check"); + __ move_freg_if_needed(dest->as_float_reg(), T_FLOAT, src->as_double_reg(), T_DOUBLE); + break; + + case Bytecodes::_i2f: + __ z_cefbr(dest->as_float_reg(), src->as_register()); + break; + + case Bytecodes::_i2d: + __ z_cdfbr(dest->as_double_reg(), src->as_register()); + break; + + case Bytecodes::_l2f: + __ z_cegbr(dest->as_float_reg(), src->as_register_lo()); + break; + case Bytecodes::_l2d: + __ z_cdgbr(dest->as_double_reg(), src->as_register_lo()); + break; + + case Bytecodes::_f2i: + case Bytecodes::_f2l: { + Label done; + FloatRegister Rsrc = src->as_float_reg(); + Register Rdst = (op->bytecode() == Bytecodes::_f2i ? dest->as_register() : dest->as_register_lo()); + __ clear_reg(Rdst, true, false); + __ z_cebr(Rsrc, Rsrc); + __ z_brno(done); // NaN -> 0 + if (op->bytecode() == Bytecodes::_f2i) { + __ z_cfebr(Rdst, Rsrc, Assembler::to_zero); + } else { // op->bytecode() == Bytecodes::_f2l + __ z_cgebr(Rdst, Rsrc, Assembler::to_zero); + } + __ bind(done); + } + break; + + case Bytecodes::_d2i: + case Bytecodes::_d2l: { + Label done; + FloatRegister Rsrc = src->as_double_reg(); + Register Rdst = (op->bytecode() == Bytecodes::_d2i ? dest->as_register() : dest->as_register_lo()); + __ clear_reg(Rdst, true, false); // Don't set CC. + __ z_cdbr(Rsrc, Rsrc); + __ z_brno(done); // NaN -> 0 + if (op->bytecode() == Bytecodes::_d2i) { + __ z_cfdbr(Rdst, Rsrc, Assembler::to_zero); + } else { // Bytecodes::_d2l + __ z_cgdbr(Rdst, Rsrc, Assembler::to_zero); + } + __ bind(done); + } + break; + + default: ShouldNotReachHere(); + } +} + +void LIR_Assembler::align_call(LIR_Code code) { + // End of call instruction must be 4 byte aligned. + int offset = __ offset(); + switch (code) { + case lir_icvirtual_call: + offset += MacroAssembler::load_const_from_toc_size(); + // no break + case lir_static_call: + case lir_optvirtual_call: + case lir_dynamic_call: + offset += NativeCall::call_far_pcrelative_displacement_offset; + break; + case lir_virtual_call: // currently, sparc-specific for niagara + default: ShouldNotReachHere(); + } + if ((offset & (NativeCall::call_far_pcrelative_displacement_alignment-1)) != 0) { + __ nop(); + } +} + +void LIR_Assembler::call(LIR_OpJavaCall* op, relocInfo::relocType rtype) { + assert((__ offset() + NativeCall::call_far_pcrelative_displacement_offset) % NativeCall::call_far_pcrelative_displacement_alignment == 0, + "must be aligned (offset=%d)", __ offset()); + assert(rtype == relocInfo::none || + rtype == relocInfo::opt_virtual_call_type || + rtype == relocInfo::static_call_type, "unexpected rtype"); + // Prepend each BRASL with a nop. + __ relocate(rtype); + __ z_nop(); + __ z_brasl(Z_R14, op->addr()); + add_call_info(code_offset(), op->info()); +} + +void LIR_Assembler::ic_call(LIR_OpJavaCall* op) { + address virtual_call_oop_addr = NULL; + AddressLiteral empty_ic((address) Universe::non_oop_word()); + virtual_call_oop_addr = __ pc(); + bool success = __ load_const_from_toc(Z_inline_cache, empty_ic); + if (!success) { + bailout("const section overflow"); + return; + } + + // CALL to fixup routine. Fixup routine uses ScopeDesc info + // to determine who we intended to call. + __ relocate(virtual_call_Relocation::spec(virtual_call_oop_addr)); + call(op, relocInfo::none); +} + +// not supported +void LIR_Assembler::vtable_call(LIR_OpJavaCall* op) { + ShouldNotReachHere(); +} + +void LIR_Assembler::move_regs(Register from_reg, Register to_reg) { + if (from_reg != to_reg) __ z_lgr(to_reg, from_reg); +} + +void LIR_Assembler::const2stack(LIR_Opr src, LIR_Opr dest) { + assert(src->is_constant(), "should not call otherwise"); + assert(dest->is_stack(), "should not call otherwise"); + LIR_Const* c = src->as_constant_ptr(); + + unsigned int lmem = 0; + unsigned int lcon = 0; + int64_t cbits = 0; + Address dest_addr; + switch (c->type()) { + case T_INT: // fall through + case T_FLOAT: + dest_addr = frame_map()->address_for_slot(dest->single_stack_ix()); + lmem = 4; lcon = 4; cbits = c->as_jint_bits(); + break; + + case T_ADDRESS: + dest_addr = frame_map()->address_for_slot(dest->single_stack_ix()); + lmem = 8; lcon = 4; cbits = c->as_jint_bits(); + break; + + case T_OBJECT: + dest_addr = frame_map()->address_for_slot(dest->single_stack_ix()); + if (c->as_jobject() == NULL) { + __ store_const(dest_addr, (int64_t)NULL_WORD, 8, 8); + } else { + jobject2reg(c->as_jobject(), Z_R1_scratch); + __ reg2mem_opt(Z_R1_scratch, dest_addr, true); + } + return; + + case T_LONG: // fall through + case T_DOUBLE: + dest_addr = frame_map()->address_for_slot(dest->double_stack_ix()); + lmem = 8; lcon = 8; cbits = (int64_t)(c->as_jlong_bits()); + break; + + default: + ShouldNotReachHere(); + } + + __ store_const(dest_addr, cbits, lmem, lcon); +} + +void LIR_Assembler::const2mem(LIR_Opr src, LIR_Opr dest, BasicType type, CodeEmitInfo* info, bool wide) { + assert(src->is_constant(), "should not call otherwise"); + assert(dest->is_address(), "should not call otherwise"); + // See special case in LIRGenerator::do_StoreIndexed. + // T_BYTE: Special case for card mark store. + assert(type == T_BYTE || !dest->as_address_ptr()->index()->is_valid(), "not supported"); + LIR_Const* c = src->as_constant_ptr(); + Address addr = as_Address(dest->as_address_ptr()); + + int store_offset = -1; + unsigned int lmem = 0; + unsigned int lcon = 0; + int64_t cbits = 0; + switch (type) { + case T_INT: // fall through + case T_FLOAT: + lmem = 4; lcon = 4; cbits = c->as_jint_bits(); + break; + + case T_ADDRESS: + lmem = 8; lcon = 4; cbits = c->as_jint_bits(); + break; + + case T_OBJECT: // fall through + case T_ARRAY: + if (c->as_jobject() == NULL) { + if (UseCompressedOops && !wide) { + store_offset = __ store_const(addr, (int32_t)NULL_WORD, 4, 4); + } else { + store_offset = __ store_const(addr, (int64_t)NULL_WORD, 8, 8); + } + } else { + jobject2reg(c->as_jobject(), Z_R1_scratch); + if (UseCompressedOops && !wide) { + __ encode_heap_oop(Z_R1_scratch); + store_offset = __ reg2mem_opt(Z_R1_scratch, addr, false); + } else { + store_offset = __ reg2mem_opt(Z_R1_scratch, addr, true); + } + } + assert(store_offset >= 0, "check"); + break; + + case T_LONG: // fall through + case T_DOUBLE: + lmem = 8; lcon = 8; cbits = (int64_t)(c->as_jlong_bits()); + break; + + case T_BOOLEAN: // fall through + case T_BYTE: + lmem = 1; lcon = 1; cbits = (int8_t)(c->as_jint()); + break; + + case T_CHAR: // fall through + case T_SHORT: + lmem = 2; lcon = 2; cbits = (int16_t)(c->as_jint()); + break; + + default: + ShouldNotReachHere(); + }; + + // Index register is normally not supported, but for + // LIRGenerator::CardTableModRef_post_barrier we make an exception. + if (type == T_BYTE && dest->as_address_ptr()->index()->is_valid()) { + __ load_const_optimized(Z_R0_scratch, (int8_t)(c->as_jint())); + store_offset = __ offset(); + if (Immediate::is_uimm12(addr.disp())) { + __ z_stc(Z_R0_scratch, addr); + } else { + __ z_stcy(Z_R0_scratch, addr); + } + } + + if (store_offset == -1) { + store_offset = __ store_const(addr, cbits, lmem, lcon); + assert(store_offset >= 0, "check"); + } + + if (info != NULL) { + add_debug_info_for_null_check(store_offset, info); + } +} + +void LIR_Assembler::const2reg(LIR_Opr src, LIR_Opr dest, LIR_PatchCode patch_code, CodeEmitInfo* info) { + assert(src->is_constant(), "should not call otherwise"); + assert(dest->is_register(), "should not call otherwise"); + LIR_Const* c = src->as_constant_ptr(); + + switch (c->type()) { + case T_INT: { + assert(patch_code == lir_patch_none, "no patching handled here"); + __ load_const_optimized(dest->as_register(), c->as_jint()); + break; + } + + case T_ADDRESS: { + assert(patch_code == lir_patch_none, "no patching handled here"); + __ load_const_optimized(dest->as_register(), c->as_jint()); + break; + } + + case T_LONG: { + assert(patch_code == lir_patch_none, "no patching handled here"); + __ load_const_optimized(dest->as_register_lo(), (intptr_t)c->as_jlong()); + break; + } + + case T_OBJECT: { + if (patch_code != lir_patch_none) { + jobject2reg_with_patching(dest->as_register(), info); + } else { + jobject2reg(c->as_jobject(), dest->as_register()); + } + break; + } + + case T_METADATA: { + if (patch_code != lir_patch_none) { + klass2reg_with_patching(dest->as_register(), info); + } else { + metadata2reg(c->as_metadata(), dest->as_register()); + } + break; + } + + case T_FLOAT: { + Register toc_reg = Z_R1_scratch; + __ load_toc(toc_reg); + address const_addr = __ float_constant(c->as_jfloat()); + if (const_addr == NULL) { + bailout("const section overflow"); + break; + } + int displ = const_addr - _masm->code()->consts()->start(); + if (dest->is_single_fpu()) { + __ z_ley(dest->as_float_reg(), displ, toc_reg); + } else { + assert(dest->is_single_cpu(), "Must be a cpu register."); + __ z_ly(dest->as_register(), displ, toc_reg); + } + } + break; + + case T_DOUBLE: { + Register toc_reg = Z_R1_scratch; + __ load_toc(toc_reg); + address const_addr = __ double_constant(c->as_jdouble()); + if (const_addr == NULL) { + bailout("const section overflow"); + break; + } + int displ = const_addr - _masm->code()->consts()->start(); + if (dest->is_double_fpu()) { + __ z_ldy(dest->as_double_reg(), displ, toc_reg); + } else { + assert(dest->is_double_cpu(), "Must be a long register."); + __ z_lg(dest->as_register_lo(), displ, toc_reg); + } + } + break; + + default: + ShouldNotReachHere(); + } +} + +Address LIR_Assembler::as_Address(LIR_Address* addr) { + if (addr->base()->is_illegal()) { + Unimplemented(); + } + + Register base = addr->base()->as_pointer_register(); + + if (addr->index()->is_illegal()) { + return Address(base, addr->disp()); + } else if (addr->index()->is_cpu_register()) { + Register index = addr->index()->as_pointer_register(); + return Address(base, index, addr->disp()); + } else if (addr->index()->is_constant()) { + intptr_t addr_offset = addr->index()->as_constant_ptr()->as_jint() + addr->disp(); + return Address(base, addr_offset); + } else { + ShouldNotReachHere(); + return Address(); + } +} + +void LIR_Assembler::stack2stack(LIR_Opr src, LIR_Opr dest, BasicType type) { + switch (type) { + case T_INT: + case T_FLOAT: { + Register tmp = Z_R1_scratch; + Address from = frame_map()->address_for_slot(src->single_stack_ix()); + Address to = frame_map()->address_for_slot(dest->single_stack_ix()); + __ mem2reg_opt(tmp, from, false); + __ reg2mem_opt(tmp, to, false); + break; + } + case T_ADDRESS: + case T_OBJECT: { + Register tmp = Z_R1_scratch; + Address from = frame_map()->address_for_slot(src->single_stack_ix()); + Address to = frame_map()->address_for_slot(dest->single_stack_ix()); + __ mem2reg_opt(tmp, from, true); + __ reg2mem_opt(tmp, to, true); + break; + } + case T_LONG: + case T_DOUBLE: { + Register tmp = Z_R1_scratch; + Address from = frame_map()->address_for_double_slot(src->double_stack_ix()); + Address to = frame_map()->address_for_double_slot(dest->double_stack_ix()); + __ mem2reg_opt(tmp, from, true); + __ reg2mem_opt(tmp, to, true); + break; + } + + default: + ShouldNotReachHere(); + } +} + +// 4-byte accesses only! Don't use it to access 8 bytes! +Address LIR_Assembler::as_Address_hi(LIR_Address* addr) { + ShouldNotCallThis(); + return 0; // unused +} + +// 4-byte accesses only! Don't use it to access 8 bytes! +Address LIR_Assembler::as_Address_lo(LIR_Address* addr) { + ShouldNotCallThis(); + return 0; // unused +} + +void LIR_Assembler::mem2reg(LIR_Opr src_opr, LIR_Opr dest, BasicType type, LIR_PatchCode patch_code, + CodeEmitInfo* info, bool wide, bool unaligned) { + + assert(type != T_METADATA, "load of metadata ptr not supported"); + LIR_Address* addr = src_opr->as_address_ptr(); + LIR_Opr to_reg = dest; + + Register src = addr->base()->as_pointer_register(); + Register disp_reg = Z_R0; + int disp_value = addr->disp(); + bool needs_patching = (patch_code != lir_patch_none); + + if (addr->base()->type() == T_OBJECT) { + __ verify_oop(src); + } + + PatchingStub* patch = NULL; + if (needs_patching) { + patch = new PatchingStub(_masm, PatchingStub::access_field_id); + assert(!to_reg->is_double_cpu() || + patch_code == lir_patch_none || + patch_code == lir_patch_normal, "patching doesn't match register"); + } + + if (addr->index()->is_illegal()) { + if (!Immediate::is_simm20(disp_value)) { + if (needs_patching) { + __ load_const(Z_R1_scratch, (intptr_t)0); + } else { + __ load_const_optimized(Z_R1_scratch, disp_value); + } + disp_reg = Z_R1_scratch; + disp_value = 0; + } + } else { + if (!Immediate::is_simm20(disp_value)) { + __ load_const_optimized(Z_R1_scratch, disp_value); + __ z_la(Z_R1_scratch, 0, Z_R1_scratch, addr->index()->as_register()); + disp_reg = Z_R1_scratch; + disp_value = 0; + } + disp_reg = addr->index()->as_pointer_register(); + } + + // Remember the offset of the load. The patching_epilog must be done + // before the call to add_debug_info, otherwise the PcDescs don't get + // entered in increasing order. + int offset = code_offset(); + + assert(disp_reg != Z_R0 || Immediate::is_simm20(disp_value), "should have set this up"); + + bool short_disp = Immediate::is_uimm12(disp_value); + + switch (type) { + case T_BOOLEAN: // fall through + case T_BYTE : __ z_lb(dest->as_register(), disp_value, disp_reg, src); break; + case T_CHAR : __ z_llgh(dest->as_register(), disp_value, disp_reg, src); break; + case T_SHORT : + if (short_disp) { + __ z_lh(dest->as_register(), disp_value, disp_reg, src); + } else { + __ z_lhy(dest->as_register(), disp_value, disp_reg, src); + } + break; + case T_INT : + if (short_disp) { + __ z_l(dest->as_register(), disp_value, disp_reg, src); + } else { + __ z_ly(dest->as_register(), disp_value, disp_reg, src); + } + break; + case T_ADDRESS: + if (UseCompressedClassPointers && addr->disp() == oopDesc::klass_offset_in_bytes()) { + __ z_llgf(dest->as_register(), disp_value, disp_reg, src); + __ decode_klass_not_null(dest->as_register()); + } else { + __ z_lg(dest->as_register(), disp_value, disp_reg, src); + } + break; + case T_ARRAY : // fall through + case T_OBJECT: + { + if (UseCompressedOops && !wide) { + __ z_llgf(dest->as_register(), disp_value, disp_reg, src); + __ oop_decoder(dest->as_register(), dest->as_register(), true); + } else { + __ z_lg(dest->as_register(), disp_value, disp_reg, src); + } + break; + } + case T_FLOAT: + if (short_disp) { + __ z_le(dest->as_float_reg(), disp_value, disp_reg, src); + } else { + __ z_ley(dest->as_float_reg(), disp_value, disp_reg, src); + } + break; + case T_DOUBLE: + if (short_disp) { + __ z_ld(dest->as_double_reg(), disp_value, disp_reg, src); + } else { + __ z_ldy(dest->as_double_reg(), disp_value, disp_reg, src); + } + break; + case T_LONG : __ z_lg(dest->as_register_lo(), disp_value, disp_reg, src); break; + default : ShouldNotReachHere(); + } + if (type == T_ARRAY || type == T_OBJECT) { + __ verify_oop(dest->as_register()); + } + + if (patch != NULL) { + patching_epilog(patch, patch_code, src, info); + } + if (info != NULL) add_debug_info_for_null_check(offset, info); +} + +void LIR_Assembler::stack2reg(LIR_Opr src, LIR_Opr dest, BasicType type) { + assert(src->is_stack(), "should not call otherwise"); + assert(dest->is_register(), "should not call otherwise"); + + if (dest->is_single_cpu()) { + if (type == T_ARRAY || type == T_OBJECT) { + __ mem2reg_opt(dest->as_register(), frame_map()->address_for_slot(src->single_stack_ix()), true); + __ verify_oop(dest->as_register()); + } else if (type == T_METADATA) { + __ mem2reg_opt(dest->as_register(), frame_map()->address_for_slot(src->single_stack_ix()), true); + } else { + __ mem2reg_opt(dest->as_register(), frame_map()->address_for_slot(src->single_stack_ix()), false); + } + } else if (dest->is_double_cpu()) { + Address src_addr_LO = frame_map()->address_for_slot(src->double_stack_ix()); + __ mem2reg_opt(dest->as_register_lo(), src_addr_LO, true); + } else if (dest->is_single_fpu()) { + Address src_addr = frame_map()->address_for_slot(src->single_stack_ix()); + __ mem2freg_opt(dest->as_float_reg(), src_addr, false); + } else if (dest->is_double_fpu()) { + Address src_addr = frame_map()->address_for_slot(src->double_stack_ix()); + __ mem2freg_opt(dest->as_double_reg(), src_addr, true); + } else { + ShouldNotReachHere(); + } +} + +void LIR_Assembler::reg2stack(LIR_Opr src, LIR_Opr dest, BasicType type, bool pop_fpu_stack) { + assert(src->is_register(), "should not call otherwise"); + assert(dest->is_stack(), "should not call otherwise"); + + if (src->is_single_cpu()) { + const Address dst = frame_map()->address_for_slot(dest->single_stack_ix()); + if (type == T_OBJECT || type == T_ARRAY) { + __ verify_oop(src->as_register()); + __ reg2mem_opt(src->as_register(), dst, true); + } else if (type == T_METADATA) { + __ reg2mem_opt(src->as_register(), dst, true); + } else { + __ reg2mem_opt(src->as_register(), dst, false); + } + } else if (src->is_double_cpu()) { + Address dstLO = frame_map()->address_for_slot(dest->double_stack_ix()); + __ reg2mem_opt(src->as_register_lo(), dstLO, true); + } else if (src->is_single_fpu()) { + Address dst_addr = frame_map()->address_for_slot(dest->single_stack_ix()); + __ freg2mem_opt(src->as_float_reg(), dst_addr, false); + } else if (src->is_double_fpu()) { + Address dst_addr = frame_map()->address_for_slot(dest->double_stack_ix()); + __ freg2mem_opt(src->as_double_reg(), dst_addr, true); + } else { + ShouldNotReachHere(); + } +} + +void LIR_Assembler::reg2reg(LIR_Opr from_reg, LIR_Opr to_reg) { + if (from_reg->is_float_kind() && to_reg->is_float_kind()) { + if (from_reg->is_double_fpu()) { + // double to double moves + assert(to_reg->is_double_fpu(), "should match"); + __ z_ldr(to_reg->as_double_reg(), from_reg->as_double_reg()); + } else { + // float to float moves + assert(to_reg->is_single_fpu(), "should match"); + __ z_ler(to_reg->as_float_reg(), from_reg->as_float_reg()); + } + } else if (!from_reg->is_float_kind() && !to_reg->is_float_kind()) { + if (from_reg->is_double_cpu()) { + __ z_lgr(to_reg->as_pointer_register(), from_reg->as_pointer_register()); + } else if (to_reg->is_double_cpu()) { + // int to int moves + __ z_lgr(to_reg->as_register_lo(), from_reg->as_register()); + } else { + // int to int moves + __ z_lgr(to_reg->as_register(), from_reg->as_register()); + } + } else { + ShouldNotReachHere(); + } + if (to_reg->type() == T_OBJECT || to_reg->type() == T_ARRAY) { + __ verify_oop(to_reg->as_register()); + } +} + +void LIR_Assembler::reg2mem(LIR_Opr from, LIR_Opr dest_opr, BasicType type, + LIR_PatchCode patch_code, CodeEmitInfo* info, bool pop_fpu_stack, + bool wide, bool unaligned) { + assert(type != T_METADATA, "store of metadata ptr not supported"); + LIR_Address* addr = dest_opr->as_address_ptr(); + + Register dest = addr->base()->as_pointer_register(); + Register disp_reg = Z_R0; + int disp_value = addr->disp(); + bool needs_patching = (patch_code != lir_patch_none); + + if (addr->base()->is_oop_register()) { + __ verify_oop(dest); + } + + PatchingStub* patch = NULL; + if (needs_patching) { + patch = new PatchingStub(_masm, PatchingStub::access_field_id); + assert(!from->is_double_cpu() || + patch_code == lir_patch_none || + patch_code == lir_patch_normal, "patching doesn't match register"); + } + + assert(!needs_patching || (!Immediate::is_simm20(disp_value) && addr->index()->is_illegal()), "assumption"); + if (addr->index()->is_illegal()) { + if (!Immediate::is_simm20(disp_value)) { + if (needs_patching) { + __ load_const(Z_R1_scratch, (intptr_t)0); + } else { + __ load_const_optimized(Z_R1_scratch, disp_value); + } + disp_reg = Z_R1_scratch; + disp_value = 0; + } + } else { + if (!Immediate::is_simm20(disp_value)) { + __ load_const_optimized(Z_R1_scratch, disp_value); + __ z_la(Z_R1_scratch, 0, Z_R1_scratch, addr->index()->as_register()); + disp_reg = Z_R1_scratch; + disp_value = 0; + } + disp_reg = addr->index()->as_pointer_register(); + } + + assert(disp_reg != Z_R0 || Immediate::is_simm20(disp_value), "should have set this up"); + + if (type == T_ARRAY || type == T_OBJECT) { + __ verify_oop(from->as_register()); + } + + bool short_disp = Immediate::is_uimm12(disp_value); + + // Remember the offset of the store. The patching_epilog must be done + // before the call to add_debug_info_for_null_check, otherwise the PcDescs don't get + // entered in increasing order. + int offset = code_offset(); + switch (type) { + case T_BOOLEAN: // fall through + case T_BYTE : + if (short_disp) { + __ z_stc(from->as_register(), disp_value, disp_reg, dest); + } else { + __ z_stcy(from->as_register(), disp_value, disp_reg, dest); + } + break; + case T_CHAR : // fall through + case T_SHORT : + if (short_disp) { + __ z_sth(from->as_register(), disp_value, disp_reg, dest); + } else { + __ z_sthy(from->as_register(), disp_value, disp_reg, dest); + } + break; + case T_INT : + if (short_disp) { + __ z_st(from->as_register(), disp_value, disp_reg, dest); + } else { + __ z_sty(from->as_register(), disp_value, disp_reg, dest); + } + break; + case T_LONG : __ z_stg(from->as_register_lo(), disp_value, disp_reg, dest); break; + case T_ADDRESS: __ z_stg(from->as_register(), disp_value, disp_reg, dest); break; + break; + case T_ARRAY : // fall through + case T_OBJECT: + { + if (UseCompressedOops && !wide) { + Register compressed_src = Z_R14; + __ z_lgr(compressed_src, from->as_register()); + __ encode_heap_oop(compressed_src); + offset = code_offset(); + if (short_disp) { + __ z_st(compressed_src, disp_value, disp_reg, dest); + } else { + __ z_sty(compressed_src, disp_value, disp_reg, dest); + } + } else { + __ z_stg(from->as_register(), disp_value, disp_reg, dest); + } + break; + } + case T_FLOAT : + if (short_disp) { + __ z_ste(from->as_float_reg(), disp_value, disp_reg, dest); + } else { + __ z_stey(from->as_float_reg(), disp_value, disp_reg, dest); + } + break; + case T_DOUBLE: + if (short_disp) { + __ z_std(from->as_double_reg(), disp_value, disp_reg, dest); + } else { + __ z_stdy(from->as_double_reg(), disp_value, disp_reg, dest); + } + break; + default: ShouldNotReachHere(); + } + + if (patch != NULL) { + patching_epilog(patch, patch_code, dest, info); + } + + if (info != NULL) add_debug_info_for_null_check(offset, info); +} + + +void LIR_Assembler::return_op(LIR_Opr result) { + assert(result->is_illegal() || + (result->is_single_cpu() && result->as_register() == Z_R2) || + (result->is_double_cpu() && result->as_register_lo() == Z_R2) || + (result->is_single_fpu() && result->as_float_reg() == Z_F0) || + (result->is_double_fpu() && result->as_double_reg() == Z_F0), "convention"); + + AddressLiteral pp(os::get_polling_page()); + __ load_const_optimized(Z_R1_scratch, pp); + + // Pop the frame before the safepoint code. + int retPC_offset = initial_frame_size_in_bytes() + _z_abi16(return_pc); + if (Displacement::is_validDisp(retPC_offset)) { + __ z_lg(Z_R14, retPC_offset, Z_SP); + __ add2reg(Z_SP, initial_frame_size_in_bytes()); + } else { + __ add2reg(Z_SP, initial_frame_size_in_bytes()); + __ restore_return_pc(); + } + + // We need to mark the code position where the load from the safepoint + // polling page was emitted as relocInfo::poll_return_type here. + __ relocate(relocInfo::poll_return_type); + __ load_from_polling_page(Z_R1_scratch); + + __ z_br(Z_R14); // Return to caller. +} + +int LIR_Assembler::safepoint_poll(LIR_Opr tmp, CodeEmitInfo* info) { + AddressLiteral pp(os::get_polling_page()); + __ load_const_optimized(tmp->as_register_lo(), pp); + guarantee(info != NULL, "Shouldn't be NULL"); + add_debug_info_for_branch(info); + int offset = __ offset(); + __ relocate(relocInfo::poll_type); + __ load_from_polling_page(tmp->as_register_lo()); + return offset; +} + +void LIR_Assembler::emit_static_call_stub() { + + // Stub is fixed up when the corresponding call is converted from calling + // compiled code to calling interpreted code. + + address call_pc = __ pc(); + address stub = __ start_a_stub(call_stub_size); + if (stub == NULL) { + bailout("static call stub overflow"); + return; + } + + int start = __ offset(); + + __ relocate(static_stub_Relocation::spec(call_pc)); + + // See also Matcher::interpreter_method_oop_reg(). + AddressLiteral meta = __ allocate_metadata_address(NULL); + bool success = __ load_const_from_toc(Z_method, meta); + + __ set_inst_mark(); + AddressLiteral a((address)-1); + success = success && __ load_const_from_toc(Z_R1, a); + if (!success) { + bailout("const section overflow"); + return; + } + + __ z_br(Z_R1); + assert(__ offset() - start <= call_stub_size, "stub too big"); + __ end_a_stub(); // Update current stubs pointer and restore insts_end. +} + +void LIR_Assembler::comp_op(LIR_Condition condition, LIR_Opr opr1, LIR_Opr opr2, LIR_Op2* op) { + bool unsigned_comp = condition == lir_cond_belowEqual || condition == lir_cond_aboveEqual; + if (opr1->is_single_cpu()) { + Register reg1 = opr1->as_register(); + if (opr2->is_single_cpu()) { + // cpu register - cpu register + if (opr1->type() == T_OBJECT || opr1->type() == T_ARRAY) { + __ z_clgr(reg1, opr2->as_register()); + } else { + assert(opr2->type() != T_OBJECT && opr2->type() != T_ARRAY, "cmp int, oop?"); + if (unsigned_comp) { + __ z_clr(reg1, opr2->as_register()); + } else { + __ z_cr(reg1, opr2->as_register()); + } + } + } else if (opr2->is_stack()) { + // cpu register - stack + if (opr1->type() == T_OBJECT || opr1->type() == T_ARRAY) { + __ z_cg(reg1, frame_map()->address_for_slot(opr2->single_stack_ix())); + } else { + if (unsigned_comp) { + __ z_cly(reg1, frame_map()->address_for_slot(opr2->single_stack_ix())); + } else { + __ z_cy(reg1, frame_map()->address_for_slot(opr2->single_stack_ix())); + } + } + } else if (opr2->is_constant()) { + // cpu register - constant + LIR_Const* c = opr2->as_constant_ptr(); + if (c->type() == T_INT) { + if (unsigned_comp) { + __ z_clfi(reg1, c->as_jint()); + } else { + __ z_cfi(reg1, c->as_jint()); + } + } else if (c->type() == T_OBJECT || c->type() == T_ARRAY) { + // In 64bit oops are single register. + jobject o = c->as_jobject(); + if (o == NULL) { + __ z_ltgr(reg1, reg1); + } else { + jobject2reg(o, Z_R1_scratch); + __ z_cgr(reg1, Z_R1_scratch); + } + } else { + fatal("unexpected type: %s", basictype_to_str(c->type())); + } + // cpu register - address + } else if (opr2->is_address()) { + if (op->info() != NULL) { + add_debug_info_for_null_check_here(op->info()); + } + if (unsigned_comp) { + __ z_cly(reg1, as_Address(opr2->as_address_ptr())); + } else { + __ z_cy(reg1, as_Address(opr2->as_address_ptr())); + } + } else { + ShouldNotReachHere(); + } + + } else if (opr1->is_double_cpu()) { + assert(!unsigned_comp, "unexpected"); + Register xlo = opr1->as_register_lo(); + Register xhi = opr1->as_register_hi(); + if (opr2->is_double_cpu()) { + __ z_cgr(xlo, opr2->as_register_lo()); + } else if (opr2->is_constant()) { + // cpu register - constant 0 + assert(opr2->as_jlong() == (jlong)0, "only handles zero"); + __ z_ltgr(xlo, xlo); + } else { + ShouldNotReachHere(); + } + + } else if (opr1->is_single_fpu()) { + if (opr2->is_single_fpu()) { + __ z_cebr(opr1->as_float_reg(), opr2->as_float_reg()); + } else { + // stack slot + Address addr = frame_map()->address_for_slot(opr2->single_stack_ix()); + if (Immediate::is_uimm12(addr.disp())) { + __ z_ceb(opr1->as_float_reg(), addr); + } else { + __ z_ley(Z_fscratch_1, addr); + __ z_cebr(opr1->as_float_reg(), Z_fscratch_1); + } + } + } else if (opr1->is_double_fpu()) { + if (opr2->is_double_fpu()) { + __ z_cdbr(opr1->as_double_reg(), opr2->as_double_reg()); + } else { + // stack slot + Address addr = frame_map()->address_for_slot(opr2->double_stack_ix()); + if (Immediate::is_uimm12(addr.disp())) { + __ z_cdb(opr1->as_double_reg(), addr); + } else { + __ z_ldy(Z_fscratch_1, addr); + __ z_cdbr(opr1->as_double_reg(), Z_fscratch_1); + } + } + } else { + ShouldNotReachHere(); + } +} + +void LIR_Assembler::comp_fl2i(LIR_Code code, LIR_Opr left, LIR_Opr right, LIR_Opr dst, LIR_Op2* op) { + Label done; + Register dreg = dst->as_register(); + + if (code == lir_cmp_fd2i || code == lir_ucmp_fd2i) { + assert((left->is_single_fpu() && right->is_single_fpu()) || + (left->is_double_fpu() && right->is_double_fpu()), "unexpected operand types"); + bool is_single = left->is_single_fpu(); + bool is_unordered_less = (code == lir_ucmp_fd2i); + FloatRegister lreg = is_single ? left->as_float_reg() : left->as_double_reg(); + FloatRegister rreg = is_single ? right->as_float_reg() : right->as_double_reg(); + if (is_single) { + __ z_cebr(lreg, rreg); + } else { + __ z_cdbr(lreg, rreg); + } + if (VM_Version::has_LoadStoreConditional()) { + Register one = Z_R0_scratch; + Register minus_one = Z_R1_scratch; + __ z_lghi(minus_one, -1); + __ z_lghi(one, 1); + __ z_lghi(dreg, 0); + __ z_locgr(dreg, one, is_unordered_less ? Assembler::bcondHigh : Assembler::bcondHighOrNotOrdered); + __ z_locgr(dreg, minus_one, is_unordered_less ? Assembler::bcondLowOrNotOrdered : Assembler::bcondLow); + } else { + __ clear_reg(dreg, true, false); + __ z_bre(done); // if (left == right) dst = 0 + + // if (left > right || ((code ~= cmpg) && (left <> right)) dst := 1 + __ z_lhi(dreg, 1); + __ z_brc(is_unordered_less ? Assembler::bcondHigh : Assembler::bcondHighOrNotOrdered, done); + + // if (left < right || ((code ~= cmpl) && (left <> right)) dst := -1 + __ z_lhi(dreg, -1); + } + } else { + assert(code == lir_cmp_l2i, "check"); + if (VM_Version::has_LoadStoreConditional()) { + Register one = Z_R0_scratch; + Register minus_one = Z_R1_scratch; + __ z_cgr(left->as_register_lo(), right->as_register_lo()); + __ z_lghi(minus_one, -1); + __ z_lghi(one, 1); + __ z_lghi(dreg, 0); + __ z_locgr(dreg, one, Assembler::bcondHigh); + __ z_locgr(dreg, minus_one, Assembler::bcondLow); + } else { + __ z_cgr(left->as_register_lo(), right->as_register_lo()); + __ z_lghi(dreg, 0); // eq value + __ z_bre(done); + __ z_lghi(dreg, 1); // gt value + __ z_brh(done); + __ z_lghi(dreg, -1); // lt value + } + } + __ bind(done); +} + +// result = condition ? opr1 : opr2 +void LIR_Assembler::cmove(LIR_Condition condition, LIR_Opr opr1, LIR_Opr opr2, LIR_Opr result, BasicType type) { + Assembler::branch_condition acond = Assembler::bcondEqual, ncond = Assembler::bcondNotEqual; + switch (condition) { + case lir_cond_equal: acond = Assembler::bcondEqual; ncond = Assembler::bcondNotEqual; break; + case lir_cond_notEqual: acond = Assembler::bcondNotEqual; ncond = Assembler::bcondEqual; break; + case lir_cond_less: acond = Assembler::bcondLow; ncond = Assembler::bcondNotLow; break; + case lir_cond_lessEqual: acond = Assembler::bcondNotHigh; ncond = Assembler::bcondHigh; break; + case lir_cond_greaterEqual: acond = Assembler::bcondNotLow; ncond = Assembler::bcondLow; break; + case lir_cond_greater: acond = Assembler::bcondHigh; ncond = Assembler::bcondNotHigh; break; + case lir_cond_belowEqual: acond = Assembler::bcondNotHigh; ncond = Assembler::bcondHigh; break; + case lir_cond_aboveEqual: acond = Assembler::bcondNotLow; ncond = Assembler::bcondLow; break; + default: ShouldNotReachHere(); + } + + if (opr1->is_cpu_register()) { + reg2reg(opr1, result); + } else if (opr1->is_stack()) { + stack2reg(opr1, result, result->type()); + } else if (opr1->is_constant()) { + const2reg(opr1, result, lir_patch_none, NULL); + } else { + ShouldNotReachHere(); + } + + if (VM_Version::has_LoadStoreConditional() && !opr2->is_constant()) { + // Optimized version that does not require a branch. + if (opr2->is_single_cpu()) { + assert(opr2->cpu_regnr() != result->cpu_regnr(), "opr2 already overwritten by previous move"); + __ z_locgr(result->as_register(), opr2->as_register(), ncond); + } else if (opr2->is_double_cpu()) { + assert(opr2->cpu_regnrLo() != result->cpu_regnrLo() && opr2->cpu_regnrLo() != result->cpu_regnrHi(), "opr2 already overwritten by previous move"); + assert(opr2->cpu_regnrHi() != result->cpu_regnrLo() && opr2->cpu_regnrHi() != result->cpu_regnrHi(), "opr2 already overwritten by previous move"); + __ z_locgr(result->as_register_lo(), opr2->as_register_lo(), ncond); + } else if (opr2->is_single_stack()) { + __ z_loc(result->as_register(), frame_map()->address_for_slot(opr2->single_stack_ix()), ncond); + } else if (opr2->is_double_stack()) { + __ z_locg(result->as_register_lo(), frame_map()->address_for_slot(opr2->double_stack_ix()), ncond); + } else { + ShouldNotReachHere(); + } + } else { + Label skip; + __ z_brc(acond, skip); + if (opr2->is_cpu_register()) { + reg2reg(opr2, result); + } else if (opr2->is_stack()) { + stack2reg(opr2, result, result->type()); + } else if (opr2->is_constant()) { + const2reg(opr2, result, lir_patch_none, NULL); + } else { + ShouldNotReachHere(); + } + __ bind(skip); + } +} + +void LIR_Assembler::arith_op(LIR_Code code, LIR_Opr left, LIR_Opr right, LIR_Opr dest, + CodeEmitInfo* info, bool pop_fpu_stack) { + assert(info == NULL, "should never be used, idiv/irem and ldiv/lrem not handled by this method"); + + if (left->is_single_cpu()) { + assert(left == dest, "left and dest must be equal"); + Register lreg = left->as_register(); + + if (right->is_single_cpu()) { + // cpu register - cpu register + Register rreg = right->as_register(); + switch (code) { + case lir_add: __ z_ar (lreg, rreg); break; + case lir_sub: __ z_sr (lreg, rreg); break; + case lir_mul: __ z_msr(lreg, rreg); break; + default: ShouldNotReachHere(); + } + + } else if (right->is_stack()) { + // cpu register - stack + Address raddr = frame_map()->address_for_slot(right->single_stack_ix()); + switch (code) { + case lir_add: __ z_ay(lreg, raddr); break; + case lir_sub: __ z_sy(lreg, raddr); break; + default: ShouldNotReachHere(); + } + + } else if (right->is_constant()) { + // cpu register - constant + jint c = right->as_constant_ptr()->as_jint(); + switch (code) { + case lir_add: __ z_agfi(lreg, c); break; + case lir_sub: __ z_agfi(lreg, -c); break; // note: -min_jint == min_jint + case lir_mul: __ z_msfi(lreg, c); break; + default: ShouldNotReachHere(); + } + + } else { + ShouldNotReachHere(); + } + + } else if (left->is_double_cpu()) { + assert(left == dest, "left and dest must be equal"); + Register lreg_lo = left->as_register_lo(); + Register lreg_hi = left->as_register_hi(); + + if (right->is_double_cpu()) { + // cpu register - cpu register + Register rreg_lo = right->as_register_lo(); + Register rreg_hi = right->as_register_hi(); + assert_different_registers(lreg_lo, rreg_lo); + switch (code) { + case lir_add: + __ z_agr(lreg_lo, rreg_lo); + break; + case lir_sub: + __ z_sgr(lreg_lo, rreg_lo); + break; + case lir_mul: + __ z_msgr(lreg_lo, rreg_lo); + break; + default: + ShouldNotReachHere(); + } + + } else if (right->is_constant()) { + // cpu register - constant + jlong c = right->as_constant_ptr()->as_jlong_bits(); + switch (code) { + case lir_add: __ z_agfi(lreg_lo, c); break; + case lir_sub: + if (c != min_jint) { + __ z_agfi(lreg_lo, -c); + } else { + // -min_jint cannot be represented as simm32 in z_agfi + // min_jint sign extended: 0xffffffff80000000 + // -min_jint as 64 bit integer: 0x0000000080000000 + // 0x80000000 can be represented as uimm32 in z_algfi + // lreg_lo := lreg_lo + -min_jint == lreg_lo + 0x80000000 + __ z_algfi(lreg_lo, UCONST64(0x80000000)); + } + break; + case lir_mul: __ z_msgfi(lreg_lo, c); break; + default: + ShouldNotReachHere(); + } + + } else { + ShouldNotReachHere(); + } + + } else if (left->is_single_fpu()) { + assert(left == dest, "left and dest must be equal"); + FloatRegister lreg = left->as_float_reg(); + FloatRegister rreg = right->is_single_fpu() ? right->as_float_reg() : fnoreg; + Address raddr; + + if (rreg == fnoreg) { + assert(right->is_single_stack(), "constants should be loaded into register"); + raddr = frame_map()->address_for_slot(right->single_stack_ix()); + if (!Immediate::is_uimm12(raddr.disp())) { + __ mem2freg_opt(rreg = Z_fscratch_1, raddr, false); + } + } + + if (rreg != fnoreg) { + switch (code) { + case lir_add: __ z_aebr(lreg, rreg); break; + case lir_sub: __ z_sebr(lreg, rreg); break; + case lir_mul_strictfp: // fall through + case lir_mul: __ z_meebr(lreg, rreg); break; + case lir_div_strictfp: // fall through + case lir_div: __ z_debr(lreg, rreg); break; + default: ShouldNotReachHere(); + } + } else { + switch (code) { + case lir_add: __ z_aeb(lreg, raddr); break; + case lir_sub: __ z_seb(lreg, raddr); break; + case lir_mul_strictfp: // fall through + case lir_mul: __ z_meeb(lreg, raddr); break; + case lir_div_strictfp: // fall through + case lir_div: __ z_deb(lreg, raddr); break; + default: ShouldNotReachHere(); + } + } + } else if (left->is_double_fpu()) { + assert(left == dest, "left and dest must be equal"); + FloatRegister lreg = left->as_double_reg(); + FloatRegister rreg = right->is_double_fpu() ? right->as_double_reg() : fnoreg; + Address raddr; + + if (rreg == fnoreg) { + assert(right->is_double_stack(), "constants should be loaded into register"); + raddr = frame_map()->address_for_slot(right->double_stack_ix()); + if (!Immediate::is_uimm12(raddr.disp())) { + __ mem2freg_opt(rreg = Z_fscratch_1, raddr, true); + } + } + + if (rreg != fnoreg) { + switch (code) { + case lir_add: __ z_adbr(lreg, rreg); break; + case lir_sub: __ z_sdbr(lreg, rreg); break; + case lir_mul_strictfp: // fall through + case lir_mul: __ z_mdbr(lreg, rreg); break; + case lir_div_strictfp: // fall through + case lir_div: __ z_ddbr(lreg, rreg); break; + default: ShouldNotReachHere(); + } + } else { + switch (code) { + case lir_add: __ z_adb(lreg, raddr); break; + case lir_sub: __ z_sdb(lreg, raddr); break; + case lir_mul_strictfp: // fall through + case lir_mul: __ z_mdb(lreg, raddr); break; + case lir_div_strictfp: // fall through + case lir_div: __ z_ddb(lreg, raddr); break; + default: ShouldNotReachHere(); + } + } + } else if (left->is_address()) { + assert(left == dest, "left and dest must be equal"); + assert(code == lir_add, "unsupported operation"); + assert(right->is_constant(), "unsupported operand"); + jint c = right->as_constant_ptr()->as_jint(); + LIR_Address* lir_addr = left->as_address_ptr(); + Address addr = as_Address(lir_addr); + switch (lir_addr->type()) { + case T_INT: + __ add2mem_32(addr, c, Z_R1_scratch); + break; + case T_LONG: + __ add2mem_64(addr, c, Z_R1_scratch); + break; + default: + ShouldNotReachHere(); + } + } else { + ShouldNotReachHere(); + } +} + +void LIR_Assembler::fpop() { + // do nothing +} + +void LIR_Assembler::intrinsic_op(LIR_Code code, LIR_Opr value, LIR_Opr thread, LIR_Opr dest, LIR_Op* op) { + switch (code) { + case lir_sqrt: { + assert(!thread->is_valid(), "there is no need for a thread_reg for dsqrt"); + FloatRegister src_reg = value->as_double_reg(); + FloatRegister dst_reg = dest->as_double_reg(); + __ z_sqdbr(dst_reg, src_reg); + break; + } + case lir_abs: { + assert(!thread->is_valid(), "there is no need for a thread_reg for fabs"); + FloatRegister src_reg = value->as_double_reg(); + FloatRegister dst_reg = dest->as_double_reg(); + __ z_lpdbr(dst_reg, src_reg); + break; + } + default: { + ShouldNotReachHere(); + break; + } + } +} + +void LIR_Assembler::logic_op(LIR_Code code, LIR_Opr left, LIR_Opr right, LIR_Opr dst) { + if (left->is_single_cpu()) { + Register reg = left->as_register(); + if (right->is_constant()) { + int val = right->as_constant_ptr()->as_jint(); + switch (code) { + case lir_logic_and: __ z_nilf(reg, val); break; + case lir_logic_or: __ z_oilf(reg, val); break; + case lir_logic_xor: __ z_xilf(reg, val); break; + default: ShouldNotReachHere(); + } + } else if (right->is_stack()) { + Address raddr = frame_map()->address_for_slot(right->single_stack_ix()); + switch (code) { + case lir_logic_and: __ z_ny(reg, raddr); break; + case lir_logic_or: __ z_oy(reg, raddr); break; + case lir_logic_xor: __ z_xy(reg, raddr); break; + default: ShouldNotReachHere(); + } + } else { + Register rright = right->as_register(); + switch (code) { + case lir_logic_and: __ z_nr(reg, rright); break; + case lir_logic_or : __ z_or(reg, rright); break; + case lir_logic_xor: __ z_xr(reg, rright); break; + default: ShouldNotReachHere(); + } + } + move_regs(reg, dst->as_register()); + } else { + Register l_lo = left->as_register_lo(); + if (right->is_constant()) { + __ load_const_optimized(Z_R1_scratch, right->as_constant_ptr()->as_jlong()); + switch (code) { + case lir_logic_and: + __ z_ngr(l_lo, Z_R1_scratch); + break; + case lir_logic_or: + __ z_ogr(l_lo, Z_R1_scratch); + break; + case lir_logic_xor: + __ z_xgr(l_lo, Z_R1_scratch); + break; + default: ShouldNotReachHere(); + } + } else { + Register r_lo; + if (right->type() == T_OBJECT || right->type() == T_ARRAY) { + r_lo = right->as_register(); + } else { + r_lo = right->as_register_lo(); + } + switch (code) { + case lir_logic_and: + __ z_ngr(l_lo, r_lo); + break; + case lir_logic_or: + __ z_ogr(l_lo, r_lo); + break; + case lir_logic_xor: + __ z_xgr(l_lo, r_lo); + break; + default: ShouldNotReachHere(); + } + } + + Register dst_lo = dst->as_register_lo(); + + move_regs(l_lo, dst_lo); + } +} + +// See operand selection in LIRGenerator::do_ArithmeticOp_Int(). +void LIR_Assembler::arithmetic_idiv(LIR_Code code, LIR_Opr left, LIR_Opr right, LIR_Opr temp, LIR_Opr result, CodeEmitInfo* info) { + if (left->is_double_cpu()) { + // 64 bit integer case + assert(left->is_double_cpu(), "left must be register"); + assert(right->is_double_cpu() || is_power_of_2_long(right->as_jlong()), + "right must be register or power of 2 constant"); + assert(result->is_double_cpu(), "result must be register"); + + Register lreg = left->as_register_lo(); + Register dreg = result->as_register_lo(); + + if (right->is_constant()) { + // Convert division by a power of two into some shifts and logical operations. + Register treg1 = Z_R0_scratch; + Register treg2 = Z_R1_scratch; + jlong divisor = right->as_jlong(); + jlong log_divisor = log2_long(right->as_jlong()); + + if (divisor == min_jlong) { + // Min_jlong is special. Result is '0' except for min_jlong/min_jlong = 1. + if (dreg == lreg) { + NearLabel done; + __ load_const_optimized(treg2, min_jlong); + __ z_cgr(lreg, treg2); + __ z_lghi(dreg, 0); // Preserves condition code. + __ z_brne(done); + __ z_lghi(dreg, 1); // min_jlong / min_jlong = 1 + __ bind(done); + } else { + assert_different_registers(dreg, lreg); + NearLabel done; + __ z_lghi(dreg, 0); + __ compare64_and_branch(lreg, min_jlong, Assembler::bcondNotEqual, done); + __ z_lghi(dreg, 1); + __ bind(done); + } + return; + } + __ move_reg_if_needed(dreg, T_LONG, lreg, T_LONG); + if (divisor == 2) { + __ z_srlg(treg2, dreg, 63); // dividend < 0 ? 1 : 0 + } else { + __ z_srag(treg2, dreg, 63); // dividend < 0 ? -1 : 0 + __ and_imm(treg2, divisor - 1, treg1, true); + } + if (code == lir_idiv) { + __ z_agr(dreg, treg2); + __ z_srag(dreg, dreg, log_divisor); + } else { + assert(code == lir_irem, "check"); + __ z_agr(treg2, dreg); + __ and_imm(treg2, ~(divisor - 1), treg1, true); + __ z_sgr(dreg, treg2); + } + return; + } + + // Divisor is not a power of 2 constant. + Register rreg = right->as_register_lo(); + Register treg = temp->as_register_lo(); + assert(right->is_double_cpu(), "right must be register"); + assert(lreg == Z_R11, "see ldivInOpr()"); + assert(rreg != lreg, "right register must not be same as left register"); + assert((code == lir_idiv && dreg == Z_R11 && treg == Z_R10) || + (code == lir_irem && dreg == Z_R10 && treg == Z_R11), "see ldivInOpr(), ldivOutOpr(), lremOutOpr()"); + + Register R1 = lreg->predecessor(); + Register R2 = rreg; + assert(code != lir_idiv || lreg==dreg, "see code below"); + if (code == lir_idiv) { + __ z_lcgr(lreg, lreg); + } else { + __ clear_reg(dreg, true, false); + } + NearLabel done; + __ compare64_and_branch(R2, -1, Assembler::bcondEqual, done); + if (code == lir_idiv) { + __ z_lcgr(lreg, lreg); // Revert lcgr above. + } + if (ImplicitDiv0Checks) { + // No debug info because the idiv won't trap. + // Add_debug_info_for_div0 would instantiate another DivByZeroStub, + // which is unnecessary, too. + add_debug_info_for_div0(__ offset(), info); + } + __ z_dsgr(R1, R2); + __ bind(done); + return; + } + + // 32 bit integer case + + assert(left->is_single_cpu(), "left must be register"); + assert(right->is_single_cpu() || is_power_of_2(right->as_jint()), "right must be register or power of 2 constant"); + assert(result->is_single_cpu(), "result must be register"); + + Register lreg = left->as_register(); + Register dreg = result->as_register(); + + if (right->is_constant()) { + // Convert division by a power of two into some shifts and logical operations. + Register treg1 = Z_R0_scratch; + Register treg2 = Z_R1_scratch; + jlong divisor = right->as_jint(); + jlong log_divisor = log2_long(right->as_jint()); + __ move_reg_if_needed(dreg, T_LONG, lreg, T_INT); // sign extend + if (divisor == 2) { + __ z_srlg(treg2, dreg, 63); // dividend < 0 ? 1 : 0 + } else { + __ z_srag(treg2, dreg, 63); // dividend < 0 ? -1 : 0 + __ and_imm(treg2, divisor - 1, treg1, true); + } + if (code == lir_idiv) { + __ z_agr(dreg, treg2); + __ z_srag(dreg, dreg, log_divisor); + } else { + assert(code == lir_irem, "check"); + __ z_agr(treg2, dreg); + __ and_imm(treg2, ~(divisor - 1), treg1, true); + __ z_sgr(dreg, treg2); + } + return; + } + + // Divisor is not a power of 2 constant. + Register rreg = right->as_register(); + Register treg = temp->as_register(); + assert(right->is_single_cpu(), "right must be register"); + assert(lreg == Z_R11, "left register must be rax,"); + assert(rreg != lreg, "right register must not be same as left register"); + assert((code == lir_idiv && dreg == Z_R11 && treg == Z_R10) + || (code == lir_irem && dreg == Z_R10 && treg == Z_R11), "see divInOpr(), divOutOpr(), remOutOpr()"); + + Register R1 = lreg->predecessor(); + Register R2 = rreg; + __ move_reg_if_needed(lreg, T_LONG, lreg, T_INT); // sign extend + if (ImplicitDiv0Checks) { + // No debug info because the idiv won't trap. + // Add_debug_info_for_div0 would instantiate another DivByZeroStub, + // which is unnecessary, too. + add_debug_info_for_div0(__ offset(), info); + } + __ z_dsgfr(R1, R2); +} + +void LIR_Assembler::throw_op(LIR_Opr exceptionPC, LIR_Opr exceptionOop, CodeEmitInfo* info) { + assert(exceptionOop->as_register() == Z_EXC_OOP, "should match"); + assert(exceptionPC->as_register() == Z_EXC_PC, "should match"); + + // Exception object is not added to oop map by LinearScan + // (LinearScan assumes that no oops are in fixed registers). + info->add_register_oop(exceptionOop); + + // Reuse the debug info from the safepoint poll for the throw op itself. + __ get_PC(Z_EXC_PC); + add_call_info(__ offset(), info); // for exception handler + address stub = Runtime1::entry_for (compilation()->has_fpu_code() ? Runtime1::handle_exception_id + : Runtime1::handle_exception_nofpu_id); + emit_call_c(stub); +} + +void LIR_Assembler::unwind_op(LIR_Opr exceptionOop) { + assert(exceptionOop->as_register() == Z_EXC_OOP, "should match"); + + __ branch_optimized(Assembler::bcondAlways, _unwind_handler_entry); +} + +void LIR_Assembler::emit_arraycopy(LIR_OpArrayCopy* op) { + ciArrayKlass* default_type = op->expected_type(); + Register src = op->src()->as_register(); + Register dst = op->dst()->as_register(); + Register src_pos = op->src_pos()->as_register(); + Register dst_pos = op->dst_pos()->as_register(); + Register length = op->length()->as_register(); + Register tmp = op->tmp()->as_register(); + + CodeStub* stub = op->stub(); + int flags = op->flags(); + BasicType basic_type = default_type != NULL ? default_type->element_type()->basic_type() : T_ILLEGAL; + if (basic_type == T_ARRAY) basic_type = T_OBJECT; + + // If we don't know anything, just go through the generic arraycopy. + if (default_type == NULL) { + Label done; + // Save outgoing arguments in callee saved registers (C convention) in case + // a call to System.arraycopy is needed. + Register callee_saved_src = Z_R10; + Register callee_saved_src_pos = Z_R11; + Register callee_saved_dst = Z_R12; + Register callee_saved_dst_pos = Z_R13; + Register callee_saved_length = Z_ARG5; // Z_ARG5 == Z_R6 is callee saved. + + __ lgr_if_needed(callee_saved_src, src); + __ lgr_if_needed(callee_saved_src_pos, src_pos); + __ lgr_if_needed(callee_saved_dst, dst); + __ lgr_if_needed(callee_saved_dst_pos, dst_pos); + __ lgr_if_needed(callee_saved_length, length); + + // C function requires 64 bit values. + __ z_lgfr(src_pos, src_pos); + __ z_lgfr(dst_pos, dst_pos); + __ z_lgfr(length, length); + + address C_entry = CAST_FROM_FN_PTR(address, Runtime1::arraycopy); + + address copyfunc_addr = StubRoutines::generic_arraycopy(); + + // Pass arguments: may push as this is not a safepoint; SP must be fix at each safepoint. + + // The arguments are in the corresponding registers. + assert(Z_ARG1 == src, "assumption"); + assert(Z_ARG2 == src_pos, "assumption"); + assert(Z_ARG3 == dst, "assumption"); + assert(Z_ARG4 == dst_pos, "assumption"); + assert(Z_ARG5 == length, "assumption"); + if (copyfunc_addr == NULL) { // Use C version if stub was not generated. + emit_call_c(C_entry); + } else { +#ifndef PRODUCT + if (PrintC1Statistics) { + __ load_const_optimized(Z_R1_scratch, (address)&Runtime1::_generic_arraycopystub_cnt); + __ add2mem_32(Address(Z_R1_scratch), 1, Z_R0_scratch); + } +#endif + emit_call_c(copyfunc_addr); + } + CHECK_BAILOUT(); + + __ compare32_and_branch(Z_RET, (intptr_t)0, Assembler::bcondEqual, *stub->continuation()); + + if (copyfunc_addr != NULL) { + __ z_lgr(tmp, Z_RET); + __ z_xilf(tmp, -1); + } + + // Restore values from callee saved registers so they are where the stub + // expects them. + __ lgr_if_needed(src, callee_saved_src); + __ lgr_if_needed(src_pos, callee_saved_src_pos); + __ lgr_if_needed(dst, callee_saved_dst); + __ lgr_if_needed(dst_pos, callee_saved_dst_pos); + __