clang API Documentation
00001 //===- ThreadSafetyLogical.cpp ---------------------------------*- C++ --*-===// 00002 // 00003 // The LLVM Compiler Infrastructure 00004 // 00005 // This file is distributed under the University of Illinois Open Source 00006 // License. See LICENSE.TXT for details. 00007 // 00008 //===----------------------------------------------------------------------===// 00009 // This file defines a representation for logical expressions with SExpr leaves 00010 // that are used as part of fact-checking capability expressions. 00011 //===----------------------------------------------------------------------===// 00012 00013 #include "clang/Analysis/Analyses/ThreadSafetyLogical.h" 00014 00015 using namespace llvm; 00016 using namespace clang::threadSafety::lexpr; 00017 00018 // Implication. We implement De Morgan's Laws by maintaining LNeg and RNeg 00019 // to keep track of whether LHS and RHS are negated. 00020 static bool implies(const LExpr *LHS, bool LNeg, const LExpr *RHS, bool RNeg) { 00021 // In comments below, we write => for implication. 00022 00023 // Calculates the logical AND implication operator. 00024 const auto LeftAndOperator = [=](const BinOp *A) { 00025 return implies(A->left(), LNeg, RHS, RNeg) && 00026 implies(A->right(), LNeg, RHS, RNeg); 00027 }; 00028 const auto RightAndOperator = [=](const BinOp *A) { 00029 return implies(LHS, LNeg, A->left(), RNeg) && 00030 implies(LHS, LNeg, A->right(), RNeg); 00031 }; 00032 00033 // Calculates the logical OR implication operator. 00034 const auto LeftOrOperator = [=](const BinOp *A) { 00035 return implies(A->left(), LNeg, RHS, RNeg) || 00036 implies(A->right(), LNeg, RHS, RNeg); 00037 }; 00038 const auto RightOrOperator = [=](const BinOp *A) { 00039 return implies(LHS, LNeg, A->left(), RNeg) || 00040 implies(LHS, LNeg, A->right(), RNeg); 00041 }; 00042 00043 // Recurse on right. 00044 switch (RHS->kind()) { 00045 case LExpr::And: 00046 // When performing right recursion: 00047 // C => A & B [if] C => A and C => B 00048 // When performing right recursion (negated): 00049 // C => !(A & B) [if] C => !A | !B [===] C => !A or C => !B 00050 return RNeg ? RightOrOperator(cast<And>(RHS)) 00051 : RightAndOperator(cast<And>(RHS)); 00052 case LExpr::Or: 00053 // When performing right recursion: 00054 // C => (A | B) [if] C => A or C => B 00055 // When performing right recursion (negated): 00056 // C => !(A | B) [if] C => !A & !B [===] C => !A and C => !B 00057 return RNeg ? RightAndOperator(cast<Or>(RHS)) 00058 : RightOrOperator(cast<Or>(RHS)); 00059 case LExpr::Not: 00060 // Note that C => !A is very different from !(C => A). It would be incorrect 00061 // to return !implies(LHS, RHS). 00062 return implies(LHS, LNeg, cast<Not>(RHS)->exp(), !RNeg); 00063 case LExpr::Terminal: 00064 // After reaching the terminal, it's time to recurse on the left. 00065 break; 00066 } 00067 00068 // RHS is now a terminal. Recurse on Left. 00069 switch (LHS->kind()) { 00070 case LExpr::And: 00071 // When performing left recursion: 00072 // A & B => C [if] A => C or B => C 00073 // When performing left recursion (negated): 00074 // !(A & B) => C [if] !A | !B => C [===] !A => C and !B => C 00075 return LNeg ? LeftAndOperator(cast<And>(LHS)) 00076 : LeftOrOperator(cast<And>(LHS)); 00077 case LExpr::Or: 00078 // When performing left recursion: 00079 // A | B => C [if] A => C and B => C 00080 // When performing left recursion (negated): 00081 // !(A | B) => C [if] !A & !B => C [===] !A => C or !B => C 00082 return LNeg ? LeftOrOperator(cast<Or>(LHS)) 00083 : LeftAndOperator(cast<Or>(LHS)); 00084 case LExpr::Not: 00085 // Note that A => !C is very different from !(A => C). It would be incorrect 00086 // to return !implies(LHS, RHS). 00087 return implies(cast<Not>(LHS)->exp(), !LNeg, RHS, RNeg); 00088 case LExpr::Terminal: 00089 // After reaching the terminal, it's time to perform identity comparisons. 00090 break; 00091 } 00092 00093 // A => A 00094 // !A => !A 00095 if (LNeg != RNeg) 00096 return false; 00097 00098 // FIXME -- this should compare SExprs for equality, not pointer equality. 00099 return cast<Terminal>(LHS)->expr() == cast<Terminal>(RHS)->expr(); 00100 } 00101 00102 namespace clang { 00103 namespace threadSafety { 00104 namespace lexpr { 00105 00106 bool implies(const LExpr *LHS, const LExpr *RHS) { 00107 // Start out by assuming that LHS and RHS are not negated. 00108 return ::implies(LHS, false, RHS, false); 00109 } 00110 } 00111 } 00112 }