From 3c827be876a39cbe199e5cd7c6e90edef3a090b5 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 27 Jan 2022 21:36:43 -0700 Subject: [PATCH] fix invalid const bitcast of f80 LLVM bitcast wants integers that match the number of bits. So the const bitcast has to use an i80, not an i128. This commit makes the behavior tests fail for me, so it seems I did not correctly construct the type. But it gets rid of the LLVM segfault. I noticed that the strategy of memcpy the buf worked if I simply did an LLVMConstTrunc() on the i128 to make it into an i80 before the LLVMConstBitCast(). But is that correct in the face of different endianness? I'm not sure. --- src/stage1/codegen.cpp | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/src/stage1/codegen.cpp b/src/stage1/codegen.cpp index 2051d39a7c..58670cf822 100644 --- a/src/stage1/codegen.cpp +++ b/src/stage1/codegen.cpp @@ -8094,10 +8094,18 @@ static LLVMValueRef gen_const_val(CodeGen *g, ZigValue *const_val, const char *n case 64: return LLVMConstReal(get_llvm_type(g, type_entry), const_val->data.x_f64); case 80: { - uint64_t buf[2]; - memcpy(&buf, &const_val->data.x_f80, 16); - LLVMValueRef as_int = LLVMConstIntOfArbitraryPrecision(LLVMInt128Type(), 2, buf); - return LLVMConstBitCast(as_int, get_llvm_type(g, type_entry)); + LLVMTypeRef llvm_i80 = LLVMIntType(80); + LLVMValueRef x; + if (g->is_big_endian) { + x = LLVMConstInt(llvm_i80, const_val->data.x_f80.signExp, false); + x = LLVMConstShl(x, LLVMConstInt(llvm_i80, 64, false)); + x = LLVMConstOr(x, LLVMConstInt(llvm_i80, const_val->data.x_f80.signif, false)); + } else { + x = LLVMConstInt(llvm_i80, const_val->data.x_f80.signif, false); + x = LLVMConstShl(x, LLVMConstInt(llvm_i80, 16, false)); + x = LLVMConstOr(x, LLVMConstInt(llvm_i80, const_val->data.x_f80.signExp, false)); + } + return LLVMConstBitCast(x, get_llvm_type(g, type_entry)); } case 128: {