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