https://gcc.gnu.org/bugzilla/show_bug.cgi?id=111026
--- Comment #1 from zhaiqiming at baidu dot com ---
======
[summary]
When I upgraded from gcc82 to gcc12, I found that linked_list_t::del execution
did not meet expectations.
Looking at .s , i noticed that the assembly statements corresponding to the
following two lines have disappeared.
(node.*list_node).next->prev = (node.*list_node).prev;
(node.*list_node).prev->next = (node.*list_node).next;
======
[environment-gcc12]
Reading specs from
/home/opt/compiler/gcc-12/bin/../lib/gcc/x86_64-pc-linux-gnu/12.1.0/specs
COLLECT_GCC=/home/opt/compiler/gcc-12/bin/gcc
COLLECT_LTO_WRAPPER=/home/opt/compiler/gcc-12/bin/../libexec/gcc/x86_64-pc-linux-gnu/12.1.0/lto-wrapper
Target: x86_64-pc-linux-gnu
Configured with: ../configure --prefix=/opt/compiler/gcc-12
--with-local-prefix=/opt/compiler/gcc-12
--with-native-system-header-dir=/opt/compiler/gcc-12/include
--enable-languages=c,c++ --disable-libstdcxx-pch --disable-multilib
--with-default-libstdcxx-abi=gcc4-compatible --disable-bootstrap
--with-sysroot=/ --build=x86_64-pc-linux-gnu --target=x86_64-pc-linux-gnu
--enable-gold --enable-lto
Thread model: posix
Supported LTO compression algorithms: zlib
gcc version 12.1.0 (GCC)
[environment-gcc82]
Using built-in specs.
COLLECT_GCC=/home/opt/compiler/gcc-8.2/gcc-8.2/bin/gcc
COLLECT_LTO_WRAPPER=/home/opt/compiler/gcc-8.2/gcc-8.2/bin/../libexec/gcc/x86_64-pc-linux-gnu/8.2.0/lto-wrapper
Target: x86_64-pc-linux-gnu
Configured with: ../configure --prefix=/opt/compiler/gcc-8.2
--with-local-prefix=/opt/compiler/gcc-8.2
--with-native-system-header-dir=/opt/compiler/gcc-8.2/include
--enable-languages=c,c++ --disable-libstdcxx-pch --disable-multilib
--disable-bootstrap --with-default-libstdcxx-abi=gcc4-compatible
Thread model: posix
gcc version 8.2.0 (GCC)
======
[source code]
struct list_node_t
{
list_node_t *next;
list_node_t *prev;
};
template <typename T, list_node_t T::*inner_list_node>
class list_t
{
public:
list_t() { _head.next = _head.prev = &_head; }
bool is_empty() const { return _head.next == &_head; }
T* entry(list_node_t &node) const { return &node == &_head ?
NULL : (T*)((char*)&node - (char*)_node_offset); }
void add(T &node)
{
_head.next->prev = &(node.*inner_list_node);
(node.*inner_list_node).next = _head.next;
(node.*inner_list_node).prev = &_head;
_head.next = &(node.*inner_list_node);
}
static void del(T &node)
{
int slot_1 = 10000;
printf("slot_1 %d\n", slot_1);
(node.*inner_list_node).next->prev =
(node.*inner_list_node).prev;
(node.*inner_list_node).prev->next =
(node.*inner_list_node).next;
int slot_2 = 20000;
printf("slot_2 %d\n", slot_2);
}
protected:
static list_node_t const * const _node_offset;
list_node_t _head;
};
template <typename T, list_node_t T::*inner_list_node>
list_node_t const * const list_t<T, inner_list_node>::_node_offset = &(((T
*)0)->*inner_list_node);
template <typename T, list_node_t T::*inner_list_node>
class safe_list_t: public list_t<T, inner_list_node>
{
public:
safe_list_t(): _alive(1),_num(0)
{
pthread_mutex_init(&_mutex, NULL);
pthread_cond_init(&_cond, NULL);
}
~safe_list_t()
{
pthread_cond_destroy(&_cond);
pthread_mutex_destroy(&_mutex);
}
int len()
{
return _num;
}
void put(T &node)
{
pthread_mutex_lock(&_mutex);
if (_alive)
{
this->add(node);
++_num;
}
pthread_mutex_unlock(&_mutex);
pthread_cond_signal(&_cond);
}
T* get()
{
T *ret;
pthread_mutex_lock(&_mutex);
while (_alive && list_t<T,
inner_list_node>::is_empty())
pthread_cond_wait(&_cond, &_mutex);
if (_alive)
{
ret = this->entry(*list_t<T, inner_list_node>::_head.prev);
this->del(*ret);
--_num;
}
else
{
ret = NULL;
}
pthread_mutex_unlock(&_mutex);
return ret;
}
protected:
pthread_mutex_t _mutex;
pthread_cond_t _cond;
int _alive;
int _num;
};
template <class T>
class worker_t
{
public:
T *t;
list_node_t inner_task_list_node;
public:
worker_t():t(NULL)
{
t = new T;
}
worker_t(T *tt):t(tt)
{
}
~worker_t()
{
delete t;
}
private:
worker_t(const worker_t& rhs);
worker_t& operator=(const worker_t& rhs);
};
int main() {
safe_list_t<worker_t<size_t>, &worker_t<size_t>::inner_task_list_node>
_serialize_merge_scan_move_list;
auto * worker_0 = new worker_t<size_t>;
*worker_0->t = 100;
_serialize_merge_scan_move_list.put(*worker_0);
auto * worker_1 = new worker_t<size_t>;
*worker_1->t = 200;
_serialize_merge_scan_move_list.put(*worker_1);
auto* temp_0 = _serialize_merge_scan_move_list.get();
printf("temp_0->t = %zu\n", *temp_0->t);
delete temp_0;
auto* temp_1 = _serialize_merge_scan_move_list.get();
printf("temp_1->t = %zu\n", *temp_1->t);
delete temp_1;
}
=====
[.s]
[important parts - gcc82]
Shell command: /home/opt/compiler/gcc-8.2/gcc-8.2/bin/gcc -S -ohello82-use.s
-save-temps -std=c++11 -O2 -pipe -Wall -Wextra -W -fPIC
-Werror=return-local-addr -Werror=return-type test_main.cpp -lstdc++ -lpthread
-lssl -lcrypto -lrt -lz -ldl
.L8:
.cfi_restore_state
movq 8(%rbx), %r12
cmpq %rbx, %r12
je .L15
movq
_ZN6list_tI8worker_tImEXadL_ZNS1_20inner_task_list_nodeEEEE12_node_offsetE@GOTPCREL(%rip),
%rax
movl $10000, %esi
leaq .LC0(%rip), %rdi
subq (%rax), %r12
xorl %eax, %eax
call printf@PLT
movq 8(%r12), %rdx
movq 16(%r12), %rax
movl $20000, %esi
leaq .LC1(%rip), %rdi
movq %rax, 8(%rdx)
movq %rdx, (%rax)
xorl %eax, %eax
call printf@PLT
subl $1, 108(%rbx)
movq %rbp, %rdi
call pthread_mutex_unlock@PLT
movq %r12, %rax
popq %rbx
.cfi_remember_state
.cfi_def_cfa_offset 24
popq %rbp
.cfi_def_cfa_offset 16
popq %r12
.cfi_def_cfa_offset 8
ret
[important parts - gcc12]
Shell command: /home/opt/compiler/gcc-12/bin/gcc -S -ohello12-use.s
-save-temps -std=c++11 -O2 -pipe -Wall -Wextra -W -fPIC
-Werror=return-local-addr -Werror=return-type test_main.cpp -lstdc++ -lpthread
-lssl -lcrypto -lrt -lz -ldl
.L11:
movl $10000, %esi
leaq .LC0(%rip), %rdi
xorl %eax, %eax
call printf@PLT
movl $20000, %esi
leaq .LC1(%rip), %rdi
xorl %eax, %eax
call printf@PLT
subl $1, 108(%rbx)
movq %rbp, %rdi
call pthread_mutex_unlock@PLT
movq %r12, %rax
popq %rbx
.cfi_remember_state
.cfi_def_cfa_offset 24
popq %rbp
.cfi_def_cfa_offset 16
popq %r12
.cfi_def_cfa_offset 8
ret
.p2align 4,,10
.p2align 3