aboutsummaryrefslogtreecommitdiff
path: root/luxc
diff options
context:
space:
mode:
Diffstat (limited to 'luxc')
-rw-r--r--luxc/src/lux/compiler/js/rt.clj18
-rw-r--r--luxc/src/lux/compiler/jvm/rt.clj59
2 files changed, 65 insertions, 12 deletions
diff --git a/luxc/src/lux/compiler/js/rt.clj b/luxc/src/lux/compiler/js/rt.clj
index f17998871..d5f503f01 100644
--- a/luxc/src/lux/compiler/js/rt.clj
+++ b/luxc/src/lux/compiler/js/rt.clj
@@ -618,8 +618,24 @@
"return LuxRT$addI64(top,bottomAndMiddle);"
"})")
+ "countLeadingZeroes" (str "(function LuxRT$countLeadingZeroes(input) {"
+ "var zeroes = 64;"
+ (str "while(!LuxRT$eqI64(input,LuxRT$ZERO)) {"
+ "zeroes--;"
+ "input = LuxRT$ushrI64(input,1);"
+ "}")
+ "return zeroes;"
+ "})")
"divD64" (str "(function LuxRT$divD64(l,r) {"
- "return LuxRT$shlI64(LuxRT$divI64(l,LuxRT$fromNumberI64(r.H)),32);"
+ (str "if(LuxRT$eqI64(l,r)) {"
+ "return LuxRT$negateI64(LuxRT$ONE);" ;; ~= 1.0 DEG
+ "}"
+ "else {"
+ "var minShift = Math.min(LuxRT$countLeadingZeroes(l), LuxRT$countLeadingZeroes(r));"
+ "l = LuxRT$shlI64(l,minShift);"
+ "r = LuxRT$shlI64(r,minShift);"
+ "return LuxRT$shlI64(LuxRT$divI64(l,LuxRT$fromNumberI64(r.H)),32);"
+ "}")
"})")
"degToReal" (str "(function LuxRT$degToReal(input) {"
"var two32 = Math.pow(2,32);"
diff --git a/luxc/src/lux/compiler/jvm/rt.clj b/luxc/src/lux/compiler/jvm/rt.clj
index a1b171a25..aa0c881d0 100644
--- a/luxc/src/lux/compiler/jvm/rt.clj
+++ b/luxc/src/lux/compiler/jvm/rt.clj
@@ -368,17 +368,54 @@
(.visitInsn Opcodes/LRETURN)
(.visitMaxs 0 0)
(.visitEnd))
- _ (doto (.visitMethod =class (+ Opcodes/ACC_PUBLIC Opcodes/ACC_STATIC) "div_deg" "(JJ)J" nil nil)
- (.visitCode)
- ;; Based on: http://stackoverflow.com/a/8510587/6823464
- (.visitVarInsn Opcodes/LLOAD 0)
- (.visitVarInsn Opcodes/LLOAD 2) high-4b
- (.visitInsn Opcodes/LDIV)
- (.visitLdcInsn (int 32))
- (.visitInsn Opcodes/LSHL)
- (.visitInsn Opcodes/LRETURN)
- (.visitMaxs 0 0)
- (.visitEnd))
+ _ (let [$loop-start (new Label)
+ $done (new Label)]
+ (doto (.visitMethod =class (+ Opcodes/ACC_PUBLIC Opcodes/ACC_STATIC) "count_leading_zeros" "(J)I" nil nil)
+ (.visitCode)
+ (.visitLdcInsn (int 64))
+ (.visitLabel $loop-start)
+ (.visitVarInsn Opcodes/LLOAD 0)
+ (.visitLdcInsn (long 0))
+ (.visitInsn Opcodes/LCMP)
+ (.visitJumpInsn Opcodes/IFEQ $done)
+ (.visitVarInsn Opcodes/LLOAD 0)
+ (.visitLdcInsn (int 1))
+ (.visitInsn Opcodes/LUSHR)
+ (.visitVarInsn Opcodes/LSTORE 0)
+ (.visitLdcInsn (int 1))
+ (.visitInsn Opcodes/ISUB)
+ (.visitJumpInsn Opcodes/GOTO $loop-start)
+ (.visitLabel $done)
+ (.visitInsn Opcodes/IRETURN)
+ (.visitMaxs 0 0)
+ (.visitEnd)))
+ _ (let [$same (new Label)]
+ (doto (.visitMethod =class (+ Opcodes/ACC_PUBLIC Opcodes/ACC_STATIC) "div_deg" "(JJ)J" nil nil)
+ (.visitCode)
+ (.visitVarInsn Opcodes/LLOAD 0)
+ (.visitVarInsn Opcodes/LLOAD 2)
+ (.visitInsn Opcodes/LCMP)
+ (.visitJumpInsn Opcodes/IFEQ $same)
+ ;; Based on: http://stackoverflow.com/a/8510587/6823464
+ ;; Shifting the operands as much as possible can help
+ ;; avoid some loss of precision later.
+ (.visitVarInsn Opcodes/LLOAD 0)
+ (.visitMethodInsn Opcodes/INVOKESTATIC "lux/LuxRT" "count_leading_zeros" "(J)I")
+ (.visitVarInsn Opcodes/LLOAD 2)
+ (.visitMethodInsn Opcodes/INVOKESTATIC "lux/LuxRT" "count_leading_zeros" "(J)I")
+ (.visitMethodInsn Opcodes/INVOKESTATIC "java/lang/Math" "min" "(II)I")
+ (.visitVarInsn Opcodes/ISTORE 4)
+ (.visitVarInsn Opcodes/LLOAD 0) (.visitVarInsn Opcodes/ILOAD 4) (.visitInsn Opcodes/LSHL)
+ (.visitVarInsn Opcodes/LLOAD 2) (.visitVarInsn Opcodes/ILOAD 4) (.visitInsn Opcodes/LSHL) high-4b
+ (.visitInsn Opcodes/LDIV)
+ (.visitLdcInsn (int 32))
+ (.visitInsn Opcodes/LSHL)
+ (.visitInsn Opcodes/LRETURN)
+ (.visitLabel $same)
+ (.visitLdcInsn (long -1)) ;; ~= 1.0 DEG
+ (.visitInsn Opcodes/LRETURN)
+ (.visitMaxs 0 0)
+ (.visitEnd)))
_ (doto (.visitMethod =class (+ Opcodes/ACC_PUBLIC Opcodes/ACC_STATIC) "deg-to-real" "(J)D" nil nil)
(.visitCode)
;; Translate high bytes