package main

foreign import llvmc "LLVM-C.lib"

LLVMBool :: distinct int
LLVMMemoryBufferRef :: distinct rawptr
LLVMContextRef :: distinct rawptr
LLVMModuleRef :: distinct rawptr
LLVMTypeRef :: distinct rawptr
LLVMValueRef :: distinct rawptr
LLVMBasicBlockRef :: distinct rawptr
LLVMMetadataRef :: distinct rawptr
LLVMNamedMDNodeRef :: distinct rawptr
LLVMBuilderRef :: distinct rawptr
LLVMDIBuilderRef :: distinct rawptr
LLVMModuleProviderRef :: distinct rawptr
LLVMPassManagerRef :: distinct rawptr
LLVMUseRef :: distinct rawptr
LLVMAttributeRef :: distinct rawptr
LLVMDiagnosticInfoRef :: distinct rawptr
LLVMComdatRef :: distinct rawptr
LLVMJITEventListenerRef :: distinct rawptr
LLVMBinaryRef :: distinct rawptr

LLVMTypeKind :: enum {
    LLVMVoidTypeKind,
    LLVMHalfTypeKind,
    LLVMFloatTypeKind,
    LLVMDoubleTypeKind,
    LLVMX86_FP80TypeKind,
    LLVMFP128TypeKind,
    LLVMPPC_FP128TypeKind,
    LLVMLabelTypeKind,
    LLVMIntegerTypeKind,
    LLVMFunctionTypeKind,
    LLVMStructTypeKind,
    LLVMArrayTypeKind,
    LLVMPointerTypeKind,
    LLVMVectorTypeKind,
    LLVMMetadataTypeKind,
    LLVMX86_MMXTypeKind,
    LLVMTokenTypeKind,
    LLVMScalableVectorTypeKind,
    LLVMBFloatTypeKind,
    LLVMX86_AMXTypeKind,
    LLVMTargetExtTypeKind,
}

LLVMIntPredicate :: enum {
    LLVMIntEQ = 32,
    LLVMIntNE,
    LLVMIntUGT,
    LLVMIntUGE,
    LLVMIntULT,
    LLVMIntULE,
    LLVMIntSGT,
    LLVMIntSGE,
    LLVMIntSLT,
    LLVMIntSLE,
}

LLVMRealPredicate :: enum {
    LLVMRealPredicateFalse,
    LLVMRealOEQ,
    LLVMRealOGT,
    LLVMRealOGE,
    LLVMRealOLT,
    LLVMRealOLE,
    LLVMRealONE,
    LLVMRealORD,
    LLVMRealUNO,
    LLVMRealUEQ,
    LLVMRealUGT,
    LLVMRealUGE,
    LLVMRealULT,
    LLVMRealULE,
    LLVMRealUNE,
    LLVMRealPredicateTrue
};

@(default_calling_convention = "std")
foreign llvmc {
    LLVMContextCreate :: proc() -> LLVMContextRef ---
    LLVMModuleCreateWithName :: proc(name: cstring) -> LLVMModuleRef ---
    LLVMModuleCreateWithNameInContext :: proc(name: cstring, C: LLVMContextRef) -> LLVMModuleRef ---

    LLVMCreateBuilderInContext :: proc(C: LLVMContextRef) -> LLVMBuilderRef ---
    LLVMPositionBuilderAtEnd :: proc(Builder: LLVMBuilderRef, Block: LLVMBasicBlockRef) ---

    LLVMBuildPointerCast :: proc(Builder: LLVMBuilderRef, Val: LLVMValueRef, DestTy: LLVMTypeRef, Name: cstring) -> LLVMValueRef ---
    LLVMBuildGlobalString :: proc(Builder: LLVMBuilderRef, Str: cstring, Name: cstring) -> LLVMValueRef ---
    LLVMBuildGlobalStringPtr :: proc(Builder: LLVMBuilderRef, Str: cstring, Name: cstring) -> LLVMValueRef ---

    LLVMBuildCall2 :: proc(Builder: LLVMBuilderRef, Type: LLVMTypeRef, Fn: LLVMValueRef, Args: [^]LLVMValueRef, NumArgs: uint, Name: cstring) -> LLVMValueRef ---

    LLVMBuildRetVoid :: proc(Builder: LLVMBuilderRef) -> LLVMValueRef ---
    LLVMBuildRet :: proc(Builder: LLVMBuilderRef, V: LLVMValueRef) -> LLVMValueRef ---

    LLVMInt1TypeInContext :: proc(C: LLVMContextRef) -> LLVMTypeRef ---
    LLVMInt8TypeInContext :: proc(C: LLVMContextRef) -> LLVMTypeRef ---
    LLVMInt16TypeInContext :: proc(C: LLVMContextRef) -> LLVMTypeRef ---
    LLVMInt32TypeInContext :: proc(C: LLVMContextRef) -> LLVMTypeRef ---
    LLVMInt64TypeInContext :: proc(C: LLVMContextRef) -> LLVMTypeRef ---
    LLVMIntTypeInContext :: proc(C: LLVMContextRef, n: uint) -> LLVMTypeRef ---

    LLVMDoubleTypeInContext :: proc(C: LLVMContextRef) -> LLVMTypeRef ---
    LLVMFloatTypeInContext :: proc(C: LLVMContextRef) -> LLVMTypeRef ---

    LLVMVoidTypeInContext :: proc(C: LLVMContextRef) -> LLVMTypeRef ---

    LLVMGetTypeKind :: proc(Ty: LLVMTypeRef) -> LLVMTypeKind ---

    LLVMArrayType2 :: proc(ElementType: LLVMTypeRef, ElementCount: u64) -> LLVMTypeRef ---
    LLVMPointerType :: proc(ElementType: LLVMTypeRef, AddressSpace: uint) -> LLVMTypeRef ---

    LLVMConstInt :: proc(IntTy: LLVMTypeRef, N: u64, SignExtend: LLVMBool) -> LLVMValueRef ---
    LLVMConstReal :: proc(RealTy: LLVMTypeRef, N: f64) -> LLVMValueRef ---

    LLVMFunctionType :: proc(ReturnType: LLVMTypeRef, ParamTypes: [^]LLVMTypeRef, ParamCount: uint, IsVarArg: LLVMBool) -> LLVMTypeRef ---
    LLVMAddFunction :: proc(M: LLVMModuleRef, Name: cstring, FunctionType: LLVMTypeRef) -> LLVMValueRef ---

    LLVMAppendBasicBlockInContext :: proc(C: LLVMContextRef, Fn: LLVMValueRef, Name: cstring) -> LLVMBasicBlockRef ---
    LLVMCreateBasicBlockInContext :: proc(C: LLVMContextRef, Name: cstring) -> LLVMBasicBlockRef ---
    LLVMGetLastBasicBlock :: proc(Fn: LLVMValueRef) -> LLVMBasicBlockRef ---
    LLVMGetInsertBlock :: proc(Builder: LLVMBuilderRef) -> LLVMBasicBlockRef ---
    LLVMInsertExistingBasicBlockAfterInsertBlock :: proc(Builder: LLVMBuilderRef, Block: LLVMBasicBlockRef) ---
    LLVMAppendExistingBasicBlock :: proc(Fn: LLVMValueRef, Block: LLVMBasicBlockRef) ---

    LLVMPrintModuleToFile :: proc(M: LLVMModuleRef, Filename: cstring, ErrorMessage: ^cstring) -> LLVMBool ---

    LLVMGetValueName2 :: proc(V: LLVMValueRef, Length: ^u64) -> cstring ---

    LLVMBuildFAdd :: proc(Builder: LLVMBuilderRef, LHS: LLVMValueRef, RHS: LLVMValueRef, Name: cstring) -> LLVMValueRef ---
    LLVMBuildAdd :: proc(Builder: LLVMBuilderRef, LHS: LLVMValueRef, RHS: LLVMValueRef, Name: cstring) -> LLVMValueRef ---
    LLVMBuildFSub :: proc(Builder: LLVMBuilderRef, LHS: LLVMValueRef, RHS: LLVMValueRef, Name: cstring) -> LLVMValueRef ---
    LLVMBuildSub :: proc(Builder: LLVMBuilderRef, LHS: LLVMValueRef, RHS: LLVMValueRef, Name: cstring) -> LLVMValueRef ---
    LLVMBuildFMul :: proc(Builder: LLVMBuilderRef, LHS: LLVMValueRef, RHS: LLVMValueRef, Name: cstring) -> LLVMValueRef ---
    LLVMBuildMul :: proc(Builder: LLVMBuilderRef, LHS: LLVMValueRef, RHS: LLVMValueRef, Name: cstring) -> LLVMValueRef ---
    LLVMBuildFDiv :: proc(Builder: LLVMBuilderRef, LHS: LLVMValueRef, RHS: LLVMValueRef, Name: cstring) -> LLVMValueRef ---
    LLVMBuildUDiv :: proc(Builder: LLVMBuilderRef, LHS: LLVMValueRef, RHS: LLVMValueRef, Name: cstring) -> LLVMValueRef ---
    LLVMBuildSDiv :: proc(Builder: LLVMBuilderRef, LHS: LLVMValueRef, RHS: LLVMValueRef, Name: cstring) -> LLVMValueRef ---
    LLVMBuildFRem :: proc(Builder: LLVMBuilderRef, LHS: LLVMValueRef, RHS: LLVMValueRef, Name: cstring) -> LLVMValueRef ---
    LLVMBuildURem :: proc(Builder: LLVMBuilderRef, LHS: LLVMValueRef, RHS: LLVMValueRef, Name: cstring) -> LLVMValueRef ---
    LLVMBuildSRem :: proc(Builder: LLVMBuilderRef, LHS: LLVMValueRef, RHS: LLVMValueRef, Name: cstring) -> LLVMValueRef ---

    LLVMBuildAlloca :: proc(Builder: LLVMBuilderRef, Ty: LLVMTypeRef, Name: cstring) -> LLVMValueRef ---
    LLVMBuildStore :: proc(Builder: LLVMBuilderRef, Val: LLVMValueRef, Ptr: LLVMValueRef) -> LLVMValueRef ---
    LLVMBuildLoad2 :: proc(Builder: LLVMBuilderRef, Ty: LLVMTypeRef, PointerVal: LLVMValueRef, Name: cstring) -> LLVMValueRef ---
    LLVMBuildBr :: proc(Builder: LLVMBuilderRef, Dest: LLVMBasicBlockRef) -> LLVMValueRef ---
    LLVMBuildCondBr :: proc(Builder: LLVMBuilderRef, If: LLVMValueRef, Then: LLVMBasicBlockRef, Else: LLVMBasicBlockRef) -> LLVMValueRef ---
    LLVMBuildICmp :: proc(Builder: LLVMBuilderRef, Predicate: LLVMIntPredicate, LHS: LLVMValueRef, RHS: LLVMValueRef, Name: cstring) -> LLVMValueRef ---
    LLVMBuildFCmp :: proc(Builder: LLVMBuilderRef, Predicate: LLVMRealPredicate, LHS: LLVMValueRef, RHS: LLVMValueRef, Name: cstring) -> LLVMValueRef ---

    LLVMBuildAnd :: proc(Builder: LLVMBuilderRef, LHS: LLVMValueRef, RHS: LLVMValueRef, Name: cstring) -> LLVMValueRef ---
    LLVMBuildOr :: proc(Builder: LLVMBuilderRef, LHS: LLVMValueRef, RHS: LLVMValueRef, Name: cstring) -> LLVMValueRef ---
    LLVMBuildXor :: proc(Builder: LLVMBuilderRef, LHS: LLVMValueRef, RHS: LLVMValueRef, Name: cstring) -> LLVMValueRef ---
    LLVMBuildNot :: proc(Builder: LLVMBuilderRef, Val: LLVMValueRef, Name: cstring) -> LLVMValueRef ---
    LLVMBuildShl :: proc(Builder: LLVMBuilderRef, LHS: LLVMValueRef, RHS: LLVMValueRef, Name: cstring) -> LLVMValueRef ---
    LLVMBuildLShr :: proc(Builder: LLVMBuilderRef, LHS: LLVMValueRef, RHS: LLVMValueRef, Name: cstring) -> LLVMValueRef ---
    LLVMBuildAShr :: proc(Builder: LLVMBuilderRef, LHS: LLVMValueRef, RHS: LLVMValueRef, Name: cstring) -> LLVMValueRef ---
    LLVMBuildShr :: proc(Builder: LLVMBuilderRef, LHS: LLVMValueRef, RHS: LLVMValueRef, Name: cstring) -> LLVMValueRef ---

    LLVMBuildPhi :: proc(Builder: LLVMBuilderRef, Ty: LLVMTypeRef, Name: cstring) -> LLVMValueRef ---

    LLVMTypeOf :: proc(Val: LLVMValueRef) -> LLVMTypeRef ---

    LLVMAddIncoming :: proc(PhiNode: LLVMValueRef, IncomingValues: [^]LLVMValueRef, IncomingBlocks: [^]LLVMBasicBlockRef, Count: uint) ---

    LLVMDisposeBuilder :: proc(Builder: LLVMBuilderRef) ---
    LLVMDisposeModule :: proc(M: LLVMModuleRef) ---
    LLVMContextDispose :: proc(C: LLVMContextRef) ---
}
