@@ -762,24 +762,6 @@ static inline void emit_alu64_imm32(struct jit_state *state,
762762 emit_alu64 (state , op , src , dst );
763763 emit4 (state , imm );
764764}
765- #elif defined(__aarch64__ )
766- static void divmod (struct jit_state * state ,
767- uint8_t opcode ,
768- int rd ,
769- int rn ,
770- int rm )
771- {
772- bool mod = (opcode & JIT_ALU_OP_MASK ) == (JIT_OP_MOD_IMM & JIT_ALU_OP_MASK );
773- bool is64 = (opcode & JIT_CLS_MASK ) == JIT_CLS_ALU64 ;
774- int div_dest = mod ? temp_div_reg : rd ;
775-
776- /* Do not need to treet divide by zero as special because the UDIV
777- * instruction already returns 0 when dividing by zero.
778- */
779- emit_dataproc_2source (state , is64 , DP2_UDIV , div_dest , rn , rm );
780- if (mod )
781- emit_dataproc_3source (state , is64 , DP3_MSUB , rd , rm , div_dest , rn );
782- }
783765#endif
784766
785767static inline void emit_cmp_imm32 (struct jit_state * state , int dst , int32_t imm )
@@ -1035,33 +1017,78 @@ static inline void emit_exit(struct jit_state *state)
10351017#endif
10361018}
10371019
1038- /* TODO: muldivmod is incomplete, it does not handle imm or overflow now */
10391020#if RV32_HAS (EXT_M )
1021+ #if defined(__x86_64__ )
1022+ static inline void emit_conditional_move (struct jit_state * state ,
1023+ int src ,
1024+ int dst )
1025+ {
1026+ emit1 (state , 0x48 );
1027+ emit1 (state , 0x0f );
1028+ emit1 (state , 0x44 );
1029+ emit_modrm_reg2reg (state , dst , src );
1030+ }
1031+ #elif defined(__aarch64__ )
1032+ static inline void emit_conditional_move (struct jit_state * state ,
1033+ int rd ,
1034+ int rn ,
1035+ int rm ,
1036+ int cond )
1037+ {
1038+ emit_a64 (state , 0x1a800000 | (rm << 16 ) | (cond << 12 ) | (rn << 5 ) | rd );
1039+ set_dirty (rd , true);
1040+ }
1041+
1042+ static void divmod (struct jit_state * state ,
1043+ uint8_t opcode ,
1044+ int rd ,
1045+ int rn ,
1046+ int rm ,
1047+ bool sign )
1048+ {
1049+ bool mod = (opcode & JIT_ALU_OP_MASK ) == (JIT_OP_MOD_IMM & JIT_ALU_OP_MASK );
1050+ bool is64 = (opcode & JIT_CLS_MASK ) == JIT_CLS_ALU64 ;
1051+ int div_dest = mod ? temp_div_reg : rd ;
1052+
1053+ if (sign )
1054+ emit_cmp_imm32 (state , rd , 0x80000000 ); /* overflow checking */
1055+
1056+ emit_dataproc_2source (state , is64 , DP2_UDIV , div_dest , rn , rm );
1057+ if (mod )
1058+ emit_dataproc_3source (state , is64 , DP3_MSUB , rd , rm , div_dest , rn );
1059+
1060+ if (sign ) {
1061+ /* handle overflow */
1062+ uint32_t jump_loc = state -> offset ;
1063+ emit_jcc_offset (state , 0x85 );
1064+ emit_cmp_imm32 (state , rm , -1 );
1065+ if (mod )
1066+ emit_load_imm (state , R10 , 0 );
1067+ else
1068+ emit_load_imm (state , R10 , 0x80000000 );
1069+ emit_conditional_move (state , rd , R10 , rd , COND_EQ );
1070+ emit_jump_target_offset (state , JUMP_LOC , state -> offset );
1071+ }
1072+ if (!mod ) {
1073+ /* handle dividing zero */
1074+ emit_cmp_imm32 (state , rm , 0 );
1075+ emit_load_imm (state , temp_reg , -1 );
1076+ emit_conditional_move (state , rd , temp_reg , rd , COND_EQ );
1077+ }
1078+ }
1079+ #endif
1080+
10401081static void muldivmod (struct jit_state * state ,
10411082 uint8_t opcode ,
10421083 int src ,
10431084 int dst ,
1044- int32_t imm UNUSED )
1085+ bool sign )
10451086{
10461087#if defined(__x86_64__ )
10471088 bool mul = (opcode & JIT_ALU_OP_MASK ) == (JIT_OP_MUL_IMM & JIT_ALU_OP_MASK );
10481089 bool div = (opcode & JIT_ALU_OP_MASK ) == (JIT_OP_DIV_IMM & JIT_ALU_OP_MASK );
10491090 bool mod = (opcode & JIT_ALU_OP_MASK ) == (JIT_OP_MOD_IMM & JIT_ALU_OP_MASK );
10501091 bool is64 = (opcode & JIT_CLS_MASK ) == JIT_CLS_ALU64 ;
1051- bool reg = (opcode & JIT_SRC_REG ) == JIT_SRC_REG ;
1052-
1053- /* Short circuit for imm == 0 */
1054- if (!reg && imm == 0 ) {
1055- assert (NULL );
1056- if (div || mul ) {
1057- /* For division and multiplication, set result to zero. */
1058- emit_alu32 (state , 0x31 , dst , dst );
1059- } else {
1060- /* For modulo, set result to dividend. */
1061- emit_mov (state , dst , dst );
1062- }
1063- return ;
1064- }
10651092
10661093 /* Record the mapping status before the registers are used for other
10671094 * purposes, and restore the status after popping the registers.
@@ -1080,51 +1107,44 @@ static void muldivmod(struct jit_state *state,
10801107 }
10811108
10821109 /* Load the divisor into RCX */
1083- if (imm )
1084- emit_load_imm (state , RCX , imm );
1085- else
1086- emit_mov (state , src , RCX );
1110+ emit_mov (state , src , RCX );
10871111
10881112 /* Load the dividend into RAX */
10891113 emit_mov (state , dst , RAX );
10901114
10911115 /* The JIT employs two different semantics for division and modulus
10921116 * operations. In the case of division, if the divisor is zero, the result
1093- * is set to zero . For modulus operations, if the divisor is zero, the
1117+ * is set to -1 . For modulus operations, if the divisor is zero, the
10941118 * result becomes the dividend. To manage this, we first set the divisor to
10951119 * 1 if it is initially zero. Then, we adjust the result accordingly: for
1096- * division, we set it to zero if the original divisor was zero; for
1120+ * division, we set it to -1 if the original divisor was zero; for
10971121 * modulus, we set it to the dividend under the same condition.
10981122 */
10991123
11001124 if (div || mod ) {
1101- /* Check if divisor is zero */
1102- if ( is64 )
1103- emit_alu64 ( state , 0x85 , RCX , RCX );
1104- else
1105- emit_alu32 ( state , 0x85 , RCX , RCX );
1106-
1107- /* Save the dividend for the modulo case */
1108- if (mod )
1125+ if ( sign ) {
1126+ emit_load_imm ( state , RDX , -1 );
1127+ /* compare divisor with -1 for overflow checking */
1128+ emit_cmp32 ( state , RDX , RCX );
1129+ /* Save the result of the comparision */
1130+ emit1 ( state , 0x9c ); /* pushfq */
1131+ }
1132+ if (mod || ( div && sign ) )
11091133 emit_push (state , RAX ); /* Save dividend */
11101134
1135+ emit_alu32 (state , 0x85 , RCX , RCX );
11111136 /* Save the result of the test */
11121137 emit1 (state , 0x9c ); /* pushfq */
11131138
11141139 /* Set the divisor to 1 if it is zero */
11151140 emit_load_imm (state , RDX , 1 );
1116- emit1 (state , 0x48 );
1117- emit1 (state , 0x0f );
1118- emit1 (state , 0x44 );
1119- emit1 (state , 0xca ); /* cmove rcx, rdx */
1120-
1141+ emit_conditional_move (state , RDX , RCX );
11211142 /* xor %edx,%edx */
11221143 emit_alu32 (state , 0x31 , RDX , RDX );
11231144 }
11241145
11251146 if (is64 )
11261147 emit_rex (state , 1 , 0 , 0 , 0 );
1127-
11281148 /* Multiply or divide */
11291149 emit_alu32 (state , 0xf7 , mul ? 4 : 6 , RCX );
11301150
@@ -1139,24 +1159,37 @@ static void muldivmod(struct jit_state *state,
11391159
11401160 if (div ) {
11411161 /* Set the dividend to zero if the divisor was zero. */
1142- emit_load_imm (state , RCX , 0 );
1162+ emit_load_imm (state , RCX , -1 );
11431163
11441164 /* Store 0 in RAX if the divisor was zero. */
11451165 /* Use conditional move to avoid a branch. */
1146- emit1 (state , 0x48 );
1147- emit1 (state , 0x0f );
1148- emit1 (state , 0x44 );
1149- emit1 (state , 0xc1 ); /* cmove rax, rcx */
1166+ emit_conditional_move (state , RCX , RAX );
1167+ if (sign ) {
1168+ emit_pop (state , RCX );
1169+ /* handle DIV overflow */
1170+ emit1 (state , 0x9d ); /* popfq */
1171+ uint32_t jump_loc = state -> offset ;
1172+ emit_jcc_offset (state , 0x85 );
1173+ emit_cmp_imm32 (state , RCX , 0x80000000 );
1174+ emit_conditional_move (state , RCX , RAX );
1175+ emit_jump_target_offset (state , JUMP_LOC , state -> offset );
1176+ }
11501177 } else {
11511178 /* Restore dividend to RCX */
11521179 emit_pop (state , RCX );
1153-
11541180 /* Store the dividend in RAX if the divisor was zero. */
11551181 /* Use conditional move to avoid a branch. */
1156- emit1 (state , 0x48 );
1157- emit1 (state , 0x0f );
1158- emit1 (state , 0x44 );
1159- emit1 (state , 0xd1 ); /* cmove rdx, rcx */
1182+ emit_conditional_move (state , RCX , RDX );
1183+ if (sign ) {
1184+ /* handle REM overflow */
1185+ emit1 (state , 0x9d ); /* popfq */
1186+ uint32_t jump_loc = state -> offset ;
1187+ emit_jcc_offset (state , 0x85 );
1188+ emit_cmp_imm32 (state , RCX , 0x80000000 );
1189+ emit_load_imm (state , RCX , 0 );
1190+ emit_conditional_move (state , RCX , RDX );
1191+ emit_jump_target_offset (state , JUMP_LOC , state -> offset );
1192+ }
11601193 }
11611194 }
11621195
@@ -1183,10 +1216,10 @@ static void muldivmod(struct jit_state *state,
11831216 emit_dataproc_3source (state , true, DP3_MADD , dst , dst , src , RZ );
11841217 break ;
11851218 case 0x38 :
1186- divmod (state , JIT_OP_DIV_REG , dst , dst , src );
1219+ divmod (state , JIT_OP_DIV_REG , dst , dst , src , sign );
11871220 break ;
11881221 case 0x98 :
1189- divmod (state , JIT_OP_MOD_REG , dst , dst , src );
1222+ divmod (state , JIT_OP_MOD_REG , dst , dst , src , sign );
11901223 break ;
11911224 default :
11921225 __UNREACHABLE ;
0 commit comments