diff options
| author | Luc Van Oostenryck <luc.vanoostenryck@gmail.com> | 2017-03-19 22:43:06 +0100 |
|---|---|---|
| committer | Luc Van Oostenryck <luc.vanoostenryck@gmail.com> | 2017-11-17 10:04:37 +0100 |
| commit | 0f1700e896ed0111fa7e248c307c620fd8506000 (patch) | |
| tree | 76d30477e65bc8bf45e530ba6c80109ab8f1adb0 | |
| parent | 880cd2465e6f2badda7c7e9e81d1d4cca7a35833 (diff) | |
| download | sparse-dev-0f1700e896ed0111fa7e248c307c620fd8506000.tar.gz | |
llvm: fix mutating function pointer
Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
| -rw-r--r-- | sparse-llvm.c | 33 | ||||
| -rw-r--r-- | validation/backend/function-ptr-xtype.c | 37 |
2 files changed, 64 insertions, 6 deletions
diff --git a/sparse-llvm.c b/sparse-llvm.c index 0043b797..1af6322d 100644 --- a/sparse-llvm.c +++ b/sparse-llvm.c @@ -456,6 +456,27 @@ static LLVMValueRef adjust_type(struct function *fn, struct symbol *ctype, LLVMV return val; } +/* + * Get the LLVMValue corresponding to the pseudo + * and force the type corresponding to ctype. + */ +static LLVMValueRef get_operand(struct function *fn, struct symbol *ctype, pseudo_t pseudo) +{ + LLVMValueRef target = pseudo_to_value(fn, ctype, pseudo); + return adjust_type(fn, ctype, target); +} + +/* + * Get the LLVMValue corresponding to the pseudo + * and force the type corresponding to ctype but + * map all pointers to intptr_t. + */ +static LLVMValueRef get_ioperand(struct function *fn, struct symbol *ctype, pseudo_t pseudo) +{ + LLVMValueRef target = pseudo_to_value(fn, ctype, pseudo); + return value_to_ivalue(fn, ctype, target); +} + static LLVMValueRef calc_gep(LLVMBuilderRef builder, LLVMValueRef base, LLVMValueRef off) { LLVMTypeRef type = LLVMTypeOf(base); @@ -515,11 +536,8 @@ static void output_op_binary(struct function *fn, struct instruction *insn) LLVMValueRef lhs, rhs, target; char target_name[64]; - lhs = pseudo_to_value(fn, insn->type, insn->src1); - lhs = value_to_ivalue(fn, insn->type, lhs); - - rhs = pseudo_to_value(fn, insn->type, insn->src2); - rhs = value_to_ivalue(fn, insn->type, rhs); + lhs = get_ioperand(fn, insn->type, insn->src1); + rhs = get_ioperand(fn, insn->type, insn->src2); pseudo_name(insn->target, target_name); @@ -807,6 +825,10 @@ static void output_op_call(struct function *fn, struct instruction *insn) args = calloc(n_arg, sizeof(LLVMValueRef)); PREPARE_PTR_LIST(insn->fntypes, ctype); + if (insn->func->type == PSEUDO_REG || insn->func->type == PSEUDO_PHI) + func = get_operand(fn, ctype, insn->func); + else + func = pseudo_to_value(fn, ctype, insn->func); i = 0; FOR_EACH_PTR(insn->arguments, arg) { NEXT_PTR_LIST(ctype); @@ -814,7 +836,6 @@ static void output_op_call(struct function *fn, struct instruction *insn) } END_FOR_EACH_PTR(arg); FINISH_PTR_LIST(ctype); - func = pseudo_to_value(fn, NULL, insn->func); pseudo_name(insn->target, name); target = LLVMBuildCall(fn->builder, func, args, n_arg, name); diff --git a/validation/backend/function-ptr-xtype.c b/validation/backend/function-ptr-xtype.c new file mode 100644 index 00000000..9cdfab05 --- /dev/null +++ b/validation/backend/function-ptr-xtype.c @@ -0,0 +1,37 @@ +typedef int (*binop_t)(int, int); +typedef int (*unop_t)(int); +typedef int (*idef_t)(void); +typedef long (*ldef_t)(void); +typedef void (*use_t)(int); + +// We want to 'fn' have several different types. +// The goal is for the ->priv member to be used +// with a type different from what it was first stored. + +int foo(void *fn, int arg1, int arg2); +int foo(void *fn, int arg1, int arg2) +{ + int res = 0; + + res += ((binop_t)fn)(arg1, arg2); + res += ((unop_t)fn)(arg1); + res += ((ldef_t)fn)(); + res += ((idef_t)fn)(); + ((use_t)fn)(res); + return res; +} + +int bar(int (*fn)(int), int arg1, int arg2); +int bar(int (*fn)(int), int arg1, int arg2) +{ + int res = 0; + + res += ((binop_t)fn)(arg1, arg2); + res += fn(arg1); + return res; +} + +/* + * check-name: mutate function pointer's type + * check-command: ./sparsec -c $file -o tmp.o + */ |
