forked from github/verilator
387 lines
12 KiB
C++
387 lines
12 KiB
C++
// -*- mode: C++; c-file-style: "cc-mode" -*-
|
|
//
|
|
//*************************************************************************
|
|
//
|
|
// Code available from: https://verilator.org
|
|
//
|
|
// Copyright 2022-2023 by Wilson Snyder. This program is free software; you can
|
|
// redistribute it and/or modify it under the terms of either the GNU
|
|
// Lesser General Public License Version 3 or the Perl Artistic License
|
|
// Version 2.0.
|
|
// SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
|
//
|
|
//*************************************************************************
|
|
|
|
#ifndef T_DIST_ATTRIBUTES_BAD_H_
|
|
#define T_DIST_ATTRIBUTES_BAD_H_
|
|
|
|
#include "verilatedos.h"
|
|
|
|
#include "verilated.h"
|
|
|
|
#include <mutex>
|
|
|
|
#define NO_ANNOTATION
|
|
|
|
#define CALL_0(prefix, annotation, aarg_type, aarg, val) prefix##_##annotation(val)
|
|
|
|
#define CALL_1(prefix, annotation, aarg_type, aarg, val) prefix##_##annotation(val)
|
|
|
|
#define SIG_ANNOTATED_0(prefix, annotation, aarg_type, aarg, val) \
|
|
void prefix##_##annotation(aarg_type aarg) annotation
|
|
|
|
#define SIG_ANNOTATED_1(prefix, annotation, aarg_type, aarg, val) \
|
|
void prefix##_##annotation(aarg_type aarg) annotation(aarg)
|
|
|
|
#define SIG_UNANNOTATED_0(prefix, annotation, aarg_type, aarg, val) \
|
|
void prefix##_##annotation(aarg_type aarg)
|
|
|
|
#define SIG_UNANNOTATED_1(prefix, annotation, aarg_type, aarg, val) \
|
|
void prefix##_##annotation(aarg_type aarg)
|
|
|
|
// clang-format off
|
|
#define EMIT_ALL(before, sig_prefix, val, after) \
|
|
before##_0(sig_prefix, NO_ANNOTATION, VerilatedMutex&, mtx, val) after \
|
|
before##_0(sig_prefix, VL_PURE, VerilatedMutex&, mtx, val) after \
|
|
before##_0(sig_prefix, VL_MT_SAFE, VerilatedMutex&, mtx, val) after \
|
|
before##_0(sig_prefix, VL_MT_SAFE_POSTINIT, VerilatedMutex&, mtx, val) after \
|
|
before##_0(sig_prefix, VL_MT_UNSAFE, VerilatedMutex&, mtx, val) after \
|
|
before##_0(sig_prefix, VL_MT_UNSAFE_ONE, VerilatedMutex&, mtx, val) after \
|
|
before##_0(sig_prefix, VL_MT_START, VerilatedMutex&, mtx, val) after \
|
|
before##_1(sig_prefix, VL_ACQUIRE, VerilatedMutex&, mtx, val) after \
|
|
before##_1(sig_prefix, VL_REQUIRES, VerilatedMutex&, mtx, val) after \
|
|
before##_1(sig_prefix, VL_RELEASE, VerilatedMutex&, mtx, val) after \
|
|
before##_1(sig_prefix, VL_ACQUIRE_SHARED, VerilatedMutex&, mtx, val) after \
|
|
before##_1(sig_prefix, VL_RELEASE_SHARED, VerilatedMutex&, mtx, val) after \
|
|
before##_1(sig_prefix, VL_EXCLUDES, VerilatedMutex&, mtx, val) after \
|
|
before##_1(sig_prefix, VL_MT_SAFE_EXCLUDES, VerilatedMutex&, mtx, val) after
|
|
// clang-format on
|
|
|
|
// Non-Static Functions, Annotated declaration, Unannotated definition.
|
|
// (declarations)
|
|
EMIT_ALL(SIG_ANNOTATED, nsf_au, /**/, ;)
|
|
|
|
// Non-Static Functions, Unannotated declaration, Annotated definition.
|
|
// (declarations)
|
|
EMIT_ALL(SIG_UNANNOTATED, nsf_ua, /**/, ;)
|
|
|
|
// Non-Static Functions, Annotated declaration, Annotated definition.
|
|
// (declarations)
|
|
EMIT_ALL(SIG_ANNOTATED, nsf_aa, /**/, ;)
|
|
|
|
// Non-Static Functions, Annotated declaration, Annotated definition.
|
|
// Definitions have extra annotations.
|
|
// (declarations)
|
|
EMIT_ALL(SIG_ANNOTATED, nsf_ae, /**/, ;)
|
|
|
|
// Non-Static Functions, Annotated declaration, Annotated definition.
|
|
// Declarations have extra annotations.
|
|
// (declarations)
|
|
EMIT_ALL(SIG_ANNOTATED, nsf_ea, /**/, VL_PURE VL_MT_SAFE;)
|
|
|
|
// Non-Static Functions (call test in header).
|
|
EMIT_ALL(inline SIG_ANNOTATED, nsf_test_caller_func_hdr, /**/, {
|
|
VerilatedMutex m;
|
|
|
|
EMIT_ALL(CALL, nsf_au, m, ;)
|
|
EMIT_ALL(CALL, nsf_ua, m, ;)
|
|
EMIT_ALL(CALL, nsf_aa, m, ;)
|
|
EMIT_ALL(CALL, nsf_ae, m, ;)
|
|
EMIT_ALL(CALL, nsf_ea, m, ;)
|
|
})
|
|
|
|
// Inline Functions in Header.
|
|
EMIT_ALL(inline SIG_ANNOTATED, ifh, /**/, {})
|
|
|
|
// Inline Functions in Header (call test in header).
|
|
EMIT_ALL(inline SIG_ANNOTATED, ifh_test_caller_func_hdr, /**/, {
|
|
VerilatedMutex m;
|
|
|
|
EMIT_ALL(CALL, ifh, m, ;)
|
|
})
|
|
|
|
struct GuardMe {
|
|
void safe_if_guarded_or_local() {}
|
|
|
|
operator int() const { return 4; }
|
|
|
|
GuardMe& operator+=(int) { return *this; }
|
|
};
|
|
|
|
class TestClass {
|
|
VerilatedMutex m_mtx;
|
|
GuardMe m_guardme VL_GUARDED_BY(m_mtx);
|
|
|
|
GuardMe m_guardme_unguarded;
|
|
|
|
public:
|
|
// Static Class Methods, Annotated declaration, Unannotated definition.
|
|
// (declarations)
|
|
EMIT_ALL(static SIG_ANNOTATED, scm_au, /**/, ;)
|
|
|
|
// Static Class Methods, Unannotated declaration, Annotated definition.
|
|
// (declarations)
|
|
EMIT_ALL(static SIG_UNANNOTATED, scm_ua, /**/, ;)
|
|
|
|
// Static Class Methods, Annotated declaration, Annotated definition.
|
|
// (declarations)
|
|
EMIT_ALL(static SIG_ANNOTATED, scm_aa, /**/, ;)
|
|
|
|
// Static Class Methods, Annotated declaration, Annotated definition.
|
|
// Definitions have extra annotations.
|
|
// (declarations)
|
|
EMIT_ALL(static SIG_ANNOTATED, scm_ae, /**/, ;)
|
|
|
|
// Static Class Methods, Annotated declaration, Annotated definition.
|
|
// Declarations have extra annotations.
|
|
// (declarations)
|
|
EMIT_ALL(static SIG_ANNOTATED, scm_ea, /**/, VL_PURE VL_MT_SAFE;)
|
|
|
|
// Static Class Methods (call test in header).
|
|
EMIT_ALL(static SIG_ANNOTATED, scm_test_caller_smethod_hdr, /**/, {
|
|
VerilatedMutex m;
|
|
|
|
EMIT_ALL(CALL, TestClass::scm_au, m, ;)
|
|
EMIT_ALL(CALL, TestClass::scm_ua, m, ;)
|
|
EMIT_ALL(CALL, TestClass::scm_aa, m, ;)
|
|
EMIT_ALL(CALL, TestClass::scm_ae, m, ;)
|
|
EMIT_ALL(CALL, TestClass::scm_ea, m, ;)
|
|
|
|
TestClass tc;
|
|
EMIT_ALL(CALL, tc.scm_au, m, ;)
|
|
EMIT_ALL(CALL, tc.scm_ua, m, ;)
|
|
EMIT_ALL(CALL, tc.scm_aa, m, ;)
|
|
EMIT_ALL(CALL, tc.scm_ae, m, ;)
|
|
EMIT_ALL(CALL, tc.scm_ea, m, ;)
|
|
|
|
TestClass* tcp = &tc;
|
|
EMIT_ALL(CALL, tcp->scm_au, m, ;)
|
|
EMIT_ALL(CALL, tcp->scm_ua, m, ;)
|
|
EMIT_ALL(CALL, tcp->scm_aa, m, ;)
|
|
EMIT_ALL(CALL, tcp->scm_ae, m, ;)
|
|
EMIT_ALL(CALL, tcp->scm_ea, m, ;)
|
|
})
|
|
|
|
// Static Class Methods (call test).
|
|
// (declaration)
|
|
EMIT_ALL(static SIG_ANNOTATED, scm_test_caller_smethod, /**/, ;)
|
|
|
|
// Inline Static Class Methods.
|
|
EMIT_ALL(static SIG_ANNOTATED, iscm, /**/, {})
|
|
|
|
// Inline Static Class Methods (call test in header).
|
|
EMIT_ALL(static SIG_ANNOTATED, iscm_test_caller_smethod_hdr, /**/, {
|
|
VerilatedMutex m;
|
|
|
|
EMIT_ALL(CALL, TestClass::iscm, m, ;)
|
|
|
|
TestClass tc;
|
|
EMIT_ALL(CALL, tc.iscm, m, ;)
|
|
|
|
TestClass* tcp = &tc;
|
|
EMIT_ALL(CALL, tcp->iscm, m, ;)
|
|
})
|
|
|
|
// Inline Static Class Methods (call test).
|
|
// (declaration)
|
|
EMIT_ALL(static SIG_ANNOTATED, iscm_test_caller_smethod, /**/, ;)
|
|
|
|
// Class Methods, Annotated declaration, Unannotated definition.
|
|
// (declarations)
|
|
EMIT_ALL(SIG_ANNOTATED, cm_au, /**/, ;)
|
|
|
|
// Class Methods, Unannotated declaration, Annotated definition.
|
|
// (declarations)
|
|
EMIT_ALL(SIG_UNANNOTATED, cm_ua, /**/, ;)
|
|
|
|
// Class Methods, Annotated declaration, Annotated definition.
|
|
// (declarations)
|
|
EMIT_ALL(SIG_ANNOTATED, cm_aa, /**/, ;)
|
|
|
|
// Class Methods, Annotated declaration, Annotated definition.
|
|
// Definitions have extra annotations.
|
|
// (declarations)
|
|
EMIT_ALL(SIG_ANNOTATED, cm_ae, /**/, ;)
|
|
|
|
// Class Methods, Annotated declaration, Annotated definition.
|
|
// Declarations have extra annotations.
|
|
// (declarations)
|
|
EMIT_ALL(SIG_ANNOTATED, cm_ea, /**/, VL_PURE VL_MT_SAFE;)
|
|
|
|
// Class Methods (call test in header).
|
|
EMIT_ALL(SIG_ANNOTATED, cm_test_caller_smethod_hdr, /**/, {
|
|
VerilatedMutex m;
|
|
|
|
TestClass tc;
|
|
EMIT_ALL(CALL, tc.cm_au, m, ;)
|
|
EMIT_ALL(CALL, tc.cm_ua, m, ;)
|
|
EMIT_ALL(CALL, tc.cm_aa, m, ;)
|
|
EMIT_ALL(CALL, tc.cm_ae, m, ;)
|
|
EMIT_ALL(CALL, tc.cm_ea, m, ;)
|
|
|
|
TestClass* tcp = &tc;
|
|
EMIT_ALL(CALL, tcp->cm_au, m, ;)
|
|
EMIT_ALL(CALL, tcp->cm_ua, m, ;)
|
|
EMIT_ALL(CALL, tcp->cm_aa, m, ;)
|
|
EMIT_ALL(CALL, tcp->cm_ae, m, ;)
|
|
EMIT_ALL(CALL, tcp->cm_ea, m, ;)
|
|
})
|
|
|
|
// Class Methods (call test).
|
|
// (declaration)
|
|
EMIT_ALL(SIG_ANNOTATED, cm_test_caller_smethod, /**/, ;)
|
|
|
|
// Inline Class Methods.
|
|
EMIT_ALL(SIG_ANNOTATED, icm, /**/, {})
|
|
|
|
// Inline Class Methods (call test in header).
|
|
EMIT_ALL(SIG_ANNOTATED, icm_test_caller_smethod_hdr, /**/, {
|
|
VerilatedMutex m;
|
|
|
|
TestClass tc;
|
|
EMIT_ALL(CALL, tc.icm, m, ;)
|
|
|
|
TestClass* tcp = &tc;
|
|
EMIT_ALL(CALL, tcp->icm, m, ;)
|
|
})
|
|
|
|
// Inline Class Methods (call test).
|
|
// (declaration)
|
|
EMIT_ALL(SIG_ANNOTATED, icm_test_caller_smethod, /**/, ;)
|
|
|
|
void guarded_by_test_pass(GuardMe& guardme_arg) VL_MT_SAFE {
|
|
guardme_arg.safe_if_guarded_or_local();
|
|
int a = guardme_arg;
|
|
guardme_arg += 4;
|
|
|
|
m_mtx.lock();
|
|
m_guardme.safe_if_guarded_or_local();
|
|
int b = m_guardme;
|
|
m_guardme += 4;
|
|
m_mtx.unlock();
|
|
|
|
GuardMe guardme_local;
|
|
guardme_local.safe_if_guarded_or_local();
|
|
int c = guardme_local;
|
|
guardme_local += 4;
|
|
}
|
|
|
|
void guarded_by_test_fail() VL_MT_SAFE {
|
|
m_guardme_unguarded.safe_if_guarded_or_local();
|
|
int a = m_guardme_unguarded;
|
|
m_guardme_unguarded += 4;
|
|
}
|
|
};
|
|
|
|
static void static_function() {}
|
|
|
|
class StaticClass {
|
|
public:
|
|
static void static_class_function() {}
|
|
};
|
|
|
|
class ConstructorCallsUnsafeLocalFunction {
|
|
public:
|
|
void unsafe_function() VL_MT_UNSAFE{};
|
|
ConstructorCallsUnsafeLocalFunction() { unsafe_function(); }
|
|
};
|
|
class ConstructorCallsStaticFunctionNoAnnotation {
|
|
public:
|
|
ConstructorCallsStaticFunctionNoAnnotation() { static_function(); }
|
|
};
|
|
|
|
class ConstructorCallsLocalFunction {
|
|
public:
|
|
void local_function() {}
|
|
ConstructorCallsLocalFunction() { local_function(); }
|
|
};
|
|
|
|
class ConstructorCallsLocalFunctionCallsGlobal {
|
|
public:
|
|
void local_function() { static_function(); }
|
|
ConstructorCallsLocalFunctionCallsGlobal() { local_function(); }
|
|
};
|
|
|
|
class SafeFunction {
|
|
public:
|
|
void safe_function() VL_MT_SAFE {}
|
|
};
|
|
class UnsafeFunction {
|
|
public:
|
|
void unsafe_function() VL_MT_UNSAFE {}
|
|
};
|
|
|
|
class ConstructorWithPointer {
|
|
public:
|
|
ConstructorWithPointer(SafeFunction* p) { p->safe_function(); }
|
|
};
|
|
|
|
class ConstructorWithReference {
|
|
public:
|
|
ConstructorWithReference(SafeFunction& p) { p.safe_function(); }
|
|
};
|
|
class ConstructorWithUnsafePointer {
|
|
public:
|
|
ConstructorWithUnsafePointer(UnsafeFunction* p) { p->unsafe_function(); }
|
|
};
|
|
|
|
class ConstructorWithUnsafeReference {
|
|
public:
|
|
ConstructorWithUnsafeReference(UnsafeFunction& p) { p.unsafe_function(); }
|
|
};
|
|
|
|
class ConstructorCallsLocalCallsGlobal {
|
|
void local_function2() { static_function(); }
|
|
void local_function() { local_function2(); }
|
|
|
|
public:
|
|
ConstructorCallsLocalCallsGlobal() { local_function(); }
|
|
};
|
|
|
|
class ConstructorCallsLocalCallsClassGlobal {
|
|
void local_function2() { StaticClass::static_class_function(); }
|
|
void local_function() { local_function2(); }
|
|
|
|
public:
|
|
ConstructorCallsLocalCallsClassGlobal() { local_function(); }
|
|
};
|
|
|
|
class TestClassConstructor {
|
|
void safe_function_unsafe_constructor_bad() VL_MT_SAFE {
|
|
ConstructorCallsUnsafeLocalFunction f{};
|
|
};
|
|
void safe_function_static_constructor_bad() VL_MT_SAFE {
|
|
ConstructorCallsStaticFunctionNoAnnotation f{};
|
|
};
|
|
void safe_function_local_function_global_bad() VL_MT_SAFE {
|
|
ConstructorCallsLocalFunctionCallsGlobal f{};
|
|
}
|
|
void safe_function_local_function_constructor_good() VL_MT_SAFE {
|
|
ConstructorCallsLocalFunction f{};
|
|
}
|
|
void safe_function_calls_constructor_with_pointer_good() VL_MT_SAFE {
|
|
SafeFunction* i = new SafeFunction{};
|
|
ConstructorWithPointer f{i};
|
|
}
|
|
void safe_function_calls_constructor_with_reference_good() VL_MT_SAFE {
|
|
SafeFunction i;
|
|
ConstructorWithReference f{i};
|
|
}
|
|
void safe_function_calls_constructor_with_unsafepointer_bad() VL_MT_SAFE {
|
|
UnsafeFunction* i = new UnsafeFunction{};
|
|
ConstructorWithUnsafePointer f{i};
|
|
}
|
|
void safe_function_calls_constructor_with_unsafereference_bad() VL_MT_SAFE {
|
|
UnsafeFunction i;
|
|
ConstructorWithUnsafeReference f{i};
|
|
}
|
|
void safe_function_calls_constructor_local_calls_global_bad() VL_MT_SAFE {
|
|
ConstructorCallsLocalCallsGlobal f{};
|
|
}
|
|
void safe_function_calls_constructor_local_calls_class_global_bad() VL_MT_SAFE {
|
|
ConstructorCallsLocalCallsClassGlobal f{};
|
|
}
|
|
};
|
|
|
|
#endif // T_DIST_ATTRIBUTES_BAD_H_
|