@@ -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",
@@ -433,6 +449,7 @@ const char *show_instruction(struct instruction *insn)
show_pseudo(insn->src));
break;
case OP_BINARY ... OP_BINARY_END:
+ case OP_FP_CMP ... OP_FP_CMP_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;
@@ -1448,10 +1465,20 @@ static pseudo_t linearize_compare(struct entrypoint *ep, struct expression *expr
[SPECIAL_UNSIGNED_LTE] = OP_SET_BE,
[SPECIAL_UNSIGNED_GTE] = OP_SET_AE,
};
+ static const int fcmpop[] = {
+ ['>'] = OP_FCMP_OGT,
+ ['<'] = OP_FCMP_OLT,
+ [SPECIAL_EQUAL] = OP_FCMP_OEQ,
+ [SPECIAL_NOTEQUAL] = OP_FCMP_ONE,
+ [SPECIAL_GTE] = OP_FCMP_OGE,
+ [SPECIAL_LTE] = OP_FCMP_OLE,
+ };
+ struct symbol *ctype = expr->right->ctype;
+ int op = is_float_type(ctype) ? fcmpop[expr->op] : cmpop[expr->op];
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;
}
@@ -169,6 +169,24 @@ enum opcode {
OP_OR_BOOL,
OP_BINARY_END = OP_OR_BOOL,
+ /* floating-point comparison */
+ OP_FP_CMP,
+ OP_FCMP_ORD = OP_FP_CMP,
+ 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_FP_CMP_END = OP_FCMP_UNO,
+
/* Binary comparison */
OP_BINCMP,
OP_SET_EQ = OP_BINCMP,
@@ -186,6 +204,7 @@ enum opcode {
/* Uni */
OP_NOT,
OP_NEG,
+ OP_ISNAN,
/* Select - three input values */
OP_SEL,
@@ -66,6 +66,7 @@ static void track_instruction_usage(struct basic_block *bb, struct instruction *
/* Binary */
case OP_BINARY ... OP_BINARY_END:
+ case OP_FP_CMP ... OP_FP_CMP_END:
case OP_BINCMP ... OP_BINCMP_END:
USES(src1); USES(src2); DEFINES(target);
break;
@@ -415,44 +415,78 @@ static int simplify_mul_div(struct instruction *insn, long long value)
static int negate_compare_opcode(int opcode, int inverse)
{
static const unsigned char opcode_tbl[] = {
- [OP_SET_EQ - OP_BINCMP] = OP_SET_NE,
- [OP_SET_NE - OP_BINCMP] = OP_SET_EQ,
- [OP_SET_GT - OP_BINCMP] = OP_SET_LE,
- [OP_SET_GE - OP_BINCMP] = OP_SET_LT,
- [OP_SET_LE - OP_BINCMP] = OP_SET_GT,
- [OP_SET_LT - OP_BINCMP] = OP_SET_GE,
- [OP_SET_A - OP_BINCMP] = OP_SET_BE,
- [OP_SET_AE - OP_BINCMP] = OP_SET_B ,
- [OP_SET_BE - OP_BINCMP] = OP_SET_A ,
- [OP_SET_B - OP_BINCMP] = OP_SET_AE,
+ [OP_FCMP_ORD - OP_FP_CMP] = OP_FCMP_UNO,
+ [OP_FCMP_UNO - OP_FP_CMP] = OP_FCMP_ORD,
+
+ [OP_FCMP_OEQ - OP_FP_CMP] = OP_FCMP_UNE,
+ [OP_FCMP_ONE - OP_FP_CMP] = OP_FCMP_UEQ,
+ [OP_FCMP_OGT - OP_FP_CMP] = OP_FCMP_ULE,
+ [OP_FCMP_OGE - OP_FP_CMP] = OP_FCMP_ULT,
+ [OP_FCMP_OLE - OP_FP_CMP] = OP_FCMP_UGT,
+ [OP_FCMP_OLT - OP_FP_CMP] = OP_FCMP_UGE,
+
+ [OP_FCMP_UEQ - OP_FP_CMP] = OP_FCMP_ONE,
+ [OP_FCMP_UNE - OP_FP_CMP] = OP_FCMP_OEQ,
+ [OP_FCMP_UGT - OP_FP_CMP] = OP_FCMP_OLE,
+ [OP_FCMP_UGE - OP_FP_CMP] = OP_FCMP_OLT,
+ [OP_FCMP_ULE - OP_FP_CMP] = OP_FCMP_OGT,
+ [OP_FCMP_ULT - OP_FP_CMP] = OP_FCMP_OGE,
+
+ [OP_SET_EQ - OP_FP_CMP] = OP_SET_NE,
+ [OP_SET_NE - OP_FP_CMP] = OP_SET_EQ,
+ [OP_SET_GT - OP_FP_CMP] = OP_SET_LE,
+ [OP_SET_GE - OP_FP_CMP] = OP_SET_LT,
+ [OP_SET_LE - OP_FP_CMP] = OP_SET_GT,
+ [OP_SET_LT - OP_FP_CMP] = OP_SET_GE,
+ [OP_SET_A - OP_FP_CMP] = OP_SET_BE,
+ [OP_SET_AE - OP_FP_CMP] = OP_SET_B ,
+ [OP_SET_BE - OP_FP_CMP] = OP_SET_A ,
+ [OP_SET_B - OP_FP_CMP] = OP_SET_AE,
};
- assert(opcode >= OP_BINCMP && opcode <= OP_BINCMP_END);
+ assert(opcode >= OP_FP_CMP && opcode <= OP_BINCMP_END);
if (!inverse)
return opcode;
- return opcode_tbl[opcode - OP_BINCMP];
+ return opcode_tbl[opcode - OP_FP_CMP];
}
static int swap_compare_opcode(int opcode)
{
static const unsigned char opcode_tbl[] = {
- [OP_SET_EQ - OP_BINCMP] = OP_SET_EQ,
- [OP_SET_NE - OP_BINCMP] = OP_SET_NE,
- [OP_SET_GT - OP_BINCMP] = OP_SET_LT,
- [OP_SET_GE - OP_BINCMP] = OP_SET_LE,
- [OP_SET_LE - OP_BINCMP] = OP_SET_GE,
- [OP_SET_LT - OP_BINCMP] = OP_SET_GT,
- [OP_SET_A - OP_BINCMP] = OP_SET_B ,
- [OP_SET_AE - OP_BINCMP] = OP_SET_BE,
- [OP_SET_BE - OP_BINCMP] = OP_SET_AE,
- [OP_SET_B - OP_BINCMP] = OP_SET_A ,
+ [OP_FCMP_ORD - OP_FP_CMP] = OP_FCMP_ORD,
+ [OP_FCMP_UNO - OP_FP_CMP] = OP_FCMP_UNO,
+
+ [OP_FCMP_OEQ - OP_FP_CMP] = OP_FCMP_OEQ,
+ [OP_FCMP_ONE - OP_FP_CMP] = OP_FCMP_ONE,
+ [OP_FCMP_OGT - OP_FP_CMP] = OP_FCMP_OLT,
+ [OP_FCMP_OGE - OP_FP_CMP] = OP_FCMP_OLE,
+ [OP_FCMP_OLE - OP_FP_CMP] = OP_FCMP_OGE,
+ [OP_FCMP_OLT - OP_FP_CMP] = OP_FCMP_OGT,
+
+ [OP_FCMP_UEQ - OP_FP_CMP] = OP_FCMP_UEQ,
+ [OP_FCMP_UNE - OP_FP_CMP] = OP_FCMP_UNE,
+ [OP_FCMP_UGT - OP_FP_CMP] = OP_FCMP_ULT,
+ [OP_FCMP_UGE - OP_FP_CMP] = OP_FCMP_ULE,
+ [OP_FCMP_ULE - OP_FP_CMP] = OP_FCMP_UGE,
+ [OP_FCMP_ULT - OP_FP_CMP] = OP_FCMP_UGT,
+
+ [OP_SET_EQ - OP_FP_CMP] = OP_SET_EQ,
+ [OP_SET_NE - OP_FP_CMP] = OP_SET_NE,
+ [OP_SET_GT - OP_FP_CMP] = OP_SET_LT,
+ [OP_SET_GE - OP_FP_CMP] = OP_SET_LE,
+ [OP_SET_LE - OP_FP_CMP] = OP_SET_GE,
+ [OP_SET_LT - OP_FP_CMP] = OP_SET_GT,
+ [OP_SET_A - OP_FP_CMP] = OP_SET_B ,
+ [OP_SET_AE - OP_FP_CMP] = OP_SET_BE,
+ [OP_SET_BE - OP_FP_CMP] = OP_SET_AE,
+ [OP_SET_B - OP_FP_CMP] = OP_SET_A ,
};
- assert(opcode >= OP_BINCMP && opcode <= OP_BINCMP_END);
+ assert(opcode >= OP_FP_CMP && opcode <= OP_BINCMP_END);
- return opcode_tbl[opcode - OP_BINCMP];
+ return opcode_tbl[opcode - OP_FP_CMP];
}
static int simplify_seteq_setne(struct instruction *insn, long long value)
@@ -472,7 +506,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_FP_CMP ... OP_BINCMP_END:
// Convert:
// setcc.n %t <- %a, %b
// setne.m %r <- %t, $0
@@ -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_FP_CMP ... OP_BINCMP_END:
output_op_compare(fn, insn);
break;
case OP_SEL:
new file mode 100644
@@ -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]
+ fcmpone.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]
+ fcmpueq.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
+ */