authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2015-12-08 12:25:30-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2015-12-08 12:25:30-07:00
log2f0e4e9cb26df7a6f6251d0e865d0d964680831e
tree24716849a69bdc49d82e87a599f58d2b4e6c50f3
parent3e06ed0e8cdfba69e28600a2fcf52d795a86f3bb

codegen does signed, unsigned, and floating point math


4 files changed, 106 insertions(+), 15 deletions(-)

src/codegen.cpp+86-15
......@@ -210,6 +210,10 @@ static LLVMValueRef gen_arithmetic_bin_op_expr(CodeGen *g, AstNode *node) {
210210 LLVMValueRef val1 = gen_expr(g, node->data.bin_op_expr.op1);
211211 LLVMValueRef val2 = gen_expr(g, node->data.bin_op_expr.op2);
212212
213 TypeTableEntry *op1_type = get_expr_type(node->data.bin_op_expr.op1);
214 TypeTableEntry *op2_type = get_expr_type(node->data.bin_op_expr.op2);
215 assert(op1_type == op2_type);
216
213217 switch (node->data.bin_op_expr.bin_op) {
214218 case BinOpTypeBinOr:
215219 add_debug_source_node(g, node);
......@@ -224,29 +228,51 @@ static LLVMValueRef gen_arithmetic_bin_op_expr(CodeGen *g, AstNode *node) {
224228 add_debug_source_node(g, node);
225229 return LLVMBuildShl(g->builder, val1, val2, "");
226230 case BinOpTypeBitShiftRight:
227 // TODO implement type system so that we know whether to do
228 // logical or arithmetic shifting here.
229 // signed -> arithmetic, unsigned -> logical
230231 add_debug_source_node(g, node);
231 return LLVMBuildLShr(g->builder, val1, val2, "");
232 if (op1_type->is_signed_int) {
233 return LLVMBuildAShr(g->builder, val1, val2, "");
234 } else {
235 return LLVMBuildLShr(g->builder, val1, val2, "");
236 }
232237 case BinOpTypeAdd:
233238 add_debug_source_node(g, node);
234 return LLVMBuildAdd(g->builder, val1, val2, "");
239 if (op1_type->is_float) {
240 return LLVMBuildFAdd(g->builder, val1, val2, "");
241 } else {
242 return LLVMBuildNSWAdd(g->builder, val1, val2, "");
243 }
235244 case BinOpTypeSub:
236245 add_debug_source_node(g, node);
237 return LLVMBuildSub(g->builder, val1, val2, "");
246 if (op1_type->is_float) {
247 return LLVMBuildFSub(g->builder, val1, val2, "");
248 } else {
249 return LLVMBuildNSWSub(g->builder, val1, val2, "");
250 }
238251 case BinOpTypeMult:
239 // TODO types so we know float vs int
240252 add_debug_source_node(g, node);
241 return LLVMBuildMul(g->builder, val1, val2, "");
253 if (op1_type->is_float) {
254 return LLVMBuildFMul(g->builder, val1, val2, "");
255 } else {
256 return LLVMBuildNSWMul(g->builder, val1, val2, "");
257 }
242258 case BinOpTypeDiv:
243 // TODO types so we know float vs int and signed vs unsigned
244259 add_debug_source_node(g, node);
245 return LLVMBuildSDiv(g->builder, val1, val2, "");
260 if (op1_type->is_float) {
261 return LLVMBuildFDiv(g->builder, val1, val2, "");
262 } else if (op1_type->is_signed_int) {
263 return LLVMBuildSDiv(g->builder, val1, val2, "");
264 } else {
265 return LLVMBuildUDiv(g->builder, val1, val2, "");
266 }
246267 case BinOpTypeMod:
247 // TODO types so we know float vs int and signed vs unsigned
248268 add_debug_source_node(g, node);
249 return LLVMBuildSRem(g->builder, val1, val2, "");
269 if (op1_type->is_float) {
270 return LLVMBuildFRem(g->builder, val1, val2, "");
271 } else if (op1_type->is_signed_int) {
272 return LLVMBuildSRem(g->builder, val1, val2, "");
273 } else {
274 return LLVMBuildURem(g->builder, val1, val2, "");
275 }
250276 case BinOpTypeBoolOr:
251277 case BinOpTypeBoolAnd:
252278 case BinOpTypeCmpEq:
......@@ -281,16 +307,43 @@ static LLVMIntPredicate cmp_op_to_int_predicate(BinOpType cmp_op, bool is_signed
281307 }
282308}
283309
310static LLVMRealPredicate cmp_op_to_real_predicate(BinOpType cmp_op) {
311 switch (cmp_op) {
312 case BinOpTypeCmpEq:
313 return LLVMRealOEQ;
314 case BinOpTypeCmpNotEq:
315 return LLVMRealONE;
316 case BinOpTypeCmpLessThan:
317 return LLVMRealOLT;
318 case BinOpTypeCmpGreaterThan:
319 return LLVMRealOGT;
320 case BinOpTypeCmpLessOrEq:
321 return LLVMRealOLE;
322 case BinOpTypeCmpGreaterOrEq:
323 return LLVMRealOGE;
324 default:
325 zig_unreachable();
326 }
327}
328
284329static LLVMValueRef gen_cmp_expr(CodeGen *g, AstNode *node) {
285330 assert(node->type == NodeTypeBinOpExpr);
286331
287332 LLVMValueRef val1 = gen_expr(g, node->data.bin_op_expr.op1);
288333 LLVMValueRef val2 = gen_expr(g, node->data.bin_op_expr.op2);
289334
290 // TODO implement type system so that we know whether to do signed or unsigned comparison here
291 LLVMIntPredicate pred = cmp_op_to_int_predicate(node->data.bin_op_expr.bin_op, true);
335 TypeTableEntry *op1_type = get_expr_type(node->data.bin_op_expr.op1);
336 TypeTableEntry *op2_type = get_expr_type(node->data.bin_op_expr.op2);
337 assert(op1_type == op2_type);
338
292339 add_debug_source_node(g, node);
293 return LLVMBuildICmp(g->builder, pred, val1, val2, "");
340 if (op1_type->is_float) {
341 LLVMRealPredicate pred = cmp_op_to_real_predicate(node->data.bin_op_expr.bin_op);
342 return LLVMBuildFCmp(g->builder, pred, val1, val2, "");
343 } else {
344 LLVMIntPredicate pred = cmp_op_to_int_predicate(node->data.bin_op_expr.bin_op, op1_type->is_signed_int);
345 return LLVMBuildICmp(g->builder, pred, val1, val2, "");
346 }
294347}
295348
296349static LLVMValueRef gen_bool_and_expr(CodeGen *g, AstNode *node) {
......@@ -847,12 +900,26 @@ static void define_primitive_types(CodeGen *g) {
847900 buf_init_from_str(&entry->name, "i32");
848901 entry->size_in_bits = 32;
849902 entry->align_in_bits = 32;
903 entry->is_signed_int = true;
850904 entry->di_type = LLVMZigCreateDebugBasicType(g->dbuilder, buf_ptr(&entry->name),
851905 entry->size_in_bits, entry->align_in_bits,
852906 LLVMZigEncoding_DW_ATE_signed());
853907 g->type_table.put(&entry->name, entry);
854908 g->builtin_types.entry_i32 = entry;
855909 }
910 {
911 TypeTableEntry *entry = new_type_table_entry();
912 entry->type_ref = LLVMFloatType();
913 buf_init_from_str(&entry->name, "f32");
914 entry->size_in_bits = 32;
915 entry->align_in_bits = 32;
916 entry->is_float = true;
917 entry->di_type = LLVMZigCreateDebugBasicType(g->dbuilder, buf_ptr(&entry->name),
918 entry->size_in_bits, entry->align_in_bits,
919 LLVMZigEncoding_DW_ATE_float());
920 g->type_table.put(&entry->name, entry);
921 g->builtin_types.entry_f32 = entry;
922 }
856923 {
857924 TypeTableEntry *entry = new_type_table_entry();
858925 entry->type_ref = LLVMVoidType();
......@@ -918,6 +985,8 @@ static void init(CodeGen *g, Buf *source_path) {
918985 g->builder = LLVMCreateBuilder();
919986 g->dbuilder = LLVMZigCreateDIBuilder(g->module, true);
920987
988 LLVMZigSetFastMath(g->builder, true);
989
921990
922991 define_primitive_types(g);
923992
......@@ -1058,6 +1127,8 @@ static void to_c_type(CodeGen *g, AstNode *type_node, Buf *out_buf) {
10581127 } else if (type_entry == g->builtin_types.entry_i32) {
10591128 g->c_stdint_used = true;
10601129 buf_init_from_str(out_buf, "int32_t");
1130 } else if (type_entry == g->builtin_types.entry_f32) {
1131 buf_init_from_str(out_buf, "float");
10611132 } else if (type_entry == g->builtin_types.entry_unreachable) {
10621133 buf_init_from_str(out_buf, "__attribute__((__noreturn__)) void");
10631134 } else if (type_entry == g->builtin_types.entry_bool) {
src/semantic_info.hpp+3
......@@ -21,6 +21,8 @@ struct TypeTableEntry {
2121 LLVMZigDIType *di_type;
2222 uint64_t size_in_bits;
2323 uint64_t align_in_bits;
24 bool is_signed_int;
25 bool is_float;
2426
2527 TypeTableEntry *pointer_child;
2628 bool pointer_is_const;
......@@ -82,6 +84,7 @@ struct CodeGen {
8284 TypeTableEntry *entry_bool;
8385 TypeTableEntry *entry_u8;
8486 TypeTableEntry *entry_i32;
87 TypeTableEntry *entry_f32;
8588 TypeTableEntry *entry_string_literal;
8689 TypeTableEntry *entry_void;
8790 TypeTableEntry *entry_unreachable;
src/zig_llvm.cpp+14
......@@ -185,6 +185,10 @@ unsigned LLVMZigEncoding_DW_ATE_signed(void) {
185185 return dwarf::DW_ATE_signed;
186186}
187187
188unsigned LLVMZigEncoding_DW_ATE_float(void) {
189 return dwarf::DW_ATE_float;
190}
191
188192unsigned LLVMZigLang_DW_LANG_C99(void) {
189193 return dwarf::DW_LANG_C99;
190194}
......@@ -322,6 +326,16 @@ LLVMZigDILocation *LLVMZigGetDebugLoc(unsigned line, unsigned col, LLVMZigDIScop
322326 return reinterpret_cast<LLVMZigDILocation*>(debug_loc.get());
323327}
324328
329void LLVMZigSetFastMath(LLVMBuilderRef builder_wrapped, bool on_state) {
330 if (on_state) {
331 FastMathFlags fmf;
332 fmf.setUnsafeAlgebra();
333 unwrap(builder_wrapped)->SetFastMathFlags(fmf);
334 } else {
335 unwrap(builder_wrapped)->clearFastMathFlags();
336 }
337}
338
325339//------------------------------------
326340
327341enum FloatAbi {
src/zig_llvm.hpp+3
......@@ -55,6 +55,7 @@ LLVMZigDISubroutineType *LLVMZigCreateSubroutineType(LLVMZigDIBuilder *dibuilder
5555
5656unsigned LLVMZigEncoding_DW_ATE_unsigned(void);
5757unsigned LLVMZigEncoding_DW_ATE_signed(void);
58unsigned LLVMZigEncoding_DW_ATE_float(void);
5859unsigned LLVMZigLang_DW_LANG_C99(void);
5960unsigned LLVMZigTag_DW_auto_variable(void);
6061unsigned LLVMZigTag_DW_arg_variable(void);
......@@ -96,6 +97,8 @@ LLVMValueRef LLVMZigInsertDeclare(LLVMZigDIBuilder *dibuilder, LLVMValueRef stor
9697 LLVMZigDILocalVariable *var_info, LLVMZigDILocation *debug_loc, LLVMValueRef insert_before_instr);
9798LLVMZigDILocation *LLVMZigGetDebugLoc(unsigned line, unsigned col, LLVMZigDIScope *scope);
9899
100void LLVMZigSetFastMath(LLVMBuilderRef builder_wrapped, bool on_state);
101
99102
100103/*
101104 * This stuff is not LLVM API but it depends on the LLVM C++ API so we put it here.