Skip to content

Commit 98a33f9

Browse files
committed
Add llvm generic_compare implementation for integers
This implements the following calculation posted by Richard on Zulip: https://roc.zulipchat.com/#narrow/stream/304641-ideas/topic/ordering.2Fsorting.20ability/near/403858126 I'm using the compare.rs module that implements equality as a guide, some the code has some similarities with that, but also I'm starting with a blank page to not overwhelm myself, which might result in some differences (at least at first). The compare.rs module we might want to rename to eq.rs in a future commit. That would free up the name compare.rs to implement generic_eq.
1 parent 5a7b74c commit 98a33f9

File tree

3 files changed

+213
-1
lines changed

3 files changed

+213
-1
lines changed

Diff for: crates/compiler/gen_llvm/src/llvm/lowlevel.rs

+13-1
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ use crate::llvm::{
5555
LLVM_SUB_WITH_OVERFLOW,
5656
},
5757
refcounting::PointerToRefcount,
58+
sort::generic_compare,
5859
};
5960

6061
use super::{build::Env, convert::zig_dec_type};
@@ -1270,7 +1271,18 @@ pub(crate) fn run_low_level<'a, 'ctx>(
12701271
BasicValueEnum::IntValue(bool_val)
12711272
}
12721273
Compare => {
1273-
panic!("TODO: implement this")
1274+
// Sort.compare : elem, elem -> [LessThan, Equal, GreaterThan]
1275+
arguments_with_layouts!((lhs_arg, lhs_layout), (rhs_arg, rhs_layout));
1276+
1277+
generic_compare(
1278+
env,
1279+
layout_interner,
1280+
layout_ids,
1281+
lhs_arg,
1282+
rhs_arg,
1283+
lhs_layout,
1284+
rhs_layout,
1285+
)
12741286
}
12751287
Hash => {
12761288
unimplemented!()

Diff for: crates/compiler/gen_llvm/src/llvm/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ pub mod externs;
99
mod intrinsics;
1010
mod lowlevel;
1111
pub mod refcounting;
12+
pub mod sort;
1213

1314
mod align;
1415
mod erased;

Diff for: crates/compiler/gen_llvm/src/llvm/sort.rs

+199
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,199 @@
1+
use super::build::BuilderExt;
2+
use crate::llvm::build::Env;
3+
use inkwell::values::{BasicValueEnum, IntValue};
4+
use inkwell::IntPredicate;
5+
use roc_builtins::bitcode::IntWidth;
6+
use roc_mono::layout::{
7+
Builtin, InLayout, LayoutIds, LayoutInterner, LayoutRepr, STLayoutInterner,
8+
};
9+
10+
pub fn generic_compare<'a, 'ctx>(
11+
env: &Env<'a, 'ctx, '_>,
12+
layout_interner: &STLayoutInterner<'a>,
13+
_layout_ids: &mut LayoutIds<'a>,
14+
lhs_val: BasicValueEnum<'ctx>,
15+
rhs_val: BasicValueEnum<'ctx>,
16+
lhs_layout: InLayout<'a>,
17+
_rhs_layout: InLayout<'a>,
18+
) -> BasicValueEnum<'ctx> {
19+
let lhs_repr = layout_interner.get_repr(lhs_layout);
20+
let result = match lhs_repr {
21+
LayoutRepr::Builtin(Builtin::Int(int_width)) => {
22+
int_compare(env, lhs_val, rhs_val, int_width)
23+
}
24+
LayoutRepr::Builtin(Builtin::Float(_)) => todo!(),
25+
LayoutRepr::Builtin(Builtin::Bool) => todo!(),
26+
LayoutRepr::Builtin(Builtin::Decimal) => todo!(),
27+
LayoutRepr::Builtin(Builtin::Str) => todo!(),
28+
LayoutRepr::Builtin(Builtin::List(_)) => todo!(),
29+
LayoutRepr::Struct(_) => todo!(),
30+
LayoutRepr::LambdaSet(_) => unreachable!("cannot compare closures"),
31+
LayoutRepr::FunctionPointer(_) => unreachable!("cannot compare function pointers"),
32+
LayoutRepr::Erased(_) => unreachable!("cannot compare erased types"),
33+
LayoutRepr::Union(_) => todo!(),
34+
LayoutRepr::Ptr(_) => todo!(),
35+
LayoutRepr::RecursivePointer(_) => todo!(),
36+
};
37+
BasicValueEnum::IntValue(result)
38+
}
39+
40+
fn int_compare<'ctx>(
41+
env: &Env<'_, 'ctx, '_>,
42+
lhs_val: BasicValueEnum<'ctx>,
43+
rhs_val: BasicValueEnum<'ctx>,
44+
builtin: IntWidth,
45+
) -> IntValue<'ctx> {
46+
// The following calculation will return 0 for equals, 1 for greater than,
47+
// and 2 for less than.
48+
// (a > b) + 2 * (a < b);
49+
let lhs_gt_rhs = int_gt(env, lhs_val, rhs_val, builtin);
50+
let lhs_lt_rhs = int_lt(env, lhs_val, rhs_val, builtin);
51+
let two = env.ptr_int().const_int(2, false);
52+
let lhs_lt_rhs_times_two =
53+
env.builder
54+
.new_build_int_mul(lhs_lt_rhs, two, "lhs_lt_rhs_times_two");
55+
env.builder
56+
.new_build_int_sub(lhs_gt_rhs, lhs_lt_rhs_times_two, "int_compare")
57+
}
58+
59+
fn int_lt<'ctx>(
60+
env: &Env<'_, 'ctx, '_>,
61+
lhs_val: BasicValueEnum<'ctx>,
62+
rhs_val: BasicValueEnum<'ctx>,
63+
builtin: IntWidth,
64+
) -> IntValue<'ctx> {
65+
use IntWidth::*;
66+
match builtin {
67+
I128 => env.builder.new_build_int_compare(
68+
IntPredicate::SLT,
69+
lhs_val.into_int_value(),
70+
rhs_val.into_int_value(),
71+
"lhs_gt_rhs_i28",
72+
),
73+
I64 => env.builder.new_build_int_compare(
74+
IntPredicate::SLT,
75+
lhs_val.into_int_value(),
76+
rhs_val.into_int_value(),
77+
"lhs_gt_rhs_i64",
78+
),
79+
I32 => env.builder.new_build_int_compare(
80+
IntPredicate::SLT,
81+
lhs_val.into_int_value(),
82+
rhs_val.into_int_value(),
83+
"lhs_gt_rhs_i32",
84+
),
85+
I16 => env.builder.new_build_int_compare(
86+
IntPredicate::SLT,
87+
lhs_val.into_int_value(),
88+
rhs_val.into_int_value(),
89+
"lhs_gt_rhs_i16",
90+
),
91+
I8 => env.builder.new_build_int_compare(
92+
IntPredicate::SLT,
93+
lhs_val.into_int_value(),
94+
rhs_val.into_int_value(),
95+
"lhs_gt_rhs_i8",
96+
),
97+
U128 => env.builder.new_build_int_compare(
98+
IntPredicate::ULT,
99+
lhs_val.into_int_value(),
100+
rhs_val.into_int_value(),
101+
"lhs_gt_rhs_u128",
102+
),
103+
U64 => env.builder.new_build_int_compare(
104+
IntPredicate::ULT,
105+
lhs_val.into_int_value(),
106+
rhs_val.into_int_value(),
107+
"lhs_gt_rhs_u64",
108+
),
109+
U32 => env.builder.new_build_int_compare(
110+
IntPredicate::ULT,
111+
lhs_val.into_int_value(),
112+
rhs_val.into_int_value(),
113+
"lhs_gt_rhs_u32",
114+
),
115+
U16 => env.builder.new_build_int_compare(
116+
IntPredicate::ULT,
117+
lhs_val.into_int_value(),
118+
rhs_val.into_int_value(),
119+
"lhs_gt_rhs_u16",
120+
),
121+
U8 => env.builder.new_build_int_compare(
122+
IntPredicate::ULT,
123+
lhs_val.into_int_value(),
124+
rhs_val.into_int_value(),
125+
"lhs_gt_rhs_u8",
126+
),
127+
}
128+
}
129+
130+
fn int_gt<'ctx>(
131+
env: &Env<'_, 'ctx, '_>,
132+
lhs_val: BasicValueEnum<'ctx>,
133+
rhs_val: BasicValueEnum<'ctx>,
134+
builtin: IntWidth,
135+
) -> IntValue<'ctx> {
136+
use IntWidth::*;
137+
match builtin {
138+
I128 => env.builder.new_build_int_compare(
139+
IntPredicate::SGT,
140+
lhs_val.into_int_value(),
141+
rhs_val.into_int_value(),
142+
"lhs_lt_rhs_i28",
143+
),
144+
I64 => env.builder.new_build_int_compare(
145+
IntPredicate::SGT,
146+
lhs_val.into_int_value(),
147+
rhs_val.into_int_value(),
148+
"lhs_lt_rhs_i64",
149+
),
150+
I32 => env.builder.new_build_int_compare(
151+
IntPredicate::SGT,
152+
lhs_val.into_int_value(),
153+
rhs_val.into_int_value(),
154+
"lhs_lt_rhs_i32",
155+
),
156+
I16 => env.builder.new_build_int_compare(
157+
IntPredicate::SGT,
158+
lhs_val.into_int_value(),
159+
rhs_val.into_int_value(),
160+
"lhs_lt_rhs_i16",
161+
),
162+
I8 => env.builder.new_build_int_compare(
163+
IntPredicate::SGT,
164+
lhs_val.into_int_value(),
165+
rhs_val.into_int_value(),
166+
"lhs_lt_rhs_i8",
167+
),
168+
U128 => env.builder.new_build_int_compare(
169+
IntPredicate::UGT,
170+
lhs_val.into_int_value(),
171+
rhs_val.into_int_value(),
172+
"lhs_lt_rhs_u128",
173+
),
174+
U64 => env.builder.new_build_int_compare(
175+
IntPredicate::UGT,
176+
lhs_val.into_int_value(),
177+
rhs_val.into_int_value(),
178+
"lhs_lt_rhs_u64",
179+
),
180+
U32 => env.builder.new_build_int_compare(
181+
IntPredicate::UGT,
182+
lhs_val.into_int_value(),
183+
rhs_val.into_int_value(),
184+
"lhs_lt_rhs_u32",
185+
),
186+
U16 => env.builder.new_build_int_compare(
187+
IntPredicate::UGT,
188+
lhs_val.into_int_value(),
189+
rhs_val.into_int_value(),
190+
"lhs_lt_rhs_u16",
191+
),
192+
U8 => env.builder.new_build_int_compare(
193+
IntPredicate::UGT,
194+
lhs_val.into_int_value(),
195+
rhs_val.into_int_value(),
196+
"lhs_lt_rhs_u8",
197+
),
198+
}
199+
}

0 commit comments

Comments
 (0)