1 /*
  2  * Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved.
  3  * Copyright (c) 2014, Red Hat Inc. All rights reserved.
  4  * Copyright (c) 2020, 2021, Huawei Technologies Co., Ltd. All rights reserved.
  5  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  6  *
  7  * This code is free software; you can redistribute it and/or modify it
  8  * under the terms of the GNU General Public License version 2 only, as
  9  * published by the Free Software Foundation.
 10  *
 11  * This code is distributed in the hope that it will be useful, but WITHOUT
 12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 14  * version 2 for more details (a copy is included in the LICENSE file that
 15  * accompanied this code).
 16  *
 17  * You should have received a copy of the GNU General Public License version
 18  * 2 along with this work; if not, write to the Free Software Foundation,
 19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 20  *
 21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 22  * or visit www.oracle.com if you need additional information or have any
 23  * questions.
 24  *
 25  */
 26 
 27 #include "precompiled.hpp"
 28 #include "asm/assembler.hpp"
 29 #include "c1/c1_LIRAssembler.hpp"
 30 #include "c1/c1_MacroAssembler.hpp"
 31 
 32 #ifndef PRODUCT
 33 #define COMMENT(x)   do { __ block_comment(x); } while (0)
 34 #else
 35 #define COMMENT(x)
 36 #endif
 37 
 38 #define __ _masm->
 39 
 40 void LIR_Assembler::arithmetic_idiv(LIR_Code code, LIR_Opr left, LIR_Opr right, LIR_Opr illegal,
 41                                     LIR_Opr result, CodeEmitInfo* info) {
 42   // opcode check
 43   assert((code == lir_idiv) || (code == lir_irem), "opcode must be idiv or irem");
 44   bool is_irem = (code == lir_irem);
 45   // opreand check
 46   assert(left->is_single_cpu(), "left must be a register");
 47   assert(right->is_single_cpu() || right->is_constant(), "right must be a register or constant");
 48   assert(result->is_single_cpu(), "result must be a register");
 49   Register lreg = left->as_register();
 50   Register dreg = result->as_register();
 51 
 52   // power-of-2 constant check and codegen
 53   if (right->is_constant()) {
 54     int c = right->as_constant_ptr()->as_jint();
 55     assert(c > 0 && is_power_of_2(c), "divisor must be power-of-2 constant");
 56     if (is_irem) {
 57       if (c == 1) {
 58         // move 0 to dreg if divisor is 1
 59         __ mv(dreg, zr);
 60       } else {
 61         unsigned int shift = log2i_exact(c);
 62         __ sraiw(t0, lreg, 0x1f);
 63         __ srliw(t0, t0, BitsPerInt - shift);
 64         __ addw(t1, lreg, t0);
 65         if (is_imm_in_range(c - 1, 12, 0)) {
 66           __ andi(t1, t1, c - 1);
 67         } else {
 68           __ slli(t1, t1, registerSize - shift);
 69           __ srli(t1, t1, registerSize - shift);
 70         }
 71         __ subw(dreg, t1, t0);
 72       }
 73     } else {
 74       if (c == 1) {
 75         // move lreg to dreg if divisor is 1
 76         __ mv(dreg, lreg);
 77       } else {
 78         unsigned int shift = log2i_exact(c);
 79         __ sraiw(t0, lreg, 0x1f);
 80         if (is_imm_in_range(c - 1, 12, 0)) {
 81           __ andi(t0, t0, c - 1);
 82         } else {
 83           __ slli(t0, t0, registerSize - shift);
 84           __ srli(t0, t0, registerSize - shift);
 85         }
 86         __ addw(dreg, t0, lreg);
 87         __ sraiw(dreg, dreg, shift);
 88       }
 89     }
 90   } else {
 91     Register rreg = right->as_register();
 92     __ corrected_idivl(dreg, lreg, rreg, is_irem);
 93   }
 94 }
 95 
 96 void LIR_Assembler::arith_op_single_cpu_right_constant(LIR_Code code, LIR_Opr left, LIR_Opr right,
 97                                                        Register lreg, Register dreg) {
 98   // cpu register - constant
 99   jlong c;
100 
101   switch (right->type()) {
102     case T_LONG:
103       c = right->as_constant_ptr()->as_jlong(); break;
104     case T_INT:     // fall through
105     case T_ADDRESS:
106       c = right->as_constant_ptr()->as_jint(); break;
107     default:
108       ShouldNotReachHere();
109       c = 0;   // unreachable
110   }
111 
112   assert(code == lir_add || code == lir_sub, "mismatched arithmetic op");
113   if (c == 0 && dreg == lreg) {
114     COMMENT("effective nop elided");
115     return;
116   }
117   switch (left->type()) {
118     case T_INT:
119       switch (code) {
120         case lir_add: __ addw(dreg, lreg, c); break;
121         case lir_sub: __ subw(dreg, lreg, c); break;
122         default:      ShouldNotReachHere();
123       }
124     break;
125     case T_OBJECT:  // fall through
126     case T_ADDRESS:
127       switch (code) {
128         case lir_add: __ add(dreg, lreg, c); break;
129         case lir_sub: __ sub(dreg, lreg, c); break;
130         default:      ShouldNotReachHere();
131       }
132     break;
133     default:
134       ShouldNotReachHere();
135   }
136 }
137 
138 void LIR_Assembler::arith_op_single_cpu(LIR_Code code, LIR_Opr left, LIR_Opr right, LIR_Opr dest) {
139   Register lreg = left->as_register();
140   Register dreg = as_reg(dest);
141 
142   if (right->is_single_cpu()) {
143     // cpu register - cpu register
144     assert(left->type() == T_INT && right->type() == T_INT && dest->type() == T_INT, "should be");
145     Register rreg = right->as_register();
146     switch (code) {
147       case lir_add: __ addw(dest->as_register(), lreg, rreg); break;
148       case lir_sub: __ subw(dest->as_register(), lreg, rreg); break;
149       case lir_mul: __ mulw(dest->as_register(), lreg, rreg); break;
150       default:      ShouldNotReachHere();
151     }
152   } else if (right->is_double_cpu()) {
153     Register rreg = right->as_register_lo();
154     // sigle_cpu + double_cpu; can happen with obj_long
155     assert(code == lir_add || code == lir_sub, "mismatched arithmetic op");
156     switch (code) {
157       case lir_add: __ add(dreg, lreg, rreg); break;
158       case lir_sub: __ sub(dreg, lreg, rreg); break;
159       default:      ShouldNotReachHere();
160     }
161   } else if (right->is_constant()) {
162     arith_op_single_cpu_right_constant(code, left, right, lreg, dreg);
163   } else {
164     ShouldNotReachHere();
165   }
166 }
167 
168 void LIR_Assembler::arith_op_double_cpu(LIR_Code code, LIR_Opr left, LIR_Opr right, LIR_Opr dest) {
169   Register lreg_lo = left->as_register_lo();
170 
171   if (right->is_double_cpu()) {
172     // cpu register - cpu register
173     Register rreg_lo = right->as_register_lo();
174     switch (code) {
175       case lir_add: __ add(dest->as_register_lo(), lreg_lo, rreg_lo); break;
176       case lir_sub: __ sub(dest->as_register_lo(), lreg_lo, rreg_lo); break;
177       case lir_mul: __ mul(dest->as_register_lo(), lreg_lo, rreg_lo); break;
178       case lir_div: __ corrected_idivq(dest->as_register_lo(), lreg_lo, rreg_lo, false); break;
179       case lir_rem: __ corrected_idivq(dest->as_register_lo(), lreg_lo, rreg_lo, true); break;
180       default:
181         ShouldNotReachHere();
182     }
183   } else if (right->is_constant()) {
184     jlong c = right->as_constant_ptr()->as_jlong();
185     Register dreg = as_reg(dest);
186     switch (code) {
187       case lir_add: // fall through
188       case lir_sub:
189         if (c == 0 && dreg == lreg_lo) {
190           COMMENT("effective nop elided");
191           return;
192         }
193         code == lir_add ? __ add(dreg, lreg_lo, c) : __ sub(dreg, lreg_lo, c);
194         break;
195       case lir_div:
196         assert(c > 0 && is_power_of_2(c), "divisor must be power-of-2 constant");
197         if (c == 1) {
198           // move lreg_lo to dreg if divisor is 1
199           __ mv(dreg, lreg_lo);
200         } else {
201           unsigned int shift = log2i_exact(c);
202           // use t0 as intermediate result register
203           __ srai(t0, lreg_lo, 0x3f);
204           if (is_imm_in_range(c - 1, 12, 0)) {
205             __ andi(t0, t0, c - 1);
206           } else {
207             __ slli(t0, t0, registerSize - shift);
208             __ srli(t0, t0, registerSize - shift);
209           }
210           __ add(dreg, t0, lreg_lo);
211           __ srai(dreg, dreg, shift);
212         }
213         break;
214       case lir_rem:
215         assert(c > 0 && is_power_of_2(c), "divisor must be power-of-2 constant");
216         if (c == 1) {
217           // move 0 to dreg if divisor is 1
218           __ mv(dreg, zr);
219         } else {
220           unsigned int shift = log2i_exact(c);
221           __ srai(t0, lreg_lo, 0x3f);
222           __ srli(t0, t0, BitsPerLong - shift);
223           __ add(t1, lreg_lo, t0);
224           if (is_imm_in_range(c - 1, 12, 0)) {
225             __ andi(t1, t1, c - 1);
226           } else {
227             __ slli(t1, t1, registerSize - shift);
228             __ srli(t1, t1, registerSize - shift);
229           }
230           __ sub(dreg, t1, t0);
231         }
232         break;
233       default:
234         ShouldNotReachHere();
235     }
236   } else {
237     ShouldNotReachHere();
238   }
239 }
240 
241 void LIR_Assembler::arith_op_single_fpu(LIR_Code code, LIR_Opr left, LIR_Opr right, LIR_Opr dest) {
242   assert(right->is_single_fpu(), "right hand side of float arithmetics needs to be float register");
243   switch (code) {
244     case lir_add: __ fadd_s(dest->as_float_reg(), left->as_float_reg(), right->as_float_reg()); break;
245     case lir_sub: __ fsub_s(dest->as_float_reg(), left->as_float_reg(), right->as_float_reg()); break;
246     case lir_mul: __ fmul_s(dest->as_float_reg(), left->as_float_reg(), right->as_float_reg()); break;
247     case lir_div: __ fdiv_s(dest->as_float_reg(), left->as_float_reg(), right->as_float_reg()); break;
248     default:
249       ShouldNotReachHere();
250   }
251 }
252 
253 void LIR_Assembler::arith_op_double_fpu(LIR_Code code, LIR_Opr left, LIR_Opr right, LIR_Opr dest) {
254   if (right->is_double_fpu()) {
255     // fpu register - fpu register
256     switch (code) {
257       case lir_add: __ fadd_d(dest->as_double_reg(), left->as_double_reg(), right->as_double_reg()); break;
258       case lir_sub: __ fsub_d(dest->as_double_reg(), left->as_double_reg(), right->as_double_reg()); break;
259       case lir_mul: __ fmul_d(dest->as_double_reg(), left->as_double_reg(), right->as_double_reg()); break;
260       case lir_div: __ fdiv_d(dest->as_double_reg(), left->as_double_reg(), right->as_double_reg()); break;
261       default:
262         ShouldNotReachHere();
263     }
264   } else {
265     ShouldNotReachHere();
266   }
267 }
268 
269 void LIR_Assembler::arith_op(LIR_Code code, LIR_Opr left, LIR_Opr right, LIR_Opr dest,
270                              CodeEmitInfo* info, bool pop_fpu_stack) {
271   assert(info == NULL, "should never be used, idiv/irem and ldiv/lrem not handled by this method");
272 
273   if (left->is_single_cpu()) {
274     arith_op_single_cpu(code, left, right, dest);
275   } else if (left->is_double_cpu()) {
276     arith_op_double_cpu(code, left, right, dest);
277   } else if (left->is_single_fpu()) {
278     arith_op_single_fpu(code, left, right, dest);
279   } else if (left->is_double_fpu()) {
280     arith_op_double_fpu(code, left, right, dest);
281   } else {
282     ShouldNotReachHere();
283   }
284 }
285 
286 #undef __