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); + break; + case AtomicExpr::AO__c11_atomic_fetch_sub: + case AtomicExpr::AO__atomic_fetch_sub: + case AtomicExpr::AO__atomic_sub_fetch: + Replacement = APValue(AtomicInt - ArgumentInt); + break; + case AtomicExpr::AO__c11_atomic_fetch_and: + case AtomicExpr::AO__atomic_fetch_and: + case AtomicExpr::AO__atomic_and_fetch: + Replacement = APValue(AtomicInt & ArgumentInt); + break; + case AtomicExpr::AO__c11_atomic_fetch_or: + case AtomicExpr::AO__atomic_fetch_or: + case AtomicExpr::AO__atomic_or_fetch: + Replacement = APValue(AtomicInt | ArgumentInt); + break; + case AtomicExpr::AO__c11_atomic_fetch_xor: + case AtomicExpr::AO__atomic_fetch_xor: + case AtomicExpr::AO__atomic_xor_fetch: + Replacement = APValue(AtomicInt ^ ArgumentInt); + break; + case AtomicExpr::AO__c11_atomic_fetch_nand: + case AtomicExpr::AO__atomic_fetch_nand: + case AtomicExpr::AO__atomic_nand_fetch: + Replacement = APValue(~(AtomicInt & ArgumentInt)); + break; + case AtomicExpr::AO__c11_atomic_fetch_max: + case AtomicExpr::AO__atomic_fetch_max: + case AtomicExpr::AO__atomic_max_fetch: + Replacement = APValue(std::max(AtomicInt, ArgumentInt)); + break; + case AtomicExpr::AO__c11_atomic_fetch_min: + case AtomicExpr::AO__atomic_fetch_min: + case AtomicExpr::AO__atomic_min_fetch: + Replacement = APValue(std::min(AtomicInt, ArgumentInt)); + break; + default: + return false; + } + } else if (AtomicValueTy->isRealFloatingType()) { + assert(CurrentValue.isFloat()); + assert(ArgumentVal.isFloat()); + + const llvm::RoundingMode RM = getActiveRoundingMode(Info, E); + APFloat AtomicFlt = CurrentValue.getFloat(); + const APFloat ArgumentFlt = ArgumentVal.getFloat(); + APFloat::opStatus St; + + switch (E->getOp()) { + case AtomicExpr::AO__c11_atomic_fetch_add: + St = AtomicFlt.add(ArgumentFlt, RM); + Replacement = APValue(AtomicFlt); + break; + case AtomicExpr::AO__c11_atomic_fetch_sub: + St = AtomicFlt.subtract(ArgumentFlt, RM); + Replacement = APValue(AtomicFlt); + break; + default: + // GCC's atomic fetch-op doesn't support float operands. + return false; + } + + if (!checkFloatingPointResult(Info, E, St)) + return false; + + } else if (AtomicValueTy->isPointerType()) { + assert(CurrentValue.isLValue()); + assert(ArgumentVal.isInt()); + + LValue AtomicPtr; + AtomicPtr.setFrom(Info.Ctx, CurrentValue); + + APSInt ArgumentInt = ArgumentVal.getInt(); + + // Calculate size of pointee object. + CharUnits SizeOfPointee; + if (!HandleSizeof(Info, E->getExprLoc(), AtomicValueTy->getPointeeType(), + SizeOfPointee)) + return false; + + // GCC's atomic_fetch add/sub operations takes arguments in bytes and + // not in multiplies of sizeof(T). ---------------- AaronBallman wrote: ```suggestion // not in multiples of sizeof(T). ``` 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