Make LLVMConstInt transparently work with bignums.master
authorJames Y Knight <foom@fuhm.net>
Sat, 2 Jan 2010 07:28:00 +0000 (2 02:28 -0500)
committerJames Y Knight <foom@fuhm.net>
Sat, 2 Jan 2010 07:28:00 +0000 (2 02:28 -0500)
README
src/core.i
src/generated/core.lisp
src/generated/llvm-extras.lisp
src/llvm-extras.cpp
src/llvm-extras.i

diff --git a/README b/README
index fd21e58..5334f4e 100644 (file)
--- 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...
index 169af63..20990ee 100644 (file)
@@ -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.
index d078792..02ebbb1 100644 (file)
 (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))
index dff0b5e..86526d9 100644 (file)
 (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))))))
+
+
 
index 79edf56..1b36895 100644 (file)
@@ -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<IntegerType>(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));
 }
index f6248da..b81775d 100644 (file)
@@ -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))))))
+%}