Skip to content

Commit

Permalink
Provide (faked) support for 96-bit floating point values.
Browse files Browse the repository at this point in the history
Just use 64-bit doubles. Unfortunately, I can't find a way to configure GCC 4.7 to use a smaller
size for the "long double" type, so we have to play some games with pointers.
  • Loading branch information
akbertram committed Oct 26, 2017
1 parent 7171b6c commit 1fac0a2
Show file tree
Hide file tree
Showing 16 changed files with 482 additions and 70 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
/**
* Renjin : JVM-based interpreter for the R language for the statistical analysis
* Copyright © 2010-2016 BeDataDriven Groep B.V. and contributors
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, a copy is available at
* https://www.gnu.org/licenses/gpl-2.0.txt
*/
package org.renjin.gcc.codegen.expr;

import org.renjin.gcc.codegen.MethodGenerator;
import org.renjin.repackaged.asm.Type;

import javax.annotation.Nonnull;

public class BinaryOpExpr implements JExpr {

private int opcode;
private Type resultType;
private JExpr x;
private JExpr y;


public BinaryOpExpr(int opcode, JExpr x, JExpr y) {
this.opcode = opcode;
this.resultType = x.getType();
this.x = x;
this.y = y;
}

public BinaryOpExpr(int opcode, Type resultType, JExpr x, JExpr y) {
this.opcode = opcode;
this.resultType = resultType;
this.x = x;
this.y = y;
}

public int getOpcode() {
return opcode;
}

public JExpr getX() {
return x;
}

public JExpr getY() {
return y;
}

@Nonnull
@Override
public Type getType() {
return resultType;
}

@Override
public void load(@Nonnull MethodGenerator mv) {
x.load(mv);
y.load(mv);
mv.visitInsn(x.getType().getOpcode(opcode));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -192,20 +192,7 @@ public static JExpr zero(final Type type) {
}

private static JExpr binary(final int opcode, final JExpr x, final JExpr y, final Type resultType) {
return new JExpr() {
@Nonnull
@Override
public Type getType() {
return resultType;
}

@Override
public void load(@Nonnull MethodGenerator mv) {
x.load(mv);
y.load(mv);
mv.visitInsn(x.getType().getOpcode(opcode));
}
};
return new BinaryOpExpr(opcode, resultType, x, y);
}

private static Type promoteSmallInts(Type type) {
Expand Down Expand Up @@ -763,7 +750,7 @@ public static JExpr bitwiseXor(JExpr x, int y) {
}

public static JExpr bitwiseXor(JExpr x, JExpr y) {
return new BinaryOp(Opcodes.IXOR, x, y);
return new BinaryOpExpr(Opcodes.IXOR, x, y);
}

public static JExpr flip(JExpr value) {
Expand Down Expand Up @@ -1109,39 +1096,4 @@ public void load(@Nonnull MethodGenerator mv) {
};
}

private static class BinaryOp implements JExpr {

private int opcode;
private Type resultType;
private JExpr x;
private JExpr y;


public BinaryOp(int opcode, JExpr x, JExpr y) {
this.opcode = opcode;
this.resultType = x.getType();
this.x = x;
this.y = y;
}

public BinaryOp(int opcode, Type resultType, JExpr x, JExpr y) {
this.opcode = opcode;
this.resultType = resultType;
this.x = x;
this.y = y;
}

@Nonnull
@Override
public Type getType() {
return resultType;
}

@Override
public void load(@Nonnull MethodGenerator mv) {
x.load(mv);
y.load(mv);
mv.visitInsn(x.getType().getOpcode(opcode));
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,33 @@ public GExpr constantExpr(GimpleConstant expr) {
return new RealExpr(gimpleType(), Expressions.constantDouble(((GimpleRealConstant) expr).getValue()));
}
},
REAL96 {

@Override
public GimpleRealType gimpleType() {
return new GimpleRealType(96);
}

@Override
public Type jvmType() {
return Type.DOUBLE_TYPE;
}

@Override
public PrimitiveExpr cast(PrimitiveExpr x) {
return x.toReal(96);
}

@Override
public PrimitiveExpr fromStackValue(JExpr jExpr, @Nullable GExpr address) {
return new RealExpr(gimpleType(), jExpr, address);
}

@Override
public GExpr constantExpr(GimpleConstant expr) {
return new RealExpr(gimpleType(), Expressions.constantDouble(((GimpleRealConstant) expr).getValue()));
}
},
BOOL {
@Override
public GimplePrimitiveType gimpleType() {
Expand Down Expand Up @@ -383,6 +410,8 @@ public static PrimitiveType of(GimplePrimitiveType type) {
return REAL32;
case 64:
return REAL64;
case 96:
return REAL96;
}
} else if(type instanceof GimpleIntegerType) {
GimpleIntegerType integerType = (GimpleIntegerType) type;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
import org.renjin.gcc.codegen.vptr.VPtrExpr;
import org.renjin.gcc.gimple.type.GimplePrimitiveType;
import org.renjin.gcc.gimple.type.GimpleType;
import org.renjin.gcc.runtime.Double96Ptr;
import org.renjin.repackaged.asm.Type;
import org.renjin.repackaged.guava.base.Optional;

Expand Down Expand Up @@ -112,8 +113,14 @@ public Optional<JExpr> getValueConstructor() {
public VPtrExpr toVPtr(JExpr array, JExpr offset) {

PointerType pointerType = PointerType.ofPrimitiveType(type.gimpleType());
JExpr newWrapper = Expressions.newObject(pointerType.alignedImpl(), array, offset);

// Special handling for double[] -> Real96
if(pointerType == PointerType.REAL96 && array.getType().getElementType().equals(Type.DOUBLE_TYPE)) {
JExpr newWrapper = Expressions.newObject(Type.getType(Double96Ptr.class), array, offset);
return new VPtrExpr(newWrapper);
}

JExpr newWrapper = Expressions.newObject(pointerType.alignedImpl(), array, offset);
return new VPtrExpr(newWrapper);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -235,11 +235,13 @@ public ConditionGenerator compareTo(GimpleOp op, GExpr operand) {
}

private JExpr jexpr(int targetPrecision) {
if(this.getPrecision() == targetPrecision) {
if(this.getPrecision() == targetPrecision ||
(this.getPrecision() == 64 && targetPrecision == 96) ||
(this.getPrecision() == 96 && targetPrecision == 64)) {
return jexpr();
} else if(this.getPrecision() == 32 && targetPrecision == 64) {
} else if(this.getPrecision() == 32 && (targetPrecision == 64 || targetPrecision == 96)) {
return Expressions.f2d(jexpr());
} else if(this.getPrecision() == 64 && targetPrecision == 32) {
} else if((this.getPrecision() == 64 || this.getPrecision() == 96) && targetPrecision == 32) {
return Expressions.d2f(jexpr());
} else {
throw new IllegalArgumentException(getPrecision() + "=>" + targetPrecision);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,9 @@
package org.renjin.gcc.codegen.vptr;

import org.renjin.gcc.codegen.MethodGenerator;
import org.renjin.gcc.codegen.expr.ConstantValue;
import org.renjin.gcc.codegen.expr.Expressions;
import org.renjin.gcc.codegen.expr.JExpr;
import org.renjin.gcc.codegen.expr.JLValue;
import org.renjin.gcc.codegen.expr.*;
import org.renjin.gcc.runtime.Ptr;
import org.renjin.repackaged.asm.Opcodes;
import org.renjin.repackaged.asm.Type;

import javax.annotation.Nonnull;
Expand Down Expand Up @@ -106,18 +104,18 @@ private JExpr isAligned() {
}
}

// if(offsetBytes instanceof PrimitiveBinOpGenerator) {
// PrimitiveBinOpGenerator op = (PrimitiveBinOpGenerator) offsetBytes;
// if(op.getOpCode() == Opcodes.IMUL) {
//
// if(isConstantEqualTo(op.getX(), pointerType.getSize())) {
// return op.getY();
// }
// if(isConstantEqualTo(op.getY(), pointerType.getSize())) {
// return op.getX();
// }
// }
// }
if(offsetBytes instanceof BinaryOpExpr) {
BinaryOpExpr op = (BinaryOpExpr) offsetBytes;
if(op.getOpcode() == Opcodes.IMUL) {

if(isConstantEqualTo(op.getX(), pointerType.getSize())) {
return op.getY();
}
if(isConstantEqualTo(op.getY(), pointerType.getSize())) {
return op.getX();
}
}
}
return null;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
package org.renjin.gcc.codegen.vptr;

import org.renjin.gcc.gimple.type.*;
import org.renjin.gcc.runtime.IntPtr;
import org.renjin.gcc.runtime.Ptr;
import org.renjin.repackaged.asm.Type;

Expand All @@ -37,6 +38,12 @@ public enum PointerType {
LONG(Type.LONG_TYPE, PointerKind.INTEGRAL, 8),
FLOAT(Type.FLOAT_TYPE, PointerKind.FLOAT, 4),
DOUBLE(Type.DOUBLE_TYPE, PointerKind.FLOAT, 8),
REAL96(Type.DOUBLE_TYPE, PointerKind.INTEGRAL, 12) {
@Override
public Type alignedImpl() {
return Type.getType(IntPtr.class);
}
},
POINTER(Type.getType(Ptr.class), PointerKind.POINTER, 4),
FUNCTION(Type.getType(MethodHandle.class), PointerKind.FUNCTION, 4);

Expand Down Expand Up @@ -69,6 +76,11 @@ public Type alignedImpl() {
}

public static PointerType ofPrimitiveType(GimplePrimitiveType primitiveType) {
if(primitiveType.equals(new GimpleRealType(96))) {
return REAL96;
} else if(primitiveType.equals(new GimpleRealType(64))) {
return DOUBLE;
}
for (PointerType pointerType : values()) {
if(pointerType.getJvmType().equals(primitiveType.jvmType())) {
return pointerType;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1225,5 +1225,10 @@ public void fortranBooleanArg() throws Exception {
public void sha256() throws Exception {
compileAndTest("sha256.c");
}

@Test
public void real96() throws Exception {
compileAndTest("real96.c");
}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@

#include <stdio.h>
#include <stdlib.h>

#include "assert.h"


void test_real96() {

long double x = 1/3;
long double y = 2/3;

ASSERT( fabs((2.0*x) - y) < 0.00001);
}

void test_real96_pointers() {

long double a[6];
a[0] = 100;
a[1] = 101;
a[2] = 102;
a[3] = 103;
a[4] = 104;
a[5] = 105;

long double *pa = &a[0];
long double *pb = &a[3];

ASSERT(*pa == 100);
ASSERT(*pb == 103);
ASSERT(pb[2] == 105);
}
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,40 @@ public void setAlignedDouble(int index, double value) {
setDouble(index * DoublePtr.BYTES, value);
}


@Override
public double getReal96() {
return getReal96(0);
}


@Override
public double getAlignedReal96(int index) {
return getReal96(index * 12);
}

@Override
public double getReal96(int offset) {
return Double.longBitsToDouble(getLong(offset));
}


@Override
public void setReal96(double value) {
setReal96(0, value);
}

@Override
public void setAlignedReal96(int index, double value) {
setReal96(index * 12, value);
}

@Override
public void setReal96(int offset, double value) {
setLong(offset, Double.doubleToRawLongBits(value));
}


@Override
public char getChar() {
return getChar(0);
Expand Down
Loading

0 comments on commit 1fac0a2

Please sign in to comment.