Alias analysis API gives different results to opt

I’m trying to use the alias analysis API to test the types of cases LLVM can and can’t catch using the following code:

	TargetLibraryInfoImpl TLII = TargetLibraryInfoImpl(Triple("x86_64-pc-linux-gnu"));
	TargetLibraryInfo TLI = TargetLibraryInfo(TLII);
	AAResults analyser = AAResults(TLI);

    ...
	for (int i=0; i < function.pointers.size(); i++)	{
		Value *p = function.pointers[i];
		for (int j=i; j < function.pointers.size(); j++)	{
			Value *q = function.pointers[j];
			LocationSize p_size = LocationSize::precise(p->getType()->getPrimitiveSizeInBits());
			LocationSize q_size = LocationSize::precise(q->getType()->getPrimitiveSizeInBits());
			if (p == q) continue;
			alias_results.push_back(analyser.alias(p, p_size, q, q_size));
		}
	}

I’ve tried this as well as opt using -aa-eval on the following function:

int alias_test(int *a){
    return a[1];
}

opt will mark the pointers a and a[1] as no alias, which is correct. The API I’m using however marks these two pointers as may alias. What am I missing in my code to make the API behave the same way as in opt?

You haven’t given enough information to reproduce your issue, but most of the time, the answer to beginner questions about alias analysis is “you need to run mem2reg/sroa first”.

Let me know what other info you need and I’ll share it. But as for the optimisations, both opt and my program are working on the exact same IR (which has gone through mem2reg) and still gave different results, so the passes certainly aren’t the issue.

Oh, sorry, I misread your original message.

I think you might be missing a call to addAAResult() somewhere? An AAResults doesn’t actually do any alias analysis; it delegates to the alias analysis passes you specify.

addAAResult says it just registers a specific result, I’m not sure what this will change if I’m calling this after I’ve already made the alias query.

How can I specify AA passes for use in AAResults?

A “result” here refers to the result of running an alias analysis pass, not any specific AA query.

If you just want BasicAA, you should be able to do something like the following (taken from llvm/unittests/Transforms/Utils/BasicBlockUtilsTest.cpp):

  BasicAAResult BAA(DL, *F, TLI, AC, &DT);
  AA.addAAResult(BAA);

Other AA passes can be registered in a similar way.

Ahh I see. Which alias analysis implementation does -aa-eval in opt use? I know it’s not BasicAA but I’m unsure what it is exactly.

Assuming you’re on a recent LLVM version, it should end up calling PassBuilder::buildDefaultAAPipeline by default (llvm-project/PassBuilderPipelines.cpp at d86a206f06a51c12a9fcf2c20199f4e819751c0c · llvm/llvm-project · GitHub). Which is BasicAA plus some other more specialized passes.

This is really helpful, thanks!

Hey, so I’m trying to run these passes on a function but running into problems

I’m using the following code which compiles fine:

	AAManager AA;
	AA.registerFunctionAnalysis<BasicAA>();
	AA.registerFunctionAnalysis<ScopedNoAliasAA>();
	AA.registerFunctionAnalysis<TypeBasedAA>();
	AA.registerModuleAnalysis<GlobalsAA>();

	FunctionAnalysisManager FAM;
	AAResults analyser = AAResults(AA.run(*function, FAM));

But causes a segfault when AA.run tries to read FAM. I’ve tried initialising FAM with FAM = FunctionAnalysisManager() but this hasn’t helped, and it seems whenever this is used in LLVM code this is left uninitialised anyway. What am I doing wrong here?

I don’t think the “run()” API is meant to be used that way? AAManager is supposed to be used as part of the pass manager infrastructure; in that context, the pass manager itself would call run(), not your code.

Ah ok. So how am I meant to extract alias results out of a pass manager?

I’ve tried using the pass manager and can’t get the results to work. There are two methods for getting results I can figure out and one still marks everything as may alias, while the other marks everything as no alias.

Here’s the part of the code that’s the same for both:

	LoopAnalysisManager LAM;
	FunctionAnalysisManager FAM;
	CGSCCAnalysisManager CGAM;
	ModuleAnalysisManager MAM;
	PassBuilder PB;
	AAManager AA;
	AA.registerFunctionAnalysis<BasicAA>();
	AA.registerFunctionAnalysis<ScopedNoAliasAA>();
	AA.registerFunctionAnalysis<TypeBasedAA>();
	AA.registerModuleAnalysis<GlobalsAA>();

	FAM.registerPass([&] {return std::move(AA);});
	PB.registerModuleAnalyses(MAM);
	PB.registerCGSCCAnalyses(CGAM);
	PB.registerFunctionAnalyses(FAM);
	PB.registerLoopAnalyses(LAM);
	PB.crossRegisterProxies(LAM, FAM, CGAM, MAM);
	ModulePassManager MPM = PB.buildModuleOptimizationPipeline(OptimizationLevel::O3);
	MPM.run(*mod, MAM);

and from there I either use this which, when using the .alias method, yields may alias for everything:

	AAResults analyser = AA.run(*function.func, FAM);

or this which gives no alias instead:

	AAResults analyser = std::move(FAM.getResult<AAManager>(*function.func));

While again on the same program opt -aa-eval will give 10 may alias results and 1 no alias. I’ve looked at the code for opt and they seem to use the API in the same way. What am I doing wrong?

Ok, I’ve figured out that the cases where everything say may alias are due to a mistake on my part. If I just stick with the default alias pipeline by calling PB.registerFunctionAnalyses(FAM); and not registering my own AAManager first, it also says no alias on every case. So the problem must be with how I’m query these results, but I’m unsure what I could be doing wrong still.

Finally fixed this problem - my calls to p->getType()->getPrimitiveSizeInBits() were always returning 0, meaning everything was marked as no alias as it was assumed to have size 0. I needed DataLayout’s .getTypeSizeInBits(p->getType()->getContainedType(0))/8 instead.