mirror of
git://repo.or.cz/tinycc.git
synced 2026-07-03 18:08:40 +08:00
Compare commits
14 Commits
7e4fc3a0d0
...
cb41cbfe71
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cb41cbfe71 | ||
|
|
831c3fa184 | ||
|
|
0fcd46f364 | ||
|
|
b4569233cb | ||
|
|
f5f544f436 | ||
|
|
7479a5c21a | ||
|
|
78e5e690a2 | ||
|
|
6da45946ae | ||
|
|
fc424c9f7b | ||
|
|
5b96aeb7fc | ||
|
|
06e24e7eed | ||
|
|
3c631fdb6d | ||
|
|
e7be7b192d | ||
|
|
3327327e5d |
26
.github/workflows/build.yml
vendored
26
.github/workflows/build.yml
vendored
@ -9,7 +9,7 @@ jobs:
|
||||
runs-on: ubuntu-22.04
|
||||
timeout-minutes: 2
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
|
||||
- name: make & test tcc (x86_64-linux)
|
||||
run: ./configure && make && make test -k
|
||||
|
||||
@ -17,7 +17,7 @@ jobs:
|
||||
runs-on: macos-13
|
||||
timeout-minutes: 2
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
|
||||
- name: make & test tcc (x86_64-osx)
|
||||
run: ./configure && make && make test -k
|
||||
|
||||
@ -25,7 +25,7 @@ jobs:
|
||||
runs-on: macos-14
|
||||
timeout-minutes: 2
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
|
||||
- name: make & test tcc (aarch64-osx)
|
||||
run: ./configure && make && make test -k
|
||||
|
||||
@ -33,7 +33,7 @@ jobs:
|
||||
runs-on: windows-2025
|
||||
timeout-minutes: 6
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
|
||||
- name: make & test tcc (x86_64-win32)
|
||||
shell: cmd
|
||||
run: |
|
||||
@ -44,7 +44,7 @@ jobs:
|
||||
C:\msys64\usr\bin\bash -l -c "pacman -S --noconfirm mingw-w64-x86_64-gcc"
|
||||
echo ::endgroup::
|
||||
C:\msys64\usr\bin\bash -l -c "./configure && make && make test -k"
|
||||
- uses: ilammy/msvc-dev-cmd@v1
|
||||
- uses: ilammy/msvc-dev-cmd@0b201ec74fa43914dc39ae48a89fd1d8cb592756 # v1.13.0
|
||||
with:
|
||||
arch: amd64
|
||||
- name: build with MSVC (x86_64-win32)
|
||||
@ -61,7 +61,7 @@ jobs:
|
||||
runs-on: windows-2025
|
||||
timeout-minutes: 6
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
|
||||
- name: make & test tcc (i386-win32)
|
||||
shell: cmd
|
||||
run: |
|
||||
@ -72,7 +72,7 @@ jobs:
|
||||
C:\msys64\usr\bin\bash -l -c "pacman -S --noconfirm mingw-w64-i686-gcc"
|
||||
echo ::endgroup::
|
||||
C:\msys64\usr\bin\bash -l -c "./configure && make && make test -k"
|
||||
- uses: ilammy/msvc-dev-cmd@v1
|
||||
- uses: ilammy/msvc-dev-cmd@0b201ec74fa43914dc39ae48a89fd1d8cb592756 # v1.13.0
|
||||
with:
|
||||
arch: x86
|
||||
- name: build with MSVC (i386-win32)
|
||||
@ -89,8 +89,8 @@ jobs:
|
||||
runs-on: ubuntu-22.04
|
||||
timeout-minutes: 8
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: uraimo/run-on-arch-action@v3
|
||||
- uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
|
||||
- uses: uraimo/run-on-arch-action@d94c13912ea685de38fccc1109385b83fd79427d # v3.0.1
|
||||
name: make & test tcc (armv7-linux)
|
||||
with:
|
||||
arch: armv7
|
||||
@ -107,8 +107,8 @@ jobs:
|
||||
runs-on: ubuntu-22.04
|
||||
timeout-minutes: 8
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: uraimo/run-on-arch-action@v3
|
||||
- uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
|
||||
- uses: uraimo/run-on-arch-action@d94c13912ea685de38fccc1109385b83fd79427d # v3.0.1
|
||||
name: make & test tcc (aarch64-linux)
|
||||
with:
|
||||
arch: aarch64
|
||||
@ -125,8 +125,8 @@ jobs:
|
||||
runs-on: ubuntu-22.04
|
||||
timeout-minutes: 8
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: uraimo/run-on-arch-action@v3
|
||||
- uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
|
||||
- uses: uraimo/run-on-arch-action@d94c13912ea685de38fccc1109385b83fd79427d # v3.0.1
|
||||
name: make & test tcc (riscv64-linux)
|
||||
with:
|
||||
arch: riscv64
|
||||
|
||||
@ -19,9 +19,7 @@ typedef union { long long __ll; long double __ld; } max_align_t;
|
||||
#undef offsetof
|
||||
#define offsetof(type, field) __builtin_offsetof(type, field)
|
||||
|
||||
#if defined __i386__ || defined __x86_64__
|
||||
void *alloca(size_t size);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@ -347,12 +347,8 @@
|
||||
__MAYBE_REDIR(void*, calloc, (__SIZE_TYPE__, __SIZE_TYPE__))
|
||||
__MAYBE_REDIR(void*, memalign, (__SIZE_TYPE__, __SIZE_TYPE__))
|
||||
__MAYBE_REDIR(void, free, (void*))
|
||||
#if defined __i386__ || defined __x86_64__
|
||||
__BOTH(void*, alloca, (__SIZE_TYPE__))
|
||||
void *alloca(__SIZE_TYPE__);
|
||||
#else
|
||||
__BUILTIN(void*, alloca, (__SIZE_TYPE__))
|
||||
#endif
|
||||
__BUILTIN(void, abort, (void))
|
||||
__BOUND(void, longjmp, ())
|
||||
#if !defined _WIN32
|
||||
|
||||
10
lib/Makefile
10
lib/Makefile
@ -35,12 +35,12 @@ endif
|
||||
|
||||
XFLAGS += -I$(TOP)
|
||||
|
||||
I386_O = libtcc1.o alloca.o alloca-bt.o $(COMMON_O)
|
||||
X86_64_O = libtcc1.o alloca.o alloca-bt.o $(COMMON_O)
|
||||
ARM_O = libtcc1.o armeabi.o alloca.o armflush.o $(COMMON_O)
|
||||
ARM64_O = lib-arm64.o alloca.o $(COMMON_O)
|
||||
I386_O = libtcc1.o $(COMMON_O)
|
||||
X86_64_O = libtcc1.o $(COMMON_O)
|
||||
ARM_O = libtcc1.o armeabi.o armflush.o $(COMMON_O)
|
||||
ARM64_O = lib-arm64.o $(COMMON_O)
|
||||
RISCV64_O = lib-arm64.o $(COMMON_O)
|
||||
COMMON_O = stdatomic.o atomic.o builtin.o
|
||||
COMMON_O = stdatomic.o atomic.o builtin.o alloca.o alloca-bt.o
|
||||
WIN_O = crt1.o crt1w.o wincrt1.o wincrt1w.o dllcrt1.o dllmain.o
|
||||
LIN_O = dsohandle.o
|
||||
OSX_O =
|
||||
|
||||
104
lib/alloca-bt.S
104
lib/alloca-bt.S
@ -92,5 +92,109 @@ p3:
|
||||
ret
|
||||
#endif
|
||||
|
||||
/* ---------------------------------------------- */
|
||||
#elif defined __arm__
|
||||
|
||||
.globl _(__bound_alloca)
|
||||
_(__bound_alloca):
|
||||
mov r1, r0
|
||||
add r0, r0, #1
|
||||
rsb sp, r0, sp
|
||||
bic sp, sp, #7
|
||||
mov r0, sp
|
||||
push { lr }
|
||||
bl _(__bound_new_region)
|
||||
pop { lr }
|
||||
mov r0, sp
|
||||
mov pc, lr
|
||||
|
||||
/* ---------------------------------------------- */
|
||||
#elif defined __aarch64__ || defined __arm64__
|
||||
|
||||
.globl _(__bound_alloca)
|
||||
_(__bound_alloca):
|
||||
#ifdef __TINYC__
|
||||
.int 0xaa0003e1
|
||||
.int 0x91004000
|
||||
.int 0x927cec00
|
||||
#ifdef _WIN32
|
||||
.int 0xb4000160
|
||||
.int 0xd2820002
|
||||
.int 0xeb02001f
|
||||
.int 0x540000c3
|
||||
.int 0xcb2263e3
|
||||
.int 0xf940007f
|
||||
.int 0xcb2263ff
|
||||
.int 0xcb020000
|
||||
.int 0x17fffffa
|
||||
.int 0xb4000040
|
||||
#endif
|
||||
.int 0xcb2063ff
|
||||
.int 0x910003e0
|
||||
.int 0xa9bf7bfd
|
||||
.reloc ., R_AARCH64_CALL26, _(__bound_new_region)
|
||||
.int 0x94000000
|
||||
.int 0xa8c17bfd
|
||||
.int 0x910003e0
|
||||
.int 0xd65f03c0
|
||||
#else
|
||||
mov x1, x0
|
||||
add x0, x0, #16 // Round up to 16-byte boundary
|
||||
and x0, x0, #-16 // Ensure 16-byte alignment
|
||||
#ifdef _WIN32
|
||||
cbz x0, p100 // If size is 0, skip to return
|
||||
// Windows requires page-wise allocation with stack probing
|
||||
mov x2, #4096 // Page size = 4096 bytes
|
||||
|
||||
p101:
|
||||
cmp x0, x2 // Compare remaining size with page size
|
||||
b.lo p102 // If less than page, jump to remainder
|
||||
|
||||
// Probe first, then allocate
|
||||
sub x3, sp, x2 // Calculate guard page address (sp - 4096)
|
||||
ldr xzr, [x3] // Touch guard page FIRST
|
||||
sub sp, sp, x2 // THEN allocate the page
|
||||
|
||||
sub x0, x0, x2 // Decrement remaining size
|
||||
b p101 // Continue loop
|
||||
|
||||
p102:
|
||||
// Allocate remaining bytes (less than one page)
|
||||
cbz x0, p100 // If no remaining bytes, skip
|
||||
sub sp, sp, x0 // Allocate remaining space
|
||||
#else
|
||||
// Non-Windows: simple one-time allocation
|
||||
sub sp, sp, x0 // Allocate space on stack
|
||||
#endif
|
||||
|
||||
p100:
|
||||
mov x0, sp // Return allocated address
|
||||
stp x29, x30, [sp, #-16]!
|
||||
bl _(__bound_new_region)
|
||||
ldp x29, x30, [sp], #16
|
||||
mov x0, sp // Return allocated address
|
||||
ret // Return to caller
|
||||
#endif
|
||||
|
||||
/* ---------------------------------------------- */
|
||||
#elif defined __riscv
|
||||
|
||||
.globl _(__bound_alloca)
|
||||
_(__bound_alloca):
|
||||
mv a1, a0
|
||||
sub sp, sp, a0
|
||||
addi sp, sp, -16
|
||||
andi sp, sp, -16
|
||||
add a0, sp, zero
|
||||
addi sp,sp,-16
|
||||
sd s0,0(sp)
|
||||
sd ra,8(sp)
|
||||
jal _(__bound_new_region)
|
||||
ld s0,0(sp)
|
||||
ld ra,8(sp)
|
||||
addi sp,sp,16
|
||||
add a0, sp, zero
|
||||
ret
|
||||
|
||||
/* ---------------------------------------------- */
|
||||
#endif
|
||||
|
||||
31
lib/alloca.S
31
lib/alloca.S
@ -70,25 +70,18 @@ p3:
|
||||
/* ---------------------------------------------- */
|
||||
#elif defined __arm__
|
||||
|
||||
.text
|
||||
.align 2
|
||||
.global alloca
|
||||
.type alloca, %function
|
||||
alloca:
|
||||
.globl _(alloca)
|
||||
_(alloca):
|
||||
rsb sp, r0, sp
|
||||
bic sp, sp, #7
|
||||
mov r0, sp
|
||||
mov pc, lr
|
||||
.size alloca, .-alloca
|
||||
|
||||
/* ---------------------------------------------- */
|
||||
#elif defined __aarch64__ || defined __arm64__
|
||||
|
||||
.text
|
||||
.align 2
|
||||
.global alloca
|
||||
.type alloca, %function
|
||||
alloca:
|
||||
.globl _(alloca)
|
||||
_(alloca):
|
||||
#ifdef __TINYC__
|
||||
.int 0x91003c00
|
||||
.int 0x927cec00
|
||||
@ -102,16 +95,16 @@ alloca:
|
||||
.int 0xcb2163ff
|
||||
.int 0xcb010000
|
||||
.int 0x17fffffa
|
||||
#endif
|
||||
.int 0xb4000040
|
||||
#endif
|
||||
.int 0xcb2063ff
|
||||
.int 0x910003e0
|
||||
.int 0xd65f03c0
|
||||
#else
|
||||
add x0, x0, #15 // Round up to 16-byte boundary
|
||||
and x0, x0, #-16 // Ensure 16-byte alignment
|
||||
cbz x0, p100 // If size is 0, skip to return
|
||||
#ifdef _WIN32
|
||||
cbz x0, p100 // If size is 0, skip to return
|
||||
// Windows requires page-wise allocation with stack probing
|
||||
mov x1, #4096 // Page size = 4096 bytes
|
||||
|
||||
@ -140,6 +133,16 @@ p100:
|
||||
mov x0, sp // Return allocated address
|
||||
ret // Return to caller
|
||||
#endif
|
||||
.size alloca, .-alloca
|
||||
|
||||
/* ---------------------------------------------- */
|
||||
#elif defined __riscv
|
||||
|
||||
.globl _(alloca)
|
||||
_(alloca):
|
||||
sub sp, sp, a0
|
||||
addi sp, sp, -15
|
||||
andi sp, sp, -16
|
||||
add a0, sp, zero
|
||||
ret
|
||||
|
||||
#endif
|
||||
|
||||
2
libtcc.c
2
libtcc.c
@ -40,7 +40,7 @@
|
||||
#elif defined(TCC_TARGET_ARM64)
|
||||
#include "arm64-gen.c"
|
||||
#include "arm64-link.c"
|
||||
#include "arm-asm.c"
|
||||
#include "arm64-asm.c"
|
||||
#elif defined(TCC_TARGET_C67)
|
||||
#include "c67-gen.c"
|
||||
#include "c67-link.c"
|
||||
|
||||
177
riscv64-asm.c
177
riscv64-asm.c
@ -63,6 +63,9 @@ static void asm_emit_opcode(uint32_t opcode);
|
||||
static void asm_emit_r(int token, uint32_t opcode, const Operand *rd, const Operand *rs1, const Operand *rs2);
|
||||
static void asm_emit_s(int token, uint32_t opcode, const Operand *rs1, const Operand *rs2, const Operand *imm);
|
||||
static void asm_emit_u(int token, uint32_t opcode, const Operand *rd, const Operand *rs2);
|
||||
static void asm_emit_f(int token, uint32_t opcode, const Operand *rd, const Operand *rs1, const Operand *rs2);
|
||||
static void asm_emit_fb(int token, uint32_t opcode, const Operand *rd, const Operand *rs);
|
||||
static void asm_emit_fq(int token, uint32_t opcode, const Operand *rd, const Operand *rs1, const Operand *rs2, const Operand *rs3);
|
||||
ST_FUNC void asm_gen_code(ASMOperand *operands, int nb_operands, int nb_outputs, int is_output, uint8_t *clobber_regs, int out_reg);
|
||||
static void asm_nullary_opcode(TCCState *s1, int token);
|
||||
ST_FUNC void asm_opcode(TCCState *s1, int token);
|
||||
@ -395,6 +398,15 @@ static void asm_unary_opcode(TCCState *s1, int token)
|
||||
case TOK_ASM_rdinstreth:
|
||||
asm_emit_opcode(opcode | (0xC82 << 20) | ENCODE_RD(op.reg));
|
||||
return;
|
||||
case TOK_ASM_frflags:
|
||||
asm_emit_opcode(opcode | (0x001 << 20) | ENCODE_RD(op.reg));
|
||||
return;
|
||||
case TOK_ASM_frrm:
|
||||
asm_emit_opcode(opcode | (0x002 << 20) | ENCODE_RD(op.reg));
|
||||
return;
|
||||
case TOK_ASM_frcsr:
|
||||
asm_emit_opcode(opcode | (0x003 << 20) | ENCODE_RD(op.reg));
|
||||
return;
|
||||
|
||||
case TOK_ASM_jr:
|
||||
/* jalr zero, 0(rs)*/
|
||||
@ -428,6 +440,7 @@ static void asm_unary_opcode(TCCState *s1, int token)
|
||||
case TOK_ASM_c_jr:
|
||||
asm_emit_cr(token, 2 | (8 << 12), &op, &zero);
|
||||
return;
|
||||
|
||||
default:
|
||||
expect("unary instruction");
|
||||
}
|
||||
@ -587,6 +600,14 @@ static void asm_binary_opcode(TCCState* s1, int token)
|
||||
asm_emit_css(token, 2 | (5 << 13), ops, ops + 1);
|
||||
return;
|
||||
|
||||
/* F/D extension */
|
||||
case TOK_ASM_fsqrt_d:
|
||||
asm_emit_fb(token, 0x53 | (11 << 27) | (1 << 25) | (7 << 12), ops, ops + 1);
|
||||
return;
|
||||
case TOK_ASM_fsqrt_s:
|
||||
asm_emit_fb(token, 0x53 | (11 << 27) | (0 << 25) | (7 << 12), ops, ops + 1);
|
||||
return;
|
||||
|
||||
/* pseudoinstructions */
|
||||
/* rd, sym */
|
||||
case TOK_ASM_la:
|
||||
@ -682,6 +703,31 @@ static void asm_binary_opcode(TCCState* s1, int token)
|
||||
asm_emit_r(token, (0xC << 2) | 3 | (2 << 12), &ops[0], &zero, &ops[1]);
|
||||
return;
|
||||
|
||||
case TOK_ASM_fabs_d:
|
||||
/* fsgnjx.d rd, rs, rs */
|
||||
asm_emit_f(token, 0x53 | (4 << 27) | (1 << 25) | (2 << 12), &ops[0], &ops[1], &ops[1]);
|
||||
return;
|
||||
case TOK_ASM_fabs_s:
|
||||
/* fsgnjx.s rd, rs, rs */
|
||||
asm_emit_f(token, 0x53 | (4 << 27) | (0 << 25) | (2 << 12), &ops[0], &ops[1], &ops[1]);
|
||||
return;
|
||||
|
||||
case TOK_ASM_csrs:
|
||||
/* csrrs x0, csr, rs */
|
||||
asm_emit_opcode(0x73 | (2 << 12) | (ops[0].e.v << 20) | ENCODE_RS1(ops[1].reg));
|
||||
return;
|
||||
case TOK_ASM_csrc:
|
||||
/* csrrc x0, csr, rs */
|
||||
asm_emit_opcode(0x73 | (3 << 12) | (ops[0].e.v << 20) | ENCODE_RS1(ops[1].reg));
|
||||
return;
|
||||
case TOK_ASM_fsrm:
|
||||
/* csrrw rd, frm, rs */
|
||||
asm_emit_opcode(0x73 | (1 << 12) | (2 << 20) | ENCODE_RD(ops[0].reg) | ENCODE_RS1(ops[1].reg));
|
||||
return;
|
||||
case TOK_ASM_fscsr:
|
||||
/* csrrw rd, fcsr, rs */
|
||||
asm_emit_opcode(0x73 | (1 << 12) | (3 << 20) | ENCODE_RD(ops[0].reg) | ENCODE_RS1(ops[1].reg));
|
||||
return;
|
||||
default:
|
||||
expect("binary instruction");
|
||||
}
|
||||
@ -709,6 +755,73 @@ static void asm_emit_r(int token, uint32_t opcode, const Operand* rd, const Oper
|
||||
gen_le32(opcode | ENCODE_RD(rd->reg) | ENCODE_RS1(rs1->reg) | ENCODE_RS2(rs2->reg));
|
||||
}
|
||||
|
||||
/* caller: Add rounding mode, fmt, funct5 to opcode */
|
||||
static void asm_emit_f(int token, uint32_t opcode, const Operand* rd, const Operand* rs1, const Operand* rs2)
|
||||
{
|
||||
if (rd->type != OP_REG || !REG_IS_FLOAT(rd->reg)) {
|
||||
tcc_error("'%s': Expected destination operand that is a floating-point register", get_tok_str(token, NULL));
|
||||
}
|
||||
if (rs1->type != OP_REG || !REG_IS_FLOAT(rs1->reg)) {
|
||||
tcc_error("'%s': Expected first source operand that is a floating-point register", get_tok_str(token, NULL));
|
||||
}
|
||||
if (rs2->type != OP_REG || !REG_IS_FLOAT(rs2->reg)) {
|
||||
tcc_error("'%s': Expected second source operand that is a floating-point register", get_tok_str(token, NULL));
|
||||
}
|
||||
/* F-type instruction:
|
||||
31...27 funct5
|
||||
26...25 fmt
|
||||
24...20 rs2
|
||||
19...15 rs1
|
||||
14...12 rm
|
||||
11...7 rd
|
||||
6...0 opcode = OP-FP */
|
||||
gen_le32(opcode | ENCODE_RD(rd->reg) | ENCODE_RS1(rs1->reg) | ENCODE_RS2(rs2->reg));
|
||||
}
|
||||
/* caller: Add rounding mode, fmt, funct5 to opcode */
|
||||
static void asm_emit_fb(int token, uint32_t opcode, const Operand* rd, const Operand* rs)
|
||||
{
|
||||
if (rd->type != OP_REG || !REG_IS_FLOAT(rd->reg)) {
|
||||
tcc_error("'%s': Expected destination operand that is a floating-point register", get_tok_str(token, NULL));
|
||||
}
|
||||
if (rs->type != OP_REG || !REG_IS_FLOAT(rs->reg)) {
|
||||
tcc_error("'%s': Expected source operand that is a floating-point register", get_tok_str(token, NULL));
|
||||
}
|
||||
/* F-type instruction:
|
||||
31...27 funct5
|
||||
26...25 fmt
|
||||
24...20 rs2 = 0
|
||||
19...15 rs1 = rs
|
||||
14...12 rm
|
||||
11...7 rd
|
||||
6...0 opcode = OP-FP */
|
||||
gen_le32(opcode | ENCODE_RD(rd->reg) | ENCODE_RS1(rs->reg) | ENCODE_RS2(0));
|
||||
}
|
||||
/* caller: Add rounding mode, fmt to opcode */
|
||||
static void asm_emit_fq(int token, uint32_t opcode, const Operand* rd, const Operand* rs1, const Operand* rs2, const Operand* rs3)
|
||||
{
|
||||
if (rd->type != OP_REG || !REG_IS_FLOAT(rd->reg)) {
|
||||
tcc_error("'%s': Expected destination operand that is a floating-point register", get_tok_str(token, NULL));
|
||||
}
|
||||
if (rs1->type != OP_REG || !REG_IS_FLOAT(rs1->reg)) {
|
||||
tcc_error("'%s': Expected first source operand that is a floating-point register", get_tok_str(token, NULL));
|
||||
}
|
||||
if (rs2->type != OP_REG || !REG_IS_FLOAT(rs2->reg)) {
|
||||
tcc_error("'%s': Expected second source operand that is a floating-point register", get_tok_str(token, NULL));
|
||||
}
|
||||
if (rs3->type != OP_REG || !REG_IS_FLOAT(rs3->reg)) {
|
||||
tcc_error("'%s': Expected third source operand that is a floating-point register", get_tok_str(token, NULL));
|
||||
}
|
||||
/* F-type instruction:
|
||||
31...27 rs3
|
||||
26...25 fmt
|
||||
24...20 rs2
|
||||
19...15 rs1
|
||||
14...12 rm
|
||||
11...7 rd
|
||||
6...0 opcode */
|
||||
gen_le32(opcode | ENCODE_RD(rd->reg) | ENCODE_RS1(rs1->reg) | ENCODE_RS2(rs2->reg) | (REG_VALUE(rs3->reg) << 27));
|
||||
}
|
||||
|
||||
/* caller: Add funct3 into opcode */
|
||||
static void asm_emit_i(int token, uint32_t opcode, const Operand* rd, const Operand* rs1, const Operand* rs2)
|
||||
{
|
||||
@ -1089,11 +1202,49 @@ static void asm_ternary_opcode(TCCState *s1, int token)
|
||||
asm_emit_cs(token, 6 << 13, ops, ops + 1, ops + 2);
|
||||
return;
|
||||
|
||||
/* F/D extension */
|
||||
case TOK_ASM_fsgnj_d:
|
||||
asm_emit_f(token, 0x53 | (4 << 27) | (1 << 25) | (0 << 12), ops, ops + 1, ops + 2);
|
||||
return;
|
||||
case TOK_ASM_fsgnj_s:
|
||||
asm_emit_f(token, 0x53 | (4 << 27) | (0 << 25) | (0 << 12), ops, ops + 1, ops + 2);
|
||||
return;
|
||||
case TOK_ASM_fmax_d:
|
||||
asm_emit_f(token, 0x53 | (5 << 27) | (1 << 25) | (1 << 12), ops, ops + 1, ops + 2);
|
||||
return;
|
||||
case TOK_ASM_fmax_s:
|
||||
asm_emit_f(token, 0x53 | (5 << 27) | (0 << 25) | (1 << 12), ops, ops + 1, ops + 2);
|
||||
return;
|
||||
case TOK_ASM_fmin_d:
|
||||
asm_emit_f(token, 0x53 | (5 << 27) | (1 << 25) | (0 << 12), ops, ops + 1, ops + 2);
|
||||
return;
|
||||
case TOK_ASM_fmin_s:
|
||||
asm_emit_f(token, 0x53 | (5 << 27) | (0 << 25) | (0 << 12), ops, ops + 1, ops + 2);
|
||||
return;
|
||||
|
||||
default:
|
||||
expect("ternary instruction");
|
||||
}
|
||||
}
|
||||
|
||||
static void asm_quaternary_opcode(TCCState *s1, int token)
|
||||
{
|
||||
Operand ops[4];
|
||||
parse_operands(s1, &ops[0], 4);
|
||||
|
||||
switch (token) {
|
||||
case TOK_ASM_fmadd_d:
|
||||
asm_emit_fq(token, 0x43 | (1 << 25) | (7 << 12), ops, ops + 1, ops + 2, ops + 3);
|
||||
return;
|
||||
case TOK_ASM_fmadd_s:
|
||||
asm_emit_fq(token, 0x43 | (0 << 25) | (7 << 12), ops, ops + 1, ops + 2, ops + 3);
|
||||
return;
|
||||
|
||||
default:
|
||||
expect("quaternary instruction");
|
||||
}
|
||||
}
|
||||
|
||||
static void asm_atomic_opcode(TCCState *s1, int token)
|
||||
{
|
||||
Operand ops[3];
|
||||
@ -1271,6 +1422,8 @@ ST_FUNC void asm_opcode(TCCState *s1, int token)
|
||||
|
||||
case TOK_ASM_lui:
|
||||
case TOK_ASM_auipc:
|
||||
case TOK_ASM_fsqrt_s:
|
||||
case TOK_ASM_fsqrt_d:
|
||||
asm_binary_opcode(s1, token);
|
||||
return;
|
||||
|
||||
@ -1349,8 +1502,19 @@ ST_FUNC void asm_opcode(TCCState *s1, int token)
|
||||
case TOK_ASM_csrrsi:
|
||||
case TOK_ASM_csrrw:
|
||||
case TOK_ASM_csrrwi:
|
||||
/* F/D extension */
|
||||
case TOK_ASM_fsgnj_d:
|
||||
case TOK_ASM_fsgnj_s:
|
||||
case TOK_ASM_fmax_s:
|
||||
case TOK_ASM_fmax_d:
|
||||
case TOK_ASM_fmin_s:
|
||||
case TOK_ASM_fmin_d:
|
||||
asm_ternary_opcode(s1, token);
|
||||
return;
|
||||
case TOK_ASM_fmadd_d:
|
||||
case TOK_ASM_fmadd_s:
|
||||
asm_quaternary_opcode(s1, token);
|
||||
return;
|
||||
|
||||
/* Branches */
|
||||
case TOK_ASM_beq:
|
||||
@ -1426,6 +1590,9 @@ ST_FUNC void asm_opcode(TCCState *s1, int token)
|
||||
case TOK_ASM_jr:
|
||||
case TOK_ASM_call:
|
||||
case TOK_ASM_tail:
|
||||
case TOK_ASM_frflags:
|
||||
case TOK_ASM_frrm:
|
||||
case TOK_ASM_frcsr:
|
||||
asm_unary_opcode(s1, token);
|
||||
return;
|
||||
|
||||
@ -1441,6 +1608,12 @@ ST_FUNC void asm_opcode(TCCState *s1, int token)
|
||||
case TOK_ASM_not:
|
||||
case TOK_ASM_neg:
|
||||
case TOK_ASM_negw:
|
||||
case TOK_ASM_fabs_s:
|
||||
case TOK_ASM_fabs_d:
|
||||
case TOK_ASM_csrc:
|
||||
case TOK_ASM_csrs:
|
||||
case TOK_ASM_fsrm:
|
||||
case TOK_ASM_fscsr:
|
||||
asm_binary_opcode(s1, token);
|
||||
return;
|
||||
|
||||
@ -1556,7 +1729,7 @@ ST_FUNC void subst_asm_operand(CString *add_str, SValue *sv, int modifier)
|
||||
if ((sv->type.t & VT_BTYPE) == VT_FLOAT ||
|
||||
(sv->type.t & VT_BTYPE) == VT_DOUBLE) {
|
||||
/* floating point register */
|
||||
reg = TOK_ASM_f0 + reg;
|
||||
reg = TOK_ASM_f0 + REG_VALUE(reg);
|
||||
} else {
|
||||
/* general purpose register */
|
||||
reg = TOK_ASM_x0 + reg;
|
||||
@ -1570,7 +1743,7 @@ ST_FUNC void subst_asm_operand(CString *add_str, SValue *sv, int modifier)
|
||||
if ((sv->type.t & VT_BTYPE) == VT_FLOAT ||
|
||||
(sv->type.t & VT_BTYPE) == VT_DOUBLE) {
|
||||
/* floating point register */
|
||||
reg = TOK_ASM_f0 + reg;
|
||||
reg = TOK_ASM_f0 + REG_VALUE(reg);
|
||||
} else {
|
||||
/* general purpose register */
|
||||
reg = TOK_ASM_x0 + reg;
|
||||
|
||||
@ -911,18 +911,14 @@ ST_FUNC void gfunc_epilog(void)
|
||||
loc = (loc - num_va_regs * 8);
|
||||
d = v = (-loc + 15) & -16;
|
||||
|
||||
if (v >= (1 << 11)) {
|
||||
d = 16;
|
||||
o(0x37 | (5 << 7) | UPPER(v-16)); //lui t0, upper(v)
|
||||
EI(0x13, 0, 5, 5, SIGN11(v-16)); // addi t0, t0, lo(v)
|
||||
ER(0x33, 0, 2, 2, 5, 0); // add sp, sp, t0
|
||||
}
|
||||
EI(0x03, 3, 1, 2, d - 8 - num_va_regs * 8); // ld ra, v-8(sp)
|
||||
EI(0x03, 3, 8, 2, d - 16 - num_va_regs * 8); // ld s0, v-16(sp)
|
||||
EI(0x13, 0, 2, 2, d); // addi sp, sp, v
|
||||
EI(0x67, 0, 0, 1, 0); // jalr x0, 0(x1), aka ret
|
||||
EI(0x13, 0, 2, 8, num_va_regs * 8); // addi sp, s0, num_va_regs*8
|
||||
EI(0x03, 3, 1, 8, -8); // ld ra, -8(s0)
|
||||
EI(0x03, 3, 8, 8, -16); // ld s0, -16(s0)
|
||||
EI(0x67, 0, 0, 1, 0); // jalr x0, 0(x1), aka ret
|
||||
|
||||
large_ofs_ind = ind;
|
||||
if (v >= (1 << 11)) {
|
||||
d = 16;
|
||||
EI(0x13, 0, 8, 2, d - num_va_regs * 8); // addi s0, sp, d
|
||||
o(0x37 | (5 << 7) | UPPER(v-16)); //lui t0, upper(v)
|
||||
EI(0x13, 0, 5, 5, SIGN11(v-16)); // addi t0, t0, lo(v)
|
||||
@ -1233,6 +1229,10 @@ ST_FUNC void gen_opf(int op)
|
||||
ER(0x53, op, rd, rs1, rs2, dbl | 0x50); // fcmp.[sd] RD, RS1, RS2 (op == eq/lt/le)
|
||||
if (invert)
|
||||
EI(0x13, 4, rd, rd, 1); // xori RD, 1
|
||||
|
||||
/* generate VT_CMP output */
|
||||
vset_VT_CMP(TOK_NE);
|
||||
vtop->cmp_r = rd | (0 << 8);
|
||||
break;
|
||||
case TOK_NE:
|
||||
invert = 1;
|
||||
|
||||
@ -266,6 +266,19 @@
|
||||
DEF_ASM(remw)
|
||||
DEF_ASM(remuw)
|
||||
|
||||
/* "F"/"D" Extension for Single/Double-Precision Floating Point Arithmetic, V2.2 */
|
||||
/* enough implemented for musl */
|
||||
DEF_ASM_WITH_SUFFIX(fsgnj, s)
|
||||
DEF_ASM_WITH_SUFFIX(fsgnj, d)
|
||||
DEF_ASM_WITH_SUFFIX(fmadd, s)
|
||||
DEF_ASM_WITH_SUFFIX(fmadd, d)
|
||||
DEF_ASM_WITH_SUFFIX(fmax, s)
|
||||
DEF_ASM_WITH_SUFFIX(fmax, d)
|
||||
DEF_ASM_WITH_SUFFIX(fmin, s)
|
||||
DEF_ASM_WITH_SUFFIX(fmin, d)
|
||||
DEF_ASM_WITH_SUFFIX(fsqrt, s)
|
||||
DEF_ASM_WITH_SUFFIX(fsqrt, d)
|
||||
|
||||
/* "C" Extension for Compressed Instructions, V2.0 */
|
||||
DEF_ASM_WITH_SUFFIX(c, nop)
|
||||
/* Loads */
|
||||
|
||||
2
tcc.h
2
tcc.h
@ -385,7 +385,7 @@ extern long double strtold (const char *__nptr, char **__endptr);
|
||||
#elif defined TCC_TARGET_ARM64
|
||||
# include "arm64-gen.c"
|
||||
# include "arm64-link.c"
|
||||
# include "arm-asm.c"
|
||||
# include "arm64-asm.c"
|
||||
#elif defined TCC_TARGET_C67
|
||||
# define TCC_TARGET_COFF
|
||||
# include "coff.h"
|
||||
|
||||
17
tccasm.c
17
tccasm.c
@ -984,6 +984,23 @@ static void asm_parse_directive(TCCState *s1, int global)
|
||||
skip('@');
|
||||
next();
|
||||
break;
|
||||
case TOK_ASMDIR_reloc:
|
||||
{
|
||||
ExprValue e;
|
||||
|
||||
next();
|
||||
asm_expr(s1, &e);
|
||||
skip(',');
|
||||
#if defined(TCC_TARGET_ARM64)
|
||||
if (strcmp(get_tok_str(tok, NULL), "R_AARCH64_CALL26"))
|
||||
#endif
|
||||
tcc_error("unimp: reloc '%s' unknown", get_tok_str(tok, NULL));
|
||||
next();
|
||||
skip(',');
|
||||
greloca(cur_text_section, get_asm_sym(tok, NULL), e.v, R_AARCH64_CALL26, 0);
|
||||
next();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
tcc_error("unknown assembler directive '.%s'", get_tok_str(tok, NULL));
|
||||
break;
|
||||
|
||||
6
tccelf.c
6
tccelf.c
@ -2419,8 +2419,10 @@ static int layout_sections(TCCState *s1, int *sec_order, struct dyn_inf *d)
|
||||
if (s->sh_type != SHT_NOBITS)
|
||||
file_offset += s->sh_size;
|
||||
|
||||
ph->p_filesz = file_offset - ph->p_offset;
|
||||
ph->p_memsz = addr - ph->p_vaddr;
|
||||
if (ph) {
|
||||
ph->p_filesz = file_offset - ph->p_offset;
|
||||
ph->p_memsz = addr - ph->p_vaddr;
|
||||
}
|
||||
}
|
||||
|
||||
/* Fill other headers */
|
||||
|
||||
8
tccgen.c
8
tccgen.c
@ -1701,10 +1701,8 @@ ST_FUNC void gbound_args(int nb_args)
|
||||
gfunc_call(1);
|
||||
func_bound_add_epilog = 1;
|
||||
}
|
||||
#if defined TCC_TARGET_I386 || defined TCC_TARGET_X86_64
|
||||
if (v == TOK_alloca)
|
||||
func_bound_add_epilog = 1;
|
||||
#endif
|
||||
#if TARGETOS_NetBSD
|
||||
if (v == TOK_longjmp) /* undo rename to __longjmp14 */
|
||||
sv->sym->asm_label = TOK___bound_longjmp;
|
||||
@ -8744,7 +8742,11 @@ static int decl(int l)
|
||||
while (1) { /* iterate thru each declaration */
|
||||
type = btype;
|
||||
ad = adbase;
|
||||
type_decl(&type, &ad, &v, TYPE_DIRECT);
|
||||
if (l == VT_CMP) {
|
||||
type_decl(&type, &ad, &v, TYPE_DIRECT | TYPE_PARAM);
|
||||
} else {
|
||||
type_decl(&type, &ad, &v, TYPE_DIRECT);
|
||||
}
|
||||
/*ptype("decl", &type, v);*/
|
||||
|
||||
if ((type.t & VT_BTYPE) == VT_FUNC) {
|
||||
|
||||
7
tcctok.h
7
tcctok.h
@ -23,8 +23,6 @@
|
||||
DEF(TOK_CONST1, "const")
|
||||
DEF(TOK_CONST2, "__const") /* gcc keyword */
|
||||
DEF(TOK_CONST3, "__const__") /* gcc keyword */
|
||||
DEF(TOK_PURE1, "pure")
|
||||
DEF(TOK_PURE2, "__pure__")
|
||||
DEF(TOK_VOLATILE1, "volatile")
|
||||
DEF(TOK_VOLATILE2, "__volatile") /* gcc keyword */
|
||||
DEF(TOK_VOLATILE3, "__volatile__") /* gcc keyword */
|
||||
@ -147,6 +145,8 @@
|
||||
DEF(TOK_ALWAYS_INLINE1, "always_inline")
|
||||
DEF(TOK_ALWAYS_INLINE2, "__always_inline__")
|
||||
DEF(TOK_NOINLINE, "__noinline__")
|
||||
DEF(TOK_PURE1, "pure")
|
||||
DEF(TOK_PURE2, "__pure__")
|
||||
|
||||
DEF(TOK_MODE, "__mode__")
|
||||
DEF(TOK_MODE_QI, "__QI__")
|
||||
@ -301,9 +301,7 @@
|
||||
DEF(TOK___fixxfdi, "__fixxfdi")
|
||||
#endif
|
||||
|
||||
#if defined TCC_TARGET_I386 || defined TCC_TARGET_X86_64
|
||||
DEF(TOK_alloca, "alloca")
|
||||
#endif
|
||||
|
||||
#if defined TCC_TARGET_PE
|
||||
DEF(TOK___chkstk, "__chkstk")
|
||||
@ -415,6 +413,7 @@
|
||||
DEF_ASMDIR(long)
|
||||
DEF_ASMDIR(int)
|
||||
DEF_ASMDIR(symver)
|
||||
DEF_ASMDIR(reloc)
|
||||
DEF_ASMDIR(section) /* must be last directive */
|
||||
|
||||
#if defined TCC_TARGET_I386 || defined TCC_TARGET_X86_64
|
||||
|
||||
@ -169,14 +169,6 @@ int test13(void)
|
||||
return strlen(tab);
|
||||
}
|
||||
|
||||
#if defined __i386__ || defined __x86_64__
|
||||
#define allocf(x)
|
||||
#else
|
||||
#undef alloca
|
||||
#define alloca(x) malloc(x)
|
||||
#define allocf(x) free(x)
|
||||
#endif
|
||||
|
||||
int test14(void)
|
||||
{
|
||||
char *p = alloca(TAB_SIZE);
|
||||
@ -184,7 +176,6 @@ int test14(void)
|
||||
memset(p, 'a', TAB_SIZE);
|
||||
p[TAB_SIZE-1] = 0;
|
||||
ret = strlen(p);
|
||||
allocf(p);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -196,7 +187,6 @@ int test15(void)
|
||||
memset(p, 'a', TAB_SIZE);
|
||||
p[TAB_SIZE-1] = 0;
|
||||
ret = strlen(p);
|
||||
allocf(p);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -211,8 +201,6 @@ int test16()
|
||||
|
||||
/* Test alloca embedded in a larger expression */
|
||||
printf("alloca : %s : %s\n", p, strcpy(q=alloca(strlen(demo)+1),demo) );
|
||||
allocf(p);
|
||||
allocf(q);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -228,8 +216,6 @@ int test17()
|
||||
|
||||
/* Test alloca embedded in a larger expression */
|
||||
printf("alloca : %s : %s\n", p, strcpy(q=alloca(strlen(demo)),demo) );
|
||||
allocf(p);
|
||||
allocf(q);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -2941,14 +2941,12 @@ void old_style_function_test(void)
|
||||
|
||||
void alloca_test()
|
||||
{
|
||||
#if defined __i386__ || defined __x86_64__ || defined __arm__
|
||||
char *p = alloca(16);
|
||||
strcpy(p,"123456789012345");
|
||||
printf("alloca: p is %s\n", p);
|
||||
char *demo = "This is only a test.\n";
|
||||
/* Test alloca embedded in a larger expression */
|
||||
printf("alloca: %s\n", strcpy(alloca(strlen(demo)+1),demo) );
|
||||
#endif
|
||||
}
|
||||
|
||||
void *bounds_checking_is_enabled()
|
||||
@ -4208,7 +4206,6 @@ double get100 () { return 100.0; }
|
||||
|
||||
void callsave_test(void)
|
||||
{
|
||||
#if defined __i386__ || defined __x86_64__ || defined __arm__
|
||||
int i, s; double *d; double t;
|
||||
s = sizeof (double);
|
||||
printf ("callsavetest: %d\n", s);
|
||||
@ -4221,7 +4218,6 @@ void callsave_test(void)
|
||||
generates a segfault. */
|
||||
i = d[0] > get100 ();
|
||||
printf ("%d\n", i);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -1173,7 +1173,8 @@ extern "C" {
|
||||
#define WM_XBUTTONDOWN 0x020B
|
||||
#define WM_XBUTTONUP 0x020C
|
||||
#define WM_XBUTTONDBLCLK 0x020D
|
||||
#define WM_MOUSELAST 0x020D
|
||||
#define WM_MOUSEHWHEEL 0x020E
|
||||
#define WM_MOUSELAST 0x020E
|
||||
|
||||
#define WHEEL_DELTA 120
|
||||
#define GET_WHEEL_DELTA_WPARAM(wParam) ((short)HIWORD(wParam))
|
||||
|
||||
10
x86_64-asm.h
10
x86_64-asm.h
@ -509,7 +509,12 @@ ALT(DEF_ASM_OP2(movhps, 0x0f17, 0, OPC_MODRM, OPT_SSE, OPT_EA | OPT_REG32 ))
|
||||
DEF_ASM_OP2(addps, 0x0f58, 0, OPC_MODRM, OPT_EA | OPT_SSE, OPT_SSE )
|
||||
DEF_ASM_OP2(cvtpi2ps, 0x0f2a, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_SSE )
|
||||
DEF_ASM_OP2(cvtps2pi, 0x0f2d, 0, OPC_MODRM, OPT_EA | OPT_SSE, OPT_MMX )
|
||||
DEF_ASM_OP2(cvtss2si, 0xf30f2d, 0, OPC_MODRM, OPT_EA | OPT_SSE, OPT_REG32 )
|
||||
ALT(DEF_ASM_OP2(cvtss2si, 0xf30f2d, 0, OPC_MODRM | OPC_48, OPT_EA | OPT_SSE, OPT_REG64 ))
|
||||
DEF_ASM_OP2(cvtsd2si, 0xf20f2d, 0, OPC_MODRM, OPT_EA | OPT_SSE, OPT_REG32 )
|
||||
ALT(DEF_ASM_OP2(cvtsd2si, 0xf20f2d, 0, OPC_MODRM | OPC_48, OPT_EA | OPT_SSE, OPT_REG64 ))
|
||||
DEF_ASM_OP2(cvttps2pi, 0x0f2c, 0, OPC_MODRM, OPT_EA | OPT_SSE, OPT_MMX )
|
||||
DEF_ASM_OP2(andps, 0x0f54, 0, OPC_MODRM, OPT_EA | OPT_SSE, OPT_SSE )
|
||||
DEF_ASM_OP2(divps, 0x0f5e, 0, OPC_MODRM, OPT_EA | OPT_SSE, OPT_SSE )
|
||||
DEF_ASM_OP2(maxps, 0x0f5f, 0, OPC_MODRM, OPT_EA | OPT_SSE, OPT_SSE )
|
||||
DEF_ASM_OP2(minps, 0x0f5d, 0, OPC_MODRM, OPT_EA | OPT_SSE, OPT_SSE )
|
||||
@ -523,8 +528,13 @@ ALT(DEF_ASM_OP2(movhps, 0x0f17, 0, OPC_MODRM, OPT_SSE, OPT_EA | OPT_REG32 ))
|
||||
DEF_ASM_OP2(rcpss, 0x0f53, 0, OPC_MODRM, OPT_EA | OPT_SSE, OPT_SSE )
|
||||
DEF_ASM_OP2(rsqrtps, 0x0f52, 0, OPC_MODRM, OPT_EA | OPT_SSE, OPT_SSE )
|
||||
DEF_ASM_OP2(sqrtps, 0x0f51, 0, OPC_MODRM, OPT_EA | OPT_SSE, OPT_SSE )
|
||||
DEF_ASM_OP2(sqrtss, 0xf30f51, 0, OPC_MODRM, OPT_EA | OPT_SSE, OPT_SSE )
|
||||
DEF_ASM_OP2(subps, 0x0f5c, 0, OPC_MODRM, OPT_EA | OPT_SSE, OPT_SSE )
|
||||
|
||||
/* sse2 */
|
||||
DEF_ASM_OP2(andpd, 0x660f54, 0, OPC_MODRM, OPT_EA | OPT_SSE, OPT_SSE)
|
||||
DEF_ASM_OP2(sqrtsd, 0xf20f51, 0, OPC_MODRM, OPT_EA | OPT_SSE, OPT_SSE)
|
||||
|
||||
/* movnti should only accept REG32 and REG64, we accept more */
|
||||
DEF_ASM_OP2(movnti, 0x0fc3, 0, OPC_MODRM, OPT_REG, OPT_EA)
|
||||
DEF_ASM_OP2(movntil, 0x0fc3, 0, OPC_MODRM, OPT_REG32, OPT_EA)
|
||||
|
||||
Loading…
Reference in New Issue
Block a user