From 81a403c7b2ef45a3d9cf49bb7251d98695891d52 Mon Sep 17 00:00:00 2001 From: James Y Knight Date: Sat, 2 Jan 2010 02:28:00 -0500 Subject: [PATCH] Make LLVMConstInt transparently work with bignums. --- README | 14 ++++++++++---- src/core.i | 3 +++ src/generated/core.lisp | 2 +- src/generated/llvm-extras.lisp | 24 ++++++++++++++++++++++++ src/llvm-extras.cpp | 8 ++++++++ src/llvm-extras.i | 22 ++++++++++++++++++++++ 6 files changed, 68 insertions(+), 5 deletions(-) diff --git a/README b/README index fd21e58..5334f4e 100644 --- a/README +++ b/README @@ -65,14 +65,20 @@ There are a few things which I have adjusted in the wrapper: take one at a time: call it multiple times to add multiple incoming values. -4) In LLVMBuild*, where the last argument is a "char *Name", I have +4) Where the C API uses an output array argument, such as + LLVMGetStructElementTypes, I instead return a list. + +5) In LLVMBuild*, where the last argument is a "char *Name", I have arranged to make that an optional argument, defaulting to the empty string. The name is only used to give a human-understandable name to the LHS of the assignment in the LLVM IR. If it is omitted, LLVM has the sane default of an auto-incrementing integer. -5) Where the C API uses an output array argument, such as - LLVMGetStructElementTypes, I instead return a list. +6) "LLVMConstInt(llvm_type ty, uint64 num, bool sign_extend)" has been + wrapped as: "(LLVMConstInt llvm-type arbitrary-width-integer)" + instead, by using the underlying LLVM-side bignum API when + llvm-type is larger than 64 bits. (This is the more intuitive + behavior, and gets rid of the superfluous "sign_extend" argument) -6) Where the C API takes a pointer to a char *ErrorMsg, ...FIXME +7) Where the C API takes a pointer to a char *ErrorMsg, ...FIXME something... diff --git a/src/core.i b/src/core.i index 169af63..20990ee 100644 --- a/src/core.i +++ b/src/core.i @@ -77,6 +77,9 @@ typedef unsigned char uint8_t; %ignore LLVMAddFunctionAttr; %ignore LLVMRemoveFunctionAttr; +// LLVMConstInt is replaced in llvm-extras.i with a bignum-capable fn +%rename LLVMConstInt "%%LLVMConstInt"; + %insert("swiglisp") %{ ;; A little hack make the Name argument for LLVMBuild* be optional and ;; default to the empty string. diff --git a/src/generated/core.lisp b/src/generated/core.lisp index d078792..02ebbb1 100644 --- a/src/generated/core.lisp +++ b/src/generated/core.lisp @@ -634,7 +634,7 @@ (wrap-defcfun ("LLVMConstPointerNull" LLVMConstPointerNull) LLVMValueRef (Ty LLVMTypeRef)) -(wrap-defcfun ("LLVMConstInt" LLVMConstInt) LLVMValueRef +(wrap-defcfun ("LLVMConstInt" %LLVMConstInt) LLVMValueRef (IntTy LLVMTypeRef) (N :unsigned-long-long) (SignExtend :boolean)) diff --git a/src/generated/llvm-extras.lisp b/src/generated/llvm-extras.lisp index dff0b5e..86526d9 100644 --- a/src/generated/llvm-extras.lisp +++ b/src/generated/llvm-extras.lisp @@ -49,8 +49,32 @@ (cffi:defcfun ("CLLLVM_LLVMGetRetAttr" LLVMGetRetAttr) LLVMAttribute (Fn LLVMValueRef)) +(cffi:defcfun ("CLLLVM_LLVMConstIntOfBigVal" LLVMConstIntOfBigVal) LLVMValueRef + (IntTy LLVMTypeRef) + (numWords :unsigned-int) + (bigVal :pointer)) + (cffi:defcfun ("CLLLVM_AddPrintAsmPass" CLLLVM_AddPrintAsmPass) :void (PM LLVMPassManagerRef) (Banner :string)) +(defun LLVMConstInt (Ty Num) + (declare (type integer Num)) + ;; If the type is <= 64 bits, it's easy: we can just pass the + ;; (truncated) number into %LLVMConstInt directly. Otherwise, + ;; convert the number to a bunch of 64-bit words, and pass those to + ;; LLVMConstIntOfBigVal. + (let ((bitwidth (LLVMGetIntTypeWidth Ty))) + (if (< bitwidth 65) + (%LLVMConstInt Ty (logand Num #xffffffffffffffff) 0) + (let ((n-words (ceiling bitwidth 64))) + (cffi:with-foreign-object (array :unsigned-long-long n-words) + (loop for i from 0 below n-words + do + (setf (cffi:mem-aref array :unsigned-long-long i) + (logand Num #xffffffffffffffff)) + (setf Num (ash Num -64))) + (LLVMConstIntOfBigVal Ty n-words array)))))) + + diff --git a/src/llvm-extras.cpp b/src/llvm-extras.cpp index 79edf56..1b36895 100644 --- a/src/llvm-extras.cpp +++ b/src/llvm-extras.cpp @@ -100,6 +100,14 @@ LLVMAttribute CLLLVM_LLVMGetRetAttr(LLVMValueRef Fn) { return (LLVMAttribute)attr; } +LLVMValueRef CLLLVM_LLVMConstIntOfBigVal(LLVMTypeRef IntTy, + unsigned numWords, + const uint64_t bigVal[]) { + IntegerType *Ty = unwrap(IntTy); + return wrap(ConstantInt::get(Ty->getContext(), + APInt(Ty->getBitWidth(), numWords, bigVal))); +} + void CLLLVM_AddPrintAsmPass(LLVMPassManagerRef PM, char *Banner) { unwrap(PM)->add(createMachineFunctionPrinterPass(errs(), Banner)); } diff --git a/src/llvm-extras.i b/src/llvm-extras.i index f6248da..b81775d 100644 --- a/src/llvm-extras.i +++ b/src/llvm-extras.i @@ -6,4 +6,26 @@ %rename CLLLVM_LLVMRemoveRetAttr "LLVMRemoveRetAttr"; %rename CLLLVM_LLVMGetRetAttr "LLVMGetRetAttr"; +%rename CLLLVM_LLVMConstIntOfBigVal "LLVMConstIntOfBigVal"; + %include "./llvm-extras.cpp" + +%insert("swiglisp") %{ +(defun LLVMConstInt (Ty Num) + (declare (type integer Num)) + ;; If the type is <= 64 bits, it's easy: we can just pass the + ;; (truncated) number into %LLVMConstInt directly. Otherwise, + ;; convert the number to a bunch of 64-bit words, and pass those to + ;; LLVMConstIntOfBigVal. + (let ((bitwidth (LLVMGetIntTypeWidth Ty))) + (if (< bitwidth 65) + (%LLVMConstInt Ty (logand Num #xffffffffffffffff) 0) + (let ((n-words (ceiling bitwidth 64))) + (cffi:with-foreign-object (array :unsigned-long-long n-words) + (loop for i from 0 below n-words + do + (setf (cffi:mem-aref array :unsigned-long-long i) + (logand Num #xffffffffffffffff)) + (setf Num (ash Num -64))) + (LLVMConstIntOfBigVal Ty n-words array)))))) +%} -- 2.11.4.GIT