aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
authorLuc Van Oostenryck <luc.vanoostenryck@gmail.com>2017-08-14 15:55:46 +0200
committerLuc Van Oostenryck <luc.vanoostenryck@gmail.com>2018-06-23 07:46:40 +0200
commitdc4117c69ef98d2e79de1fab18ea0ba9d1496344 (patch)
treec27eba2819576ac4878a1c92672cc79b62407c76
parent52856c815a191b73530557133bd44ec478f3fece (diff)
downloadsparse-dev-dc4117c69ef98d2e79de1fab18ea0ba9d1496344.tar.gz
cast: specialize casts from unsigned to pointers
Currently all casts to pointers are processed alike. This is simple but rather unconvenient as it correspond to different operations that obeys to different rules and which later need extra checks. Change this by using a specific instructions (OP_UTPTR) for unsigned integer to pointers. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
-rw-r--r--Documentation/IR.rst3
-rw-r--r--cse.c2
-rw-r--r--example.c2
-rw-r--r--lib.c2
-rw-r--r--lib.h1
-rw-r--r--linearize.c22
-rw-r--r--linearize.h1
-rw-r--r--simplify.c1
-rw-r--r--sparse-llvm.c1
-rw-r--r--validation/backend/pointer-sub.c2
-rw-r--r--validation/cast-kinds-check.c2
-rw-r--r--validation/cast-weirds.c49
-rw-r--r--validation/linear/cast-kinds.c10
-rw-r--r--validation/optim/kill-casts.c1
14 files changed, 92 insertions, 7 deletions
diff --git a/Documentation/IR.rst b/Documentation/IR.rst
index 5b9155f7..56f02318 100644
--- a/Documentation/IR.rst
+++ b/Documentation/IR.rst
@@ -270,6 +270,9 @@ They all have the following signature:
.. op:: OP_SCAST
Cast to signed integer.
+.. op:: OP_UTPTR
+ Cast from unsigned integer to pointer type.
+
.. op:: OP_PTRCAST
Cast to pointer.
diff --git a/cse.c b/cse.c
index 79d37cfd..2a076709 100644
--- a/cse.c
+++ b/cse.c
@@ -94,6 +94,7 @@ void cse_collect(struct instruction *insn)
case OP_CAST:
case OP_SCAST:
case OP_PTRCAST:
+ case OP_UTPTR:
/*
* This is crap! Many "orig_types" are the
* same as far as casts go, we should generate
@@ -241,6 +242,7 @@ static int insn_compare(const void *_i1, const void *_i2)
case OP_CAST:
case OP_SCAST:
case OP_PTRCAST:
+ case OP_UTPTR:
/*
* This is crap! See the comments on hashing.
*/
diff --git a/example.c b/example.c
index 8f0869c9..2bc9de2c 100644
--- a/example.c
+++ b/example.c
@@ -81,6 +81,7 @@ static const char *opcodes[] = {
[OP_UCVTF] = "ucvtf",
[OP_SCVTF] = "scvtf",
[OP_FCVTF] = "fcvtf",
+ [OP_UTPTR] = "utptr",
[OP_PTRCAST] = "ptrcast",
[OP_CALL] = "call",
[OP_SLICE] = "slice",
@@ -1414,6 +1415,7 @@ static void generate_one_insn(struct instruction *insn, struct bb_state *state)
break;
case OP_CAST: case OP_SCAST: case OP_PTRCAST:
+ case OP_UTPTR:
case OP_FCVTU: case OP_FCVTS:
case OP_UCVTF: case OP_SCVTF:
case OP_FCVTF:
diff --git a/lib.c b/lib.c
index 7d9f4f91..0c92227f 100644
--- a/lib.c
+++ b/lib.c
@@ -258,6 +258,7 @@ int Wdefault_bitfield_sign = 0;
int Wdesignated_init = 1;
int Wdo_while = 0;
int Winit_cstring = 0;
+int Wint_to_pointer_cast = 1;
int Wenum_mismatch = 1;
int Wsparse_error = 0;
int Wmemcpy_max_count = 1;
@@ -687,6 +688,7 @@ static const struct flag warnings[] = {
{ "do-while", &Wdo_while },
{ "enum-mismatch", &Wenum_mismatch },
{ "init-cstring", &Winit_cstring },
+ { "int-to-pointer-cast", &Wint_to_pointer_cast },
{ "memcpy-max-count", &Wmemcpy_max_count },
{ "non-pointer-null", &Wnon_pointer_null },
{ "old-initializer", &Wold_initializer },
diff --git a/lib.h b/lib.h
index 6c3f84cf..33c41672 100644
--- a/lib.h
+++ b/lib.h
@@ -149,6 +149,7 @@ extern int Wdo_while;
extern int Wenum_mismatch;
extern int Wsparse_error;
extern int Winit_cstring;
+extern int Wint_to_pointer_cast;
extern int Wmemcpy_max_count;
extern int Wnon_pointer_null;
extern int Wold_initializer;
diff --git a/linearize.c b/linearize.c
index a7d2b068..0f40682c 100644
--- a/linearize.c
+++ b/linearize.c
@@ -268,6 +268,7 @@ static const char *opcodes[] = {
[OP_UCVTF] = "ucvtf",
[OP_SCVTF] = "scvtf",
[OP_FCVTF] = "fcvtf",
+ [OP_UTPTR] = "utptr",
[OP_PTRCAST] = "ptrcast",
[OP_INLINED_CALL] = "# call",
[OP_CALL] = "call",
@@ -452,6 +453,7 @@ const char *show_instruction(struct instruction *insn)
case OP_FCVTU: case OP_FCVTS:
case OP_UCVTF: case OP_SCVTF:
case OP_FCVTF:
+ case OP_UTPTR:
case OP_PTRCAST:
buf += sprintf(buf, "%s <- (%d) %s",
show_pseudo(insn->target),
@@ -1221,7 +1223,17 @@ static int get_cast_opcode(struct symbol *dst, struct symbol *src)
return OP_BADOP;
}
case MTYPE_PTR:
- return OP_PTRCAST;
+ switch (stype) {
+ case MTYPE_UINT:
+ case MTYPE_SINT:
+ if (is_ptr_type(src)) // must be a void pointer
+ return OP_PTRCAST;// FIXME: to be removed?
+ return OP_UTPTR;
+ case MTYPE_PTR:
+ return OP_PTRCAST;
+ default:
+ return OP_BADOP;
+ }
case MTYPE_UINT:
case MTYPE_SINT:
switch (stype) {
@@ -1254,6 +1266,14 @@ static pseudo_t cast_pseudo(struct entrypoint *ep, pseudo_t src, struct symbol *
switch (opcode) {
case OP_NOP:
return src;
+ case OP_UTPTR:
+ if (from->bit_size == to->bit_size)
+ break;
+ if (src == value_pseudo(0))
+ break;
+ if (Wint_to_pointer_cast)
+ warning(to->pos, "non size-preserving integer to pointer cast");
+ break;
default:
break;
}
diff --git a/linearize.h b/linearize.h
index b513d549..c5d98a2d 100644
--- a/linearize.h
+++ b/linearize.h
@@ -226,6 +226,7 @@ enum opcode {
OP_FCVTU, OP_FCVTS,
OP_UCVTF, OP_SCVTF,
OP_FCVTF,
+ OP_UTPTR,
OP_PTRCAST,
OP_UNOP_END = OP_PTRCAST,
diff --git a/simplify.c b/simplify.c
index 3a0926f1..274202fa 100644
--- a/simplify.c
+++ b/simplify.c
@@ -1223,6 +1223,7 @@ int simplify_instruction(struct instruction *insn)
case OP_FCVTU: case OP_FCVTS:
case OP_UCVTF: case OP_SCVTF:
case OP_FCVTF:
+ case OP_UTPTR:
case OP_PTRCAST:
return simplify_cast(insn);
case OP_PHI:
diff --git a/sparse-llvm.c b/sparse-llvm.c
index 75cac8f9..8732f989 100644
--- a/sparse-llvm.c
+++ b/sparse-llvm.c
@@ -1045,6 +1045,7 @@ static void output_insn(struct function *fn, struct instruction *insn)
case OP_FCVTF:
output_op_fpcast(fn, insn);
break;
+ case OP_UTPTR:
case OP_PTRCAST:
output_op_ptrcast(fn, insn);
break;
diff --git a/validation/backend/pointer-sub.c b/validation/backend/pointer-sub.c
index 3cb8f5a9..5c99f4fa 100644
--- a/validation/backend/pointer-sub.c
+++ b/validation/backend/pointer-sub.c
@@ -13,5 +13,5 @@ long subvx3(void *p, int a) { return (p - ((void*)0)) ^ 3; }
/*
* check-name: pointer-sub
- * check-command: sparsec -Wno-decl -c $file -o tmp.o
+ * check-command: sparsec -Wno-int-to-pointer-cast -Wno-decl -c $file -o tmp.o
*/
diff --git a/validation/cast-kinds-check.c b/validation/cast-kinds-check.c
index 1f10e0ec..736ab391 100644
--- a/validation/cast-kinds-check.c
+++ b/validation/cast-kinds-check.c
@@ -20,5 +20,7 @@ linear/cast-kinds.c:29:51: warning: cast wasn't removed
linear/cast-kinds.c:34:52: warning: cast wasn't removed
linear/cast-kinds.c:35:54: warning: cast wasn't removed
linear/cast-kinds.c:36:52: warning: cast wasn't removed
+linear/cast-kinds.c:37:42: warning: non size-preserving integer to pointer cast
+linear/cast-kinds.c:38:44: warning: non size-preserving integer to pointer cast
* check-error-end
*/
diff --git a/validation/cast-weirds.c b/validation/cast-weirds.c
new file mode 100644
index 00000000..136137b4
--- /dev/null
+++ b/validation/cast-weirds.c
@@ -0,0 +1,49 @@
+typedef unsigned int uint;
+typedef unsigned long ulong;
+
+static int * int_2_iptr(int a) { return (int *)a; }
+static int * uint_2_iptr(uint a) { return (int *)a; }
+
+static void * int_2_vptr(int a) { return (void *)a; }
+static void * uint_2_vptr(uint a) { return (void *)a; }
+
+/*
+ * check-name: cast-weirds
+ * check-command: test-linearize -m64 $file
+ *
+ * check-error-start
+cast-weirds.c:4:42: warning: non size-preserving integer to pointer cast
+cast-weirds.c:5:44: warning: non size-preserving integer to pointer cast
+ * check-error-end
+ *
+ * check-output-start
+int_2_iptr:
+.L0:
+ <entry-point>
+ utptr.64 %r2 <- (32) %arg1
+ ret.64 %r2
+
+
+uint_2_iptr:
+.L2:
+ <entry-point>
+ utptr.64 %r5 <- (32) %arg1
+ ret.64 %r5
+
+
+int_2_vptr:
+.L4:
+ <entry-point>
+ scast.64 %r8 <- (32) %arg1
+ ret.64 %r8
+
+
+uint_2_vptr:
+.L6:
+ <entry-point>
+ cast.64 %r11 <- (32) %arg1
+ ret.64 %r11
+
+
+ * check-output-end
+ */
diff --git a/validation/linear/cast-kinds.c b/validation/linear/cast-kinds.c
index d07a9419..4449d0af 100644
--- a/validation/linear/cast-kinds.c
+++ b/validation/linear/cast-kinds.c
@@ -55,7 +55,7 @@ static double double_2_double(double a) { return a; }
/*
* check-name: cast-kinds
- * check-command: test-linearize -m64 $file
+ * check-command: test-linearize -Wno-int-to-pointer-cast -m64 $file
*
* check-output-start
uint_2_int:
@@ -288,28 +288,28 @@ iptr_2_vptr:
int_2_iptr:
.L66:
<entry-point>
- ptrcast.64 %r101 <- (32) %arg1
+ utptr.64 %r101 <- (32) %arg1
ret.64 %r101
uint_2_iptr:
.L68:
<entry-point>
- ptrcast.64 %r104 <- (32) %arg1
+ utptr.64 %r104 <- (32) %arg1
ret.64 %r104
long_2_iptr:
.L70:
<entry-point>
- ptrcast.64 %r107 <- (64) %arg1
+ utptr.64 %r107 <- (64) %arg1
ret.64 %r107
ulong_2_iptr:
.L72:
<entry-point>
- ptrcast.64 %r110 <- (64) %arg1
+ utptr.64 %r110 <- (64) %arg1
ret.64 %r110
diff --git a/validation/optim/kill-casts.c b/validation/optim/kill-casts.c
index b79335ab..c375f5fb 100644
--- a/validation/optim/kill-casts.c
+++ b/validation/optim/kill-casts.c
@@ -20,4 +20,5 @@ void foo(struct s *x)
* check-output-ignore
* check-output-excludes: cast\\.
* check-output-excludes: fcvt[us]\\.
+ * check-output-excludes: utptr\\.
*/