Skip to content

Commit 9f0a6c2

Browse files
committed
Implement preliminary form of structured compare. No boxes, vectors or strings yet.
1 parent 72cc89c commit 9f0a6c2

File tree

5 files changed

+203
-79
lines changed

5 files changed

+203
-79
lines changed

src/Makefile

+1
Original file line numberDiff line numberDiff line change
@@ -537,6 +537,7 @@ TEST_XFAILS_LLVM := $(TASK_XFAILS) \
537537
str-append.rs \
538538
str-concat.rs \
539539
str-idx.rs \
540+
structured-compare.rs \
540541
tag.rs \
541542
tail-call-arg-leak.rs \
542543
tail-cps.rs \

src/boot/me/semant.ml

+2-2
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ type glue =
2626
| GLUE_sever of Ast.ty (* Null all box state slots. *)
2727
| GLUE_mark of Ast.ty (* Mark all box state slots. *)
2828
| GLUE_clone of Ast.ty (* Deep copy. *)
29-
| GLUE_compare of Ast.ty
29+
| GLUE_cmp of Ast.ty
3030
| GLUE_hash of Ast.ty
3131
| GLUE_write of Ast.ty
3232
| GLUE_read of Ast.ty
@@ -2508,7 +2508,7 @@ let glue_str (cx:ctxt) (g:glue) : string =
25082508
| GLUE_sever ty -> "glue$sever$" ^ (ty_str cx ty)
25092509
| GLUE_mark ty -> "glue$mark$" ^ (ty_str cx ty)
25102510
| GLUE_clone ty -> "glue$clone$" ^ (ty_str cx ty)
2511-
| GLUE_compare ty -> "glue$compare$" ^ (ty_str cx ty)
2511+
| GLUE_cmp ty -> "glue$cmp$" ^ (ty_str cx ty)
25122512
| GLUE_hash ty -> "glue$hash$" ^ (ty_str cx ty)
25132513
| GLUE_write ty -> "glue$write$" ^ (ty_str cx ty)
25142514
| GLUE_read ty -> "glue$read$" ^ (ty_str cx ty)

src/boot/me/trans.ml

+179-75
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ let trans_visitor
9191
let imm (i:int64) : Il.operand = imm_of_ty i word_ty_mach in
9292
let simm (i:int64) : Il.operand = imm_of_ty i word_ty_signed_mach in
9393
let one = imm 1L in
94+
let neg_one = simm (-1L) in
9495
let zero = imm 0L in
9596
let imm_true = imm_of_ty 1L TY_u8 in
9697
let imm_false = imm_of_ty 0L TY_u8 in
@@ -1858,7 +1859,38 @@ let trans_visitor
18581859
in
18591860
get_typed_mem_glue g fty inner
18601861

1861-
and get_cmp_glue _ = failwith "TODO"
1862+
and get_cmp_glue ty =
1863+
let arg_ty_params_alias = 0 in
1864+
let arg_lhs_alias = 1 in
1865+
let arg_rhs_alias = 2 in
1866+
let g = GLUE_cmp ty in
1867+
let inner (out_ptr:Il.cell) (args:Il.cell) =
1868+
let dst = deref out_ptr in
1869+
let ty_params = deref (get_element_ptr args arg_ty_params_alias) in
1870+
let lhs = deref (get_element_ptr args arg_lhs_alias) in
1871+
let rhs = deref (get_element_ptr args arg_rhs_alias) in
1872+
let early_finish_jmps = Queue.create () in
1873+
let cmp_part lhs rhs ty =
1874+
let tmp = trans_cmp ~ty_params ~ty (Il.Cell lhs) (Il.Cell rhs) in
1875+
let keep_going_jmps =
1876+
trans_compare_simple Il.JE tmp zero
1877+
in
1878+
mov dst tmp;
1879+
Queue.add (mark()) early_finish_jmps;
1880+
emit (Il.jmp Il.JMP Il.CodeNone);
1881+
List.iter patch keep_going_jmps
1882+
in
1883+
mov dst zero;
1884+
iter_ty_parts_full ty_params lhs rhs ty cmp_part;
1885+
Queue.iter patch early_finish_jmps;
1886+
in
1887+
let ty_params_ptr = ty_params_covering ty in
1888+
let fty =
1889+
mk_ty_fn
1890+
(local_slot Ast.TY_int)
1891+
[| ty_params_ptr; alias_slot ty; alias_slot ty |]
1892+
in
1893+
get_typed_mem_glue g fty inner
18621894

18631895
(*
18641896
* Vector-growth glue takes four arguments:
@@ -2108,62 +2140,120 @@ let trans_visitor
21082140
(Array.append [| ty_params_ptr |] args)
21092141
clo
21102142

2111-
(* [trans_compare_full] returns the quad number of the cjmp, which the
2112-
* caller patches to the cjmp destination.
2143+
(*
2144+
* NB: there are 2 categories of comparisons:
2145+
*
2146+
* - Those called 'compare' that take a jmpop and return a jump list
2147+
* that the caller should patch.
2148+
*
2149+
* - Those called 'cmp' that return a number, -1/0/1, indicating the
2150+
* relative order of lhs and rhs.
2151+
*
2152+
* While in theory compare could be built out of cmp, on real machines
2153+
* we are forced to build cmp out of compare.
2154+
*)
2155+
2156+
2157+
(*
2158+
* [trans_cmp] returns the result-code of a three-value comparison,
2159+
* which is an operand representing the ordering of lhs and rhs. -1 means
2160+
* less than, 0 means equal, 1 means greater-than.
21132161
*
21142162
* We assume that the LHS and RHS of the comparison have the same type, an
2115-
* invariant that the typechecker enforces. *)
2116-
and trans_compare_full
2117-
~cjmp:(cjmp:Il.jmpop)
2163+
* invariant that the typechecker enforces.
2164+
*)
2165+
and trans_cmp
21182166
~ty_params:(ty_params:Il.cell)
21192167
~ty:(ty:Ast.ty)
2120-
(lhs:Il.cell)
2121-
(rhs:Il.cell)
2122-
: quad_idx list =
2168+
(lhs:Il.operand)
2169+
(rhs:Il.operand)
2170+
: Il.operand =
21232171
let ty = strip_mutable_or_constrained_ty ty in
21242172
let (result:Il.cell) = next_vreg_cell (Il.ValTy Il.Bits32) in
2125-
begin
2126-
match ty with
2127-
Ast.TY_obj _ ->
2128-
let lhs_binding = get_element_ptr lhs Abi.obj_field_box in
2129-
let rhs_binding = get_element_ptr rhs Abi.obj_field_box in
2130-
let lhs_box, rhs_box = deref lhs_binding, deref rhs_binding in
2131-
let lhs_obj = get_element_ptr lhs_box Abi.box_rc_field_body in
2132-
let rhs_obj = get_element_ptr rhs_box Abi.box_rc_field_body in
2133-
let tydesc = get_element_ptr lhs_obj Abi.obj_body_elt_tydesc in
2134-
let lhs_body = get_element_ptr lhs_obj Abi.obj_body_elt_fields in
2135-
let rhs_body = get_element_ptr rhs_obj Abi.obj_body_elt_fields in
2136-
trans_call_dynamic_glue
2137-
tydesc
2138-
Abi.tydesc_field_cmp_glue
2139-
(Some result)
2140-
[| alias lhs_body; alias rhs_body |]
2141-
None
2142-
2143-
| Ast.TY_param (i, _) ->
2144-
trans_call_simple_dynamic_glue
2145-
i
2146-
Abi.tydesc_field_cmp_glue
2147-
ty_params
2148-
[| alias lhs; alias rhs |]
2149-
None
2173+
begin
2174+
match ty with
21502175

2151-
| _ ->
2152-
trans_call_static_glue
2153-
(code_fixup_to_ptr_operand (get_cmp_glue ty))
2154-
(Some result)
2155-
[| lhs; rhs |]
2156-
None
2157-
end;
2158-
emit (Il.cmp (Il.Cell result) zero);
2159-
let jmp = mark() in
2160-
emit (Il.jmp cjmp Il.CodeNone);
2161-
[ jmp ]
2176+
Ast.TY_bool
2177+
| Ast.TY_mach _
2178+
| Ast.TY_int
2179+
| Ast.TY_uint
2180+
| Ast.TY_char ->
2181+
let cjmp =
2182+
if type_is_unsigned_2s_complement ty
2183+
then Il.JB
2184+
else Il.JL
2185+
in
2186+
(* Start with assumption lhs < rhs *)
2187+
mov result neg_one;
2188+
let lhs_lt_rhs_jmps =
2189+
trans_compare ~ty_params ~cjmp ~ty lhs rhs
2190+
in
2191+
(* ... disproven, so assume lhs > rhs *)
2192+
mov result one;
2193+
let rhs_lt_lhs_jmps =
2194+
trans_compare ~ty_params ~cjmp ~ty rhs lhs
2195+
in
2196+
(* ... disproven, must be lhs == rhs *)
2197+
mov result zero;
2198+
List.iter patch lhs_lt_rhs_jmps;
2199+
List.iter patch rhs_lt_lhs_jmps;
2200+
2201+
| Ast.TY_obj _ ->
2202+
let lhs = need_cell lhs in
2203+
let rhs = need_cell rhs in
2204+
let lhs_binding = get_element_ptr lhs Abi.obj_field_box in
2205+
let rhs_binding = get_element_ptr rhs Abi.obj_field_box in
2206+
let lhs_box, rhs_box = deref lhs_binding, deref rhs_binding in
2207+
let lhs_obj = get_element_ptr lhs_box Abi.box_rc_field_body in
2208+
let rhs_obj = get_element_ptr rhs_box Abi.box_rc_field_body in
2209+
let td = get_element_ptr lhs_obj Abi.obj_body_elt_tydesc in
2210+
let lhs_body =
2211+
get_element_ptr lhs_obj Abi.obj_body_elt_fields
2212+
in
2213+
let rhs_body =
2214+
get_element_ptr rhs_obj Abi.obj_body_elt_fields
2215+
in
2216+
let ty_params_ptr = get_tydesc_params ty_params td in
2217+
trans_call_dynamic_glue
2218+
td Abi.tydesc_field_cmp_glue
2219+
(Some result)
2220+
[| ty_params_ptr; alias lhs_body; alias rhs_body |]
2221+
None
21622222

2163-
(* Like [trans_compare_full], returns the address of the jump, which the
2223+
| Ast.TY_param (i, _) ->
2224+
let lhs = need_cell lhs in
2225+
let rhs = need_cell rhs in
2226+
let td = get_ty_param ty_params i in
2227+
let ty_params_ptr = get_tydesc_params ty_params td in
2228+
trans_call_dynamic_glue
2229+
td Abi.tydesc_field_cmp_glue
2230+
(Some result)
2231+
[| ty_params_ptr; alias lhs; alias rhs |]
2232+
None
2233+
2234+
| Ast.TY_vec _
2235+
| Ast.TY_str ->
2236+
(* FIXME: temporary until we get sequence-compares working. *)
2237+
mov result zero;
2238+
2239+
| _ ->
2240+
let lhs = need_cell lhs in
2241+
let rhs = need_cell rhs in
2242+
trans_call_static_glue
2243+
(code_fixup_to_ptr_operand (get_cmp_glue ty))
2244+
(Some result)
2245+
[| alias ty_params; alias lhs; alias rhs |]
2246+
None
2247+
end;
2248+
Il.Cell result
2249+
2250+
2251+
(*
2252+
* [trans_compare_simple] returns a set of jump addresses, which the
21642253
* caller patches to the destination. Only use this function if you are sure
21652254
* that the LHS and RHS have the same type and that both will fit in a
2166-
* machine register; otherwise, use [trans_compare] instead. *)
2255+
* machine register; otherwise, use [trans_compare] instead.
2256+
*)
21672257
and trans_compare_simple
21682258
(cjmp:Il.jmpop)
21692259
(lhs:Il.operand)
@@ -2174,20 +2264,34 @@ let trans_visitor
21742264
emit (Il.jmp cjmp Il.CodeNone);
21752265
[ jmp ]
21762266

2267+
(*
2268+
* [trans_compare] returns a set of jump addresses, which the
2269+
* caller patches to the destination.
2270+
*)
21772271
and trans_compare
21782272
?ty_params:(ty_params=get_ty_params_of_current_frame())
21792273
~cjmp:(cjmp:Il.jmpop)
21802274
~ty:(ty:Ast.ty)
21812275
(lhs:Il.operand)
21822276
(rhs:Il.operand)
21832277
: quad_idx list =
2184-
ignore (trans_compare ~cjmp ~ty lhs rhs);
2185-
(* TODO *)
2186-
match lhs, rhs with
2187-
Il.Cell lhs, Il.Cell rhs ->
2188-
trans_compare_full
2189-
~cjmp ~ty_params ~ty lhs rhs
2190-
| _ -> trans_compare_simple cjmp lhs rhs
2278+
match ty with
2279+
Ast.TY_bool
2280+
| Ast.TY_mach _
2281+
| Ast.TY_int
2282+
| Ast.TY_uint
2283+
| Ast.TY_char ->
2284+
trans_compare_simple cjmp lhs rhs
2285+
2286+
| _ ->
2287+
let result =
2288+
trans_cmp ~ty_params ~ty lhs rhs
2289+
in
2290+
emit (Il.cmp result zero);
2291+
let jmp = mark() in
2292+
emit (Il.jmp cjmp Il.CodeNone);
2293+
[ jmp ]
2294+
21912295

21922296
and trans_cond (invert:bool) (expr:Ast.expr) : quad_idx list =
21932297
let anno _ =
@@ -2198,27 +2302,27 @@ let trans_visitor
21982302
": cond, finale")
21992303
end
22002304
in
2201-
2202-
match expr with
2203-
Ast.EXPR_binary (binop, a, b) ->
2204-
let lhs = trans_atom a in
2205-
let rhs = trans_atom b in
2206-
let cjmp = binop_to_jmpop binop in
2207-
let cjmp' =
2208-
if invert then
2209-
match cjmp with
2210-
Il.JE -> Il.JNE
2211-
| Il.JNE -> Il.JE
2212-
| Il.JL -> Il.JGE
2213-
| Il.JLE -> Il.JG
2214-
| Il.JGE -> Il.JL
2215-
| Il.JG -> Il.JLE
2216-
| _ -> bug () "Unhandled inverse binop in trans_cond"
2217-
else
2218-
cjmp
2219-
in
2220-
anno ();
2221-
trans_compare_simple cjmp' lhs rhs
2305+
match expr with
2306+
Ast.EXPR_binary (binop, a, b) ->
2307+
let lhs = trans_atom a in
2308+
let rhs = trans_atom b in
2309+
let cjmp = binop_to_jmpop binop in
2310+
let cjmp =
2311+
if invert then
2312+
match cjmp with
2313+
Il.JE -> Il.JNE
2314+
| Il.JNE -> Il.JE
2315+
| Il.JL -> Il.JGE
2316+
| Il.JLE -> Il.JG
2317+
| Il.JGE -> Il.JL
2318+
| Il.JG -> Il.JLE
2319+
| _ -> bug () "Unhandled inverse binop in trans_cond"
2320+
else
2321+
cjmp
2322+
in
2323+
anno ();
2324+
let ty = atom_type cx a in
2325+
trans_compare ~cjmp ~ty lhs rhs
22222326

22232327
| _ ->
22242328
let bool_operand = trans_expr expr in

src/comp/fe/parser.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,7 @@ state fn new_parser(session.session sess, str path) -> parser {
5050
}
5151

5252
state fn expect(parser p, token.token t) {
53-
// FIXME: comparing tags would be good. One of these days.
54-
if (true /* p.peek() == t */) {
53+
if (p.peek() == t) {
5554
p.bump();
5655
} else {
5756
let str s = "expecting ";
+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
tag foo {
2+
large;
3+
small;
4+
}
5+
6+
fn main() {
7+
auto a = tup(1,2,3);
8+
auto b = tup(1,2,3);
9+
check (a == b);
10+
check (a != tup(1,2,4));
11+
check (a < tup(1,2,4));
12+
check (a <= tup(1,2,4));
13+
check (tup(1,2,4) > a);
14+
check (tup(1,2,4) >= a);
15+
auto x = large;
16+
auto y = small;
17+
check (x != y);
18+
check (x == large);
19+
check (x != small);
20+
}

0 commit comments

Comments
 (0)