Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
G
go
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
go
Commits
ae167bf0
Commit
ae167bf0
authored
Jan 09, 2009
by
Russ Cox
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
clean up automatic indirect, delete some dead code.
R=ken OCL=22454 CL=22457
parent
40d54352
Changes
5
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
71 additions
and
204 deletions
+71
-204
src/cmd/6g/cgen.c
src/cmd/6g/cgen.c
+10
-85
src/cmd/6g/gsubr.c
src/cmd/6g/gsubr.c
+0
-1
src/cmd/gc/go.h
src/cmd/gc/go.h
+3
-6
src/cmd/gc/subr.c
src/cmd/gc/subr.c
+5
-46
src/cmd/gc/walk.c
src/cmd/gc/walk.c
+53
-66
No files found.
src/cmd/6g/cgen.c
View file @
ae167bf0
...
...
@@ -189,27 +189,12 @@ cgen(Node *n, Node *res)
}
regalloc
(
&
n1
,
nl
->
type
,
res
);
cgen
(
nl
,
&
n1
);
if
(
isptrsarray
(
n
->
type
)
&&
isptrdarray
(
nl
->
type
))
{
// convert dynamic array to static array
n2
=
n1
;
n2
.
op
=
OINDREG
;
n2
.
xoffset
=
Array_array
;
n2
.
type
=
types
[
tptr
];
gins
(
AMOVQ
,
&
n2
,
&
n1
);
}
if
(
isptrdarray
(
n
->
type
)
&&
isptrsarray
(
nl
->
type
))
{
// conver static array to dynamic array
// it is assumed that the dope is just before the array
nodconst
(
&
n2
,
types
[
tptr
],
sizeof_Array
);
gins
(
ASUBQ
,
&
n2
,
&
n1
);
}
gmove
(
&
n1
,
res
);
regfree
(
&
n1
);
break
;
case
ODOT
:
case
ODOTPTR
:
case
OINDEXPTR
:
case
OINDEX
:
case
OIND
:
igen
(
n
,
&
n1
,
res
);
...
...
@@ -218,7 +203,9 @@ cgen(Node *n, Node *res)
break
;
case
OLEN
:
if
(
istype
(
nl
->
type
,
TSTRING
))
{
if
(
istype
(
nl
->
type
,
TSTRING
)
||
istype
(
nl
->
type
,
TMAP
))
{
// both string and map have len in the first 32-bit word.
// a zero pointer means zero length
regalloc
(
&
n1
,
types
[
tptr
],
res
);
cgen
(
nl
,
&
n1
);
...
...
@@ -237,26 +224,7 @@ cgen(Node *n, Node *res)
regfree
(
&
n1
);
break
;
}
if
(
istype
(
nl
->
type
,
TMAP
))
{
regalloc
(
&
n1
,
types
[
tptr
],
res
);
cgen
(
nl
,
&
n1
);
n1
.
op
=
OINDREG
;
n1
.
type
=
types
[
TINT32
];
gmove
(
&
n1
,
res
);
regfree
(
&
n1
);
break
;
}
if
(
isptrdarray
(
nl
->
type
))
{
regalloc
(
&
n1
,
types
[
tptr
],
res
);
cgen
(
nl
,
&
n1
);
n1
.
op
=
OINDREG
;
n1
.
type
=
types
[
TUINT32
];
n1
.
xoffset
=
Array_nel
;
gmove
(
&
n1
,
res
);
regfree
(
&
n1
);
break
;
}
if
(
isdarray
(
nl
->
type
))
{
if
(
isslice
(
nl
->
type
))
{
regalloc
(
&
n1
,
types
[
tptr
],
res
);
agen
(
nl
,
&
n1
);
n1
.
op
=
OINDREG
;
...
...
@@ -270,17 +238,7 @@ cgen(Node *n, Node *res)
break
;
case
OCAP
:
if
(
isptrdarray
(
nl
->
type
))
{
regalloc
(
&
n1
,
types
[
tptr
],
res
);
cgen
(
nl
,
&
n1
);
n1
.
op
=
OINDREG
;
n1
.
type
=
types
[
TUINT32
];
n1
.
xoffset
=
Array_cap
;
gmove
(
&
n1
,
res
);
regfree
(
&
n1
);
break
;
}
if
(
isdarray
(
nl
->
type
))
{
if
(
isslice
(
nl
->
type
))
{
regalloc
(
&
n1
,
types
[
tptr
],
res
);
agen
(
nl
,
&
n1
);
n1
.
op
=
OINDREG
;
...
...
@@ -436,32 +394,6 @@ agen(Node *n, Node *res)
cgen_aret
(
n
,
res
);
break
;
case
OINDEXPTR
:
w
=
n
->
type
->
width
;
if
(
nr
->
addable
)
goto
iprad
;
if
(
nl
->
addable
)
{
if
(
whatis
(
nr
)
!=
Wlitint
)
{
regalloc
(
&
n1
,
nr
->
type
,
N
);
cgen
(
nr
,
&
n1
);
}
regalloc
(
&
n3
,
types
[
tptr
],
res
);
cgen
(
nl
,
&
n3
);
goto
index
;
}
cgen
(
nr
,
res
);
tempname
(
&
tmp
,
nr
->
type
);
gmove
(
res
,
&
tmp
);
iprad:
regalloc
(
&
n3
,
types
[
tptr
],
res
);
cgen
(
nl
,
&
n3
);
if
(
whatis
(
nr
)
!=
Wlitint
)
{
regalloc
(
&
n1
,
nr
->
type
,
N
);
cgen
(
nr
,
&
n1
);
}
goto
index
;
case
OINDEX
:
w
=
n
->
type
->
width
;
if
(
nr
->
addable
)
...
...
@@ -499,7 +431,7 @@ agen(Node *n, Node *res)
// constant index
if
(
whatis
(
nr
)
==
Wlitint
)
{
v
=
mpgetfix
(
nr
->
val
.
u
.
xval
);
if
(
is
darray
(
nl
->
type
))
{
if
(
is
slice
(
nl
->
type
))
{
if
(
!
debug
[
'B'
])
{
n1
=
n3
;
...
...
@@ -523,10 +455,6 @@ agen(Node *n, Node *res)
if
(
v
<
0
)
yyerror
(
"out of bounds on array"
);
else
if
(
isptrsarray
(
nl
->
type
))
{
if
(
v
>=
nl
->
type
->
type
->
bound
)
yyerror
(
"out of bounds on array"
);
}
else
if
(
v
>=
nl
->
type
->
bound
)
yyerror
(
"out of bounds on array"
);
}
...
...
@@ -550,23 +478,20 @@ agen(Node *n, Node *res)
if
(
!
debug
[
'B'
])
{
// check bounds
if
(
is
darray
(
nl
->
type
))
{
if
(
is
slice
(
nl
->
type
))
{
n1
=
n3
;
n1
.
op
=
OINDREG
;
n1
.
type
=
types
[
tptr
];
n1
.
xoffset
=
Array_nel
;
}
else
{
}
else
nodconst
(
&
n1
,
types
[
TUINT64
],
nl
->
type
->
bound
);
if
(
isptrsarray
(
nl
->
type
))
nodconst
(
&
n1
,
types
[
TUINT64
],
nl
->
type
->
type
->
bound
);
}
gins
(
optoas
(
OCMP
,
types
[
TUINT32
]),
&
n2
,
&
n1
);
p1
=
gbranch
(
optoas
(
OLT
,
types
[
TUINT32
]),
T
);
gins
(
ACALL
,
N
,
throwindex
);
patch
(
p1
,
pc
);
}
if
(
is
darray
(
nl
->
type
))
{
if
(
is
slice
(
nl
->
type
))
{
n1
=
n3
;
n1
.
op
=
OINDREG
;
n1
.
type
=
types
[
tptr
];
...
...
@@ -776,7 +701,7 @@ bgen(Node *n, int true, Prog *to)
nr
=
r
;
}
if
(
is
darray
(
nl
->
type
))
{
if
(
is
slice
(
nl
->
type
))
{
// only valid to cmp darray to literal nil
if
((
a
!=
OEQ
&&
a
!=
ONE
)
||
nr
->
op
!=
OLITERAL
)
{
yyerror
(
"illegal array comparison"
);
...
...
src/cmd/6g/gsubr.c
View file @
ae167bf0
...
...
@@ -1913,7 +1913,6 @@ sudoaddable(Node *n, Addr *a)
reg1
->
op
=
OEMPTY
;
goto
odot
;
case
OINDEXPTR
:
case
OINDEX
:
cleani
+=
2
;
reg
=
&
clean
[
cleani
-
1
];
...
...
src/cmd/gc/go.h
View file @
ae167bf0
...
...
@@ -308,7 +308,7 @@ enum
OADDR
,
OIND
,
OCALL
,
OCALLMETH
,
OCALLINTER
,
OINDEX
,
O
INDEXPTR
,
O
SLICE
,
OINDEX
,
OSLICE
,
ONOT
,
OCOM
,
OPLUS
,
OMINUS
,
OSEND
,
ORECV
,
OLITERAL
,
OREGISTER
,
OINDREG
,
OCONV
,
OCOMP
,
OKEY
,
...
...
@@ -627,10 +627,8 @@ Type* aindex(Node*, Type*);
int
isnil
(
Node
*
);
int
isptrto
(
Type
*
,
int
);
int
istype
(
Type
*
,
int
);
int
isptrsarray
(
Type
*
);
int
isptrdarray
(
Type
*
);
int
issarray
(
Type
*
);
int
isdarray
(
Type
*
);
int
isfixedarray
(
Type
*
);
int
isslice
(
Type
*
);
int
isinter
(
Type
*
);
int
isnilinter
(
Type
*
);
int
isddd
(
Type
*
);
...
...
@@ -638,7 +636,6 @@ Type* dclmethod(Type*);
Type
*
methtype
(
Type
*
);
int
methconv
(
Type
*
);
Sym
*
signame
(
Type
*
);
int
bytearraysz
(
Type
*
);
int
eqtype
(
Type
*
,
Type
*
,
int
);
void
argtype
(
Node
*
,
Type
*
);
int
eqargs
(
Type
*
,
Type
*
);
...
...
src/cmd/gc/subr.c
View file @
ae167bf0
...
...
@@ -301,7 +301,7 @@ algtype(Type *t)
if
(
isptr
[
simtype
[
t
->
etype
]])
a
=
APTR
;
// pointer
else
if
(
t
->
etype
==
TARRAY
&&
t
->
bound
<
0
)
if
(
isslice
(
t
)
)
a
=
ASLICE
;
else
if
(
t
->
etype
==
TSTRUCT
)
...
...
@@ -667,7 +667,6 @@ opnames[] =
[
OGT
]
=
"GT"
,
[
OIF
]
=
"IF"
,
[
OINDEX
]
=
"INDEX"
,
[
OINDEXPTR
]
=
"INDEXPTR"
,
[
OIND
]
=
"IND"
,
[
OKEY
]
=
"KEY"
,
[
OLABEL
]
=
"LABEL"
,
...
...
@@ -831,7 +830,6 @@ etnames[] =
[
TDDD
]
=
"DDD"
,
[
TFUNC
]
=
"FUNC"
,
[
TARRAY
]
=
"ARRAY"
,
// [TDARRAY] = "DARRAY",
[
TSTRUCT
]
=
"STRUCT"
,
[
TCHAN
]
=
"CHAN"
,
[
TMAP
]
=
"MAP"
,
...
...
@@ -1436,37 +1434,15 @@ istype(Type *t, int et)
}
int
is
ptrs
array
(
Type
*
t
)
is
fixed
array
(
Type
*
t
)
{
if
(
isptrto
(
t
,
TARRAY
))
if
(
t
->
type
->
bound
>=
0
)
return
1
;
return
0
;
return
t
!=
T
&&
t
->
etype
==
TARRAY
&&
t
->
bound
>=
0
;
}
int
is
ptrdarray
(
Type
*
t
)
is
slice
(
Type
*
t
)
{
if
(
isptrto
(
t
,
TARRAY
))
if
(
t
->
type
->
bound
<
0
)
return
1
;
return
0
;
}
int
issarray
(
Type
*
t
)
{
if
(
t
!=
T
&&
t
->
etype
==
TARRAY
&&
t
->
bound
>=
0
)
return
1
;
return
0
;
}
int
isdarray
(
Type
*
t
)
{
if
(
t
!=
T
&&
t
->
etype
==
TARRAY
&&
t
->
bound
<
0
)
return
1
;
return
0
;
return
t
!=
T
&&
t
->
etype
==
TARRAY
&&
t
->
bound
<
0
;
}
int
...
...
@@ -1683,23 +1659,6 @@ bad:
return
S
;
}
int
bytearraysz
(
Type
*
t
)
{
if
(
t
==
T
)
return
-
2
;
if
(
isptr
[
t
->
etype
])
{
t
=
t
->
type
;
if
(
t
==
T
)
return
-
2
;
}
if
(
t
->
etype
!=
TARRAY
)
return
-
2
;
if
(
!
eqtype
(
t
->
type
,
types
[
TUINT8
],
0
))
return
-
2
;
return
t
->
bound
;
// -1 is dyn, >=0 is fixed
}
int
eqtype
(
Type
*
t1
,
Type
*
t2
,
int
d
)
{
...
...
src/cmd/gc/walk.c
View file @
ae167bf0
...
...
@@ -164,6 +164,33 @@ indir(Node *nl, Node *nr)
*
nl
=
*
nr
;
}
void
implicitstar
(
Node
**
nn
)
{
Type
*
t
;
Node
*
n
;
// insert implicit * if needed
n
=
*
nn
;
t
=
n
->
type
;
if
(
t
==
T
||
!
isptr
[
t
->
etype
])
return
;
t
=
t
->
type
;
if
(
t
==
T
)
return
;
switch
(
t
->
etype
)
{
case
TMAP
:
case
TSTRING
:
case
TARRAY
:
break
;
default:
return
;
}
n
=
nod
(
OIND
,
n
,
N
);
walktype
(
n
,
Elv
);
*
nn
=
n
;
}
void
walktype
(
Node
*
n
,
int
top
)
{
...
...
@@ -437,7 +464,6 @@ loop:
break
;
case
OINDEX
:
case
OINDEXPTR
:
if
(
cl
==
2
&&
cr
==
1
)
{
// a,b = map[] - mapaccess2
walktype
(
r
->
left
,
Erv
);
...
...
@@ -496,7 +522,6 @@ loop:
switch
(
l
->
op
)
{
case
OINDEX
:
case
OINDEXPTR
:
if
(
cl
==
1
&&
cr
==
2
)
{
// map[] = a,b - mapassign2
if
(
!
istype
(
l
->
left
->
type
,
TMAP
))
...
...
@@ -581,11 +606,13 @@ loop:
// to string
if
(
l
->
type
!=
T
)
if
(
istype
(
t
,
TSTRING
))
{
if
(
isint
[
l
->
type
->
etype
])
{
et
=
l
->
type
->
etype
;
if
(
isint
[
et
])
{
indir
(
n
,
stringop
(
n
,
top
));
goto
ret
;
}
if
(
bytearraysz
(
l
->
type
)
!=
-
2
)
{
if
(
et
==
TARRAY
)
if
(
istype
(
l
->
type
->
type
,
TUINT8
))
{
n
->
op
=
OARRAY
;
indir
(
n
,
stringop
(
n
,
top
));
goto
ret
;
...
...
@@ -593,11 +620,11 @@ loop:
}
// convert dynamic to static generated by ONEW/OMAKE
if
(
is
sarray
(
t
)
&&
isdarray
(
l
->
type
))
if
(
is
fixedarray
(
t
)
&&
isslice
(
l
->
type
))
goto
ret
;
// convert static array to dynamic array
if
(
is
darray
(
t
)
&&
iss
array
(
l
->
type
))
{
if
(
is
slice
(
t
)
&&
isfixed
array
(
l
->
type
))
{
if
(
eqtype
(
t
->
type
->
type
,
l
->
type
->
type
->
type
,
0
))
{
indir
(
n
,
arrayop
(
n
,
Erv
));
goto
ret
;
...
...
@@ -795,10 +822,9 @@ loop:
if
(
top
!=
Erv
)
goto
nottop
;
walktype
(
n
->
left
,
Erv
);
implicitstar
(
&
n
->
left
);
evconst
(
n
);
t
=
n
->
left
->
type
;
if
(
t
!=
T
&&
isptr
[
t
->
etype
])
t
=
t
->
type
;
if
(
t
==
T
)
goto
ret
;
switch
(
t
->
etype
)
{
...
...
@@ -819,10 +845,9 @@ loop:
if
(
top
!=
Erv
)
goto
nottop
;
walktype
(
n
->
left
,
Erv
);
implicitstar
(
&
n
->
left
);
evconst
(
n
);
t
=
n
->
left
->
type
;
if
(
t
!=
T
&&
isptr
[
t
->
etype
])
t
=
t
->
type
;
if
(
t
==
T
)
goto
ret
;
switch
(
t
->
etype
)
{
...
...
@@ -837,7 +862,6 @@ loop:
goto
ret
;
case
OINDEX
:
case
OINDEXPTR
:
if
(
top
==
Etop
)
goto
nottop
;
...
...
@@ -848,36 +872,29 @@ loop:
goto
ret
;
defaultlit
(
n
->
left
);
implicitstar
(
&
n
->
left
);
t
=
n
->
left
->
type
;
if
(
t
==
T
)
goto
ret
;
// BOTCH - convert each index opcode
// to look like this and get rid of OINDEXPTR
if
(
istype
(
t
,
TSTRING
)
||
isptrto
(
t
,
TSTRING
))
{
switch
(
t
->
etype
)
{
default:
goto
badt
;
case
TSTRING
:
// right side must be an int
if
(
top
!=
Erv
)
goto
nottop
;
if
(
n
->
right
->
type
==
T
)
{
convlit
(
n
->
right
,
types
[
TINT
]);
if
(
n
->
right
->
type
==
T
)
goto
ret
;
break
;
}
if
(
!
isint
[
n
->
right
->
type
->
etype
])
goto
badt
;
indir
(
n
,
stringop
(
n
,
top
));
goto
ret
;
}
// left side is indirect
if
(
isptr
[
t
->
etype
])
{
t
=
t
->
type
;
n
->
op
=
OINDEXPTR
;
}
switch
(
t
->
etype
)
{
default:
goto
badt
;
break
;
case
TMAP
:
// right side must be map type
...
...
@@ -888,7 +905,6 @@ loop:
}
if
(
!
eqtype
(
n
->
right
->
type
,
t
->
down
,
0
))
goto
badt
;
n
->
op
=
OINDEX
;
n
->
type
=
t
->
type
;
if
(
top
==
Erv
)
indir
(
n
,
mapop
(
n
,
top
));
...
...
@@ -939,11 +955,10 @@ loop:
if
(
n
->
left
==
N
||
n
->
right
==
N
)
goto
ret
;
convlit
(
n
->
left
,
types
[
TSTRING
]);
implicitstar
(
&
n
->
left
);
t
=
n
->
left
->
type
;
if
(
t
==
T
)
goto
ret
;
if
(
isptr
[
t
->
etype
])
//XXX?
t
=
t
->
type
;
if
(
t
->
etype
==
TSTRING
)
{
indir
(
n
,
stringop
(
n
,
top
));
goto
ret
;
...
...
@@ -1064,7 +1079,7 @@ loop:
case
ONE
:
if
(
n
->
left
->
type
==
T
)
goto
ret
;
if
(
is
darray
(
n
->
left
->
type
))
{
if
(
is
slice
(
n
->
left
->
type
))
{
t
=
types
[
TBOOL
];
break
;
}
...
...
@@ -1912,7 +1927,7 @@ ascompat(Type *dst, Type *src)
if
(
eqtype
(
dst
,
src
,
0
))
return
1
;
if
(
is
darray
(
dst
)
&&
iss
array
(
src
))
if
(
is
slice
(
dst
)
&&
isfixed
array
(
src
))
return
1
;
if
(
isnilinter
(
dst
)
||
isnilinter
(
src
))
...
...
@@ -1973,7 +1988,7 @@ loop:
argtype
(
on
,
l
->
type
->
type
);
// any-1
break
;
}
if
(
is
darray
(
l
->
type
))
{
if
(
is
slice
(
l
->
type
))
{
on
=
syslook
(
"printarray"
,
1
);
argtype
(
on
,
l
->
type
);
// any-1
break
;
...
...
@@ -2147,15 +2162,9 @@ stringop(Node *n, int top)
case
OINDEX
:
// sys_indexstring(s, i)
c
=
n
->
left
;
if
(
istype
(
c
->
type
->
type
,
TSTRING
))
{
// lhs is string or *string
c
=
nod
(
OIND
,
c
,
N
);
c
->
type
=
c
->
left
->
type
->
type
;
}
r
=
nod
(
OCONV
,
n
->
right
,
N
);
r
->
type
=
types
[
TINT
];
r
=
list
(
c
,
r
);
r
=
list
(
n
->
left
,
r
);
on
=
syslook
(
"indexstring"
,
0
);
r
=
nod
(
OCALL
,
on
,
r
);
break
;
...
...
@@ -2284,11 +2293,6 @@ mapop(Node *n, int top)
}
a
=
n
->
right
;
// key
// if(!isptr[t->down->etype]) {
// a = nod(OADDR, a, N);
// a->type = ptrto(t);
// }
r
=
a
;
a
=
n
->
left
;
// map
r
=
list
(
a
,
r
);
...
...
@@ -2916,12 +2920,6 @@ convas(Node *n)
goto
out
;
}
if
(
n
->
left
->
op
==
OINDEXPTR
)
if
(
n
->
left
->
left
->
type
->
etype
==
TMAP
)
{
indir
(
n
,
mapop
(
n
,
Elv
));
goto
out
;
}
if
(
n
->
left
->
op
==
OSEND
)
if
(
n
->
left
->
type
!=
T
)
{
indir
(
n
,
chanop
(
n
,
Elv
));
...
...
@@ -2937,7 +2935,7 @@ convas(Node *n)
goto
out
;
}
if
(
is
darray
(
lt
)
&&
iss
array
(
rt
))
{
if
(
is
slice
(
lt
)
&&
isfixed
array
(
rt
))
{
if
(
!
eqtype
(
lt
->
type
->
type
,
rt
->
type
->
type
,
0
))
goto
bad
;
indir
(
n
,
arrayop
(
n
,
Etop
));
...
...
@@ -3040,18 +3038,14 @@ multi:
break
;
case
OINDEX
:
case
OINDEXPTR
:
// check if rhs is a map index.
// if so, types are
bool,maptype
// if so, types are
valuetype,bool
if
(
cl
!=
2
)
goto
badt
;
walktype
(
nr
->
left
,
Elv
);
t
=
nr
->
left
->
type
;
if
(
t
!=
T
&&
isptr
[
t
->
etype
])
t
=
t
->
type
;
if
(
t
==
T
||
t
->
etype
!=
TMAP
)
if
(
!
istype
(
t
,
TMAP
))
goto
badt
;
a
=
old2new
(
nl
->
left
,
t
->
type
);
n
=
a
;
a
=
old2new
(
nl
->
right
,
types
[
TBOOL
]);
...
...
@@ -3110,6 +3104,7 @@ dorange(Node *nn)
if
(
nn
->
op
!=
ORANGE
)
fatal
(
"dorange not ORANGE"
);
implicitstar
(
&
nn
->
right
);
k
=
nn
->
left
;
m
=
nn
->
right
;
local
=
nn
->
etype
;
...
...
@@ -3128,16 +3123,8 @@ dorange(Node *nn)
goto
out
;
if
(
t
->
etype
==
TARRAY
)
goto
ary
;
if
(
isptrto
(
t
,
TARRAY
))
{
t
=
t
->
type
;
goto
ary
;
}
if
(
t
->
etype
==
TMAP
)
goto
map
;
if
(
isptrto
(
t
,
TMAP
))
{
t
=
t
->
type
;
goto
map
;
}
yyerror
(
"range must be over map/array"
);
goto
out
;
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment