[cfe-dev] Unexpected behaviour on transparent_union attribute

Stefan Kristiansson stefan.kristiansson at saunalahti.fi
Mon Jul 2 06:27:44 PDT 2012


Hi,

I'm working on a LLVM backend for OpenRISC and
noticed some odd behaviour when compiling busybox for uClibc
using Clang.

After digging in to the issue I found out that functions that
are declared with a transparent union argument got called
with the argument casted to the union instead of using the
calling convention of the first member of the union.

Let me show an example:

typedef union {
  int *a;
  char *b;
} ARG __attribute__ ((__transparent_union__));

void foo(ARG u);

void bar(int *a)
{
  foo(a);
}

Turns into:

%union.ARG = type { i32* }

define void @bar(i32* %a) nounwind {
entry:
  %a.addr = alloca i32*, align 4
  %u = alloca %union.ARG, align 4
  %agg.tmp = alloca %union.ARG, align 4
  %.compoundliteral = alloca %union.ARG, align 4
  store i32* %a, i32** %a.addr, align 4
  %a1 = bitcast %union.ARG* %.compoundliteral to i32**
  %0 = load i32** %a.addr, align 4
  store i32* %0, i32** %a1, align 4
  %1 = bitcast %union.ARG* %agg.tmp to i8*
  %2 = bitcast %union.ARG* %.compoundliteral to i8*
  call void @llvm.memcpy.p0i8.p0i8.i32(i8* %1, i8* %2, i32 4, i32 4, i1 false)
  call void @foo(%union.ARG* byval %agg.tmp)
  ret void
}

declare void @foo(%union.ARG* byval)

declare void @llvm.memcpy.p0i8.p0i8.i32(i8* nocapture, i8* nocapture, i32, i32, i1) nounwind

When I would have expected something like:

define void @bar(i32* %a) nounwind {
entry:
  %a.addr = alloca i32*, align 4
  %u = alloca i32*, align 4
  store i32* %a, i32** %a.addr, align 4
  %0 = load i32** %a.addr, align 4
  call void @foo(i32* %0)
  ret void
}

declare void @foo(i32*)

I've been able to "solve" the problem by inserting conversions of the
argument type in various places in CodeGen, by it's more of an ugly hack
than a real solution as it is now.
I've got a feeling that the record type (with the transparent union attribute)
should be kept intact as long as possible, so I believe the ideal solution would
be to go through all possible places right before CodeGen, but I'm too much of
a Clang novice to be able to pinpoint where and how (and if my belief is right),
so it's here that I'd like some advice on this issue.

Stefan



More information about the cfe-dev mailing list