Skip to content

Commit f8c8fe4

Browse files
Merge pull request #67 from goblint/atomic_ops
Minimal support for `__auto_type`
2 parents 1e53aa8 + 85b174f commit f8c8fe4

File tree

7 files changed

+139
-69
lines changed

7 files changed

+139
-69
lines changed

src/frontc/cabs.ml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ type typeSpecifier = (* Merge all specifiers into one type *)
8888
| TtypeofE of expression (* GCC __typeof__ *)
8989
| TtypeofT of specifier * decl_type (* GCC __typeof__ *)
9090
| Tdefault (** "default" in generic associations *)
91+
| Tauto (** GCC __auto_type *)
9192

9293
and storage =
9394
NO_STORAGE | AUTO | STATIC | EXTERN | REGISTER

src/frontc/cabs2cil.ml

Lines changed: 99 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,8 @@ open Cil
5353
open Cilint
5454
open Trace
5555

56+
(* This exception is thrown if there is an attempt to transform Tauto into a CIL type *)
57+
exception TautoEncountered
5658

5759
let mydebugfunction () =
5860
E.s (error "mydebugfunction")
@@ -2327,9 +2329,7 @@ let rec doSpecList (suggestedAnonName: string) (* This string will be part of
23272329
let attrs : A.attribute list ref = ref [] in (* __attribute__, etc. *)
23282330
let cvattrs : A.cvspec list ref = ref [] in (* const/volatile *)
23292331

2330-
let doSpecElem (se: A.spec_elem)
2331-
(acc: A.typeSpecifier list)
2332-
: A.typeSpecifier list =
2332+
let doSpecElem (se: A.spec_elem) (acc: A.typeSpecifier list): A.typeSpecifier list =
23332333
match se with
23342334
A.SpecTypedef -> acc
23352335
| A.SpecInline -> isinline := true; acc
@@ -2360,14 +2360,12 @@ let rec doSpecList (suggestedAnonName: string) (* This string will be part of
23602360
(* GCC allows a named type that appears first to be followed by things
23612361
* like "short", "signed", "unsigned" or "long". *)
23622362
match tspecs with
2363-
A.Tnamed n :: (_ :: _ as rest) ->
2364-
(* If rest contains "short" or "long" then drop the Tnamed *)
2365-
if List.exists (function A.Tshort -> true
2366-
| A.Tlong -> true | _ -> false) rest then
2367-
rest
2368-
else
2369-
tspecs
2370-
2363+
| A.Tnamed n :: (_ :: _ as rest) ->
2364+
(* If rest contains "short" or "long" then drop the Tnamed *)
2365+
if List.exists (function A.Tshort -> true | A.Tlong -> true | _ -> false) rest then
2366+
rest
2367+
else
2368+
tspecs
23712369
| _ -> tspecs
23722370
in
23732371
(* Sort the type specifiers *)
@@ -2574,37 +2572,37 @@ let rec doSpecList (suggestedAnonName: string) (* This string will be part of
25742572
let a = extraAttrs @ (getTypeAttrs ()) in
25752573
enum.eattr <- doAttributes a;
25762574
let res = TEnum (enum, []) in
2577-
let smallest = ref zero_cilint in
2578-
let largest = ref zero_cilint in
2579-
2580-
(* Life is fun here. ANSI says: enum constants are ints,
2581-
and there's an implementation-dependent underlying integer
2582-
type for the enum, which must be capable of holding all the
2583-
enum's values.
2584-
GCC allows enum constants that don't fit in int: the enum
2585-
constant's type is the smallest type (but at least int) that
2586-
will hold the value, with a preference for signed types.
2587-
The underlying type EI of the enum is picked as follows:
2588-
- let T be the smallest integer type that holds all the enum's
2589-
values; T is signed if any enum value is negative, unsigned otherwise
2590-
- if the enum is packed or sizeof(T) >= sizeof(int), then EI = T
2591-
- otherwise EI = int if T is signed and unsigned int otherwise
2592-
Note that these rules make the enum unsigned if possible (as
2593-
opposed the enum constants which tend towards being signed...) *)
2594-
2595-
let updateEnum (i:cilint) : ikind =
2596-
if compare_cilint i !smallest < 0 then
2597-
smallest := i;
2598-
if compare_cilint i !largest > 0 then
2599-
largest := i;
2600-
(* This matches gcc's behaviour *)
2601-
if fitsInInt IInt i then IInt
2602-
else if fitsInInt IUInt i then IUInt
2603-
else if fitsInInt ILong i then ILong
2604-
else if fitsInInt IULong i then IULong
2605-
else if fitsInInt ILongLong i then ILongLong
2606-
else IULongLong (* assume there can be not enum constants that don't fit in long long since there can only be 128bit constants if long long is also 128bit *)
2607-
in
2575+
let smallest = ref zero_cilint in
2576+
let largest = ref zero_cilint in
2577+
2578+
(* Life is fun here. ANSI says: enum constants are ints,
2579+
and there's an implementation-dependent underlying integer
2580+
type for the enum, which must be capable of holding all the
2581+
enum's values.
2582+
GCC allows enum constants that don't fit in int: the enum
2583+
constant's type is the smallest type (but at least int) that
2584+
will hold the value, with a preference for signed types.
2585+
The underlying type EI of the enum is picked as follows:
2586+
- let T be the smallest integer type that holds all the enum's
2587+
values; T is signed if any enum value is negative, unsigned otherwise
2588+
- if the enum is packed or sizeof(T) >= sizeof(int), then EI = T
2589+
- otherwise EI = int if T is signed and unsigned int otherwise
2590+
Note that these rules make the enum unsigned if possible (as
2591+
opposed the enum constants which tend towards being signed...) *)
2592+
2593+
let updateEnum (i:cilint) : ikind =
2594+
if compare_cilint i !smallest < 0 then
2595+
smallest := i;
2596+
if compare_cilint i !largest > 0 then
2597+
largest := i;
2598+
(* This matches gcc's behaviour *)
2599+
if fitsInInt IInt i then IInt
2600+
else if fitsInInt IUInt i then IUInt
2601+
else if fitsInInt ILong i then ILong
2602+
else if fitsInInt IULong i then IULong
2603+
else if fitsInInt ILongLong i then ILongLong
2604+
else IULongLong (* assume there can be not enum constants that don't fit in long long since there can only be 128bit constants if long long is also 128bit *)
2605+
in
26082606
(* as each name,value pair is determined, this is called *)
26092607
let rec processName kname (i: exp) loc rest = begin
26102608
(* add the name to the environment, but with a faked 'typ' field;
@@ -2641,25 +2639,24 @@ let rec doSpecList (suggestedAnonName: string) (* This string will be part of
26412639
let fields = loop zero eil in
26422640
(* Now set the right set of items *)
26432641
enum.eitems <- Util.list_map (fun (_, x) -> x) fields;
2644-
(* Pick the enum's kind - see discussion above *)
2645-
let unsigned = compare_cilint !smallest zero_cilint >= 0 in
2646-
let smallKind = intKindForValue !smallest unsigned in
2647-
let largeKind = intKindForValue !largest unsigned in
2648-
let ekind =
2649-
if (bytesSizeOfInt smallKind) > (bytesSizeOfInt largeKind) then
2650-
smallKind
2651-
else
2652-
largeKind
2653-
in
2654-
enum.ekind <-
2655-
if bytesSizeOfInt ekind < bytesSizeOfInt IInt then
2656-
if hasAttribute "packed" enum.eattr then
2657-
ekind
2658-
else
2659-
if unsigned then IUInt else IInt
2660-
else
2661-
ekind
2662-
;
2642+
(* Pick the enum's kind - see discussion above *)
2643+
let unsigned = compare_cilint !smallest zero_cilint >= 0 in
2644+
let smallKind = intKindForValue !smallest unsigned in
2645+
let largeKind = intKindForValue !largest unsigned in
2646+
let ekind =
2647+
if (bytesSizeOfInt smallKind) > (bytesSizeOfInt largeKind) then
2648+
smallKind
2649+
else
2650+
largeKind
2651+
in
2652+
enum.ekind <-
2653+
if bytesSizeOfInt ekind < bytesSizeOfInt IInt then
2654+
if hasAttribute "packed" enum.eattr then ekind
2655+
else if unsigned then IUInt
2656+
else IInt
2657+
else
2658+
ekind
2659+
;
26632660
(* Record the enum name in the environment *)
26642661
addLocalToEnv (kindPlusName "enum" n'') (EnvTyp res);
26652662
(* And define the tag *)
@@ -2689,6 +2686,7 @@ let rec doSpecList (suggestedAnonName: string) (* This string will be part of
26892686
| [A.TtypeofT (specs, dt)] ->
26902687
let typ = doOnlyType specs dt in
26912688
typ
2689+
| [A.Tauto] -> raise TautoEncountered
26922690

26932691
| _ ->
26942692
E.s (error "Invalid combination of type specifiers")
@@ -3008,7 +3006,7 @@ and doType (nameortype: attributeClass) (* This is AttrName if we are doing
30083006
None
30093007
end
30103008
in
3011-
let al' = doAttributes al in
3009+
let al' = doAttributes al in
30123010
doDeclType (TArray(bt, lo, al')) acc d
30133011

30143012
| A.PROTO (d, args, isva) ->
@@ -5685,7 +5683,29 @@ and createGlobal (specs : (typ * storage * bool * A.attribute list))
56855683
ignore (E.log "Alpha after processing global %s is:@!%t@!"
56865684
n docAlphaTable)
56875685
*)
5688-
5686+
and createAutoLocal ((((n, ndt, a, cloc) : A.name), (inite: A.init_expression)) as name):chunk =
5687+
let rec isProto (dt: decl_type) : bool =
5688+
match dt with
5689+
| PROTO (JUSTBASE, _, _) -> true
5690+
| PROTO (x, _, _) -> isProto x
5691+
| PARENTYPE (_, x, _) -> isProto x
5692+
| ARRAY (x, _, _) -> isProto x
5693+
| PTR (_, x) -> isProto x
5694+
| _ -> false
5695+
in
5696+
if isProto ndt then
5697+
E.s (error "__auto_type for prototype unsupported")
5698+
else
5699+
match inite with
5700+
| SINGLE_INIT exp ->
5701+
(match doPureExp exp with
5702+
| Some exp ->
5703+
let t = Cil.typeOf exp in
5704+
let specs = t,NoStorage,false,[] in
5705+
createLocal specs name
5706+
| None -> E.s (error "__auto_type but init not pure")
5707+
)
5708+
| _ -> E.s (error "__auto_type but not SINGLE_INIT")
56895709
(* Must catch the Static local variables. Make them global *)
56905710
and createLocal ?allow_var_decl:(allow_var_decl=true) ((_, sto, _, _) as specs)
56915711
((((n, ndt, a, cloc) : A.name),
@@ -5853,14 +5873,22 @@ and doDecl (isglobal: bool) : A.definition -> chunk = function
58535873
[] -> ""
58545874
| ((n, _, _, _), _) :: _ -> n
58555875
in
5856-
let spec_res = doSpecList sugg s in
5876+
let spec_res = try Some (doSpecList sugg s) with
5877+
TautoEncountered ->
5878+
if List.length nl <> 1 then
5879+
E.s (error "__auto_type but not exactly one initializer")
5880+
else if isglobal then
5881+
E.s (error "__auto_type unsupported for globals")
5882+
else
5883+
None
5884+
in
58575885
(* Do all the variables and concatenate the resulting statements *)
58585886
let doOneDeclarator (acc: chunk) (name: init_name) =
58595887
let (n,ndt,a,l),_ = name in
58605888
if isglobal then begin
5889+
let spec_res = match spec_res with Some s -> s | _ -> failwith "Option.get" in
58615890
let bt,_,_,attrs = spec_res in
5862-
let vtype, nattr =
5863-
doType AttrName bt (A.PARENTYPE(attrs, ndt, a)) in
5891+
let vtype, nattr = doType AttrName bt (A.PARENTYPE(attrs, ndt, a)) in
58645892
(match filterAttributes "alias" nattr with
58655893
[] -> (* ordinary prototype. *)
58665894
ignore (createGlobal spec_res name)
@@ -5873,10 +5901,13 @@ and doDecl (isglobal: bool) : A.definition -> chunk = function
58735901
ignore (createGlobal spec_res name)
58745902
end else
58755903
doAliasFun vtype n othername (s, (n,ndt,a,l)) loc
5876-
| _ -> E.s (error "Bad alias attribute at %a" d_loc !currentLoc));
5904+
| _ -> E.s (error "Bad alias attribute at %a" d_loc !currentLoc)
5905+
);
58775906
acc
58785907
end else
5879-
acc @@ createLocal spec_res name
5908+
match spec_res with
5909+
| Some spec_res -> acc @@ createLocal spec_res name
5910+
| None -> acc @@ createAutoLocal name
58805911
in
58815912
let res = List.fold_left doOneDeclarator empty nl in
58825913
(*

src/frontc/clexer.mll

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,7 @@ let init_lexicon _ =
198198
("__restrict", fun loc -> RESTRICT loc);
199199
("__restrict__", fun loc -> RESTRICT loc);
200200
("restrict", fun loc -> RESTRICT loc);
201+
("__auto_type", fun loc -> AUTOTYPE loc);
201202
(* ("__extension__", EXTENSION); *)
202203
(**** MS VC ***)
203204
("__int32", fun loc -> INT loc);

src/frontc/cparser.mly

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,7 @@ let transformOffsetOf (speclist, dtype) member =
255255
%token<Cabs.cabsloc> FLOAT32 FLOAT64 /* FloatN */
256256
%token<Cabs.cabsloc> FLOAT32X FLOAT64X /* FloatNx */
257257
%token<Cabs.cabsloc> GENERIC NORETURN /* C11 */
258+
%token<Cabs.cabsloc> AUTOTYPE /* GCC */
258259
%token<Cabs.cabsloc> ENUM STRUCT TYPEDEF UNION
259260
%token<Cabs.cabsloc> SIGNED UNSIGNED LONG SHORT
260261
%token<Cabs.cabsloc> VOLATILE EXTERN STATIC CONST ATOMIC RESTRICT AUTO REGISTER
@@ -1006,6 +1007,7 @@ type_spec: /* ISO 6.7.2 */
10061007
| FLOAT32X { Tfloat32x, $1 }
10071008
| FLOAT64X { Tfloat64x, $1 }
10081009
| DOUBLE { Tdouble, $1 }
1010+
| AUTOTYPE { Tauto, $1 }
10091011
/* | COMPLEX FLOAT { Tfloat, $2 } */
10101012
/* | COMPLEX FLOAT128{ Tfloat128, $2 } */
10111013
/* | COMPLEX DOUBLE { Tdouble, $2 } */
@@ -1044,7 +1046,7 @@ type_spec: /* ISO 6.7.2 */
10441046
| ENUM just_attributes LBRACE enum_list maybecomma RBRACE
10451047
{ Tenum ("", Some $4, $2), $1 }
10461048
| NAMED_TYPE { Tnamed (fst $1), snd $1 }
1047-
| TYPEOF LPAREN expression RPAREN { TtypeofE (fst $3), $1 }
1049+
| TYPEOF LPAREN comma_expression RPAREN { TtypeofE (smooth_expression (fst $3)), $1 }
10481050
| TYPEOF LPAREN type_name RPAREN { let s, d = $3 in
10491051
TtypeofT (s, d), $1 }
10501052
;

src/frontc/cprint.ml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,7 @@ and print_type_spec = function
194194
| TtypeofE e -> printl ["__typeof__";"("]; print_expression e; print ") "
195195
| TtypeofT (s,d) -> printl ["__typeof__";"("]; print_onlytype (s, d); print ") "
196196
| Tdefault -> print "default " (* TODO: is this right? *)
197+
| Tauto -> print "__auto_type"
197198

198199

199200
(* print "struct foo", but with specified keyword and a list of

test/small1/c11-atomic-store.c

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
#include "testharness.h"
2+
#include <stdnoreturn.h>
3+
#include <stdatomic.h>
4+
5+
typedef _Atomic _Bool atomic_bool;
6+
7+
8+
int main() {
9+
atomic_int ato;
10+
_Atomic int* ptr = &ato;
11+
12+
__extension__ ({
13+
__auto_type blub = ato;
14+
ato = 8;
15+
});
16+
17+
18+
// Extended version from GCC
19+
__extension__ ({ __auto_type __atomic_store_ptr = (
20+
21+
ptr
22+
); __typeof__ ((void)0, *__atomic_store_ptr) __atomic_store_tmp = (
23+
24+
17
25+
26+
); __atomic_store (__atomic_store_ptr, &__atomic_store_tmp, (5)); })
27+
;
28+
29+
30+
atomic_store(ptr,17);
31+
atomic_store_explicit(ptr,17,memory_order_relaxed);
32+
SUCCESS;
33+
}

test/testcil.pl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -698,6 +698,7 @@ sub addToGroup {
698698
addTest("testrunc11/c11-extendedFloat");
699699
addTest("testrunc11/c11-noreturn");
700700
addTest("testrunc11/c11-atomic");
701+
addTest("testrunc11/c11-atomic-store");
701702
addTest("testrunc11/c11-static-assert");
702703
addTest("testrunc11/c11-align-of");
703704
addTest("testrunc11/gcc-c11-generic-1");

0 commit comments

Comments
 (0)