diff options
| author | gingerBill <gingerBill@users.noreply.github.com> | 2025-08-10 17:42:49 +0100 |
|---|---|---|
| committer | gingerBill <gingerBill@users.noreply.github.com> | 2025-08-10 17:42:49 +0100 |
| commit | da76c743e9b7c88f2f15bbee1dba3b2ab6ebc0b0 (patch) | |
| tree | f4422e7ad9a497f47af3ac67d0524ddc289110ac /src/llvm_backend_expr.cpp | |
| parent | ecb6b35da561bfdaf89c0d39865a93abc26c3ad0 (diff) | |
Add shortcut for division by a constant
Diffstat (limited to 'src/llvm_backend_expr.cpp')
| -rw-r--r-- | src/llvm_backend_expr.cpp | 127 |
1 files changed, 87 insertions, 40 deletions
diff --git a/src/llvm_backend_expr.cpp b/src/llvm_backend_expr.cpp index a29682874..13c6082fb 100644 --- a/src/llvm_backend_expr.cpp +++ b/src/llvm_backend_expr.cpp @@ -1139,8 +1139,23 @@ gb_internal LLVMValueRef lb_integer_division(lbProcedure *p, LLVMValueRef lhs, L LLVMTypeRef type = LLVMTypeOf(rhs); GB_ASSERT(LLVMTypeOf(lhs) == type); + LLVMValueRef zero = LLVMConstNull(type); + auto behaviour = lb_check_for_integer_division_by_zero_behaviour(p); + auto *call = is_signed ? LLVMBuildSDiv : LLVMBuildUDiv; + if (LLVMIsConstant(rhs)) { + if (LLVMIsNull(rhs)) { + switch (behaviour) { + case IntegerDivisionByZero_Self: + return lhs; + case IntegerDivisionByZero_Zero: + return zero; + } + } else { + return call(p->builder, lhs, rhs, ""); + } + } LLVMValueRef incoming_values[2] = {}; LLVMBasicBlockRef incoming_blocks[2] = {}; @@ -1149,7 +1164,6 @@ gb_internal LLVMValueRef lb_integer_division(lbProcedure *p, LLVMValueRef lhs, L lbBlock *edge_case_block = lb_create_block(p, "div.edge"); lbBlock *done_block = lb_create_block(p, "div.done"); - LLVMValueRef zero = LLVMConstNull(type); LLVMValueRef dem_check = LLVMBuildICmp(p->builder, LLVMIntNE, rhs, zero, ""); lbValue cond = {dem_check, t_untyped_bool}; @@ -1157,13 +1171,12 @@ gb_internal LLVMValueRef lb_integer_division(lbProcedure *p, LLVMValueRef lhs, L lb_start_block(p, safe_block); incoming_values[0] = call(p->builder, lhs, rhs, ""); - lb_emit_jump(p, done_block); lb_start_block(p, edge_case_block); - switch (lb_check_for_integer_division_by_zero_behaviour(p)) { + switch (behaviour) { case IntegerDivisionByZero_Trap: lb_call_intrinsic(p, "llvm.trap", nullptr, 0, nullptr, 0); LLVMBuildUnreachable(p->builder); @@ -1181,7 +1194,7 @@ gb_internal LLVMValueRef lb_integer_division(lbProcedure *p, LLVMValueRef lhs, L LLVMValueRef res = incoming_values[0]; - switch (lb_check_for_integer_division_by_zero_behaviour(p)) { + switch (behaviour) { case IntegerDivisionByZero_Trap: case IntegerDivisionByZero_Self: res = incoming_values[0]; @@ -1204,6 +1217,33 @@ gb_internal LLVMValueRef lb_integer_division_intrinsics(lbProcedure *p, LLVMValu LLVMTypeRef type = LLVMTypeOf(rhs); GB_ASSERT(LLVMTypeOf(lhs) == type); + LLVMValueRef zero = LLVMConstNull(type); + auto behaviour = lb_check_for_integer_division_by_zero_behaviour(p); + + auto const do_op = [&]() -> LLVMValueRef { + LLVMTypeRef types[1] = {lb_type(p->module, platform_type)}; + + LLVMValueRef args[3] = { + lhs, + rhs, + scale }; + + return lb_call_intrinsic(p, name, args, gb_count_of(args), types, gb_count_of(types)); + }; + + if (LLVMIsConstant(rhs)) { + if (LLVMIsNull(rhs)) { + switch (behaviour) { + case IntegerDivisionByZero_Self: + return lhs; + case IntegerDivisionByZero_Zero: + return zero; + } + } else { + return do_op(); + } + } + LLVMValueRef incoming_values[2] = {}; LLVMBasicBlockRef incoming_blocks[2] = {}; @@ -1211,31 +1251,19 @@ gb_internal LLVMValueRef lb_integer_division_intrinsics(lbProcedure *p, LLVMValu lbBlock *edge_case_block = lb_create_block(p, "div.edge"); lbBlock *done_block = lb_create_block(p, "div.done"); - LLVMValueRef zero = LLVMConstNull(type); LLVMValueRef dem_check = LLVMBuildICmp(p->builder, LLVMIntNE, rhs, zero, ""); lbValue cond = {dem_check, t_untyped_bool}; lb_emit_if(p, cond, safe_block, edge_case_block); lb_start_block(p, safe_block); - - { - LLVMTypeRef types[1] = {lb_type(p->module, platform_type)}; - - LLVMValueRef args[3] = { - lhs, - rhs, - scale }; - - incoming_values[0] = lb_call_intrinsic(p, name, args, gb_count_of(args), types, gb_count_of(types)); - } - + incoming_values[0] = do_op(); lb_emit_jump(p, done_block); lb_start_block(p, edge_case_block); - switch (lb_check_for_integer_division_by_zero_behaviour(p)) { + switch (behaviour) { case IntegerDivisionByZero_Trap: lb_call_intrinsic(p, "llvm.trap", nullptr, 0, nullptr, 0); LLVMBuildUnreachable(p->builder); @@ -1253,7 +1281,7 @@ gb_internal LLVMValueRef lb_integer_division_intrinsics(lbProcedure *p, LLVMValu LLVMValueRef res = incoming_values[0]; - switch (lb_check_for_integer_division_by_zero_behaviour(p)) { + switch (behaviour) { case IntegerDivisionByZero_Trap: case IntegerDivisionByZero_Self: res = incoming_values[0]; @@ -1277,6 +1305,42 @@ gb_internal LLVMValueRef lb_integer_modulo(lbProcedure *p, LLVMValueRef lhs, LLV LLVMTypeRef type = LLVMTypeOf(rhs); GB_ASSERT(LLVMTypeOf(lhs) == type); + LLVMValueRef zero = LLVMConstNull(type); + auto behaviour = lb_check_for_integer_division_by_zero_behaviour(p); + + auto const do_op = [&]() -> LLVMValueRef { + if (is_floored) { // %% + if (is_unsigned) { + return LLVMBuildURem(p->builder, lhs, rhs, ""); + } else { + LLVMValueRef a = LLVMBuildSRem(p->builder, lhs, rhs, ""); + LLVMValueRef b = LLVMBuildAdd(p->builder, a, rhs, ""); + LLVMValueRef c = LLVMBuildSRem(p->builder, b, rhs, ""); + return c; + } + } else { // % + if (is_unsigned) { + return LLVMBuildURem(p->builder, lhs, rhs, ""); + } else { + return LLVMBuildSRem(p->builder, lhs, rhs, ""); + } + } + }; + + if (LLVMIsConstant(rhs)) { + if (LLVMIsNull(rhs)) { + switch (behaviour) { + case IntegerDivisionByZero_Self: + return zero; + case IntegerDivisionByZero_Zero: + return lhs; + } + } else { + return do_op(); + } + } + + LLVMValueRef incoming_values[2] = {}; LLVMBasicBlockRef incoming_blocks[2] = {}; @@ -1284,31 +1348,13 @@ gb_internal LLVMValueRef lb_integer_modulo(lbProcedure *p, LLVMValueRef lhs, LLV lbBlock *edge_case_block = lb_create_block(p, "div.edge"); lbBlock *done_block = lb_create_block(p, "div.done"); - LLVMValueRef zero = LLVMConstNull(type); LLVMValueRef dem_check = LLVMBuildICmp(p->builder, LLVMIntNE, rhs, zero, ""); lbValue cond = {dem_check, t_untyped_bool}; lb_emit_if(p, cond, safe_block, edge_case_block); lb_start_block(p, safe_block); - - if (is_floored) { // %% - if (is_unsigned) { - incoming_values[0] = LLVMBuildURem(p->builder, lhs, rhs, ""); - } else { - LLVMValueRef a = LLVMBuildSRem(p->builder, lhs, rhs, ""); - LLVMValueRef b = LLVMBuildAdd(p->builder, a, rhs, ""); - LLVMValueRef c = LLVMBuildSRem(p->builder, b, rhs, ""); - incoming_values[0] = c; - } - } else { // % - if (is_unsigned) { - incoming_values[0] = LLVMBuildURem(p->builder, lhs, rhs, ""); - } else { - incoming_values[0] = LLVMBuildSRem(p->builder, lhs, rhs, ""); - } - } - + incoming_values[0] = do_op(); lb_emit_jump(p, done_block); lb_start_block(p, edge_case_block); @@ -1320,9 +1366,10 @@ gb_internal LLVMValueRef lb_integer_modulo(lbProcedure *p, LLVMValueRef lhs, LLV floored: r = a - b*floor(a/b) IFF a/0 == 0, then (a%0 == a) or (a%%0 == a) + IFF a/0 == a, then (a%0 == 0) or (a%%0 == 0) */ - switch (lb_check_for_integer_division_by_zero_behaviour(p)) { + switch (behaviour) { case IntegerDivisionByZero_Trap: lb_call_intrinsic(p, "llvm.trap", nullptr, 0, nullptr, 0); LLVMBuildUnreachable(p->builder); @@ -1340,7 +1387,7 @@ gb_internal LLVMValueRef lb_integer_modulo(lbProcedure *p, LLVMValueRef lhs, LLV LLVMValueRef res = incoming_values[0]; - switch (lb_check_for_integer_division_by_zero_behaviour(p)) { + switch (behaviour) { case IntegerDivisionByZero_Trap: case IntegerDivisionByZero_Self: res = incoming_values[0]; |