Your program is wrong. It's technically doing this
uint64_t p = *((uint64_t*)0x8000000000123456ULL);
p += 0x8000000000000000ULL;
which actually toggles the top bits and won't give you the correct value if the value has the top bit set. In fact it'll trap if the top bit is set since this is dadd and not daddu
You should read more about bitwise operations: To clear a bit, use and; use or to set and xor to toggle a bit
In MIPS you can do like this
ldi $2, 0x8000000000123456
ld $3, 0($2)
lui $4, 0x8000 # $4 = 0x80000000
dsll $4, $4, 32 # $4 = 0x8000000000000000
or $4, $3, $4
sd $3, 0($2)
The lui/dsll pair is for loading the immediate. It can be replaced with any equivalent sequences that load a power of 2 to the low half then shift it to the high part
Note that there's nothing called "register address" unless you're using MMIO. It's the register that contains the address to a memory location. If you're accessing real memory or a MMIO device that allows partial register access then you have an alternative solution by simply loading the specific byte, halfword or word and edit it, which saves you several instructions to load the 64-bit immediate
# byte
ldi $2, 0x8000000000123456 # assume big endian
lbu $3, 0($2)
ori $3, 0x80
sb $3, 0($2)
# halfword
ldi $2, 0x8000000000123456
lhu $3, 0($2)
ori $3, 0x8000
sh $3, 0($2)
# word
ldi $2, 0x8000000000123456
lbu $3, 0($2)
lui $4, 0x8000
or $3, $4, $3
sd $3, 0($2)