LLVM converts integer types to floats
Hey!
I'm making a compiler which will use LLVM as its backend. But while I was doing some tests, I saw that LLVM, for some reason, was transforming any integer types (i8, i16, i32 or i64) to floats (more precisely, ppc_fp128). But some other types like double work and are not converted to floats (since doubles can hold decimals already).
What I don't understand is that I'm not using any decimal values, and it is still converting them into floats, which actually breaks my code.
Here is a sample demo which does this behavior:
unsafe
{
LLVMModuleRef module = LLVM.ModuleCreateWithName((sbyte*)0);
LLVMBuilderRef builder = LLVM.CreateBuilder();
const string targetStr = "x86_64-unknown-none";
LLVM.InitializeX86TargetInfo();
LLVM.InitializeX86Target();
LLVM.InitializeX86TargetMC();
LLVM.InitializeX86AsmParser();
LLVM.InitializeX86AsmPrinter();
module.Target = targetStr;
var target = LLVMTargetRef.GetTargetFromTriple(targetStr);
var machine = target.CreateTargetMachine(targetStr, "generic", "", LLVMCodeGenOptLevel.LLVMCodeGenLevelNone,
LLVMRelocMode.LLVMRelocStatic, LLVMCodeModel.LLVMCodeModelKernel);
LLVM.SetModuleDataLayout(module, machine.CreateTargetDataLayout());
var function = module.AddFunction("main", LLVM.FunctionType(LLVM.VoidType(), null, 0, 0));
var stack = new Stack<LLVMValueRef>();
LLVM.SetLinkage(function, LLVMLinkage.LLVMExternalLinkage);
builder.PositionAtEnd(function.AppendBasicBlock("entry"));
// Simulating what the stack would look like before Add
stack.Push(LLVM.ConstReal(LLVM.Int32Type(), 8));
stack.Push(LLVM.ConstReal(LLVM.Int32Type(), 4));
var value2 = stack.Pop();
var value1 = stack.Pop();
stack.Push(builder.BuildAdd(value1, value2));
fixed (LLVMOpaqueType** ptr = new[] { LLVM.Int32Type() })
{
var tmp = module.AddFunction("tmp", LLVM.FunctionType(LLVM.VoidType(), ptr, 1, 0));
LLVM.SetLinkage(tmp, LLVMLinkage.LLVMExternalLinkage);
builder.BuildCall(tmp, new[] { stack.Pop() /* This should be the result of the previous Add instruction */ });
}
builder.BuildRetVoid();
LLVM.DumpModule(module);
}
Here is the LLVM IR output:
target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-unknown-none"
define void @main() {
entry:
call void @tmp(ppc_fp128 add (ppc_fp128 0xM40200000000000000000000000000000, ppc_fp128 0xM40100000000000000000000000000000))
ret void
}
declare void @tmp(i32 %0)
I'm not quite sure if this is a bug, or if I'm using LLVM(Sharp) wrong here. Any help would be greatly appreciated!
Could you clarify which version of LLVMSharp you're using?
For reference, this is incorrect usage and likely and I'm actually surprised its producing IR at all:
-
LLVMConstRealjust callsConstantFP::get(RealTy, N): https://llvm.org/doxygen/IR_2Core_8cpp_source.html#l01396 - This in turn ends up calling
FV.convert(Ty->getScalarType()->getFltSemantics(), APFloat::rmNearestTiesToEven, &ignored): https://llvm.org/doxygen/Constants_8cpp_source.html#l00926 -
getFltSemanticsswitches on the type id and should be raisingllvm_unreachable("Invalid floating type"): https://llvm.org/doxygen/Type_8cpp_source.html#l00067
LLVMSharp is ultimately fairly simple bindings over LLVM. As such, it is very lowlevel and only really has the safety that libLLVM has built into itself, but should in general work exactly like it does in C.
I'd like to eventually build a higher level safe wrapper on top (much like I did for ClangSharp) and there is some semblance on the start of that with things like: https://github.com/dotnet/LLVMSharp/blob/main/sources/LLVMSharp/LLVMContext.cs, but its not nearly there or close to complete yet.
Could you clarify which version of LLVMSharp you're using?
I'm using LLVMSharp 14.0.0-beta1 from NuGet.
For reference, this is incorrect usage and likely and I'm actually surprised its producing IR at all:
I'm fairly new to LLVM in general, so I just guessed how to use it. And documentation doesn't really help in my case, as I'm not actually making an AST or anything, I'm transforming the bytecode to LLVM IR.
So I guess it's not how you create constant values. So yeah, it doesn't generate any error or anything. For reference (which may or may not help), here is what I get when running llc --version, I get this on the first line:
Ubuntu LLVM version 14.0.0
Thanks! That all lines up then. I'm unsure why its not erroring, as it really should be.
I'll leave this issue open to track adding some diagnostics on the LLVMSharp side to help catch some of these issues. The raw LLVM.RealConst wouldn't expose them, but I can expose it via LLVMValueRef.CreateConstReal which is a "safer" (but still lowlevel) wrapper over the raw bindings.