Get constants of undefined types in IR

Hello all,

I would like to obtain a constant that is initialized with a value of type cpu_set_t, a type which is defined by Pthreads. The problem is that a variable of this type cannot be cast to an int value, even in C source code. I tried get methods from Constant or ConstantInt classes, but with no result.

How can I obtain such constant object in IR?

Thank you,

Iulia

Hi Iulia,

I would like to obtain a constant that is initialized with a value of type cpu_set_t, a type which is defined by Pthreads. The problem is that a variable of this type cannot be cast to an int value, even in C source code. I tried get methods from Constant or ConstantInt classes, but with no result.

cpu_set_t appears to be a Linux-specific concept, which actually makes
this slightly easier because it would otherwise be highly platform
specific. This version looks reasonable:
https://android.googlesource.com/platform/bionic/+/f664034/libc/include/sched.h.
It's not 100% canonical since it's outside the kernel, but has the
advantage that all he details are in a single file.

That file tells you a couple of things:

1. The underlying type is a struct containing an array of "unsigned
long" sufficient for 32 or 1024 CPUs depending on the host.
2. The __CPU_ELT and __CPU_MASK defines tell you how that array
corresponds to each particular numbered CPU (i.e. which element and
which bit of that element you'd toggle to set CPU N).

From that it's fairly easy to check that Clang turns the type into

something like "{ [16 x i64] }" and so that's what you'll have to
construct piece by piece.

1. Work out the contents of each integer element according to those
rules and get them with a ConstantInt::get.
2. Put them together into an array with ConstantArray::get
3. Put that array into a struct with ConstantStruct::get.

Cheers.

Tim.

Adding llvm-dev back.

Thank very much you for your answer. Following the indications in your mail, I obtained one of the 16th elements as below:

static cpu_set_t getCpuAffinityElement(cpu_set_t affinity, int index) {
cpu_set_t mask;
CPU_ZERO(&mask);
for(int i = index * sizeof(unsigned long); i < (index + 1) * sizeof(unsigned long); i++) {
CPU_SET(i,&mask);
}
CPU_AND(&affinity, &affinity, &mask);
return affinity;
}

That looks like a weird function, but it’s just within the realms of plausible so I’ll assume you know what you’re doing.

The problem is that the element is of type cpu_set_t and cannot be converted to unsigned long. So, when I try to get the ConstantInt object like below, I get an error saying that I cannot pass a cpu_set_t parameter as second parameter of get method.

ConstantInt * elem = ConstantInt::get(Type::getInt64Ty(I.getContext()),affinityElement,false);

To use a real cpu_set_t from the host as part of a. ConstantInt like that you’ll have to look at its actual definition and access something like affinityElement.__bits[0]. The exact internals may vary with the header you’re using, but you’re fundamentally trying to do something ABI specific so you will have to get your hands dirty.

What I need is to insert in IR a call that has a cpu_set_t parameter, and the parameter is already set (so I don’t need to construct it).

An alternative might be to pass a pointer to the cpu_set_t you created above into the Module somehow (a global might work). It would sidestep the tricky annoying API for Constants in LLVM, and possibly even be a buffer against the structure changing in future.

Cheers.

Tim.

Hi Tim,

My mistake not including the llvm-dev, excuse me. affinityElement.__bits[0] worked fine for me, thank you. I am new in using the API for Constants and I am facing the error “incomplete type is not allowed” on the last last of below code:

Type * ET = IntegerType::getInt64Ty(I.getContext());
unsigned long size = cpuAffinityVector.size();
ArrayType * AT = ArrayType::get(ET,size);

Internet gives different solutions for this error but none of them was appropriate for this case.

Could you please help?

Regards,
Iulia

Adding llvm-dev back.

Thank very much you for your answer. Following the indications in your mail, I obtained one of the 16th elements as below:

static cpu_set_t getCpuAffinityElement(cpu_set_t affinity, int index) {
cpu_set_t mask;
CPU_ZERO(&mask);
for(int i = index * sizeof(unsigned long); i < (index + 1) * sizeof(unsigned long); i++) {
CPU_SET(i,&mask);
}
CPU_AND(&affinity, &affinity, &mask);
return affinity;
}

That looks like a weird function, but it’s just within the realms of plausible so I’ll assume you know what you’re doing.

The problem is that the element is of type cpu_set_t and cannot be converted to unsigned long. So, when I try to get the ConstantInt object like below, I get an error saying that I cannot pass a cpu_set_t parameter as second parameter of get method.

ConstantInt * elem = ConstantInt::get(Type::getInt64Ty(I.getContext()),affinityElement,false);

To use a real cpu_set_t from the host as part of a. ConstantInt like that you’ll have to look at its actual definition and access something like affinityElement.__bits[0]. The exact internals may vary with the header you’re using, but you’re fundamentally trying to do something ABI specific so you will have to get your hands dirty.

What I need is to insert in IR a call that has a cpu_set_t parameter, and the parameter is already set (so I don’t need to construct it).

An alternative might be to pass a pointer to the cpu_set_t you created above into the Module somehow (a global might work). It would sidestep the tricky annoying API for Constants in LLVM, and possibly even be a buffer against the structure changing in future.

Cheers.

Tim.

Hi Iulia,

ArrayType * AT = ArrayType::get(ET,size);

Internet gives different solutions for this error but none of them was appropriate for this case.
Could you please help?

I take it that's a Clang error when compiling the code? I'm not
entirely sure, but it's possible you don't have a full definition for
llvm::ArrayType. It's not in the same header as IntegerType, so try
#including DerivedTypes.h.

Otherwise, does it give any indication about which type is incomplete?

Cheers.

Tim.

Hi Tim,

Thank you for the answer. I found another solution so I didn’t need to use ArrayType for what I intended to do. I did include the DerivedTypes.h from the first place, but the problem was still there and there was no indication about which type is incomplete (I assume ArrayType).

Regards,
Iulia

Hi Iulia,

ArrayType * AT = ArrayType::get(ET,size);

Internet gives different solutions for this error but none of them was appropriate for this case.
Could you please help?

I take it that’s a Clang error when compiling the code? I’m not
entirely sure, but it’s possible you don’t have a full definition for
llvm::ArrayType. It’s not in the same header as IntegerType, so try
#including DerivedTypes.h.

Otherwise, does it give any indication about which type is incomplete?

Cheers.

Tim.