Vendor import of llvm-project branch release/18.x llvmorg-18.1.1-0-gdba2a75e9c7e.
This commit is contained in:
@@ -1090,7 +1090,9 @@ class Sema final {
|
||||
if (FD) {
|
||||
FD->setWillHaveBody(true);
|
||||
S.ExprEvalContexts.back().InImmediateFunctionContext =
|
||||
FD->isImmediateFunction();
|
||||
FD->isImmediateFunction() ||
|
||||
S.ExprEvalContexts[S.ExprEvalContexts.size() - 2]
|
||||
.isConstantEvaluated();
|
||||
S.ExprEvalContexts.back().InImmediateEscalatingFunctionContext =
|
||||
S.getLangOpts().CPlusPlus20 && FD->isImmediateEscalating();
|
||||
} else
|
||||
|
||||
@@ -258,7 +258,6 @@ void AArch64TargetInfo::getTargetDefinesARMV83A(const LangOptions &Opts,
|
||||
MacroBuilder &Builder) const {
|
||||
Builder.defineMacro("__ARM_FEATURE_COMPLEX", "1");
|
||||
Builder.defineMacro("__ARM_FEATURE_JCVT", "1");
|
||||
Builder.defineMacro("__ARM_FEATURE_PAUTH", "1");
|
||||
// Also include the Armv8.2 defines
|
||||
getTargetDefinesARMV82A(Opts, Builder);
|
||||
}
|
||||
|
||||
@@ -237,12 +237,14 @@ class LLVM_LIBRARY_VISIBILITY MipsTargetInfo : public TargetInfo {
|
||||
case 'r': // CPU registers.
|
||||
case 'd': // Equivalent to "r" unless generating MIPS16 code.
|
||||
case 'y': // Equivalent to "r", backward compatibility only.
|
||||
case 'f': // floating-point registers.
|
||||
case 'c': // $25 for indirect jumps
|
||||
case 'l': // lo register
|
||||
case 'x': // hilo register pair
|
||||
Info.setAllowsRegister();
|
||||
return true;
|
||||
case 'f': // floating-point registers.
|
||||
Info.setAllowsRegister();
|
||||
return FloatABI != SoftFloat;
|
||||
case 'I': // Signed 16-bit constant
|
||||
case 'J': // Integer 0
|
||||
case 'K': // Unsigned 16-bit constant
|
||||
|
||||
@@ -240,9 +240,12 @@ struct MapRegionCounters : public RecursiveASTVisitor<MapRegionCounters> {
|
||||
if (MCDCMaxCond == 0)
|
||||
return true;
|
||||
|
||||
/// At the top of the logical operator nest, reset the number of conditions.
|
||||
if (LogOpStack.empty())
|
||||
/// At the top of the logical operator nest, reset the number of conditions,
|
||||
/// also forget previously seen split nesting cases.
|
||||
if (LogOpStack.empty()) {
|
||||
NumCond = 0;
|
||||
SplitNestedLogicalOp = false;
|
||||
}
|
||||
|
||||
if (const Expr *E = dyn_cast<Expr>(S)) {
|
||||
const BinaryOperator *BinOp = dyn_cast<BinaryOperator>(E->IgnoreParens());
|
||||
@@ -293,7 +296,7 @@ struct MapRegionCounters : public RecursiveASTVisitor<MapRegionCounters> {
|
||||
"contains an operation with a nested boolean expression. "
|
||||
"Expression will not be covered");
|
||||
Diag.Report(S->getBeginLoc(), DiagID);
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Was the maximum number of conditions encountered?
|
||||
@@ -304,7 +307,7 @@ struct MapRegionCounters : public RecursiveASTVisitor<MapRegionCounters> {
|
||||
"number of conditions (%0) exceeds max (%1). "
|
||||
"Expression will not be covered");
|
||||
Diag.Report(S->getBeginLoc(), DiagID) << NumCond << MCDCMaxCond;
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Otherwise, allocate the number of bytes required for the bitmap
|
||||
|
||||
@@ -18294,7 +18294,6 @@ void Sema::CheckUnusedVolatileAssignment(Expr *E) {
|
||||
}
|
||||
|
||||
void Sema::MarkExpressionAsImmediateEscalating(Expr *E) {
|
||||
assert(!FunctionScopes.empty() && "Expected a function scope");
|
||||
assert(getLangOpts().CPlusPlus20 &&
|
||||
ExprEvalContexts.back().InImmediateEscalatingFunctionContext &&
|
||||
"Cannot mark an immediate escalating expression outside of an "
|
||||
@@ -18311,7 +18310,8 @@ void Sema::MarkExpressionAsImmediateEscalating(Expr *E) {
|
||||
} else {
|
||||
assert(false && "expected an immediately escalating expression");
|
||||
}
|
||||
getCurFunction()->FoundImmediateEscalatingExpression = true;
|
||||
if (FunctionScopeInfo *FI = getCurFunction())
|
||||
FI->FoundImmediateEscalatingExpression = true;
|
||||
}
|
||||
|
||||
ExprResult Sema::CheckForImmediateInvocation(ExprResult E, FunctionDecl *Decl) {
|
||||
|
||||
@@ -33,7 +33,13 @@ void longjmp(jmp_buf env, int val);
|
||||
#include <__assert> // all public C++ headers provide the assertion handler
|
||||
#include <__config>
|
||||
|
||||
#include <setjmp.h>
|
||||
// <setjmp.h> is not provided by libc++
|
||||
#if __has_include(<setjmp.h>)
|
||||
# include <setjmp.h>
|
||||
# ifdef _LIBCPP_SETJMP_H
|
||||
# error "If libc++ starts defining <setjmp.h>, the __has_include check should move to libc++'s <setjmp.h>"
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
|
||||
# pragma GCC system_header
|
||||
|
||||
@@ -43,8 +43,8 @@ class iterator_range {
|
||||
IteratorT begin_iterator, end_iterator;
|
||||
|
||||
public:
|
||||
#if __GNUC__ == 7
|
||||
// Be careful no to break gcc-7 on the mlir target.
|
||||
#if __GNUC__ == 7 || (__GNUC__ == 8 && __GNUC_MINOR__ < 4)
|
||||
// Be careful no to break gcc-7 and gcc-8 < 8.4 on the mlir target.
|
||||
// See https://github.com/llvm/llvm-project/issues/63843
|
||||
template <typename Container>
|
||||
#else
|
||||
|
||||
@@ -339,14 +339,26 @@ def UseSampleProfile : StrBoolAttr<"use-sample-profile">;
|
||||
def DenormalFPMath : ComplexStrAttr<"denormal-fp-math", [FnAttr]>;
|
||||
def DenormalFPMathF32 : ComplexStrAttr<"denormal-fp-math-f32", [FnAttr]>;
|
||||
|
||||
// Attribute compatiblity rules are generated to check the attribute of the
|
||||
// caller and callee and decide whether inlining should be allowed. CompatRule
|
||||
// and child classes are used for the rule generation. CompatRule takes only a
|
||||
// compare function which could be templated with the attribute type.
|
||||
// CompatRuleStrAttr takes the compare function and the string attribute for
|
||||
// checking compatibility for inline substitution.
|
||||
class CompatRule<string F> {
|
||||
// The name of the function called to check the attribute of the caller and
|
||||
// callee and decide whether inlining should be allowed. The function's
|
||||
// signature must match "bool(const Function&, const Function &)", where the
|
||||
// first parameter is the reference to the caller and the second parameter is
|
||||
// the reference to the callee. It must return false if the attributes of the
|
||||
// caller and callee are incompatible, and true otherwise.
|
||||
// The function's signature must match "bool(const Function&, const
|
||||
// Function&)", where the first parameter is the reference to the caller and
|
||||
// the second parameter is the reference to the callee. It must return false
|
||||
// if the attributes of the caller and callee are incompatible, and true
|
||||
// otherwise.
|
||||
string CompatFunc = F;
|
||||
string AttrName = "";
|
||||
}
|
||||
|
||||
class CompatRuleStrAttr<string F, string Attr> : CompatRule<F> {
|
||||
// The checker function is extended with an third argument as the function
|
||||
// attribute string "bool(const Function&, const Function&, const StringRef&)".
|
||||
string AttrName = Attr;
|
||||
}
|
||||
|
||||
def : CompatRule<"isEqual<SanitizeAddressAttr>">;
|
||||
@@ -359,7 +371,9 @@ def : CompatRule<"isEqual<ShadowCallStackAttr>">;
|
||||
def : CompatRule<"isEqual<UseSampleProfileAttr>">;
|
||||
def : CompatRule<"isEqual<NoProfileAttr>">;
|
||||
def : CompatRule<"checkDenormMode">;
|
||||
|
||||
def : CompatRuleStrAttr<"isEqual", "sign-return-address">;
|
||||
def : CompatRuleStrAttr<"isEqual", "sign-return-address-key">;
|
||||
def : CompatRuleStrAttr<"isEqual", "branch-protection-pauth-lr">;
|
||||
|
||||
class MergeRule<string F> {
|
||||
// The name of the function called to merge the attributes of the caller and
|
||||
|
||||
@@ -478,7 +478,7 @@ inline constexpr ArchInfo ARMV8_1A = { VersionTuple{8, 1}, AProfile, "armv8.1-a
|
||||
inline constexpr ArchInfo ARMV8_2A = { VersionTuple{8, 2}, AProfile, "armv8.2-a", "+v8.2a", (ARMV8_1A.DefaultExts |
|
||||
AArch64::ExtensionBitset({AArch64::AEK_RAS}))};
|
||||
inline constexpr ArchInfo ARMV8_3A = { VersionTuple{8, 3}, AProfile, "armv8.3-a", "+v8.3a", (ARMV8_2A.DefaultExts |
|
||||
AArch64::ExtensionBitset({AArch64::AEK_RCPC, AArch64::AEK_JSCVT, AArch64::AEK_FCMA}))};
|
||||
AArch64::ExtensionBitset({AArch64::AEK_FCMA, AArch64::AEK_JSCVT, AArch64::AEK_PAUTH, AArch64::AEK_RCPC}))};
|
||||
inline constexpr ArchInfo ARMV8_4A = { VersionTuple{8, 4}, AProfile, "armv8.4-a", "+v8.4a", (ARMV8_3A.DefaultExts |
|
||||
AArch64::ExtensionBitset({AArch64::AEK_DOTPROD}))};
|
||||
inline constexpr ArchInfo ARMV8_5A = { VersionTuple{8, 5}, AProfile, "armv8.5-a", "+v8.5a", (ARMV8_4A.DefaultExts)};
|
||||
@@ -805,6 +805,12 @@ inline constexpr CpuInfo CpuInfos[] = {
|
||||
{AArch64::AEK_FP16, AArch64::AEK_RAND, AArch64::AEK_SM4,
|
||||
AArch64::AEK_SHA3, AArch64::AEK_SHA2, AArch64::AEK_AES,
|
||||
AArch64::AEK_MTE, AArch64::AEK_SB, AArch64::AEK_SSBS}))},
|
||||
{"ampere1b", ARMV8_7A,
|
||||
(AArch64::ExtensionBitset({AArch64::AEK_FP16, AArch64::AEK_RAND,
|
||||
AArch64::AEK_SM4, AArch64::AEK_SHA3,
|
||||
AArch64::AEK_SHA2, AArch64::AEK_AES,
|
||||
AArch64::AEK_MTE, AArch64::AEK_SB,
|
||||
AArch64::AEK_SSBS, AArch64::AEK_CSSC}))},
|
||||
};
|
||||
|
||||
// An alias for a CPU.
|
||||
|
||||
@@ -364,7 +364,7 @@ bool llvm::isSafeToLoadUnconditionally(Value *V, Align Alignment, APInt &Size,
|
||||
|
||||
if (Size.getBitWidth() > 64)
|
||||
return false;
|
||||
const uint64_t LoadSize = Size.getZExtValue();
|
||||
const TypeSize LoadSize = TypeSize::getFixed(Size.getZExtValue());
|
||||
|
||||
// Otherwise, be a little bit aggressive by scanning the local block where we
|
||||
// want to check to see if the pointer is already being loaded or stored
|
||||
@@ -414,11 +414,11 @@ bool llvm::isSafeToLoadUnconditionally(Value *V, Align Alignment, APInt &Size,
|
||||
|
||||
// Handle trivial cases.
|
||||
if (AccessedPtr == V &&
|
||||
LoadSize <= DL.getTypeStoreSize(AccessedTy))
|
||||
TypeSize::isKnownLE(LoadSize, DL.getTypeStoreSize(AccessedTy)))
|
||||
return true;
|
||||
|
||||
if (AreEquivalentAddressValues(AccessedPtr->stripPointerCasts(), V) &&
|
||||
LoadSize <= DL.getTypeStoreSize(AccessedTy))
|
||||
TypeSize::isKnownLE(LoadSize, DL.getTypeStoreSize(AccessedTy)))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
||||
@@ -2045,6 +2045,11 @@ static bool isEqual(const Function &Caller, const Function &Callee) {
|
||||
Callee.getFnAttribute(AttrClass::getKind());
|
||||
}
|
||||
|
||||
static bool isEqual(const Function &Caller, const Function &Callee,
|
||||
const StringRef &AttrName) {
|
||||
return Caller.getFnAttribute(AttrName) == Callee.getFnAttribute(AttrName);
|
||||
}
|
||||
|
||||
/// Compute the logical AND of the attributes of the caller and the
|
||||
/// callee.
|
||||
///
|
||||
|
||||
@@ -837,6 +837,7 @@ include "AArch64SchedA64FX.td"
|
||||
include "AArch64SchedThunderX3T110.td"
|
||||
include "AArch64SchedTSV110.td"
|
||||
include "AArch64SchedAmpere1.td"
|
||||
include "AArch64SchedAmpere1B.td"
|
||||
include "AArch64SchedNeoverseN1.td"
|
||||
include "AArch64SchedNeoverseN2.td"
|
||||
include "AArch64SchedNeoverseV1.td"
|
||||
@@ -1376,6 +1377,24 @@ def TuneAmpere1A : SubtargetFeature<"ampere1a", "ARMProcFamily", "Ampere1A",
|
||||
FeatureLdpAlignedOnly,
|
||||
FeatureStpAlignedOnly]>;
|
||||
|
||||
def TuneAmpere1B : SubtargetFeature<"ampere1b", "ARMProcFamily", "Ampere1B",
|
||||
"Ampere Computing Ampere-1B processors", [
|
||||
FeaturePostRAScheduler,
|
||||
FeatureFuseAES,
|
||||
FeatureFuseAdrpAdd,
|
||||
FeatureAddrLSLFast,
|
||||
FeatureALULSLFast,
|
||||
FeatureAggressiveFMA,
|
||||
FeatureArithmeticBccFusion,
|
||||
FeatureCmpBccFusion,
|
||||
FeatureFuseAddress,
|
||||
FeatureFuseLiterals,
|
||||
FeatureStorePairSuppress,
|
||||
FeatureEnableSelectOptimize,
|
||||
FeaturePredictableSelectIsExpensive,
|
||||
FeatureLdpAlignedOnly,
|
||||
FeatureStpAlignedOnly]>;
|
||||
|
||||
def ProcessorFeatures {
|
||||
list<SubtargetFeature> A53 = [HasV8_0aOps, FeatureCRC, FeatureCrypto,
|
||||
FeatureFPARMv8, FeatureNEON, FeaturePerfMon];
|
||||
@@ -1529,6 +1548,11 @@ def ProcessorFeatures {
|
||||
FeatureMTE, FeatureSSBS, FeatureRandGen,
|
||||
FeatureSB, FeatureSM4, FeatureSHA2,
|
||||
FeatureSHA3, FeatureAES];
|
||||
list<SubtargetFeature> Ampere1B = [HasV8_7aOps, FeatureNEON, FeaturePerfMon,
|
||||
FeatureMTE, FeatureSSBS, FeatureRandGen,
|
||||
FeatureSB, FeatureSM4, FeatureSHA2,
|
||||
FeatureSHA3, FeatureAES, FeatureCSSC,
|
||||
FeatureWFxT, FeatureFullFP16];
|
||||
|
||||
// ETE and TRBE are future architecture extensions. We temporarily enable them
|
||||
// by default for users targeting generic AArch64. The extensions do not
|
||||
@@ -1696,6 +1720,9 @@ def : ProcessorModel<"ampere1", Ampere1Model, ProcessorFeatures.Ampere1,
|
||||
def : ProcessorModel<"ampere1a", Ampere1Model, ProcessorFeatures.Ampere1A,
|
||||
[TuneAmpere1A]>;
|
||||
|
||||
def : ProcessorModel<"ampere1b", Ampere1BModel, ProcessorFeatures.Ampere1B,
|
||||
[TuneAmpere1B]>;
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Assembly parser
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
@@ -29,7 +29,7 @@ def CortexA53Model : SchedMachineModel {
|
||||
list<Predicate> UnsupportedFeatures = !listconcat(SVEUnsupported.F,
|
||||
PAUnsupported.F,
|
||||
SMEUnsupported.F,
|
||||
[HasMTE]);
|
||||
[HasMTE, HasCSSC]);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -34,7 +34,7 @@ def CortexA57Model : SchedMachineModel {
|
||||
list<Predicate> UnsupportedFeatures = !listconcat(SVEUnsupported.F,
|
||||
PAUnsupported.F,
|
||||
SMEUnsupported.F,
|
||||
[HasMTE]);
|
||||
[HasMTE, HasCSSC]);
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
@@ -22,7 +22,8 @@ def A64FXModel : SchedMachineModel {
|
||||
|
||||
list<Predicate> UnsupportedFeatures = !listconcat(SMEUnsupported.F, SVEUnsupported.F,
|
||||
[HasMTE, HasMatMulInt8, HasBF16,
|
||||
HasPAuth, HasPAuthLR, HasCPA]);
|
||||
HasPAuth, HasPAuthLR, HasCPA,
|
||||
HasCSSC]);
|
||||
let FullInstRWOverlapCheck = 0;
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -21,7 +21,7 @@ def CycloneModel : SchedMachineModel {
|
||||
list<Predicate> UnsupportedFeatures = !listconcat(SVEUnsupported.F,
|
||||
PAUnsupported.F,
|
||||
SMEUnsupported.F,
|
||||
[HasMTE]);
|
||||
[HasMTE, HasCSSC]);
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
@@ -27,7 +27,7 @@ def ExynosM3Model : SchedMachineModel {
|
||||
list<Predicate> UnsupportedFeatures = !listconcat(SVEUnsupported.F,
|
||||
PAUnsupported.F,
|
||||
SMEUnsupported.F,
|
||||
[HasMTE]);
|
||||
[HasMTE, HasCSSC]);
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
@@ -27,7 +27,7 @@ def ExynosM4Model : SchedMachineModel {
|
||||
list<Predicate> UnsupportedFeatures = !listconcat(SVEUnsupported.F,
|
||||
PAUnsupported.F,
|
||||
SMEUnsupported.F,
|
||||
[HasMTE]);
|
||||
[HasMTE, HasCSSC]);
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
@@ -27,7 +27,7 @@ def ExynosM5Model : SchedMachineModel {
|
||||
list<Predicate> UnsupportedFeatures = !listconcat(SVEUnsupported.F,
|
||||
PAUnsupported.F,
|
||||
SMEUnsupported.F,
|
||||
[HasMTE]);
|
||||
[HasMTE, HasCSSC]);
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
@@ -26,7 +26,7 @@ def FalkorModel : SchedMachineModel {
|
||||
list<Predicate> UnsupportedFeatures = !listconcat(SVEUnsupported.F,
|
||||
PAUnsupported.F,
|
||||
SMEUnsupported.F,
|
||||
[HasMTE]);
|
||||
[HasMTE, HasCSSC]);
|
||||
// FIXME: Remove when all errors have been fixed.
|
||||
let FullInstRWOverlapCheck = 0;
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@ def KryoModel : SchedMachineModel {
|
||||
list<Predicate> UnsupportedFeatures = !listconcat(SVEUnsupported.F,
|
||||
PAUnsupported.F,
|
||||
SMEUnsupported.F,
|
||||
[HasMTE]);
|
||||
[HasMTE, HasCSSC]);
|
||||
// FIXME: Remove when all errors have been fixed.
|
||||
let FullInstRWOverlapCheck = 0;
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@ def NeoverseN1Model : SchedMachineModel {
|
||||
list<Predicate> UnsupportedFeatures = !listconcat(PAUnsupported.F,
|
||||
SMEUnsupported.F,
|
||||
SVEUnsupported.F,
|
||||
[HasMTE]);
|
||||
[HasMTE, HasCSSC]);
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
@@ -19,7 +19,7 @@ def NeoverseN2Model : SchedMachineModel {
|
||||
let CompleteModel = 1;
|
||||
|
||||
list<Predicate> UnsupportedFeatures = !listconcat(SMEUnsupported.F,
|
||||
[HasSVE2p1, HasPAuthLR, HasCPA]);
|
||||
[HasSVE2p1, HasPAuthLR, HasCPA, HasCSSC]);
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
@@ -28,7 +28,8 @@ def NeoverseV1Model : SchedMachineModel {
|
||||
|
||||
list<Predicate> UnsupportedFeatures = !listconcat(SVE2Unsupported.F,
|
||||
SMEUnsupported.F,
|
||||
[HasMTE, HasCPA]);
|
||||
[HasMTE, HasCPA,
|
||||
HasCSSC]);
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
@@ -22,7 +22,8 @@ def NeoverseV2Model : SchedMachineModel {
|
||||
let CompleteModel = 1;
|
||||
|
||||
list<Predicate> UnsupportedFeatures = !listconcat(SMEUnsupported.F,
|
||||
[HasSVE2p1, HasCPA]);
|
||||
[HasSVE2p1, HasCPA,
|
||||
HasCSSC]);
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
@@ -27,7 +27,7 @@ def TSV110Model : SchedMachineModel {
|
||||
list<Predicate> UnsupportedFeatures = !listconcat(SVEUnsupported.F,
|
||||
PAUnsupported.F,
|
||||
SMEUnsupported.F,
|
||||
[HasMTE]);
|
||||
[HasMTE, HasCSSC]);
|
||||
}
|
||||
|
||||
// Define each kind of processor resource and number available on the TSV110,
|
||||
|
||||
@@ -28,7 +28,7 @@ def ThunderXT8XModel : SchedMachineModel {
|
||||
list<Predicate> UnsupportedFeatures = !listconcat(SVEUnsupported.F,
|
||||
PAUnsupported.F,
|
||||
SMEUnsupported.F,
|
||||
[HasMTE]);
|
||||
[HasMTE, HasCSSC]);
|
||||
// FIXME: Remove when all errors have been fixed.
|
||||
let FullInstRWOverlapCheck = 0;
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@ def ThunderX2T99Model : SchedMachineModel {
|
||||
list<Predicate> UnsupportedFeatures = !listconcat(SVEUnsupported.F,
|
||||
PAUnsupported.F,
|
||||
SMEUnsupported.F,
|
||||
[HasMTE]);
|
||||
[HasMTE, HasCSSC]);
|
||||
// FIXME: Remove when all errors have been fixed.
|
||||
let FullInstRWOverlapCheck = 0;
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@ def ThunderX3T110Model : SchedMachineModel {
|
||||
list<Predicate> UnsupportedFeatures = !listconcat(SVEUnsupported.F,
|
||||
PAUnsupported.F,
|
||||
SMEUnsupported.F,
|
||||
[HasMTE]);
|
||||
[HasMTE, HasCSSC]);
|
||||
// FIXME: Remove when all errors have been fixed.
|
||||
let FullInstRWOverlapCheck = 0;
|
||||
}
|
||||
|
||||
@@ -296,6 +296,7 @@ void AArch64Subtarget::initializeProperties(bool HasMinSize) {
|
||||
break;
|
||||
case Ampere1:
|
||||
case Ampere1A:
|
||||
case Ampere1B:
|
||||
CacheLineSize = 64;
|
||||
PrefFunctionAlignment = Align(64);
|
||||
PrefLoopAlignment = Align(64);
|
||||
|
||||
@@ -42,6 +42,7 @@ class AArch64Subtarget final : public AArch64GenSubtargetInfo {
|
||||
A64FX,
|
||||
Ampere1,
|
||||
Ampere1A,
|
||||
Ampere1B,
|
||||
AppleA7,
|
||||
AppleA10,
|
||||
AppleA11,
|
||||
|
||||
@@ -150,6 +150,7 @@ class MipsAsmParser : public MCTargetAsmParser {
|
||||
bool IsLittleEndian;
|
||||
bool IsPicEnabled;
|
||||
bool IsCpRestoreSet;
|
||||
bool CurForbiddenSlotAttr;
|
||||
int CpRestoreOffset;
|
||||
unsigned GPReg;
|
||||
unsigned CpSaveLocation;
|
||||
@@ -552,6 +553,7 @@ class MipsAsmParser : public MCTargetAsmParser {
|
||||
|
||||
CurrentFn = nullptr;
|
||||
|
||||
CurForbiddenSlotAttr = false;
|
||||
IsPicEnabled = getContext().getObjectFileInfo()->isPositionIndependent();
|
||||
|
||||
IsCpRestoreSet = false;
|
||||
@@ -723,6 +725,16 @@ class MipsAsmParser : public MCTargetAsmParser {
|
||||
return getSTI().hasFeature(Mips::FeatureGINV);
|
||||
}
|
||||
|
||||
bool hasForbiddenSlot(const MCInstrDesc &MCID) const {
|
||||
return !inMicroMipsMode() && (MCID.TSFlags & MipsII::HasForbiddenSlot);
|
||||
}
|
||||
|
||||
bool SafeInForbiddenSlot(const MCInstrDesc &MCID) const {
|
||||
return !(MCID.TSFlags & MipsII::IsCTI);
|
||||
}
|
||||
|
||||
void onEndOfFile() override;
|
||||
|
||||
/// Warn if RegIndex is the same as the current AT.
|
||||
void warnIfRegIndexIsAT(unsigned RegIndex, SMLoc Loc);
|
||||
|
||||
@@ -2307,7 +2319,41 @@ bool MipsAsmParser::processInstruction(MCInst &Inst, SMLoc IDLoc,
|
||||
|
||||
bool FillDelaySlot =
|
||||
MCID.hasDelaySlot() && AssemblerOptions.back()->isReorder();
|
||||
if (FillDelaySlot)
|
||||
|
||||
// Get previous instruction`s forbidden slot attribute and
|
||||
// whether set reorder.
|
||||
bool PrevForbiddenSlotAttr = CurForbiddenSlotAttr;
|
||||
|
||||
// Flag represents we set reorder after nop.
|
||||
bool SetReorderAfterNop = false;
|
||||
|
||||
// If previous instruction has forbidden slot and .set reorder
|
||||
// is active and current instruction is CTI.
|
||||
// Then emit a NOP after it.
|
||||
if (PrevForbiddenSlotAttr && !SafeInForbiddenSlot(MCID)) {
|
||||
TOut.emitEmptyDelaySlot(false, IDLoc, STI);
|
||||
// When 'FillDelaySlot' is true, the existing logic will add
|
||||
// noreorder before instruction and reorder after it. So there
|
||||
// need exclude this case avoiding two '.set reorder'.
|
||||
// The format of the first case is:
|
||||
// .set noreorder
|
||||
// bnezc
|
||||
// nop
|
||||
// .set reorder
|
||||
if (AssemblerOptions.back()->isReorder() && !FillDelaySlot) {
|
||||
SetReorderAfterNop = true;
|
||||
TOut.emitDirectiveSetReorder();
|
||||
}
|
||||
}
|
||||
|
||||
// Save current instruction`s forbidden slot and whether set reorder.
|
||||
// This is the judgment condition for whether to add nop.
|
||||
// We would add a couple of '.set noreorder' and '.set reorder' to
|
||||
// wrap the current instruction and the next instruction.
|
||||
CurForbiddenSlotAttr =
|
||||
hasForbiddenSlot(MCID) && AssemblerOptions.back()->isReorder();
|
||||
|
||||
if (FillDelaySlot || CurForbiddenSlotAttr)
|
||||
TOut.emitDirectiveSetNoReorder();
|
||||
|
||||
MacroExpanderResultTy ExpandResult =
|
||||
@@ -2322,6 +2368,17 @@ bool MipsAsmParser::processInstruction(MCInst &Inst, SMLoc IDLoc,
|
||||
return true;
|
||||
}
|
||||
|
||||
// When current instruction was not CTI, recover reorder state.
|
||||
// The format of the second case is:
|
||||
// .set noreoder
|
||||
// bnezc
|
||||
// add
|
||||
// .set reorder
|
||||
if (PrevForbiddenSlotAttr && !SetReorderAfterNop && !FillDelaySlot &&
|
||||
AssemblerOptions.back()->isReorder()) {
|
||||
TOut.emitDirectiveSetReorder();
|
||||
}
|
||||
|
||||
// We know we emitted an instruction on the MER_NotAMacro or MER_Success path.
|
||||
// If we're in microMIPS mode then we must also set EF_MIPS_MICROMIPS.
|
||||
if (inMicroMipsMode()) {
|
||||
@@ -2331,6 +2388,14 @@ bool MipsAsmParser::processInstruction(MCInst &Inst, SMLoc IDLoc,
|
||||
|
||||
// If this instruction has a delay slot and .set reorder is active,
|
||||
// emit a NOP after it.
|
||||
// The format of the third case is:
|
||||
// .set noreorder
|
||||
// bnezc
|
||||
// nop
|
||||
// .set noreorder
|
||||
// j
|
||||
// nop
|
||||
// .set reorder
|
||||
if (FillDelaySlot) {
|
||||
TOut.emitEmptyDelaySlot(hasShortDelaySlot(Inst), IDLoc, STI);
|
||||
TOut.emitDirectiveSetReorder();
|
||||
@@ -2356,6 +2421,17 @@ bool MipsAsmParser::processInstruction(MCInst &Inst, SMLoc IDLoc,
|
||||
return false;
|
||||
}
|
||||
|
||||
void MipsAsmParser::onEndOfFile() {
|
||||
MipsTargetStreamer &TOut = getTargetStreamer();
|
||||
SMLoc IDLoc = SMLoc();
|
||||
// If has pending forbidden slot, fill nop and recover reorder.
|
||||
if (CurForbiddenSlotAttr) {
|
||||
TOut.emitEmptyDelaySlot(false, IDLoc, STI);
|
||||
if (AssemblerOptions.back()->isReorder())
|
||||
TOut.emitDirectiveSetReorder();
|
||||
}
|
||||
}
|
||||
|
||||
MipsAsmParser::MacroExpanderResultTy
|
||||
MipsAsmParser::tryExpandInstruction(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out,
|
||||
const MCSubtargetInfo *STI) {
|
||||
|
||||
@@ -4128,14 +4128,18 @@ MipsTargetLowering::getRegForInlineAsmConstraint(const TargetRegisterInfo *TRI,
|
||||
case 'd': // Address register. Same as 'r' unless generating MIPS16 code.
|
||||
case 'y': // Same as 'r'. Exists for compatibility.
|
||||
case 'r':
|
||||
if (VT == MVT::i32 || VT == MVT::i16 || VT == MVT::i8 || VT == MVT::i1) {
|
||||
if ((VT == MVT::i32 || VT == MVT::i16 || VT == MVT::i8 ||
|
||||
VT == MVT::i1) ||
|
||||
(VT == MVT::f32 && Subtarget.useSoftFloat())) {
|
||||
if (Subtarget.inMips16Mode())
|
||||
return std::make_pair(0U, &Mips::CPU16RegsRegClass);
|
||||
return std::make_pair(0U, &Mips::GPR32RegClass);
|
||||
}
|
||||
if (VT == MVT::i64 && !Subtarget.isGP64bit())
|
||||
if ((VT == MVT::i64 || (VT == MVT::f64 && Subtarget.useSoftFloat())) &&
|
||||
!Subtarget.isGP64bit())
|
||||
return std::make_pair(0U, &Mips::GPR32RegClass);
|
||||
if (VT == MVT::i64 && Subtarget.isGP64bit())
|
||||
if ((VT == MVT::i64 || (VT == MVT::f64 && Subtarget.useSoftFloat())) &&
|
||||
Subtarget.isGP64bit())
|
||||
return std::make_pair(0U, &Mips::GPR64RegClass);
|
||||
// This will generate an error message
|
||||
return std::make_pair(0U, nullptr);
|
||||
|
||||
@@ -1067,7 +1067,8 @@ bool SystemZTargetLowering::isLegalAddressingMode(const DataLayout &DL,
|
||||
if (!isInt<20>(AM.BaseOffs))
|
||||
return false;
|
||||
|
||||
bool RequireD12 = Subtarget.hasVector() && Ty->isVectorTy();
|
||||
bool RequireD12 =
|
||||
Subtarget.hasVector() && (Ty->isVectorTy() || Ty->isIntegerTy(128));
|
||||
AddressingMode SupportedAM(!RequireD12, true);
|
||||
if (I != nullptr)
|
||||
SupportedAM = supportedAddressingMode(I, Subtarget.hasVector());
|
||||
@@ -1922,7 +1923,7 @@ SystemZTargetLowering::LowerCall(CallLoweringInfo &CLI,
|
||||
unsigned N = getNumRegistersForCallingConv(Ctx, CLI.CallConv, OrigArgVT);
|
||||
SlotVT = EVT::getIntegerVT(Ctx, PartVT.getSizeInBits() * N);
|
||||
} else {
|
||||
SlotVT = Outs[I].ArgVT;
|
||||
SlotVT = Outs[I].VT;
|
||||
}
|
||||
SDValue SpillSlot = DAG.CreateStackTemporary(SlotVT);
|
||||
int FI = cast<FrameIndexSDNode>(SpillSlot)->getIndex();
|
||||
|
||||
@@ -321,6 +321,7 @@ StringRef sys::detail::getHostCPUNameForARM(StringRef ProcCpuinfoContent) {
|
||||
return StringSwitch<const char *>(Part)
|
||||
.Case("0xac3", "ampere1")
|
||||
.Case("0xac4", "ampere1a")
|
||||
.Case("0xac5", "ampere1b")
|
||||
.Default("generic");
|
||||
}
|
||||
|
||||
|
||||
@@ -407,6 +407,10 @@ bool FlattenCFGOpt::CompareIfRegionBlock(BasicBlock *Block1, BasicBlock *Block2,
|
||||
/// form, by inverting the condition and the branch successors. The same
|
||||
/// approach goes for the opposite case.
|
||||
bool FlattenCFGOpt::MergeIfRegion(BasicBlock *BB, IRBuilder<> &Builder) {
|
||||
// We cannot merge the if-region if the merge point has phi nodes.
|
||||
if (isa<PHINode>(BB->front()))
|
||||
return false;
|
||||
|
||||
BasicBlock *IfTrue2, *IfFalse2;
|
||||
BranchInst *DomBI2 = GetIfCondition(BB, IfTrue2, IfFalse2);
|
||||
if (!DomBI2)
|
||||
@@ -493,16 +497,6 @@ bool FlattenCFGOpt::MergeIfRegion(BasicBlock *BB, IRBuilder<> &Builder) {
|
||||
PBI->replaceUsesOfWith(PBI->getCondition(), NC);
|
||||
Builder.SetInsertPoint(SaveInsertBB, SaveInsertPt);
|
||||
|
||||
// Handle PHI node to replace its predecessors to FirstEntryBlock.
|
||||
for (BasicBlock *Succ : successors(PBI)) {
|
||||
for (PHINode &Phi : Succ->phis()) {
|
||||
for (unsigned i = 0, e = Phi.getNumIncomingValues(); i != e; ++i) {
|
||||
if (Phi.getIncomingBlock(i) == SecondEntryBlock)
|
||||
Phi.setIncomingBlock(i, FirstEntryBlock);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Remove IfTrue1
|
||||
if (IfTrue1 != FirstEntryBlock) {
|
||||
IfTrue1->dropAllReferences();
|
||||
|
||||
@@ -3369,11 +3369,17 @@ void llvm::patchReplacementInstruction(Instruction *I, Value *Repl) {
|
||||
|
||||
// Patch the replacement so that it is not more restrictive than the value
|
||||
// being replaced.
|
||||
WithOverflowInst *UnusedWO;
|
||||
// When replacing the result of a llvm.*.with.overflow intrinsic with a
|
||||
// overflowing binary operator, nuw/nsw flags may no longer hold.
|
||||
if (isa<OverflowingBinaryOperator>(ReplInst) &&
|
||||
match(I, m_ExtractValue<0>(m_WithOverflowInst(UnusedWO))))
|
||||
ReplInst->dropPoisonGeneratingFlags();
|
||||
// Note that if 'I' is a load being replaced by some operation,
|
||||
// for example, by an arithmetic operation, then andIRFlags()
|
||||
// would just erase all math flags from the original arithmetic
|
||||
// operation, which is clearly not wanted and not needed.
|
||||
if (!isa<LoadInst>(I))
|
||||
else if (!isa<LoadInst>(I))
|
||||
ReplInst->andIRFlags(I);
|
||||
|
||||
// FIXME: If both the original and replacement value are part of the
|
||||
|
||||
@@ -139,7 +139,7 @@ bool SourceCoverageView::shouldRenderRegionMarkers(
|
||||
|
||||
bool SourceCoverageView::hasSubViews() const {
|
||||
return !ExpansionSubViews.empty() || !InstantiationSubViews.empty() ||
|
||||
!BranchSubViews.empty();
|
||||
!BranchSubViews.empty() || !MCDCSubViews.empty();
|
||||
}
|
||||
|
||||
std::unique_ptr<SourceCoverageView>
|
||||
|
||||
@@ -246,6 +246,9 @@ tr:hover {
|
||||
tr:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
tr:has(> td >a:target) > td.code > pre {
|
||||
background-color: #ffa;
|
||||
}
|
||||
)";
|
||||
|
||||
const char *EndHeader = "</head>";
|
||||
@@ -990,15 +993,13 @@ void SourceCoverageViewHTML::renderMCDCView(raw_ostream &OS, MCDCView &MRV,
|
||||
std::string ColNoStr = Twine(DecisionRegion.ColumnStart).str();
|
||||
std::string TargetName = "L" + LineNoStr;
|
||||
OS << tag("span",
|
||||
a("#" + TargetName, tag("span", LineNoStr + ":" + ColNoStr),
|
||||
TargetName),
|
||||
a("#" + TargetName, tag("span", LineNoStr + ":" + ColNoStr)),
|
||||
"line-number") +
|
||||
") to (";
|
||||
LineNoStr = utostr(uint64_t(DecisionRegion.LineEnd));
|
||||
ColNoStr = utostr(uint64_t(DecisionRegion.ColumnEnd));
|
||||
OS << tag("span",
|
||||
a("#" + TargetName, tag("span", LineNoStr + ":" + ColNoStr),
|
||||
TargetName),
|
||||
a("#" + TargetName, tag("span", LineNoStr + ":" + ColNoStr)),
|
||||
"line-number") +
|
||||
")\n\n";
|
||||
|
||||
|
||||
@@ -382,7 +382,8 @@ void SourceCoverageViewText::renderMCDCView(raw_ostream &OS, MCDCView &MRV,
|
||||
colored_ostream(OS, raw_ostream::RED,
|
||||
getOptions().Colors && Record.getPercentCovered() < 100.0,
|
||||
/*Bold=*/false, /*BG=*/true)
|
||||
<< format("%0.2f", Record.getPercentCovered()) << "%\n";
|
||||
<< format("%0.2f", Record.getPercentCovered()) << "%";
|
||||
OS << "\n";
|
||||
renderLinePrefix(OS, ViewDepth);
|
||||
OS << "\n";
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#include "ObjDumper.h"
|
||||
#include "llvm-readobj.h"
|
||||
#include "llvm/Object/Archive.h"
|
||||
#include "llvm/Object/Decompressor.h"
|
||||
#include "llvm/Object/ObjectFile.h"
|
||||
#include "llvm/Support/Error.h"
|
||||
#include "llvm/Support/FormatVariadic.h"
|
||||
@@ -142,8 +143,23 @@ getSectionRefsByNameOrIndex(const object::ObjectFile &Obj,
|
||||
return Ret;
|
||||
}
|
||||
|
||||
static void maybeDecompress(const object::ObjectFile &Obj,
|
||||
StringRef SectionName, StringRef &SectionContent,
|
||||
SmallString<0> &Out) {
|
||||
Expected<object::Decompressor> Decompressor = object::Decompressor::create(
|
||||
SectionName, SectionContent, Obj.isLittleEndian(), Obj.is64Bit());
|
||||
if (!Decompressor)
|
||||
reportWarning(Decompressor.takeError(), Obj.getFileName());
|
||||
else if (auto Err = Decompressor->resizeAndDecompress(Out))
|
||||
reportWarning(std::move(Err), Obj.getFileName());
|
||||
else
|
||||
SectionContent = Out;
|
||||
}
|
||||
|
||||
void ObjDumper::printSectionsAsString(const object::ObjectFile &Obj,
|
||||
ArrayRef<std::string> Sections) {
|
||||
ArrayRef<std::string> Sections,
|
||||
bool Decompress) {
|
||||
SmallString<0> Out;
|
||||
bool First = true;
|
||||
for (object::SectionRef Section :
|
||||
getSectionRefsByNameOrIndex(Obj, Sections)) {
|
||||
@@ -156,12 +172,16 @@ void ObjDumper::printSectionsAsString(const object::ObjectFile &Obj,
|
||||
|
||||
StringRef SectionContent =
|
||||
unwrapOrError(Obj.getFileName(), Section.getContents());
|
||||
if (Decompress && Section.isCompressed())
|
||||
maybeDecompress(Obj, SectionName, SectionContent, Out);
|
||||
printAsStringList(SectionContent);
|
||||
}
|
||||
}
|
||||
|
||||
void ObjDumper::printSectionsAsHex(const object::ObjectFile &Obj,
|
||||
ArrayRef<std::string> Sections) {
|
||||
ArrayRef<std::string> Sections,
|
||||
bool Decompress) {
|
||||
SmallString<0> Out;
|
||||
bool First = true;
|
||||
for (object::SectionRef Section :
|
||||
getSectionRefsByNameOrIndex(Obj, Sections)) {
|
||||
@@ -174,6 +194,8 @@ void ObjDumper::printSectionsAsHex(const object::ObjectFile &Obj,
|
||||
|
||||
StringRef SectionContent =
|
||||
unwrapOrError(Obj.getFileName(), Section.getContents());
|
||||
if (Decompress && Section.isCompressed())
|
||||
maybeDecompress(Obj, SectionName, SectionContent, Out);
|
||||
const uint8_t *SecContent = SectionContent.bytes_begin();
|
||||
const uint8_t *SecEnd = SecContent + SectionContent.size();
|
||||
|
||||
|
||||
@@ -175,9 +175,9 @@ class ObjDumper {
|
||||
void printAsStringList(StringRef StringContent, size_t StringDataOffset = 0);
|
||||
|
||||
void printSectionsAsString(const object::ObjectFile &Obj,
|
||||
ArrayRef<std::string> Sections);
|
||||
ArrayRef<std::string> Sections, bool Decompress);
|
||||
void printSectionsAsHex(const object::ObjectFile &Obj,
|
||||
ArrayRef<std::string> Sections);
|
||||
ArrayRef<std::string> Sections, bool Decompress);
|
||||
|
||||
std::function<Error(const Twine &Msg)> WarningHandler;
|
||||
void reportUniqueWarning(Error Err) const;
|
||||
|
||||
@@ -20,6 +20,7 @@ def all : FF<"all", "Equivalent to setting: --file-header, --program-headers, --
|
||||
def arch_specific : FF<"arch-specific", "Display architecture-specific information">;
|
||||
def bb_addr_map : FF<"bb-addr-map", "Display the BB address map section">;
|
||||
def cg_profile : FF<"cg-profile", "Display call graph profile section">;
|
||||
def decompress : FF<"decompress", "Dump decompressed section content when used with -x or -p">;
|
||||
defm demangle : BB<"demangle", "Demangle symbol names", "Do not demangle symbol names (default)">;
|
||||
def dependent_libraries : FF<"dependent-libraries", "Display the dependent libraries section">;
|
||||
def dyn_relocations : FF<"dyn-relocations", "Display the dynamic relocation entries in the file">;
|
||||
@@ -139,3 +140,4 @@ def : F<"u", "Alias for --unwind">, Alias<unwind>;
|
||||
def : F<"X", "Alias for --extra-sym-info">, Alias<extra_sym_info>, Group<grp_elf>;
|
||||
def : F<"V", "Alias for --version-info">, Alias<version_info>, Group<grp_elf>;
|
||||
def : JoinedOrSeparate<["-"], "x">, Alias<hex_dump_EQ>, HelpText<"Alias for --hex-dump">, MetaVarName<"<name or index>">;
|
||||
def : F<"z", "Alias for --decompress">, Alias<decompress>;
|
||||
|
||||
@@ -97,6 +97,7 @@ static bool ArchSpecificInfo;
|
||||
static bool BBAddrMap;
|
||||
bool ExpandRelocs;
|
||||
static bool CGProfile;
|
||||
static bool Decompress;
|
||||
bool Demangle;
|
||||
static bool DependentLibraries;
|
||||
static bool DynRelocs;
|
||||
@@ -212,6 +213,7 @@ static void parseOptions(const opt::InputArgList &Args) {
|
||||
opts::ArchSpecificInfo = Args.hasArg(OPT_arch_specific);
|
||||
opts::BBAddrMap = Args.hasArg(OPT_bb_addr_map);
|
||||
opts::CGProfile = Args.hasArg(OPT_cg_profile);
|
||||
opts::Decompress = Args.hasArg(OPT_decompress);
|
||||
opts::Demangle = Args.hasFlag(OPT_demangle, OPT_no_demangle, false);
|
||||
opts::DependentLibraries = Args.hasArg(OPT_dependent_libraries);
|
||||
opts::DynRelocs = Args.hasArg(OPT_dyn_relocations);
|
||||
@@ -439,9 +441,9 @@ static void dumpObject(ObjectFile &Obj, ScopedPrinter &Writer,
|
||||
Dumper->printSymbols(opts::Symbols, opts::DynamicSymbols,
|
||||
opts::ExtraSymInfo, SymComp);
|
||||
if (!opts::StringDump.empty())
|
||||
Dumper->printSectionsAsString(Obj, opts::StringDump);
|
||||
Dumper->printSectionsAsString(Obj, opts::StringDump, opts::Decompress);
|
||||
if (!opts::HexDump.empty())
|
||||
Dumper->printSectionsAsHex(Obj, opts::HexDump);
|
||||
Dumper->printSectionsAsHex(Obj, opts::HexDump, opts::Decompress);
|
||||
if (opts::HashTable)
|
||||
Dumper->printHashTable();
|
||||
if (opts::GnuHashTable)
|
||||
|
||||
@@ -87,7 +87,11 @@ void Attributes::emitFnAttrCompatCheck(raw_ostream &OS, bool IsStringAttr) {
|
||||
|
||||
for (auto *Rule : CompatRules) {
|
||||
StringRef FuncName = Rule->getValueAsString("CompatFunc");
|
||||
OS << " Ret &= " << FuncName << "(Caller, Callee);\n";
|
||||
OS << " Ret &= " << FuncName << "(Caller, Callee";
|
||||
StringRef AttrName = Rule->getValueAsString("AttrName");
|
||||
if (!AttrName.empty())
|
||||
OS << ", \"" << AttrName << "\"";
|
||||
OS << ");\n";
|
||||
}
|
||||
|
||||
OS << "\n";
|
||||
|
||||
Reference in New Issue
Block a user