diff options
| -rw-r--r-- | Documentation/IR.md | 46 | ||||
| -rw-r--r-- | cse.c | 14 | ||||
| -rw-r--r-- | linearize.c | 19 | ||||
| -rw-r--r-- | linearize.h | 7 | ||||
| -rw-r--r-- | opcode.c | 8 | ||||
| -rw-r--r-- | sparse-llvm.c | 37 | ||||
| -rw-r--r-- | validation/backend/arithmetic-ops.c | 20 | ||||
| -rw-r--r-- | validation/fp-ops.c | 57 |
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 @@ -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, @@ -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 + */ |
