Call via a function pointer does not compile

I looked at the IR code generated by clang from some piece of C++ code and it creates a ptr variable on the stack to store the passed in function pointer and then calls via it. My code is doing the same thing, except that the function pointer is decided by an if-statement – which boils out to something created using CreatePHI() – and it does not compile…

	virtual Value *ifFunction(
		Function*const _pCurrent,
		Value *const _pTest,
		Function*const _pTrue,
		Function*const _pFalse,
		const std::vector<Value*>&_rArgs
	) const override
	{	getBuilder().SetInsertPoint(
			BasicBlock::Create(
				getContext(),
				"entry",
				_pCurrent
			)
		);
		const auto pTrueBB = BasicBlock::Create(
			getContext(),
			"true",
			_pCurrent
		);
		const auto pFalseBB = BasicBlock::Create(
			getContext(),
			"false",
			_pCurrent
		);
		const auto pAfterBB = BasicBlock::Create(
			getContext(),
			"after",
			_pCurrent
		);
		getBuilder().CreateCondBr(
			_pTest,
			pTrueBB,
			pFalseBB
		);
		getBuilder().SetInsertPoint(pTrueBB);
		getBuilder().CreateBr(pAfterBB);
		getBuilder().SetInsertPoint(pFalseBB);
		getBuilder().CreateBr(pAfterBB);
		const auto pFP = getBuilder().CreatePHI(_pTrue->getType(), 2);
		pFP->addIncoming(_pTrue, pTrueBB);
		pFP->addIncoming(_pFalse, pFalseBB);
		return getBuilder().CreateCall(
			pFP,
			ArrayRef(_rArgs)
		);
	}

Does one have to extract the name of the function first, and then use some function to get the function pointer by name?

Ok – here comes the version of the code which compiles:

	virtual Value *ifFunction(
		Function*const _pCurrent,
		Value *const _pTest,
		Function*const _pTrue,
		Function*const _pFalse,
		const std::vector<Value*>&_rArgs
	) const override
	{	getBuilder().SetInsertPoint(
			BasicBlock::Create(
				getContext(),
				"entry",
				_pCurrent
			)
		);
		const auto pTrueBB = BasicBlock::Create(
			getContext(),
			"true",
			_pCurrent
		);
		const auto pFalseBB = BasicBlock::Create(
			getContext(),
			"false",
			_pCurrent
		);
		const auto pAfterBB = BasicBlock::Create(
			getContext(),
			"after",
			_pCurrent
		);
		getBuilder().CreateCondBr(
			_pTest,
			pTrueBB,
			pFalseBB
		);
		getBuilder().SetInsertPoint(pTrueBB);
		getBuilder().CreateBr(pAfterBB);
		getBuilder().SetInsertPoint(pFalseBB);
		getBuilder().CreateBr(pAfterBB);
		const auto pFP = getBuilder().CreatePHI(_pTrue->getFunctionType(), 2);
		pFP->addIncoming(_pTrue, pTrueBB);
		pFP->addIncoming(_pFalse, pFalseBB);
		return getBuilder().CreateCall(
			_pTrue->getFunctionType(),
			pFP,
			ArrayRef(_rArgs)
		);
	}

getFunctionType gives you the actual function type, not a pointer to the function type. I would hope that there would be error messages given for this invalid IR construction that would point at this being the problem. It would be helpful in future for your reports to give the errors you get, not just that it doesn’t work, and expecting us to trawl through your code to find the bug without any hints from LLVM’s error messages.

1 Like

(Contrast with GlobalValue::getValueType() which doesn’t give you the pointer type; in fact Function::getFunctionType is just a wrapper around that, since functions are special types of global values in LLVM)

1 Like