Re: sparse-llvm incorrect definition of local variables

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi Luc,

On 9 March 2017 at 14:35, Luc Van Oostenryck
<luc.vanoostenryck@xxxxxxxxx> wrote:
> On Thu, Mar 09, 2017 at 01:50:16AM +0000, Dibyendu Majumdar wrote:
>>
>> I think by combining the symbol's identifier and address a unique
>> reference can be created - thus whenever we encounter a symbol that is
>> not extern or toplevel we should create a local object using the
>> symbol's name + address as the LLVM identifier.
>
> That's more or less the idea, of course.
> And you need to consider all objects that you don't need to
> allocate because they are always in a (pseudo-) register.
>

This is my initial attempt at a fix. In the function pseudo_to_value()
I modified the handling of PSEUDO_SYM. Note that I needed to add a new
field 'priv' in the symbol structure (type void *) to hold the
allocated value - there is an 'aux' field already for the backend to
use but this is already used, so I wasn't sure whether there would be
a conflict if I tried to reuse that field.

 case PSEUDO_SYM: {
  struct symbol *sym = pseudo->sym;
  struct expression *expr;
  assert(sym->bb_target == NULL);
  expr = sym->initializer;
  if (expr) {
    ...
  } else {
   const char *name = show_ident(sym->ident);
   LLVMTypeRef type = symbol_type(fn->module, sym);
   if (LLVMGetTypeKind(type) == LLVMFunctionTypeKind) {
    result = LLVMGetNamedFunction(fn->module, name);
    if (!result)
     result = LLVMAddFunction(fn->module, name, type);
   } else {
    char localname[256] = { 0 };
    if (is_extern(sym) || is_toplevel(sym)) {
     result = LLVMGetNamedGlobal(fn->module, name);
     if (!result)
      result = LLVMAddGlobal(fn->module, type, name);
    }
    else {
     result = (LLVMValueRef)sym->priv;
     if (!result) {
      /* insert alloca into entry block */
      /* LLVM requires allocas to be at the start */
      LLVMBasicBlockRef entrybbr = LLVMGetEntryBasicBlock(fn->fn);
      /* Use temporary Builder as we don't want to mess the function builder */
      LLVMBuilderRef tmp_builder = LLVMCreateBuilder();
      LLVMValueRef firstins = LLVMGetFirstInstruction(entrybbr);
      if (firstins)
       LLVMPositionBuilderBefore(tmp_builder, firstins);
      else
       LLVMPositionBuilderAtEnd(tmp_builder, entrybbr);
      /* Since multiple locals may have same name but in different scopes we
         append the symbol's address to make each variable unique */
      snprintf(localname, sizeof localname, "%s_%p", name, sym);
      result = LLVMBuildAlloca(tmp_builder, type, localname);
      LLVMDisposeBuilder(tmp_builder);
      /* Store the alloca instruction for references to the value later on.
         TODO - should we convert this to pointer here? */
      sym->priv = result;
     }
    }
   }
  }
  break;
 }

Of course I hit the next issue - which is that when calling functions,
array parameters need to degenerate to pointers - I haven't resolved
this yet. Perhaps, the cached value should be converted to a pointer
immediately so that any references see the pointer rather than the
array, or there needs to be a conversion when an array is passed to a
function.

Anyway to workaround this issue. I added a cast to the simple test program:

extern void init(int *v);
int main(const char *argv[]) {

 int n = 0;
 {
  int x[5];
  init((int *)x);
  n += x[0];
 }
 {
  int x[6];
  init((int *)x);
  n += x[0];
 }
 return n;
}

With that the LLVM IR I get looks like this:

define i32 @main(i8**) {
L0:
  %x_0000020C5D05B2E8 = alloca [6 x i32]
  %x_0000020C5D05AF68 = alloca [5 x i32]
  %R2 = bitcast [5 x i32]* %x_0000020C5D05AF68 to i32*
  call void @init(i32* %R2)
  %1 = bitcast [5 x i32]* %x_0000020C5D05AF68 to i32*
  %2 = bitcast i32* %1 to i8*
  %3 = getelementptr inbounds i8, i8* %2, i64 0
  %4 = bitcast i8* %3 to i32*
  %load_target = load i32, i32* %4
  %R9 = bitcast [6 x i32]* %x_0000020C5D05B2E8 to i32*
  call void @init(i32* %R9)
  %5 = bitcast [6 x i32]* %x_0000020C5D05B2E8 to i32*
  %6 = bitcast i32* %5 to i8*
  %7 = getelementptr inbounds i8, i8* %6, i64 0
  %8 = bitcast i8* %7 to i32*
  %load_target1 = load i32, i32* %8
  %R13 = add i32 %load_target, %load_target1
  ret i32 %R13
}
declare void @init(i32*)
--
To unsubscribe from this list: send the line "unsubscribe linux-sparse" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html



[Index of Archives]     [Newbies FAQ]     [LKML]     [IETF Annouce]     [DCCP]     [Netdev]     [Networking]     [Security]     [Bugtraq]     [Yosemite]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux SCSI]     [Trinity Fuzzer Tool]

  Powered by Linux