Mapping InlineAsm parameters to ConstraintInfoVector elements

Hi all,

I'm trying to figure out which parameters of a given InlineAsm instruction
are its inputs, and which are the outputs (rationale: make sure MSan
doesn't check the output parameters of an asm() statement).

As far as I understand, this information is only available through the
ConstraintInfoVector for the InlineAsm. However there's no exact match
between the constraints and the InlineAsm params. In addition to clobber
constraints, which should be safe to ignore, there can be multiple
occurrences of a single parameter having different constraints. Also, for
InlineAsm instructions returning non-void values there's one additional
constraint, but it's unclear whether it always goes first.

My current implementation is quite ad-hoc, so I'm wondering if there's any
code that already does what I'm trying to achieve.

Thanks in advance,
Alexander

Could you provide an example where MSan checks an output parameter?

Sorry, I’ve stated the problem incorrectly.
Turns out that I’m seeing false positives exactly because MSan fails to see that the inline assembly routine initializes its outputs.
E.g. for functions like __test_and_set_bit() in the kernel, there’s a local variable holding the return value:

static [__always_inline](https://elixir.bootlin.com/linux/latest/ident/__always_inline) bool [__test_and_set_bit](https://elixir.bootlin.com/linux/latest/ident/__test_and_set_bit)(long [nr](https://elixir.bootlin.com/linux/latest/ident/nr), [volatile](https://elixir.bootlin.com/linux/latest/ident/volatile) unsigned long *addr)
{
	bool oldbit;

	[asm](https://elixir.bootlin.com/linux/latest/ident/asm)("bts %2,%1"
	    [CC_SET](https://elixir.bootlin.com/linux/latest/ident/CC_SET)(c)
	    : [CC_OUT](https://elixir.bootlin.com/linux/latest/ident/CC_OUT)(c) (oldbit), [ADDR](https://elixir.bootlin.com/linux/latest/ident/ADDR)
	    : "Ir" ([nr](https://elixir.bootlin.com/linux/latest/ident/nr)));
	return oldbit;
}

, which the tool treats as uninitialized, unless we explicitly set it to false before calling asm().

To close the loop, mapping inputs/outputs to constraints isn't
actually that complicated.

Constraints in ConstraintInfoVector are grouped by type; the first nO
constraints are outputs, they're followed by nI inputs and nC
clobbers. The type is a member of InlineAsm::ConstraintInfo.
A CallInst calling an InlineAsm has an optional return value, which is
either a scalar, or a structure containing nV outputs returnable by
value.
The remaining nO-nV first operands of that CallInst are its outputs
returned by pointer. Other nI operands are the inputs.
The total number of InlineAsm operands is therefore nO-nV+nI+1 (the
last one is the InlineAsm instance).