aboutsummaryrefslogtreecommitdiffstats
path: root/cfrontend/C2C.ml
diff options
context:
space:
mode:
Diffstat (limited to 'cfrontend/C2C.ml')
-rw-r--r--cfrontend/C2C.ml95
1 files changed, 93 insertions, 2 deletions
diff --git a/cfrontend/C2C.ml b/cfrontend/C2C.ml
index fd10efb4..7413c443 100644
--- a/cfrontend/C2C.ml
+++ b/cfrontend/C2C.ml
@@ -831,6 +831,97 @@ and convertExprList env el =
| [] -> Enil
| e1 :: el' -> Econs(convertExpr env e1, convertExprList env el')
+(** ** Extended assembly *)
+
+module StringMap = Map.Make(String)
+
+let re_asm_placeholder =
+ Str.regexp "\\(%[0-9]+\\|%\\[[a-zA-Z_][a-zA-Z_0-9]*\\]\\|%%\\)"
+
+let convertAsm env txt outputs inputs clobber =
+
+ (* On the fly renaming of labeled and numbered arguments *)
+ let name_of_label lbl pos =
+ match lbl with
+ | None -> sprintf "%%%d" pos
+ | Some l -> sprintf "%%[%s]" l in
+ let set_label_reg lbl pos pos' subst =
+ StringMap.add (name_of_label lbl pos) (sprintf "%%%d" pos') subst
+ and set_label_mem lbl pos pos' subst =
+ StringMap.add (name_of_label lbl pos)
+ (CBuiltins.asm_mem_argument (sprintf "%%%d" pos'))
+ subst
+ and set_label_const lbl pos n subst =
+ StringMap.add (name_of_label lbl pos) (sprintf "%Ld" n) subst in
+
+ (* Fix up the input expressions:
+ - add "&" for inputs of kind "m"
+ - evaluate constants for inputs of kind "i" *)
+ let rec fixupInputs accu pos pos' subst = function
+ | [] ->
+ (List.rev accu, subst)
+ | (lbl, cstr, e) :: inputs ->
+ match cstr with
+ | "r" | "rm" ->
+ fixupInputs (e :: accu) (pos + 1) (pos' + 1)
+ (set_label_reg lbl pos pos' subst) inputs
+ | "m" | "o" ->
+ fixupInputs (Cutil.eaddrof e :: accu) (pos + 1) (pos' + 1)
+ (set_label_mem lbl pos pos' subst) inputs
+ | "i" | "n" ->
+ let n =
+ match Ceval.integer_expr env e with
+ | Some n -> n
+ | None -> error "asm argument of kind 'i'/'n' is not a constant"; 0L in
+ fixupInputs accu (pos + 1) pos'
+ (set_label_const lbl pos n subst) inputs
+ | _ ->
+ unsupported ("asm argument of kind '" ^ cstr ^ "'");
+ ([], subst) in
+
+ (* Check the output expressions *)
+ let (output', ty_res, (inputs', subst)) =
+ match outputs with
+ | [] ->
+ (None, TVoid [], fixupInputs [] 0 0 StringMap.empty inputs)
+ | [(lbl, cstr, e)] ->
+ if not (cstr = "=r" || cstr = "=rm") then
+ unsupported ("asm result of kind '" ^ cstr ^ "'");
+ (Some e, e.etyp,
+ fixupInputs [] 1 1 (set_label_reg lbl 0 0 StringMap.empty) inputs)
+ | _ ->
+ error "asm statement with 2 or more results";
+ (None, TVoid [], ([], StringMap.empty)) in
+
+ (* Check the clobber list *)
+ List.iter
+ (fun c ->
+ if not (c = "memory" || c = "cc") then
+ unsupported ("asm register clobber '" ^ c ^ "'"))
+ clobber;
+
+ (* Rename the %[ident] and %nnn placeholders in the asm text *)
+ let txt' =
+ Str.global_substitute re_asm_placeholder
+ (fun txt -> let s = Str.matched_group 1 txt in
+ try StringMap.find s subst with Not_found -> s)
+ txt in
+
+ (* Build the Ebuiltin expression *)
+ let e =
+ let tinputs = convertTypArgs env [] inputs' in
+ let toutput = convertTyp env ty_res in
+ Ebuiltin(EF_inline_asm(intern_string txt',
+ signature_of_type tinputs toutput cc_default),
+ tinputs,
+ convertExprList env inputs',
+ convertTyp env ty_res) in
+
+ (* Add an assignment to the output, if any *)
+ match output' with
+ | None -> e
+ | Some lhs -> Eassign (convertLvalue env lhs, e, typeof e)
+
(* Separate the cases of a switch statement body *)
type switchlabel =
@@ -940,11 +1031,11 @@ let rec convertStmt ploc env s =
unsupported "nested blocks"; Sskip
| C.Sdecl _ ->
unsupported "inner declarations"; Sskip
- | C.Sasm txt ->
+ | C.Sasm(attrs, txt, outputs, inputs, clobber) ->
if not !Clflags.option_finline_asm then
unsupported "inline 'asm' statement (consider adding option -finline-asm)";
add_lineno ploc s.sloc
- (Sdo (Ebuiltin (EF_inline_asm (intern_string txt), Tnil, Enil, Tvoid)))
+ (Sdo (convertAsm env txt outputs inputs clobber))
and convertSwitch ploc env is_64 = function
| [] ->