Skip to content

Commit 7583800

Browse files
author
Tim Hutt
committed
Add location to all assertion strings
Sail currently replaces empty assertion messages with their location, so `assert(false, "")` and `assert(false)` (which is equivalent to the former) will print their location, but `assert(false, "foo")` won't. This changes the behaviour so that instead all assertions print their location. The previous substitution was applied during type checking, but now it is done in the ANF step.
1 parent d55f92c commit 7583800

File tree

14 files changed

+73
-43
lines changed

14 files changed

+73
-43
lines changed

lib/int128/rts.c

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,14 @@ void sail_match_failure(const_sail_string msg)
1616
exit(EXIT_FAILURE);
1717
}
1818

19-
unit sail_assert(bool b, const_sail_string msg)
19+
unit sail_assert(bool b, const_sail_string msg, const_sail_string loc)
2020
{
2121
if (b) return UNIT;
22-
fprintf(stderr, "Assertion failed: %s\n", msg);
23-
exit(EXIT_FAILURE);
22+
if (msg[0] == '\0') {
23+
fprintf(stderr, "Assertion failed at %s\n", loc);
24+
} else {
25+
fprintf(stderr, "Assertion failed at %s: %s\n", loc, msg);
26+
} exit(EXIT_FAILURE);
2427
}
2528

2629
unit sail_exit(unit u)
@@ -244,7 +247,7 @@ bool write_ram(const sail_int addr_size, // Either 32 or 64
244247
// Then shift buf 8 bits right.
245248
mpz_fdiv_q_2exp(write_buf, write_buf, 8);
246249
}
247-
250+
248251
return true;
249252
}
250253
}
@@ -253,7 +256,7 @@ sbits fast_read_ram(const int64_t data_size,
253256
const uint64_t addr)
254257
{
255258
uint64_t r = 0;
256-
259+
257260
uint64_t byte;
258261
for(uint64_t i = (uint64_t) data_size; i > 0; --i) {
259262
byte = read_mem(addr + (i - 1));

lib/int128/rts.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ void sail_match_failure(const_sail_string msg);
1616
* sail_assert implements the assert construct in Sail. If any
1717
* assertion fails we immediately exit the model.
1818
*/
19-
unit sail_assert(bool b, const_sail_string msg);
19+
unit sail_assert(bool b, const_sail_string msg, const_sail_string loc);
2020

2121
unit sail_exit(unit);
2222

lib/sail_config.c

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -71,29 +71,29 @@ void sail_config_set_string(const char *json)
7171
else {
7272
snprintf(error_message, sizeof error_message, "Failed to parse JSON configuration at offset %ld", parse_end - json);
7373
}
74-
sail_assert(false, error_message);
74+
sail_assert(false, error_message, "sail_config_set_string()");
7575
}
7676
}
7777

7878
void sail_config_set_file(const char *path)
7979
{
8080
FILE *f = fopen(path, "rb");
81-
sail_assert(f != NULL, "Failed to open configuration file");
81+
sail_assert(f != NULL, "Failed to open configuration file", path);
8282

8383
int rc = fseek(f, 0, SEEK_END);
84-
sail_assert(rc != -1, "Failed to seek to end of configuration file");
84+
sail_assert(rc != -1, "Failed to seek to end of configuration file", path);
8585

8686
long fsize = ftell(f);
87-
sail_assert(fsize != -1, "Failed to get size of configuration file");
87+
sail_assert(fsize != -1, "Failed to get size of configuration file", path);
8888

8989
rc = fseek(f, 0, SEEK_SET);
90-
sail_assert(rc != -1, "Failed to seek to start of configuration file");
90+
sail_assert(rc != -1, "Failed to seek to start of configuration file", path);
9191

9292
char *buffer = (char *)sail_malloc(fsize + 1);
9393

9494
size_t ret_size = fread(buffer, fsize, 1, f);
9595

96-
sail_assert(ret_size == 1, "Failed to read configuration");
96+
sail_assert(ret_size == 1, "Failed to read configuration", path);
9797

9898
buffer[fsize] = 0;
9999
fclose(f);
@@ -102,7 +102,7 @@ void sail_config_set_file(const char *path)
102102
// sail_config_set_string() relies on null termination
103103
// to find the end of the string.
104104
for (size_t i = 0; i < fsize; ++i) {
105-
sail_assert(buffer[i] != 0, "Null byte in JSON configuration");
105+
sail_assert(buffer[i] != 0, "Null byte in JSON configuration", path);
106106
}
107107

108108
sail_config_set_string(buffer);
@@ -289,7 +289,7 @@ void sail_config_unwrap_int(sail_int *n, const sail_config_json config)
289289
{
290290
cJSON *json = (cJSON *)config;
291291
if (mpz_set_str(*n, json->valuestring, 10) == -1) {
292-
sail_assert(false, "Failed to parse integer from configuration");
292+
sail_assert(false, "Failed to parse integer from configuration", "sail_config_unwrap_int()");
293293
}
294294
}
295295

lib/sail_failure.c

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,10 +56,14 @@ void sail_match_failure(const_sail_string msg)
5656
exit(EXIT_FAILURE);
5757
}
5858

59-
unit sail_assert(bool b, const_sail_string msg)
59+
unit sail_assert(bool b, const_sail_string msg, const_sail_string loc)
6060
{
6161
if (b) return UNIT;
62-
fprintf(stderr, "Assertion failed: %s\n", msg);
62+
if (msg[0] == '\0') {
63+
fprintf(stderr, "Assertion failed at %s\n", loc);
64+
} else {
65+
fprintf(stderr, "Assertion failed at %s: %s\n", loc, msg);
66+
}
6367
exit(EXIT_FAILURE);
6468
}
6569

lib/sail_failure.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ void sail_match_failure(const_sail_string msg);
6363
* sail_assert implements the assert construct in Sail. If any
6464
* assertion fails we immediately exit the model.
6565
*/
66-
unit sail_assert(bool b, const_sail_string msg);
66+
unit sail_assert(bool b, const_sail_string msg, const_sail_string loc);
6767

6868
#ifdef __cplusplus
6969
}

lib/sv/sail.sv

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,9 @@ function automatic sail_unit sail_prerr(sail_unit s);
2525
return SAIL_UNIT;
2626
endfunction // sail_prerr
2727

28-
function automatic sail_unit sail_assert(bit b, sail_unit msg);
28+
// TODO: Is this actually used? It looks like asserts actually get written to
29+
// if (not condition) then $fatal(msg);
30+
function automatic sail_unit sail_assert(bit b, sail_unit loc, sail_unit msg);
2931
return SAIL_UNIT;
3032
endfunction // sail_assert
3133

@@ -55,9 +57,9 @@ function automatic sail_unit sail_prerr(string s);
5557
return SAIL_UNIT;
5658
endfunction // sail_prerr
5759

58-
function automatic sail_unit sail_assert(bit b, string msg);
60+
function automatic sail_unit sail_assert(bit b, string loc, string msg);
5961
if (!b) begin
60-
$display("%s", msg);
62+
$error("Assertion failed at %s: %s", loc, msg);
6163
end;
6264
return SAIL_UNIT;
6365
endfunction // sail_assert

src/lib/anf.ml

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -785,7 +785,12 @@ let rec anf (E_aux (e_aux, (l, tannot)) as exp) =
785785
let aexp2 = anf exp2 in
786786
let aval1, wrap1 = to_aval aexp1 in
787787
let aval2, wrap2 = to_aval aexp2 in
788-
wrap1 (wrap2 (mk_aexp (AE_app (Extern (mk_id "sail_assert", None), [aval1; aval2], unit_typ))))
788+
(* Add the location of the assertion as a parameter. *)
789+
let loc_string = Reporting.short_loc_to_string l in
790+
let loc_aexp = mk_aexp (ae_lit (L_aux (L_string loc_string, l)) string_typ) in
791+
let loc_aval, loc_wrap = to_aval loc_aexp in
792+
(* TODO: What are these wrap functions? Do I need to use loc_wrap? *)
793+
wrap1 (wrap2 (mk_aexp (AE_app (Extern (mk_id "sail_assert", None), [aval1; aval2; loc_aval], unit_typ))))
789794
| E_cons (exp1, exp2) ->
790795
let aexp1 = anf exp1 in
791796
let aexp2 = anf exp2 in

src/lib/jib_compile.ml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1206,7 +1206,8 @@ module Make (C : CONFIG) = struct
12061206
let str = string_of_id id in
12071207
if str = "sail_assert" && C.assert_to_exception then (
12081208
match args with
1209-
| [cond; msg] ->
1209+
| [cond; msg; _loc] ->
1210+
(* TODO: Should we include the location in the assertion message? *)
12101211
let cond_setup, cond_cval, cond_cleanup = compile_aval l ctx cond in
12111212
let msg_setup, msg_cval, _ = compile_aval l ctx msg in
12121213
let exn_setup, exn_cval = assert_exception l msg_cval in

src/lib/smt_gen.ml

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1526,6 +1526,8 @@ module Make (Config : CONFIG) (Primop_gen : PRIMOP_GEN) = struct
15261526
let ternary_primop f =
15271527
Some (fun args ret_ctyp -> match args with [v1; v2; v3] -> f v1 v2 v3 ret_ctyp | _ -> arity_error)
15281528

1529+
let ternary_primop_simple f = Some (fun args _ -> match args with [v1; v2; v3] -> f v1 v2 v3 | _ -> arity_error)
1530+
15291531
let builtin ?(allow_io = true) ?(undefined = Undefined_disable) = function
15301532
| "eq_bit" -> binary_primop (binary_smt "=")
15311533
| "eq_bool" -> binary_primop (binary_smt "=")
@@ -1651,10 +1653,11 @@ module Make (Config : CONFIG) (Primop_gen : PRIMOP_GEN) = struct
16511653
return (Fn (op, [bv]))
16521654
)
16531655
| "sail_assert" when allow_io ->
1654-
binary_primop_simple (fun b msg ->
1656+
ternary_primop_simple (fun b msg loc ->
16551657
let* b = smt_cval b in
16561658
let* msg = smt_cval msg in
1657-
return (Fn ("sail_assert", [b; msg]))
1659+
let* loc = smt_cval loc in
1660+
return (Fn ("sail_assert", [b; msg; loc]))
16581661
)
16591662
| "reg_deref" when allow_io ->
16601663
unary_primop_simple (fun reg_ref ->

src/lib/type_check.ml

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1974,13 +1974,6 @@ let irule r env exp =
19741974
let bt = Printexc.get_raw_backtrace () in
19751975
Printexc.raise_with_backtrace (Type_error (l, err)) bt
19761976

1977-
(* This function adds useful assertion messages to asserts missing them *)
1978-
let assert_msg = function
1979-
| E_aux (E_lit (L_aux (L_string "", _)), (l, _)) ->
1980-
let open Reporting in
1981-
locate (fun _ -> l) (mk_lit_exp (L_string (short_loc_to_string l)))
1982-
| msg -> msg
1983-
19841977
let strip_exp exp = map_exp_annot (fun (l, tannot) -> (l, untyped_annot tannot)) exp
19851978
let strip_pat pat = map_pat_annot (fun (l, tannot) -> (l, untyped_annot tannot)) pat
19861979
let strip_pexp pexp = map_pexp_annot (fun (l, tannot) -> (l, untyped_annot tannot)) pexp
@@ -2644,7 +2637,6 @@ and check_block' f_p env exps ret_typ =
26442637
let _, exps = check_block' f_p env exps ret_typ in
26452638
(s_p, annotated_exp :: exps)
26462639
| E_aux (E_assert (constr_exp, msg), (assert_l, _)), _ ->
2647-
let msg = assert_msg msg in
26482640
let constr_exp = crule check_exp env constr_exp bool_typ in
26492641
let checked_msg = crule check_exp env msg string_typ in
26502642
let env, added_constraint =
@@ -3899,7 +3891,6 @@ and infer_exp env (E_aux (exp_aux, (l, uannot)) as exp) =
38993891
| None -> typ_error l "Could not infer type of list literal"
39003892
end
39013893
| E_assert (test, msg) ->
3902-
let msg = assert_msg msg in
39033894
let checked_test = crule check_exp env test bool_typ in
39043895
let checked_msg = crule check_exp env msg string_typ in
39053896
annot_exp (E_assert (checked_test, checked_msg)) unit_typ

0 commit comments

Comments
 (0)