diff options
| -rw-r--r-- | Documentation/IR.md | 56 | ||||
| -rw-r--r-- | linearize.c | 21 | ||||
| -rw-r--r-- | linearize.h | 18 | ||||
| -rw-r--r-- | liveness.c | 1 | ||||
| -rw-r--r-- | opcode.c | 38 | ||||
| -rw-r--r-- | opcode.h | 10 | ||||
| -rw-r--r-- | simplify.c | 2 | ||||
| -rw-r--r-- | sparse-llvm.c | 27 | ||||
| -rw-r--r-- | validation/optim/canonical-fcmp.c | 123 |
9 files changed, 270 insertions, 26 deletions
diff --git a/Documentation/IR.md b/Documentation/IR.md index e6d14e19..8d49936f 100644 --- a/Documentation/IR.md +++ b/Documentation/IR.md @@ -95,7 +95,7 @@ They all follow the same signature: #### OP_AND_BOOL #### OP_OR_BOOL -### Comparisons +### Integer compares They all have the following signature: - .src1, .src2: operands (types must be compatible) - .target: result of the operation (0/1 valued integer) @@ -131,6 +131,60 @@ Compare less-than-or-equal (unsigned). #### OP_SET_AE Compare greater-than-or-equal (unsigned). +### Floating-point compares +They all have the same signature as the integer compares. +The usual 6 operations exist in two versions: 'ordered' and +'unordered'. Theses operations first check if any operand is a +NaN and if it is the case the ordered compares return false +and then unordered return true, otherwise the result of the +comparison, now garanted to be done on non-NaNs, is returned. + +#### OP_FCMP_OEQ +Floating-point compare ordered equal + +#### OP_FCMP_ONE +Floating-point compare ordered not-equal + +#### OP_FCMP_OLE +Floating-point compare ordered less-than-or-equal + +#### OP_FCMP_OGE +Floating-point compare ordered greater-or-equal + +#### OP_FCMP_OLT +Floating-point compare ordered less-than + +#### OP_FCMP_OGT +Floating-point compare ordered greater-than + + +#### OP_FCMP_UEQ +Floating-point compare unordered equal + +#### OP_FCMP_UNE +Floating-point compare unordered not-equal + +#### OP_FCMP_ULE +Floating-point compare unordered less-than-or-equal + +#### OP_FCMP_UGE +Floating-point compare unordered greater-or-equal + +#### OP_FCMP_ULT +Floating-point compare unordered less-than + +#### OP_FCMP_UGT +Floating-point compare unordered greater-than + + +#### OP_FCMP_ORD +Floating-point compare ordered: return true if both operands are ordered +(none of the operands are a NaN) and false otherwise. + +#### OP_FCMP_UNO +Floating-point compare unordered: return false if no operands is ordered +and true otherwise. + ### Unary ops #### OP_NOT Logical not. diff --git a/linearize.c b/linearize.c index b4eb06c1..12703085 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", @@ -435,6 +451,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; @@ -1472,10 +1489,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 ad5476c6..e4ad7b70 100644 --- a/linearize.h +++ b/linearize.h @@ -163,6 +163,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, @@ -67,6 +67,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; @@ -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, }, }; @@ -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 @@ -450,7 +450,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 fa0689dc..b984b6a3 100644 --- a/sparse-llvm.c +++ b/sparse-llvm.c @@ -497,17 +497,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]; @@ -1043,7 +1046,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 00000000..e3e758a9 --- /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 + */ |
