Hana =?utf-8?q?Dusíková?= <hani...@hanicka.net>, Hana =?utf-8?q?Dusíková?= <hani...@hanicka.net> Message-ID: In-Reply-To: <llvm.org/llvm/llvm-project/pull/98...@github.com>
================ @@ -17893,4 +18005,425 @@ std::optional<bool> EvaluateBuiltinIsWithinLifetime(IntExprEvaluator &IEE, IsWithinLifetimeHandler handler{Info}; return findSubobject(Info, E, CO, Val.getLValueDesignator(), handler); } + } // namespace + +static bool EvaluateAtomicOrder(const AtomicExpr *E, EvalInfo &Info) { + // We need to evaluate Order argument(s), but we ignore it as constant + // evaluation is single threaded. + APSInt OrderIgnoredResult; + + if (E->getOp() != AtomicExpr::AO__c11_atomic_init) { + const Expr *OrderSuccess = E->getOrder(); + if (OrderSuccess && + !EvaluateInteger(OrderSuccess, OrderIgnoredResult, Info)) + return false; + } + + if (E->isCmpXChg()) { + const Expr *OrderFail = E->getOrderFail(); + if (!EvaluateInteger(OrderFail, OrderIgnoredResult, Info)) + return false; + } + + return true; +} + +static bool EvaluateAtomicLoad(const AtomicExpr *E, APValue &Result, + EvalInfo &Info) { + LValue AtomicStorageLV; + + if (!EvaluatePointer(E->getPtr(), AtomicStorageLV, Info)) + return false; + + return handleLValueToRValueConversion(Info, E->getPtr(), E->getValueType(), + AtomicStorageLV, Result); +} + +static bool EvaluateAtomicLoadInto(const AtomicExpr *E, EvalInfo &Info) { + APValue LocalResult; + + if (!EvaluateAtomicLoad(E, LocalResult, Info)) + return false; + + assert(E->getVal1()->getType()->isPointerType()); + QualType PointeeTy = E->getVal1()->getType()->getPointeeType(); + LValue PointeeLV; + + if (!EvaluatePointer(E->getVal1(), PointeeLV, Info)) + return false; + + if (!handleAssignment(Info, E->getVal1(), PointeeLV, PointeeTy, LocalResult)) + return false; + + return true; +} + +static bool EvaluateAtomicStore(const AtomicExpr *E, EvalInfo &Info) { + LValue AtomicStorageLV; + + if (!EvaluatePointer(E->getPtr(), AtomicStorageLV, Info)) + return false; + + APValue ProvidedValue; + + // GCC's atomic_store takes pointer to value, not value itself. + if (E->getOp() == AtomicExpr::AO__atomic_store) { + LValue ProvidedLV; + if (!EvaluatePointer(E->getVal1(), ProvidedLV, Info)) + return false; + + if (!handleLValueToRValueConversion(Info, E->getVal1(), + E->getVal1()->getType(), ProvidedLV, + ProvidedValue)) + return false; + + } else { + if (!Evaluate(ProvidedValue, Info, E->getVal1())) + return false; + } + if (!handleAssignment(Info, E, AtomicStorageLV, E->getValueType(), + ProvidedValue)) + return false; + + return true; +} + +static bool EvaluateAtomicExchange(const AtomicExpr *E, APValue &Result, + EvalInfo &Info) { + assert(E->getOp() == AtomicExpr::AO__c11_atomic_exchange || + E->getOp() == AtomicExpr::AO__atomic_exchange_n); + + if (!EvaluateAtomicLoad(E, Result, Info)) + return false; + + if (!EvaluateAtomicStore(E, Info)) + return false; + + return true; +} + +static bool EvaluateAtomicExchangeInto(const AtomicExpr *E, EvalInfo &Info) { + assert(E->getOp() == AtomicExpr::AO__atomic_exchange); + // Implementation of GCC's exchange (non _n version). + LValue AtomicStorageLV; + if (!EvaluatePointer(E->getPtr(), AtomicStorageLV, Info)) + return false; + + // Read previous value. + APValue PreviousValue; + if (!handleLValueToRValueConversion(Info, E->getPtr(), E->getValueType(), + AtomicStorageLV, PreviousValue)) + return false; + + // Get value pointer by argument of the exchange operation. + LValue ProvidedLV; + if (!EvaluatePointer(E->getVal1(), ProvidedLV, Info)) + return false; + + APValue ProvidedValue; + if (!handleLValueToRValueConversion(Info, E->getVal1(), + E->getVal1()->getType(), ProvidedLV, + ProvidedValue)) + return false; + + // Store provided value to atomic value. + if (!handleAssignment(Info, E, AtomicStorageLV, E->getValueType(), + ProvidedValue)) + return false; + + // Store previous value in output pointer. + assert(E->getVal2()->getType()->isPointerType()); + QualType PointeeTy = E->getVal2()->getType()->getPointeeType(); + LValue PointeeLV; + + if (!EvaluatePointer(E->getVal2(), PointeeLV, Info)) + return false; + + if (!handleAssignment(Info, E->getVal2(), PointeeLV, PointeeTy, + PreviousValue)) + return false; + + return true; +} + +static bool EvaluateAtomicFetchOp(const AtomicExpr *E, APValue &Result, + EvalInfo &Info, bool StoreToResultAfter) { + // Read the atomic. + LValue AtomicStorageLV; + QualType AtomicValueTy = E->getValueType(); + if (!EvaluatePointer(E->getPtr(), AtomicStorageLV, Info)) + return false; + + APValue CurrentValue; + if (!handleLValueToRValueConversion(Info, E->getPtr(), E->getType(), + AtomicStorageLV, CurrentValue)) + return false; + + // Store current value for fetch-OP operations. + if (!StoreToResultAfter) + Result = CurrentValue; + + // Read argument for fetch OP. + APValue ArgumentVal; + if (!Evaluate(ArgumentVal, Info, E->getVal1())) + return false; + + // Calculate new value. + APValue Replacement; + if (AtomicValueTy->isIntegralOrEnumerationType()) { + assert(CurrentValue.isInt()); + assert(ArgumentVal.isInt()); + + const APSInt AtomicInt = CurrentValue.getInt(); + const APSInt ArgumentInt = ArgumentVal.getInt(); + + switch (E->getOp()) { + case AtomicExpr::AO__c11_atomic_fetch_add: + case AtomicExpr::AO__atomic_fetch_add: + case AtomicExpr::AO__atomic_add_fetch: + // Atomic operations are defined for overflow + Replacement = APValue(AtomicInt + ArgumentInt); ---------------- AaronBallman wrote: Please be sure there's a test that overflow gives the expected results. Also, please be sure to test weirder atomic integer types like `__int128`, `_BitInt`, and if we support them, vector types. (I've not gotten to the tests yet, so if this is already handled, please ignore.) https://github.com/llvm/llvm-project/pull/98756 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits