xref: /qemu/target/s390x/tcg/int_helper.c (revision a47dddd7348d3e75ad650ef5e2ca9c3b13a600ac)
1fc8d72c2SBlue Swirl /*
2fc8d72c2SBlue Swirl  *  S/390 integer helper routines
3fc8d72c2SBlue Swirl  *
4fc8d72c2SBlue Swirl  *  Copyright (c) 2009 Ulrich Hecht
5fc8d72c2SBlue Swirl  *  Copyright (c) 2009 Alexander Graf
6fc8d72c2SBlue Swirl  *
7fc8d72c2SBlue Swirl  * This library is free software; you can redistribute it and/or
8fc8d72c2SBlue Swirl  * modify it under the terms of the GNU Lesser General Public
9fc8d72c2SBlue Swirl  * License as published by the Free Software Foundation; either
10fc8d72c2SBlue Swirl  * version 2 of the License, or (at your option) any later version.
11fc8d72c2SBlue Swirl  *
12fc8d72c2SBlue Swirl  * This library is distributed in the hope that it will be useful,
13fc8d72c2SBlue Swirl  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14fc8d72c2SBlue Swirl  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15fc8d72c2SBlue Swirl  * Lesser General Public License for more details.
16fc8d72c2SBlue Swirl  *
17fc8d72c2SBlue Swirl  * You should have received a copy of the GNU Lesser General Public
18fc8d72c2SBlue Swirl  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
19fc8d72c2SBlue Swirl  */
20fc8d72c2SBlue Swirl 
21fc8d72c2SBlue Swirl #include "cpu.h"
221de7afc9SPaolo Bonzini #include "qemu/host-utils.h"
23fc8d72c2SBlue Swirl #include "helper.h"
24fc8d72c2SBlue Swirl 
25fc8d72c2SBlue Swirl /* #define DEBUG_HELPER */
26fc8d72c2SBlue Swirl #ifdef DEBUG_HELPER
27fc8d72c2SBlue Swirl #define HELPER_LOG(x...) qemu_log(x)
28fc8d72c2SBlue Swirl #else
29fc8d72c2SBlue Swirl #define HELPER_LOG(x...)
30fc8d72c2SBlue Swirl #endif
31fc8d72c2SBlue Swirl 
32891452e5SRichard Henderson /* 64/32 -> 32 signed division */
33b4e2bd35SRichard Henderson int64_t HELPER(divs32)(CPUS390XState *env, int64_t a, int64_t b64)
34fc8d72c2SBlue Swirl {
35b4e2bd35SRichard Henderson     int32_t ret, b = b64;
36b4e2bd35SRichard Henderson     int64_t q;
37b4e2bd35SRichard Henderson 
38b4e2bd35SRichard Henderson     if (b == 0) {
39b4e2bd35SRichard Henderson         runtime_exception(env, PGM_FIXPT_DIVIDE, GETPC());
40b4e2bd35SRichard Henderson     }
41b4e2bd35SRichard Henderson 
42b4e2bd35SRichard Henderson     ret = q = a / b;
43b4e2bd35SRichard Henderson     env->retxl = a % b;
44b4e2bd35SRichard Henderson 
45b4e2bd35SRichard Henderson     /* Catch non-representable quotient.  */
46b4e2bd35SRichard Henderson     if (ret != q) {
47b4e2bd35SRichard Henderson         runtime_exception(env, PGM_FIXPT_DIVIDE, GETPC());
48b4e2bd35SRichard Henderson     }
49b4e2bd35SRichard Henderson 
50b4e2bd35SRichard Henderson     return ret;
51891452e5SRichard Henderson }
52fc8d72c2SBlue Swirl 
53891452e5SRichard Henderson /* 64/32 -> 32 unsigned division */
54b4e2bd35SRichard Henderson uint64_t HELPER(divu32)(CPUS390XState *env, uint64_t a, uint64_t b64)
55891452e5SRichard Henderson {
56b4e2bd35SRichard Henderson     uint32_t ret, b = b64;
57b4e2bd35SRichard Henderson     uint64_t q;
58b4e2bd35SRichard Henderson 
59b4e2bd35SRichard Henderson     if (b == 0) {
60b4e2bd35SRichard Henderson         runtime_exception(env, PGM_FIXPT_DIVIDE, GETPC());
61b4e2bd35SRichard Henderson     }
62b4e2bd35SRichard Henderson 
63b4e2bd35SRichard Henderson     ret = q = a / b;
64b4e2bd35SRichard Henderson     env->retxl = a % b;
65b4e2bd35SRichard Henderson 
66b4e2bd35SRichard Henderson     /* Catch non-representable quotient.  */
67b4e2bd35SRichard Henderson     if (ret != q) {
68b4e2bd35SRichard Henderson         runtime_exception(env, PGM_FIXPT_DIVIDE, GETPC());
69b4e2bd35SRichard Henderson     }
70b4e2bd35SRichard Henderson 
71b4e2bd35SRichard Henderson     return ret;
72891452e5SRichard Henderson }
73891452e5SRichard Henderson 
74891452e5SRichard Henderson /* 64/64 -> 64 signed division */
75891452e5SRichard Henderson int64_t HELPER(divs64)(CPUS390XState *env, int64_t a, int64_t b)
76891452e5SRichard Henderson {
77b4e2bd35SRichard Henderson     /* Catch divide by zero, and non-representable quotient (MIN / -1).  */
78b4e2bd35SRichard Henderson     if (b == 0 || (b == -1 && a == (1ll << 63))) {
79b4e2bd35SRichard Henderson         runtime_exception(env, PGM_FIXPT_DIVIDE, GETPC());
80b4e2bd35SRichard Henderson     }
81891452e5SRichard Henderson     env->retxl = a % b;
82891452e5SRichard Henderson     return a / b;
83891452e5SRichard Henderson }
84891452e5SRichard Henderson 
85891452e5SRichard Henderson /* 128 -> 64/64 unsigned division */
86891452e5SRichard Henderson uint64_t HELPER(divu64)(CPUS390XState *env, uint64_t ah, uint64_t al,
87891452e5SRichard Henderson                         uint64_t b)
88891452e5SRichard Henderson {
89891452e5SRichard Henderson     uint64_t ret;
90b4e2bd35SRichard Henderson     /* Signal divide by zero.  */
91b4e2bd35SRichard Henderson     if (b == 0) {
92b4e2bd35SRichard Henderson         runtime_exception(env, PGM_FIXPT_DIVIDE, GETPC());
93b4e2bd35SRichard Henderson     }
94891452e5SRichard Henderson     if (ah == 0) {
95fc8d72c2SBlue Swirl         /* 64 -> 64/64 case */
96891452e5SRichard Henderson         env->retxl = al % b;
97891452e5SRichard Henderson         ret = al / b;
98fc8d72c2SBlue Swirl     } else {
99891452e5SRichard Henderson         /* ??? Move i386 idivq helper to host-utils.  */
100d49b8e0bSGabriel Kerneis #ifdef CONFIG_INT128
101891452e5SRichard Henderson         __uint128_t a = ((__uint128_t)ah << 64) | al;
102891452e5SRichard Henderson         __uint128_t q = a / b;
103891452e5SRichard Henderson         env->retxl = a % b;
104891452e5SRichard Henderson         ret = q;
105b4e2bd35SRichard Henderson         if (ret != q) {
106b4e2bd35SRichard Henderson             runtime_exception(env, PGM_FIXPT_DIVIDE, GETPC());
107b4e2bd35SRichard Henderson         }
108fc8d72c2SBlue Swirl #else
109a47dddd7SAndreas Färber         S390CPU *cpu = s390_env_get_cpu(env);
110fc8d72c2SBlue Swirl         /* 32-bit hosts would need special wrapper functionality - just abort if
111fc8d72c2SBlue Swirl            we encounter such a case; it's very unlikely anyways. */
112a47dddd7SAndreas Färber         cpu_abort(CPU(cpu), "128 -> 64/64 division not implemented\n");
113fc8d72c2SBlue Swirl #endif
114fc8d72c2SBlue Swirl     }
115891452e5SRichard Henderson     return ret;
116fc8d72c2SBlue Swirl }
117fc8d72c2SBlue Swirl 
118fc8d72c2SBlue Swirl /* absolute value 32-bit */
119fc8d72c2SBlue Swirl uint32_t HELPER(abs_i32)(int32_t val)
120fc8d72c2SBlue Swirl {
121fc8d72c2SBlue Swirl     if (val < 0) {
122fc8d72c2SBlue Swirl         return -val;
123fc8d72c2SBlue Swirl     } else {
124fc8d72c2SBlue Swirl         return val;
125fc8d72c2SBlue Swirl     }
126fc8d72c2SBlue Swirl }
127fc8d72c2SBlue Swirl 
128fc8d72c2SBlue Swirl /* negative absolute value 32-bit */
129fc8d72c2SBlue Swirl int32_t HELPER(nabs_i32)(int32_t val)
130fc8d72c2SBlue Swirl {
131fc8d72c2SBlue Swirl     if (val < 0) {
132fc8d72c2SBlue Swirl         return val;
133fc8d72c2SBlue Swirl     } else {
134fc8d72c2SBlue Swirl         return -val;
135fc8d72c2SBlue Swirl     }
136fc8d72c2SBlue Swirl }
137fc8d72c2SBlue Swirl 
138fc8d72c2SBlue Swirl /* absolute value 64-bit */
139fc8d72c2SBlue Swirl uint64_t HELPER(abs_i64)(int64_t val)
140fc8d72c2SBlue Swirl {
141fc8d72c2SBlue Swirl     HELPER_LOG("%s: val 0x%" PRIx64 "\n", __func__, val);
142fc8d72c2SBlue Swirl 
143fc8d72c2SBlue Swirl     if (val < 0) {
144fc8d72c2SBlue Swirl         return -val;
145fc8d72c2SBlue Swirl     } else {
146fc8d72c2SBlue Swirl         return val;
147fc8d72c2SBlue Swirl     }
148fc8d72c2SBlue Swirl }
149fc8d72c2SBlue Swirl 
150fc8d72c2SBlue Swirl /* negative absolute value 64-bit */
151fc8d72c2SBlue Swirl int64_t HELPER(nabs_i64)(int64_t val)
152fc8d72c2SBlue Swirl {
153fc8d72c2SBlue Swirl     if (val < 0) {
154fc8d72c2SBlue Swirl         return val;
155fc8d72c2SBlue Swirl     } else {
156fc8d72c2SBlue Swirl         return -val;
157fc8d72c2SBlue Swirl     }
158fc8d72c2SBlue Swirl }
159fc8d72c2SBlue Swirl 
160102bf2c6SRichard Henderson /* count leading zeros, for find leftmost one */
161102bf2c6SRichard Henderson uint64_t HELPER(clz)(uint64_t v)
162fc8d72c2SBlue Swirl {
163102bf2c6SRichard Henderson     return clz64(v);
164fc8d72c2SBlue Swirl }
165fc8d72c2SBlue Swirl 
166fc8d72c2SBlue Swirl uint64_t HELPER(cvd)(int32_t bin)
167fc8d72c2SBlue Swirl {
168fc8d72c2SBlue Swirl     /* positive 0 */
169fc8d72c2SBlue Swirl     uint64_t dec = 0x0c;
170fc8d72c2SBlue Swirl     int shift = 4;
171fc8d72c2SBlue Swirl 
172fc8d72c2SBlue Swirl     if (bin < 0) {
173fc8d72c2SBlue Swirl         bin = -bin;
174fc8d72c2SBlue Swirl         dec = 0x0d;
175fc8d72c2SBlue Swirl     }
176fc8d72c2SBlue Swirl 
177fc8d72c2SBlue Swirl     for (shift = 4; (shift < 64) && bin; shift += 4) {
178fc8d72c2SBlue Swirl         int current_number = bin % 10;
179fc8d72c2SBlue Swirl 
180fc8d72c2SBlue Swirl         dec |= (current_number) << shift;
181fc8d72c2SBlue Swirl         bin /= 10;
182fc8d72c2SBlue Swirl     }
183fc8d72c2SBlue Swirl 
184fc8d72c2SBlue Swirl     return dec;
185fc8d72c2SBlue Swirl }
18699b4f24bSRichard Henderson 
18799b4f24bSRichard Henderson uint64_t HELPER(popcnt)(uint64_t r2)
18899b4f24bSRichard Henderson {
18999b4f24bSRichard Henderson     uint64_t ret = 0;
19099b4f24bSRichard Henderson     int i;
19199b4f24bSRichard Henderson 
19299b4f24bSRichard Henderson     for (i = 0; i < 64; i += 8) {
19399b4f24bSRichard Henderson         uint64_t t = ctpop32((r2 >> i) & 0xff);
19499b4f24bSRichard Henderson         ret |= t << i;
19599b4f24bSRichard Henderson     }
19699b4f24bSRichard Henderson     return ret;
19799b4f24bSRichard Henderson }
198