aboutsummaryrefslogtreecommitdiff
path: root/src/llvm_backend_expr.cpp
diff options
context:
space:
mode:
authorgingerBill <gingerBill@users.noreply.github.com>2025-08-10 17:42:49 +0100
committergingerBill <gingerBill@users.noreply.github.com>2025-08-10 17:42:49 +0100
commitda76c743e9b7c88f2f15bbee1dba3b2ab6ebc0b0 (patch)
treef4422e7ad9a497f47af3ac67d0524ddc289110ac /src/llvm_backend_expr.cpp
parentecb6b35da561bfdaf89c0d39865a93abc26c3ad0 (diff)
Add shortcut for division by a constant
Diffstat (limited to 'src/llvm_backend_expr.cpp')
-rw-r--r--src/llvm_backend_expr.cpp127
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];