aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
authorLuc Van Oostenryck <luc.vanoostenryck@gmail.com>2017-08-15 09:55:19 +0200
committerLuc Van Oostenryck <luc.vanoostenryck@gmail.com>2018-06-23 07:46:40 +0200
commitc8fac68af94b9d23b64e844a283f16b9bed2f9e0 (patch)
treecc5ace2a1e618680ce141e5b0aa6ad7066bad21c
parentff7f001bef9aa88ff951d61ec10772e7d2143180 (diff)
downloadsparse-dev-c8fac68af94b9d23b64e844a283f16b9bed2f9e0.tar.gz
cast: specialize cast from pointers
Currently all casts to pointers are processed alike. This is simple but rather unconvenient in later phases as this 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.rst10
-rw-r--r--cse.c4
-rw-r--r--example.c2
-rw-r--r--linearize.c7
-rw-r--r--linearize.h1
-rw-r--r--simplify.c1
-rw-r--r--sparse-llvm.c25
-rw-r--r--sparse.c1
-rw-r--r--validation/linear/bool-cast-lp32.c19
-rw-r--r--validation/linear/bool-cast-lp64.c18
-rw-r--r--validation/linear/bool-cast.c1
-rw-r--r--validation/linear/cast-kinds.c8
-rw-r--r--validation/optim/kill-casts.c1
13 files changed, 84 insertions, 14 deletions
diff --git a/Documentation/IR.rst b/Documentation/IR.rst
index b7fe98a4..61575386 100644
--- a/Documentation/IR.rst
+++ b/Documentation/IR.rst
@@ -264,8 +264,11 @@ They all have the following signature:
* .target: result value
* .type: type of .target
+Currently, a cast to a void pointer is treated like a cast to
+an unsigned integer of the same size.
+
.. op:: OP_CAST
- Cast to unsigned integer (and to void pointer).
+ Cast to unsigned integer.
.. op:: OP_SCAST
Cast to signed integer.
@@ -273,8 +276,11 @@ They all have the following signature:
.. op:: OP_UTPTR
Cast from pointer-sized unsigned integer to pointer type.
+.. op:: OP_PTRTU
+ Cast from pointer type to unsigned integer.
+
.. op:: OP_PTRCAST
- Cast to pointer.
+ Cast between pointers.
.. op:: OP_FCVTU
Conversion from float type to unsigned integer.
diff --git a/cse.c b/cse.c
index 2a076709..5a55caa7 100644
--- a/cse.c
+++ b/cse.c
@@ -94,7 +94,7 @@ void cse_collect(struct instruction *insn)
case OP_CAST:
case OP_SCAST:
case OP_PTRCAST:
- case OP_UTPTR:
+ case OP_UTPTR: case OP_PTRTU:
/*
* This is crap! Many "orig_types" are the
* same as far as casts go, we should generate
@@ -242,7 +242,7 @@ static int insn_compare(const void *_i1, const void *_i2)
case OP_CAST:
case OP_SCAST:
case OP_PTRCAST:
- case OP_UTPTR:
+ case OP_UTPTR: case OP_PTRTU:
/*
* This is crap! See the comments on hashing.
*/
diff --git a/example.c b/example.c
index 2bc9de2c..4ca663e6 100644
--- a/example.c
+++ b/example.c
@@ -82,6 +82,7 @@ static const char *opcodes[] = {
[OP_SCVTF] = "scvtf",
[OP_FCVTF] = "fcvtf",
[OP_UTPTR] = "utptr",
+ [OP_PTRTU] = "utptr",
[OP_PTRCAST] = "ptrcast",
[OP_CALL] = "call",
[OP_SLICE] = "slice",
@@ -1416,6 +1417,7 @@ static void generate_one_insn(struct instruction *insn, struct bb_state *state)
case OP_CAST: case OP_SCAST: case OP_PTRCAST:
case OP_UTPTR:
+ case OP_PTRTU:
case OP_FCVTU: case OP_FCVTS:
case OP_UCVTF: case OP_SCVTF:
case OP_FCVTF:
diff --git a/linearize.c b/linearize.c
index 01bd68d2..de6e4b93 100644
--- a/linearize.c
+++ b/linearize.c
@@ -269,6 +269,7 @@ static const char *opcodes[] = {
[OP_SCVTF] = "scvtf",
[OP_FCVTF] = "fcvtf",
[OP_UTPTR] = "utptr",
+ [OP_PTRTU] = "ptrtu",
[OP_PTRCAST] = "ptrcast",
[OP_INLINED_CALL] = "# call",
[OP_CALL] = "call",
@@ -454,6 +455,7 @@ const char *show_instruction(struct instruction *insn)
case OP_UCVTF: case OP_SCVTF:
case OP_FCVTF:
case OP_UTPTR:
+ case OP_PTRTU:
case OP_PTRCAST:
buf += sprintf(buf, "%s <- (%d) %s",
show_pseudo(insn->target),
@@ -1250,6 +1252,11 @@ static int get_cast_opcode(struct symbol *dst, struct symbol *src)
switch (stype) {
case MTYPE_FLOAT:
return dtype == MTYPE_UINT ? OP_FCVTU : OP_FCVTS;
+ case MTYPE_PTR:
+ return OP_PTRTU;
+ case MTYPE_VPTR:
+ case MTYPE_UINT:
+ return OP_CAST;
case MTYPE_SINT:
return OP_SCAST;
default:
diff --git a/linearize.h b/linearize.h
index c5d98a2d..d660d332 100644
--- a/linearize.h
+++ b/linearize.h
@@ -227,6 +227,7 @@ enum opcode {
OP_UCVTF, OP_SCVTF,
OP_FCVTF,
OP_UTPTR,
+ OP_PTRTU,
OP_PTRCAST,
OP_UNOP_END = OP_PTRCAST,
diff --git a/simplify.c b/simplify.c
index 274202fa..cf1c8d5f 100644
--- a/simplify.c
+++ b/simplify.c
@@ -1224,6 +1224,7 @@ int simplify_instruction(struct instruction *insn)
case OP_UCVTF: case OP_SCVTF:
case OP_FCVTF:
case OP_UTPTR:
+ case OP_PTRTU:
case OP_PTRCAST:
return simplify_cast(insn);
case OP_PHI:
diff --git a/sparse-llvm.c b/sparse-llvm.c
index 8732f989..69b77a37 100644
--- a/sparse-llvm.c
+++ b/sparse-llvm.c
@@ -881,17 +881,29 @@ static void output_op_ptrcast(struct function *fn, struct instruction *insn)
LLVMOpcode op;
char target_name[64];
- assert(is_ptr_type(insn->type));
-
src = get_operand(fn, otype, insn->src);
pseudo_name(insn->target, target_name);
dtype = symbol_type(insn->type);
- if (is_ptr_type(otype)) {
- op = LLVMBitCast;
- } else if (is_int_type(otype)) {
+ switch (insn->opcode) {
+ case OP_UTPTR:
+ case OP_SCAST: // FIXME
+ assert(is_int_type(otype));
+ assert(is_ptr_type(insn->type));
op = LLVMIntToPtr;
- } else {
+ break;
+ case OP_PTRTU:
+ assert(is_ptr_type(otype));
+ assert(is_int_type(insn->type));
+ op = LLVMPtrToInt;
+ break;
+ case OP_PTRCAST:
+ case OP_CAST: // FIXME
+ assert(is_ptr_type(otype));
+ assert(is_ptr_type(insn->type));
+ op = LLVMBitCast;
+ break;
+ default:
assert(0);
}
@@ -1046,6 +1058,7 @@ static void output_insn(struct function *fn, struct instruction *insn)
output_op_fpcast(fn, insn);
break;
case OP_UTPTR:
+ case OP_PTRTU:
case OP_PTRCAST:
output_op_ptrcast(fn, insn);
break;
diff --git a/sparse.c b/sparse.c
index afdc314e..d4884007 100644
--- a/sparse.c
+++ b/sparse.c
@@ -217,6 +217,7 @@ static void check_one_instruction(struct instruction *insn)
{
switch (insn->opcode) {
case OP_CAST: case OP_SCAST:
+ case OP_PTRTU:
if (verbose)
check_cast_instruction(insn);
break;
diff --git a/validation/linear/bool-cast-lp32.c b/validation/linear/bool-cast-lp32.c
new file mode 100644
index 00000000..44a650f4
--- /dev/null
+++ b/validation/linear/bool-cast-lp32.c
@@ -0,0 +1,19 @@
+extern int ffun(void);
+typedef void *vdp;
+typedef int *sip;
+
+static _Bool fvdp_i(vdp a) { return a; }
+static _Bool fvdp_e(vdp a) { return (_Bool)a; }
+static _Bool fsip_i(sip a) { return a; }
+static _Bool fsip_e(sip a) { return (_Bool)a; }
+static _Bool ffun_i(void) { return ffun; }
+static _Bool ffun_e(void) { return (_Bool)ffun; }
+
+/*
+ * check-name: bool-cast-pointer
+ * check-command: test-linearize -m32 -fdump-ir $file
+ * check-known-to-fail
+ *
+ * check-output-ignore
+ * check-output-excludes: ptrtu\\.
+ */
diff --git a/validation/linear/bool-cast-lp64.c b/validation/linear/bool-cast-lp64.c
new file mode 100644
index 00000000..9b2a020a
--- /dev/null
+++ b/validation/linear/bool-cast-lp64.c
@@ -0,0 +1,18 @@
+extern int ffun(void);
+typedef void *vdp;
+typedef int *sip;
+
+static _Bool fvdp_i(vdp a) { return a; }
+static _Bool fvdp_e(vdp a) { return (_Bool)a; }
+static _Bool fsip_i(sip a) { return a; }
+static _Bool fsip_e(sip a) { return (_Bool)a; }
+static _Bool ffun_i(void) { return ffun; }
+static _Bool ffun_e(void) { return (_Bool)ffun; }
+
+/*
+ * check-name: bool-cast-pointer
+ * check-command: test-linearize -m64 -fdump-ir $file
+ *
+ * check-output-ignore
+ * check-output-excludes: ptrtu\\.
+ */
diff --git a/validation/linear/bool-cast.c b/validation/linear/bool-cast.c
index 094f4438..43276a46 100644
--- a/validation/linear/bool-cast.c
+++ b/validation/linear/bool-cast.c
@@ -28,6 +28,7 @@ static _Bool fdbl_e(dbl a) { return (_Bool)a; }
* check-output-ignore
* check-output-excludes: cast\\.
* check-output-excludes: fcvt[us]\\.
+ * check-output-excludes: ptrtu\\.
* check-output-pattern(12): setne\\.
* check-output-pattern(2): fcmpune\\.
*/
diff --git a/validation/linear/cast-kinds.c b/validation/linear/cast-kinds.c
index 1742cd1e..6683ea93 100644
--- a/validation/linear/cast-kinds.c
+++ b/validation/linear/cast-kinds.c
@@ -88,7 +88,7 @@ vptr_2_int:
iptr_2_int:
.L8:
<entry-point>
- cast.32 %r14 <- (64) %arg1
+ ptrtu.32 %r14 <- (64) %arg1
ret.32 %r14
@@ -136,7 +136,7 @@ vptr_2_uint:
iptr_2_uint:
.L22:
<entry-point>
- cast.32 %r35 <- (64) %arg1
+ ptrtu.32 %r35 <- (64) %arg1
ret.32 %r35
@@ -184,7 +184,7 @@ vptr_2_long:
iptr_2_long:
.L36:
<entry-point>
- cast.64 %r56 <- (64) %arg1
+ ptrtu.64 %r56 <- (64) %arg1
ret.64 %r56
@@ -232,7 +232,7 @@ vptr_2_ulong:
iptr_2_ulong:
.L50:
<entry-point>
- cast.64 %r77 <- (64) %arg1
+ ptrtu.64 %r77 <- (64) %arg1
ret.64 %r77
diff --git a/validation/optim/kill-casts.c b/validation/optim/kill-casts.c
index c375f5fb..140b8d20 100644
--- a/validation/optim/kill-casts.c
+++ b/validation/optim/kill-casts.c
@@ -21,4 +21,5 @@ void foo(struct s *x)
* check-output-excludes: cast\\.
* check-output-excludes: fcvt[us]\\.
* check-output-excludes: utptr\\.
+ * check-output-excludes: ptrtu\\.
*/