The next long C program generates a simple LLVM module containing a function that simply calls llvm.x86.sse41.round.ps . It emits a bitcode file, and then runs the code generated by LLVM. My question is how to find out what are the three-way tags and instruction extensions, such as the SSE or AVX of the host machine, and how can I add this information to the LLVM module or how can I otherwise report this to the LLVM execution engine. That's what I'm doing:
$ cat ctest/avx-instruction-selection.c #include <llvm-c/Core.h> #include <llvm-c/Target.h> #include <llvm-c/ExecutionEngine.h> #include <llvm-c/BitWriter.h> #include <llvm-c/Transforms/Scalar.h> #include <stdlib.h> #include <stdio.h> #include <string.h> #if 1 const int vectorSize = 4; const char* roundName = "llvm.x86.sse41.round.ps"; #else const int vectorSize = 8; const char* roundName = "llvm.x86.avx.round.ps.256"; #endif int main () { LLVMModuleRef module; LLVMExecutionEngineRef execEngine; LLVMTargetDataRef targetData; LLVMTypeRef floatType, vectorType, ptrType, voidType, funcType, roundType, int32Type; LLVMValueRef func, roundFunc; LLVMValueRef param, loaded, const1, callRound; LLVMBuilderRef builder; LLVMBasicBlockRef block; const int false = 0; LLVMInitializeX86TargetInfo(); LLVMInitializeX86Target(); LLVMInitializeX86TargetMC(); module = LLVMModuleCreateWithName("_module"); LLVMSetTarget(module, "x86_64-unknown-linux-gnu"); floatType = LLVMFloatType(); vectorType = LLVMVectorType(floatType, vectorSize); ptrType = LLVMPointerType(vectorType, 0); voidType = LLVMVoidType(); LLVMTypeRef roundParams[] = { ptrType }; roundType = LLVMFunctionType(voidType, roundParams, 1, false); func = LLVMAddFunction(module, "round", roundType); LLVMSetLinkage(func, LLVMExternalLinkage); builder = LLVMCreateBuilder(); block = LLVMAppendBasicBlock(func, "_L1"); LLVMPositionBuilderAtEnd(builder, block); param = LLVMGetParam(func, 0); loaded = LLVMBuildLoad(builder, param, ""); int32Type = LLVMIntType(32); LLVMTypeRef funcParams[] = { vectorType, int32Type } ; funcType = LLVMFunctionType(vectorType, funcParams, 2, false); roundFunc = LLVMAddFunction(module, roundName, funcType); LLVMSetLinkage(roundFunc, LLVMExternalLinkage); const1 = LLVMConstInt(int32Type, 1, false); LLVMValueRef callParams [] = { loaded, const1 } ; callRound = LLVMBuildCall(builder, roundFunc, callParams, 2, ""); LLVMSetInstructionCallConv(callRound, 0); LLVMAddInstrAttribute(callRound, 0, 0); LLVMBuildStore(builder, callRound, param); LLVMBuildRetVoid(builder); LLVMWriteBitcodeToFile(module, "round-avx.bc"); char *errorMsg; LLVMCreateExecutionEngineForModule(&execEngine, module, &errorMsg); targetData = LLVMGetExecutionEngineTargetData(execEngine); size_t vectorSize0 = LLVMStoreSizeOfType(targetData, vectorType); size_t vectorAlign = LLVMABIAlignmentOfType(targetData, vectorType); float vector[vectorSize]; printf("%lx, size %lx, align %lx\n", (size_t)vector, vectorSize0, vectorAlign); LLVMGenericValueRef genericVector = LLVMCreateGenericValueOfPointer(vector); LLVMGenericValueRef runParams[] = { genericVector } ; LLVMRunFunction(execEngine, func, 1, runParams); return 0; } $ gcc -Wall -o ctest/avx-instruction-selection ctest/avx-instruction-selection.c `/usr/lib/llvm-3.4/bin/llvm-config --cflags --ldflags` -lLLVM-3.4 $ ctest/avx-instruction-selection 7fff590431c0, size 10, align 10 $ ls round-avx.bc round-avx.bc $ llvm-dis -o - round-avx.bc ; ModuleID = 'round-avx.bc' target triple = "x86_64-unknown-linux-gnu" define void @round(<4 x float>*) { _L1: %1 = load <4 x float>* %0 %2 = call <4 x float> @llvm.x86.sse41.round.ps(<4 x float> %1, i32 1) store <4 x float> %2, <4 x float>* %0 ret void } ; Function Attrs: nounwind readnone declare <4 x float> @llvm.x86.sse41.round.ps(<4 x float>, i32) #0 attributes #0 = { nounwind readnone } $ gcc -Wall -o ctest/avx-instruction-selection ctest/avx-instruction-selection.c `/usr/lib/llvm-3.5/bin/llvm-config --cflags --ldflags` -lLLVM-3.5 $ ctest/avx-instruction-selection 7ffed6170350, size 10, align 10 LLVM ERROR: Cannot select: intrinsic %llvm.x86.sse41.round.ps $ gcc -Wall -o ctest/avx-instruction-selection ctest/avx-instruction-selection.c `/usr/lib/llvm-3.6/bin/llvm-config --cflags --ldflags` -lLLVM-3.6 $ ctest/avx-instruction-selection 7ffeae91eb40, size 10, align 10 LLVM ERROR: Target does not support MC emission! $ gcc -Wall -o ctest/avx-instruction-selection ctest/avx-instruction-selection.c `/usr/lib/llvm-3.7/bin/llvm-config --cflags --ldflags` -lLLVM-3.7 $ ctest/avx-instruction-selection 7fffb6464ea0, size 10, align 10 LLVM ERROR: Target does not support MC emission! $ gcc -Wall -o ctest/avx-instruction-selection ctest/avx-instruction-selection.c `/usr/lib/llvm-3.8/bin/llvm-config --cflags --ldflags` -lLLVM-3.8 $ ctest/avx-instruction-selection 7ffd5e233000, size 10, align 10 LLVM ERROR: Target does not support MC emission!
To summarize: LLVM-3.5 works with LLVM-3.4 in the example, the round.ps internal function cannot be found, and LLVM-3.6 and later talk about MC outliers that I donβt understand.
As I understand it, LLVM-3.5 does not find the built-in round.ps , and I assume that it cannot find it, because I did not talk about this existing SSE extension. When running llc I can add the -mattr=sse4.1 , but how can I tell the runtime engine about this?
Second question: how can I find out about available command extensions, such as SSE host machines, through the LLVM-C API? On x86, I can invoke the CPUID instruction, but is there a way that works the same on all platforms and can LLVM help detect extensions?
Third question: I programmed the target triple in C code. How to find the target triple of the host through the LLVM-C API?
Last question: How about this MC emission error?