diff mbox

llvm: fix output_op_[ptr]cast()

Message ID 20170303052459.2351-1-luc.vanoostenryck@gmail.com (mailing list archive)
State Superseded, archived
Headers show

Commit Message

Luc Van Oostenryck March 3, 2017, 5:24 a.m. UTC
This should fox the problems of mixed types in casts.
Without much testing but should be essentialy OK.

CC: Dibyendu Majumdar <mobile@majumdar.org.uk>
---
 sparse-llvm.c | 40 +++++++++++++++++++++++++++++++++++-----
 1 file changed, 35 insertions(+), 5 deletions(-)

Comments

Dibyendu Majumdar March 3, 2017, 7:37 a.m. UTC | #1
Hi Luc,

On 3 March 2017 at 05:24, Luc Van Oostenryck
<luc.vanoostenryck@gmail.com> wrote:
> This should fox the problems of mixed types in casts.
> Without much testing but should be essentialy OK.
>
> CC: Dibyendu Majumdar <mobile@majumdar.org.uk>
> ---
>  sparse-llvm.c | 40 +++++++++++++++++++++++++++++++++++-----
>  1 file changed, 35 insertions(+), 5 deletions(-)
>
> diff --git a/sparse-llvm.c b/sparse-llvm.c
> index edd0615ec..92ad26845 100644
> --- a/sparse-llvm.c
> +++ b/sparse-llvm.c
> @@ -763,6 +763,8 @@ static void output_op_phi(struct function *fn, struct instruction *insn)
>  static void output_op_ptrcast(struct function *fn, struct instruction *insn)
>  {
>         LLVMValueRef src, target;
> +       LLVMTypeRef dtype;
> +       LLVMOpcode op;
>         char target_name[64];
>
>         src = insn->src->priv;
> @@ -773,15 +775,31 @@ static void output_op_ptrcast(struct function *fn, struct instruction *insn)
>
>         assert(!symbol_is_fp_type(insn->type));
>
> -       target = LLVMBuildBitCast(fn->builder, src, insn_symbol_type(fn->module, insn), target_name);
> +       dtype = insn_symbol_type(fn->module, insn);
> +       switch (LLVMGetTypeKind(LLVMTypeOf(src))) {
> +       case LLVMPointerTypeKind:
> +               op = LLVMBitCast;
> +               break;
> +       case LLVMIntegerTypeKind:
> +               op = LLVMIntToPtr;
> +               break;
> +       default:
> +               assert(0);
> +       }
>
> +       target = LLVMBuildCast(fn->builder, op, src, dtype, target_name);
>         insn->target->priv = target;
>  }
>
>  static void output_op_cast(struct function *fn, struct instruction *insn, LLVMOpcode op)
>  {
>         LLVMValueRef src, target;
> +       LLVMTypeRef dtype;
>         char target_name[64];
> +       unsigned int width;
> +
> +       if (is_ptr_type(insn->type))
> +               return output_op_ptrcast(fn, insn);
>
>         src = insn->src->priv;
>         if (!src)
> @@ -791,11 +809,23 @@ static void output_op_cast(struct function *fn, struct instruction *insn, LLVMOp
>
>         assert(!symbol_is_fp_type(insn->type));
>
> -       if (insn->size < LLVMGetIntTypeWidth(LLVMTypeOf(src)))
> -               target = LLVMBuildTrunc(fn->builder, src, insn_symbol_type(fn->module, insn), target_name);
> -       else
> -               target = LLVMBuildCast(fn->builder, op, src, insn_symbol_type(fn->module, insn), target_name);
> +       dtype = insn_symbol_type(fn->module, insn);
> +       switch (LLVMGetTypeKind(LLVMTypeOf(src))) {
> +       case LLVMPointerTypeKind:
> +               op = LLVMPtrToInt;
> +               break;
> +       case LLVMIntegerTypeKind:
> +               width = LLVMGetIntTypeWidth(LLVMTypeOf(src));
> +               if (insn->size < width)
> +                       op = LLVMTrunc;
> +               else if (insn->size == width)
> +                       op = LLVMBitCast;
> +               break;
> +       default:
> +               assert(0);
> +       }
>
> +       target = LLVMBuildCast(fn->builder, op, src, dtype, target_name);
>         insn->target->priv = target;
>  }
>


This doesn't quite work. The problem is that in op_cast, the pointer
is being cast to int, but subsequent operations expect a pointer.

Regards
--
To unsubscribe from this list: send the line "unsubscribe linux-sparse" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Dibyendu Majumdar March 3, 2017, 6:06 p.m. UTC | #2
On 3 March 2017 at 07:37, Dibyendu Majumdar <mobile@majumdar.org.uk> wrote:
> On 3 March 2017 at 05:24, Luc Van Oostenryck
> <luc.vanoostenryck@gmail.com> wrote:
>> This should fox the problems of mixed types in casts.
>> Without much testing but should be essentialy OK.
>>
>> CC: Dibyendu Majumdar <mobile@majumdar.org.uk>
>> ---
>>  sparse-llvm.c | 40 +++++++++++++++++++++++++++++++++++-----
>>  1 file changed, 35 insertions(+), 5 deletions(-)
>>
>> diff --git a/sparse-llvm.c b/sparse-llvm.c
>> index edd0615ec..92ad26845 100644
>> --- a/sparse-llvm.c
>> +++ b/sparse-llvm.c
>> @@ -763,6 +763,8 @@ static void output_op_phi(struct function *fn, struct instruction *insn)
>>  static void output_op_ptrcast(struct function *fn, struct instruction *insn)
>>  {
>>         LLVMValueRef src, target;
>> +       LLVMTypeRef dtype;
>> +       LLVMOpcode op;
>>         char target_name[64];
>>
>>         src = insn->src->priv;
>> @@ -773,15 +775,31 @@ static void output_op_ptrcast(struct function *fn, struct instruction *insn)
>>
>>         assert(!symbol_is_fp_type(insn->type));
>>
>> -       target = LLVMBuildBitCast(fn->builder, src, insn_symbol_type(fn->module, insn), target_name);
>> +       dtype = insn_symbol_type(fn->module, insn);
>> +       switch (LLVMGetTypeKind(LLVMTypeOf(src))) {
>> +       case LLVMPointerTypeKind:
>> +               op = LLVMBitCast;
>> +               break;
>> +       case LLVMIntegerTypeKind:
>> +               op = LLVMIntToPtr;
>> +               break;
>> +       default:
>> +               assert(0);
>> +       }
>>
>> +       target = LLVMBuildCast(fn->builder, op, src, dtype, target_name);
>>         insn->target->priv = target;
>>  }
>>
>>  static void output_op_cast(struct function *fn, struct instruction *insn, LLVMOpcode op)
>>  {
>>         LLVMValueRef src, target;
>> +       LLVMTypeRef dtype;
>>         char target_name[64];
>> +       unsigned int width;
>> +
>> +       if (is_ptr_type(insn->type))
>> +               return output_op_ptrcast(fn, insn);
>>
>>         src = insn->src->priv;
>>         if (!src)
>> @@ -791,11 +809,23 @@ static void output_op_cast(struct function *fn, struct instruction *insn, LLVMOp
>>
>>         assert(!symbol_is_fp_type(insn->type));
>>
>> -       if (insn->size < LLVMGetIntTypeWidth(LLVMTypeOf(src)))
>> -               target = LLVMBuildTrunc(fn->builder, src, insn_symbol_type(fn->module, insn), target_name);
>> -       else
>> -               target = LLVMBuildCast(fn->builder, op, src, insn_symbol_type(fn->module, insn), target_name);
>> +       dtype = insn_symbol_type(fn->module, insn);
>> +       switch (LLVMGetTypeKind(LLVMTypeOf(src))) {
>> +       case LLVMPointerTypeKind:
>> +               op = LLVMPtrToInt;
>> +               break;
>> +       case LLVMIntegerTypeKind:
>> +               width = LLVMGetIntTypeWidth(LLVMTypeOf(src));
>> +               if (insn->size < width)
>> +                       op = LLVMTrunc;
>> +               else if (insn->size == width)
>> +                       op = LLVMBitCast;
>> +               break;
>> +       default:
>> +               assert(0);
>> +       }
>>
>> +       target = LLVMBuildCast(fn->builder, op, src, dtype, target_name);
>>         insn->target->priv = target;
>>  }
>>
>
>
> This doesn't quite work. The problem is that in op_cast, the pointer
> is being cast to int, but subsequent operations expect a pointer.
>

The problem occurs in this sequence:

       ptrcast.64  %r26 <- (64) %r20
       add.64      %r27 <- %r26, %r23
       cast.64     %r28 <- (64) %r27
       store.64    %r28 -> 16[%arg1]

The last cast finds that the instruction type in an integer and does a
cast to Integer, so that causes the store to fail as it expects a
pointer.

Question in my mind is what is the result type of an add operation
when one of the arguments is a pointer?

Regards
Dibyendu
--
To unsubscribe from this list: send the line "unsubscribe linux-sparse" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Dibyendu Majumdar March 3, 2017, 6:30 p.m. UTC | #3
Perhaps we need these fixes?

https://patchwork.kernel.org/patch/8175541/

On 3 March 2017 at 18:06, Dibyendu Majumdar <mobile@majumdar.org.uk> wrote:
> On 3 March 2017 at 07:37, Dibyendu Majumdar <mobile@majumdar.org.uk> wrote:
>> On 3 March 2017 at 05:24, Luc Van Oostenryck
>> <luc.vanoostenryck@gmail.com> wrote:
>>> This should fox the problems of mixed types in casts.
>>> Without much testing but should be essentialy OK.
>>>
>>> CC: Dibyendu Majumdar <mobile@majumdar.org.uk>
>>> ---
>>>  sparse-llvm.c | 40 +++++++++++++++++++++++++++++++++++-----
>>>  1 file changed, 35 insertions(+), 5 deletions(-)
>>>
>>> diff --git a/sparse-llvm.c b/sparse-llvm.c
>>> index edd0615ec..92ad26845 100644
>>> --- a/sparse-llvm.c
>>> +++ b/sparse-llvm.c
>>> @@ -763,6 +763,8 @@ static void output_op_phi(struct function *fn, struct instruction *insn)
>>>  static void output_op_ptrcast(struct function *fn, struct instruction *insn)
>>>  {
>>>         LLVMValueRef src, target;
>>> +       LLVMTypeRef dtype;
>>> +       LLVMOpcode op;
>>>         char target_name[64];
>>>
>>>         src = insn->src->priv;
>>> @@ -773,15 +775,31 @@ static void output_op_ptrcast(struct function *fn, struct instruction *insn)
>>>
>>>         assert(!symbol_is_fp_type(insn->type));
>>>
>>> -       target = LLVMBuildBitCast(fn->builder, src, insn_symbol_type(fn->module, insn), target_name);
>>> +       dtype = insn_symbol_type(fn->module, insn);
>>> +       switch (LLVMGetTypeKind(LLVMTypeOf(src))) {
>>> +       case LLVMPointerTypeKind:
>>> +               op = LLVMBitCast;
>>> +               break;
>>> +       case LLVMIntegerTypeKind:
>>> +               op = LLVMIntToPtr;
>>> +               break;
>>> +       default:
>>> +               assert(0);
>>> +       }
>>>
>>> +       target = LLVMBuildCast(fn->builder, op, src, dtype, target_name);
>>>         insn->target->priv = target;
>>>  }
>>>
>>>  static void output_op_cast(struct function *fn, struct instruction *insn, LLVMOpcode op)
>>>  {
>>>         LLVMValueRef src, target;
>>> +       LLVMTypeRef dtype;
>>>         char target_name[64];
>>> +       unsigned int width;
>>> +
>>> +       if (is_ptr_type(insn->type))
>>> +               return output_op_ptrcast(fn, insn);
>>>
>>>         src = insn->src->priv;
>>>         if (!src)
>>> @@ -791,11 +809,23 @@ static void output_op_cast(struct function *fn, struct instruction *insn, LLVMOp
>>>
>>>         assert(!symbol_is_fp_type(insn->type));
>>>
>>> -       if (insn->size < LLVMGetIntTypeWidth(LLVMTypeOf(src)))
>>> -               target = LLVMBuildTrunc(fn->builder, src, insn_symbol_type(fn->module, insn), target_name);
>>> -       else
>>> -               target = LLVMBuildCast(fn->builder, op, src, insn_symbol_type(fn->module, insn), target_name);
>>> +       dtype = insn_symbol_type(fn->module, insn);
>>> +       switch (LLVMGetTypeKind(LLVMTypeOf(src))) {
>>> +       case LLVMPointerTypeKind:
>>> +               op = LLVMPtrToInt;
>>> +               break;
>>> +       case LLVMIntegerTypeKind:
>>> +               width = LLVMGetIntTypeWidth(LLVMTypeOf(src));
>>> +               if (insn->size < width)
>>> +                       op = LLVMTrunc;
>>> +               else if (insn->size == width)
>>> +                       op = LLVMBitCast;
>>> +               break;
>>> +       default:
>>> +               assert(0);
>>> +       }
>>>
>>> +       target = LLVMBuildCast(fn->builder, op, src, dtype, target_name);
>>>         insn->target->priv = target;
>>>  }
>>>
>>
>>
>> This doesn't quite work. The problem is that in op_cast, the pointer
>> is being cast to int, but subsequent operations expect a pointer.
>>
>
> The problem occurs in this sequence:
>
>        ptrcast.64  %r26 <- (64) %r20
>        add.64      %r27 <- %r26, %r23
>        cast.64     %r28 <- (64) %r27
>        store.64    %r28 -> 16[%arg1]
>
> The last cast finds that the instruction type in an integer and does a
> cast to Integer, so that causes the store to fail as it expects a
> pointer.
>
> Question in my mind is what is the result type of an add operation
> when one of the arguments is a pointer?
>
> Regards
> Dibyendu
--
To unsubscribe from this list: send the line "unsubscribe linux-sparse" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Luc Van Oostenryck March 3, 2017, 7:50 p.m. UTC | #4
On Fri, Mar 3, 2017 at 7:06 PM, Dibyendu Majumdar
<mobile@majumdar.org.uk> wrote:
> The problem occurs in this sequence:
>
>        ptrcast.64  %r26 <- (64) %r20
>        add.64      %r27 <- %r26, %r23
>        cast.64     %r28 <- (64) %r27
>        store.64    %r28 -> 16[%arg1]
>
> The last cast finds that the instruction type in an integer and does a
> cast to Integer, so that causes the store to fail as it expects a
> pointer.

What is the corresponding C code?
With the patches I've posted, the three example you've given are handled
without error for me.

> Question in my mind is what is the result type of an add operation
> when one of the arguments is a pointer?

This should only occurs as some form of pointer arithmetic, so the result
should be some kind of pointer.

Luc
--
To unsubscribe from this list: send the line "unsubscribe linux-sparse" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Dibyendu Majumdar March 3, 2017, 7:54 p.m. UTC | #5
On 3 March 2017 at 19:50, Luc Van Oostenryck
<luc.vanoostenryck@gmail.com> wrote:
> On Fri, Mar 3, 2017 at 7:06 PM, Dibyendu Majumdar
> <mobile@majumdar.org.uk> wrote:
>> The problem occurs in this sequence:
>>
>>        ptrcast.64  %r26 <- (64) %r20
>>        add.64      %r27 <- %r26, %r23
>>        cast.64     %r28 <- (64) %r27
>>        store.64    %r28 -> 16[%arg1]
>>
>> The last cast finds that the instruction type in an integer and does a
>> cast to Integer, so that causes the store to fail as it expects a
>> pointer.
>
> What is the corresponding C code?
> With the patches I've posted, the three example you've given are handled
> without error for me.
>

C code below, it is the last += that is failing.

typedef unsigned long long size_t;
struct buffer_type_st {
 struct buffer_type_st    *next_buffer;
 char           *buffer;
};
typedef struct buffer_type_st buffer_type_t;
struct link_st {
 struct link_st           *next;
};
typedef struct link_st link_t;
struct allocator_st {
 buffer_type_t    *buffer_list;
 link_t           *free_list;
 char           *next_avail;
 char           *last;
 size_t          size;
 size_t          n;
};
typedef struct allocator_st allocator;
extern void *
alloc_node(allocator * a);
extern void
grow_allocator(allocator * a);
void *
alloc_node(allocator * a)
{
 link_t           *tmp;
 tmp = a->free_list;
 if (a->free_list) {
  a->free_list = (link_t *) (a->free_list->next);
  return (void *) tmp;
 } else {
  if (a->next_avail == a->last) {
   grow_allocator(a);
  }
  {
   void           *tmp;
   tmp = (void *) a->next_avail;
   a->next_avail += a->size;
   return tmp;
  }
 }
}
--
To unsubscribe from this list: send the line "unsubscribe linux-sparse" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Luc Van Oostenryck March 3, 2017, 7:55 p.m. UTC | #6
On Fri, Mar 3, 2017 at 7:30 PM, Dibyendu Majumdar
<mobile@majumdar.org.uk> wrote:
> Perhaps we need these fixes?
>
> https://patchwork.kernel.org/patch/8175541/

I very much doubt it would make any difference.
This patch is part of a serie enforcing correct handling
of constant expression *as defined by the standard*.
It won't change the type of an expression or something like this.

Luc
--
To unsubscribe from this list: send the line "unsubscribe linux-sparse" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Christopher Li March 6, 2017, 1:56 a.m. UTC | #7
On Sat, Mar 4, 2017 at 3:55 AM, Luc Van Oostenryck
<luc.vanoostenryck@gmail.com> wrote:
> On Fri, Mar 3, 2017 at 7:30 PM, Dibyendu Majumdar
> <mobile@majumdar.org.uk> wrote:
>> Perhaps we need these fixes?
>>
>> https://patchwork.kernel.org/patch/8175541/
>
> I very much doubt it would make any difference.
> This patch is part of a serie enforcing correct handling
> of constant expression *as defined by the standard*.
> It won't change the type of an expression or something like this.

I second that. Those patch series give warnings but it should not
affect the IR.

Chris
--
To unsubscribe from this list: send the line "unsubscribe linux-sparse" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/sparse-llvm.c b/sparse-llvm.c
index edd0615ec..92ad26845 100644
--- a/sparse-llvm.c
+++ b/sparse-llvm.c
@@ -763,6 +763,8 @@  static void output_op_phi(struct function *fn, struct instruction *insn)
 static void output_op_ptrcast(struct function *fn, struct instruction *insn)
 {
 	LLVMValueRef src, target;
+	LLVMTypeRef dtype;
+	LLVMOpcode op;
 	char target_name[64];
 
 	src = insn->src->priv;
@@ -773,15 +775,31 @@  static void output_op_ptrcast(struct function *fn, struct instruction *insn)
 
 	assert(!symbol_is_fp_type(insn->type));
 
-	target = LLVMBuildBitCast(fn->builder, src, insn_symbol_type(fn->module, insn), target_name);
+	dtype = insn_symbol_type(fn->module, insn);
+	switch (LLVMGetTypeKind(LLVMTypeOf(src))) {
+	case LLVMPointerTypeKind:
+		op = LLVMBitCast;
+		break;
+	case LLVMIntegerTypeKind:
+		op = LLVMIntToPtr;
+		break;
+	default:
+		assert(0);
+	}
 
+	target = LLVMBuildCast(fn->builder, op, src, dtype, target_name);
 	insn->target->priv = target;
 }
 
 static void output_op_cast(struct function *fn, struct instruction *insn, LLVMOpcode op)
 {
 	LLVMValueRef src, target;
+	LLVMTypeRef dtype;
 	char target_name[64];
+	unsigned int width;
+
+	if (is_ptr_type(insn->type))
+		return output_op_ptrcast(fn, insn);
 
 	src = insn->src->priv;
 	if (!src)
@@ -791,11 +809,23 @@  static void output_op_cast(struct function *fn, struct instruction *insn, LLVMOp
 
 	assert(!symbol_is_fp_type(insn->type));
 
-	if (insn->size < LLVMGetIntTypeWidth(LLVMTypeOf(src)))
-		target = LLVMBuildTrunc(fn->builder, src, insn_symbol_type(fn->module, insn), target_name);
-	else
-		target = LLVMBuildCast(fn->builder, op, src, insn_symbol_type(fn->module, insn), target_name);
+	dtype = insn_symbol_type(fn->module, insn);
+	switch (LLVMGetTypeKind(LLVMTypeOf(src))) {
+	case LLVMPointerTypeKind:
+		op = LLVMPtrToInt;
+		break;
+	case LLVMIntegerTypeKind:
+		width = LLVMGetIntTypeWidth(LLVMTypeOf(src));
+		if (insn->size < width)
+			op = LLVMTrunc;
+		else if (insn->size == width)
+			op = LLVMBitCast;
+		break;
+	default:
+		assert(0);
+	}
 
+	target = LLVMBuildCast(fn->builder, op, src, dtype, target_name);
 	insn->target->priv = target;
 }