All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/4] floating-point specific instructions
@ 2017-03-28 14:18 Luc Van Oostenryck
  2017-03-28 14:18 ` [PATCH 1/4] fix linearize_inc_dec() with floats Luc Van Oostenryck
                   ` (5 more replies)
  0 siblings, 6 replies; 7+ messages in thread
From: Luc Van Oostenryck @ 2017-03-28 14:18 UTC (permalink / raw)
  To: linux-sparse; +Cc: Christopher Li, Luc Van Oostenryck

Floating-point arithmetic is quite different from arithmetic
on integers (or on real numbers). In particular,
most transformations, simplifications that can be done on integers
are invalid when done on floats.

Since they don't follow the same rules as their integer
counterpart, better to give a specific opcode to floating-point
operations instead of having to test the type of the operands at
each manipulation.


Luc Van Oostenryck (4):
  fix linearize_inc_dec() with floats
  add test case for boolean negation on float
  fix support of floating-point compare
  add support of floating-point specific arithmetic ops

 cse.c                               |  14 ++++
 linearize.c                         |  58 ++++++++++++++---
 linearize.h                         |  25 ++++++++
 liveness.c                          |   1 +
 opcode.c                            |  46 +++++++++++---
 opcode.h                            |  10 +++
 simplify.c                          |   2 +-
 sparse-llvm.c                       |  64 ++++++++++---------
 validation/backend/arithmetic-ops.c |  20 ++++++
 validation/bool-float.c             |   9 +++
 validation/fp-ops.c                 |  57 +++++++++++++++++
 validation/inc-dec-float.c          |  13 ++++
 validation/optim/canonical-fcmp.c   | 123 ++++++++++++++++++++++++++++++++++++
 13 files changed, 394 insertions(+), 48 deletions(-)
 create mode 100644 validation/bool-float.c
 create mode 100644 validation/fp-ops.c
 create mode 100644 validation/inc-dec-float.c
 create mode 100644 validation/optim/canonical-fcmp.c

-- 
2.12.0


^ permalink raw reply	[flat|nested] 7+ messages in thread

* [PATCH 1/4] fix linearize_inc_dec() with floats
  2017-03-28 14:18 [PATCH 0/4] floating-point specific instructions Luc Van Oostenryck
@ 2017-03-28 14:18 ` Luc Van Oostenryck
  2017-03-28 14:18 ` [PATCH 2/4] add test case for boolean negation on float Luc Van Oostenryck
                   ` (4 subsequent siblings)
  5 siblings, 0 replies; 7+ messages in thread
From: Luc Van Oostenryck @ 2017-03-28 14:18 UTC (permalink / raw)
  To: linux-sparse; +Cc: Christopher Li, Luc Van Oostenryck

Using the pre or post increment or decrement operator on
floating-point values mix the addition of a floating-point
value with an *integral* constant 1 or -1.

Fix this by checking if we're dealing with fp or not and using
the proper fp constants (1.0 or -1.0) if it is the case.

Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
---
 linearize.c                | 18 ++++++++++++++++--
 validation/inc-dec-float.c | 13 +++++++++++++
 2 files changed, 29 insertions(+), 2 deletions(-)
 create mode 100644 validation/inc-dec-float.c

diff --git a/linearize.c b/linearize.c
index 209bd2bf3..ed649a86a 100644
--- a/linearize.c
+++ b/linearize.c
@@ -991,6 +991,18 @@ static pseudo_t add_setval(struct entrypoint *ep, struct symbol *ctype, struct e
 	return target;
 }
 
+static pseudo_t add_setfval(struct entrypoint *ep, struct symbol *ctype, long double fval)
+{
+	struct instruction *insn = alloc_typed_instruction(OP_SETVAL, ctype);
+	struct expression *expr = alloc_expression(insn->pos, EXPR_FVALUE);
+	pseudo_t target = alloc_pseudo(insn);
+	insn->target = target;
+	insn->val = expr;
+	expr->fvalue = fval;
+	add_one_insn(ep, insn);
+	return target;
+}
+
 static pseudo_t add_symbol_address(struct entrypoint *ep, struct symbol *sym)
 {
 	struct instruction *insn = alloc_instruction(OP_SYMADDR, bits_in_pointer);
@@ -1028,7 +1040,6 @@ static pseudo_t linearize_access(struct entrypoint *ep, struct expression *expr)
 	return value;
 }
 
-/* FIXME: FP */
 static pseudo_t linearize_inc_dec(struct entrypoint *ep, struct expression *expr, int postop)
 {
 	struct access_data ad = { NULL, };
@@ -1039,7 +1050,10 @@ static pseudo_t linearize_inc_dec(struct entrypoint *ep, struct expression *expr
 		return VOID;
 
 	old = linearize_load_gen(ep, &ad);
-	one = value_pseudo(expr->op_value);
+	if (is_float_type(expr->ctype))
+		one = add_setfval(ep, expr->ctype, expr->op_value);
+	else
+		one = value_pseudo(expr->op_value);
 	new = add_binary_op(ep, expr->ctype, op, old, one);
 	linearize_store_gen(ep, new, &ad);
 	finish_address_gen(ep, &ad);
diff --git a/validation/inc-dec-float.c b/validation/inc-dec-float.c
new file mode 100644
index 000000000..3cac8f3ee
--- /dev/null
+++ b/validation/inc-dec-float.c
@@ -0,0 +1,13 @@
+double fincpre(double a)  { ++a; return a; }
+double fdecpre(double a)  { --a; return a; }
+double fincpost(double a) { a++; return a; }
+double fdecpost(double a) { a--; return a; }
+
+/*
+ * check-name: float inc & dec
+ * check-command: test-linearize -Wno-decl $file
+ * check-output-ignore
+ *
+ * check-output-excludes: \\$1$
+ * check-output-excludes: \\$-1$
+ */
-- 
2.12.0


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH 2/4] add test case for boolean negation on float
  2017-03-28 14:18 [PATCH 0/4] floating-point specific instructions Luc Van Oostenryck
  2017-03-28 14:18 ` [PATCH 1/4] fix linearize_inc_dec() with floats Luc Van Oostenryck
@ 2017-03-28 14:18 ` Luc Van Oostenryck
  2017-03-28 14:18 ` [PATCH 3/4] fix support of floating-point compare Luc Van Oostenryck
                   ` (3 subsequent siblings)
  5 siblings, 0 replies; 7+ messages in thread
From: Luc Van Oostenryck @ 2017-03-28 14:18 UTC (permalink / raw)
  To: linux-sparse; +Cc: Christopher Li, Luc Van Oostenryck

Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
---
 validation/bool-float.c | 9 +++++++++
 1 file changed, 9 insertions(+)
 create mode 100644 validation/bool-float.c

diff --git a/validation/bool-float.c b/validation/bool-float.c
new file mode 100644
index 000000000..eadf4cf09
--- /dev/null
+++ b/validation/bool-float.c
@@ -0,0 +1,9 @@
+int ftst(double a)  { return !a; }
+
+/*
+ * check-name: not-operator on float
+ * check-command: test-linearize -Wno-decl $file
+ * check-output-ignore
+ *
+ * check-output-excludes: \\$0
+ */
-- 
2.12.0


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH 3/4] fix support of floating-point compare
  2017-03-28 14:18 [PATCH 0/4] floating-point specific instructions Luc Van Oostenryck
  2017-03-28 14:18 ` [PATCH 1/4] fix linearize_inc_dec() with floats Luc Van Oostenryck
  2017-03-28 14:18 ` [PATCH 2/4] add test case for boolean negation on float Luc Van Oostenryck
@ 2017-03-28 14:18 ` Luc Van Oostenryck
  2017-03-28 14:18 ` [PATCH 4/4] add support of floating-point specific arithmetic ops Luc Van Oostenryck
                   ` (2 subsequent siblings)
  5 siblings, 0 replies; 7+ messages in thread
From: Luc Van Oostenryck @ 2017-03-28 14:18 UTC (permalink / raw)
  To: linux-sparse; +Cc: Christopher Li, Luc Van Oostenryck

Comparision of floating-point values can't be done
like for integral values because of the possibility to have
NaNs which can't be ordered with normal values or even between
themselves.
The real difference appears once there is any "reasoning"
done with the result of the comparison. For example, once NaNs
are taken in account: "!(a < b)" and "(a >= b)" are not the same.

In fact the usual comparison operators must be reinterpreted
as implicitely first testing if any of the operand is a Nan
and return 'false' if it is the case. Thus "a < b" becomes
"!isnan(a) && !isnan(b) && (a < b)".
If we need to negate the comparison we get "!(a < b)" which
naturally becomes "isnan(a) || isnan(b) || (a >= b)".

We thus need two sets of operators for comparison of floats:
one for the "ordered" values (only true if neither operand
is a Nan) and one for the "values" (also true if either
operand is a NaN). A negation of the comparison switch from one
of the set to the other.

So, introduce another set of instructions for the comparison
of floats.

Note: the C standard requires that:
	*) "x == x" is false if x is a NaN,
	*) "x != x" is true  if x is a NaN,
and this is coherent with "x != x" <-> "!(x == x)".

Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
---
 linearize.c                       |  21 ++++++-
 linearize.h                       |  18 ++++++
 liveness.c                        |   1 +
 opcode.c                          |  38 ++++++++----
 opcode.h                          |  10 ++++
 simplify.c                        |   2 +-
 sparse-llvm.c                     |  27 +++++----
 validation/optim/canonical-fcmp.c | 123 ++++++++++++++++++++++++++++++++++++++
 8 files changed, 215 insertions(+), 25 deletions(-)
 create mode 100644 validation/optim/canonical-fcmp.c

diff --git a/linearize.c b/linearize.c
index ed649a86a..37c201496 100644
--- a/linearize.c
+++ b/linearize.c
@@ -208,6 +208,22 @@ static const char *opcodes[] = {
 	[OP_SET_BE] = "setbe",
 	[OP_SET_AE] = "setae",
 
+	/* floating-point comparison */
+	[OP_FCMP_ORD] = "fcmpord",
+	[OP_FCMP_OEQ] = "fcmpoeq",
+	[OP_FCMP_ONE] = "fcmpone",
+	[OP_FCMP_OLE] = "fcmpole",
+	[OP_FCMP_OGE] = "fcmpoge",
+	[OP_FCMP_OLT] = "fcmpolt",
+	[OP_FCMP_OGT] = "fcmpogt",
+	[OP_FCMP_UEQ] = "fcmpueq",
+	[OP_FCMP_UNE] = "fcmpune",
+	[OP_FCMP_ULE] = "fcmpule",
+	[OP_FCMP_UGE] = "fcmpuge",
+	[OP_FCMP_ULT] = "fcmpult",
+	[OP_FCMP_UGT] = "fcmpugt",
+	[OP_FCMP_UNO] = "fcmpuno",
+
 	/* Uni */
 	[OP_NOT] = "not",
 	[OP_NEG] = "neg",
@@ -437,6 +453,7 @@ const char *show_instruction(struct instruction *insn)
 			show_pseudo(insn->src));
 		break;
 	case OP_BINARY ... OP_BINARY_END:
+	case OP_FPCMP ... OP_FPCMP_END:
 	case OP_BINCMP ... OP_BINCMP_END:
 		buf += sprintf(buf, "%s <- %s, %s", show_pseudo(insn->target), show_pseudo(insn->src1), show_pseudo(insn->src2));
 		break;
@@ -1465,10 +1482,10 @@ static pseudo_t linearize_compare(struct entrypoint *ep, struct expression *expr
 		[SPECIAL_UNSIGNED_LTE] = OP_SET_BE,
 		[SPECIAL_UNSIGNED_GTE] = OP_SET_AE,
 	};
-
+	int op = opcode_float(cmpop[expr->op], expr->right->ctype);
 	pseudo_t src1 = linearize_expression(ep, expr->left);
 	pseudo_t src2 = linearize_expression(ep, expr->right);
-	pseudo_t dst = add_binary_op(ep, expr->ctype, cmpop[expr->op], src1, src2);
+	pseudo_t dst = add_binary_op(ep, expr->ctype, op, src1, src2);
 	return dst;
 }
 
diff --git a/linearize.h b/linearize.h
index ce065fe76..3bb9426ca 100644
--- a/linearize.h
+++ b/linearize.h
@@ -170,6 +170,24 @@ enum opcode {
 	OP_OR_BOOL,
 	OP_BINARY_END = OP_OR_BOOL,
 
+	/* floating-point comparison */
+	OP_FPCMP,
+	OP_FCMP_ORD = OP_FPCMP,
+	OP_FCMP_OEQ,
+	OP_FCMP_ONE,
+	OP_FCMP_OLE,
+	OP_FCMP_OGE,
+	OP_FCMP_OLT,
+	OP_FCMP_OGT,
+	OP_FCMP_UEQ,
+	OP_FCMP_UNE,
+	OP_FCMP_ULE,
+	OP_FCMP_UGE,
+	OP_FCMP_ULT,
+	OP_FCMP_UGT,
+	OP_FCMP_UNO,
+	OP_FPCMP_END = OP_FCMP_UNO,
+
 	/* Binary comparison */
 	OP_BINCMP,
 	OP_SET_EQ = OP_BINCMP,
diff --git a/liveness.c b/liveness.c
index 7b5b1693a..f7c0414b5 100644
--- a/liveness.c
+++ b/liveness.c
@@ -66,6 +66,7 @@ static void track_instruction_usage(struct basic_block *bb, struct instruction *
 	
 	/* Binary */
 	case OP_BINARY ... OP_BINARY_END:
+	case OP_FPCMP ... OP_FPCMP_END:
 	case OP_BINCMP ... OP_BINCMP_END:
 		USES(src1); USES(src2); DEFINES(target);
 		break;
diff --git a/opcode.c b/opcode.c
index 102bef68d..c28a08859 100644
--- a/opcode.c
+++ b/opcode.c
@@ -23,14 +23,32 @@
 #include "linearize.h"
 
 const struct opcode_table opcode_table[OP_LAST] = {
-	[OP_SET_EQ] = {	.negate = OP_SET_NE, .swap = OP_SET_EQ, },
-	[OP_SET_NE] = {	.negate = OP_SET_EQ, .swap = OP_SET_NE, },
-	[OP_SET_LT] = {	.negate = OP_SET_GE, .swap = OP_SET_GT, },
-	[OP_SET_LE] = {	.negate = OP_SET_GT, .swap = OP_SET_GE, },
-	[OP_SET_GE] = {	.negate = OP_SET_LT, .swap = OP_SET_LE, },
-	[OP_SET_GT] = {	.negate = OP_SET_LE, .swap = OP_SET_LT, },
-	[OP_SET_B ] = {	.negate = OP_SET_AE, .swap = OP_SET_A , },
-	[OP_SET_BE] = {	.negate = OP_SET_A , .swap = OP_SET_AE, },
-	[OP_SET_AE] = {	.negate = OP_SET_B , .swap = OP_SET_BE, },
-	[OP_SET_A ] = {	.negate = OP_SET_BE, .swap = OP_SET_B , },
+	[OP_SET_EQ] = {	.negate = OP_SET_NE, .swap = OP_SET_EQ, .to_float = OP_FCMP_OEQ, },
+	[OP_SET_NE] = {	.negate = OP_SET_EQ, .swap = OP_SET_NE, .to_float = OP_FCMP_UNE, },
+	[OP_SET_LT] = {	.negate = OP_SET_GE, .swap = OP_SET_GT, .to_float = OP_FCMP_OLT, },
+	[OP_SET_LE] = {	.negate = OP_SET_GT, .swap = OP_SET_GE, .to_float = OP_FCMP_OLE, },
+	[OP_SET_GE] = {	.negate = OP_SET_LT, .swap = OP_SET_LE, .to_float = OP_FCMP_OGE, },
+	[OP_SET_GT] = {	.negate = OP_SET_LE, .swap = OP_SET_LT, .to_float = OP_FCMP_OGT, },
+	[OP_SET_B ] = {	.negate = OP_SET_AE, .swap = OP_SET_A , .to_float = OP_FCMP_OLT, },
+	[OP_SET_BE] = {	.negate = OP_SET_A , .swap = OP_SET_AE, .to_float = OP_FCMP_OLE, },
+	[OP_SET_AE] = {	.negate = OP_SET_B , .swap = OP_SET_BE, .to_float = OP_FCMP_OGE, },
+	[OP_SET_A ] = {	.negate = OP_SET_BE, .swap = OP_SET_B , .to_float = OP_FCMP_OGT, },
+
+	[OP_FCMP_ORD] = { .negate = OP_FCMP_UNO, .swap = OP_FCMP_ORD, },
+	[OP_FCMP_UNO] = { .negate = OP_FCMP_ORD, .swap = OP_FCMP_UNO, },
+
+	[OP_FCMP_OEQ] = { .negate = OP_FCMP_UNE, .swap = OP_FCMP_OEQ, },
+	[OP_FCMP_ONE] = { .negate = OP_FCMP_UEQ, .swap = OP_FCMP_ONE, },
+	[OP_FCMP_UEQ] = { .negate = OP_FCMP_ONE, .swap = OP_FCMP_UEQ, },
+	[OP_FCMP_UNE] = { .negate = OP_FCMP_OEQ, .swap = OP_FCMP_UNE, },
+
+	[OP_FCMP_OLT] = { .negate = OP_FCMP_UGE, .swap = OP_FCMP_OGT, },
+	[OP_FCMP_OLE] = { .negate = OP_FCMP_UGT, .swap = OP_FCMP_OGE, },
+	[OP_FCMP_OGE] = { .negate = OP_FCMP_ULT, .swap = OP_FCMP_OLE, },
+	[OP_FCMP_OGT] = { .negate = OP_FCMP_ULE, .swap = OP_FCMP_OLT, },
+
+	[OP_FCMP_ULT] = { .negate = OP_FCMP_OGE, .swap = OP_FCMP_UGT, },
+	[OP_FCMP_ULE] = { .negate = OP_FCMP_OGT, .swap = OP_FCMP_UGE, },
+	[OP_FCMP_UGE] = { .negate = OP_FCMP_OLT, .swap = OP_FCMP_ULE, },
+	[OP_FCMP_UGT] = { .negate = OP_FCMP_OLE, .swap = OP_FCMP_ULT, },
 };
diff --git a/opcode.h b/opcode.h
index 4a9b102f2..eda4c3a74 100644
--- a/opcode.h
+++ b/opcode.h
@@ -1,10 +1,20 @@
 #ifndef OPCODE_H
 #define OPCODE_H
 
+#include "symbol.h"
 
 extern const struct opcode_table {
 	int	negate:8;
 	int	swap:8;
+	int	to_float:8;
 } opcode_table[];
 
+
+static inline int opcode_float(int opcode, struct symbol *type)
+{
+	if (!type || !is_float_type(type))
+		return opcode;
+	return opcode_table[opcode].to_float;
+}
+
 #endif
diff --git a/simplify.c b/simplify.c
index 7ca727416..2286440e0 100644
--- a/simplify.c
+++ b/simplify.c
@@ -429,7 +429,7 @@ static int simplify_seteq_setne(struct instruction *insn, long long value)
 	inverse = (insn->opcode == OP_SET_NE) == value;
 	opcode = def->opcode;
 	switch (opcode) {
-	case OP_BINCMP ... OP_BINCMP_END:
+	case OP_FPCMP ... OP_BINCMP_END:
 		// Convert:
 		//	setcc.n	%t <- %a, %b
 		//	setne.m %r <- %t, $0
diff --git a/sparse-llvm.c b/sparse-llvm.c
index b82fbefa1..c21c38947 100644
--- a/sparse-llvm.c
+++ b/sparse-llvm.c
@@ -492,17 +492,20 @@ static LLVMValueRef calc_gep(LLVMBuilderRef builder, LLVMValueRef base, LLVMValu
 static LLVMRealPredicate translate_fop(int opcode)
 {
 	static const LLVMRealPredicate trans_tbl[] = {
-		[OP_SET_EQ]	= LLVMRealOEQ,
-		[OP_SET_NE]	= LLVMRealUNE,
-		[OP_SET_LE]	= LLVMRealOLE,
-		[OP_SET_GE]	= LLVMRealOGE,
-		[OP_SET_LT]	= LLVMRealOLT,
-		[OP_SET_GT]	= LLVMRealOGT,
-		/* Are these used with FP? */
-		[OP_SET_B]	= LLVMRealOLT,
-		[OP_SET_A]	= LLVMRealOGT,
-		[OP_SET_BE]	= LLVMRealOLE,
-		[OP_SET_AE]	= LLVMRealOGE,
+		[OP_FCMP_ORD]	= LLVMRealORD,
+		[OP_FCMP_OEQ]	= LLVMRealOEQ,
+		[OP_FCMP_ONE]	= LLVMRealONE,
+		[OP_FCMP_OLE]	= LLVMRealOLE,
+		[OP_FCMP_OGE]	= LLVMRealOGE,
+		[OP_FCMP_OLT]	= LLVMRealOLT,
+		[OP_FCMP_OGT]	= LLVMRealOGT,
+		[OP_FCMP_UEQ]	= LLVMRealUEQ,
+		[OP_FCMP_UNE]	= LLVMRealUNE,
+		[OP_FCMP_ULE]	= LLVMRealULE,
+		[OP_FCMP_UGE]	= LLVMRealUGE,
+		[OP_FCMP_ULT]	= LLVMRealULT,
+		[OP_FCMP_UGT]	= LLVMRealUGT,
+		[OP_FCMP_UNO]	= LLVMRealUNO,
 	};
 
 	return trans_tbl[opcode];
@@ -1029,7 +1032,7 @@ static void output_insn(struct function *fn, struct instruction *insn)
 	case OP_BINARY ... OP_BINARY_END:
 		output_op_binary(fn, insn);
 		break;
-	case OP_BINCMP ... OP_BINCMP_END:
+	case OP_FPCMP ... OP_BINCMP_END:
 		output_op_compare(fn, insn);
 		break;
 	case OP_SEL:
diff --git a/validation/optim/canonical-fcmp.c b/validation/optim/canonical-fcmp.c
new file mode 100644
index 000000000..e3e758a9b
--- /dev/null
+++ b/validation/optim/canonical-fcmp.c
@@ -0,0 +1,123 @@
+extern double g;
+
+int  fcmp_eq(double a) { return  (g == a); }
+int  fcmp_ne(double a) { return  (g != a); }
+
+int  fcmp_gt(double a) { return  (g >  a); }
+int  fcmp_ge(double a) { return  (g >= a); }
+int  fcmp_le(double a) { return  (g <= a); }
+int  fcmp_lt(double a) { return  (g <  a); }
+
+int nfcmp_ne(double a) { return !(g == a); }
+int nfcmp_eq(double a) { return !(g != a); }
+
+int nfcmp_le(double a) { return !(g >  a); }
+int nfcmp_lt(double a) { return !(g >= a); }
+int nfcmp_gt(double a) { return !(g <= a); }
+int nfcmp_ge(double a) { return !(g <  a); }
+
+/*
+ * check-name: canonical-cmp
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-exclude: \$123,
+ *
+ * check-output-start
+fcmp_eq:
+.L0:
+	<entry-point>
+	load.64     %r1 <- 0[g]
+	fcmpoeq.32  %r3 <- %r1, %arg1
+	ret.32      %r3
+
+
+fcmp_ne:
+.L2:
+	<entry-point>
+	load.64     %r5 <- 0[g]
+	fcmpune.32  %r7 <- %r5, %arg1
+	ret.32      %r7
+
+
+fcmp_gt:
+.L4:
+	<entry-point>
+	load.64     %r9 <- 0[g]
+	fcmpogt.32  %r11 <- %r9, %arg1
+	ret.32      %r11
+
+
+fcmp_ge:
+.L6:
+	<entry-point>
+	load.64     %r13 <- 0[g]
+	fcmpoge.32  %r15 <- %r13, %arg1
+	ret.32      %r15
+
+
+fcmp_le:
+.L8:
+	<entry-point>
+	load.64     %r17 <- 0[g]
+	fcmpole.32  %r19 <- %r17, %arg1
+	ret.32      %r19
+
+
+fcmp_lt:
+.L10:
+	<entry-point>
+	load.64     %r21 <- 0[g]
+	fcmpolt.32  %r23 <- %r21, %arg1
+	ret.32      %r23
+
+
+nfcmp_ne:
+.L12:
+	<entry-point>
+	load.64     %r25 <- 0[g]
+	fcmpune.32  %r28 <- %r25, %arg1
+	ret.32      %r28
+
+
+nfcmp_eq:
+.L14:
+	<entry-point>
+	load.64     %r30 <- 0[g]
+	fcmpoeq.32  %r33 <- %r30, %arg1
+	ret.32      %r33
+
+
+nfcmp_le:
+.L16:
+	<entry-point>
+	load.64     %r35 <- 0[g]
+	fcmpule.32  %r38 <- %r35, %arg1
+	ret.32      %r38
+
+
+nfcmp_lt:
+.L18:
+	<entry-point>
+	load.64     %r40 <- 0[g]
+	fcmpult.32  %r43 <- %r40, %arg1
+	ret.32      %r43
+
+
+nfcmp_gt:
+.L20:
+	<entry-point>
+	load.64     %r45 <- 0[g]
+	fcmpugt.32  %r48 <- %r45, %arg1
+	ret.32      %r48
+
+
+nfcmp_ge:
+.L22:
+	<entry-point>
+	load.64     %r50 <- 0[g]
+	fcmpuge.32  %r53 <- %r50, %arg1
+	ret.32      %r53
+
+
+ * check-output-end
+ */
-- 
2.12.0


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH 4/4] add support of floating-point specific arithmetic ops
  2017-03-28 14:18 [PATCH 0/4] floating-point specific instructions Luc Van Oostenryck
                   ` (2 preceding siblings ...)
  2017-03-28 14:18 ` [PATCH 3/4] fix support of floating-point compare Luc Van Oostenryck
@ 2017-03-28 14:18 ` Luc Van Oostenryck
  2017-04-01 10:56 ` [GIT PULL] floating-point specific instructions Luc Van Oostenryck
  2017-11-18 14:27 ` [PATCH 0/4] " Luc Van Oostenryck
  5 siblings, 0 replies; 7+ messages in thread
From: Luc Van Oostenryck @ 2017-03-28 14:18 UTC (permalink / raw)
  To: linux-sparse; +Cc: Christopher Li, Luc Van Oostenryck

Floating-point arithmetic is quite different from the
arithmetic on integers or the one of real numbers.
In particular, most transformations, simplifications that can
be done on integers are invalid when done on floats.
For example:
- associativity doesn't hold
- distributivity doesn't hold
- comparison is tricky & complex
This is because (among others things):
- limited precision, rounding everywhere
- presence of signed zeroes
- presence of infinities
- presence of NaNs (signaling or quiet)
- presence of numbers without inverse
- several kind of exceptions.

Since they don't follow the same rules as their integer
counterpart, better to give them a specific opcode
instead of having to test the type of the operands at
each manipulation.

Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
---
 cse.c                               | 14 +++++++++
 linearize.c                         | 19 ++++++++++---
 linearize.h                         |  7 +++++
 opcode.c                            |  8 ++++++
 sparse-llvm.c                       | 37 +++++++++++++-----------
 validation/backend/arithmetic-ops.c | 20 +++++++++++++
 validation/fp-ops.c                 | 57 +++++++++++++++++++++++++++++++++++++
 7 files changed, 141 insertions(+), 21 deletions(-)
 create mode 100644 validation/fp-ops.c

diff --git a/cse.c b/cse.c
index 0d3815c5a..f535636b4 100644
--- a/cse.c
+++ b/cse.c
@@ -70,11 +70,18 @@ static void clean_up_one_instruction(struct basic_block *bb, struct instruction
 	case OP_SET_LT: case OP_SET_GT:
 	case OP_SET_B:  case OP_SET_A:
 	case OP_SET_BE: case OP_SET_AE:
+
+	/* floating-point arithmetic */
+	case OP_FADD:
+	case OP_FSUB:
+	case OP_FMUL:
+	case OP_FDIV:
 		hash += hashval(insn->src2);
 		/* Fall through */
 	
 	/* Unary */
 	case OP_NOT: case OP_NEG:
+	case OP_FNEG:
 		hash += hashval(insn->src1);
 		break;
 
@@ -205,6 +212,12 @@ static int insn_compare(const void *_i1, const void *_i2)
 	case OP_SET_LT: case OP_SET_GT:
 	case OP_SET_B:  case OP_SET_A:
 	case OP_SET_BE: case OP_SET_AE:
+
+	/* floating-point arithmetic */
+	case OP_FADD:
+	case OP_FSUB:
+	case OP_FMUL:
+	case OP_FDIV:
 	case_binops:
 		if (i1->src2 != i2->src2)
 			return i1->src2 < i2->src2 ? -1 : 1;
@@ -212,6 +225,7 @@ static int insn_compare(const void *_i1, const void *_i2)
 
 	/* Unary */
 	case OP_NOT: case OP_NEG:
+	case OP_FNEG:
 		if (i1->src1 != i2->src1)
 			return i1->src1 < i2->src1 ? -1 : 1;
 		break;
diff --git a/linearize.c b/linearize.c
index 37c201496..902d45087 100644
--- a/linearize.c
+++ b/linearize.c
@@ -189,6 +189,12 @@ static const char *opcodes[] = {
 	[OP_LSR] = "lsr",
 	[OP_ASR] = "asr",
 	
+	/* Floating-point Binary */
+	[OP_FADD] = "fadd",
+	[OP_FSUB] = "fsub",
+	[OP_FMUL] = "fmul",
+	[OP_FDIV] = "fdiv",
+
 	/* Logical */
 	[OP_AND] = "and",
 	[OP_OR] = "or",
@@ -227,6 +233,7 @@ static const char *opcodes[] = {
 	/* Uni */
 	[OP_NOT] = "not",
 	[OP_NEG] = "neg",
+	[OP_FNEG] = "fneg",
 
 	/* Special three-input */
 	[OP_SEL] = "select",
@@ -468,6 +475,7 @@ const char *show_instruction(struct instruction *insn)
 		break;
 
 	case OP_NOT: case OP_NEG:
+	case OP_FNEG:
 		buf += sprintf(buf, "%s <- %s", show_pseudo(insn->target), show_pseudo(insn->src1));
 		break;
 
@@ -1067,6 +1075,7 @@ static pseudo_t linearize_inc_dec(struct entrypoint *ep, struct expression *expr
 		return VOID;
 
 	old = linearize_load_gen(ep, &ad);
+	op = opcode_float(op, expr->ctype);
 	if (is_float_type(expr->ctype))
 		one = add_setfval(ep, expr->ctype, expr->op_value);
 	else
@@ -1115,7 +1124,7 @@ static pseudo_t linearize_regular_preop(struct entrypoint *ep, struct expression
 	case '~':
 		return add_uniop(ep, expr, OP_NOT, pre);
 	case '-':
-		return add_uniop(ep, expr, OP_NEG, pre);
+		return add_uniop(ep, expr, opcode_float(OP_NEG, expr->ctype), pre);
 	}
 	return VOID;
 }
@@ -1183,8 +1192,10 @@ static pseudo_t cast_pseudo(struct entrypoint *ep, pseudo_t src, struct symbol *
 	return result;
 }
 
-static int opcode_sign(int opcode, struct symbol *ctype)
+static int map_opcode(int opcode, struct symbol *ctype)
 {
+	if (ctype && is_float_type(ctype))
+		return opcode_table[opcode].to_float;
 	if (ctype && (ctype->ctype.modifiers & MOD_SIGNED)) {
 		switch(opcode) {
 		case OP_MULU: case OP_DIVU: case OP_MODU: case OP_LSR:
@@ -1227,7 +1238,7 @@ static pseudo_t linearize_assignment(struct entrypoint *ep, struct expression *e
 
 		ctype = src->ctype;
 		oldvalue = cast_pseudo(ep, oldvalue, target->ctype, ctype);
-		opcode = opcode_sign(op_trans[expr->op - SPECIAL_BASE], ctype);
+		opcode = map_opcode(op_trans[expr->op - SPECIAL_BASE], ctype);
 		dst = add_binary_op(ep, ctype, opcode, oldvalue, value);
 		value = cast_pseudo(ep, dst, ctype, expr->ctype);
 	}
@@ -1353,7 +1364,7 @@ static pseudo_t linearize_binop(struct entrypoint *ep, struct expression *expr)
 
 	src1 = linearize_expression(ep, expr->left);
 	src2 = linearize_expression(ep, expr->right);
-	op = opcode_sign(opcode[expr->op], expr->ctype);
+	op = map_opcode(opcode[expr->op], expr->ctype);
 	dst = add_binary_op(ep, expr->ctype, op, src1, src2);
 	return dst;
 }
diff --git a/linearize.h b/linearize.h
index 3bb9426ca..7e8c0eb2c 100644
--- a/linearize.h
+++ b/linearize.h
@@ -162,6 +162,12 @@ enum opcode {
 	OP_SHL,
 	OP_LSR, OP_ASR,
 	
+	/* Floating-point binops */
+	OP_FADD,
+	OP_FSUB,
+	OP_FMUL,
+	OP_FDIV,
+
 	/* Logical */
 	OP_AND,
 	OP_OR,
@@ -205,6 +211,7 @@ enum opcode {
 	/* Uni */
 	OP_NOT,
 	OP_NEG,
+	OP_FNEG,
 
 	/* Select - three input values */
 	OP_SEL,
diff --git a/opcode.c b/opcode.c
index c28a08859..b5eaae6ad 100644
--- a/opcode.c
+++ b/opcode.c
@@ -51,4 +51,12 @@ const struct opcode_table opcode_table[OP_LAST] = {
 	[OP_FCMP_ULE] = { .negate = OP_FCMP_OGT, .swap = OP_FCMP_UGE, },
 	[OP_FCMP_UGE] = { .negate = OP_FCMP_OLT, .swap = OP_FCMP_ULE, },
 	[OP_FCMP_UGT] = { .negate = OP_FCMP_OLE, .swap = OP_FCMP_ULT, },
+
+	[OP_ADD] = {	.to_float = OP_FADD, },
+	[OP_SUB] = {	.to_float = OP_FSUB, },
+	[OP_MULS] = {	.to_float = OP_FMUL, },
+	[OP_MULU] = {	.to_float = OP_FMUL, },
+	[OP_DIVS] = {	.to_float = OP_FDIV, },
+	[OP_DIVU] = {	.to_float = OP_FDIV, },
+	[OP_NEG] = {	.to_float = OP_FNEG, },
 };
diff --git a/sparse-llvm.c b/sparse-llvm.c
index c21c38947..415f29607 100644
--- a/sparse-llvm.c
+++ b/sparse-llvm.c
@@ -542,32 +542,20 @@ static void output_op_binary(struct function *fn, struct instruction *insn)
 	switch (insn->opcode) {
 	/* Binary */
 	case OP_ADD:
-		if (is_float_type(insn->type))
-			target = LLVMBuildFAdd(fn->builder, lhs, rhs, target_name);
-		else
-			target = LLVMBuildAdd(fn->builder, lhs, rhs, target_name);
+		target = LLVMBuildAdd(fn->builder, lhs, rhs, target_name);
 		break;
 	case OP_SUB:
-		if (is_float_type(insn->type))
-			target = LLVMBuildFSub(fn->builder, lhs, rhs, target_name);
-		else
-			target = LLVMBuildSub(fn->builder, lhs, rhs, target_name);
+		target = LLVMBuildSub(fn->builder, lhs, rhs, target_name);
 		break;
 	case OP_MULU:
-		if (is_float_type(insn->type))
-			target = LLVMBuildFMul(fn->builder, lhs, rhs, target_name);
-		else
-			target = LLVMBuildMul(fn->builder, lhs, rhs, target_name);
+		target = LLVMBuildMul(fn->builder, lhs, rhs, target_name);
 		break;
 	case OP_MULS:
 		assert(!is_float_type(insn->type));
 		target = LLVMBuildMul(fn->builder, lhs, rhs, target_name);
 		break;
 	case OP_DIVU:
-		if (is_float_type(insn->type))
-			target = LLVMBuildFDiv(fn->builder, lhs, rhs, target_name);
-		else
-			target = LLVMBuildUDiv(fn->builder, lhs, rhs, target_name);
+		target = LLVMBuildUDiv(fn->builder, lhs, rhs, target_name);
 		break;
 	case OP_DIVS:
 		assert(!is_float_type(insn->type));
@@ -593,6 +581,20 @@ static void output_op_binary(struct function *fn, struct instruction *insn)
 		assert(!is_float_type(insn->type));
 		target = LLVMBuildAShr(fn->builder, lhs, rhs, target_name);
 		break;
+
+	/* floating-point */
+	case OP_FADD:
+		target = LLVMBuildFAdd(fn->builder, lhs, rhs, target_name);
+		break;
+	case OP_FSUB:
+		target = LLVMBuildFSub(fn->builder, lhs, rhs, target_name);
+		break;
+	case OP_FMUL:
+		target = LLVMBuildFMul(fn->builder, lhs, rhs, target_name);
+		break;
+	case OP_FDIV:
+		target = LLVMBuildFDiv(fn->builder, lhs, rhs, target_name);
+		break;
 	
 	/* Logical */
 	case OP_AND:
@@ -1054,6 +1056,7 @@ static void output_insn(struct function *fn, struct instruction *insn)
 		insn->target->priv = target;
 		break;
 	}
+	case OP_FNEG:
 	case OP_NEG: {
 		LLVMValueRef src, target;
 		char target_name[64];
@@ -1062,7 +1065,7 @@ static void output_insn(struct function *fn, struct instruction *insn)
 
 		pseudo_name(insn->target, target_name);
 
-		if (is_float_type(insn->type))
+		if (insn->opcode == OP_FNEG)
 			target = LLVMBuildFNeg(fn->builder, src, target_name);
 		else
 			target = LLVMBuildNeg(fn->builder, src, target_name);
diff --git a/validation/backend/arithmetic-ops.c b/validation/backend/arithmetic-ops.c
index 7c299d033..d2988a0f6 100644
--- a/validation/backend/arithmetic-ops.c
+++ b/validation/backend/arithmetic-ops.c
@@ -88,6 +88,26 @@ static unsigned int umod(unsigned int x, unsigned int y)
 	return x % y;
 }
 
+static int neg(int x)
+{
+	return -x;
+}
+
+static unsigned int uneg(unsigned int x)
+{
+	return -x;
+}
+
+static float fneg(float x)
+{
+	return -x;
+}
+
+static double dneg(double x)
+{
+	return -x;
+}
+
 /*
  * check-name: Arithmetic operator code generation
  * check-command: ./sparsec -c $file -o tmp.o
diff --git a/validation/fp-ops.c b/validation/fp-ops.c
new file mode 100644
index 000000000..7f58a72fc
--- /dev/null
+++ b/validation/fp-ops.c
@@ -0,0 +1,57 @@
+double fadd(double x, double y) { return x + y; }
+double fsub(double x, double y) { return x - y; }
+double fmul(double x, double y) { return x * y; }
+double fdiv(double x, double y) { return x / y; }
+double fneg(double x)           { return -x; }
+_Bool  ftst(double x)           { return !x; }
+
+/*
+ * check-name: floating-point ops
+ * check-command: ./test-linearize -Wno-decl $file
+
+ * check-output-start
+fadd:
+.L0:
+	<entry-point>
+	fadd.64     %r3 <- %arg1, %arg2
+	ret.64      %r3
+
+
+fsub:
+.L2:
+	<entry-point>
+	fsub.64     %r7 <- %arg1, %arg2
+	ret.64      %r7
+
+
+fmul:
+.L4:
+	<entry-point>
+	fmul.64     %r11 <- %arg1, %arg2
+	ret.64      %r11
+
+
+fdiv:
+.L6:
+	<entry-point>
+	fdiv.64     %r15 <- %arg1, %arg2
+	ret.64      %r15
+
+
+fneg:
+.L8:
+	<entry-point>
+	fneg.64     %r18 <- %arg1
+	ret.64      %r18
+
+
+ftst:
+.L10:
+	<entry-point>
+	set.64      %r21 <- 0.000000
+	fcmpoeq.1   %r23 <- %arg1, %r21
+	ret.1       %r23
+
+
+ * check-output-end
+ */
-- 
2.12.0


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [GIT PULL] floating-point specific instructions
  2017-03-28 14:18 [PATCH 0/4] floating-point specific instructions Luc Van Oostenryck
                   ` (3 preceding siblings ...)
  2017-03-28 14:18 ` [PATCH 4/4] add support of floating-point specific arithmetic ops Luc Van Oostenryck
@ 2017-04-01 10:56 ` Luc Van Oostenryck
  2017-11-18 14:27 ` [PATCH 0/4] " Luc Van Oostenryck
  5 siblings, 0 replies; 7+ messages in thread
From: Luc Van Oostenryck @ 2017-04-01 10:56 UTC (permalink / raw)
  To: linux-sparse; +Cc: Christopher Li

This series is available at:
	git://github.com/lucvoo/sparse.git fpops
based on commit:
	6c5ee5c931d480043d04644cfda5593bfb52e40c (llvm-fixes-v6)
up to commit:
	d440a16358aefd718029963bb2261f1deccfddab


-- Luc Van Oostenryck

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH 0/4] floating-point specific instructions
  2017-03-28 14:18 [PATCH 0/4] floating-point specific instructions Luc Van Oostenryck
                   ` (4 preceding siblings ...)
  2017-04-01 10:56 ` [GIT PULL] floating-point specific instructions Luc Van Oostenryck
@ 2017-11-18 14:27 ` Luc Van Oostenryck
  5 siblings, 0 replies; 7+ messages in thread
From: Luc Van Oostenryck @ 2017-11-18 14:27 UTC (permalink / raw)
  To: Linux-Sparse

On Tue, Mar 28, 2017 at 4:18 PM, Luc Van Oostenryck
<luc.vanoostenryck@gmail.com> wrote:
> Floating-point arithmetic is quite different from arithmetic
> on integers (or on real numbers). In particular,
> most transformations, simplifications that can be done on integers
> are invalid when done on floats.
>
> Since they don't follow the same rules as their integer
> counterpart, better to give a specific opcode to floating-point
> operations instead of having to test the type of the operands at
> each manipulation.
>

This has now been pushed this to my dev tree at:
        git://github.com/lucvoo/sparse.git master

By excluding the floating-point operations from the integer ones,
this fixes a whole class of problems with illegal simplification of
float operations.

This ends the first batch of essential fixes I wanted to be integrated.

-- Luc

^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2017-11-18 14:27 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-03-28 14:18 [PATCH 0/4] floating-point specific instructions Luc Van Oostenryck
2017-03-28 14:18 ` [PATCH 1/4] fix linearize_inc_dec() with floats Luc Van Oostenryck
2017-03-28 14:18 ` [PATCH 2/4] add test case for boolean negation on float Luc Van Oostenryck
2017-03-28 14:18 ` [PATCH 3/4] fix support of floating-point compare Luc Van Oostenryck
2017-03-28 14:18 ` [PATCH 4/4] add support of floating-point specific arithmetic ops Luc Van Oostenryck
2017-04-01 10:56 ` [GIT PULL] floating-point specific instructions Luc Van Oostenryck
2017-11-18 14:27 ` [PATCH 0/4] " Luc Van Oostenryck

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.