Go has a very unfortunate lack of built-in assertions. I want to implement them this way:
const ASSERT = true
func SomeFunction() {
if ASSERT && !some_condition_that_should_always_be_true() {
panic("Error message or object.")
}
}
My question is will the if-statement be optimized out if I define const ASSERT = false?
As noted by the people in the comments to your question, it's implementation-specific.
gc does remove it. You can build your program with -gcflags '-S' and see that the ASSERT part is not in the binary.
E.g. compile the following code with -gcflags '-S', and you'll see that the code on lines 8 and 9 is included, but change Assert to be false, and they won't be there in the asm listing.
package main
const Assert = true
var cond = true
func main() {
if Assert && !cond {
panic("failed")
}
}
EDIT:
As for gccgo, it removes this code at -O1 and above. You can see it by compiling the same code with
go build -compiler gccgo -gccgoflags '-O1' main.go
and then doing
objdump -S main
to see the annotated assembly.
Related
I am trying to write a verilator test that is a bit complicated. I am building a cpu in verilog and I would like to make sure that control signals are correct at certain stages. As such I am trying to write some code that works as follows:
checkAssertion(phase=2, instruction=3766636548)
I was hoping to implement this as
std::map<int, std::function<bool()>[5]>
This way for every instruction I aim to test I could look up the instruction and check that the state is valid for a specific instruction at a specific phase.
I also tried making something that looked like this as well
std::vector<std::function<bool()>> functors;
functors.push_back([&] { return read_cpu_var("phase") == 0; });
functors.push_back([&] { return (read_cpu_var("phase") == 1) && (read_cpu_var("register_read_1") == 2); });
functors.push_back([&] { return read_cpu_var("phase") == 2; });
functors.push_back([&] { return read_cpu_var("phase") == 3; });
functors.push_back([&] { return read_cpu_var("phase") == 4; });
However it seems that this will not work as I cant get verilator to compile the c++ as c++11. Though if you are curious this is the build and run command
verilator -Wall --trace -cc --vpi cpu.v --exe -std=c++11 ../TestBenches/cpu_verify.cpp && make -j -C obj_dir -f Vcpu.mk Vcpu && obj_dir/Vcpu
So without c++11 I am without lambdas and without std::function. I figured those would be an eloquent way to lay out each of the assertions for each of the phases. How would I do this eloquently before c++11
I have a piece of code with this structure:
__forceinline void problemFunction(bool condition, int & value)
{
if (condition)
{
value = 0;
return;
}
// ...
// a lot of calculations
// ...
}
void caller()
{
bool condition;
int value;
// ...
problemFunction(condition, value);
someOtherStuff();
}
But after building Release configuration with optimization turned on in Disassembly I get something like this:
void caller()
{
bool condition;
int value;
// ...
if (condition)
value = 0;
else
goto CalculateLabel;
ReturnProblemFunctionLabel:
someOtherStuff();
goto ReturnLabel;
CalculateLabel:
// ...
// a lot of calculations
// ...
goto ReturnProblemFunctionLabel;
ReturnLabel:
}
ProblemFunction was splitted into two parts. And the proble is that the second part is located after the someOtherStuff function call.
How can I locally suppress this kind of optimization?
I am using Visual Studio 2019 Version 16.4.2 on Windows 10.
In C++20 you can mark branches with the likely/unlikely attribute (see this question and cppreference), which can give the compiler a hint on how to better optimize the code. In your original post I'm assuming that the condition passed to problemFunction is usually false, which would mean an unnecessary jump in most cases.
As you can see on godbolt, if you mark your if statement with [[unlikely]] g++ will output your desired result, but msvc will not change the generated code. Note that this example is just a basic demo. Compiling your actual program may give different results.
Also note that jumps do not necessarily mean worse performance, because of branch prediction. You have to measure your execution time to make any meaningful conclusions.
I want to implement rbreak from Python scripting.
The simplest way to do that would be to loop over all functions, and compare their name to a regular expression in Python.
Or if there is a better way without explicit looping, I'm interested as well.
I expect the solution to use some API like: https://sourceware.org/gdb/onlinedocs/gdb/Symbol-Tables-In-Python.html but it's hard to do it without examples.
The documentation can definitely be improved. This provides a clue:
The outermost block is known as the global block.
The global block typically holds public global variables and functions.
A gdb.Block is iterable.
So all we need to do is get hold of the global block, and iterate over it.
Using the following test:
int a_global;
int foo() { return a_global; }
int bar() { return foo(); }
int main() { return bar(); }
$ gcc -g t.c && gdb -q ./a.out
(gdb) py
> for sym in gdb.lookup_global_symbol('main').symtab.global_block():
> print(sym.name, sym.is_function)
^D
('foo', True)
('bar', True)
('main', True)
('a_global', False)
Voilà.
lately I have been faced with a strange problem that a simple source did not want to compile. I was looking for solutions (and cause) in many sites but without good effects (except bugs reports but I have not found there direct cause ).
Below I present simple code to reproduce that situation:
struct Foo {
Foo() : m_x( true ) {}
__property bool x = { read=m_x };
private:
bool m_x;
};
template<typename T>
struct TMyPointer {
T * m_ptr;
TMyPointer( T * ptr ) : m_ptr( ptr ) {}
~TMyPointer()
{
delete m_ptr;
}
T * operator->() const
{
return Get();
}
T * Get() const
{
if( m_ptr == NULL )
; // some error handling
return m_ptr;
}
};
int _tmain(int argc, _TCHAR* argv[])
{
TMyPointer<Foo> bar( new Foo );
if( bar->x && 1 == 1 ) ; // Failed
if( 1 == 1 && bar->x ) ; // OK
if( !!bar->x && 1 == 1 ) ; // OK
if( bar->x == true && 1 == 1 ) ; // OK
if( (bar->x) && 1 == 1 ) ; // OK
return 0;
}
Compiler has failed to compile first condition inside main function. What stranger compilation of other equivalent conditions is finished successfully.
That's behavior I have only during release compilation. To reproduce I have used Embarcadero® C++Builder® XE5 Version 19.0.13476.4176
Error message: [bcc32 Fatal Error] File1.cpp(43): F1004 Internal
compiler error at 0x14470090 with base 0x14410000
Anybody knows what is the problematic in above example? Maybe usage templates with properties mechanism is the cause?
In my case is simple solution it seems to be problematic condition inside Get method. When I change
if( m_ptr == NULL )
to equivalent form
if( !m_ptr )
everything compile without errors.
I am writing about it here becouse I would like to share my insights - it can be helpfully for somebody.
recently I got similar ICE (once my source code grows in size) and your solution seemingly helped for a while but not really as after some minor changes in code ICE resurfaced again. Based on the behavior of mine problem:
IDE: BDS2006 Turbo C++ explorer (its version of BCB between BCB6 and RAD)
Huge win32 project (several MBytes of code involving USB,OpenGL,CAD/CAM)
Each part of code is tested for years and compilable separably problem occurs once they together and code grows too big
Project compiles fine at first run but after that any recompile fails
The temporary workaround was to close IDE, delete all obj,tds,exe,... files restart IDE and compile again.
I assumed compiler and or IDE leaks or overwrites some parts of itself corrupting its functionality. As the problem persist after IDE restart without deleting temp files I assumed it has something to do with debug info stored in them.
So I played with Project->Options->Debugging settings and turning off this:
Inline function expansion (-vi)
Helped (not even IDE restart or temp file removal was needed).
Don't have enough reputation to upvote or comment someone else's posts, but I have recently found the same solution as in #Spektre reply.
Disabling Inline function expansion fixed our multiple-year problems with completely unrelated internal compiler errors on random projects. We only experienced them on MSBUILD scripts in Release config.
I found this out by going over all the compiler options in Release config that were different from Debug config and changed them one-by-one to match Debug config through msbuild parameters for the entire solution/projectgroup. And eventually it started to build without any errors when I've disabled Inline function expansion option.
These problems happened and I confirmed the fix on C++ Builder XE5;
This kept on resurfacing at random for as long as I can remember (Borland C++ 2006 and later)
The older developers used to try and revert latest commits until it started compiling again... Which is a pain in the behind.
Anyone looking for solution to pass a parameter to an MSBUILD command (for all targets in the script) add this line to the msbuild.exe call:
msbuild.exe Targets.xml /p:BCC_InlineFunctionExpansion=false /t:Build
Today I discovered some of my assertion functions are still exist and being called in release build. Here's an example of my assertion function.
bool const isDebugMode()
{
return false; // Will be controlled by preprocessor flag.
}
void assertWithReason(bool const condition, std::string const reason = "")
{
if (isDebugMode() and not condition)
{
abort();
}
}
I think some side-effect in condition expression is preventing eliminating the assertion call.
For example,
assertWithReason(glGetError() == GL_NO_ERROR);
I expected this assertion call to be eliminated, but it is not. Because it is being executed before checking debug-build.
I am not sure how C++ handles this case, but as C++ is very strict language, it doesn't seem to be eliminated unless I put some special flag. Anyway, I intentionally wrote the assertions to be removed in release build.
Is it possible to write a function which is surely removed in release build in C++?
Of course I can use preprocessor macro, but I want to avoid using preprocessor macro as much as possible.
I am using Clang, and compiler specific extension (such as GCC attribute) is also fine.
I quite like using macros for this purpose. Yes, I know, Macros are evil, but just like knives (used wrong) are evil, they come in handy if you use them right.
#define MY_ASSERT(x) do {\
if (is_debug() && !x) assertFailed(__FILE__, __LINE__, __FUNCTION__, #x);\
} while(0);
Now you can also show where it failed (my_drawfunc.cpp: 34 : my_do_draw(): assertion failed: glGetError == GL_NO_ERROR or something like that.
In C++11 you can use lambda expressions. It is likely that constant propogation will make it so that is_debug is never evaulated, and even if it is, the lambda is not called.
class Debug { enum { is_debug = 1; } };
template <class F>
void assert(F f) {
if (is_debug && !f()) abort();
}
{
int x = 6;
assert([&]() { return x == 6; });
}