aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
-rw-r--r--Documentation/IR.md46
-rw-r--r--cse.c14
-rw-r--r--linearize.c19
-rw-r--r--linearize.h7
-rw-r--r--opcode.c8
-rw-r--r--sparse-llvm.c37
-rw-r--r--validation/backend/arithmetic-ops.c20
-rw-r--r--validation/fp-ops.c57
8 files changed, 176 insertions, 32 deletions
diff --git a/Documentation/IR.md b/Documentation/IR.md
index 8d49936f..af972f93 100644
--- a/Documentation/IR.md
+++ b/Documentation/IR.md
@@ -45,32 +45,32 @@ Computed goto / branch to register
### Arithmetic binops
They all follow the same signature:
- .src1, .src1: operands (types must be compatible with .target)
-- .target: result of the operation
+- .target: result of the operation (must be an integral type)
- .type: type of .target
#### OP_ADD
-Addition.
+Integer addition.
#### OP_SUB
-Subtraction.
+Integer subtraction.
#### OP_MULU
-Multiplication (unsigned ints & floating-points)
+Integer unsigned multiplication.
#### OP_MULS
-Multiplication (signed ints)
+Integer signed multiplication.
#### OP_DIVU
-Division (unsigned ints & floating-points)
+Integer unsigned division.
#### OP_DIVS
-Division (signed ints)
+Integer signed division.
#### OP_MODU
-Modulo (unsigned division remainder, integer only)
+Integer unsigned remainder.
#### OP_MODS
-Modulo (signed division remainder, integer only)
+Integer signed remainder.
#### OP_SHL
Shift left (integer only)
@@ -81,6 +81,24 @@ Logical Shift right (integer only)
#### OP_ASR
Arithmetic Shift right (integer only)
+### Floating-point binops
+They all follow the same signature:
+- .src1, .src1: operands (types must be compatible with .target)
+- .target: result of the operation (must be a floating-point type)
+- .type: type of .target
+
+#### OP_FADD
+Floating-point addition.
+
+#### OP_FSUB
+Floating-point subtraction.
+
+#### OP_FMUL
+Floating-point multiplication.
+
+#### OP_FDIV
+Floating-point division.
+
### Logical ops
They all follow the same signature:
- .src1, .src2: operands (types must be compatible with .target)
@@ -193,9 +211,15 @@ Logical not.
- .type: type of .target, must be an integral type
#### OP_NEG
-Arithmetic negation.
+Integer negation.
- .src: operand (type must be compatible with .target)
-- .target: result of the operation
+- .target: result of the operation (must be an integral type)
+- .type: type of .target
+
+#### OP_FNEG
+Floating-point negation.
+- .src: operand (type must be compatible with .target)
+- .target: result of the operation (must be a floating-point type)
- .type: type of .target
#### OP_COPY
diff --git a/cse.c b/cse.c
index 17b3da01..d5da26fb 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 12703085..eff7d95f 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",
@@ -466,6 +473,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;
@@ -1064,6 +1072,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
@@ -1112,7 +1121,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;
}
@@ -1180,8 +1189,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:
@@ -1244,7 +1255,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);
}
@@ -1360,7 +1371,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 e4ad7b70..4bca9c1e 100644
--- a/linearize.h
+++ b/linearize.h
@@ -155,6 +155,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,
@@ -198,6 +204,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 c28a0885..b5eaae6a 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 b984b6a3..a8186df5 100644
--- a/sparse-llvm.c
+++ b/sparse-llvm.c
@@ -547,32 +547,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));
@@ -598,6 +586,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:
@@ -1068,6 +1070,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];
@@ -1076,7 +1079,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 55996d9c..fc4f0e5a 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 00000000..7f58a72f
--- /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
+ */