You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

227 lines
9.3 KiB

(*
* Copyright (c) 2013 - present Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*)
(** Utility module for translating unary and binary operations and compound assignments *)
open! IStd
module L = Logging
(* Returns the translation of assignment when ARC mode is enabled in Obj-C *)
(* For __weak and __unsafe_unretained the translation is the same as non-ARC *)
(* (this is because, in these cases, there is no change in the reference counter *)
(* of the pointee).*)
(* The difference is when the lvalue is a __strong or __autoreleasing. In those*)
(* case we need to add proper retain/release.*)
(* See document: "Objective-C Automatic Reference Counting" describing the semantics *)
let assignment_arc_mode e1 typ e2 loc rhs_owning_method is_e1_decl =
let assign = Sil.Store (e1, typ, e2, loc) in
let retain_pname = BuiltinDecl.__objc_retain in
let release_pname = BuiltinDecl.__objc_release in
let autorelease_pname = BuiltinDecl.__set_autorelease_attribute in
let mk_call procname e t =
let bi_retain = Exp.Const (Const.Cfun procname) in
Sil.Call (None, bi_retain, [(e, t)], loc, CallFlags.default) in
match typ.Typ.desc with
| Typ.Tptr (_, Typ.Pk_pointer) when not rhs_owning_method && not is_e1_decl ->
(* for __strong e1 = e2 the semantics is*)
(* retain(e2); tmp=e1; e1=e2; release(tmp); *)
let retain = mk_call retain_pname e2 typ in
let id = Ident.create_fresh Ident.knormal in
let tmp_assign = Sil.Load (id, e1, typ, loc) in
let release = mk_call release_pname (Exp.Var id) typ in
(e1,[retain; tmp_assign; assign; release])
| Typ.Tptr (_, Typ.Pk_pointer) when not rhs_owning_method && is_e1_decl ->
(* for A __strong *e1 = e2 the semantics is*)
(* retain(e2); e1=e2; *)
let retain = mk_call retain_pname e2 typ in
(e1,[retain; assign])
| Typ.Tptr (_, Typ.Pk_objc_weak)
| Typ.Tptr (_, Typ.Pk_objc_unsafe_unretained) ->
(e1, [assign])
| Typ.Tptr (_, Typ.Pk_objc_autoreleasing) ->
(* for __autoreleasing e1 = e2 the semantics is*)
(* retain(e2); autorelease(e2); e1=e2; *)
let retain = mk_call retain_pname e2 typ in
let autorelease = mk_call autorelease_pname e2 typ in
(e1, [retain; autorelease; assign])
| _ -> (e1, [assign])
(* Returns a pair ([binary_expression], instructions) for binary operator representing a *)
(* CompoundAssignment. "binary_expression" is returned when we are calculating an expression*)
(* "instructions" is not empty when the binary operator is actually a statement like an *)
(* assignment. *)
let compound_assignment_binary_operation_instruction boi e1 typ e2 loc =
let id = Ident.create_fresh Ident.knormal in
let instr1 = Sil.Load (id, e1, typ, loc) in
let e_res, instr_op = match boi.Clang_ast_t.boi_kind with
| `AddAssign ->
let e1_plus_e2 = Exp.BinOp(Binop.PlusA, Exp.Var id, e2) in
(e1, [Sil.Store (e1, typ, e1_plus_e2, loc)])
| `SubAssign ->
let e1_sub_e2 = Exp.BinOp(Binop.MinusA, Exp.Var id, e2) in
(e1, [Sil.Store (e1, typ, e1_sub_e2, loc)])
| `MulAssign ->
let e1_mul_e2 = Exp.BinOp(Binop.Mult, Exp.Var id, e2) in
(e1, [Sil.Store (e1, typ, e1_mul_e2, loc)])
| `DivAssign ->
let e1_div_e2 = Exp.BinOp(Binop.Div, Exp.Var id, e2) in
(e1, [Sil.Store (e1, typ, e1_div_e2, loc)])
| `ShlAssign ->
let e1_shl_e2 = Exp.BinOp(Binop.Shiftlt, Exp.Var id, e2) in
(e1, [Sil.Store (e1, typ, e1_shl_e2, loc)])
| `ShrAssign ->
let e1_shr_e2 = Exp.BinOp(Binop.Shiftrt, Exp.Var id, e2) in
(e1, [Sil.Store (e1, typ, e1_shr_e2, loc)])
| `RemAssign ->
let e1_mod_e2 = Exp.BinOp(Binop.Mod, Exp.Var id, e2) in
(e1, [Sil.Store (e1, typ, e1_mod_e2, loc)])
| `AndAssign ->
let e1_and_e2 = Exp.BinOp(Binop.BAnd, Exp.Var id, e2) in
(e1, [Sil.Store (e1, typ, e1_and_e2, loc)])
| `OrAssign ->
let e1_or_e2 = Exp.BinOp(Binop.BOr, Exp.Var id, e2) in
(e1, [Sil.Store (e1, typ, e1_or_e2, loc)])
| `XorAssign ->
let e1_xor_e2 = Exp.BinOp(Binop.BXor, Exp.Var id, e2) in
(e1, [Sil.Store (e1, typ, e1_xor_e2, loc)])
| _ -> assert false in
(e_res, instr1:: instr_op)
(* Returns a pair ([binary_expression], instructions). "binary_expression" *)
(* is returned when we are calculating an expression "instructions" is not *)
(* empty when the binary operator is actually a statement like an *)
(* assignment. *)
let binary_operation_instruction boi e1 typ e2 loc rhs_owning_method =
let binop_exp op = Exp.BinOp(op, e1, e2) in
match boi.Clang_ast_t.boi_kind with
| `Add -> (binop_exp (Binop.PlusA), [])
| `Mul -> (binop_exp (Binop.Mult), [])
| `Div -> (binop_exp (Binop.Div), [])
| `Rem -> (binop_exp (Binop.Mod), [])
| `Sub -> (binop_exp (Binop.MinusA), [])
| `Shl -> (binop_exp (Binop.Shiftlt), [])
| `Shr -> (binop_exp(Binop.Shiftrt), [])
| `Or -> (binop_exp (Binop.BOr), [])
| `And -> (binop_exp (Binop.BAnd), [])
| `Xor -> (binop_exp (Binop.BXor), [])
| `LT -> (binop_exp (Binop.Lt), [])
| `GT -> (binop_exp (Binop.Gt), [])
| `LE -> (binop_exp (Binop.Le), [])
| `GE -> (binop_exp (Binop.Ge), [])
| `NE -> (binop_exp (Binop.Ne), [])
| `EQ -> (binop_exp (Binop.Eq), [])
| `LAnd -> (binop_exp (Binop.LAnd), [])
| `LOr -> (binop_exp (Binop.LOr), [])
| `Assign ->
if !Config.arc_mode && ObjcInterface_decl.is_pointer_to_objc_class typ then
assignment_arc_mode e1 typ e2 loc rhs_owning_method false
else
(e1, [Sil.Store (e1, typ, e2, loc)])
| `Comma -> (e2, []) (* C99 6.5.17-2 *)
| `MulAssign | `DivAssign | `RemAssign | `AddAssign | `SubAssign
| `ShlAssign | `ShrAssign | `AndAssign | `XorAssign | `OrAssign ->
compound_assignment_binary_operation_instruction boi e1 typ e2 loc
(* We should not get here. *)
(* These should be treated by compound_assignment_binary_operation_instruction*)
| bok ->
L.(debug Capture Medium)
"@\nWARNING: Missing translation for Binary Operator Kind %s. Construct ignored...@\n"
(Clang_ast_j.string_of_binary_operator_kind bok);
(Exp.minus_one, [])
let unary_operation_instruction translation_unit_context uoi e typ loc =
let un_exp op =
Exp.UnOp(op, e, Some typ) in
match uoi.Clang_ast_t.uoi_kind with
| `PostInc ->
let id = Ident.create_fresh Ident.knormal in
let instr1 = Sil.Load (id, e, typ, loc) in
let e_plus_1 = Exp.BinOp(Binop.PlusA, Exp.Var id, Exp.Const(Const.Cint (IntLit.one))) in
(Exp.Var id, instr1::[Sil.Store (e, typ, e_plus_1, loc)])
| `PreInc ->
let id = Ident.create_fresh Ident.knormal in
let instr1 = Sil.Load (id, e, typ, loc) in
let e_plus_1 = Exp.BinOp(Binop.PlusA, Exp.Var id, Exp.Const(Const.Cint (IntLit.one))) in
let exp = if CGeneral_utils.is_cpp_translation translation_unit_context then
e
else
e_plus_1 in
(exp, instr1::[Sil.Store (e, typ, e_plus_1, loc)])
| `PostDec ->
let id = Ident.create_fresh Ident.knormal in
let instr1 = Sil.Load (id, e, typ, loc) in
let e_minus_1 = Exp.BinOp(Binop.MinusA, Exp.Var id, Exp.Const(Const.Cint (IntLit.one))) in
(Exp.Var id, instr1::[Sil.Store (e, typ, e_minus_1, loc)])
| `PreDec ->
let id = Ident.create_fresh Ident.knormal in
let instr1 = Sil.Load (id, e, typ, loc) in
let e_minus_1 = Exp.BinOp(Binop.MinusA, Exp.Var id, Exp.Const(Const.Cint (IntLit.one))) in
let exp = if CGeneral_utils.is_cpp_translation translation_unit_context then
e
else
e_minus_1 in
(exp, instr1::[Sil.Store (e, typ, e_minus_1, loc)])
| `Not -> (un_exp (Unop.BNot), [])
| `Minus -> (un_exp (Unop.Neg), [])
| `Plus -> (e, [])
| `LNot -> (un_exp (Unop.LNot), [])
| `Deref ->
(* Actual dereferencing is handled by implicit cast from rvalue to lvalue *)
(e, [])
| `AddrOf -> (e, [])
| `Real | `Imag | `Extension | `Coawait ->
let uok = Clang_ast_j.string_of_unary_operator_kind (uoi.Clang_ast_t.uoi_kind) in
L.(debug Capture Medium)
"@\nWARNING: Missing translation for Unary Operator Kind %s. \
The construct has been ignored...@\n"
uok;
(e, [])
let bin_op_to_string boi =
match boi.Clang_ast_t.boi_kind with
| `PtrMemD -> "PtrMemD"
| `PtrMemI -> "PtrMemI"
| `Mul -> "Mul"
| `Div -> "Div"
| `Rem -> "Rem"
| `Add -> "Add"
| `Sub -> "Sub"
| `Shl -> "Shl"
| `Shr -> "Shr"
| `LT -> "LT"
| `GT -> "GT"
| `LE -> "LE"
| `GE -> "GE"
| `EQ -> "EQ"
| `NE -> "NE"
| `And -> "And"
| `Xor -> "Xor"
| `Or -> "Or"
| `LAnd -> "LAnd"
| `LOr -> "LOr"
| `Assign -> "Assign"
| `MulAssign -> "MulAssign"
| `DivAssign -> "DivAssign"
| `RemAssign -> "RemAssing"
| `AddAssign -> "AddAssign"
| `SubAssign -> "SubAssign"
| `ShlAssign -> "ShlAssign"
| `ShrAssign -> "ShrAssign"
| `AndAssign -> "AndAssign"
| `XorAssign -> "XorAssign"
| `OrAssign -> "OrAssign"
| `Comma -> "Comma"
let sil_const_plus_one const =
match const with
| Exp.Const (Const.Cint n) ->
Exp.Const (Const.Cint (IntLit.add n IntLit.one))
| _ -> Exp.BinOp (Binop.PlusA, const, Exp.Const (Const.Cint (IntLit.one)))